diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/private/helpers.c | 4 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 235 | ||||
-rw-r--r-- | src/nvim/digraph.c | 6 | ||||
-rw-r--r-- | src/nvim/eval.c | 29 | ||||
-rw-r--r-- | src/nvim/ex_eval.c | 31 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 7 | ||||
-rw-r--r-- | src/nvim/globals.h | 4 | ||||
-rw-r--r-- | src/nvim/memfile.c | 152 | ||||
-rw-r--r-- | src/nvim/memfile_defs.h | 3 | ||||
-rw-r--r-- | src/nvim/memline.c | 7 | ||||
-rw-r--r-- | src/nvim/option.c | 26 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/options.lua | 14 | ||||
-rw-r--r-- | src/nvim/os/os_defs.h | 9 | ||||
-rw-r--r-- | src/nvim/screen.c | 7 | ||||
-rw-r--r-- | src/nvim/terminal.c | 3 | ||||
-rw-r--r-- | src/nvim/testdir/test_spell.vim | 2 |
17 files changed, 253 insertions, 288 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 72542ed3e4..b922036893 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -120,9 +120,7 @@ bool try_end(Error *err) // try_enter/try_leave. trylevel--; - // Without this it stops processing all subsequent VimL commands and - // generates strange error messages if I e.g. try calling Test() in a - // cycle + // Set by emsg(), affects aborting(). See also enter_cleanup(). did_emsg = false; if (got_int) { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 46ec8fe10b..df4912a51e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -46,8 +46,7 @@ /// Executes an ex-command. /// -/// On parse error: forwards the Vim error; does not update v:errmsg. -/// On runtime error: forwards the Vim error; does not update v:errmsg. +/// On execution error: fails with VimL error, does not update v:errmsg. /// /// @param command Ex-command string /// @param[out] err Error details (Vim error), if any @@ -103,7 +102,8 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err) } /// Passes input keys to Nvim. -/// On VimL error: Does not fail, but updates v:errmsg. +/// +/// On execution error: does not fail, but updates v:errmsg. /// /// @param keys to be typed /// @param mode mapping options @@ -169,7 +169,8 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi) } /// Passes keys to Nvim as raw user-input. -/// On VimL error: Does not fail, but updates v:errmsg. +/// +/// On execution 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 send real user input. @@ -213,8 +214,7 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, /// Executes an ex-command and returns its (non-error) output. /// Shell |:!| output is not captured. /// -/// On parse error: forwards the Vim error; does not update v:errmsg. -/// On runtime error: forwards the Vim error; does not update v:errmsg. +/// On execution error: fails with VimL error, does not update v:errmsg. /// /// @param command Ex-command string /// @param[out] err Error details (Vim error), if any @@ -259,7 +259,8 @@ theend: /// Evaluates a VimL expression (:help expression). /// Dictionaries and Lists are recursively expanded. -/// On VimL error: Returns a generic error; v:errmsg is not updated. +/// +/// On execution error: fails with VimL error, does not update v:errmsg. /// /// @param expr VimL expression string /// @param[out] err Error details, if any @@ -267,41 +268,79 @@ theend: Object nvim_eval(String expr, Error *err) FUNC_API_SINCE(1) { + static int recursive = 0; // recursion depth Object rv = OBJECT_INIT; - // Evaluate the expression + + // `msg_list` controls the collection of abort-causing non-exception errors, + // which would otherwise be ignored. This pattern is from do_cmdline(). + struct msglist **saved_msg_list = msg_list; + struct msglist *private_msg_list; + msg_list = &private_msg_list; + private_msg_list = NULL; + + // Initialize `force_abort` and `suppress_errthrow` at the top level. + if (!recursive) { + force_abort = false; + suppress_errthrow = false; + current_exception = NULL; + // `did_emsg` is set by emsg(), which cancels execution. + did_emsg = false; + } + recursive++; try_start(); typval_T rettv; - if (eval0((char_u *)expr.data, &rettv, NULL, true) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to evaluate expression"); - } + int ok = eval0((char_u *)expr.data, &rettv, NULL, true); if (!try_end(err)) { - // No errors, convert the result - rv = vim_to_object(&rettv); + if (ok == FAIL) { + // Should never happen, try_end() should get the error. #8371 + api_set_error(err, kErrorTypeException, "Failed to evaluate expression"); + } else { + rv = vim_to_object(&rettv); + } } - // Free the Vim object tv_clear(&rettv); + msg_list = saved_msg_list; // Restore the exception context. + recursive--; return rv; } -/// Calls a VimL function with the given arguments +/// Execute lua code. Parameters (if any) are available as `...` inside the +/// chunk. The chunk can return a value. /// -/// On VimL error: Returns a generic error; v:errmsg is not updated. +/// Only statements are executed. To evaluate an expression, prefix it +/// with `return`: return my_function(...) /// -/// @param fname Function to call -/// @param args Function arguments packed in an Array +/// @param code lua code to execute +/// @param args Arguments to the code +/// @param[out] err Details of an error encountered while parsing +/// or executing the lua code. +/// +/// @return Return value of lua code if present or NIL. +Object nvim_execute_lua(String code, Array args, Error *err) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY +{ + return executor_exec_lua_api(code, args, err); +} + +/// Calls a VimL function. +/// +/// @param fn Function name +/// @param args Function arguments +/// @param self `self` dict, or NULL for non-dict functions /// @param[out] err Error details, if any /// @return Result of the function call -Object nvim_call_function(String fname, Array args, Error *err) - FUNC_API_SINCE(1) +static Object _call_function(String fn, Array args, dict_T *self, Error *err) { + static int recursive = 0; // recursion depth Object rv = OBJECT_INIT; + if (args.size > MAX_FUNC_ARGS) { api_set_error(err, kErrorTypeValidation, - "Function called with too many arguments."); + "Function called with too many arguments"); return rv; } @@ -314,21 +353,36 @@ Object nvim_call_function(String fname, Array args, Error *err) } } + // `msg_list` controls the collection of abort-causing non-exception errors, + // which would otherwise be ignored. This pattern is from do_cmdline(). + struct msglist **saved_msg_list = msg_list; + struct msglist *private_msg_list; + msg_list = &private_msg_list; + private_msg_list = NULL; + + // Initialize `force_abort` and `suppress_errthrow` at the top level. + if (!recursive) { + force_abort = false; + suppress_errthrow = false; + current_exception = NULL; + // `did_emsg` is set by emsg(), which cancels execution. + did_emsg = false; + } + recursive++; try_start(); - // Call the function typval_T rettv; int dummy; - int r = call_func((char_u *)fname.data, (int)fname.size, - &rettv, (int)args.size, vim_args, NULL, - curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy, - true, NULL, NULL); - if (r == FAIL) { - api_set_error(err, kErrorTypeException, "Error calling function."); - } + // call_func() retval is deceptive, ignore it. Instead we set `msg_list` + // (see above) to capture abort-causing non-exception errors. + (void)call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size, + vim_args, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum, + &dummy, true, NULL, self); if (!try_end(err)) { rv = vim_to_object(&rettv); } tv_clear(&rettv); + msg_list = saved_msg_list; // Restore the exception context. + recursive--; free_vim_args: while (i > 0) { @@ -338,22 +392,102 @@ free_vim_args: return rv; } -/// Execute lua code. Parameters (if any) are available as `...` inside the -/// chunk. The chunk can return a value. +/// Calls a VimL function with the given arguments. /// -/// Only statements are executed. To evaluate an expression, prefix it -/// with `return`: return my_function(...) +/// On execution error: fails with VimL error, does not update v:errmsg. /// -/// @param code lua code to execute -/// @param args Arguments to the code -/// @param[out] err Details of an error encountered while parsing -/// or executing the lua code. +/// @param fn 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 fn, Array args, Error *err) + FUNC_API_SINCE(1) +{ + return _call_function(fn, args, NULL, err); +} + +/// Calls a VimL |Dictionary-function| with the given arguments. /// -/// @return Return value of lua code if present or NIL. -Object nvim_execute_lua(String code, Array args, Error *err) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY +/// On execution error: fails with VimL error, does not update v:errmsg. +/// +/// @param dict Dictionary, or String evaluating to a VimL |self| dict +/// @param fn Name of the function defined on the VimL dict +/// @param args Function arguments packed in an Array +/// @param[out] err Error details, if any +/// @return Result of the function call +Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err) + FUNC_API_SINCE(4) { - return executor_exec_lua_api(code, args, err); + Object rv = OBJECT_INIT; + + typval_T rettv; + bool mustfree = false; + switch (dict.type) { + case kObjectTypeString: { + try_start(); + if (eval0((char_u *)dict.data.string.data, &rettv, NULL, true) == FAIL) { + api_set_error(err, kErrorTypeException, + "Failed to evaluate dict expression"); + } + if (try_end(err)) { + return rv; + } + // Evaluation of the string arg created a new dict or increased the + // refcount of a dict. Not necessary for a RPC dict. + mustfree = true; + break; + } + case kObjectTypeDictionary: { + if (!object_to_vim(dict, &rettv, err)) { + goto end; + } + break; + } + default: { + api_set_error(err, kErrorTypeValidation, + "dict argument type must be String or Dictionary"); + return rv; + } + } + dict_T *self_dict = rettv.vval.v_dict; + if (rettv.v_type != VAR_DICT || !self_dict) { + api_set_error(err, kErrorTypeValidation, "dict not found"); + goto end; + } + + if (fn.data && fn.size > 0 && dict.type != kObjectTypeDictionary) { + dictitem_T *const di = tv_dict_find(self_dict, fn.data, (ptrdiff_t)fn.size); + if (di == NULL) { + api_set_error(err, kErrorTypeValidation, "Not found: %s", fn.data); + goto end; + } + if (di->di_tv.v_type == VAR_PARTIAL) { + api_set_error(err, kErrorTypeValidation, + "partial function not supported"); + goto end; + } + if (di->di_tv.v_type != VAR_FUNC) { + api_set_error(err, kErrorTypeValidation, "Not a function: %s", fn.data); + goto end; + } + fn = (String) { + .data = (char *)di->di_tv.vval.v_string, + .size = strlen((char *)di->di_tv.vval.v_string), + }; + } + + if (!fn.data || fn.size < 1) { + api_set_error(err, kErrorTypeValidation, "Invalid (empty) function name"); + goto end; + } + + rv = _call_function(fn, args, self_dict, err); +end: + if (mustfree) { + tv_clear(&rettv); + } + + return rv; } /// Calculates the number of display cells occupied by `text`. @@ -841,27 +975,26 @@ Array nvim_get_api_info(uint64_t channel_id) return rv; } -/// Call many api methods atomically +/// Calls many API methods atomically. /// -/// This has two main usages: Firstly, to perform several requests from an -/// async context atomically, i.e. without processing requests from other rpc -/// clients or redrawing or allowing user interaction in between. Note that api -/// methods that could fire autocommands or do event processing still might do -/// so. For instance invoking the :sleep command might call timer callbacks. -/// Secondly, it can be used to reduce rpc overhead (roundtrips) when doing -/// many requests in sequence. +/// This has two main usages: +/// 1. To perform several requests from an async context atomically, i.e. +/// without interleaving redraws, RPC requests from other clients, or user +/// interactions (however API methods may trigger autocommands or event +/// processing which have such side-effects, e.g. |:sleep| may wake timers). +/// 2. To minimize RPC overhead (roundtrips) of a sequence of many requests. /// /// @param calls an array of calls, where each call is described by an array /// with two elements: the request name, and an array of arguments. /// @param[out] err Details of a validation error of the nvim_multi_request call -/// itself, i e malformatted `calls` parameter. Errors from called methods will +/// itself, i.e. malformed `calls` parameter. Errors from called methods will /// be indicated in the return value, see below. /// /// @return an array with two elements. The first is an array of return /// values. The second is NIL if all calls succeeded. If a call resulted in /// an error, it is a three-element array with the zero-based index of the call /// which resulted in an error, the error type and the error message. If an -/// error ocurred, the values from all preceding calls will still be returned. +/// error occurred, the values from all preceding calls will still be returned. Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index bc4c12e0b7..9e475bf66c 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1700,6 +1700,9 @@ static void printdigraph(digr_T *dp) *p++ = dp->char1; *p++ = dp->char2; *p++ = ' '; + *p = NUL; + msg_outtrans(buf); + p = buf; // add a space to draw a composing char on if (utf_iscomposing(dp->result)) { @@ -1707,6 +1710,9 @@ static void printdigraph(digr_T *dp) } p += (*mb_char2bytes)(dp->result, p); + *p = NUL; + msg_outtrans_attr(buf, hl_attr(HLF_8)); + p = buf; if (char2cells(dp->result) == 1) { *p++ = ' '; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b9df155919..126e9e0da9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6241,20 +6241,21 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) /// invoked function uses them. It is called like this: /// new_argcount = argv_func(current_argcount, argv, called_func_argcount) /// -/// Return FAIL when the function can't be called, OK otherwise. -/// Also returns OK when an error was encountered while executing the function. +/// @return FAIL if function cannot be called, else OK (even if an error +/// occurred while executing the function! Set `msg_list` to capture +/// the error, see do_cmdline()). int call_func( const char_u *funcname, // name of the function int len, // length of "name" - typval_T *rettv, // return value goes here + typval_T *rettv, // [out] value goes here int argcount_in, // number of "argvars" typval_T *argvars_in, // vars for arguments, must have "argcount" // PLUS ONE elements! ArgvFunc argv_func, // function to fill in argvars linenr_T firstline, // first line of range linenr_T lastline, // last line of range - int *doesrange, // return: function handled range + int *doesrange, // [out] function handled range bool evaluate, partial_T *partial, // optional, can be NULL dict_T *selfdict_in // Dictionary for "self" @@ -6428,21 +6429,25 @@ call_func( return ret; } -/* - * Give an error message with a function name. Handle <SNR> things. - * "ermsg" is to be passed without translation, use N_() instead of _(). - */ +/// Give an error message with a function name. Handle <SNR> things. +/// +/// @param ermsg must be passed without translation (use N_() instead of _()). +/// @param name function name static void emsg_funcname(char *ermsg, char_u *name) { - char_u *p; + char_u *p; - if (*name == K_SPECIAL) + if (*name == K_SPECIAL) { p = concat_str((char_u *)"<SNR>", name + 3); - else + } else { p = name; + } + EMSG2(_(ermsg), p); - if (p != name) + + if (p != name) { xfree(p); + } } /* diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index e23945c842..7f7851f078 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -28,22 +28,21 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_eval.c.generated.h" #endif -/* - * Exception handling terms: - * - * :try ":try" command \ - * ... try block | - * :catch RE ":catch" command | - * ... catch clause |- try conditional - * :finally ":finally" command | - * ... finally clause | - * :endtry ":endtry" command / - * - * The try conditional may have any number of catch clauses and at most one - * finally clause. A ":throw" command can be inside the try block, a catch - * clause, the finally clause, or in a function called or script sourced from - * there or even outside the try conditional. Try conditionals may be nested. - */ + +// Exception handling terms: +// +// :try ":try" command ─┐ +// ... try block │ +// :catch RE ":catch" command │ +// ... catch clause ├─ try conditional +// :finally ":finally" command │ +// ... finally clause │ +// :endtry ":endtry" command ─┘ +// +// The try conditional may have any number of catch clauses and at most one +// finally clause. A ":throw" command can be inside the try block, a catch +// clause, the finally clause, or in a function called or script sourced from +// there or even outside the try conditional. Try conditionals may be nested. // Configuration whether an exception is thrown on error or interrupt. When // the preprocessor macros below evaluate to FALSE, an error (did_emsg) or diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index e1198d6f1c..96388a2a9d 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -347,6 +347,13 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) redrawcmd(); } + // redraw the statusline for statuslines that display the current mode + // using the mode() function. + if (KeyTyped) { + curwin->w_redr_status = true; + redraw_statuslines(); + } + did_emsg = false; got_int = false; s->state.check = command_line_check; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 0f2b37e41b..ddc58c2425 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -544,10 +544,6 @@ EXTERN buf_T *curbuf INIT(= NULL); // currently active buffer #define FOR_ALL_BUFFERS_BACKWARDS(buf) \ for (buf_T *buf = lastbuf; buf != NULL; buf = buf->b_prev) -/* Flag that is set when switching off 'swapfile'. It means that all blocks - * are to be loaded into memory. Shouldn't be global... */ -EXTERN int mf_dont_release INIT(= FALSE); /* don't release blocks */ - /* * List of files being edited (global argument list). curwin->w_alist points * to this when the window is using the global argument list. diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 4eeba12b87..f6e03e2532 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -61,8 +61,6 @@ #define MEMFILE_PAGE_SIZE 4096 /// default page size -static size_t total_mem_used = 0; /// total memory used for memfiles - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "memfile.c.generated.h" #endif @@ -99,7 +97,6 @@ memfile_T *mf_open(char_u *fname, int flags) mfp->mf_used_first = NULL; // used list is empty mfp->mf_used_last = NULL; mfp->mf_dirty = false; - mfp->mf_used_count = 0; mf_hash_init(&mfp->mf_hash); mf_hash_init(&mfp->mf_trans); mfp->mf_page_size = MEMFILE_PAGE_SIZE; @@ -136,25 +133,6 @@ memfile_T *mf_open(char_u *fname, int flags) mfp->mf_neg_count = 0; mfp->mf_infile_count = mfp->mf_blocknr_max; - // Compute maximum number of pages ('maxmem' is in Kbytes): - // 'mammem' * 1Kbyte / page-size-in-bytes. - // Avoid overflow by first reducing page size as much as possible. - { - int shift = 10; - unsigned page_size = mfp->mf_page_size; - - while (shift > 0 && (page_size & 1) == 0) { - page_size /= 2; - --shift; - } - - assert(p_mm <= LONG_MAX >> shift); // check we don't overflow - assert((uintmax_t)(p_mm << shift) <= UINT_MAX); // check we can cast safely - mfp->mf_used_count_max = (unsigned)(p_mm << shift) / page_size; - if (mfp->mf_used_count_max < 10) - mfp->mf_used_count_max = 10; - } - return mfp; } @@ -198,7 +176,6 @@ void mf_close(memfile_T *mfp, bool del_file) // free entries in used list for (bhdr_T *hp = mfp->mf_used_first, *nextp; hp != NULL; hp = nextp) { - total_mem_used -= hp->bh_page_count * mfp->mf_page_size; nextp = hp->bh_next; mf_free_bhdr(hp); } @@ -223,12 +200,9 @@ void mf_close_file(buf_T *buf, bool getlines) if (getlines) { // get all blocks in memory by accessing all lines (clumsy!) - mf_dont_release = true; - for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) { + for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { (void)ml_get_buf(buf, lnum, false); } - mf_dont_release = false; - // TODO(elmart): should check if all blocks are really in core } if (close(mfp->mf_fd) < 0) { // close the file @@ -246,13 +220,6 @@ void mf_close_file(buf_T *buf, bool getlines) /// and the size it indicates differs from what was guessed. void mf_new_page_size(memfile_T *mfp, unsigned new_size) { - // Correct the memory used for block 0 to the new size, because it will be - // freed with that size later on. - if (new_size >= mfp->mf_page_size) { - total_mem_used += new_size - mfp->mf_page_size; - } else { - total_mem_used -= mfp->mf_page_size - new_size; - } mfp->mf_page_size = new_size; } @@ -262,10 +229,7 @@ void mf_new_page_size(memfile_T *mfp, unsigned new_size) /// @param page_count Desired number of pages. bhdr_T *mf_new(memfile_T *mfp, bool negative, unsigned page_count) { - // If we reached the maximum size for the used memory blocks, release one. - // If a bhdr_T is returned, use it and adjust the page_count if necessary. - // If no bhdr_T is returned, a new one will be created. - bhdr_T *hp = mf_release(mfp, page_count); // the block to be returned + bhdr_T *hp = NULL; // Decide on the number to use: // If there is a free block, use its number. @@ -273,34 +237,22 @@ bhdr_T *mf_new(memfile_T *mfp, bool negative, unsigned page_count) // a positive number. bhdr_T *freep = mfp->mf_free_first; // first free block if (!negative && freep != NULL && freep->bh_page_count >= page_count) { - // If the block in the free list has more pages, take only the number - // of pages needed and allocate a new bhdr_T with data. - // - // If the number of pages matches and mf_release() did not return a - // bhdr_T, use the bhdr_T from the free list and allocate the data. - // - // If the number of pages matches and mf_release() returned a bhdr_T, - // just use the number and free the bhdr_T from the free list if (freep->bh_page_count > page_count) { - if (hp == NULL) { - hp = mf_alloc_bhdr(mfp, page_count); - } + // If the block in the free list has more pages, take only the number + // of pages needed and allocate a new bhdr_T with data. + hp = mf_alloc_bhdr(mfp, page_count); hp->bh_bnum = freep->bh_bnum; freep->bh_bnum += page_count; freep->bh_page_count -= page_count; - } else if (hp == NULL) { // need to allocate memory for this block + } else { // need to allocate memory for this block + // If the number of pages matches use the bhdr_T from the free list and + // allocate the data. void *p = xmalloc(mfp->mf_page_size * page_count); hp = mf_rem_free(mfp); hp->bh_data = p; - } else { // use the number, remove entry from free list - freep = mf_rem_free(mfp); - hp->bh_bnum = freep->bh_bnum; - xfree(freep); } } else { // get a new number - if (hp == NULL) { - hp = mf_alloc_bhdr(mfp, page_count); - } + hp = mf_alloc_bhdr(mfp, page_count); if (negative) { hp->bh_bnum = mfp->mf_blocknr_min--; mfp->mf_neg_count++; @@ -341,13 +293,7 @@ bhdr_T *mf_get(memfile_T *mfp, blocknr_T nr, unsigned page_count) // could check here if the block is in the free list - // Check if we need to flush an existing block. - // If so, use that block. - // If not, allocate a new block. - hp = mf_release(mfp, page_count); - if (hp == NULL) { - hp = mf_alloc_bhdr(mfp, page_count); - } + hp = mf_alloc_bhdr(mfp, page_count); hp->bh_bnum = nr; hp->bh_flags = 0; @@ -514,8 +460,6 @@ static void mf_ins_used(memfile_T *mfp, bhdr_T *hp) } else { hp->bh_next->bh_prev = hp; } - mfp->mf_used_count += hp->bh_page_count; - total_mem_used += hp->bh_page_count * mfp->mf_page_size; } /// Remove block from memfile's used list. @@ -530,82 +474,6 @@ static void mf_rem_used(memfile_T *mfp, bhdr_T *hp) mfp->mf_used_first = hp->bh_next; else hp->bh_prev->bh_next = hp->bh_next; - - mfp->mf_used_count -= hp->bh_page_count; - total_mem_used -= hp->bh_page_count * mfp->mf_page_size; -} - -/// Try to release the least recently used block from the used list if the -/// number of used memory blocks gets too big. -/// -/// @return The block header, when release needed and possible. -/// Resulting block header includes memory block, so it can be -/// reused. Page count is checked to be right. -/// NULL, when release not needed, or not possible. -/// Not needed when number of blocks less than allowed maximum and -/// total memory used below 'maxmemtot'. -/// Not possible when: -/// - Called while closing file. -/// - Tried to create swap file but couldn't. -/// - All blocks are locked. -/// - Unlocked dirty block found, but flush failed. -static bhdr_T *mf_release(memfile_T *mfp, unsigned page_count) -{ - // don't release while in mf_close_file() - if (mf_dont_release) - return NULL; - - /// Need to release a block if the number of blocks for this memfile is - /// higher than the maximum one or total memory used is over 'maxmemtot'. - bool need_release = (mfp->mf_used_count >= mfp->mf_used_count_max - || (total_mem_used >> 10) >= (size_t)p_mmt); - - /// Try to create swap file if the amount of memory used is getting too high. - if (mfp->mf_fd < 0 && need_release && p_uc) { - // find for which buffer this memfile is - buf_T *buf = NULL; - FOR_ALL_BUFFERS(bp) { - if (bp->b_ml.ml_mfp == mfp) { - buf = bp; - break; - } - } - if (buf != NULL && buf->b_may_swap) { - ml_open_file(buf); - } - } - - /// Don't release a block if: - /// there is no file for this memfile - /// or - /// the number of blocks for this memfile is lower than the maximum - /// and - /// total memory used is not up to 'maxmemtot' - if (mfp->mf_fd < 0 || !need_release) - return NULL; - - bhdr_T *hp; - for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev) - if (!(hp->bh_flags & BH_LOCKED)) - break; - if (hp == NULL) // not a single one that can be released - return NULL; - - // If the block is dirty, write it. - // If the write fails we don't free it. - if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL) - return NULL; - - mf_rem_used(mfp, hp); - mf_rem_hash(mfp, hp); - - /// Make sure page_count of bh_data is right. - if (hp->bh_page_count != page_count) { - xfree(hp->bh_data); - hp->bh_data = xmalloc(mfp->mf_page_size * page_count); - hp->bh_page_count = page_count; - } - return hp; } /// Release as many blocks as possible. diff --git a/src/nvim/memfile_defs.h b/src/nvim/memfile_defs.h index b3c2f3564c..2402d2147d 100644 --- a/src/nvim/memfile_defs.h +++ b/src/nvim/memfile_defs.h @@ -56,7 +56,6 @@ typedef struct mf_hashtab { /// /// The used list is a doubly linked list, most recently used block first. /// The blocks in the used list have a block of memory allocated. -/// mf_used_count is the number of pages in the used list. /// The hash lists are used to quickly find a block in the used list. /// The free list is a single linked list, not sorted. /// The blocks in the free list have no block of memory allocated and @@ -95,8 +94,6 @@ typedef struct memfile { bhdr_T *mf_free_first; /// first block header in free list bhdr_T *mf_used_first; /// mru block header in used list bhdr_T *mf_used_last; /// lru block header in used list - unsigned mf_used_count; /// number of pages in used list - unsigned mf_used_count_max; /// maximum number of pages in memory mf_hashtab_T mf_hash; /// hash lists mf_hashtab_T mf_trans; /// trans lists blocknr_T mf_blocknr_max; /// highest positive block number + 1 diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 1f388dd34c..06de9fda67 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1766,7 +1766,7 @@ errorret: * Don't use the last used line when 'swapfile' is reset, need to load all * blocks. */ - if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release) { + if (buf->b_ml.ml_line_lnum != lnum) { ml_flush_line(buf); /* @@ -2767,9 +2767,8 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) if (buf->b_ml.ml_locked) { if (ML_SIMPLE(action) && buf->b_ml.ml_locked_low <= lnum - && buf->b_ml.ml_locked_high >= lnum - && !mf_dont_release) { - /* remember to update pointer blocks and stack later */ + && buf->b_ml.ml_locked_high >= lnum) { + // remember to update pointer blocks and stack later if (action == ML_INSERT) { ++(buf->b_ml.ml_locked_lineadd); ++(buf->b_ml.ml_locked_high); diff --git a/src/nvim/option.c b/src/nvim/option.c index 96b2413c8f..1da259e6b8 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -619,27 +619,6 @@ void set_init_1(void) } } - /* - * 'maxmemtot' and 'maxmem' may have to be adjusted for available memory - */ - opt_idx = findoption("maxmemtot"); - if (opt_idx >= 0) { - { - // Use half of amount of memory available to Vim. - // If too much to fit in uintptr_t, get uintptr_t max. - uint64_t available_kib = os_get_total_mem_kib(); - uintptr_t n = (available_kib / 2 > UINTPTR_MAX // -V547 - ? UINTPTR_MAX - : (uintptr_t)(available_kib /2)); - options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n; - opt_idx = findoption("maxmem"); - if (opt_idx >= 0) { - options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n; - } - } - } - - { char_u *cdpath; char_u *buf; @@ -3672,10 +3651,11 @@ static void set_option_scriptID_idx(int opt_idx, int opt_flags, int id) options[opt_idx].last_set = last_set; } if (both || (opt_flags & OPT_LOCAL)) { - if (indir & PV_BUF) + if (indir & PV_BUF) { curbuf->b_p_scriptID[indir & PV_MASK] = last_set; - else if (indir & PV_WIN) + } else if (indir & PV_WIN) { curwin->w_p_scriptID[indir & PV_MASK] = last_set; + } } } diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 670af1cc76..f7dfa65053 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -499,9 +499,7 @@ EXTERN long p_mat; // 'matchtime' EXTERN long p_mco; // 'maxcombine' EXTERN long p_mfd; // 'maxfuncdepth' EXTERN long p_mmd; // 'maxmapdepth' -EXTERN long p_mm; // 'maxmem' EXTERN long p_mmp; // 'maxmempattern' -EXTERN long p_mmt; // 'maxmemtot' EXTERN long p_mis; // 'menuitems' EXTERN char_u *p_msm; // 'mkspellmem' EXTERN long p_mls; // 'modelines' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 66018b2475..f1f559fff0 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1512,13 +1512,6 @@ return { defaults={if_true={vi=1000}} }, { - full_name='maxmem', abbreviation='mm', - type='number', scope={'global'}, - vi_def=true, - varname='p_mm', - defaults={if_true={vi=macros('DFLT_MAXMEM')}} - }, - { full_name='maxmempattern', abbreviation='mmp', type='number', scope={'global'}, vi_def=true, @@ -1526,13 +1519,6 @@ return { defaults={if_true={vi=1000}} }, { - full_name='maxmemtot', abbreviation='mmt', - type='number', scope={'global'}, - vi_def=true, - varname='p_mmt', - defaults={if_true={vi=macros('DFLT_MAXMEMTOT')}} - }, - { full_name='menuitems', abbreviation='mis', type='number', scope={'global'}, vi_def=true, diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h index f81785675e..c29af5c160 100644 --- a/src/nvim/os/os_defs.h +++ b/src/nvim/os/os_defs.h @@ -25,15 +25,6 @@ // Command-processing buffer. Use large buffers for all platforms. #define CMDBUFFSIZE 1024 -// Use up to 5 Mbyte for a buffer. -#ifndef DFLT_MAXMEM -# define DFLT_MAXMEM (5 * 1024) -#endif -// use up to 10 Mbyte for Vim. -#ifndef DFLT_MAXMEMTOT -# define DFLT_MAXMEMTOT (10 * 1024) -#endif - // Note: Some systems need both string.h and strings.h (Savage). However, // some systems can't handle both, only use string.h in that case. #include <string.h> diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 2e64eb864f..f034ac33f1 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -309,6 +309,9 @@ void update_screen(int type) if (wp->w_winrow + wp->w_height + wp->w_status_height > valid) { wp->w_redr_status = true; } + if (valid == 0) { + redraw_tabline = true; + } } } else if (msg_scrolled > Rows - 5) { // clearing is faster type = CLEAR; @@ -5307,7 +5310,9 @@ void screen_getbytes(int row, int col, char_u *bytes, int *attrp) bytes[0] = ScreenLines[off]; bytes[1] = NUL; - bytes[utfc_char2bytes(off, bytes)] = NUL; + if (ScreenLinesUC[off] != 0) { + bytes[utfc_char2bytes(off, bytes)] = NUL; + } } } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index d006477c80..f68bb2458d 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -396,10 +396,8 @@ void terminal_enter(void) win_T *save_curwin = curwin; int save_w_p_cul = curwin->w_p_cul; int save_w_p_cuc = curwin->w_p_cuc; - int save_w_p_rnu = curwin->w_p_rnu; curwin->w_p_cul = false; curwin->w_p_cuc = false; - curwin->w_p_rnu = false; adjust_topline(s->term, buf, 0); // scroll to end // erase the unfocused cursor @@ -417,7 +415,6 @@ void terminal_enter(void) if (save_curwin == curwin) { // save_curwin may be invalid (window closed)! curwin->w_p_cul = save_w_p_cul; curwin->w_p_cuc = save_w_p_cuc; - curwin->w_p_rnu = save_w_p_rnu; } // draw the unfocused cursor diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index 21f2363731..a2828b21d2 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -315,7 +315,7 @@ endfunc " Check using z= in new buffer (crash fixed by patch 7.4a.028). func Test_zeq_crash() new - set maxmem=512 spell + set spell call feedkeys('iasdz=:\"', 'tx') bwipe! |