aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/helpers.c4
-rw-r--r--src/nvim/api/vim.c235
-rw-r--r--src/nvim/digraph.c6
-rw-r--r--src/nvim/eval.c29
-rw-r--r--src/nvim/ex_eval.c31
-rw-r--r--src/nvim/ex_getln.c7
-rw-r--r--src/nvim/globals.h4
-rw-r--r--src/nvim/memfile.c152
-rw-r--r--src/nvim/memfile_defs.h3
-rw-r--r--src/nvim/memline.c7
-rw-r--r--src/nvim/option.c26
-rw-r--r--src/nvim/option_defs.h2
-rw-r--r--src/nvim/options.lua14
-rw-r--r--src/nvim/os/os_defs.h9
-rw-r--r--src/nvim/screen.c7
-rw-r--r--src/nvim/terminal.c3
-rw-r--r--src/nvim/testdir/test_spell.vim2
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!