diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/buffer.c | 206 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 2 | ||||
-rw-r--r-- | src/nvim/api/tabpage.c | 68 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 193 | ||||
-rw-r--r-- | src/nvim/api/window.c | 120 | ||||
-rw-r--r-- | src/nvim/buffer.c | 54 | ||||
-rw-r--r-- | src/nvim/charset.c | 39 | ||||
-rw-r--r-- | src/nvim/eval.c | 40 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 111 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 28 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 13 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 5 | ||||
-rw-r--r-- | src/nvim/screen.c | 20 | ||||
-rw-r--r-- | src/nvim/syntax.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_tabpage.vim | 58 | ||||
-rw-r--r-- | src/nvim/version.c | 85 | ||||
-rw-r--r-- | src/nvim/window.c | 56 |
17 files changed, 654 insertions, 446 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 09d717bff6..eaaae943d2 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -28,9 +28,9 @@ /// Gets the buffer line count /// -/// @param buffer The buffer handle -/// @param[out] err Details of an error that may have occurred -/// @return The line count +/// @param buffer Buffer handle +/// @param[out] err Error details, if any +/// @return Line count Integer nvim_buf_line_count(Buffer buffer, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -50,10 +50,10 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err) /// for negative indices use /// "nvim_buf_get_lines(buffer, index-1, index, true)" /// -/// @param buffer The buffer handle -/// @param index The line index -/// @param[out] err Details of an error that may have occurred -/// @return The line string +/// @param buffer Buffer handle +/// @param index Line index +/// @param[out] err Error details, if any +/// @return Line string String buffer_get_line(Buffer buffer, Integer index, Error *err) { String rv = { .size = 0 }; @@ -78,10 +78,10 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err) /// for negative indices use /// "nvim_buf_set_lines(buffer, index-1, index, true, [line])" /// -/// @param buffer The buffer handle -/// @param index The line index -/// @param line The new line. -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param index Line index +/// @param line Contents of the new line +/// @param[out] err Error details, if any void buffer_set_line(Buffer buffer, Integer index, String line, Error *err) { Object l = STRING_OBJ(line); @@ -97,9 +97,9 @@ void buffer_set_line(Buffer buffer, Integer index, String line, Error *err) /// "nvim_buf_set_lines(buffer, index, index+1, true, [])" /// for negative indices use /// "nvim_buf_set_lines(buffer, index-1, index, true, [])" -/// @param buffer The buffer handle -/// @param index The line index -/// @param[out] err Details of an error that may have occurred +/// @param buffer buffer handle +/// @param index line index +/// @param[out] err Error details, if any void buffer_del_line(Buffer buffer, Integer index, Error *err) { Array array = ARRAY_DICT_INIT; @@ -113,13 +113,13 @@ void buffer_del_line(Buffer buffer, Integer index, Error *err) /// where newstart = start + int(not include_start) - int(start < 0) /// newend = end + int(include_end) - int(end < 0) /// int(bool) = 1 if bool is true else 0 -/// @param buffer The buffer handle -/// @param start The first line index -/// @param end The last line index -/// @param include_start True if the slice includes the `start` parameter -/// @param include_end True if the slice includes the `end` parameter -/// @param[out] err Details of an error that may have occurred -/// @return An array of lines +/// @param buffer Buffer handle +/// @param start First line index +/// @param end Last line index +/// @param include_start True if the slice includes the `start` parameter +/// @param include_end True if the slice includes the `end` parameter +/// @param[out] err Error details, if any +/// @return Array of lines ArrayOf(String) buffer_get_line_slice(Buffer buffer, Integer start, Integer end, @@ -142,12 +142,12 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer, /// Out-of-bounds indices are clamped to the nearest valid value, unless /// `strict_indexing` is set. /// -/// @param buffer The buffer handle -/// @param start The first line index -/// @param end The last line index (exclusive) -/// @param strict_indexing whether out-of-bounds should be an error. -/// @param[out] err Details of an error that may have occurred -/// @return An array of lines +/// @param buffer Buffer handle +/// @param start First line index +/// @param end Last line index (exclusive) +/// @param strict_indexing Whether out-of-bounds should be an error. +/// @param[out] err Error details, if any +/// @return Array of lines ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id, Buffer buffer, Integer start, @@ -219,14 +219,14 @@ end: /// newend = end + int(include_end) + int(end < 0) /// int(bool) = 1 if bool is true else 0 /// -/// @param buffer The buffer handle -/// @param start The first line index -/// @param end The last line index -/// @param include_start True if the slice includes the `start` parameter -/// @param include_end True if the slice includes the `end` parameter -/// @param replacement An array of lines to use as replacement(A 0-length -// array will simply delete the line range) -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param start First line index +/// @param end Last line index +/// @param include_start True if the slice includes the `start` parameter +/// @param include_end True if the slice includes the `end` parameter +/// @param replacement Array of lines to use as replacement (0-length +// array will delete the line range) +/// @param[out] err Error details, if any void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, @@ -253,12 +253,12 @@ void buffer_set_line_slice(Buffer buffer, /// Out-of-bounds indices are clamped to the nearest valid value, unless /// `strict_indexing` is set. /// -/// @param buffer The buffer handle -/// @param start The first line index -/// @param end The last line index (exclusive) -/// @param strict_indexing whether out-of-bounds should be an error. -/// @param replacement An array of lines to use as replacement -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param start First line index +/// @param end Last line index (exclusive) +/// @param strict_indexing Whether out-of-bounds should be an error. +/// @param replacement Array of lines to use as replacement +/// @param[out] err Error details, if any void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, @@ -411,10 +411,10 @@ end: /// Gets a buffer-scoped (b:) variable. /// -/// @param buffer The buffer handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The variable value +/// @param buffer Buffer handle +/// @param name Variable name +/// @param[out] err Error details, if any +/// @return Variable value Object nvim_buf_get_var(Buffer buffer, String name, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -428,10 +428,10 @@ Object nvim_buf_get_var(Buffer buffer, String name, Error *err) /// Sets a buffer-scoped (b:) variable /// -/// @param buffer The buffer handle -/// @param name The variable name -/// @param value The variable value -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param name Variable name +/// @param value Variable value +/// @param[out] err Error details, if any void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -445,9 +445,9 @@ void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err) /// Removes a buffer-scoped (b:) variable /// -/// @param buffer The buffer handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param name Variable name +/// @param[out] err Error details, if any void nvim_buf_del_var(Buffer buffer, String name, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -463,11 +463,11 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err) /// /// @deprecated /// -/// @param buffer The buffer handle -/// @param name The variable name -/// @param value The variable value -/// @param[out] err Details of an error that may have occurred -/// @return The old value or nil if there was no previous value. +/// @param buffer Buffer handle +/// @param name Variable name +/// @param value Variable value +/// @param[out] err Error details, if any +/// @return Old value or nil if there was no previous value. /// /// @warning It may return nil if there was no previous value /// or if previous value was `v:null`. @@ -486,10 +486,10 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err) /// /// @deprecated /// -/// @param buffer The buffer handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The old value +/// @param buffer Buffer handle +/// @param name Variable name +/// @param[out] err Error details, if any +/// @return Old value Object buffer_del_var(Buffer buffer, String name, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -504,10 +504,10 @@ Object buffer_del_var(Buffer buffer, String name, Error *err) /// Gets a buffer option value /// -/// @param buffer The buffer handle -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -/// @return The option value +/// @param buffer Buffer handle +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value Object nvim_buf_get_option(Buffer buffer, String name, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -519,13 +519,13 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err) return get_option_from(buf, SREQ_BUF, name, err); } -/// Sets a buffer option value. Passing 'nil' as value deletes the option(only +/// Sets a buffer option value. Passing 'nil' as value deletes the option (only /// works if there's a global fallback) /// -/// @param buffer The buffer handle -/// @param name The option name -/// @param value The option value -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param name Option name +/// @param value Option value +/// @param[out] err Error details, if any void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -539,9 +539,9 @@ void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err) /// Gets the buffer number /// -/// @param buffer The buffer handle -/// @param[out] err Details of an error that may have occurred -/// @return The buffer number +/// @param buffer Buffer handle +/// @param[out] err Error details, if any +/// @return Buffer number Integer nvim_buf_get_number(Buffer buffer, Error *err) { Integer rv = 0; @@ -556,9 +556,9 @@ Integer nvim_buf_get_number(Buffer buffer, Error *err) /// Gets the full file name for the buffer /// -/// @param buffer The buffer handle -/// @param[out] err Details of an error that may have occurred -/// @return The buffer name +/// @param buffer Buffer handle +/// @param[out] err Error details, if any +/// @return Buffer name String nvim_buf_get_name(Buffer buffer, Error *err) { String rv = STRING_INIT; @@ -573,9 +573,9 @@ String nvim_buf_get_name(Buffer buffer, Error *err) /// Sets the full file name for a buffer /// -/// @param buffer The buffer handle -/// @param name The buffer name -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param name Buffer name +/// @param[out] err Error details, if any void nvim_buf_set_name(Buffer buffer, String name, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -603,7 +603,7 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err) /// Checks if a buffer is valid /// -/// @param buffer The buffer handle +/// @param buffer Buffer handle /// @return true if the buffer is valid, false otherwise Boolean nvim_buf_is_valid(Buffer buffer) { @@ -615,11 +615,11 @@ Boolean nvim_buf_is_valid(Buffer buffer) /// /// @deprecated use nvim_buf_set_lines(buffer, lnum, lnum, true, lines) /// -/// @param buffer The buffer handle -/// @param lnum Insert the lines after `lnum`. If negative, it will append -/// to the end of the buffer. -/// @param lines An array of lines -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param lnum Insert the lines after `lnum`. If negative, appends to +/// the end of the buffer. +/// @param lines Array of lines +/// @param[out] err Error details, if any void buffer_insert(Buffer buffer, Integer lnum, ArrayOf(String) lines, @@ -632,10 +632,10 @@ void buffer_insert(Buffer buffer, /// Return a tuple (row,col) representing the position of the named mark /// -/// @param buffer The buffer handle -/// @param name The mark's name -/// @param[out] err Details of an error that may have occurred -/// @return The (row, col) tuple +/// @param buffer Buffer handle +/// @param name Mark name +/// @param[out] err Error details, if any +/// @return (row, col) tuple ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) { Array rv = ARRAY_DICT_INIT; @@ -694,15 +694,15 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) /// request an unique src_id at initialization, and later asynchronously add and /// clear highlights in response to buffer changes. /// -/// @param buffer The buffer handle -/// @param src_id Source group to use or 0 to use a new group, -/// or -1 for ungrouped highlight -/// @param hl_group Name of the highlight group to use -/// @param line The line to highlight -/// @param col_start Start of range of columns to highlight -/// @param col_end End of range of columns to highlight, -/// or -1 to highlight to end of line -/// @param[out] err Details of an error that may have occurred +/// @param buffer Buffer handle +/// @param src_id Source group to use or 0 to use a new group, +/// or -1 for ungrouped highlight +/// @param hl_group Name of the highlight group to use +/// @param line Line to highlight +/// @param col_start Start of range of columns to highlight +/// @param col_end End of range of columns to highlight, +/// or -1 to highlight to end of line +/// @param[out] err Error details, if any /// @return The src_id that was used Integer nvim_buf_add_highlight(Buffer buffer, Integer src_id, @@ -740,12 +740,12 @@ Integer nvim_buf_add_highlight(Buffer buffer, /// To clear a source group in the entire buffer, pass in 1 and -1 to /// line_start and line_end respectively. /// -/// @param buffer The buffer handle -/// @param src_id Highlight source group to clear, or -1 to clear all groups. +/// @param buffer Buffer handle +/// @param src_id Highlight source group to clear, or -1 to clear all. /// @param line_start Start of range of lines to clear -/// @param line_end End of range of lines to clear (exclusive) -/// or -1 to clear to end of file. -/// @param[out] err Details of an error that may have occurred +/// @param line_end End of range of lines to clear (exclusive) or -1 to clear +/// to end of file. +/// @param[out] err Error details, if any void nvim_buf_clear_highlight(Buffer buffer, Integer src_id, Integer line_start, diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index c0ee735d1a..208c3b53c8 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -18,6 +18,7 @@ #include "nvim/map.h" #include "nvim/option.h" #include "nvim/option_defs.h" +#include "nvim/version.h" #include "nvim/eval/typval_encode.h" #include "nvim/lib/kvec.h" @@ -763,6 +764,7 @@ Dictionary api_metadata(void) static Dictionary metadata = ARRAY_DICT_INIT; if (!metadata.size) { + PUT(metadata, "version", DICTIONARY_OBJ(version_dict())); init_function_metadata(&metadata); init_error_type_metadata(&metadata); init_type_metadata(&metadata); diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index fa00988ae3..9e61ec1871 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -11,9 +11,9 @@ /// Gets the windows in a tabpage /// -/// @param tabpage The tabpage -/// @param[out] err Details of an error that may have occurred -/// @return The windows in `tabpage` +/// @param tabpage Tabpage +/// @param[out] err Error details, if any +/// @return List of windows in `tabpage` ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Error *err) { Array rv = ARRAY_DICT_INIT; @@ -39,10 +39,10 @@ ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Error *err) /// Gets a tab-scoped (t:) variable /// -/// @param tabpage The tab page handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The variable value +/// @param tabpage Tabpage handle +/// @param name Variable name +/// @param[out] err Error details, if any +/// @return Variable value Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err) { tabpage_T *tab = find_tab_by_handle(tabpage, err); @@ -56,10 +56,10 @@ Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err) /// Sets a tab-scoped (t:) variable /// -/// @param tabpage handle -/// @param name The variable name -/// @param value The variable value -/// @param[out] err Details of an error that may have occurred +/// @param tabpage Tabpage handle +/// @param name Variable name +/// @param value Variable value +/// @param[out] err Error details, if any void nvim_tabpage_set_var(Tabpage tabpage, String name, Object value, @@ -76,9 +76,9 @@ void nvim_tabpage_set_var(Tabpage tabpage, /// Removes a tab-scoped (t:) variable /// -/// @param tabpage handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred +/// @param tabpage Tabpage handle +/// @param name Variable name +/// @param[out] err Error details, if any void nvim_tabpage_del_var(Tabpage tabpage, String name, Error *err) { tabpage_T *tab = find_tab_by_handle(tabpage, err); @@ -94,11 +94,11 @@ void nvim_tabpage_del_var(Tabpage tabpage, String name, Error *err) /// /// @deprecated /// -/// @param tabpage handle -/// @param name The variable name -/// @param value The variable value -/// @param[out] err Details of an error that may have occurred -/// @return The old value or nil if there was no previous value. +/// @param tabpage Tabpage handle +/// @param name Variable name +/// @param value Variable value +/// @param[out] err Error details, if any +/// @return Old value or nil if there was no previous value. /// /// @warning It may return nil if there was no previous value /// or if previous value was `v:null`. @@ -117,10 +117,10 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err) /// /// @deprecated /// -/// @param tabpage handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The old value +/// @param tabpage Tabpage handle +/// @param name Variable name +/// @param[out] err Error details, if any +/// @return Old value Object tabpage_del_var(Tabpage tabpage, String name, Error *err) { tabpage_T *tab = find_tab_by_handle(tabpage, err); @@ -132,11 +132,11 @@ Object tabpage_del_var(Tabpage tabpage, String name, Error *err) return dict_set_value(tab->tp_vars, name, NIL, true, true, err); } -/// Gets the current window in a tab page +/// Gets the current window in a tabpage /// -/// @param tabpage The tab page handle -/// @param[out] err Details of an error that may have occurred -/// @return The Window handle +/// @param tabpage Tabpage handle +/// @param[out] err Error details, if any +/// @return Window handle Window nvim_tabpage_get_win(Tabpage tabpage, Error *err) { Window rv = 0; @@ -159,11 +159,11 @@ Window nvim_tabpage_get_win(Tabpage tabpage, Error *err) } } -/// Gets the tab page number +/// Gets the tabpage number /// -/// @param tabpage The tabpage handle -/// @param[out] err Details of an error that may have occurred -/// @return The tabpage number +/// @param tabpage Tabpage handle +/// @param[out] err Error details, if any +/// @return Tabpage number Integer nvim_tabpage_get_number(Tabpage tabpage, Error *err) { Integer rv = 0; @@ -176,10 +176,10 @@ Integer nvim_tabpage_get_number(Tabpage tabpage, Error *err) return tabpage_index(tab); } -/// Checks if a tab page is valid +/// Checks if a tabpage is valid /// -/// @param tabpage The tab page handle -/// @return true if the tab page is valid, false otherwise +/// @param tabpage Tabpage handle +/// @return true if the tabpage is valid, false otherwise Boolean nvim_tabpage_is_valid(Tabpage tabpage) { Error stub = ERROR_INIT; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9f3a84c88b..491375bd73 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -33,24 +33,26 @@ # include "api/vim.c.generated.h" #endif -/// Executes an ex-mode command str +/// Executes an ex-command. +/// On VimL error: Returns the VimL error; v:errmsg is not updated. /// -/// @param str The command str -/// @param[out] err Details of an error that may have occurred -void nvim_command(String str, Error *err) +/// @param command Ex-command string +/// @param[out] err Error details (including actual VimL error), if any +void nvim_command(String command, Error *err) { // Run the command try_start(); - do_cmdline_cmd(str.data); + do_cmdline_cmd(command.data); update_screen(VALID); try_end(err); } -/// Passes input keys to Neovim +/// Passes input keys to Nvim. +/// On VimL error: Does not fail, but updates v:errmsg. /// -/// @param keys to be typed -/// @param mode specifies the mapping options -/// @param escape_csi the string needs escaping for K_SPECIAL/CSI bytes +/// @param keys to be typed +/// @param mode mapping options +/// @param escape_csi If true, escape K_SPECIAL/CSI bytes in `keys` /// @see feedkeys() /// @see vim_strsave_escape_csi void nvim_feedkeys(String keys, String mode, Boolean escape_csi) @@ -102,13 +104,15 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi) } } -/// Passes input keys to Neovim. Unlike `nvim_feedkeys`, this will use a -/// lower-level input buffer and the call is not deferred. -/// This is the most reliable way to emulate real user input. +/// Passes keys to Nvim as raw user-input. +/// On VimL error: Does not fail, but updates v:errmsg. +/// +/// Unlike `nvim_feedkeys`, this uses a lower-level input buffer and the call +/// is not deferred. This is the most reliable way to emulate real user input. /// /// @param keys to be typed -/// @return The number of bytes actually written, which can be lower than -/// requested if the buffer becomes full. +/// @return Number of bytes actually written (can be fewer than +/// requested if the buffer becomes full). Integer nvim_input(String keys) FUNC_API_ASYNC { @@ -152,19 +156,19 @@ String nvim_command_output(String str, Error *err) return cstr_to_string((char *)get_vim_var_str(VV_COMMAND_OUTPUT)); } -/// Evaluates the expression str using the Vim internal expression -/// evaluator (see |expression|). -/// Dictionaries and lists are recursively expanded. +/// Evaluates a VimL expression (:help expression). +/// Dictionaries and Lists are recursively expanded. +/// On VimL error: Returns a generic error; v:errmsg is not updated. /// -/// @param str The expression str -/// @param[out] err Details of an error that may have occurred -/// @return The expanded object -Object nvim_eval(String str, Error *err) +/// @param expr VimL expression string +/// @param[out] err Error details, if any +/// @return Evaluation result or expanded object +Object nvim_eval(String expr, Error *err) { Object rv = OBJECT_INIT; // Evaluate the expression try_start(); - typval_T *expr_result = eval_expr((char_u *) str.data, NULL); + typval_T *expr_result = eval_expr((char_u *)expr.data, NULL); if (!expr_result) { api_set_error(err, Exception, _("Failed to evaluate expression")); @@ -180,11 +184,12 @@ Object nvim_eval(String str, Error *err) return rv; } -/// Call the given function with the given arguments stored in an array. +/// Calls a VimL function with the given arguments. +/// On VimL error: Returns a generic error; v:errmsg is not updated. /// -/// @param fname Function to call -/// @param args Functions arguments packed in an Array -/// @param[out] err Details of an error that may have occurred +/// @param fname Function to call +/// @param args Function arguments packed in an Array +/// @param[out] err Error details, if any /// @return Result of the function call Object nvim_call_function(String fname, Array args, Error *err) { @@ -229,12 +234,12 @@ free_vim_args: return rv; } -/// Calculates the number of display cells `str` occupies, tab is counted as -/// one cell. +/// Calculates the number of display cells occupied by `text`. +/// <Tab> counts as one cell. /// -/// @param str Some text -/// @param[out] err Details of an error that may have occurred -/// @return The number of cells +/// @param text Some text +/// @param[out] err Error details, if any +/// @return Number of cells Integer nvim_strwidth(String str, Error *err) { if (str.size > INT_MAX) { @@ -245,9 +250,9 @@ Integer nvim_strwidth(String str, Error *err) return (Integer) mb_string2cells((char_u *) str.data); } -/// Gets a list of paths contained in 'runtimepath' +/// Gets the paths contained in 'runtimepath'. /// -/// @return The list of paths +/// @return List of paths ArrayOf(String) nvim_list_runtime_paths(void) { Array rv = ARRAY_DICT_INIT; @@ -285,10 +290,10 @@ ArrayOf(String) nvim_list_runtime_paths(void) return rv; } -/// Changes Vim working directory +/// Changes the global working directory. /// -/// @param dir The new working directory -/// @param[out] err Details of an error that may have occurred +/// @param dir Directory path +/// @param[out] err Error details, if any void nvim_set_current_dir(String dir, Error *err) { if (dir.size >= MAXPATHL) { @@ -315,8 +320,8 @@ void nvim_set_current_dir(String dir, Error *err) /// Gets the current line /// -/// @param[out] err Details of an error that may have occurred -/// @return The current line string +/// @param[out] err Error details, if any +/// @return Current line string String nvim_get_current_line(Error *err) { return buffer_get_line(curbuf->handle, curwin->w_cursor.lnum - 1, err); @@ -324,8 +329,8 @@ String nvim_get_current_line(Error *err) /// Sets the current line /// -/// @param line The line contents -/// @param[out] err Details of an error that may have occurred +/// @param line Line contents +/// @param[out] err Error details, if any void nvim_set_current_line(String line, Error *err) { buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, err); @@ -333,36 +338,36 @@ void nvim_set_current_line(String line, Error *err) /// Deletes the current line /// -/// @param[out] err Details of an error that may have occurred +/// @param[out] err Error details, if any void nvim_del_current_line(Error *err) { buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, err); } -/// Gets a global variable +/// Gets a global (g:) variable /// -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The variable value +/// @param name Variable name +/// @param[out] err Error details, if any +/// @return Variable value Object nvim_get_var(String name, Error *err) { return dict_get_value(&globvardict, name, err); } -/// Sets a global variable +/// Sets a global (g:) variable /// -/// @param name The variable name -/// @param value The variable value -/// @param[out] err Details of an error that may have occurred +/// @param name Variable name +/// @param value Variable value +/// @param[out] err Error details, if any void nvim_set_var(String name, Object value, Error *err) { dict_set_value(&globvardict, name, value, false, false, err); } -/// Removes a global variable +/// Removes a global (g:) variable /// -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred +/// @param name Variable name +/// @param[out] err Error details, if any void nvim_del_var(String name, Error *err) { dict_set_value(&globvardict, name, NIL, true, false, err); @@ -372,10 +377,10 @@ void nvim_del_var(String name, Error *err) /// /// @deprecated /// -/// @param name The variable name -/// @param value The variable value -/// @param[out] err Details of an error that may have occurred -/// @return The old value or nil if there was no previous value. +/// @param name Variable name +/// @param value Variable value +/// @param[out] err Error details, if any +/// @return Old value or nil if there was no previous value. /// /// @warning It may return nil if there was no previous value /// or if previous value was `v:null`. @@ -388,19 +393,19 @@ Object vim_set_var(String name, Object value, Error *err) /// /// @deprecated /// -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The old value +/// @param name Variable name +/// @param[out] err Error details, if any +/// @return Old value Object vim_del_var(String name, Error *err) { return dict_set_value(&globvardict, name, NIL, true, true, err); } -/// Gets a vim variable +/// Gets a v: variable /// -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The variable value +/// @param name Variable name +/// @param[out] err Error details, if any +/// @return Variable value Object nvim_get_vvar(String name, Error *err) { return dict_get_value(&vimvardict, name, err); @@ -408,9 +413,9 @@ Object nvim_get_vvar(String name, Error *err) /// Gets an option value string /// -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -/// @return The option value +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value Object nvim_get_option(String name, Error *err) { return get_option_from(NULL, SREQ_GLOBAL, name, err); @@ -418,9 +423,9 @@ Object nvim_get_option(String name, Error *err) /// Sets an option value /// -/// @param name The option name -/// @param value The new option value -/// @param[out] err Details of an error that may have occurred +/// @param name Option name +/// @param value New option value +/// @param[out] err Error details, if any void nvim_set_option(String name, Object value, Error *err) { set_option_to(NULL, SREQ_GLOBAL, name, value, err); @@ -428,7 +433,7 @@ void nvim_set_option(String name, Object value, Error *err) /// Writes a message to vim output buffer /// -/// @param str The message +/// @param str Message void nvim_out_write(String str) { write_msg(str, false); @@ -436,16 +441,17 @@ void nvim_out_write(String str) /// Writes a message to vim error buffer /// -/// @param str The message +/// @param str Message void nvim_err_write(String str) { write_msg(str, true); } -/// Higher level error reporting function that ensures all str contents -/// are written by sending a trailing linefeed to `nvim_err_write` +/// Writes a message to vim error buffer. Appends a linefeed to ensure all +/// contents are written. /// -/// @param str The message +/// @param str Message +/// @see nvim_err_write() void nvim_err_writeln(String str) { nvim_err_write(str); @@ -454,7 +460,7 @@ void nvim_err_writeln(String str) /// Gets the current list of buffer handles /// -/// @return The number of buffers +/// @return List of buffer handles ArrayOf(Buffer) nvim_list_bufs(void) { Array rv = ARRAY_DICT_INIT; @@ -475,7 +481,7 @@ ArrayOf(Buffer) nvim_list_bufs(void) /// Gets the current buffer /// -/// @reqturn The buffer handle +/// @return Buffer handle Buffer nvim_get_current_buf(void) { return curbuf->handle; @@ -483,8 +489,8 @@ Buffer nvim_get_current_buf(void) /// Sets the current buffer /// -/// @param id The buffer handle -/// @param[out] err Details of an error that may have occurred +/// @param id Buffer handle +/// @param[out] err Error details, if any void nvim_set_current_buf(Buffer buffer, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -505,7 +511,7 @@ void nvim_set_current_buf(Buffer buffer, Error *err) /// Gets the current list of window handles /// -/// @return The number of windows +/// @return List of window handles ArrayOf(Window) nvim_list_wins(void) { Array rv = ARRAY_DICT_INIT; @@ -526,7 +532,7 @@ ArrayOf(Window) nvim_list_wins(void) /// Gets the current window /// -/// @return The window handle +/// @return Window handle Window nvim_get_current_win(void) { return curwin->handle; @@ -534,7 +540,7 @@ Window nvim_get_current_win(void) /// Sets the current window /// -/// @param handle The window handle +/// @param handle Window handle void nvim_set_current_win(Window window, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -555,7 +561,7 @@ void nvim_set_current_win(Window window, Error *err) /// Gets the current list of tabpage handles /// -/// @return The number of tab pages +/// @return List of tabpage handles ArrayOf(Tabpage) nvim_list_tabpages(void) { Array rv = ARRAY_DICT_INIT; @@ -574,18 +580,18 @@ ArrayOf(Tabpage) nvim_list_tabpages(void) return rv; } -/// Gets the current tab page +/// Gets the current tabpage /// -/// @return The tab page handle +/// @return Tabpage handle Tabpage nvim_get_current_tabpage(void) { return curtab->handle; } -/// Sets the current tab page +/// Sets the current tabpage /// -/// @param handle The tab page handle -/// @param[out] err Details of an error that may have occurred +/// @param handle Tabpage handle +/// @param[out] err Error details, if any void nvim_set_current_tabpage(Tabpage tabpage, Error *err) { tabpage_T *tp = find_tab_by_handle(tabpage, err); @@ -606,8 +612,8 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) /// Subscribes to event broadcasts /// -/// @param channel_id The channel id (passed automatically by the dispatcher) -/// @param event The event type string +/// @param channel_id Channel id (passed automatically by the dispatcher) +/// @param event Event type string void nvim_subscribe(uint64_t channel_id, String event) FUNC_API_NOEVAL { @@ -620,8 +626,8 @@ void nvim_subscribe(uint64_t channel_id, String event) /// Unsubscribes to event broadcasts /// -/// @param channel_id The channel id (passed automatically by the dispatcher) -/// @param event The event type string +/// @param channel_id Channel id (passed automatically by the dispatcher) +/// @param event Event type string void nvim_unsubscribe(uint64_t channel_id, String event) FUNC_API_NOEVAL { @@ -756,9 +762,8 @@ validation_error: /// and flushed after each newline. Incomplete lines are kept for writing /// later. /// -/// @param message The message to write -/// @param to_err true if it should be treated as an error message (use -/// `emsg` instead of `msg` to print each line) +/// @param message Message to write +/// @param to_err true: message is an error (uses `emsg` instead of `msg`) static void write_msg(String message, bool to_err) { static size_t out_pos = 0, err_pos = 0; diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 382f65e7d9..ef881fa0eb 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -15,9 +15,9 @@ /// Gets the current buffer in a window /// -/// @param window The window handle -/// @param[out] err Details of an error that may have occurred -/// @return The buffer handle +/// @param window Window handle +/// @param[out] err Error details, if any +/// @return Buffer handle Buffer nvim_win_get_buf(Window window, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -31,9 +31,9 @@ Buffer nvim_win_get_buf(Window window, Error *err) /// Gets the cursor position in the window /// -/// @param window The window handle -/// @param[out] err Details of an error that may have occurred -/// @return the (row, col) tuple +/// @param window Window handle +/// @param[out] err Error details, if any +/// @return (row, col) tuple ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err) { Array rv = ARRAY_DICT_INIT; @@ -49,9 +49,9 @@ ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err) /// Sets the cursor position in the window /// -/// @param window The window handle -/// @param pos the (row, col) tuple representing the new position -/// @param[out] err Details of an error that may have occurred +/// @param window Window handle +/// @param pos (row, col) tuple representing the new position +/// @param[out] err Error details, if any void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -95,9 +95,9 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) /// Gets the window height /// -/// @param window The window handle -/// @param[out] err Details of an error that may have occurred -/// @return the height in rows +/// @param window Window handle +/// @param[out] err Error details, if any +/// @return Height as a count of rows Integer nvim_win_get_height(Window window, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -112,9 +112,9 @@ Integer nvim_win_get_height(Window window, Error *err) /// Sets the window height. This will only succeed if the screen is split /// horizontally. /// -/// @param window The window handle -/// @param height the new height in rows -/// @param[out] err Details of an error that may have occurred +/// @param window Window handle +/// @param height Height as a count of rows +/// @param[out] err Error details, if any void nvim_win_set_height(Window window, Integer height, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -138,9 +138,9 @@ void nvim_win_set_height(Window window, Integer height, Error *err) /// Gets the window width /// -/// @param window The window handle -/// @param[out] err Details of an error that may have occurred -/// @return the width in columns +/// @param window Window handle +/// @param[out] err Error details, if any +/// @return Width as a count of columns Integer nvim_win_get_width(Window window, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -155,9 +155,9 @@ Integer nvim_win_get_width(Window window, Error *err) /// Sets the window width. This will only succeed if the screen is split /// vertically. /// -/// @param window The window handle -/// @param width the new width in columns -/// @param[out] err Details of an error that may have occurred +/// @param window Window handle +/// @param width Width as a count of columns +/// @param[out] err Error details, if any void nvim_win_set_width(Window window, Integer width, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -181,10 +181,10 @@ void nvim_win_set_width(Window window, Integer width, Error *err) /// Gets a window-scoped (w:) variable /// -/// @param window The window handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The variable value +/// @param window Window handle +/// @param name Variable name +/// @param[out] err Error details, if any +/// @return Variable value Object nvim_win_get_var(Window window, String name, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -198,10 +198,10 @@ Object nvim_win_get_var(Window window, String name, Error *err) /// Sets a window-scoped (w:) variable /// -/// @param window The window handle -/// @param name The variable name -/// @param value The variable value -/// @param[out] err Details of an error that may have occurred +/// @param window Window handle +/// @param name Variable name +/// @param value Variable value +/// @param[out] err Error details, if any void nvim_win_set_var(Window window, String name, Object value, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -215,9 +215,9 @@ void nvim_win_set_var(Window window, String name, Object value, Error *err) /// Removes a window-scoped (w:) variable /// -/// @param window The window handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred +/// @param window Window handle +/// @param name Variable name +/// @param[out] err Error details, if any void nvim_win_del_var(Window window, String name, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -233,11 +233,11 @@ void nvim_win_del_var(Window window, String name, Error *err) /// /// @deprecated /// -/// @param window The window handle -/// @param name The variable name -/// @param value The variable value -/// @param[out] err Details of an error that may have occurred -/// @return The old value or nil if there was no previous value. +/// @param window Window handle +/// @param name Variable name +/// @param value Variable value +/// @param[out] err Error details, if any +/// @return Old value or nil if there was no previous value. /// /// @warning It may return nil if there was no previous value /// or if previous value was `v:null`. @@ -256,10 +256,10 @@ Object window_set_var(Window window, String name, Object value, Error *err) /// /// @deprecated /// -/// @param window The window handle -/// @param name The variable name -/// @param[out] err Details of an error that may have occurred -/// @return The old value +/// @param window Window handle +/// @param name variable name +/// @param[out] err Error details, if any +/// @return Old value Object window_del_var(Window window, String name, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -273,10 +273,10 @@ Object window_del_var(Window window, String name, Error *err) /// Gets a window option value /// -/// @param window The window handle -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -/// @return The option value +/// @param window Window handle +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value Object nvim_win_get_option(Window window, String name, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -291,10 +291,10 @@ Object nvim_win_get_option(Window window, String name, Error *err) /// Sets a window option value. Passing 'nil' as value deletes the option(only /// works if there's a global fallback) /// -/// @param window The window handle -/// @param name The option name -/// @param value The option value -/// @param[out] err Details of an error that may have occurred +/// @param window Window handle +/// @param name Option name +/// @param value Option value +/// @param[out] err Error details, if any void nvim_win_set_option(Window window, String name, Object value, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -308,9 +308,9 @@ void nvim_win_set_option(Window window, String name, Object value, Error *err) /// Gets the window position in display cells. First position is zero. /// -/// @param window The window handle -/// @param[out] err Details of an error that may have occurred -/// @return The (row, col) tuple with the window position +/// @param window Window handle +/// @param[out] err Error details, if any +/// @return (row, col) tuple with the window position ArrayOf(Integer, 2) nvim_win_get_position(Window window, Error *err) { Array rv = ARRAY_DICT_INIT; @@ -324,11 +324,11 @@ ArrayOf(Integer, 2) nvim_win_get_position(Window window, Error *err) return rv; } -/// Gets the window tab page +/// Gets the window tabpage /// -/// @param window The window handle -/// @param[out] err Details of an error that may have occurred -/// @return The tab page that contains the window +/// @param window Window handle +/// @param[out] err Error details, if any +/// @return Tabpage that contains the window Tabpage nvim_win_get_tabpage(Window window, Error *err) { Tabpage rv = 0; @@ -343,9 +343,9 @@ Tabpage nvim_win_get_tabpage(Window window, Error *err) /// Gets the window number /// -/// @param window The window handle -/// @param[out] err Details of an error that may have occurred -/// @return The window number +/// @param window Window handle +/// @param[out] err Error details, if any +/// @return Window number Integer nvim_win_get_number(Window window, Error *err) { Integer rv = 0; @@ -363,7 +363,7 @@ Integer nvim_win_get_number(Window window, Error *err) /// Checks if a window is valid /// -/// @param window The window handle +/// @param window Window handle /// @return true if the window is valid, false otherwise Boolean nvim_win_is_valid(Window window) { diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 5fb011885e..a66fdc1304 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -323,13 +323,14 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last) wipe_buf = true; } - if (win_valid(win)) { - /* Set b_last_cursor when closing the last window for the buffer. - * Remember the last cursor position and window options of the buffer. - * This used to be only for the current window, but then options like - * 'foldmethod' may be lost with a ":only" command. */ - if (buf->b_nwindows == 1) + if (win_valid_any_tab(win)) { + // Set b_last_cursor when closing the last window for the buffer. + // Remember the last cursor position and window options of the buffer. + // This used to be only for the current window, but then options like + // 'foldmethod' may be lost with a ":only" command. + if (buf->b_nwindows == 1) { set_last_cursor(win); + } buflist_setfpos(buf, win, win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum, win->w_cursor.col, TRUE); @@ -402,7 +403,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last) buf->b_nwindows = nwindows; buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0)); - if (win_valid(win) && win->w_buffer == buf) { + if (win_valid_any_tab(win) && win->w_buffer == buf) { win->w_buffer = NULL; // make sure we don't use the buffer now } @@ -478,17 +479,20 @@ void buf_clear_file(buf_T *buf) buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */ } -/* - * buf_freeall() - free all things allocated for a buffer that are related to - * the file. flags: - * BFA_DEL buffer is going to be deleted - * BFA_WIPE buffer is going to be wiped out - * BFA_KEEP_UNDO do not free undo information - */ +/// buf_freeall() - free all things allocated for a buffer that are related to +/// the file. Careful: get here with "curwin" NULL when exiting. +/// +/// @param flags BFA_DEL buffer is going to be deleted +/// BFA_WIPE buffer is going to be wiped out +/// BFA_KEEP_UNDO do not free undo information void buf_freeall(buf_T *buf, int flags) { bool is_curbuf = (buf == curbuf); + int is_curwin = (curwin != NULL && curwin->w_buffer == buf); + win_T *the_curwin = curwin; + tabpage_T *the_curtab = curtab; + // Make sure the buffer isn't closed by autocommands. buf->b_closing = true; apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, FALSE, buf); if (!buf_valid(buf)) /* autocommands may delete the buffer */ @@ -505,8 +509,18 @@ void buf_freeall(buf_T *buf, int flags) return; } buf->b_closing = false; - if (aborting()) /* autocmds may abort script processing */ + + // If the buffer was in curwin and the window has changed, go back to that + // window, if it still exists. This avoids that ":edit x" triggering a + // "tabnext" BufUnload autocmd leaves a window behind without a buffer. + if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) { + block_autocmds(); + goto_tabpage_win(the_curtab, the_curwin); + unblock_autocmds(); + } + if (aborting()) { // autocmds may abort script processing return; + } /* * It's possible that autocommands change curbuf to the one being deleted. @@ -4509,7 +4523,7 @@ chk_modeline ( char_u *e; char_u *linecopy; /* local copy of any modeline found */ int prev; - int vers; + intmax_t vers; int end; int retval = OK; char_u *save_sourcing_name; @@ -4528,7 +4542,10 @@ chk_modeline ( e = s + 4; else e = s + 3; - vers = getdigits_int(&e); + if (getdigits_safe(&e, &vers) != OK) { + continue; + } + if (*e == ':' && (s[0] != 'V' || STRNCMP(skipwhite(e + 1), "set", 3) == 0) @@ -4536,8 +4553,9 @@ chk_modeline ( || (VIM_VERSION_100 >= vers && isdigit(s[3])) || (VIM_VERSION_100 < vers && s[3] == '<') || (VIM_VERSION_100 > vers && s[3] == '>') - || (VIM_VERSION_100 == vers && s[3] == '='))) + || (VIM_VERSION_100 == vers && s[3] == '='))) { break; + } } } prev = *s; diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 78f5d96fc7..61c5b10808 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1732,6 +1732,26 @@ char_u* skiptowhite_esc(char_u *p) { return p; } +/// Get a number from a string and skip over it, signalling overflows +/// +/// @param[out] pp A pointer to a pointer to char_u. +/// It will be advanced past the read number. +/// @param[out] nr Number read from the string. +/// +/// @return OK on success, FAIL on error/overflow +int getdigits_safe(char_u **pp, intmax_t *nr) +{ + errno = 0; + *nr = strtoimax((char *)(*pp), (char **)pp, 10); + + if ((*nr == INTMAX_MIN || *nr == INTMAX_MAX) + && errno == ERANGE) { + return FAIL; + } + + return OK; +} + /// Get a number from a string and skip over it. /// /// @param[out] pp A pointer to a pointer to char_u. @@ -1740,17 +1760,16 @@ char_u* skiptowhite_esc(char_u *p) { /// @return Number read from the string. intmax_t getdigits(char_u **pp) { - errno = 0; - intmax_t number = strtoimax((char *)*pp, (char **)pp, 10); - if (number == INTMAX_MAX || number == INTMAX_MIN) { - assert(errno != ERANGE); - } + intmax_t number; + int ret = getdigits_safe(pp, &number); + + (void)ret; // Avoid "unused variable" warning in Release build + assert(ret == OK); + return number; } -/// Get an int number from a string. -/// -/// A getdigits wrapper restricted to int values. +/// Get an int number from a string. Like getdigits(), but restricted to `int`. int getdigits_int(char_u **pp) { intmax_t number = getdigits(pp); @@ -1760,9 +1779,7 @@ int getdigits_int(char_u **pp) return (int)number; } -/// Get a long number from a string. -/// -/// A getdigits wrapper restricted to long values. +/// Get a long number from a string. Like getdigits(), but restricted to `long`. long getdigits_long(char_u **pp) { intmax_t number = getdigits(pp); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4eb3b36464..5d4241c8af 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10524,16 +10524,10 @@ static void f_glob2regpat(typval_T *argvars, typval_T *rettv, FunPtr fptr) : file_pat_to_reg_pat(pat, NULL, NULL, false); } -/* - * "has()" function - */ +/// "has()" function static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - int i; - char_u *name; - int n = FALSE; - static char *(has_list[]) = - { + static char *(has_list[]) = { #ifdef UNIX "unix", #endif @@ -10646,36 +10640,42 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) NULL }; - name = get_tv_string(&argvars[0]); - for (i = 0; has_list[i] != NULL; ++i) + bool n = false; + char *name = (char *)get_tv_string(&argvars[0]); + + for (int i = 0; has_list[i] != NULL; i++) { if (STRICMP(name, has_list[i]) == 0) { - n = TRUE; + n = true; break; } + } - if (n == FALSE) { + if (!n) { if (STRNICMP(name, "patch", 5) == 0) { if (name[5] == '-' - && STRLEN(name) > 11 + && strlen(name) > 11 && ascii_isdigit(name[6]) && ascii_isdigit(name[8]) && ascii_isdigit(name[10])) { - int major = atoi((char *)name + 6); - int minor = atoi((char *)name + 8); + int major = atoi(name + 6); + int minor = atoi(name + 8); // Expect "patch-9.9.01234". n = (major < VIM_VERSION_MAJOR || (major == VIM_VERSION_MAJOR && (minor < VIM_VERSION_MINOR || (minor == VIM_VERSION_MINOR - && has_patch(atoi((char *)name + 10)))))); + && has_vim_patch(atoi(name + 10)))))); } else { - n = has_patch(atoi((char *)name + 5)); + n = has_vim_patch(atoi(name + 5)); } + } else if (STRNICMP(name, "nvim-", 5) == 0) { + // Expect "nvim-x.y.z" + n = has_nvim_version(name + 5); } else if (STRICMP(name, "vim_starting") == 0) { n = (starting != 0); } else if (STRICMP(name, "multi_byte_encoding") == 0) { - n = has_mbyte; + n = has_mbyte != 0; #if defined(USE_ICONV) && defined(DYNAMIC_ICONV) } else if (STRICMP(name, "iconv") == 0) { n = iconv_enabled(false); @@ -10685,8 +10685,8 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - if (n == FALSE && eval_has_provider((char *)name)) { - n = TRUE; + if (!n && eval_has_provider(name)) { + n = true; } rettv->vval.v_number = n; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 6205daf0cb..4674460a16 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2250,28 +2250,28 @@ do_ecmd ( xfree(new_name); goto theend; } - if (buf == curbuf) /* already in new buffer */ - auto_buf = TRUE; - else { - if (curbuf == old_curbuf) + if (buf == curbuf) { // already in new buffer + auto_buf = true; + } else { + win_T *the_curwin = curwin; + + // Set the w_closing flag to avoid that autocommands close the window. + the_curwin->w_closing = true; + if (curbuf == old_curbuf) { buf_copy_options(buf, BCO_ENTER); + } - /* close the link to the current buffer */ - u_sync(FALSE); + // Close the link to the current buffer. This will set + // curwin->w_buffer to NULL. + u_sync(false); close_buffer(oldwin, curbuf, - (flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD, FALSE); - - /* Autocommands may open a new window and leave oldwin open - * which leads to crashes since the above call sets - * oldwin->w_buffer to NULL. */ - if (curwin != oldwin && oldwin != aucmd_win && win_valid(oldwin)) { - assert(oldwin); - if (oldwin->w_buffer == NULL) { - win_close(oldwin, FALSE); - } - } + (flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD, + false); + + the_curwin->w_closing = false; - if (aborting()) { /* autocmds may abort script processing */ + // autocmds may abort script processing + if (aborting() && curwin->w_buffer != NULL) { xfree(new_name); goto theend; } @@ -2370,10 +2370,12 @@ do_ecmd ( if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) { /* Save all the text, so that the reload can be undone. * Sync first so that this is a separate undo-able action. */ - u_sync(FALSE); - if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE) - == FAIL) + u_sync(false); + if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, true) + == FAIL) { + xfree(new_name); goto theend; + } u_unchanged(curbuf); buf_freeall(curbuf, BFA_KEEP_UNDO); @@ -4072,61 +4074,66 @@ void ex_global(exarg_T *eap) vim_regfree(regmatch.regprog); } -/* - * Execute "cmd" on lines marked with ml_setmarked(). - */ +/// Execute `cmd` on lines marked with ml_setmarked(). void global_exe(char_u *cmd) { - linenr_T old_lcount; /* b_ml.ml_line_count before the command */ - buf_T *old_buf = curbuf; /* remember what buffer we started in */ - linenr_T lnum; /* line number according to old situation */ - - /* - * Set current position only once for a global command. - * If global_busy is set, setpcmark() will not do anything. - * If there is an error, global_busy will be incremented. - */ + linenr_T old_lcount; // b_ml.ml_line_count before the command + buf_T *old_buf = curbuf; // remember what buffer we started in + linenr_T lnum; // line number according to old situation + int save_mapped_ctrl_c = mapped_ctrl_c; + + // Set current position only once for a global command. + // If global_busy is set, setpcmark() will not do anything. + // If there is an error, global_busy will be incremented. setpcmark(); - /* When the command writes a message, don't overwrite the command. */ - msg_didout = TRUE; + // When the command writes a message, don't overwrite the command. + msg_didout = true; + // Disable CTRL-C mapping, let it interrupt (potentially long output). + mapped_ctrl_c = 0; sub_nsubs = 0; sub_nlines = 0; - global_need_beginline = FALSE; + global_need_beginline = false; global_busy = 1; old_lcount = curbuf->b_ml.ml_line_count; + while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1) { curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = 0; - if (*cmd == NUL || *cmd == '\n') + if (*cmd == NUL || *cmd == '\n') { do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT); - else + } else { do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT); + } os_breakcheck(); } + mapped_ctrl_c = save_mapped_ctrl_c; global_busy = 0; - if (global_need_beginline) + if (global_need_beginline) { beginline(BL_WHITE | BL_FIX); - else - check_cursor(); /* cursor may be beyond the end of the line */ + } else { + check_cursor(); // cursor may be beyond the end of the line + } - /* the cursor may not have moved in the text but a change in a previous - * line may move it on the screen */ + // the cursor may not have moved in the text but a change in a previous + // line may move it on the screen changed_line_abv_curs(); - /* If it looks like no message was written, allow overwriting the - * command with the report for number of changes. */ - if (msg_col == 0 && msg_scrolled == 0) - msg_didout = FALSE; + // If it looks like no message was written, allow overwriting the + // command with the report for number of changes. + if (msg_col == 0 && msg_scrolled == 0) { + msg_didout = false; + } - /* If substitutes done, report number of substitutes, otherwise report - * number of extra or deleted lines. - * Don't report extra or deleted lines in the edge case where the buffer - * we are in after execution is different from the buffer we started in. */ - if (!do_sub_msg(false) && curbuf == old_buf) + // If substitutes done, report number of substitutes, otherwise report + // number of extra or deleted lines. + // Don't report extra or deleted lines in the edge case where the buffer + // we are in after execution is different from the buffer we started in. + if (!do_sub_msg(false) && curbuf == old_buf) { msgmore(curbuf->b_ml.ml_line_count - old_lcount); + } } #if defined(EXITFREE) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 9f83688e1e..5e418bf099 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1302,8 +1302,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, * 2. Handle command modifiers. */ p = ea.cmd; - if (ascii_isdigit(*ea.cmd)) - p = skipwhite(skipdigits(ea.cmd)); + p = skip_range(ea.cmd, NULL); switch (*p) { /* When adding an entry, also modify cmd_exists(). */ case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3)) @@ -1406,12 +1405,18 @@ static char_u * do_one_cmd(char_u **cmdlinep, continue; case 't': if (checkforcmd(&p, "tab", 3)) { - if (ascii_isdigit(*ea.cmd)) - cmdmod.tab = atoi((char *)ea.cmd) + 1; - else - cmdmod.tab = tabpage_index(curtab) + 1; - ea.cmd = p; - continue; + long tabnr = get_address(&ea, &ea.cmd, ADDR_TABS, ea.skip, false); + if (tabnr == MAXLNUM) { + cmdmod.tab = tabpage_index(curtab) + 1; + } else { + if (tabnr < 0 || tabnr > LAST_TAB_NR) { + errormsg = (char_u *)_(e_invrange); + goto doend; + } + cmdmod.tab = tabnr + 1; + } + ea.cmd = p; + continue; } if (!checkforcmd(&ea.cmd, "topleft", 2)) break; @@ -1766,11 +1771,8 @@ static char_u * do_one_cmd(char_u **cmdlinep, if (text_locked() && !(ea.argt & CMDWIN) && !IS_USER_CMDIDX(ea.cmdidx)) { - /* Command not allowed when editing the command line. */ - if (cmdwin_type != 0) - errormsg = (char_u *)_(e_cmdwin); - else - errormsg = (char_u *)_(e_secure); + // Command not allowed when editing the command line. + errormsg = get_text_locked_msg(); goto doend; } /* Disallow editing another buffer when "curbuf_lock" is set. diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 7444eb8a38..e525c949bd 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1688,10 +1688,15 @@ int text_locked(void) { */ void text_locked_msg(void) { - if (cmdwin_type != 0) - EMSG(_(e_cmdwin)); - else - EMSG(_(e_secure)); + EMSG(_(get_text_locked_msg())); +} + +char_u * get_text_locked_msg(void) { + if (cmdwin_type != 0) { + return e_cmdwin; + } else { + return e_secure; + } } /* diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index e085b973ea..fdfcd1f428 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -397,10 +397,11 @@ EXTERN char_u *p_dir; /* 'directory' */ EXTERN char_u *p_dy; /* 'display' */ EXTERN unsigned dy_flags; #ifdef IN_OPTION_C -static char *(p_dy_values[]) = {"lastline", "uhex", NULL}; +static char *(p_dy_values[]) = { "lastline", "truncate", "uhex", NULL }; #endif #define DY_LASTLINE 0x001 -#define DY_UHEX 0x002 +#define DY_TRUNCATE 0x002 +#define DY_UHEX 0x004 EXTERN int p_ed; // 'edcompatible' EXTERN bool p_emoji; // 'emoji' EXTERN char_u *p_ead; // 'eadirection' diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 47dd640e59..3e4d016fe7 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1401,7 +1401,7 @@ static void win_update(win_T *wp) && wp->w_lines[idx].wl_valid && wp->w_lines[idx].wl_lnum == lnum && lnum > wp->w_topline - && !(dy_flags & DY_LASTLINE) + && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) && srow + wp->w_lines[idx].wl_size > wp->w_height && diff_check_fill(wp, lnum) == 0 ) { @@ -1484,10 +1484,20 @@ static void win_update(win_T *wp) /* Window ends in filler lines. */ wp->w_botline = lnum; wp->w_filler_rows = wp->w_height - srow; - } else if (dy_flags & DY_LASTLINE) { /* 'display' has "lastline" */ - /* - * Last line isn't finished: Display "@@@" at the end. - */ + } else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate" + int scr_row = wp->w_winrow + wp->w_height - 1; + + // Last line isn't finished: Display "@@@" in the last screen line. + screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol, + hl_attr(HLF_AT)); + + screen_fill(scr_row, scr_row + 1, + (int)wp->w_wincol + 2, (int)W_ENDCOL(wp), + '@', ' ', hl_attr(HLF_AT)); + set_empty_rows(wp, srow); + wp->w_botline = lnum; + } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" + // Last line isn't finished: Display "@@@" at the end. screen_fill(wp->w_winrow + wp->w_height - 1, wp->w_winrow + wp->w_height, W_ENDCOL(wp) - 3, W_ENDCOL(wp), diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 6fd7603629..b49ae9da21 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5537,7 +5537,7 @@ void ex_ownsyntax(exarg_T *eap) } } -int syntax_present(win_T *win) +bool syntax_present(win_T *win) { return win->w_s->b_syn_patterns.ga_len != 0 || win->w_s->b_syn_clusters.ga_len != 0 diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim index e6b85d6e14..0bf7d056de 100644 --- a/src/nvim/testdir/test_tabpage.vim +++ b/src/nvim/testdir/test_tabpage.vim @@ -186,4 +186,62 @@ function Test_tabpage_with_autocmd() bw! endfunction +function Test_tabpage_with_tab_modifier() + for n in range(4) + tabedit + endfor + + function s:check_tab(pre_nr, cmd, post_nr) + exec 'tabnext ' . a:pre_nr + exec a:cmd + call assert_equal(a:post_nr, tabpagenr()) + call assert_equal('help', &filetype) + helpclose + endfunc + + call s:check_tab(1, 'tab help', 2) + call s:check_tab(1, '3tab help', 4) + call s:check_tab(1, '.tab help', 2) + call s:check_tab(1, '.+1tab help', 3) + call s:check_tab(1, '0tab help', 1) + call s:check_tab(2, '+tab help', 4) + call s:check_tab(2, '+2tab help', 5) + call s:check_tab(4, '-tab help', 4) + call s:check_tab(4, '-2tab help', 3) + call s:check_tab(3, '$tab help', 6) + call assert_fails('99tab help', 'E16:') + call assert_fails('+99tab help', 'E16:') + call assert_fails('-99tab help', 'E16:') + + delfunction s:check_tab + tabonly! + bw! +endfunction + +func Test_tabnext_on_buf_unload1() + " This once caused a crash + new + tabedit + tabfirst + au BufUnload <buffer> tabnext + q + + while tabpagenr('$') > 1 + bwipe! + endwhile +endfunc + +func Test_tabnext_on_buf_unload2() + " This once caused a crash + tabedit + autocmd BufUnload <buffer> tabnext + file x + edit y + + while tabpagenr('$') > 1 + bwipe! + endwhile +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/version.c b/src/nvim/version.c index 153b7fb5fd..a215001194 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -7,6 +7,7 @@ #include <assert.h> #include <limits.h> +#include "nvim/api/private/helpers.h" #include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/iconv.h" @@ -129,10 +130,10 @@ static int included_patches[] = { // 2315, // 2314, // 2313, - // 2312, + 2312, // 2311, // 2310 NA - // 2309, + 2309, // 2308 NA // 2307, // 2306, @@ -204,7 +205,7 @@ static int included_patches[] = { // 2240, // 2239, // 2238 NA - // 2237, + 2237, // 2236, // 2235, // 2234 NA @@ -229,7 +230,7 @@ static int included_patches[] = { // 2215, // 2214 NA 2213, - // 2212, + 2212, // 2211 NA // 2210 NA // 2209, @@ -313,7 +314,7 @@ static int included_patches[] = { // 2131 NA // 2130 NA // 2129 NA - // 2128, + 2128, // 2127, // 2126, // 2125, @@ -332,7 +333,7 @@ static int included_patches[] = { 2112, // 2111, // 2110, - // 2109, + 2109, // 2108 NA // 2107, // 2106, @@ -2457,20 +2458,72 @@ static char *(extra_patches[]) = { NULL }; -/// Checks whether patch `n` has been included. +/// Compares a version string to the current Nvim version. /// -/// @param n The patch number. +/// @param version Version string like "1.3.42" /// -/// @return TRUE if patch "n" has been included. -int has_patch(int n) +/// @return true if Nvim is at or above the version. +bool has_nvim_version(char *version_str) + FUNC_ATTR_NONNULL_ALL { - int i; - for (i = 0; included_patches[i] != 0; ++i) { + char *p = version_str; + int major = 0; + int minor = 0; + int patch = 0; + + if (!ascii_isdigit(*p)) { + return false; + } + major = atoi(p); + p = strchr(p, '.'); // Find the next dot. + + if (p) { + p++; // Advance past the dot. + if (!ascii_isdigit(*p)) { + return false; + } + minor = atoi(p); + p = strchr(p, '.'); + if (p) { + p++; + if (!ascii_isdigit(*p)) { + return false; + } + patch = atoi(p); + } + } + + return (major < NVIM_VERSION_MAJOR + || (major == NVIM_VERSION_MAJOR + && (minor < NVIM_VERSION_MINOR + || (minor == NVIM_VERSION_MINOR + && patch <= NVIM_VERSION_PATCH)))); +} + +/// Checks whether a Vim patch has been included. +/// +/// @param n Patch number. +/// +/// @return true if patch `n` has been included. +bool has_vim_patch(int n) +{ + for (int i = 0; included_patches[i] != 0; i++) { if (included_patches[i] == n) { - return TRUE; + return true; } } - return FALSE; + return false; +} + +Dictionary version_dict(void) { + Dictionary d = ARRAY_DICT_INIT; + PUT(d, "major", INTEGER_OBJ(NVIM_VERSION_MAJOR)); + PUT(d, "minor", INTEGER_OBJ(NVIM_VERSION_MINOR)); + PUT(d, "patch", INTEGER_OBJ(NVIM_VERSION_PATCH)); + PUT(d, "api_level", INTEGER_OBJ(NVIM_API_LEVEL)); + PUT(d, "api_compatible", INTEGER_OBJ(NVIM_API_LEVEL_COMPAT)); + PUT(d, "api_prerelease", BOOLEAN_OBJ(NVIM_API_PRERELEASE)); + return d; } void ex_version(exarg_T *eap) @@ -2529,7 +2582,11 @@ static void list_features(void) } } else { while (msg_col % width) { + int old_msg_col = msg_col; msg_putchar(' '); + if (old_msg_col == msg_col) { + break; // XXX: Avoid infinite loop. + } } } } else { diff --git a/src/nvim/window.c b/src/nvim/window.c index 03a2e9a842..9c6a2e26a6 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -1065,6 +1065,23 @@ bool win_valid(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT return false; } +/// Check if "win" is a pointer to an existing window in any tabpage. +/// +/// @param win window to check +bool win_valid_any_tab(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (win == NULL) { + return false; + } + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp == win) { + return true; + } + } + return false; +} + /* * Return the number of windows. */ @@ -1918,7 +1935,7 @@ int win_close(win_T *win, int free_buf) if (win->w_buffer != NULL) { win->w_closing = true; close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, true); - if (win_valid(win)) { + if (win_valid_any_tab(win)) { win->w_closing = false; } @@ -1938,11 +1955,19 @@ int win_close(win_T *win, int free_buf) curwin->w_buffer = curbuf; getout(0); } - /* Autocommands may have closed the window already, or closed the only - * other window or moved to another tab page. */ - else if (!win_valid(win) || last_window() || curtab != prev_curtab - || close_last_window_tabpage(win, free_buf, prev_curtab)) + // Autocommands may have moved to another tab page. + if (curtab != prev_curtab && win_valid_any_tab(win) + && win->w_buffer == NULL) { + // Need to close the window anyway, since the buffer is NULL. + win_close_othertab(win, false, prev_curtab); return FAIL; + } + // Autocommands may have closed the window already, or closed the only + // other window or moved to another tab page. + if (!win_valid(win) || last_window() + || close_last_window_tabpage(win, free_buf, prev_curtab)) { + return FAIL; + } // let terminal buffers know that this window dimensions may be ignored win->w_closing = true; @@ -2019,12 +2044,16 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) tabpage_T *ptp = NULL; int free_tp = FALSE; - assert(win->w_buffer); // to avoid np dereference warning in next line - if (win->w_closing || win->w_buffer->b_closing) - return; /* window is already being closed */ + // Get here with win->w_buffer == NULL when win_close() detects the tab page + // changed. + if (win->w_closing || (win->w_buffer != NULL && win->w_buffer->b_closing)) { + return; // window is already being closed + } - /* Close the link to the buffer. */ - close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE); + if (win->w_buffer != NULL) { + // Close the link to the buffer. + close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, false); + } /* Careful: Autocommands may have closed the tab page or made it the * current tab page. */ @@ -3213,11 +3242,8 @@ void goto_tabpage(int n) int i; if (text_locked()) { - /* Not allowed when editing the command line. */ - if (cmdwin_type != 0) - EMSG(_(e_cmdwin)); - else - EMSG(_(e_secure)); + // Not allowed when editing the command line. + text_locked_msg(); return; } |