From b853b6e4ea1269ab7ae766bd71d9bafd54dc2b98 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 20 Sep 2019 01:31:01 -0400 Subject: vim-patch:8.0.1109: timer causes error on exit from Ex mode Problem: Timer causes error on exit from Ex mode. (xtal8) Solution: save and restore the ex_pressedreturn flag. (Christian Brabandt, closes vim/vim#2079) https://github.com/vim/vim/commit/f5291f301e9322545f0621b2157e93050d1d4fb3 --- src/nvim/ex_docmd.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 72d39adb3e..a6931f3acd 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -77,7 +77,7 @@ #include "nvim/api/private/helpers.h" static int quitmore = 0; -static int ex_pressedreturn = FALSE; +static bool ex_pressedreturn = false; /// Whether ":lcd" or ":tcd" was produced for a session. static int did_lcd; @@ -1278,14 +1278,14 @@ static char_u * do_one_cmd(char_u **cmdlinep, || getline_equal(fgetline, cookie, getexline)) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { ea.cmd = (char_u *)"+"; - ex_pressedreturn = TRUE; + ex_pressedreturn = true; } /* ignore comment and empty lines */ if (*ea.cmd == '"') goto doend; if (*ea.cmd == NUL) { - ex_pressedreturn = TRUE; + ex_pressedreturn = true; goto doend; } @@ -10131,6 +10131,17 @@ static void ex_folddo(exarg_T *eap) ml_clearmarked(); // clear rest of the marks } +bool get_pressedreturn(void) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return ex_pressedreturn; +} + +void set_pressedreturn(bool val) +{ + ex_pressedreturn = val; +} + static void ex_terminal(exarg_T *eap) { char ex_cmd[1024]; -- cgit From 655085204e36cdf91750db5e09ae3feb4884c670 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 29 Sep 2019 09:29:16 -0400 Subject: vim-patch:8.1.0230: directly checking 'buftype' value Problem: Directly checking 'buftype' value. Solution: Add the bt_normal() function. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/91335e5a67aaa9937e65f1e779b9f3f10fd33ee4 --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a6931f3acd..34b4c10d3e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -9553,7 +9553,7 @@ put_view( */ if ((*flagp & SSOP_FOLDS) && wp->w_buffer->b_ffname != NULL - && (*wp->w_buffer->b_p_bt == NUL || bt_help(wp->w_buffer)) + && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer)) ) { if (put_folds(fd, wp) == FAIL) return FAIL; -- cgit From fe074611cd5b3319a3f639f68289df6a718e64eb Mon Sep 17 00:00:00 2001 From: Jurica Bradarić Date: Sun, 6 Oct 2019 05:35:48 +0200 Subject: vim-patch:8.1.1371: cannot recover from a swap file #11081 Problem: Cannot recover from a swap file. Solution: Do not expand environment variables in the swap file name. Do not check the extension when we already know a file is a swap file. (Ken Takata, closes 4415, closes vim/vim#4369) https://github.com/vim/vim/commit/99499b1c05f85f83876b828eea3f6e14f0f407b4 --- src/nvim/ex_docmd.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 34b4c10d3e..a6042b0e8c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6708,17 +6708,18 @@ static void ex_preserve(exarg_T *eap) /// ":recover". static void ex_recover(exarg_T *eap) { - /* Set recoverymode right away to avoid the ATTENTION prompt. */ - recoverymode = TRUE; + // Set recoverymode right away to avoid the ATTENTION prompt. + recoverymode = true; if (!check_changed(curbuf, (p_awa ? CCGD_AW : 0) | CCGD_MULTWIN | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD) && (*eap->arg == NUL - || setfname(curbuf, eap->arg, NULL, TRUE) == OK)) - ml_recover(); - recoverymode = FALSE; + || setfname(curbuf, eap->arg, NULL, true) == OK)) { + ml_recover(true); + } + recoverymode = false; } /* -- cgit From d1abd6513e95a41e41ad570038310087e97f3bb1 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 6 Oct 2019 08:03:47 -0400 Subject: vim-patch:8.1.0586: :digraph output is not easy to read Problem: :digraph output is not easy to read. Solution: Add highlighting for :digraphs. (Marcin Szamotulski, closes vim/vim#3572) Also add section headers for :digraphs!. https://github.com/vim/vim/commit/eae8ae1b2b4e532b125077d9838b70d966891be3 --- src/nvim/ex_docmd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 34b4c10d3e..29b63c3f99 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -10010,10 +10010,11 @@ static void ex_setfiletype(exarg_T *eap) static void ex_digraphs(exarg_T *eap) { - if (*eap->arg != NUL) + if (*eap->arg != NUL) { putdigraph(eap->arg); - else - listdigraphs(); + } else { + listdigraphs(eap->forceit); + } } static void ex_set(exarg_T *eap) -- cgit From 0586a4b512b2495d32f20c46946d35a0d403bd52 Mon Sep 17 00:00:00 2001 From: Jurica Bradaric Date: Mon, 23 Sep 2019 21:19:26 +0200 Subject: vim-patch:8.1.1588: in :let-heredoc line continuation is recognized Problem: In :let-heredoc line continuation is recognized. Solution: Do not consume line continuation. (Ozaki Kiichi, closes vim/vim#4580) https://github.com/vim/vim/commit/e96a2498f9a2d3e93ac07431f6d4afd77f30afdf --- src/nvim/ex_docmd.c | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 8d67ab5348..0da2cd67d6 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -117,11 +117,11 @@ typedef struct { * reads more lines that may come from the while/for loop. */ struct loop_cookie { - garray_T *lines_gap; /* growarray with line info */ - int current_line; /* last read line from growarray */ - int repeating; /* TRUE when looping a second time */ - /* When "repeating" is FALSE use "getline" and "cookie" to get lines */ - char_u *(*getline)(int, void *, int); + garray_T *lines_gap; // growarray with line info + int current_line; // last read line from growarray + int repeating; // TRUE when looping a second time + // When "repeating" is FALSE use "getline" and "cookie" to get lines + char_u *(*getline)(int, void *, int, bool); void *cookie; }; @@ -313,8 +313,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, struct msglist **saved_msg_list = NULL; struct msglist *private_msg_list; - /* "fgetline" and "cookie" passed to do_one_cmd() */ - char_u *(*cmd_getline)(int, void *, int); + // "fgetline" and "cookie" passed to do_one_cmd() + char_u *(*cmd_getline)(int, void *, int, bool); void *cmd_cookie; struct loop_cookie cmd_loop_cookie; void *real_cookie; @@ -507,17 +507,20 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, * Need to set msg_didout for the first line after an ":if", * otherwise the ":if" will be overwritten. */ - if (count == 1 && getline_equal(fgetline, cookie, getexline)) - msg_didout = TRUE; - if (fgetline == NULL || (next_cmdline = fgetline(':', cookie, - cstack.cs_idx < - 0 ? 0 : (cstack.cs_idx + 1) * 2 - )) == NULL) { - /* Don't call wait_return for aborted command line. The NULL - * returned for the end of a sourced file or executed function - * doesn't do this. */ - if (KeyTyped && !(flags & DOCMD_REPEAT)) - need_wait_return = FALSE; + if (count == 1 && getline_equal(fgetline, cookie, getexline)) { + msg_didout = true; + } + if (fgetline == NULL + || (next_cmdline = fgetline(':', cookie, + cstack.cs_idx < + 0 ? 0 : (cstack.cs_idx + 1) * 2, + true)) == NULL) { + // Don't call wait_return for aborted command line. The NULL + // returned for the end of a sourced file or executed function + // doesn't do this. + if (KeyTyped && !(flags & DOCMD_REPEAT)) { + need_wait_return = false; + } retval = FAIL; break; } @@ -951,7 +954,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, /* * Obtain a line when inside a ":while" or ":for" loop. */ -static char_u *get_loop_line(int c, void *cookie, int indent) +static char_u *get_loop_line(int c, void *cookie, int indent, bool do_concat) { struct loop_cookie *cp = (struct loop_cookie *)cookie; wcmd_T *wp; @@ -961,11 +964,12 @@ static char_u *get_loop_line(int c, void *cookie, int indent) if (cp->repeating) return NULL; /* trying to read past ":endwhile"/":endfor" */ - /* First time inside the ":while"/":for": get line normally. */ - if (cp->getline == NULL) - line = getcmdline(c, 0L, indent); - else - line = cp->getline(c, cp->cookie, indent); + // First time inside the ":while"/":for": get line normally. + if (cp->getline == NULL) { + line = getcmdline(c, 0L, indent, do_concat); + } else { + line = cp->getline(c, cp->cookie, indent, do_concat); + } if (line != NULL) { store_loop_line(cp->lines_gap, line); ++cp->current_line; -- cgit From c067efa696698d455d9a1488c26e0fb5d8cb5bf5 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 20 Oct 2019 20:12:08 -0400 Subject: vim-patch:8.1.2197: ExitPre autocommand may cause accessing freed memory Problem: ExitPre autocommand may cause accessing freed memory. Solution: Check the window pointer is still valid. (closes vim/vim#5093) https://github.com/vim/vim/commit/34ba06b6e6f94bb46062e6c85dbfdcbb0d255ada --- src/nvim/ex_docmd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 0da2cd67d6..ae3fb4fbfb 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6070,9 +6070,11 @@ static bool before_quit_autocmds(win_T *wp, bool quit_all, int forceit) if (quit_all || (check_more(false, forceit) == OK && only_one_window())) { apply_autocmds(EVENT_EXITPRE, NULL, NULL, false, curbuf); - // Refuse to quit when locked or when the buffer in the last window is - // being closed (can only happen in autocommands). - if (curbuf_locked() + // Refuse to quit when locked or when the window was closed or the + // buffer in the last window is being closed (can only happen in + // autocommands). + if (!win_valid(wp) + || curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) { return true; } -- cgit From 5e02bd071ed054b52ca7e53536d4b5cd594737eb Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 13 Oct 2019 19:19:32 -0400 Subject: vim-patch:8.1.0288: quickfix code uses cmdidx too often Problem: Quickfix code uses cmdidx too often. Solution: Add is_loclist_cmd(). (Yegappan Lakshmanan) https://github.com/vim/vim/commit/396659592fe039decc8c088694912067fe32a681 --- src/nvim/ex_docmd.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index ae3fb4fbfb..16751b3a53 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -10139,6 +10139,17 @@ static void ex_folddo(exarg_T *eap) ml_clearmarked(); // clear rest of the marks } +// Returns true if the supplied Ex cmdidx is for a location list command +// instead of a quickfix command. +bool is_loclist_cmd(int cmdidx) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (cmdidx < 0 || cmdidx > CMD_SIZE) { + return false; + } + return cmdnames[cmdidx].cmd_name[0] == 'l'; +} + bool get_pressedreturn(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { -- cgit From 034077ed1c1fa71aa15829ed2dfb27de4a5e5359 Mon Sep 17 00:00:00 2001 From: Jaehwang Jerry Jung Date: Fri, 25 Oct 2019 19:54:53 +0900 Subject: vim-patch:8.1.2173: searchit() has too many arguments Problem: Searchit() has too many arguments. Solution: Move optional arguments to a struct. Add the "wrapped" argument. https://github.com/vim/vim/commit/92ea26b925a0835badb0af2d5887238a4198cabb --- src/nvim/ex_docmd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 16751b3a53..da0184aa45 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3750,8 +3750,7 @@ static linenr_T get_address(exarg_T *eap, curwin->w_cursor.col = 0; } searchcmdlen = 0; - if (!do_search(NULL, c, cmd, 1L, - SEARCH_HIS | SEARCH_MSG, NULL, NULL)) { + if (!do_search(NULL, c, cmd, 1L, SEARCH_HIS | SEARCH_MSG, NULL)) { curwin->w_cursor = pos; cmd = NULL; goto error; @@ -3788,8 +3787,7 @@ static linenr_T get_address(exarg_T *eap, pos.coladd = 0; if (searchit(curwin, curbuf, &pos, NULL, *cmd == '?' ? BACKWARD : FORWARD, - (char_u *)"", 1L, SEARCH_MSG, - i, (linenr_T)0, NULL, NULL) != FAIL) { + (char_u *)"", 1L, SEARCH_MSG, i, NULL) != FAIL) { lnum = pos.lnum; } else { cmd = NULL; -- cgit From 3b3d21775478cc97acf391a30d844eb3a81e96f6 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 8 Mar 2019 22:49:03 +0000 Subject: Factor out skip_colon_white() --- src/nvim/ex_docmd.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index da0184aa45..22c4fd264d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1201,6 +1201,19 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap) } } +static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite) +{ + if (skipleadingwhite) { + p = skipwhite(p); + } + + while (*p == ':') { + p = skipwhite(p + 1); + } + + return (char_u *)p; +} + /* * Execute one Ex command. * @@ -1705,9 +1718,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, /* * Skip ':' and any white space */ - ea.cmd = skipwhite(ea.cmd); - while (*ea.cmd == ':') - ea.cmd = skipwhite(ea.cmd + 1); + ea.cmd = skip_colon_white(ea.cmd, true); /* * If we got a line, but no command, then go to the line. @@ -3580,9 +3591,8 @@ char_u *skip_range( ++cmd; } - /* Skip ":" and white space. */ - while (*cmd == ':') - cmd = skipwhite(cmd + 1); + // Skip ":" and white space. + cmd = skip_colon_white(cmd, false); return (char_u *)cmd; } -- cgit From 1c7aa1131297b4b3686d66aae06090e1398da56c Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 8 Mar 2019 22:49:48 +0000 Subject: Allow multiple leading colons before and after modifiers for 'inccommand' --- src/nvim/ex_docmd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 22c4fd264d..48d29caf60 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -10216,10 +10216,13 @@ bool cmd_can_preview(char_u *cmd) return false; } + // Ignore additional colons at the start... + cmd = skip_colon_white(cmd, true); + // Ignore any leading modifiers (:keeppatterns, :verbose, etc.) for (int len = modifier_len(cmd); len != 0; len = modifier_len(cmd)) { cmd += len; - cmd = skipwhite(cmd); + cmd = skip_colon_white(cmd, true); } exarg_T ea; -- cgit From 36b4191e41788192c7fc5cef2f7b11d3bcd13880 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 31 Oct 2019 23:20:33 +0000 Subject: Document skip_colon_white() --- src/nvim/ex_docmd.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 48d29caf60..d3e2120721 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1201,6 +1201,10 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap) } } +/// Skip colons and trailing whitespace, returning a pointer to the first +/// non-colon, non-whitespace character. +// +/// @param skipleadingwhite Skip leading whitespace too static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite) { if (skipleadingwhite) { -- cgit From 6e42eb4dc9d2c1f3b114651673e6f2699f2416a0 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 9 Nov 2019 09:56:36 -0500 Subject: vim-patch:8.1.0324: off-by-one error in cmdidx check Problem: Off-by-one error in cmdidx check. (Coverity) Solution: Use ">=" instead of ">". https://github.com/vim/vim/commit/74c8be2c6803eda3a57991b8867c5c65259b73d6 Fix pvs/v557. --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index d3e2120721..7d02623d67 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -10156,7 +10156,7 @@ static void ex_folddo(exarg_T *eap) bool is_loclist_cmd(int cmdidx) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - if (cmdidx < 0 || cmdidx > CMD_SIZE) { + if (cmdidx < 0 || cmdidx >= CMD_SIZE) { return false; } return cmdnames[cmdidx].cmd_name[0] == 'l'; -- cgit From c512dffb55b259d50fb91326e40a7b4da95e525b Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 30 Oct 2019 20:36:53 -0400 Subject: vim-patch:8.1.0266: parsing Ex address range is not a separate function Problem: Parsing Ex address range is not a separate function. Solution: Refactor do_one_cmd() to separate address parsing. https://github.com/vim/vim/commit/ee8415bc5998792fab6f4dcf289d027856e05b89 --- src/nvim/ex_docmd.c | 314 +++++++++++++++++++++++++++------------------------- 1 file changed, 163 insertions(+), 151 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 7d02623d67..c48e5e0a4e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1255,7 +1255,6 @@ static char_u * do_one_cmd(char_u **cmdlinep, cmdmod_T save_cmdmod; const int save_reg_executing = reg_executing; char_u *cmd; - int address_count = 1; memset(&ea, 0, sizeof(ea)); ea.line1 = 1; @@ -1571,148 +1570,9 @@ static char_u * do_one_cmd(char_u **cmdlinep, } } - /* repeat for all ',' or ';' separated addresses */ ea.cmd = cmd; - for (;; ) { - ea.line1 = ea.line2; - switch (ea.addr_type) { - case ADDR_LINES: - // default is current line number - ea.line2 = curwin->w_cursor.lnum; - break; - case ADDR_WINDOWS: - ea.line2 = CURRENT_WIN_NR; - break; - case ADDR_ARGUMENTS: - ea.line2 = curwin->w_arg_idx + 1; - if (ea.line2 > ARGCOUNT) { - ea.line2 = ARGCOUNT; - } - break; - case ADDR_LOADED_BUFFERS: - case ADDR_BUFFERS: - ea.line2 = curbuf->b_fnum; - break; - case ADDR_TABS: - ea.line2 = CURRENT_TAB_NR; - break; - case ADDR_TABS_RELATIVE: - ea.line2 = 1; - break; - case ADDR_QUICKFIX: - ea.line2 = qf_get_cur_valid_idx(&ea); - break; - } - ea.cmd = skipwhite(ea.cmd); - lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip, - ea.addr_count == 0, address_count++); - if (ea.cmd == NULL) { // error detected - goto doend; - } - if (lnum == MAXLNUM) { - if (*ea.cmd == '%') { /* '%' - all lines */ - ++ea.cmd; - switch (ea.addr_type) { - case ADDR_LINES: - ea.line1 = 1; - ea.line2 = curbuf->b_ml.ml_line_count; - break; - case ADDR_LOADED_BUFFERS: { - buf_T *buf = firstbuf; - while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) { - buf = buf->b_next; - } - ea.line1 = buf->b_fnum; - buf = lastbuf; - while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) { - buf = buf->b_prev; - } - ea.line2 = buf->b_fnum; - break; - } - case ADDR_BUFFERS: - ea.line1 = firstbuf->b_fnum; - ea.line2 = lastbuf->b_fnum; - break; - case ADDR_WINDOWS: - case ADDR_TABS: - if (IS_USER_CMDIDX(ea.cmdidx)) { - ea.line1 = 1; - ea.line2 = - ea.addr_type == ADDR_WINDOWS ? LAST_WIN_NR : LAST_TAB_NR; - } else { - // there is no Vim command which uses '%' and - // ADDR_WINDOWS or ADDR_TABS - errormsg = (char_u *)_(e_invrange); - goto doend; - } - break; - case ADDR_TABS_RELATIVE: - errormsg = (char_u *)_(e_invrange); - goto doend; - break; - case ADDR_ARGUMENTS: - if (ARGCOUNT == 0) { - ea.line1 = ea.line2 = 0; - } else { - ea.line1 = 1; - ea.line2 = ARGCOUNT; - } - break; - case ADDR_QUICKFIX: - ea.line1 = 1; - ea.line2 = qf_get_size(&ea); - if (ea.line2 == 0) { - ea.line2 = 1; - } - break; - } - ++ea.addr_count; - } - /* '*' - visual area */ - else if (*ea.cmd == '*') { - pos_T *fp; - - if (ea.addr_type != ADDR_LINES) { - errormsg = (char_u *)_(e_invrange); - goto doend; - } - - ++ea.cmd; - if (!ea.skip) { - fp = getmark('<', FALSE); - if (check_mark(fp) == FAIL) - goto doend; - ea.line1 = fp->lnum; - fp = getmark('>', FALSE); - if (check_mark(fp) == FAIL) - goto doend; - ea.line2 = fp->lnum; - ++ea.addr_count; - } - } - } else - ea.line2 = lnum; - ea.addr_count++; - - if (*ea.cmd == ';') { - if (!ea.skip) { - curwin->w_cursor.lnum = ea.line2; - // don't leave the cursor on an illegal line or column - check_cursor(); - } - } else if (*ea.cmd != ',') { - break; - } - ea.cmd++; - } - - /* One address given: set start and end lines */ - if (ea.addr_count == 1) { - ea.line1 = ea.line2; - /* ... but only implicit: really no address given */ - if (lnum == MAXLNUM) - ea.addr_count = 0; + if (parse_cmd_address(&ea, &errormsg) == FAIL) { + goto doend; } /* @@ -2376,6 +2236,160 @@ doend: return ea.nextcmd; } +// Parse the address range, if any, in "eap". +// Return FAIL and set "errormsg" or return OK. +int parse_cmd_address(exarg_T *eap, char_u **errormsg) + FUNC_ATTR_NONNULL_ALL +{ + int address_count = 1; + linenr_T lnum; + + // Repeat for all ',' or ';' separated addresses. + for (;;) { + eap->line1 = eap->line2; + switch (eap->addr_type) { + case ADDR_LINES: + // default is current line number + eap->line2 = curwin->w_cursor.lnum; + break; + case ADDR_WINDOWS: + eap->line2 = CURRENT_WIN_NR; + break; + case ADDR_ARGUMENTS: + eap->line2 = curwin->w_arg_idx + 1; + if (eap->line2 > ARGCOUNT) { + eap->line2 = ARGCOUNT; + } + break; + case ADDR_LOADED_BUFFERS: + case ADDR_BUFFERS: + eap->line2 = curbuf->b_fnum; + break; + case ADDR_TABS: + eap->line2 = CURRENT_TAB_NR; + break; + case ADDR_TABS_RELATIVE: + eap->line2 = 1; + break; + case ADDR_QUICKFIX: + eap->line2 = qf_get_cur_valid_idx(eap); + break; + } + eap->cmd = skipwhite(eap->cmd); + lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, + eap->addr_count == 0, address_count++); + if (eap->cmd == NULL) { // error detected + return FAIL; + } + if (lnum == MAXLNUM) { + if (*eap->cmd == '%') { // '%' - all lines + eap->cmd++; + switch (eap->addr_type) { + case ADDR_LINES: + eap->line1 = 1; + eap->line2 = curbuf->b_ml.ml_line_count; + break; + case ADDR_LOADED_BUFFERS: { + buf_T *buf = firstbuf; + + while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) { + buf = buf->b_next; + } + eap->line1 = buf->b_fnum; + buf = lastbuf; + while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) { + buf = buf->b_prev; + } + eap->line2 = buf->b_fnum; + break; + } + case ADDR_BUFFERS: + eap->line1 = firstbuf->b_fnum; + eap->line2 = lastbuf->b_fnum; + break; + case ADDR_WINDOWS: + case ADDR_TABS: + if (IS_USER_CMDIDX(eap->cmdidx)) { + eap->line1 = 1; + eap->line2 = eap->addr_type == ADDR_WINDOWS + ? LAST_WIN_NR : LAST_TAB_NR; + } else { + // there is no Vim command which uses '%' and + // ADDR_WINDOWS or ADDR_TABS + *errormsg = (char_u *)_(e_invrange); + return FAIL; + } + break; + case ADDR_TABS_RELATIVE: + *errormsg = (char_u *)_(e_invrange); + return FAIL; + case ADDR_ARGUMENTS: + if (ARGCOUNT == 0) { + eap->line1 = eap->line2 = 0; + } else { + eap->line1 = 1; + eap->line2 = ARGCOUNT; + } + break; + case ADDR_QUICKFIX: + eap->line1 = 1; + eap->line2 = qf_get_size(eap); + if (eap->line2 == 0) { + eap->line2 = 1; + } + break; + } + eap->addr_count++; + } else if (*eap->cmd == '*') { + // '*' - visual area + if (eap->addr_type != ADDR_LINES) { + *errormsg = (char_u *)_(e_invrange); + return FAIL; + } + + eap->cmd++; + if (!eap->skip) { + pos_T *fp = getmark('<', false); + if (check_mark(fp) == FAIL) { + return FAIL; + } + eap->line1 = fp->lnum; + fp = getmark('>', false); + if (check_mark(fp) == FAIL) { + return FAIL; + } + eap->line2 = fp->lnum; + eap->addr_count++; + } + } + } else { + eap->line2 = lnum; + } + eap->addr_count++; + + if (*eap->cmd == ';') { + if (!eap->skip) { + curwin->w_cursor.lnum = eap->line2; + // don't leave the cursor on an illegal line or column + check_cursor(); + } + } else if (*eap->cmd != ',') { + break; + } + eap->cmd++; + } + + // One address given: set start and end lines. + if (eap->addr_count == 1) { + eap->line1 = eap->line2; + // ... but only implicit: really no address given + if (lnum == MAXLNUM) { + eap->addr_count = 0; + } + } + return OK; +} + /* * Check for an Ex command with optional tail. * If there is a match advance "pp" to the argument and return TRUE. @@ -3556,15 +3570,13 @@ const char * set_one_cmd_context( return NULL; } -/* - * skip a range specifier of the form: addr [,addr] [;addr] .. - * - * Backslashed delimiters after / or ? will be skipped, and commands will - * not be expanded between /'s and ?'s or after "'". - * - * Also skip white space and ":" characters. - * Returns the "cmd" pointer advanced to beyond the range. - */ +// Skip a range specifier of the form: addr [,addr] [;addr] .. +// +// Backslashed delimiters after / or ? will be skipped, and commands will +// not be expanded between /'s and ?'s or after "'". +// +// Also skip white space and ":" characters. +// Returns the "cmd" pointer advanced to beyond the range. char_u *skip_range( const char_u *cmd, int *ctx // pointer to xp_context or NULL -- cgit From 63abe3ca196aa0c889b8cf295e3a6c6c0c20cf2b Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 5 Nov 2019 20:13:06 +0000 Subject: Factor out parse_one_cmd() This will allow us to reuse the parsing logic elsewhere, namely for inccommand logic. --- src/nvim/ex_docmd.c | 411 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 259 insertions(+), 152 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index c48e5e0a4e..b826bb3262 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -140,6 +140,31 @@ struct dbg_stuff { except_T *current_exception; }; +typedef struct { + // parsed results + exarg_T *eap; + char_u *parsed_upto; // local we've parsed up to so far + char_u *cmd; // start of command + char_u *after_modifier; + + // errors + char_u *errormsg; + + // globals that need to be updated + cmdmod_T cmdmod; + int sandbox; + int msg_silent; + int emsg_silent; + bool ex_pressedreturn; + long p_verbose; + + // other side-effects + bool set_eventignore; + long verbose_save; + int save_msg_silent; + int did_esilent; + bool did_sandbox; +} parse_state_T; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_docmd.c.generated.h" @@ -1218,68 +1243,57 @@ static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite) return (char_u *)p; } -/* - * Execute one Ex command. - * - * If 'sourcing' is TRUE, the command will be included in the error message. - * - * 1. skip comment lines and leading space - * 2. handle command modifiers - * 3. skip over the range to find the command - * 4. parse the range - * 5. parse the command - * 6. parse arguments - * 7. switch on command name - * - * Note: "fgetline" can be NULL. - * - * This function may be called recursively! - */ -static char_u * do_one_cmd(char_u **cmdlinep, - int flags, - struct condstack *cstack, - LineGetter fgetline, - void *cookie /* argument for fgetline() */ - ) +static void parse_state_to_global(const parse_state_T *parse_state) { - char_u *p; - linenr_T lnum; - long n; - char_u *errormsg = NULL; /* error message */ - exarg_T ea; /* Ex command arguments */ - long verbose_save = -1; - int save_msg_scroll = msg_scroll; - int save_msg_silent = -1; - int did_esilent = 0; - int did_sandbox = FALSE; - cmdmod_T save_cmdmod; - const int save_reg_executing = reg_executing; - char_u *cmd; + cmdmod = parse_state->cmdmod; + sandbox = parse_state->sandbox; + msg_silent = parse_state->msg_silent; + emsg_silent = parse_state->emsg_silent; + ex_pressedreturn = parse_state->ex_pressedreturn; + p_verbose = parse_state->p_verbose; - memset(&ea, 0, sizeof(ea)); - ea.line1 = 1; - ea.line2 = 1; - ex_nesting_level++; + if (parse_state->set_eventignore) { + set_string_option_direct( + (char_u *)"ei", -1, (char_u *)"all", OPT_FREE, SID_NONE); + } +} - /* When the last file has not been edited :q has to be typed twice. */ - if (quitmore - /* avoid that a function call in 'statusline' does this */ - && !getline_equal(fgetline, cookie, get_func_line) - /* avoid that an autocommand, e.g. QuitPre, does this */ - && !getline_equal(fgetline, cookie, getnextac) - ) - --quitmore; +static void parse_state_from_global(parse_state_T *parse_state) +{ + memset(parse_state, 0, sizeof(*parse_state)); + parse_state->cmdmod = cmdmod; + parse_state->sandbox = sandbox; + parse_state->msg_silent = msg_silent; + parse_state->emsg_silent = emsg_silent; + parse_state->ex_pressedreturn = ex_pressedreturn; + parse_state->p_verbose = p_verbose; +} - /* - * Reset browse, confirm, etc.. They are restored when returning, for - * recursive calls. - */ - save_cmdmod = cmdmod; - memset(&cmdmod, 0, sizeof(cmdmod)); +// +// Parse one Ex command. +// +// This has no side-effects, except for modifying parameters +// passed in by pointer. +// +// The `out` should be zeroed, and its `ea` member initialised, +// before calling this function. +// +static bool parse_one_cmd( + char_u **cmdlinep, + parse_state_T *const out, + LineGetter fgetline, + void *fgetline_cookie) +{ + exarg_T ea = { + .line1 = 1, + .line2 = 1, + }; + *out->eap = ea; - /* "#!anything" is handled like a comment. */ - if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') - goto doend; + // "#!anything" is handled like a comment. + if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') { + return false; + } /* * Repeat until no more command modifiers are found. @@ -1289,70 +1303,76 @@ static char_u * do_one_cmd(char_u **cmdlinep, /* * 1. Skip comment lines and leading white space and colons. */ - while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':') - ++ea.cmd; + while (*ea.cmd == ' ' + || *ea.cmd == '\t' + || *ea.cmd == ':') { + ea.cmd++; + } - /* in ex mode, an empty line works like :+ */ + // in ex mode, an empty line works like :+ if (*ea.cmd == NUL && exmode_active - && (getline_equal(fgetline, cookie, getexmodeline) - || getline_equal(fgetline, cookie, getexline)) + && (getline_equal(fgetline, fgetline_cookie, getexmodeline) + || getline_equal(fgetline, fgetline_cookie, getexline)) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { ea.cmd = (char_u *)"+"; - ex_pressedreturn = true; + out->ex_pressedreturn = true; } - /* ignore comment and empty lines */ - if (*ea.cmd == '"') - goto doend; + // ignore comment and empty lines + if (*ea.cmd == '"') { + return false; + } if (*ea.cmd == NUL) { - ex_pressedreturn = true; - goto doend; + out->ex_pressedreturn = true; + return false; } /* * 2. Handle command modifiers. */ - p = skip_range(ea.cmd, NULL); + char_u *p = skip_range(ea.cmd, NULL); switch (*p) { - /* When adding an entry, also modify cmd_exists(). */ + // When adding an entry, also modify cmd_exists(). case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3)) break; - cmdmod.split |= WSP_ABOVE; + out->cmdmod.split |= WSP_ABOVE; continue; case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) { - cmdmod.split |= WSP_BELOW; + out->cmdmod.split |= WSP_BELOW; continue; } if (checkforcmd(&ea.cmd, "browse", 3)) { - cmdmod.browse = true; + out->cmdmod.browse = true; continue; } - if (!checkforcmd(&ea.cmd, "botright", 2)) + if (!checkforcmd(&ea.cmd, "botright", 2)) { break; - cmdmod.split |= WSP_BOT; + } + out->cmdmod.split |= WSP_BOT; continue; case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4)) break; - cmdmod.confirm = true; + out->cmdmod.confirm = true; continue; case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) { - cmdmod.keepmarks = true; + out->cmdmod.keepmarks = true; continue; } if (checkforcmd(&ea.cmd, "keepalt", 5)) { - cmdmod.keepalt = true; + out->cmdmod.keepalt = true; continue; } if (checkforcmd(&ea.cmd, "keeppatterns", 5)) { - cmdmod.keeppatterns = true; + out->cmdmod.keeppatterns = true; continue; } - if (!checkforcmd(&ea.cmd, "keepjumps", 5)) + if (!checkforcmd(&ea.cmd, "keepjumps", 5)) { break; - cmdmod.keepjumps = true; + } + out->cmdmod.keepjumps = true; continue; case 'f': { // only accept ":filter {pat} cmd" @@ -1362,7 +1382,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, break; } if (*p == '!') { - cmdmod.filter_force = true; + out->cmdmod.filter_force = true; p = skipwhite(p + 1); if (*p == NUL || ends_excmd(*p)) { break; @@ -1372,134 +1392,217 @@ static char_u * do_one_cmd(char_u **cmdlinep, if (p == NULL || *p == NUL) { break; } - cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC); - if (cmdmod.filter_regmatch.regprog == NULL) { + out->cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC); + if (out->cmdmod.filter_regmatch.regprog == NULL) { break; } ea.cmd = p; continue; } - /* ":hide" and ":hide | cmd" are not modifiers */ + // ":hide" and ":hide | cmd" are not modifiers case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3) || *p == NUL || ends_excmd(*p)) break; ea.cmd = p; - cmdmod.hide = true; + out->cmdmod.hide = true; continue; case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) { - cmdmod.lockmarks = true; + out->cmdmod.lockmarks = true; continue; } - if (!checkforcmd(&ea.cmd, "leftabove", 5)) + if (!checkforcmd(&ea.cmd, "leftabove", 5)) { break; - cmdmod.split |= WSP_ABOVE; + } + out->cmdmod.split |= WSP_ABOVE; continue; case 'n': if (checkforcmd(&ea.cmd, "noautocmd", 3)) { - if (cmdmod.save_ei == NULL) { - /* Set 'eventignore' to "all". Restore the - * existing option value later. */ - cmdmod.save_ei = vim_strsave(p_ei); - set_string_option_direct( - (char_u *)"ei", -1, (char_u *)"all", OPT_FREE, SID_NONE); + if (out->cmdmod.save_ei == NULL) { + // Set 'eventignore' to "all". Restore the + // existing option value later. + out->cmdmod.save_ei = vim_strsave(p_ei); + out->set_eventignore = true; } continue; } if (!checkforcmd(&ea.cmd, "noswapfile", 3)) { break; } - cmdmod.noswapfile = true; + out->cmdmod.noswapfile = true; continue; case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6)) break; - cmdmod.split |= WSP_BELOW; + out->cmdmod.split |= WSP_BELOW; continue; case 's': if (checkforcmd(&ea.cmd, "sandbox", 3)) { - if (!did_sandbox) - ++sandbox; - did_sandbox = TRUE; + if (!out->did_sandbox) { + out->sandbox++; + } + out->did_sandbox = true; continue; } - if (!checkforcmd(&ea.cmd, "silent", 3)) + if (!checkforcmd(&ea.cmd, "silent", 3)) { break; - if (save_msg_silent == -1) - save_msg_silent = msg_silent; - ++msg_silent; + } + if (out->save_msg_silent == -1) { + out->save_msg_silent = out->msg_silent; + } + out->msg_silent++; if (*ea.cmd == '!' && !ascii_iswhite(ea.cmd[-1])) { - /* ":silent!", but not "silent !cmd" */ + // ":silent!", but not "silent !cmd" ea.cmd = skipwhite(ea.cmd + 1); - ++emsg_silent; - ++did_esilent; + out->emsg_silent++; + out->did_esilent++; } continue; case 't': if (checkforcmd(&p, "tab", 3)) { - long tabnr = get_address(&ea, &ea.cmd, ADDR_TABS, ea.skip, false, 1); + long tabnr = get_address( + &ea, &ea.cmd, ADDR_TABS, ea.skip, false, 1); + if (tabnr == MAXLNUM) { - cmdmod.tab = tabpage_index(curtab) + 1; + out->cmdmod.tab = tabpage_index(curtab) + 1; } else { if (tabnr < 0 || tabnr > LAST_TAB_NR) { - errormsg = (char_u *)_(e_invrange); - goto doend; + out->errormsg = (char_u *)_(e_invrange); + return false; } - cmdmod.tab = tabnr + 1; + out->cmdmod.tab = tabnr + 1; } ea.cmd = p; continue; } - if (!checkforcmd(&ea.cmd, "topleft", 2)) + if (!checkforcmd(&ea.cmd, "topleft", 2)) { break; - cmdmod.split |= WSP_TOP; + } + out->cmdmod.split |= WSP_TOP; continue; case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3)) break; - if (save_msg_silent == -1) - save_msg_silent = msg_silent; - msg_silent = 0; + if (out->save_msg_silent == -1) { + out->save_msg_silent = out->msg_silent; + } + out->msg_silent = 0; continue; case 'v': if (checkforcmd(&ea.cmd, "vertical", 4)) { - cmdmod.split |= WSP_VERT; + out->cmdmod.split |= WSP_VERT; continue; } if (!checkforcmd(&p, "verbose", 4)) break; - if (verbose_save < 0) - verbose_save = p_verbose; - if (ascii_isdigit(*ea.cmd)) - p_verbose = atoi((char *)ea.cmd); - else - p_verbose = 1; + if (out->verbose_save < 0) { + out->verbose_save = out->p_verbose; + } + if (ascii_isdigit(*ea.cmd)) { + out->p_verbose = atoi((char *)ea.cmd); + } else { + out->p_verbose = 1; + } ea.cmd = p; continue; } break; } - char_u *after_modifier = ea.cmd; - - ea.skip = (did_emsg - || got_int - || current_exception - || (cstack->cs_idx >= 0 - && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE))); + out->after_modifier = ea.cmd; // 3. Skip over the range to find the command. Let "p" point to after it. // // We need the command to know what kind of range it uses. - cmd = ea.cmd; + out->cmd = ea.cmd; ea.cmd = skip_range(ea.cmd, NULL); if (*ea.cmd == '*') { ea.cmd = skipwhite(ea.cmd + 1); } - p = find_command(&ea, NULL); + out->parsed_upto = find_command(&ea, NULL); + + *out->eap = ea; + + return true; +} + +/* + * Execute one Ex command. + * + * If 'sourcing' is TRUE, the command will be included in the error message. + * + * 1. skip comment lines and leading space + * 2. handle command modifiers + * 3. skip over the range to find the command + * 4. parse the range + * 5. parse the command + * 6. parse arguments + * 7. switch on command name + * + * Note: "fgetline" can be NULL. + * + * This function may be called recursively! + */ +static char_u * do_one_cmd(char_u **cmdlinep, + int flags, + struct condstack *cstack, + LineGetter fgetline, + void *cookie /* argument for fgetline() */ + ) +{ + char_u *p; + linenr_T lnum; + long n; + char_u *errormsg = NULL; // error message + exarg_T ea; + int save_msg_scroll = msg_scroll; + parse_state_T parsed; + cmdmod_T save_cmdmod; + const int save_reg_executing = reg_executing; + + ex_nesting_level++; + + /* When the last file has not been edited :q has to be typed twice. */ + if (quitmore + /* avoid that a function call in 'statusline' does this */ + && !getline_equal(fgetline, cookie, get_func_line) + /* avoid that an autocommand, e.g. QuitPre, does this */ + && !getline_equal(fgetline, cookie, getnextac) + ) + --quitmore; + + /* + * Reset browse, confirm, etc.. They are restored when returning, for + * recursive calls. + */ + save_cmdmod = cmdmod; + memset(&cmdmod, 0, sizeof(cmdmod)); + + parse_state_from_global(&parsed); + parsed.eap = &ea; + parsed.verbose_save = -1; + parsed.save_msg_silent = -1; + parsed.did_esilent = 0; + parsed.did_sandbox = false; + bool parse_success = parse_one_cmd(cmdlinep, &parsed, fgetline, cookie); + parse_state_to_global(&parsed); + + // Update locals from parse_one_cmd() + errormsg = parsed.errormsg; + p = parsed.parsed_upto; + + if (!parse_success) { + goto doend; + } + + ea.skip = (did_emsg + || got_int + || current_exception + || (cstack->cs_idx >= 0 + && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE))); // Count this line for profiling if skip is TRUE. if (do_profiling == PROF_YES @@ -1570,7 +1673,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, } } - ea.cmd = cmd; + ea.cmd = parsed.cmd; if (parse_cmd_address(&ea, &errormsg) == FAIL) { goto doend; } @@ -1651,8 +1754,8 @@ static char_u * do_one_cmd(char_u **cmdlinep, if (!(flags & DOCMD_VERBOSE)) { // If the modifier was parsed OK the error must be in the following // command - if (after_modifier != NULL) { - append_command(after_modifier); + if (parsed.after_modifier != NULL) { + append_command(parsed.after_modifier); } else { append_command(*cmdlinep); } @@ -2120,12 +2223,12 @@ static char_u * do_one_cmd(char_u **cmdlinep, // The :try command saves the emsg_silent flag, reset it here when // ":silent! try" was used, it should only apply to :try itself. - if (ea.cmdidx == CMD_try && did_esilent > 0) { - emsg_silent -= did_esilent; + if (ea.cmdidx == CMD_try && parsed.did_esilent > 0) { + emsg_silent -= parsed.did_esilent; if (emsg_silent < 0) { emsg_silent = 0; } - did_esilent = 0; + parsed.did_esilent = 0; } // 7. Execute the command. @@ -2191,8 +2294,9 @@ doend: ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); - if (verbose_save >= 0) - p_verbose = verbose_save; + if (parsed.verbose_save >= 0) { + p_verbose = parsed.verbose_save; + } if (cmdmod.save_ei != NULL) { /* Restore 'eventignore' to the value before ":noautocmd". */ set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei, @@ -2207,16 +2311,18 @@ doend: cmdmod = save_cmdmod; reg_executing = save_reg_executing; - if (save_msg_silent != -1) { - /* messages could be enabled for a serious error, need to check if the - * counters don't become negative */ - if (!did_emsg || msg_silent > save_msg_silent) - msg_silent = save_msg_silent; - emsg_silent -= did_esilent; - if (emsg_silent < 0) + if (parsed.save_msg_silent != -1) { + // messages could be enabled for a serious error, need to check if the + // counters don't become negative + if (!did_emsg || msg_silent > parsed.save_msg_silent) { + msg_silent = parsed.save_msg_silent; + } + emsg_silent -= parsed.did_esilent; + if (emsg_silent < 0) { emsg_silent = 0; - /* Restore msg_scroll, it's set by file I/O commands, even when no - * message is actually displayed. */ + } + // Restore msg_scroll, it's set by file I/O commands, even when no + // message is actually displayed. msg_scroll = save_msg_scroll; /* "silent reg" or "silent echo x" inside "redir" leaves msg_col @@ -2225,8 +2331,9 @@ doend: msg_col = 0; } - if (did_sandbox) - --sandbox; + if (parsed.did_sandbox) { + sandbox--; + } if (ea.nextcmd && *ea.nextcmd == NUL) /* not really a next command */ ea.nextcmd = NULL; -- cgit From d79164c9f9ffbb17b82b3a523e217e61f43697be Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 16 Nov 2019 03:34:25 -0500 Subject: vim-patch:8.1.0992: :normal resets reg_executing() result #11398 Problem: A :normal command while executing a register resets the reg_executing() result. Solution: Save and restore reg_executing. (closes vim/vim#4066) https://github.com/vim/vim/commit/cce713ddcc0c9ab29926c28e287cbb587a959b08 --- src/nvim/ex_docmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 7d02623d67..6a8bea28a7 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8207,6 +8207,7 @@ static void ex_normal(exarg_T *eap) int save_insertmode = p_im; int save_finish_op = finish_op; long save_opcount = opcount; + const int save_reg_executing = reg_executing; char_u *arg = NULL; int l; char_u *p; @@ -8301,7 +8302,8 @@ static void ex_normal(exarg_T *eap) p_im = save_insertmode; finish_op = save_finish_op; opcount = save_opcount; - msg_didout |= save_msg_didout; /* don't reset msg_didout now */ + reg_executing = save_reg_executing; + msg_didout |= save_msg_didout; // don't reset msg_didout now /* Restore the state (needed when called from a function executed for * 'indentexpr'). Update the mouse and cursor, they may have changed. */ -- cgit From 7a0a2eb310a5568d6ee743d65f5ae12f60111c6e Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 24 Nov 2019 21:50:24 -0500 Subject: vim-patch:8.1.1732: completion in cmdwin does not work for buffer-local commands Problem: Completion in cmdwin does not work for buffer-local commands. Solution: Use the right buffer. (closes vim/vim#4711) https://github.com/vim/vim/commit/f03e328348f87e1fe8ce4aad2a6a4237b9f78ce3 --- src/nvim/ex_docmd.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 641edf4610..f18ebffa0a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5133,9 +5133,11 @@ static void uc_list(char_u *name, size_t name_len) ucmd_T *cmd; int len; uint32_t a; - garray_T *gap; - gap = &curbuf->b_ucmds; + // In cmdwin, the alternative buffer should be used. + garray_T *gap = (cmdwin_type != 0 && get_cmdline_type() == NUL) + ? &prevwin->w_buffer->b_ucmds + : &curbuf->b_ucmds; for (;; ) { for (i = 0; i < gap->ga_len; ++i) { cmd = USER_CMD_GA(gap, i); @@ -5984,13 +5986,21 @@ char_u *get_user_cmd_addr_type(expand_T *xp, int idx) /* * Function given to ExpandGeneric() to obtain the list of user command names. */ -char_u *get_user_commands(expand_T *xp, int idx) +char_u *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - if (idx < curbuf->b_ucmds.ga_len) - return USER_CMD_GA(&curbuf->b_ucmds, idx)->uc_name; - idx -= curbuf->b_ucmds.ga_len; - if (idx < ucmds.ga_len) + // In cmdwin, the alternative buffer should be used. + const buf_T *const buf = (cmdwin_type != 0 && get_cmdline_type() == NUL) + ? prevwin->w_buffer + : curbuf; + + if (idx < buf->b_ucmds.ga_len) { + return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; + } + idx -= buf->b_ucmds.ga_len; + if (idx < ucmds.ga_len) { return USER_CMD(idx)->uc_name; + } return NULL; } -- cgit From f196ab87a1b5a9da1326d4de883ab7e97a0bb1f0 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 26 Nov 2019 20:05:52 -0500 Subject: vim-patch:8.1.2348: :const cannot be followed by "| endif" Problem: :const cannot be followed by "| endif". Solution: Check following command for :const. (closes vim/vim#5269) Also fix completion after :const. https://github.com/vim/vim/commit/8f76e6b12b958f2779444a92234bbaf3f49eeb99 --- src/nvim/ex_docmd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index f18ebffa0a..b24bf119b3 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2126,6 +2126,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, case CMD_browse: case CMD_call: case CMD_confirm: + case CMD_const: case CMD_delfunction: case CMD_djump: case CMD_dlist: @@ -3437,6 +3438,7 @@ const char * set_one_cmd_context( case CMD_syntax: set_context_in_syntax_cmd(xp, arg); break; + case CMD_const: case CMD_let: case CMD_if: case CMD_elseif: -- cgit From 90f2b1360469821dfd0e7e75d0b43859aa27dac1 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 26 Nov 2019 20:40:12 -0500 Subject: vim-patch:8.1.2349: :lockvar and :unlockvar cannot be followed by "| endif" Problem: :lockvar and :unlockvar cannot be followed by "| endif". Solution: Check for following commands. (closes vim/vim#5269) https://github.com/vim/vim/commit/cc4423ae13d78367a3d0b5756783523d3b3a1d31 --- src/nvim/ex_docmd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index b24bf119b3..743286c64a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2151,6 +2151,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, case CMD_leftabove: case CMD_let: case CMD_lockmarks: + case CMD_lockvar: case CMD_lua: case CMD_match: case CMD_mzscheme: @@ -2179,6 +2180,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, case CMD_tilde: case CMD_topleft: case CMD_unlet: + case CMD_unlockvar: case CMD_verbose: case CMD_vertical: case CMD_wincmd: -- cgit From b1991f66d5845ccb72c73fdf39153a0e1fbb1124 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 1 Dec 2019 22:26:36 -0800 Subject: API: rename nvim_source => nvim_exec - Eliminate nvim_source_output(): add boolean `output` param to nvim_exec() instead. --- src/nvim/ex_docmd.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 743286c64a..dc2726709f 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -421,13 +421,12 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, // If force_abort is set, we cancel everything. did_emsg = false; - /* - * KeyTyped is only set when calling vgetc(). Reset it here when not - * calling vgetc() (sourced command lines). - */ + // KeyTyped is only set when calling vgetc(). Reset it here when not + // calling vgetc() (sourced command lines). if (!(flags & DOCMD_KEYTYPED) - && !getline_equal(fgetline, cookie, getexline)) + && !getline_equal(fgetline, cookie, getexline)) { KeyTyped = false; + } /* * Continue executing command lines: -- cgit From c34130d13a842ae0c0c1724d05800a954547d327 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 1 Dec 2019 22:43:16 -0800 Subject: API: deprecate nvim_command_output --- src/nvim/ex_docmd.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index dc2726709f..30c1373445 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -296,25 +296,23 @@ int do_cmdline_cmd(const char *cmd) DOCMD_NOWAIT|DOCMD_KEYTYPED); } -/* - * do_cmdline(): execute one Ex command line - * - * 1. Execute "cmdline" when it is not NULL. - * If "cmdline" is NULL, or more lines are needed, fgetline() is used. - * 2. Split up in parts separated with '|'. - * - * This function can be called recursively! - * - * flags: - * DOCMD_VERBOSE - The command will be included in the error message. - * DOCMD_NOWAIT - Don't call wait_return() and friends. - * DOCMD_REPEAT - Repeat execution until fgetline() returns NULL. - * DOCMD_KEYTYPED - Don't reset KeyTyped. - * DOCMD_EXCRESET - Reset the exception environment (used for debugging). - * DOCMD_KEEPLINE - Store first typed line (for repeating with "."). - * - * return FAIL if cmdline could not be executed, OK otherwise - */ +/// do_cmdline(): execute one Ex command line +/// +/// 1. Execute "cmdline" when it is not NULL. +/// If "cmdline" is NULL, or more lines are needed, fgetline() is used. +/// 2. Split up in parts separated with '|'. +/// +/// This function can be called recursively! +/// +/// flags: +/// DOCMD_VERBOSE - The command will be included in the error message. +/// DOCMD_NOWAIT - Don't call wait_return() and friends. +/// DOCMD_REPEAT - Repeat execution until fgetline() returns NULL. +/// DOCMD_KEYTYPED - Don't reset KeyTyped. +/// DOCMD_EXCRESET - Reset the exception environment (used for debugging). +/// DOCMD_KEEPLINE - Store first typed line (for repeating with "."). +/// +/// @return FAIL if cmdline could not be executed, OK otherwise int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, /* argument for fgetline() */ int flags) -- cgit From 9e6ebed6f4c695cfa00710e003d606d5d720b542 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 16 Dec 2019 19:48:57 -0500 Subject: vim-patch:8.2.0013: not using a typedef for condstack Problem: Not using a typedef for condstack. Solution: Add a typedef. https://github.com/vim/vim/commit/ddef129160ff0676e5da482071fb2fdc2988ac34 --- src/nvim/ex_docmd.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 30c1373445..d16ad9db2c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -325,13 +325,13 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, int count = 0; /* line number count */ int did_inc = FALSE; /* incremented RedrawingDisabled */ int retval = OK; - struct condstack cstack; /* conditional stack */ - garray_T lines_ga; /* keep lines for ":while"/":for" */ - int current_line = 0; /* active line in lines_ga */ - char_u *fname = NULL; /* function or script name */ - linenr_T *breakpoint = NULL; /* ptr to breakpoint field in cookie */ - int *dbg_tick = NULL; /* ptr to dbg_tick field in cookie */ - struct dbg_stuff debug_saved; /* saved things for debug mode */ + cstack_T cstack; // conditional stack + garray_T lines_ga; // keep lines for ":while"/":for" + int current_line = 0; // active line in lines_ga + char_u *fname = NULL; // function or script name + linenr_T *breakpoint = NULL; // ptr to breakpoint field in cookie + int *dbg_tick = NULL; // ptr to dbg_tick field in cookie + struct dbg_stuff debug_saved; // saved things for debug mode int initial_trylevel; struct msglist **saved_msg_list = NULL; struct msglist *private_msg_list; @@ -361,7 +361,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, EMSG(_("E169: Command too recursive")); // When converting to an exception, we do not include the command name // since this is not an error of the specific command. - do_errthrow((struct condstack *)NULL, (char_u *)NULL); + do_errthrow((cstack_T *)NULL, (char_u *)NULL); msg_list = saved_msg_list; return FAIL; } @@ -1545,7 +1545,7 @@ static bool parse_one_cmd( */ static char_u * do_one_cmd(char_u **cmdlinep, int flags, - struct condstack *cstack, + cstack_T *cstack, LineGetter fgetline, void *cookie /* argument for fgetline() */ ) -- cgit From 23dbe73585fbedfdeb09aac032ffe12ae79f7397 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 25 Dec 2019 18:30:28 -0500 Subject: ex_docmd: fix pvs/v781 --- src/nvim/ex_docmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index d16ad9db2c..afe2660cdf 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2807,9 +2807,11 @@ int modifier_len(char_u *cmd) for (j = 0; p[j] != NUL; ++j) if (p[j] != cmdmods[i].name[j]) break; - if (!ASCII_ISALPHA(p[j]) && j >= cmdmods[i].minlen - && (p == cmd || cmdmods[i].has_count)) + if (j >= cmdmods[i].minlen + && !ASCII_ISALPHA(p[j]) + && (p == cmd || cmdmods[i].has_count)) { return j + (int)(p - cmd); + } } return 0; } -- cgit From 45759e44f9cff9deef1538933fad3e42f94d5930 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 8 Jan 2020 01:08:55 -0500 Subject: Remove (void) hacks, Mark unused attrs --- src/nvim/ex_docmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index afe2660cdf..30e7ecd434 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -10397,8 +10397,6 @@ bool cmd_can_preview(char_u *cmd) Dictionary commands_array(buf_T *buf) { Dictionary rv = ARRAY_DICT_INIT; - Object obj = NIL; - (void)obj; // Avoid "dead assignment" warning. char str[20]; garray_T *gap = (buf == NULL) ? &ucmds : &buf->b_ucmds; @@ -10429,7 +10427,7 @@ Dictionary commands_array(buf_T *buf) PUT(d, "complete_arg", cmd->uc_compl_arg == NULL ? NIL : STRING_OBJ(cstr_to_string((char *)cmd->uc_compl_arg))); - obj = NIL; + Object obj = NIL; if (cmd->uc_argt & COUNT) { if (cmd->uc_def >= 0) { snprintf(str, sizeof(str), "%" PRId64, (int64_t)cmd->uc_def); -- cgit From 8e385eb46a8b961a760e05b4cfa053cf713def62 Mon Sep 17 00:00:00 2001 From: We're Yet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Sat, 18 Jan 2020 13:19:56 -0800 Subject: tabpage: :tabs indicates previous tabpage's curwin --- src/nvim/ex_docmd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 30e7ecd434..6bda62594e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7037,6 +7037,10 @@ static void ex_tabs(exarg_T *eap) msg_start(); msg_scroll = TRUE; + win_T *lastused_win = valid_tabpage(lastused_tabpage) + ? lastused_tabpage->tp_curwin + : NULL; + FOR_ALL_TABS(tp) { if (got_int) { break; @@ -7054,7 +7058,7 @@ static void ex_tabs(exarg_T *eap) } msg_putchar('\n'); - msg_putchar(wp == curwin ? '>' : ' '); + msg_putchar(wp == curwin ? '>' : wp == lastused_win ? '#' : ' '); msg_putchar(' '); msg_putchar(bufIsChanged(wp->w_buffer) ? '+' : ' '); msg_putchar(' '); -- cgit From f245c0218adc9ff3452660dff97e62cea8e9a411 Mon Sep 17 00:00:00 2001 From: butwerenotthereyet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Mon, 20 Jan 2020 15:14:51 -0800 Subject: tabpage: "tabnext #" switches to previous tab #11734 --- src/nvim/ex_docmd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6bda62594e..02bee838d5 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4651,6 +4651,8 @@ static int get_tabpage_arg(exarg_T *eap) if (relative == 0) { if (STRCMP(p, "$") == 0) { tab_number = LAST_TAB_NR; + } else if (STRCMP(p, "#") == 0) { + tab_number = tabpage_index(lastused_tabpage); } else if (p == p_save || *p_save == '-' || *p != NUL || tab_number > LAST_TAB_NR) { // No numbers as argument. -- cgit From cf67f19ac2104ece76d040c8184bc287428299b3 Mon Sep 17 00:00:00 2001 From: Alexandre Dubray Date: Tue, 9 Jan 2018 12:01:02 +0100 Subject: mksession: restore same :term buf in split windows Problem: When session-restore creates a terminal buffer with command like `:edit term://.//16450:/bin/bash`, the buffer gets a different name (depends on PID). Thus the later call to `bufexists('term://.//16450:/bin/bash)` will return false. Solution: Force the buffer name with :file. This as least ensures the same buffer will show in multiple windows correctly, as expected when saving the session. But it still has problems: 1. the PID in the buffer name is bogus 2. redundant :terminal buffers still hang around fix #5250 --- src/nvim/ex_docmd.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 02bee838d5..0732409666 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -9346,6 +9346,10 @@ makeopens( /* * Restore the view of the window (options, file, cursor, etc.). */ + if (put_line(fd, "let s:buffer_names = []") == FAIL) { + return FAIL; + } + for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { if (!ses_do_win(wp)) continue; @@ -9357,6 +9361,16 @@ makeopens( next_arg_idx = wp->w_arg_idx; } + if (put_line(fd, "for [s:name, s:tbuf] in s:buffer_names") == FAIL + || put_line(fd, " if buflisted(s:tbuf)") == FAIL + || put_line(fd, " execute 'buffer' fnameescape(s:tbuf)") == FAIL + || put_line(fd, " execute 'file' fnameescape(s:name)") == FAIL + || put_line(fd, " endif") == FAIL + || put_line(fd, "endfor") == FAIL + || put_line(fd, "unlet! s:buffer_names s:tbuf s:name") == FAIL) { + return FAIL; + } + /* The argument index in the first tab page is zero, need to set it in * each window. For further tab pages it's the window where we do * "tabedit". */ @@ -9662,6 +9676,19 @@ put_view( || put_eol(fd) == FAIL) { return FAIL; } + + if (fputs("call add(s:buffer_names, [bufname('%'),'", fd) < 0 + || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL + || fputs("'])", fd) < 0 + || put_eol(fd) == FAIL) { + return FAIL; + } + + if (fputs("file ", fd) < 0 + || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL + || put_eol(fd) == FAIL) { + return FAIL; + } } else { // No file in this buffer, just make it empty. if (put_line(fd, "enew") == FAIL) { -- cgit From 1e103b3c12597a9dd2f20d45686822ab6ee089b0 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 02:43:12 -0800 Subject: mksession: simplify generated commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doing ":file …" immediately after is enough to fixup the :terminal buffer name. ref #5250 --- src/nvim/ex_docmd.c | 78 ++++++++++++++++++----------------------------------- 1 file changed, 26 insertions(+), 52 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 0732409666..5253233c15 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8090,14 +8090,12 @@ static void close_redir(void) static int mksession_nl = FALSE; /* use NL only in put_eol() */ #endif -/* - * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession". - */ +/// ":mkexrc", ":mkvimrc", ":mkview", ":mksession". static void ex_mkrc(exarg_T *eap) { FILE *fd; int failed = false; - int view_session = false; + int view_session = false; // :mkview, :mksession int using_vdir = false; // using 'viewdir'? char *viewFile = NULL; unsigned *flagp; @@ -8159,11 +8157,11 @@ static void ex_mkrc(exarg_T *eap) failed = TRUE; } - if (!view_session - || (eap->cmdidx == CMD_mksession - && (*flagp & SSOP_OPTIONS))) + if (!view_session || (eap->cmdidx == CMD_mksession + && (*flagp & SSOP_OPTIONS))) { failed |= (makemap(fd, NULL) == FAIL || makeset(fd, OPT_GLOBAL, FALSE) == FAIL); + } if (!failed && view_session) { if (put_line(fd, @@ -9119,15 +9117,13 @@ char_u *expand_sfile(char_u *arg) } -/* - * Write openfile commands for the current buffers to an .exrc file. - * Return FAIL on error, OK otherwise. - */ -static int -makeopens( - FILE *fd, - char_u *dirnow /* Current directory name */ -) +/// Writes commands for restoring the current buffers, for :mksession. +/// +/// @param dirnow Current directory name +/// @param fd File descriptor to write to +/// +/// @return FAIL on error, OK otherwise. +static int makeopens(FILE *fd, char_u *dirnow) { int only_save_windows = TRUE; int nr; @@ -9240,12 +9236,11 @@ makeopens( restore_stal = TRUE; } - /* - * May repeat putting Windows for each tab, when "tabpages" is in - * 'sessionoptions'. - * Don't use goto_tabpage(), it may change directory and trigger - * autocommands. - */ + // + // For each tab: + // - Put windows for each tab, when "tabpages" is in 'sessionoptions'. + // - Don't use goto_tabpage(), it may change CWD and trigger autocommands. + // tab_firstwin = firstwin; /* first window in tab page "tabnr" */ tab_topframe = topframe; for (tabnr = 1;; tabnr++) { @@ -9269,11 +9264,11 @@ makeopens( need_tabnew = TRUE; } - /* - * Before creating the window layout, try loading one file. If this - * is aborted we don't end up with a number of useless windows. - * This may have side effects! (e.g., compressed or network file). - */ + // + // Before creating the window layout, try loading one file. If this + // is aborted we don't end up with a number of useless windows. + // This may have side effects! (e.g., compressed or network file). + // for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { if (ses_do_win(wp) && wp->w_buffer->b_ffname != NULL @@ -9343,13 +9338,9 @@ makeopens( return FAIL; } - /* - * Restore the view of the window (options, file, cursor, etc.). - */ - if (put_line(fd, "let s:buffer_names = []") == FAIL) { - return FAIL; - } - + // + // Restore the view of the window (options, file, cursor, etc.). + // for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { if (!ses_do_win(wp)) continue; @@ -9361,16 +9352,6 @@ makeopens( next_arg_idx = wp->w_arg_idx; } - if (put_line(fd, "for [s:name, s:tbuf] in s:buffer_names") == FAIL - || put_line(fd, " if buflisted(s:tbuf)") == FAIL - || put_line(fd, " execute 'buffer' fnameescape(s:tbuf)") == FAIL - || put_line(fd, " execute 'file' fnameescape(s:name)") == FAIL - || put_line(fd, " endif") == FAIL - || put_line(fd, "endfor") == FAIL - || put_line(fd, "unlet! s:buffer_names s:tbuf s:name") == FAIL) { - return FAIL; - } - /* The argument index in the first tab page is zero, need to set it in * each window. For further tab pages it's the window where we do * "tabedit". */ @@ -9677,14 +9658,7 @@ put_view( return FAIL; } - if (fputs("call add(s:buffer_names, [bufname('%'),'", fd) < 0 - || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL - || fputs("'])", fd) < 0 - || put_eol(fd) == FAIL) { - return FAIL; - } - - if (fputs("file ", fd) < 0 + if (fputs("silent file ", fd) < 0 || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL || put_eol(fd) == FAIL) { return FAIL; -- cgit From 598a1cd7c5b9b0f4e4b175f55b58bdb0e1a398eb Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 03:09:18 -0800 Subject: mksession: avoid ":file …" when restoring non-terminal bufs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nvim/ex_docmd.c | 84 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 34 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 5253233c15..6791bbd34c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8160,7 +8160,7 @@ static void ex_mkrc(exarg_T *eap) if (!view_session || (eap->cmdidx == CMD_mksession && (*flagp & SSOP_OPTIONS))) { failed |= (makemap(fd, NULL) == FAIL - || makeset(fd, OPT_GLOBAL, FALSE) == FAIL); + || makeset(fd, OPT_GLOBAL, false) == FAIL); } if (!failed && view_session) { @@ -9241,7 +9241,7 @@ static int makeopens(FILE *fd, char_u *dirnow) // - Put windows for each tab, when "tabpages" is in 'sessionoptions'. // - Don't use goto_tabpage(), it may change CWD and trigger autocommands. // - tab_firstwin = firstwin; /* first window in tab page "tabnr" */ + tab_firstwin = firstwin; // First window in tab page "tabnr". tab_topframe = topframe; for (tabnr = 1;; tabnr++) { tabpage_T *tp = find_tabpage(tabnr); @@ -9658,11 +9658,18 @@ put_view( return FAIL; } - if (fputs("silent file ", fd) < 0 - || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL - || put_eol(fd) == FAIL) { + char *fname_esc = + ses_escape_fname(ses_get_fname(wp->w_buffer, flagp, false), flagp); + // Fixup :terminal buffer name. + if (fprintf(fd, + "if &buftype ==# 'terminal'\n" + " silent file %s\n" + "endif\n", + fname_esc) < 0) { + xfree(fname_esc); return FAIL; } + xfree(fname_esc); } else { // No file in this buffer, just make it empty. if (put_line(fd, "enew") == FAIL) { @@ -9828,44 +9835,45 @@ ses_arglist( return OK; } -/// Write a buffer name to the session file. -/// Also ends the line, if "add_eol" is true. -/// Returns FAIL if writing fails. -static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, bool add_eol) +/// Gets the buffer name for `buf`. +static char *ses_get_fname(buf_T *buf, unsigned *flagp, bool add_eol) { - char_u *name; - - /* Use the short file name if the current directory is known at the time - * the session file will be sourced. - * Don't do this for ":mkview", we don't know the current directory. - * Don't do this after ":lcd", we don't keep track of what the current - * directory is. */ + // Use the short file name if the current directory is known at the time + // the session file will be sourced. + // Don't do this for ":mkview", we don't know the current directory. + // Don't do this after ":lcd", we don't keep track of what the current + // directory is. if (buf->b_sfname != NULL && flagp == &ssop_flags && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR)) && !p_acd - && !did_lcd) - name = buf->b_sfname; - else - name = buf->b_ffname; - if (ses_put_fname(fd, name, flagp) == FAIL + && !did_lcd) { + return (char *)buf->b_sfname; + } + return (char *)buf->b_ffname; +} +/// Write a buffer name to the session file. +/// Also ends the line, if "add_eol" is true. +/// Returns FAIL if writing fails. +static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, bool add_eol) +{ + char *name = ses_get_fname(buf, flagp, add_eol); + if (ses_put_fname(fd, (char_u *)name, flagp) == FAIL || (add_eol && put_eol(fd) == FAIL)) { return FAIL; } return OK; } -/* - * Write a file name to the session file. - * Takes care of the "slash" option in 'sessionoptions' and escapes special - * characters. - * Returns FAIL if writing fails. - */ -static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp) +// Escapes a filename for session writing. +// Takes care of "slash" flag in 'sessionoptions' and escapes special +// characters. +// +// Returns allocated string or NULL. +static char *ses_escape_fname(char *name, unsigned *flagp) { - char_u *p; - - char_u *sname = home_replace_save(NULL, name); + char *p; + char *sname = (char *)home_replace_save(NULL, (char_u *)name); if (*flagp & SSOP_SLASH) { // change all backslashes to forward slashes @@ -9877,11 +9885,19 @@ static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp) } // Escape special characters. - p = (char_u *)vim_strsave_fnameescape((const char *)sname, false); + p = vim_strsave_fnameescape(sname, false); xfree(sname); + return p; +} - /* write the result */ - bool retval = fputs((char *)p, fd) < 0 ? FAIL : OK; +// Write a file name to the session file. +// Takes care of the "slash" option in 'sessionoptions' and escapes special +// characters. +// Returns FAIL if writing fails. +static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp) +{ + char *p = ses_escape_fname((char *)name, flagp); + bool retval = fputs(p, fd) < 0 ? FAIL : OK; xfree(p); return retval; } -- cgit From 2c1d12d0beda7b359fec94c00746b7206ae8fedd Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 03:18:45 -0800 Subject: mksession: always write LF "\n" line-endings - remove `MKSESSION_NL`, `mksession_nl` - deprecate the "unix" flag of 'sessionoptions' There is no reason to choose CRLF or LF for session files. Instead just always write LF. --- src/nvim/ex_docmd.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6791bbd34c..2950b2950c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8085,11 +8085,6 @@ static void close_redir(void) } } -#ifdef USE_CRNL -# define MKSESSION_NL -static int mksession_nl = FALSE; /* use NL only in put_eol() */ -#endif - /// ":mkexrc", ":mkvimrc", ":mkview", ":mksession". static void ex_mkrc(exarg_T *eap) { @@ -8142,12 +8137,6 @@ static void ex_mkrc(exarg_T *eap) else flagp = &ssop_flags; -#ifdef MKSESSION_NL - /* "unix" in 'sessionoptions': use NL line separator */ - if (view_session && (*flagp & SSOP_UNIX)) - mksession_nl = TRUE; -#endif - /* Write the version command for :mkvimrc */ if (eap->cmdidx == CMD_mkvimrc) (void)put_line(fd, "version 6.0"); @@ -8236,9 +8225,6 @@ static void ex_mkrc(exarg_T *eap) } xfree(tbuf); } -#ifdef MKSESSION_NL - mksession_nl = FALSE; -#endif } xfree(viewFile); @@ -9964,19 +9950,11 @@ static char *get_view_file(int c) } -/* - * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession". - * Return FAIL for a write error. - */ +/// TODO(justinmk): remove this. Formerly used to choose CRLF or LF for session +// files, but that's useless--instead we always write LF. int put_eol(FILE *fd) { -#if defined(USE_CRNL) && defined(MKSESSION_NL) - if ((!mksession_nl && putc('\r', fd) < 0) || putc('\n', fd) < 0) { -#elif defined(USE_CRNL) - if (putc('\r', fd) < 0 || putc('\n', fd) < 0) { -#else if (putc('\n', fd) < 0) { -#endif return FAIL; } return OK; -- cgit From 2070c082b516361161dba04e72fcaafad8bc3860 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 03:45:48 -0800 Subject: cleanup/ex_docmd.c: remove most put_line() calls - prefer fprintf() instead of put_line() - PUTLINE_FAIL macro to avoid some boilerplate --- src/nvim/ex_docmd.c | 349 +++++++++++++++++++++++++--------------------------- 1 file changed, 169 insertions(+), 180 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2950b2950c..2b952b3f15 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8085,6 +8085,9 @@ static void close_redir(void) } } +#define PUTLINE_FAIL(s) \ + do { if (FAIL == put_line(fd, (s))) { return FAIL; } } while (0) + /// ":mkexrc", ":mkvimrc", ":mkview", ":mksession". static void ex_mkrc(exarg_T *eap) { @@ -8137,9 +8140,10 @@ static void ex_mkrc(exarg_T *eap) else flagp = &ssop_flags; - /* Write the version command for :mkvimrc */ - if (eap->cmdidx == CMD_mkvimrc) + // Write the version command for :mkvimrc + if (eap->cmdidx == CMD_mkvimrc) { (void)put_line(fd, "version 6.0"); + } if (eap->cmdidx == CMD_mksession) { if (put_line(fd, "let SessionLoad = 1") == FAIL) @@ -8200,14 +8204,17 @@ static void ex_mkrc(exarg_T *eap) failed |= (put_view(fd, curwin, !using_vdir, flagp, -1) == FAIL); } - if (put_line(fd, "let &so = s:so_save | let &siso = s:siso_save") - == FAIL) - failed = TRUE; - if (put_line(fd, "doautoall SessionLoadPost") == FAIL) - failed = TRUE; + if (fprintf(fd, + "%s", + "let &so = s:so_save | let &siso = s:siso_save\n" + "doautoall SessionLoadPost\n") + < 0) { + failed = true; + } if (eap->cmdidx == CMD_mksession) { - if (put_line(fd, "unlet SessionLoad") == FAIL) - failed = TRUE; + if (fprintf(fd, "unlet SessionLoad\n") < 0) { + failed = true; + } } } if (put_line(fd, "\" vim: set ft=vim :") == FAIL) @@ -9127,28 +9134,21 @@ static int makeopens(FILE *fd, char_u *dirnow) only_save_windows = FALSE; /* Save ALL buffers */ // Begin by setting v:this_session, and then other sessionable variables. - if (put_line(fd, "let v:this_session=expand(\":p\")") == FAIL) { - return FAIL; - } + PUTLINE_FAIL("let v:this_session=expand(\":p\")"); if (ssop_flags & SSOP_GLOBALS) { if (store_session_globals(fd) == FAIL) { return FAIL; } } - /* - * Close all windows but one. - */ - if (put_line(fd, "silent only") == FAIL) - return FAIL; + // Close all windows but one. + PUTLINE_FAIL("silent only"); - /* - * Now a :cd command to the session directory or the current directory - */ + // + // Now a :cd command to the session directory or the current directory + // if (ssop_flags & SSOP_SESDIR) { - if (put_line(fd, "exe \"cd \" . escape(expand(\":p:h\"), ' ')") - == FAIL) - return FAIL; + PUTLINE_FAIL("exe \"cd \" . escape(expand(\":p:h\"), ' ')"); } else if (ssop_flags & SSOP_CURDIR) { sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow); if (fputs("cd ", fd) < 0 @@ -9160,27 +9160,20 @@ static int makeopens(FILE *fd, char_u *dirnow) xfree(sname); } - /* - * If there is an empty, unnamed buffer we will wipe it out later. - * Remember the buffer number. - */ - if (put_line(fd, - "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") - == - FAIL) - return FAIL; - if (put_line(fd, " let s:wipebuf = bufnr('%')") == FAIL) - return FAIL; - if (put_line(fd, "endif") == FAIL) - return FAIL; - - /* - * Now save the current files, current buffer first. - */ - if (put_line(fd, "set shortmess=aoO") == FAIL) + if (fprintf(fd, + "%s", + // If there is an empty, unnamed buffer we will wipe it out later. + // Remember the buffer number. + "if expand('%') == '' && !&modified && line('$') <= 1" + " && getline(1) == ''\n" + " let s:wipebuf = bufnr('%')\n" + "endif\n" + // Now save the current files, current buffer first. + "set shortmess=aoO\n") < 0) { return FAIL; + } - /* Now put the other buffers into the buffer list */ + // Now put the other buffers into the buffer list. FOR_ALL_BUFFERS(buf) { if (!(only_save_windows && buf->b_nwindows == 0) && !(buf->b_help && !(ssop_flags & SSOP_HELP)) @@ -9216,9 +9209,7 @@ static int makeopens(FILE *fd, char_u *dirnow) // in the first tab, which may cause problems. Set 'showtabline' to 2 // temporarily to avoid that. if (p_stal == 1 && first_tabpage->tp_next != NULL) { - if (put_line(fd, "set stal=2") == FAIL) { - return FAIL; - } + PUTLINE_FAIL("set stal=2"); restore_stal = TRUE; } @@ -9273,26 +9264,29 @@ static int makeopens(FILE *fd, char_u *dirnow) } } - /* If no file got edited create an empty tab page. */ - if (need_tabnew && put_line(fd, "tabnew") == FAIL) + // If no file got edited create an empty tab page. + if (need_tabnew && put_line(fd, "tabnew") == FAIL) { return FAIL; + } - /* - * Save current window layout. - */ - if (put_line(fd, "set splitbelow splitright") == FAIL) - return FAIL; - if (ses_win_rec(fd, tab_topframe) == FAIL) + // + // Save current window layout. + // + PUTLINE_FAIL("set splitbelow splitright"); + if (ses_win_rec(fd, tab_topframe) == FAIL) { return FAIL; - if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL) + } + if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL) { return FAIL; - if (!p_spr && put_line(fd, "set nosplitright") == FAIL) + } + if (!p_spr && put_line(fd, "set nosplitright") == FAIL) { return FAIL; + } - /* - * Check if window sizes can be restored (no windows omitted). - * Remember the window number of the current window after restoring. - */ + // + // Check if window sizes can be restored (no windows omitted). + // Remember the window number of the current window after restoring. + // nr = 0; for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { if (ses_do_win(wp)) @@ -9303,9 +9297,8 @@ static int makeopens(FILE *fd, char_u *dirnow) cnr = nr; } - /* Go to the first window. */ - if (put_line(fd, "wincmd t") == FAIL) - return FAIL; + // Go to the first window. + PUTLINE_FAIL("wincmd t"); // If more than one window, see if sizes can be restored. // First set 'winheight' and 'winwidth' to 1 to avoid the windows being @@ -9314,10 +9307,11 @@ static int makeopens(FILE *fd, char_u *dirnow) // cursor can be set. This is done again below. // winminheight and winminwidth need to be set to avoid an error if the // user has set winheight or winwidth. - if (put_line(fd, "set winminheight=0") == FAIL - || put_line(fd, "set winheight=1") == FAIL - || put_line(fd, "set winminwidth=0") == FAIL - || put_line(fd, "set winwidth=1") == FAIL) { + if (fprintf(fd, + "set winminheight=0\n" + "set winheight=1\n" + "set winminwidth=0\n" + "set winwidth=1\n") < 0) { return FAIL; } if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) { @@ -9328,34 +9322,39 @@ static int makeopens(FILE *fd, char_u *dirnow) // Restore the view of the window (options, file, cursor, etc.). // for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { - if (!ses_do_win(wp)) + if (!ses_do_win(wp)) { continue; - if (put_view(fd, wp, wp != edited_win, &ssop_flags, - cur_arg_idx) == FAIL) + } + if (put_view(fd, wp, wp != edited_win, &ssop_flags, cur_arg_idx) + == FAIL) { return FAIL; - if (nr > 1 && put_line(fd, "wincmd w") == FAIL) + } + if (nr > 1 && put_line(fd, "wincmd w") == FAIL) { return FAIL; + } next_arg_idx = wp->w_arg_idx; } - /* The argument index in the first tab page is zero, need to set it in - * each window. For further tab pages it's the window where we do - * "tabedit". */ + // The argument index in the first tab page is zero, need to set it in + // each window. For further tab pages it's the window where we do + // "tabedit". cur_arg_idx = next_arg_idx; - /* - * Restore cursor to the current window if it's not the first one. - */ + // + // Restore cursor to the current window if it's not the first one. + // if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0 - || put_eol(fd) == FAIL)) + || put_eol(fd) == FAIL)) { return FAIL; + } - /* - * Restore window sizes again after jumping around in windows, because - * the current window has a minimum size while others may not. - */ - if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) + // + // Restore window sizes again after jumping around in windows, because + // the current window has a minimum size while others may not. + // + if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) { return FAIL; + } // Take care of tab-local working directories if applicable if (tp->tp_localdir) { @@ -9368,34 +9367,33 @@ static int makeopens(FILE *fd, char_u *dirnow) did_lcd = true; } - /* Don't continue in another tab page when doing only the current one - * or when at the last tab page. */ - if (!(ssop_flags & SSOP_TABPAGES)) + // Don't continue in another tab page when doing only the current one + // or when at the last tab page. + if (!(ssop_flags & SSOP_TABPAGES)) { break; + } } if (ssop_flags & SSOP_TABPAGES) { - if (fprintf(fd, "tabnext %d", tabpage_index(curtab)) < 0 - || put_eol(fd) == FAIL) + if (fprintf(fd, "tabnext %d\n", tabpage_index(curtab)) < 0) { return FAIL; + } } if (restore_stal && put_line(fd, "set stal=1") == FAIL) { return FAIL; } - /* - * Wipe out an empty unnamed buffer we started in. - */ - if (put_line(fd, "if exists('s:wipebuf') " - "&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'") - == FAIL) - return FAIL; - if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL) - return FAIL; - if (put_line(fd, "endif") == FAIL) - return FAIL; - if (put_line(fd, "unlet! s:wipebuf") == FAIL) + // + // Wipe out an empty unnamed buffer we started in. + // + if (fprintf(fd, "%s", + "if exists('s:wipebuf') " + "&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'\n" + " silent exe 'bwipe ' . s:wipebuf\n" + "endif\n" + "unlet! s:wipebuf\n") < 0) { return FAIL; + } // Re-apply options. if (fprintf(fd, "set winheight=%" PRId64 " winwidth=%" PRId64 @@ -9410,14 +9408,16 @@ static int makeopens(FILE *fd, char_u *dirnow) return FAIL; } - /* - * Lastly, execute the x.vim file if it exists. - */ - if (put_line(fd, "let s:sx = expand(\":p:r\").\"x.vim\"") == FAIL - || put_line(fd, "if file_readable(s:sx)") == FAIL - || put_line(fd, " exe \"source \" . fnameescape(s:sx)") == FAIL - || put_line(fd, "endif") == FAIL) + // + // Lastly, execute the x.vim file if it exists. + // + if (fprintf(fd, "%s", + "let s:sx = expand(\":p:r\").\"x.vim\"\n" + "if file_readable(s:sx)\n" + " exe \"source \" . fnameescape(s:sx)\n" + "endif\n") < 0) { return FAIL; + } return OK; } @@ -9457,53 +9457,50 @@ static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin) } } } else { - // Just equalise window sizes - if (put_line(fd, "wincmd =") == FAIL) { - return FAIL; - } + // Just equalize window sizes. + PUTLINE_FAIL("wincmd ="); } return OK; } -/* - * Write commands to "fd" to recursively create windows for frame "fr", - * horizontally and vertically split. - * After the commands the last window in the frame is the current window. - * Returns FAIL when writing the commands to "fd" fails. - */ +// Write commands to "fd" to recursively create windows for frame "fr", +// horizontally and vertically split. +// After the commands the last window in the frame is the current window. +// Returns FAIL when writing the commands to "fd" fails. static int ses_win_rec(FILE *fd, frame_T *fr) { frame_T *frc; int count = 0; if (fr->fr_layout != FR_LEAF) { - /* Find first frame that's not skipped and then create a window for - * each following one (first frame is already there). */ + // Find first frame that's not skipped and then create a window for + // each following one (first frame is already there). frc = ses_skipframe(fr->fr_child); if (frc != NULL) while ((frc = ses_skipframe(frc->fr_next)) != NULL) { - /* Make window as big as possible so that we have lots of room - * to split. */ - if (put_line(fd, "wincmd _ | wincmd |") == FAIL - || put_line(fd, fr->fr_layout == FR_COL - ? "split" : "vsplit") == FAIL) + // Make window as big as possible so that we have lots of room + // to split. + if (fprintf(fd, "%s%s", + "wincmd _ | wincmd |\n", + (fr->fr_layout == FR_COL ? "split\n" : "vsplit\n") + ) < 0) { return FAIL; + } ++count; } - /* Go back to the first window. */ + // Go back to the first window. if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL ? "%dwincmd k" : "%dwincmd h", count) < 0 || put_eol(fd) == FAIL)) return FAIL; - /* Recursively create frames/windows in each window of this column or - * row. */ + // Recursively create frames/windows in each window of this column or row. frc = ses_skipframe(fr->fr_child); while (frc != NULL) { ses_win_rec(fd, frc); frc = ses_skipframe(frc->fr_next); - /* Go to next window. */ + // Go to next window. if (frc != NULL && put_line(fd, "wincmd w") == FAIL) return FAIL; } @@ -9511,10 +9508,8 @@ static int ses_win_rec(FILE *fd, frame_T *fr) return OK; } -/* - * Skip frames that don't contain windows we want to save in the Session. - * Returns NULL when there none. - */ +// Skip frames that don't contain windows we want to save in the Session. +// Returns NULL when there none. static frame_T *ses_skipframe(frame_T *fr) { frame_T *frc; @@ -9598,14 +9593,14 @@ put_view( * Local argument list. */ if (wp->w_alist == &global_alist) { - if (put_line(fd, "argglobal") == FAIL) - return FAIL; + PUTLINE_FAIL("argglobal"); } else { if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga, - flagp == &vop_flags - || !(*flagp & SSOP_CURDIR) - || wp->w_localdir != NULL, flagp) == FAIL) + flagp == &vop_flags + || !(*flagp & SSOP_CURDIR) + || wp->w_localdir != NULL, flagp) == FAIL) { return FAIL; + } } /* Only when part of a session: restore the argument index. Some @@ -9658,9 +9653,7 @@ put_view( xfree(fname_esc); } else { // No file in this buffer, just make it empty. - if (put_line(fd, "enew") == FAIL) { - return FAIL; - } + PUTLINE_FAIL("enew"); if (wp->w_buffer->b_ffname != NULL) { // The buffer does have a name, but it's not a file name. if (fputs("file ", fd) < 0 @@ -9717,41 +9710,41 @@ put_view( */ if (do_cursor) { - /* Restore the cursor line in the file and relatively in the - * window. Don't use "G", it changes the jumplist. */ + // Restore the cursor line in the file and relatively in the + // window. Don't use "G", it changes the jumplist. if (fprintf(fd, "let s:l = %" PRId64 " - ((%" PRId64 - " * winheight(0) + %" PRId64 ") / %" PRId64 ")", + " * winheight(0) + %" PRId64 ") / %" PRId64 ")\n" + "if s:l < 1 | let s:l = 1 | endif\n" + "exe s:l\n" + "normal! zt\n" + "%" PRId64 "\n" + , (int64_t)wp->w_cursor.lnum, (int64_t)(wp->w_cursor.lnum - wp->w_topline), (int64_t)(wp->w_height_inner / 2), - (int64_t)wp->w_height_inner) < 0 - || put_eol(fd) == FAIL - || put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL - || put_line(fd, "exe s:l") == FAIL - || put_line(fd, "normal! zt") == FAIL - || fprintf(fd, "%" PRId64, (int64_t)wp->w_cursor.lnum) < 0 - || put_eol(fd) == FAIL) + (int64_t)wp->w_height_inner, + (int64_t)wp->w_cursor.lnum + ) < 0) { return FAIL; - /* Restore the cursor column and left offset when not wrapping. */ + } + // Restore the cursor column and left offset when not wrapping. if (wp->w_cursor.col == 0) { - if (put_line(fd, "normal! 0") == FAIL) - return FAIL; + PUTLINE_FAIL("normal! 0"); } else { if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0) { if (fprintf(fd, "let s:c = %" PRId64 " - ((%" PRId64 - " * winwidth(0) + %" PRId64 ") / %" PRId64 ")", + " * winwidth(0) + %" PRId64 ") / %" PRId64 ")\n" + "if s:c > 0\n" + " exe 'normal! ' . s:c . '|zs' . %" PRId64 " . '|'\n" + "else\n" + , (int64_t)wp->w_virtcol + 1, (int64_t)(wp->w_virtcol - wp->w_leftcol), (int64_t)(wp->w_width / 2), - (int64_t)wp->w_width) < 0 - || put_eol(fd) == FAIL - || put_line(fd, "if s:c > 0") == FAIL - || fprintf(fd, " exe 'normal! ' . s:c . '|zs' . %" PRId64 " . '|'", - (int64_t)wp->w_virtcol + 1) < 0 - || put_eol(fd) == FAIL - || put_line(fd, "else") == FAIL + (int64_t)wp->w_width, + (int64_t)wp->w_virtcol + 1) < 0 || put_view_curpos(fd, wp, " ") == FAIL || put_line(fd, "endif") == FAIL) { return FAIL; @@ -9779,18 +9772,17 @@ put_view( return OK; } -/* - * Write an argument list to the session file. - * Returns FAIL if writing fails. - */ -static int -ses_arglist( - FILE *fd, - char *cmd, - garray_T *gap, - int fullname, /* TRUE: use full path name */ - unsigned *flagp -) +/// Writes an :argument list to the session file. +/// +/// @param fd +/// @param cmd +/// @param gap +/// @param fullname true: use full path name +/// @param flagp +/// +/// @returns FAIL if writing fails. +static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, + unsigned *flagp) { char_u *buf = NULL; char_u *s; @@ -9798,9 +9790,7 @@ ses_arglist( if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL) { return FAIL; } - if (put_line(fd, "%argdel") == FAIL) { - return FAIL; - } + PUTLINE_FAIL("%argdel"); for (int i = 0; i < gap->ga_len; ++i) { /* NULL file names are skipped (only happens when out of memory). */ s = alist_name(&((aentry_T *)gap->ga_data)[i]); @@ -9838,6 +9828,7 @@ static char *ses_get_fname(buf_T *buf, unsigned *flagp, bool add_eol) } return (char *)buf->b_ffname; } + /// Write a buffer name to the session file. /// Also ends the line, if "add_eol" is true. /// Returns FAIL if writing fails. @@ -9960,14 +9951,12 @@ int put_eol(FILE *fd) return OK; } -/* - * Write a line to "fd". - * Return FAIL for a write error. - */ +// TODO(justinmk): remove this, not needed after 823750fef315. int put_line(FILE *fd, char *s) { - if (fputs(s, fd) < 0 || put_eol(fd) == FAIL) + if (0 > fprintf(fd, "%s\n", s)) { return FAIL; + } return OK; } -- cgit From 90486278061f114eba8703d2f058678bb6e247e6 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 05:08:12 -0800 Subject: lint --- src/nvim/ex_docmd.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2b952b3f15..47c42c001e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -9210,7 +9210,7 @@ static int makeopens(FILE *fd, char_u *dirnow) // temporarily to avoid that. if (p_stal == 1 && first_tabpage->tp_next != NULL) { PUTLINE_FAIL("set stal=2"); - restore_stal = TRUE; + restore_stal = true; } // @@ -9482,18 +9482,18 @@ static int ses_win_rec(FILE *fd, frame_T *fr) // to split. if (fprintf(fd, "%s%s", "wincmd _ | wincmd |\n", - (fr->fr_layout == FR_COL ? "split\n" : "vsplit\n") - ) < 0) { + (fr->fr_layout == FR_COL ? "split\n" : "vsplit\n")) < 0) { return FAIL; } - ++count; + count++; } // Go back to the first window. if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL - ? "%dwincmd k" : "%dwincmd h", count) < 0 - || put_eol(fd) == FAIL)) + ? "%dwincmd k" : "%dwincmd h", count) < 0 + || put_eol(fd) == FAIL)) { return FAIL; + } // Recursively create frames/windows in each window of this column or row. frc = ses_skipframe(fr->fr_child); @@ -9501,8 +9501,9 @@ static int ses_win_rec(FILE *fd, frame_T *fr) ses_win_rec(fd, frc); frc = ses_skipframe(frc->fr_next); // Go to next window. - if (frc != NULL && put_line(fd, "wincmd w") == FAIL) + if (frc != NULL && put_line(fd, "wincmd w") == FAIL) { return FAIL; + } } } return OK; @@ -9694,9 +9695,9 @@ put_view( if (f == FAIL) return FAIL; - /* - * Save Folds when 'buftype' is empty and for help files. - */ + // + // Save Folds when 'buftype' is empty and for help files. + // if ((*flagp & SSOP_FOLDS) && wp->w_buffer->b_ffname != NULL && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer)) @@ -9705,11 +9706,10 @@ put_view( return FAIL; } - /* - * Set the cursor after creating folds, since that moves the cursor. - */ + // + // Set the cursor after creating folds, since that moves the cursor. + // if (do_cursor) { - // Restore the cursor line in the file and relatively in the // window. Don't use "G", it changes the jumplist. if (fprintf(fd, @@ -9718,14 +9718,12 @@ put_view( "if s:l < 1 | let s:l = 1 | endif\n" "exe s:l\n" "normal! zt\n" - "%" PRId64 "\n" - , + "%" PRId64 "\n", (int64_t)wp->w_cursor.lnum, (int64_t)(wp->w_cursor.lnum - wp->w_topline), (int64_t)(wp->w_height_inner / 2), (int64_t)wp->w_height_inner, - (int64_t)wp->w_cursor.lnum - ) < 0) { + (int64_t)wp->w_cursor.lnum) < 0) { return FAIL; } // Restore the cursor column and left offset when not wrapping. @@ -9791,8 +9789,8 @@ static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, return FAIL; } PUTLINE_FAIL("%argdel"); - for (int i = 0; i < gap->ga_len; ++i) { - /* NULL file names are skipped (only happens when out of memory). */ + for (int i = 0; i < gap->ga_len; i++) { + // NULL file names are skipped (only happens when out of memory). s = alist_name(&((aentry_T *)gap->ga_data)[i]); if (s != NULL) { if (fullname) { -- cgit From c4f4719ced9101195a84b350249ab2a105de627c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 05:36:20 -0800 Subject: cleanup/ex_docmd.c: remove most put_eol() calls --- src/nvim/ex_docmd.c | 121 ++++++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 66 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 47c42c001e..79cf1794b1 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -9151,12 +9151,13 @@ static int makeopens(FILE *fd, char_u *dirnow) PUTLINE_FAIL("exe \"cd \" . escape(expand(\":p:h\"), ' ')"); } else if (ssop_flags & SSOP_CURDIR) { sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow); - if (fputs("cd ", fd) < 0 - || ses_put_fname(fd, sname, &ssop_flags) == FAIL - || put_eol(fd) == FAIL) { + char *fname_esc = ses_escape_fname((char *)sname, &ssop_flags); + if (fprintf(fd, "cd %s\n", fname_esc) < 0) { + xfree(fname_esc); xfree(sname); return FAIL; } + xfree(fname_esc); xfree(sname); } @@ -9196,11 +9197,11 @@ static int makeopens(FILE *fd, char_u *dirnow) } if (ssop_flags & SSOP_RESIZE) { - /* Note: after the restore we still check it worked!*/ - if (fprintf(fd, "set lines=%" PRId64 " columns=%" PRId64, - (int64_t)Rows, (int64_t)Columns) < 0 - || put_eol(fd) == FAIL) + // Note: after the restore we still check it worked! + if (fprintf(fd, "set lines=%" PRId64 " columns=%" PRId64 "\n", + (int64_t)Rows, (int64_t)Columns) < 0) { return FAIL; + } } int restore_stal = FALSE; @@ -9343,8 +9344,7 @@ static int makeopens(FILE *fd, char_u *dirnow) // // Restore cursor to the current window if it's not the first one. // - if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0 - || put_eol(fd) == FAIL)) { + if (cnr > 1 && (fprintf(fd, "%dwincmd w\n", cnr) < 0)) { return FAIL; } @@ -9360,8 +9360,7 @@ static int makeopens(FILE *fd, char_u *dirnow) if (tp->tp_localdir) { if (fputs("if exists(':tcd') == 2 | tcd ", fd) < 0 || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL - || fputs(" | endif", fd) < 0 - || put_eol(fd) == FAIL) { + || fputs(" | endif\n", fd) < 0) { return FAIL; } did_lcd = true; @@ -9396,15 +9395,15 @@ static int makeopens(FILE *fd, char_u *dirnow) } // Re-apply options. - if (fprintf(fd, "set winheight=%" PRId64 " winwidth=%" PRId64 - " winminheight=%" PRId64 " winminwidth=%" PRId64 - " shortmess=%s", + if (fprintf(fd, + "set winheight=%" PRId64 " winwidth=%" PRId64 + " winminheight=%" PRId64 " winminwidth=%" PRId64 + " shortmess=%s\n", (int64_t)p_wh, (int64_t)p_wiw, (int64_t)p_wmh, (int64_t)p_wmw, - p_shm) < 0 - || put_eol(fd) == FAIL) { + p_shm) < 0) { return FAIL; } @@ -9438,10 +9437,9 @@ static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin) if (wp->w_height + wp->w_status_height < topframe->fr_height && (fprintf(fd, "exe '%dresize ' . ((&lines * %" PRId64 - " + %" PRId64 ") / %" PRId64 ")", + " + %" PRId64 ") / %" PRId64 ")\n", n, (int64_t)wp->w_height, - (int64_t)Rows / 2, (int64_t)Rows) < 0 - || put_eol(fd) == FAIL)) { + (int64_t)Rows / 2, (int64_t)Rows) < 0)) { return FAIL; } @@ -9449,10 +9447,9 @@ static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin) if (wp->w_width < Columns && (fprintf(fd, "exe 'vert %dresize ' . ((&columns * %" PRId64 - " + %" PRId64 ") / %" PRId64 ")", + " + %" PRId64 ") / %" PRId64 ")\n", n, (int64_t)wp->w_width, (int64_t)Columns / 2, - (int64_t)Columns) < 0 - || put_eol(fd) == FAIL)) { + (int64_t)Columns) < 0)) { return FAIL; } } @@ -9490,8 +9487,7 @@ static int ses_win_rec(FILE *fd, frame_T *fr) // Go back to the first window. if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL - ? "%dwincmd k" : "%dwincmd h", count) < 0 - || put_eol(fd) == FAIL)) { + ? "%dwincmd k\n" : "%dwincmd h\n", count) < 0)) { return FAIL; } @@ -9560,11 +9556,11 @@ static int put_view_curpos(FILE *fd, const win_T *wp, char *spaces) int r; if (wp->w_curswant == MAXCOL) { - r = fprintf(fd, "%snormal! $", spaces); + r = fprintf(fd, "%snormal! $\n", spaces); } else { - r = fprintf(fd, "%snormal! 0%d|", spaces, wp->w_virtcol + 1); + r = fprintf(fd, "%snormal! 0%d|\n", spaces, wp->w_virtcol + 1); } - return r < 0 || put_eol(fd) == FAIL ? FAIL : OK; + return r >= 0; } /* @@ -9608,18 +9604,19 @@ put_view( * arguments may have been deleted, check if the index is valid. */ if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp) && flagp == &ssop_flags) { - if (fprintf(fd, "%" PRId64 "argu", (int64_t)wp->w_arg_idx + 1) < 0 - || put_eol(fd) == FAIL) { + if (fprintf(fd, "%" PRId64 "argu\n", (int64_t)wp->w_arg_idx + 1) < 0) { return FAIL; } did_next = true; } - /* Edit the file. Skip this when ":next" already did it. */ + // Edit the file. Skip this when ":next" already did it. if (add_edit && (!did_next || wp->w_arg_idx_invalid)) { - /* - * Load the file. - */ + char *fname_esc = + ses_escape_fname(ses_get_fname(wp->w_buffer, flagp), flagp); + // + // Load the file. + // if (wp->w_buffer->b_ffname != NULL && (!bt_nofile(wp->w_buffer) || wp->w_buffer->terminal) ) { @@ -9629,49 +9626,41 @@ put_view( // Note, if a buffer for that file already exists, use :badd to // edit that buffer, to not lose folding information (:edit resets // folds in other buffers) - if (fputs("if bufexists(\"", fd) < 0 - || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL - || fputs("\") | buffer ", fd) < 0 - || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL - || fputs(" | else | edit ", fd) < 0 - || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL - || fputs(" | endif", fd) < 0 - || put_eol(fd) == FAIL) { - return FAIL; - } - - char *fname_esc = - ses_escape_fname(ses_get_fname(wp->w_buffer, flagp, false), flagp); - // Fixup :terminal buffer name. if (fprintf(fd, + "if bufexists(\"%s\") | buffer %s | else | edit %s | endif\n" + // Fixup :terminal buffer name. #7836 "if &buftype ==# 'terminal'\n" " silent file %s\n" "endif\n", + fname_esc, + fname_esc, + fname_esc, fname_esc) < 0) { xfree(fname_esc); return FAIL; } - xfree(fname_esc); } else { // No file in this buffer, just make it empty. PUTLINE_FAIL("enew"); if (wp->w_buffer->b_ffname != NULL) { // The buffer does have a name, but it's not a file name. - if (fputs("file ", fd) < 0 - || ses_fname(fd, wp->w_buffer, flagp, true) == FAIL) { + if (fprintf(fd, "file %s\n", fname_esc) < 0) { + xfree(fname_esc); return FAIL; } } do_cursor = false; } + xfree(fname_esc); } /* * Local mappings and abbreviations. */ if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) - && makemap(fd, wp->w_buffer) == FAIL) + && makemap(fd, wp->w_buffer) == FAIL) { return FAIL; + } /* * Local options. Need to go to the window temporarily. @@ -9692,8 +9681,9 @@ put_view( f = OK; curwin = save_curwin; curbuf = curwin->w_buffer; - if (f == FAIL) + if (f == FAIL) { return FAIL; + } // // Save Folds when 'buftype' is empty and for help files. @@ -9736,8 +9726,7 @@ put_view( " * winwidth(0) + %" PRId64 ") / %" PRId64 ")\n" "if s:c > 0\n" " exe 'normal! ' . s:c . '|zs' . %" PRId64 " . '|'\n" - "else\n" - , + "else\n", (int64_t)wp->w_virtcol + 1, (int64_t)(wp->w_virtcol - wp->w_leftcol), (int64_t)(wp->w_width / 2), @@ -9761,7 +9750,7 @@ put_view( && (flagp != &vop_flags || (*flagp & SSOP_CURDIR))) { if (fputs("lcd ", fd) < 0 || ses_put_fname(fd, wp->w_localdir, flagp) == FAIL - || put_eol(fd) == FAIL) { + || fprintf(fd, "\n") < 0) { return FAIL; } did_lcd = true; @@ -9785,10 +9774,9 @@ static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, char_u *buf = NULL; char_u *s; - if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL) { + if (fprintf(fd, "%s\n%s\n", cmd, "%argdel") < 0) { return FAIL; } - PUTLINE_FAIL("%argdel"); for (int i = 0; i < gap->ga_len; i++) { // NULL file names are skipped (only happens when out of memory). s = alist_name(&((aentry_T *)gap->ga_data)[i]); @@ -9798,11 +9786,13 @@ static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, (void)vim_FullName((char *)s, (char *)buf, MAXPATHL, FALSE); s = buf; } - if (fputs("$argadd ", fd) < 0 || ses_put_fname(fd, s, flagp) == FAIL - || put_eol(fd) == FAIL) { + char *fname_esc = ses_escape_fname((char *)s, flagp); + if (fprintf(fd, "$argadd %s\n", fname_esc) < 0) { + xfree(fname_esc); xfree(buf); return FAIL; } + xfree(fname_esc); xfree(buf); } } @@ -9810,7 +9800,7 @@ static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, } /// Gets the buffer name for `buf`. -static char *ses_get_fname(buf_T *buf, unsigned *flagp, bool add_eol) +static char *ses_get_fname(buf_T *buf, unsigned *flagp) { // Use the short file name if the current directory is known at the time // the session file will be sourced. @@ -9832,9 +9822,9 @@ static char *ses_get_fname(buf_T *buf, unsigned *flagp, bool add_eol) /// Returns FAIL if writing fails. static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, bool add_eol) { - char *name = ses_get_fname(buf, flagp, add_eol); + char *name = ses_get_fname(buf, flagp); if (ses_put_fname(fd, (char_u *)name, flagp) == FAIL - || (add_eol && put_eol(fd) == FAIL)) { + || (add_eol && fprintf(fd, "\n") < 0)) { return FAIL; } return OK; @@ -9939,8 +9929,7 @@ static char *get_view_file(int c) } -/// TODO(justinmk): remove this. Formerly used to choose CRLF or LF for session -// files, but that's useless--instead we always write LF. +// TODO(justinmk): remove this, not needed after 5ba3cecb68cd. int put_eol(FILE *fd) { if (putc('\n', fd) < 0) { @@ -9949,10 +9938,10 @@ int put_eol(FILE *fd) return OK; } -// TODO(justinmk): remove this, not needed after 823750fef315. +// TODO(justinmk): remove this, not needed after 5ba3cecb68cd. int put_line(FILE *fd, char *s) { - if (0 > fprintf(fd, "%s\n", s)) { + if (fprintf(fd, "%s\n", s) < 0) { return FAIL; } return OK; -- cgit From 1c3ca4f18fdc403813d8959b49626ac1c99e2c59 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 14:26:01 -0800 Subject: mksession: always unix slashes "/" for filepaths --- src/nvim/ex_docmd.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 79cf1794b1..d87dd29f88 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8089,6 +8089,10 @@ static void close_redir(void) do { if (FAIL == put_line(fd, (s))) { return FAIL; } } while (0) /// ":mkexrc", ":mkvimrc", ":mkview", ":mksession". +/// +/// Legacy 'sessionoptions' flags SSOP_UNIX, SSOP_SLASH are always enabled. +/// - SSOP_UNIX: line-endings are always LF +/// - SSOP_SLASH: filenames are always written with "/" slash static void ex_mkrc(exarg_T *eap) { FILE *fd; @@ -9112,6 +9116,8 @@ char_u *expand_sfile(char_u *arg) /// Writes commands for restoring the current buffers, for :mksession. /// +/// Legacy 'sessionoptions' flags SSOP_UNIX, SSOP_SLASH are always enabled. +/// /// @param dirnow Current directory name /// @param fd File descriptor to write to /// @@ -9840,12 +9846,10 @@ static char *ses_escape_fname(char *name, unsigned *flagp) char *p; char *sname = (char *)home_replace_save(NULL, (char_u *)name); - if (*flagp & SSOP_SLASH) { - // change all backslashes to forward slashes - for (p = sname; *p != NUL; MB_PTR_ADV(p)) { - if (*p == '\\') { - *p = '/'; - } + // Always SSOP_SLASH: change all backslashes to forward slashes. + for (p = sname; *p != NUL; MB_PTR_ADV(p)) { + if (*p == '\\') { + *p = '/'; } } -- cgit From 75e85622493cfbd357d2d87d988dc0ab79fd8326 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 27 Jan 2020 01:10:23 -0800 Subject: refactor: move session functions to ex_session.c --- src/nvim/ex_docmd.c | 1002 +-------------------------------------------------- 1 file changed, 2 insertions(+), 1000 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index d87dd29f88..12bee3ab86 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * ex_docmd.c: functions for executing an Ex command line. - */ +// ex_docmd.c: functions for executing an Ex command line. #include #include @@ -40,6 +38,7 @@ #include "nvim/menu.h" #include "nvim/message.h" #include "nvim/misc1.h" +#include "nvim/ex_session.h" #include "nvim/keymap.h" #include "nvim/file_search.h" #include "nvim/garray.h" @@ -79,9 +78,6 @@ static int quitmore = 0; static bool ex_pressedreturn = false; -/// Whether ":lcd" or ":tcd" was produced for a session. -static int did_lcd; - typedef struct ucmd { char_u *uc_name; // The command name uint32_t uc_argt; // The argument type @@ -8085,162 +8081,6 @@ static void close_redir(void) } } -#define PUTLINE_FAIL(s) \ - do { if (FAIL == put_line(fd, (s))) { return FAIL; } } while (0) - -/// ":mkexrc", ":mkvimrc", ":mkview", ":mksession". -/// -/// Legacy 'sessionoptions' flags SSOP_UNIX, SSOP_SLASH are always enabled. -/// - SSOP_UNIX: line-endings are always LF -/// - SSOP_SLASH: filenames are always written with "/" slash -static void ex_mkrc(exarg_T *eap) -{ - FILE *fd; - int failed = false; - int view_session = false; // :mkview, :mksession - int using_vdir = false; // using 'viewdir'? - char *viewFile = NULL; - unsigned *flagp; - - if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) { - view_session = TRUE; - } - - /* Use the short file name until ":lcd" is used. We also don't use the - * short file name when 'acd' is set, that is checked later. */ - did_lcd = FALSE; - - char *fname; - // ":mkview" or ":mkview 9": generate file name with 'viewdir' - if (eap->cmdidx == CMD_mkview - && (*eap->arg == NUL - || (ascii_isdigit(*eap->arg) && eap->arg[1] == NUL))) { - eap->forceit = true; - fname = get_view_file(*eap->arg); - if (fname == NULL) { - return; - } - viewFile = fname; - using_vdir = true; - } else if (*eap->arg != NUL) { - fname = (char *) eap->arg; - } else if (eap->cmdidx == CMD_mkvimrc) { - fname = VIMRC_FILE; - } else if (eap->cmdidx == CMD_mksession) { - fname = SESSION_FILE; - } else { - fname = EXRC_FILE; - } - - /* When using 'viewdir' may have to create the directory. */ - if (using_vdir && !os_isdir(p_vdir)) { - vim_mkdir_emsg((const char *)p_vdir, 0755); - } - - fd = open_exfile((char_u *) fname, eap->forceit, WRITEBIN); - if (fd != NULL) { - if (eap->cmdidx == CMD_mkview) - flagp = &vop_flags; - else - flagp = &ssop_flags; - - // Write the version command for :mkvimrc - if (eap->cmdidx == CMD_mkvimrc) { - (void)put_line(fd, "version 6.0"); - } - - if (eap->cmdidx == CMD_mksession) { - if (put_line(fd, "let SessionLoad = 1") == FAIL) - failed = TRUE; - } - - if (!view_session || (eap->cmdidx == CMD_mksession - && (*flagp & SSOP_OPTIONS))) { - failed |= (makemap(fd, NULL) == FAIL - || makeset(fd, OPT_GLOBAL, false) == FAIL); - } - - if (!failed && view_session) { - if (put_line(fd, - "let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0") - == FAIL) - failed = TRUE; - if (eap->cmdidx == CMD_mksession) { - char_u *dirnow; /* current directory */ - - dirnow = xmalloc(MAXPATHL); - /* - * Change to session file's dir. - */ - if (os_dirname(dirnow, MAXPATHL) == FAIL - || os_chdir((char *)dirnow) != 0) - *dirnow = NUL; - if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR)) { - if (vim_chdirfile((char_u *) fname) == OK) { - shorten_fnames(true); - } - } else if (*dirnow != NUL - && (ssop_flags & SSOP_CURDIR) && globaldir != NULL) { - if (os_chdir((char *)globaldir) == 0) - shorten_fnames(TRUE); - } - - failed |= (makeopens(fd, dirnow) == FAIL); - - /* restore original dir */ - if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR) - || ((ssop_flags & SSOP_CURDIR) && globaldir != - NULL))) { - if (os_chdir((char *)dirnow) != 0) - EMSG(_(e_prev_dir)); - shorten_fnames(TRUE); - /* restore original dir */ - if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR) - || ((ssop_flags & SSOP_CURDIR) && globaldir != - NULL))) { - if (os_chdir((char *)dirnow) != 0) - EMSG(_(e_prev_dir)); - shorten_fnames(TRUE); - } - } - xfree(dirnow); - } else { - failed |= (put_view(fd, curwin, !using_vdir, flagp, - -1) == FAIL); - } - if (fprintf(fd, - "%s", - "let &so = s:so_save | let &siso = s:siso_save\n" - "doautoall SessionLoadPost\n") - < 0) { - failed = true; - } - if (eap->cmdidx == CMD_mksession) { - if (fprintf(fd, "unlet SessionLoad\n") < 0) { - failed = true; - } - } - } - if (put_line(fd, "\" vim: set ft=vim :") == FAIL) - failed = TRUE; - - failed |= fclose(fd); - - if (failed) { - EMSG(_(e_write)); - } else if (eap->cmdidx == CMD_mksession) { - // successful session write - set v:this_session - char *const tbuf = xmalloc(MAXPATHL); - if (vim_FullName(fname, tbuf, MAXPATHL, false) == OK) { - set_vim_var_string(VV_THIS_SESSION, tbuf, -1); - } - xfree(tbuf); - } - } - - xfree(viewFile); -} - /// Try creating a directory, give error message on failure /// /// @param[in] name Directory to create. @@ -9113,844 +8953,6 @@ char_u *expand_sfile(char_u *arg) return result; } - -/// Writes commands for restoring the current buffers, for :mksession. -/// -/// Legacy 'sessionoptions' flags SSOP_UNIX, SSOP_SLASH are always enabled. -/// -/// @param dirnow Current directory name -/// @param fd File descriptor to write to -/// -/// @return FAIL on error, OK otherwise. -static int makeopens(FILE *fd, char_u *dirnow) -{ - int only_save_windows = TRUE; - int nr; - int restore_size = true; - win_T *wp; - char_u *sname; - win_T *edited_win = NULL; - int tabnr; - win_T *tab_firstwin; - frame_T *tab_topframe; - int cur_arg_idx = 0; - int next_arg_idx = 0; - - if (ssop_flags & SSOP_BUFFERS) - only_save_windows = FALSE; /* Save ALL buffers */ - - // Begin by setting v:this_session, and then other sessionable variables. - PUTLINE_FAIL("let v:this_session=expand(\":p\")"); - if (ssop_flags & SSOP_GLOBALS) { - if (store_session_globals(fd) == FAIL) { - return FAIL; - } - } - - // Close all windows but one. - PUTLINE_FAIL("silent only"); - - // - // Now a :cd command to the session directory or the current directory - // - if (ssop_flags & SSOP_SESDIR) { - PUTLINE_FAIL("exe \"cd \" . escape(expand(\":p:h\"), ' ')"); - } else if (ssop_flags & SSOP_CURDIR) { - sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow); - char *fname_esc = ses_escape_fname((char *)sname, &ssop_flags); - if (fprintf(fd, "cd %s\n", fname_esc) < 0) { - xfree(fname_esc); - xfree(sname); - return FAIL; - } - xfree(fname_esc); - xfree(sname); - } - - if (fprintf(fd, - "%s", - // If there is an empty, unnamed buffer we will wipe it out later. - // Remember the buffer number. - "if expand('%') == '' && !&modified && line('$') <= 1" - " && getline(1) == ''\n" - " let s:wipebuf = bufnr('%')\n" - "endif\n" - // Now save the current files, current buffer first. - "set shortmess=aoO\n") < 0) { - return FAIL; - } - - // Now put the other buffers into the buffer list. - FOR_ALL_BUFFERS(buf) { - if (!(only_save_windows && buf->b_nwindows == 0) - && !(buf->b_help && !(ssop_flags & SSOP_HELP)) - && buf->b_fname != NULL - && buf->b_p_bl) { - if (fprintf(fd, "badd +%" PRId64 " ", - buf->b_wininfo == NULL - ? (int64_t)1L - : (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0 - || ses_fname(fd, buf, &ssop_flags, true) == FAIL) { - return FAIL; - } - } - } - - /* the global argument list */ - if (ses_arglist(fd, "argglobal", &global_alist.al_ga, - !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL) { - return FAIL; - } - - if (ssop_flags & SSOP_RESIZE) { - // Note: after the restore we still check it worked! - if (fprintf(fd, "set lines=%" PRId64 " columns=%" PRId64 "\n", - (int64_t)Rows, (int64_t)Columns) < 0) { - return FAIL; - } - } - - int restore_stal = FALSE; - // When there are two or more tabpages and 'showtabline' is 1 the tabline - // will be displayed when creating the next tab. That resizes the windows - // in the first tab, which may cause problems. Set 'showtabline' to 2 - // temporarily to avoid that. - if (p_stal == 1 && first_tabpage->tp_next != NULL) { - PUTLINE_FAIL("set stal=2"); - restore_stal = true; - } - - // - // For each tab: - // - Put windows for each tab, when "tabpages" is in 'sessionoptions'. - // - Don't use goto_tabpage(), it may change CWD and trigger autocommands. - // - tab_firstwin = firstwin; // First window in tab page "tabnr". - tab_topframe = topframe; - for (tabnr = 1;; tabnr++) { - tabpage_T *tp = find_tabpage(tabnr); - if (tp == NULL) { - break; // done all tab pages - } - - int need_tabnew = false; - int cnr = 1; - - if ((ssop_flags & SSOP_TABPAGES)) { - if (tp == curtab) { - tab_firstwin = firstwin; - tab_topframe = topframe; - } else { - tab_firstwin = tp->tp_firstwin; - tab_topframe = tp->tp_topframe; - } - if (tabnr > 1) - need_tabnew = TRUE; - } - - // - // Before creating the window layout, try loading one file. If this - // is aborted we don't end up with a number of useless windows. - // This may have side effects! (e.g., compressed or network file). - // - for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { - if (ses_do_win(wp) - && wp->w_buffer->b_ffname != NULL - && !bt_help(wp->w_buffer) - && !bt_nofile(wp->w_buffer) - ) { - if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0 - || ses_fname(fd, wp->w_buffer, &ssop_flags, true) == FAIL) { - return FAIL; - } - need_tabnew = false; - if (!wp->w_arg_idx_invalid) { - edited_win = wp; - } - break; - } - } - - // If no file got edited create an empty tab page. - if (need_tabnew && put_line(fd, "tabnew") == FAIL) { - return FAIL; - } - - // - // Save current window layout. - // - PUTLINE_FAIL("set splitbelow splitright"); - if (ses_win_rec(fd, tab_topframe) == FAIL) { - return FAIL; - } - if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL) { - return FAIL; - } - if (!p_spr && put_line(fd, "set nosplitright") == FAIL) { - return FAIL; - } - - // - // Check if window sizes can be restored (no windows omitted). - // Remember the window number of the current window after restoring. - // - nr = 0; - for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { - if (ses_do_win(wp)) - ++nr; - else - restore_size = FALSE; - if (curwin == wp) - cnr = nr; - } - - // Go to the first window. - PUTLINE_FAIL("wincmd t"); - - // If more than one window, see if sizes can be restored. - // First set 'winheight' and 'winwidth' to 1 to avoid the windows being - // resized when moving between windows. - // Do this before restoring the view, so that the topline and the - // cursor can be set. This is done again below. - // winminheight and winminwidth need to be set to avoid an error if the - // user has set winheight or winwidth. - if (fprintf(fd, - "set winminheight=0\n" - "set winheight=1\n" - "set winminwidth=0\n" - "set winwidth=1\n") < 0) { - return FAIL; - } - if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) { - return FAIL; - } - - // - // Restore the view of the window (options, file, cursor, etc.). - // - for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { - if (!ses_do_win(wp)) { - continue; - } - if (put_view(fd, wp, wp != edited_win, &ssop_flags, cur_arg_idx) - == FAIL) { - return FAIL; - } - if (nr > 1 && put_line(fd, "wincmd w") == FAIL) { - return FAIL; - } - next_arg_idx = wp->w_arg_idx; - } - - // The argument index in the first tab page is zero, need to set it in - // each window. For further tab pages it's the window where we do - // "tabedit". - cur_arg_idx = next_arg_idx; - - // - // Restore cursor to the current window if it's not the first one. - // - if (cnr > 1 && (fprintf(fd, "%dwincmd w\n", cnr) < 0)) { - return FAIL; - } - - // - // Restore window sizes again after jumping around in windows, because - // the current window has a minimum size while others may not. - // - if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) { - return FAIL; - } - - // Take care of tab-local working directories if applicable - if (tp->tp_localdir) { - if (fputs("if exists(':tcd') == 2 | tcd ", fd) < 0 - || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL - || fputs(" | endif\n", fd) < 0) { - return FAIL; - } - did_lcd = true; - } - - // Don't continue in another tab page when doing only the current one - // or when at the last tab page. - if (!(ssop_flags & SSOP_TABPAGES)) { - break; - } - } - - if (ssop_flags & SSOP_TABPAGES) { - if (fprintf(fd, "tabnext %d\n", tabpage_index(curtab)) < 0) { - return FAIL; - } - } - if (restore_stal && put_line(fd, "set stal=1") == FAIL) { - return FAIL; - } - - // - // Wipe out an empty unnamed buffer we started in. - // - if (fprintf(fd, "%s", - "if exists('s:wipebuf') " - "&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'\n" - " silent exe 'bwipe ' . s:wipebuf\n" - "endif\n" - "unlet! s:wipebuf\n") < 0) { - return FAIL; - } - - // Re-apply options. - if (fprintf(fd, - "set winheight=%" PRId64 " winwidth=%" PRId64 - " winminheight=%" PRId64 " winminwidth=%" PRId64 - " shortmess=%s\n", - (int64_t)p_wh, - (int64_t)p_wiw, - (int64_t)p_wmh, - (int64_t)p_wmw, - p_shm) < 0) { - return FAIL; - } - - // - // Lastly, execute the x.vim file if it exists. - // - if (fprintf(fd, "%s", - "let s:sx = expand(\":p:r\").\"x.vim\"\n" - "if file_readable(s:sx)\n" - " exe \"source \" . fnameescape(s:sx)\n" - "endif\n") < 0) { - return FAIL; - } - - return OK; -} - -static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin) -{ - int n = 0; - win_T *wp; - - if (restore_size && (ssop_flags & SSOP_WINSIZE)) { - for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { - if (!ses_do_win(wp)) { - continue; - } - n++; - - // restore height when not full height - if (wp->w_height + wp->w_status_height < topframe->fr_height - && (fprintf(fd, - "exe '%dresize ' . ((&lines * %" PRId64 - " + %" PRId64 ") / %" PRId64 ")\n", - n, (int64_t)wp->w_height, - (int64_t)Rows / 2, (int64_t)Rows) < 0)) { - return FAIL; - } - - // restore width when not full width - if (wp->w_width < Columns - && (fprintf(fd, - "exe 'vert %dresize ' . ((&columns * %" PRId64 - " + %" PRId64 ") / %" PRId64 ")\n", - n, (int64_t)wp->w_width, (int64_t)Columns / 2, - (int64_t)Columns) < 0)) { - return FAIL; - } - } - } else { - // Just equalize window sizes. - PUTLINE_FAIL("wincmd ="); - } - return OK; -} - -// Write commands to "fd" to recursively create windows for frame "fr", -// horizontally and vertically split. -// After the commands the last window in the frame is the current window. -// Returns FAIL when writing the commands to "fd" fails. -static int ses_win_rec(FILE *fd, frame_T *fr) -{ - frame_T *frc; - int count = 0; - - if (fr->fr_layout != FR_LEAF) { - // Find first frame that's not skipped and then create a window for - // each following one (first frame is already there). - frc = ses_skipframe(fr->fr_child); - if (frc != NULL) - while ((frc = ses_skipframe(frc->fr_next)) != NULL) { - // Make window as big as possible so that we have lots of room - // to split. - if (fprintf(fd, "%s%s", - "wincmd _ | wincmd |\n", - (fr->fr_layout == FR_COL ? "split\n" : "vsplit\n")) < 0) { - return FAIL; - } - count++; - } - - // Go back to the first window. - if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL - ? "%dwincmd k\n" : "%dwincmd h\n", count) < 0)) { - return FAIL; - } - - // Recursively create frames/windows in each window of this column or row. - frc = ses_skipframe(fr->fr_child); - while (frc != NULL) { - ses_win_rec(fd, frc); - frc = ses_skipframe(frc->fr_next); - // Go to next window. - if (frc != NULL && put_line(fd, "wincmd w") == FAIL) { - return FAIL; - } - } - } - return OK; -} - -// Skip frames that don't contain windows we want to save in the Session. -// Returns NULL when there none. -static frame_T *ses_skipframe(frame_T *fr) -{ - frame_T *frc; - - FOR_ALL_FRAMES(frc, fr) { - if (ses_do_frame(frc)) { - break; - } - } - return frc; -} - -// Return true if frame "fr" has a window somewhere that we want to save in -// the Session. -static bool ses_do_frame(const frame_T *fr) - FUNC_ATTR_NONNULL_ARG(1) -{ - const frame_T *frc; - - if (fr->fr_layout == FR_LEAF) { - return ses_do_win(fr->fr_win); - } - FOR_ALL_FRAMES(frc, fr->fr_child) { - if (ses_do_frame(frc)) { - return true; - } - } - return false; -} - -/// Return non-zero if window "wp" is to be stored in the Session. -static int ses_do_win(win_T *wp) -{ - if (wp->w_buffer->b_fname == NULL - // When 'buftype' is "nofile" can't restore the window contents. - || (!wp->w_buffer->terminal && bt_nofile(wp->w_buffer))) { - return ssop_flags & SSOP_BLANK; - } - if (bt_help(wp->w_buffer)) { - return ssop_flags & SSOP_HELP; - } - return true; -} - -static int put_view_curpos(FILE *fd, const win_T *wp, char *spaces) -{ - int r; - - if (wp->w_curswant == MAXCOL) { - r = fprintf(fd, "%snormal! $\n", spaces); - } else { - r = fprintf(fd, "%snormal! 0%d|\n", spaces, wp->w_virtcol + 1); - } - return r >= 0; -} - -/* - * Write commands to "fd" to restore the view of a window. - * Caller must make sure 'scrolloff' is zero. - */ -static int -put_view( - FILE *fd, - win_T *wp, - int add_edit, /* add ":edit" command to view */ - unsigned *flagp, /* vop_flags or ssop_flags */ - int current_arg_idx /* current argument index of the window, use - * -1 if unknown */ -) -{ - win_T *save_curwin; - int f; - int do_cursor; - int did_next = FALSE; - - /* Always restore cursor position for ":mksession". For ":mkview" only - * when 'viewoptions' contains "cursor". */ - do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR); - - /* - * Local argument list. - */ - if (wp->w_alist == &global_alist) { - PUTLINE_FAIL("argglobal"); - } else { - if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga, - flagp == &vop_flags - || !(*flagp & SSOP_CURDIR) - || wp->w_localdir != NULL, flagp) == FAIL) { - return FAIL; - } - } - - /* Only when part of a session: restore the argument index. Some - * arguments may have been deleted, check if the index is valid. */ - if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp) - && flagp == &ssop_flags) { - if (fprintf(fd, "%" PRId64 "argu\n", (int64_t)wp->w_arg_idx + 1) < 0) { - return FAIL; - } - did_next = true; - } - - // Edit the file. Skip this when ":next" already did it. - if (add_edit && (!did_next || wp->w_arg_idx_invalid)) { - char *fname_esc = - ses_escape_fname(ses_get_fname(wp->w_buffer, flagp), flagp); - // - // Load the file. - // - if (wp->w_buffer->b_ffname != NULL - && (!bt_nofile(wp->w_buffer) || wp->w_buffer->terminal) - ) { - // Editing a file in this buffer: use ":edit file". - // This may have side effects! (e.g., compressed or network file). - // - // Note, if a buffer for that file already exists, use :badd to - // edit that buffer, to not lose folding information (:edit resets - // folds in other buffers) - if (fprintf(fd, - "if bufexists(\"%s\") | buffer %s | else | edit %s | endif\n" - // Fixup :terminal buffer name. #7836 - "if &buftype ==# 'terminal'\n" - " silent file %s\n" - "endif\n", - fname_esc, - fname_esc, - fname_esc, - fname_esc) < 0) { - xfree(fname_esc); - return FAIL; - } - } else { - // No file in this buffer, just make it empty. - PUTLINE_FAIL("enew"); - if (wp->w_buffer->b_ffname != NULL) { - // The buffer does have a name, but it's not a file name. - if (fprintf(fd, "file %s\n", fname_esc) < 0) { - xfree(fname_esc); - return FAIL; - } - } - do_cursor = false; - } - xfree(fname_esc); - } - - /* - * Local mappings and abbreviations. - */ - if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) - && makemap(fd, wp->w_buffer) == FAIL) { - return FAIL; - } - - /* - * Local options. Need to go to the window temporarily. - * Store only local values when using ":mkview" and when ":mksession" is - * used and 'sessionoptions' doesn't include "nvim/options". - * Some folding options are always stored when "folds" is included, - * otherwise the folds would not be restored correctly. - */ - save_curwin = curwin; - curwin = wp; - curbuf = curwin->w_buffer; - if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) - f = makeset(fd, OPT_LOCAL, - flagp == &vop_flags || !(*flagp & SSOP_OPTIONS)); - else if (*flagp & SSOP_FOLDS) - f = makefoldset(fd); - else - f = OK; - curwin = save_curwin; - curbuf = curwin->w_buffer; - if (f == FAIL) { - return FAIL; - } - - // - // Save Folds when 'buftype' is empty and for help files. - // - if ((*flagp & SSOP_FOLDS) - && wp->w_buffer->b_ffname != NULL - && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer)) - ) { - if (put_folds(fd, wp) == FAIL) - return FAIL; - } - - // - // Set the cursor after creating folds, since that moves the cursor. - // - if (do_cursor) { - // Restore the cursor line in the file and relatively in the - // window. Don't use "G", it changes the jumplist. - if (fprintf(fd, - "let s:l = %" PRId64 " - ((%" PRId64 - " * winheight(0) + %" PRId64 ") / %" PRId64 ")\n" - "if s:l < 1 | let s:l = 1 | endif\n" - "exe s:l\n" - "normal! zt\n" - "%" PRId64 "\n", - (int64_t)wp->w_cursor.lnum, - (int64_t)(wp->w_cursor.lnum - wp->w_topline), - (int64_t)(wp->w_height_inner / 2), - (int64_t)wp->w_height_inner, - (int64_t)wp->w_cursor.lnum) < 0) { - return FAIL; - } - // Restore the cursor column and left offset when not wrapping. - if (wp->w_cursor.col == 0) { - PUTLINE_FAIL("normal! 0"); - } else { - if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0) { - if (fprintf(fd, - "let s:c = %" PRId64 " - ((%" PRId64 - " * winwidth(0) + %" PRId64 ") / %" PRId64 ")\n" - "if s:c > 0\n" - " exe 'normal! ' . s:c . '|zs' . %" PRId64 " . '|'\n" - "else\n", - (int64_t)wp->w_virtcol + 1, - (int64_t)(wp->w_virtcol - wp->w_leftcol), - (int64_t)(wp->w_width / 2), - (int64_t)wp->w_width, - (int64_t)wp->w_virtcol + 1) < 0 - || put_view_curpos(fd, wp, " ") == FAIL - || put_line(fd, "endif") == FAIL) { - return FAIL; - } - } else if (put_view_curpos(fd, wp, "") == FAIL) { - return FAIL; - } - } - } - - // - // Local directory, if the current flag is not view options or the "curdir" - // option is included. - // - if (wp->w_localdir != NULL - && (flagp != &vop_flags || (*flagp & SSOP_CURDIR))) { - if (fputs("lcd ", fd) < 0 - || ses_put_fname(fd, wp->w_localdir, flagp) == FAIL - || fprintf(fd, "\n") < 0) { - return FAIL; - } - did_lcd = true; - } - - return OK; -} - -/// Writes an :argument list to the session file. -/// -/// @param fd -/// @param cmd -/// @param gap -/// @param fullname true: use full path name -/// @param flagp -/// -/// @returns FAIL if writing fails. -static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, - unsigned *flagp) -{ - char_u *buf = NULL; - char_u *s; - - if (fprintf(fd, "%s\n%s\n", cmd, "%argdel") < 0) { - return FAIL; - } - for (int i = 0; i < gap->ga_len; i++) { - // NULL file names are skipped (only happens when out of memory). - s = alist_name(&((aentry_T *)gap->ga_data)[i]); - if (s != NULL) { - if (fullname) { - buf = xmalloc(MAXPATHL); - (void)vim_FullName((char *)s, (char *)buf, MAXPATHL, FALSE); - s = buf; - } - char *fname_esc = ses_escape_fname((char *)s, flagp); - if (fprintf(fd, "$argadd %s\n", fname_esc) < 0) { - xfree(fname_esc); - xfree(buf); - return FAIL; - } - xfree(fname_esc); - xfree(buf); - } - } - return OK; -} - -/// Gets the buffer name for `buf`. -static char *ses_get_fname(buf_T *buf, unsigned *flagp) -{ - // Use the short file name if the current directory is known at the time - // the session file will be sourced. - // Don't do this for ":mkview", we don't know the current directory. - // Don't do this after ":lcd", we don't keep track of what the current - // directory is. - if (buf->b_sfname != NULL - && flagp == &ssop_flags - && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR)) - && !p_acd - && !did_lcd) { - return (char *)buf->b_sfname; - } - return (char *)buf->b_ffname; -} - -/// Write a buffer name to the session file. -/// Also ends the line, if "add_eol" is true. -/// Returns FAIL if writing fails. -static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, bool add_eol) -{ - char *name = ses_get_fname(buf, flagp); - if (ses_put_fname(fd, (char_u *)name, flagp) == FAIL - || (add_eol && fprintf(fd, "\n") < 0)) { - return FAIL; - } - return OK; -} - -// Escapes a filename for session writing. -// Takes care of "slash" flag in 'sessionoptions' and escapes special -// characters. -// -// Returns allocated string or NULL. -static char *ses_escape_fname(char *name, unsigned *flagp) -{ - char *p; - char *sname = (char *)home_replace_save(NULL, (char_u *)name); - - // Always SSOP_SLASH: change all backslashes to forward slashes. - for (p = sname; *p != NUL; MB_PTR_ADV(p)) { - if (*p == '\\') { - *p = '/'; - } - } - - // Escape special characters. - p = vim_strsave_fnameescape(sname, false); - xfree(sname); - return p; -} - -// Write a file name to the session file. -// Takes care of the "slash" option in 'sessionoptions' and escapes special -// characters. -// Returns FAIL if writing fails. -static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp) -{ - char *p = ses_escape_fname((char *)name, flagp); - bool retval = fputs(p, fd) < 0 ? FAIL : OK; - xfree(p); - return retval; -} - -/* - * ":loadview [nr]" - */ -static void ex_loadview(exarg_T *eap) -{ - char *fname = get_view_file(*eap->arg); - if (fname != NULL) { - if (do_source((char_u *)fname, FALSE, DOSO_NONE) == FAIL) { - EMSG2(_(e_notopen), fname); - } - xfree(fname); - } -} - -/// Get the name of the view file for the current buffer. -static char *get_view_file(int c) -{ - if (curbuf->b_ffname == NULL) { - EMSG(_(e_noname)); - return NULL; - } - char *sname = (char *)home_replace_save(NULL, curbuf->b_ffname); - - // We want a file name without separators, because we're not going to make - // a directory. - // "normal" path separator -> "=+" - // "=" -> "==" - // ":" path separator -> "=-" - size_t len = 0; - for (char *p = sname; *p; p++) { - if (*p == '=' || vim_ispathsep(*p)) { - ++len; - } - } - char *retval = xmalloc(strlen(sname) + len + STRLEN(p_vdir) + 9); - STRCPY(retval, p_vdir); - add_pathsep(retval); - char *s = retval + strlen(retval); - for (char *p = sname; *p; p++) { - if (*p == '=') { - *s++ = '='; - *s++ = '='; - } else if (vim_ispathsep(*p)) { - *s++ = '='; -#if defined(BACKSLASH_IN_FILENAME) - if (*p == ':') - *s++ = '-'; - else -#endif - *s++ = '+'; - } else - *s++ = *p; - } - *s++ = '='; - *s++ = c; - strcpy(s, ".vim"); - - xfree(sname); - return retval; -} - - -// TODO(justinmk): remove this, not needed after 5ba3cecb68cd. -int put_eol(FILE *fd) -{ - if (putc('\n', fd) < 0) { - return FAIL; - } - return OK; -} - -// TODO(justinmk): remove this, not needed after 5ba3cecb68cd. -int put_line(FILE *fd, char *s) -{ - if (fprintf(fd, "%s\n", s) < 0) { - return FAIL; - } - return OK; -} - /* * ":rshada" and ":wshada". */ -- cgit From d50c1123d5616c9757bb5707416696cda1a43716 Mon Sep 17 00:00:00 2001 From: Jakub Łuczyński Date: Mon, 10 Feb 2020 18:34:18 +0100 Subject: fix: includes --- src/nvim/ex_docmd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 12bee3ab86..289811701c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -20,6 +20,7 @@ #include "nvim/digraph.h" #include "nvim/edit.h" #include "nvim/eval.h" +#include "nvim/eval/user_funcs.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_eval.h" -- cgit From 5e815edece308a91296720cd6cb8d988af6c90c8 Mon Sep 17 00:00:00 2001 From: Jakub Łuczyński Date: Tue, 11 Feb 2020 16:19:14 +0100 Subject: rename: user_funcs -> userfunc Lets stick with vim for now --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 289811701c..fa01e06471 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -20,7 +20,7 @@ #include "nvim/digraph.h" #include "nvim/edit.h" #include "nvim/eval.h" -#include "nvim/eval/user_funcs.h" +#include "nvim/eval/userfunc.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_eval.h" -- cgit From 986eafce4708c8f49552d7dcd0cc5fe471caa655 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 12 Feb 2020 21:33:51 -0500 Subject: vim-patch:8.1.2187: error for bad regexp even though regexp is not used Problem: Error for bad regexp even though regexp is not used when writing a file. (Arseny Nasokin) Solution: Ignore regexp errors. (closes vim/vim#5059) https://github.com/vim/vim/commit/b40c2576d4e0e2dd2c580414c45947d88556d76d --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 12bee3ab86..d0193064b0 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4373,7 +4373,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp) if (has_wildcards) { expand_T xpc; - int options = WILD_LIST_NOTFOUND|WILD_ADD_SLASH; + int options = WILD_LIST_NOTFOUND | WILD_NOERROR | WILD_ADD_SLASH; ExpandInit(&xpc); xpc.xp_context = EXPAND_FILES; -- cgit From 7955c05accaac452c1350d08af62d9d75387f24f Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 30 Oct 2019 00:56:49 -0400 Subject: vim-patch:8.1.1201: output of :command is hard to read Problem: Output of :command is hard to read. Solution: Make some columns wider, some narrower. Truncate the command when listing all. https://github.com/vim/vim/commit/725310d89e1ba268bf410472b7de054c6c260161 --- src/nvim/ex_docmd.c | 103 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 35 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index d0193064b0..b8b98c4f0d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5130,9 +5130,8 @@ static char *get_command_complete(int arg) static void uc_list(char_u *name, size_t name_len) { int i, j; - int found = FALSE; + bool found = false; ucmd_T *cmd; - int len; uint32_t a; // In cmdwin, the alternative buffer should be used. @@ -5151,62 +5150,96 @@ static void uc_list(char_u *name, size_t name_len) continue; } - /* Put out the title first time */ - if (!found) - MSG_PUTS_TITLE(_("\n Name Args Address Complete Definition")); - found = TRUE; + // Put out the title first time + if (!found) { + MSG_PUTS_TITLE(_("\n Name Args Address " + "Complete Definition")); + } + found = true; msg_putchar('\n'); if (got_int) break; - /* Special cases */ - msg_putchar(a & BANG ? '!' : ' '); - msg_putchar(a & REGSTR ? '"' : ' '); - msg_putchar(gap != &ucmds ? 'b' : ' '); - msg_putchar(' '); + // Special cases + int len = 4; + if (a & BANG) { + msg_putchar('!'); + len--; + } + if (a & REGSTR) { + msg_putchar('"'); + len--; + } + if (gap != &ucmds) { + msg_putchar('b'); + len--; + } + if (a & TRLBAR) { + msg_putchar('|'); + len--; + } + while (len-- > 0) { + msg_putchar(' '); + } msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D)); len = (int)STRLEN(cmd->uc_name) + 4; do { msg_putchar(' '); - ++len; - } while (len < 16); + len++; + } while (len < 22); + // "over" is how much longer the name is than the column width for + // the name, we'll try to align what comes after. + const int over = len - 22; len = 0; - /* Arguments */ + // Arguments switch (a & (EXTRA|NOSPC|NEEDARG)) { - case 0: IObuff[len++] = '0'; break; - case (EXTRA): IObuff[len++] = '*'; break; - case (EXTRA|NOSPC): IObuff[len++] = '?'; break; - case (EXTRA|NEEDARG): IObuff[len++] = '+'; break; - case (EXTRA|NOSPC|NEEDARG): IObuff[len++] = '1'; break; + case 0: + IObuff[len++] = '0'; + break; + case (EXTRA): + IObuff[len++] = '*'; + break; + case (EXTRA|NOSPC): + IObuff[len++] = '?'; + break; + case (EXTRA|NEEDARG): + IObuff[len++] = '+'; + break; + case (EXTRA|NOSPC|NEEDARG): + IObuff[len++] = '1'; + break; } do { IObuff[len++] = ' '; - } while (len < 5); + } while (len < 5 - over); - /* Range */ + // Address / Range if (a & (RANGE|COUNT)) { if (a & COUNT) { - /* -count=N */ - sprintf((char *)IObuff + len, "%" PRId64 "c", (int64_t)cmd->uc_def); + // -count=N + snprintf((char *)IObuff + len, IOSIZE, "%" PRId64 "c", + (int64_t)cmd->uc_def); len += (int)STRLEN(IObuff + len); - } else if (a & DFLALL) + } else if (a & DFLALL) { IObuff[len++] = '%'; - else if (cmd->uc_def >= 0) { - /* -range=N */ - sprintf((char *)IObuff + len, "%" PRId64 "", (int64_t)cmd->uc_def); + } else if (cmd->uc_def >= 0) { + // -range=N + snprintf((char *)IObuff + len, IOSIZE, "%" PRId64 "", + (int64_t)cmd->uc_def); len += (int)STRLEN(IObuff + len); - } else + } else { IObuff[len++] = '.'; + } } do { IObuff[len++] = ' '; - } while (len < 11); + } while (len < 9 - over); // Address Type for (j = 0; addr_type_complete[j].expand != -1; j++) { @@ -5220,7 +5253,7 @@ static void uc_list(char_u *name, size_t name_len) do { IObuff[len++] = ' '; - } while (len < 21); + } while (len < 13 - over); // Completion char *cmd_compl = get_command_complete(cmd->uc_compl); @@ -5231,12 +5264,13 @@ static void uc_list(char_u *name, size_t name_len) do { IObuff[len++] = ' '; - } while (len < 35); + } while (len < 24 - over); IObuff[len] = '\0'; msg_outtrans(IObuff); - msg_outtrans_special(cmd->uc_rep, false); + msg_outtrans_special(cmd->uc_rep, false, + name_len == 0 ? Columns - 46 : 0); if (p_verbose > 0) { last_set_msg(cmd->uc_script_ctx); } @@ -5424,9 +5458,8 @@ static void ex_command(exarg_T *eap) end = p; name_len = (int)(end - name); - /* If there is nothing after the name, and no attributes were specified, - * we are listing commands - */ + // If there is nothing after the name, and no attributes were specified, + // we are listing commands p = skipwhite(end); if (!has_attr && ends_excmd(*p)) { uc_list(name, end - name); -- cgit From 18d86283b04c42f331da23b61e09ae0039825143 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 16 Feb 2020 08:34:48 -0500 Subject: vim-patch:8.0.1660: the terminal API "drop" command doesn't support options Problem: The terminal API "drop" command doesn't support options. Solution: Implement the options. https://github.com/vim/vim/commit/333b80acf3a44e462456e6d5730e47ffa449c83d --- src/nvim/ex_docmd.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index b8b98c4f0d..ead0922c5a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4538,6 +4538,19 @@ skip_cmd_arg ( return p; } +int get_bad_opt(const char_u *p, exarg_T *eap) + FUNC_ATTR_NONNULL_ALL +{ + if (STRICMP(p, "keep") == 0) { + eap->bad_char = BAD_KEEP; + } else if (STRICMP(p, "drop") == 0) { + eap->bad_char = BAD_DROP; + } else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) { + eap->bad_char = *p; + } + return FAIL; +} + /* * Get "++opt=arg" argument. * Return FAIL or OK. @@ -4596,8 +4609,10 @@ static int getargopt(exarg_T *eap) *arg = NUL; if (pp == &eap->force_ff) { - if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) + if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) { return FAIL; + } + eap->force_ff = eap->cmd[eap->force_ff]; } else if (pp == &eap->force_enc) { /* Make 'fileencoding' lower case. */ for (p = eap->cmd + eap->force_enc; *p != NUL; ++p) @@ -4605,15 +4620,9 @@ static int getargopt(exarg_T *eap) } else { /* Check ++bad= argument. Must be a single-byte character, "keep" or * "drop". */ - p = eap->cmd + bad_char_idx; - if (STRICMP(p, "keep") == 0) - eap->bad_char = BAD_KEEP; - else if (STRICMP(p, "drop") == 0) - eap->bad_char = BAD_DROP; - else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) - eap->bad_char = *p; - else + if (get_bad_opt(eap->cmd + bad_char_idx, eap) == FAIL) { return FAIL; + } } return OK; -- cgit From acc5fd9fac60de4494925be23f873cf98aaa61b0 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 16 Feb 2020 09:04:30 -0500 Subject: vim-patch:8.1.0043: ++bad argument of :edit does not work properly Problem: ++bad argument of :edit does not work properly. Solution: Return FAIL from get_bad_opt() only when there is no valid argument. (Dominique Pelle, Christian Brabandt, closes vim/vim#2966, closes vim/vim#2947) https://github.com/vim/vim/commit/7580849df9d6c7c515f5ed784019336d8a8ec0f0 --- src/nvim/ex_docmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index ead0922c5a..28ecaf684a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4547,8 +4547,10 @@ int get_bad_opt(const char_u *p, exarg_T *eap) eap->bad_char = BAD_DROP; } else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) { eap->bad_char = *p; + } else { + return FAIL; } - return FAIL; + return OK; } /* -- cgit From d846f47cc88cd36da5ad8fd7e716552c80e3b418 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 24 Feb 2020 20:33:43 -0500 Subject: vim-patch:8.1.0881: can execute shell commands in rvim through interfaces Problem: Can execute shell commands in rvim through interfaces. Solution: Disable using interfaces in restricted mode. Allow for writing file with writefile(), histadd() and a few others. https://github.com/vim/vim/commit/8c62a08faf89663e5633dc5036cd8695c80f1075 --- src/nvim/ex_docmd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 28ecaf684a..abe394dc3a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1783,10 +1783,14 @@ static char_u * do_one_cmd(char_u **cmdlinep, if (!ea.skip) { if (sandbox != 0 && !(ea.argt & SBOXOK)) { - /* Command not allowed in sandbox. */ + // Command not allowed in sandbox. errormsg = (char_u *)_(e_sandbox); goto doend; } + if (restricted != 0 && (ea.argt & RESTRICT)) { + errormsg = (char_u *)_("E981: Command not allowed in restricted mode"); + goto doend; + } if (!MODIFIABLE(curbuf) && (ea.argt & MODIFY) // allow :put in terminals && (!curbuf->terminal || ea.cmdidx != CMD_put)) { -- cgit From 87d892afa0475644e91d9c8a57b7c35491c4dc32 Mon Sep 17 00:00:00 2001 From: Will Eccles Date: Tue, 17 Mar 2020 15:05:34 -0400 Subject: vim-patch:8.1.0864 Make 'scrolloff' and 'sidescrolloff' options window local (#11854) Problem: cannot have a local value for 'scrolloff' and 'sidescrolloff' Author: Bram Moolenar https://github.com/vim/vim/commit/375e3390078e740d3c83b0c118c50d9a920036c7 --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index abe394dc3a..4f8bf63ffe 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7367,7 +7367,7 @@ static void ex_syncbind(exarg_T *eap) topline = curwin->w_topline; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_p_scb && wp->w_buffer) { - y = wp->w_buffer->b_ml.ml_line_count - p_so; + y = wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value(); if (topline > y) { topline = y; } -- cgit From a122f6c6d4d64ab6a3bcd55bde220dc115acd73c Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 12 Apr 2020 15:58:14 -0400 Subject: vim-patch:8.2.0560: compiler warning in tiny build Problem: Compiler warning in tiny build. Solution: Move declaration inside #ifdef. (Dominique Pelle, closes vim/vim#5915) https://github.com/vim/vim/commit/2196bce56fcd56b0eaece50c079bac99f5bc31af --- src/nvim/ex_docmd.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 4f8bf63ffe..a86b8ec871 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -197,7 +197,7 @@ static void save_dbg_stuff(struct dbg_stuff *dsp) static void restore_dbg_stuff(struct dbg_stuff *dsp) { - suppress_errthrow = FALSE; + suppress_errthrow = false; trylevel = dsp->trylevel; force_abort = dsp->force_abort; caught_stack = dsp->caught_stack; @@ -394,8 +394,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, * Initialize "force_abort" and "suppress_errthrow" at the top level. */ if (!recursive) { - force_abort = FALSE; - suppress_errthrow = FALSE; + force_abort = false; + suppress_errthrow = false; } // If requested, store and reset the global values controlling the @@ -879,16 +879,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, xfree(sourcing_name); sourcing_name = saved_sourcing_name; sourcing_lnum = saved_sourcing_lnum; + } else if (got_int || (did_emsg && force_abort)) { + // On an interrupt or an aborting error not converted to an exception, + // disable the conversion of errors to exceptions. (Interrupts are not + // converted any more, here.) This enables also the interrupt message + // when force_abort is set and did_emsg unset in case of an interrupt + // from a finally clause after an error. + suppress_errthrow = true; } - /* - * On an interrupt or an aborting error not converted to an exception, - * disable the conversion of errors to exceptions. (Interrupts are not - * converted any more, here.) This enables also the interrupt message - * when force_abort is set and did_emsg unset in case of an interrupt - * from a finally clause after an error. - */ - else if (got_int || (did_emsg && force_abort)) - suppress_errthrow = TRUE; } // The current cstack will be freed when do_cmdline() returns. An uncaught -- cgit From fb4c7a53cfe4d4c8a786c8a5dc3c4b999c2df815 Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Thu, 16 Apr 2020 21:29:04 +0200 Subject: folds: decrease reliance on global "curwin" (#12132) Pass the window in which to create/delete folds instead of using the global "curwin" (current window). Preliminary work for a fold API. TODO: I kept changed_lines prototype unchanged. This should be updated when a fold API sees the light. --- src/nvim/ex_docmd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a86b8ec871..27d5e4998f 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -9291,8 +9291,9 @@ static void ex_match(exarg_T *eap) static void ex_fold(exarg_T *eap) { - if (foldManualAllowed(TRUE)) - foldCreate(eap->line1, eap->line2); + if (foldManualAllowed(true)) { + foldCreate(curwin, eap->line1, eap->line2); + } } static void ex_foldopen(exarg_T *eap) -- cgit From 5b3ec39df379ae01d6046689ffd9fb265196d21a Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 14 Mar 2020 12:47:49 -0400 Subject: vim-patch:8.0.1139: using window toolbar changes state Problem: Using window toolbar changes state. Solution: Always execute window toolbar actions in Normal mode. https://github.com/vim/vim/commit/a21a6a9ade7bec3a07992d4d900d4ce82eeb8a29 --- src/nvim/ex_docmd.c | 107 +++++++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 47 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 27d5e4998f..373bd93b24 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8209,6 +8209,57 @@ void update_topline_cursor(void) update_curswant(); } +// Save the current State and go to Normal mode. +// Return true if the typeahead could be saved. +bool save_current_state(save_state_T *sst) + FUNC_ATTR_NONNULL_ALL +{ + sst->save_msg_scroll = msg_scroll; + sst->save_restart_edit = restart_edit; + sst->save_msg_didout = msg_didout; + sst->save_State = State; + sst->save_insertmode = p_im; + sst->save_finish_op = finish_op; + sst->save_opcount = opcount; + sst->save_reg_executing = reg_executing; + + msg_scroll = false; // no msg scrolling in Normal mode + restart_edit = 0; // don't go to Insert mode + p_im = false; // don't use 'insertmode + + // Save the current typeahead. This is required to allow using ":normal" + // from an event handler and makes sure we don't hang when the argument + // ends with half a command. + save_typeahead(&sst->tabuf); + return sst->tabuf.typebuf_valid; +} + +void restore_current_state(save_state_T *sst) + FUNC_ATTR_NONNULL_ALL +{ + // Restore the previous typeahead. + restore_typeahead(&sst->tabuf); + + msg_scroll = sst->save_msg_scroll; + if (force_restart_edit) { + force_restart_edit = false; + } else { + // Some function (terminal_enter()) was aware of ex_normal and decided to + // override the value of restart_edit anyway. + restart_edit = sst->save_restart_edit; + } + p_im = sst->save_insertmode; + finish_op = sst->save_finish_op; + opcount = sst->save_opcount; + reg_executing = sst->save_reg_executing; + msg_didout |= sst->save_msg_didout; // don't reset msg_didout now + + // Restore the state (needed when called from a function executed for + // 'indentexpr'). Update the mouse and cursor, they may have changed. + State = sst->save_State; + ui_cursor_shape(); // may show different cursor shape +} + /* * ":normal[!] {commands}": Execute normal mode commands. */ @@ -8218,15 +8269,7 @@ static void ex_normal(exarg_T *eap) EMSG("Can't re-enter normal mode from terminal mode"); return; } - int save_msg_scroll = msg_scroll; - int save_restart_edit = restart_edit; - int save_msg_didout = msg_didout; - int save_State = State; - tasave_T tabuf; - int save_insertmode = p_im; - int save_finish_op = finish_op; - long save_opcount = opcount; - const int save_reg_executing = reg_executing; + save_state_T save_state; char_u *arg = NULL; int l; char_u *p; @@ -8239,11 +8282,6 @@ static void ex_normal(exarg_T *eap) EMSG(_("E192: Recursive use of :normal too deep")); return; } - ++ex_normal_busy; - - msg_scroll = FALSE; /* no msg scrolling in Normal mode */ - restart_edit = 0; /* don't go to Insert mode */ - p_im = FALSE; /* don't use 'insertmode' */ /* * vgetc() expects a CSI and K_SPECIAL to have been escaped. Don't do @@ -8277,19 +8315,11 @@ static void ex_normal(exarg_T *eap) } } - /* - * Save the current typeahead. This is required to allow using ":normal" - * from an event handler and makes sure we don't hang when the argument - * ends with half a command. - */ - save_typeahead(&tabuf); - // TODO(philix): after save_typeahead() this is always TRUE - if (tabuf.typebuf_valid) { - /* - * Repeat the :normal command for each line in the range. When no - * range given, execute it just once, without positioning the cursor - * first. - */ + ex_normal_busy++; + if (save_current_state(&save_state)) { + // Repeat the :normal command for each line in the range. When no + // range given, execute it just once, without positioning the cursor + // first. do { if (eap->addr_count != 0) { curwin->w_cursor.lnum = eap->line1++; @@ -8306,29 +8336,12 @@ static void ex_normal(exarg_T *eap) /* Might not return to the main loop when in an event handler. */ update_topline_cursor(); - /* Restore the previous typeahead. */ - restore_typeahead(&tabuf); + restore_current_state(&save_state); - --ex_normal_busy; - msg_scroll = save_msg_scroll; - if (force_restart_edit) { - force_restart_edit = false; - } else { - // Some function (terminal_enter()) was aware of ex_normal and decided to - // override the value of restart_edit anyway. - restart_edit = save_restart_edit; - } - p_im = save_insertmode; - finish_op = save_finish_op; - opcount = save_opcount; - reg_executing = save_reg_executing; - msg_didout |= save_msg_didout; // don't reset msg_didout now + ex_normal_busy--; - /* Restore the state (needed when called from a function executed for - * 'indentexpr'). Update the mouse and cursor, they may have changed. */ - State = save_State; setmouse(); - ui_cursor_shape(); /* may show different cursor shape */ + ui_cursor_shape(); // may show different cursor shape xfree(arg); } -- cgit From a576bf6196a66a0542af82c51e77e51d90a80c67 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 28 Apr 2020 18:57:11 -0400 Subject: vim-patch:8.2.0648: semicolon search does not work in first line Problem: Semicolon search does not work in first line. Solution: Allow the cursor to be in line zero. (Christian Brabandt, closes vim/vim#5996) https://github.com/vim/vim/commit/0e71704b77a9891ccae9f5a9c7429e933078f232 --- src/nvim/ex_docmd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 3f7d616b8f..5bf6aa73c6 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2476,8 +2476,11 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg) if (*eap->cmd == ';') { if (!eap->skip) { curwin->w_cursor.lnum = eap->line2; - // don't leave the cursor on an illegal line or column - check_cursor(); + // Don't leave the cursor on an illegal line or column, but do + // accept zero as address, so 0;/PATTERN/ works correctly. + if (eap->line2 > 0) { + check_cursor(); + } } } else if (*eap->cmd != ',') { break; -- cgit