From bcb70eeac48040fd6d6bfc20cf7fb6f41374a67c Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 4 Feb 2024 00:42:36 +0000 Subject: fix(api): win_set_config autocmds crash when moving win to other tabpage Problem: win_enter autocommands can close new_curwin, crashing if it was the last window in its tabpage after removing win, or can close parent, crashing when attempting to split it later. Solution: remove win first, check that parent is valid after win_enter. NOTE: This isn't actually quite right, as this means win is not in the window list or even has a frame when triggering enter autocommands (so it's not considered valid in the tabpage). This is addressed in later commits. --- src/nvim/api/win_config.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 3cc520dc78..bb1117b3fe 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -478,12 +478,17 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) int dir; new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); } + win_remove(win, win_tp == curtab ? NULL : win_tp); // move to neighboring window if we're moving the current window to a new tabpage if (curwin == win && parent != NULL && new_curwin != NULL && win_tp != win_find_tabpage(parent)) { win_enter(new_curwin, true); + if (!win_valid_any_tab(parent)) { + // win_enter autocommands closed the `parent` to split from. + api_set_error(err, kErrorTypeException, "Window to split was closed"); + return; + } } - win_remove(win, win_tp == curtab ? NULL : win_tp); } else { win_remove(win, win_tp == curtab ? NULL : win_tp); ui_comp_remove_grid(&win->w_grid_alloc); -- cgit From 233649bc757743f7677b2ae414779192a94aa2ae Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 4 Feb 2024 01:50:49 +0000 Subject: fix(api): win_set_config fires unnecessary autocmds Problem: win_set_config should have the observable effect of moving an existing window to another place, but instead fires autocommands as if a new window was created and entered (and does not fire autocommands reflecting a "return" to the original window). Solution: do not fire win_enter-related autocommands when splitting the window, but continue to fire them when entering the window that fills the new space when moving a window to a different tabpage, as the new curwin changes. Also, remove "++once" from the WinEnter autocmd in the other test, as omitting it also crashed Nvim before this fix. --- src/nvim/api/win_config.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index bb1117b3fe..e53e13e2a3 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -505,7 +505,7 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) win->w_pos_changed = true; } - int flags = win_split_flags(fconfig.split, parent == NULL); + int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; if (parent == NULL) { if (!win_split_ins(0, flags, win, 0)) { @@ -514,24 +514,13 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) return; } } else { - win_execute_T args; - - tabpage_T *tp = win_find_tabpage(parent); - if (!win_execute_before(&args, parent, tp)) { - // TODO(willothy): how should we handle this / what should the message be? - api_set_error(err, kErrorTypeException, "Failed to switch to tabpage %d", tp->handle); - win_execute_after(&args); - return; - } - // This should return the same ptr to `win`, but we check for - // NULL to detect errors. - win_T *res = win_split_ins(0, flags, win, 0); - win_execute_after(&args); - if (!res) { - // TODO(willothy): What should this error message say? - api_set_error(err, kErrorTypeException, "Failed to split window"); - return; - } + switchwin_T switchwin; + // `parent` is valid in its tabpage, so switch_win should not fail. + const int result = switch_win(&switchwin, parent, win_find_tabpage(parent), true); + (void)result; + assert(result == OK); + win_split_ins(0, flags, win, 0); + restore_win(&switchwin, true); } if (HAS_KEY_X(config, width)) { win_setwidth_win(fconfig.width, win); @@ -539,7 +528,6 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) if (HAS_KEY_X(config, height)) { win_setheight_win(fconfig.height, win); } - redraw_later(win, UPD_NOT_VALID); return; } else { win_config_float(win, fconfig); -- cgit From a873f33993ef84e3f954127038e559e1ac1cac43 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 4 Feb 2024 02:59:26 +0000 Subject: fix(api): open_win fire BufWinEnter for other buffer when !enter && !noautocmd Problem: BufWinEnter is not fired when not entering a new window, even when a different buffer is specified and buffer-related autocommands are unblocked (!noautocmd). Solution: fire it in the context of the new window and buffer. Do not do it if the buffer is unchanged, like :{s}buffer. Be wary of autocommands! For example, it's possible for nvim_win_set_config to be used in an autocommand to move a window to a different tabpage (in contrast, things like wincmd T actually create a *new* window, so it may not have been possible before, meaning other parts of Nvim could assume windows can't do this... I'd be especially cautious of logic that restores curwin and curtab without checking if curwin is still valid in curtab, if any such logic exists). Also, bail early from win_set_buf if setting the temp curwin fails; this shouldn't be possible, as the callers check that wp is valid, but in case that's not true, win_set_buf will no longer continue setting a buffer for the wrong window. Note that pum_create_float_preview also uses win_set_buf, but from a glance, doesn't look like it properly checks for autocmds screwing things up (win_enter, nvim_create_buf...). I haven't addressed that here. Also adds some test coverage for nvim_open_win autocommands. Closes #27121. --- src/nvim/api/win_config.c | 39 +++++++++++++++++++++++++++++++-------- src/nvim/window.c | 6 ++++-- 2 files changed, 35 insertions(+), 10 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index e53e13e2a3..9d63a1997c 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -261,8 +261,8 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err switchwin_T switchwin; // `parent` is valid in `tp`, so switch_win should not fail. const int result = switch_win(&switchwin, parent, tp, true); - (void)result; assert(result == OK); + (void)result; wp = win_split_ins(0, flags, NULL, 0); restore_win(&switchwin, true); } @@ -276,18 +276,41 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err api_set_error(err, kErrorTypeException, "Failed to create window"); return 0; } + + // Autocommands may close `wp` or move it to another tabpage, so update and check `tp` after each + // event. In each case, `wp` should already be valid in `tp`, so switch_win should not fail. switchwin_T switchwin; - if (switch_win_noblock(&switchwin, wp, tp, true) == OK) { - apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); + { + const int result = switch_win_noblock(&switchwin, wp, tp, true); + assert(result == OK); + (void)result; + if (apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf)) { + tp = win_find_tabpage(wp); + } + restore_win_noblock(&switchwin, true); } - restore_win_noblock(&switchwin, true); - if (enter) { + if (tp && enter) { goto_tabpage_win(tp, wp); + tp = win_find_tabpage(wp); } - if (win_valid_any_tab(wp) && buf != wp->w_buffer) { - win_set_buf(wp, buf, !enter || fconfig.noautocmd, err); + if (tp && buf != wp->w_buffer) { + const bool noautocmd = !enter || fconfig.noautocmd; + win_set_buf(wp, buf, noautocmd, err); + if (!noautocmd) { + tp = win_find_tabpage(wp); + } + // win_set_buf autocommands were blocked if we didn't enter, but we still want BufWinEnter. + if (noautocmd && !fconfig.noautocmd && wp->w_buffer == buf) { + const int result = switch_win_noblock(&switchwin, wp, tp, true); + assert(result == OK); + (void)result; + if (apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, false, buf)) { + tp = win_find_tabpage(wp); + } + restore_win_noblock(&switchwin, true); + } } - if (!win_valid_any_tab(wp)) { + if (!tp) { api_set_error(err, kErrorTypeException, "Window was closed immediately"); return 0; } diff --git a/src/nvim/window.c b/src/nvim/window.c index e2c4524eaa..d5a6e347e7 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -718,6 +718,7 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err) kErrorTypeException, "Failed to switch to window %d", win->handle); + goto cleanup; } try_start(); @@ -729,10 +730,11 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err) buf->handle); } - // If window is not current, state logic will not validate its cursor. - // So do it now. + // If window is not current, state logic will not validate its cursor. So do it now. + // Still needed if do_buffer returns FAIL (e.g: autocmds abort script after buffer was set). validate_cursor(); +cleanup: restore_win_noblock(&switchwin, true); if (noautocmd) { unblock_autocmds(); -- cgit From e55a502ed413d2bc8954b5227acfb34c8689f979 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 11 Feb 2024 18:45:56 +0000 Subject: fix(api): open_win fire Buf* events when !enter && !noautocmd if entered early Problem: if switch_win{_noblock} fails to restore the old curwin after WinNew (e.g: it was closed), wp will become the new curwin, but win_set_buf enter events would still be blocked if !enter && !noautocmd. Solution: fire them, as we've actually entered the new window. Note: there's a problem of switch_win{_noblock} failing to restore the old curwin, leaving us in wp without triggering WinEnter/WinLeave, but this affects all callers of switch_win{_noblock} anyways. (It's also not clear how WinLeave can be called if the old curwin was closed already). --- src/nvim/api/win_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 9d63a1997c..238ec5df1e 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -294,7 +294,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err tp = win_find_tabpage(wp); } if (tp && buf != wp->w_buffer) { - const bool noautocmd = !enter || fconfig.noautocmd; + const bool noautocmd = curwin != wp || fconfig.noautocmd; win_set_buf(wp, buf, noautocmd, err); if (!noautocmd) { tp = win_find_tabpage(wp); -- cgit From b1e24f240baeea80dcf4a3d8453fed0230fb88fd Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 11 Feb 2024 20:15:47 +0000 Subject: fix(api): avoid open_win UAF if target buf deleted by autocmds Problem: WinNew and win_enter autocommands can delete the target buffer to switch to, causing a heap-use-after-free. Solution: store a bufref to the buffer, check it before attempting to switch. --- src/nvim/api/win_config.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 238ec5df1e..3959e74af9 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -12,6 +12,7 @@ #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" +#include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" #include "nvim/decoration_defs.h" @@ -279,6 +280,9 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err // Autocommands may close `wp` or move it to another tabpage, so update and check `tp` after each // event. In each case, `wp` should already be valid in `tp`, so switch_win should not fail. + // Also, autocommands may free the `buf` to switch to, so store a bufref to check. + bufref_T bufref; + set_bufref(&bufref, buf); switchwin_T switchwin; { const int result = switch_win_noblock(&switchwin, wp, tp, true); @@ -293,7 +297,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err goto_tabpage_win(tp, wp); tp = win_find_tabpage(wp); } - if (tp && buf != wp->w_buffer) { + if (tp && bufref_valid(&bufref) && buf != wp->w_buffer) { const bool noautocmd = curwin != wp || fconfig.noautocmd; win_set_buf(wp, buf, noautocmd, err); if (!noautocmd) { -- cgit From 5d58136cccc760f6d95eb45b46f2ad60f06b103b Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Wed, 7 Feb 2024 17:17:44 +0000 Subject: fix(api): make open_win/win_set_config check if splitting allowed Problem: splitting is disallowed in some cases to prevent the window layout changes while a window is closing, but it's not checked for. Solution: check for this, and set the API error message directly. (Also sneak in a change to tui.c that got lost from #27352; it's a char* buf, and the memset is assuming one byte each anyway) --- src/nvim/api/win_config.c | 8 ++++++++ src/nvim/tui/tui.c | 2 +- src/nvim/window.c | 36 ++++++++++++++++++++++++++---------- 3 files changed, 35 insertions(+), 11 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 3959e74af9..557c2f37f9 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -246,6 +246,10 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err } } + if (!check_split_disallowed_err(parent ? parent : curwin, err)) { + return 0; // error already set + } + if (HAS_KEY_X(config, vertical) && !HAS_KEY_X(config, split)) { if (config->vertical) { fconfig.split = p_spr ? kWinSplitRight : kWinSplitLeft; @@ -440,6 +444,10 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) return; } + if (!check_split_disallowed_err(win, err)) { + return; // error already set + } + if (was_split) { win_T *new_curwin = NULL; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 7fae34d33f..c332c17e43 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1643,7 +1643,7 @@ static void invalidate(TUIData *tui, int top, int bot, int left, int right) static void ensure_space_buf_size(TUIData *tui, size_t len) { if (len > tui->space_buf_len) { - tui->space_buf = xrealloc(tui->space_buf, len * sizeof *tui->space_buf); + tui->space_buf = xrealloc(tui->space_buf, len); memset(tui->space_buf + tui->space_buf_len, ' ', len - tui->space_buf_len); tui->space_buf_len = len; } diff --git a/src/nvim/window.c b/src/nvim/window.c index d5a6e347e7..81f8304b22 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -905,19 +905,35 @@ void ui_ext_win_viewport(win_T *wp) } } -/// If "split_disallowed" is set give an error and return FAIL. +/// If "split_disallowed" is set or "wp"s buffer is closing, give an error and return FAIL. /// Otherwise return OK. -static int check_split_disallowed(void) +static int check_split_disallowed(const win_T *wp) + FUNC_ATTR_NONNULL_ALL +{ + Error err = ERROR_INIT; + const bool ok = check_split_disallowed_err(wp, &err); + if (ERROR_SET(&err)) { + emsg(_(err.msg)); + api_clear_error(&err); + } + return ok ? OK : FAIL; +} + +/// Like `check_split_disallowed`, but set `err` to the (untranslated) error message on failure and +/// return false. Otherwise return true. +/// @see check_split_disallowed +bool check_split_disallowed_err(const win_T *wp, Error *err) + FUNC_ATTR_NONNULL_ALL { if (split_disallowed > 0) { - emsg(_("E242: Can't split a window while closing another")); - return FAIL; + api_set_error(err, kErrorTypeException, "E242: Can't split a window while closing another"); + return false; } - if (curwin->w_buffer->b_locked_split) { - emsg(_(e_cannot_split_window_when_closing_buffer)); - return FAIL; + if (wp->w_buffer->b_locked_split) { + api_set_error(err, kErrorTypeException, "%s", e_cannot_split_window_when_closing_buffer); + return false; } - return OK; + return true; } // split the current window, implements CTRL-W s and :split @@ -936,7 +952,7 @@ static int check_split_disallowed(void) // return FAIL for failure, OK otherwise int win_split(int size, int flags) { - if (check_split_disallowed() == FAIL) { + if (check_split_disallowed(curwin) == FAIL) { return FAIL; } @@ -1871,7 +1887,7 @@ static void win_totop(int size, int flags) if (is_aucmd_win(curwin)) { return; } - if (check_split_disallowed() == FAIL) { + if (check_split_disallowed(curwin) == FAIL) { return; } -- cgit From b1577d371a6db43222de9e3a525def82320ebdb1 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Wed, 7 Feb 2024 21:44:42 +0000 Subject: fix(api): make win_set_config with "win" for splits need "split/vertical" Problem: currently, for splits, nvim_win_set_config accepts win without any of split or vertical set, which has little effect and seems error-prone. Solution: require at least one of split or vertical to also be set for splits. Also, update nvim_win_set_config docs, as it's no longer limited to just floating and external windows. --- src/nvim/api/win_config.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 557c2f37f9..21d6d59b1e 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -361,11 +361,11 @@ static int win_split_flags(WinSplit split, bool toplevel) return flags; } -/// Configures window layout. Currently only for floating and external windows -/// (including changing a split window to those layouts). +/// Configures window layout. Cannot be used to move the last window in a +/// tabpage to a different one. /// -/// When reconfiguring a floating window, absent option keys will not be -/// changed. `row`/`col` and `relative` must be reconfigured together. +/// When reconfiguring a window, absent option keys will not be changed. +/// `row`/`col` and `relative` must be reconfigured together. /// /// @see |nvim_open_win()| /// @@ -1099,11 +1099,15 @@ static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, boo fconfig->window = config->win; } } - } else if (has_relative) { - if (HAS_KEY_X(config, win)) { + } else if (HAS_KEY_X(config, win)) { + if (has_relative) { api_set_error(err, kErrorTypeValidation, "'win' key is only valid with relative='win' and relative=''"); return false; + } else if (!is_split) { + api_set_error(err, kErrorTypeValidation, + "non-float with 'win' requires at least 'split' or 'vertical'"); + return false; } } -- cgit From a70eae57bd44208a77b5ac29839e8a39ab3c9cd8 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 11 Feb 2024 22:53:37 +0000 Subject: fix(api): make open_win block only enter/leave events if !enter && !noautocmd Problem: nvim_open_win blocking all win_set_buf autocommands when !enter && !noautocmd is too aggressive. Solution: temporarily block WinEnter/Leave and BufEnter/Leave events when setting the buffer. Delegate the firing of BufWinEnter back to win_set_buf, which also has the advantage of keeping the timing consistent (e.g: before the epilogue in enter_buffer, which also handles restoring the cursor position if autocommands didn't change it, among other things). Reword the documentation for noautocmd a bit. I pondered modifying do_buffer and callees to allow for BufEnter/Leave being conditionally disabled, but it seems too invasive (and potentially error-prone, especially if new code paths to BufEnter/Leave are added in the future). Unfortunately, doing this has the drawback of blocking ALL such events for the duration, which also means blocking unrelated such events; like if window switching occurs in a ++nested autocmd fired by win_set_buf. If this turns out to be a problem in practice, a different solution specialized for nvim_open_win could be considered. :-) --- src/nvim/api/win_config.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 21d6d59b1e..8608b0dde9 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -199,9 +199,9 @@ /// - footer_pos: Footer position. Must be set with `footer` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. -/// - noautocmd: If true then no buffer-related autocommand events such as -/// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from -/// calling this function. +/// - noautocmd: If true then autocommands triggered from setting the +/// `buffer` to display are blocked (e.g: |BufEnter|, |BufLeave|, +/// |BufWinEnter|). /// - fixed: If true when anchor is NW or SW, the float window /// would be kept fixed even if the window would be truncated. /// - hide: If true the floating window will be hidden. @@ -302,20 +302,20 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err tp = win_find_tabpage(wp); } if (tp && bufref_valid(&bufref) && buf != wp->w_buffer) { - const bool noautocmd = curwin != wp || fconfig.noautocmd; - win_set_buf(wp, buf, noautocmd, err); - if (!noautocmd) { + // win_set_buf temporarily makes `wp` the curwin to set the buffer. + // If not entering `wp`, block Enter and Leave events. (cringe) + const bool au_no_enter_leave = curwin != wp && !fconfig.noautocmd; + if (au_no_enter_leave) { + autocmd_no_enter++; + autocmd_no_leave++; + } + win_set_buf(wp, buf, fconfig.noautocmd, err); + if (!fconfig.noautocmd) { tp = win_find_tabpage(wp); } - // win_set_buf autocommands were blocked if we didn't enter, but we still want BufWinEnter. - if (noautocmd && !fconfig.noautocmd && wp->w_buffer == buf) { - const int result = switch_win_noblock(&switchwin, wp, tp, true); - assert(result == OK); - (void)result; - if (apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, false, buf)) { - tp = win_find_tabpage(wp); - } - restore_win_noblock(&switchwin, true); + if (au_no_enter_leave) { + autocmd_no_enter--; + autocmd_no_leave--; } } if (!tp) { -- cgit From 66f331fef7ad3df480bd02f1705e176d1a07c785 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Fri, 23 Feb 2024 09:49:28 +0000 Subject: vim-patch:9.1.0116: win_split_ins may not check available room Problem: win_split_ins has no check for E36 when moving an existing window Solution: check for room and fix the issues in f_win_splitmove() (Sean Dewar) https://github.com/vim/vim/commit/0fd44a5ad81ade342cb54d8984965bdedd2272c8 Omit WSP_FORCE_ROOM, as it's not needed for Nvim's autocmd window, which is floating. Shouldn't be difficult to port later if it's used for anything else. Make win_splitmove continue working for turning floating windows into splits. Move the logic for "unfloating" a float to win_split_ins; unlike splits, no changes to the window layout are needed before calling it, as floats take no room in the window layout and cannot affect the e_noroom check. Add missing tp_curwin-fixing logic for turning external windows into splits, and add a test. NOTE: there are other issues with the way "tabpage independence" is implemented for external windows; namely, some things assume that tp_curwin is indeed a window within that tabpage, and as such, functions like tabpage_winnr and nvim_tabpage_get_win currently don't always work for external windows (with the latter aborting!) Use last_status over frame_add_statusline, as Nvim's last_status already does this for all windows in the current tabpage. Adjust restore_full_snapshot_rec to handle this. This "restore everything" approach is changed in a future commit anyway, so only ensure it's robust enough to just pass tests. Keep check_split_disallowed's current doc comment, as it's actually a bit more accurate here. (I should probably PR Vim to use this one) Allow f_win_splitmove to move a floating "wp" into a split; Nvim supports this. Continue to disallow it from moving the autocommand window into a split (funnily enough, the check wasn't reachable before, as moving a float was disallowed), but now return -1 in that case (win_splitmove also returns FAIL for this, but handling it in f_win_splitmove avoids us needing to switch windows first). Cherry-pick Test_window_split_no_room fix from v9.1.0121. Update nvim_win_set_config to handle win_split_ins failure in later commits. --- src/nvim/api/win_config.c | 12 --- src/nvim/buffer.c | 1 - src/nvim/eval/window.c | 66 ++++++-------- src/nvim/globals.h | 1 + src/nvim/window.c | 213 +++++++++++++++++++++++++++++++++++----------- 5 files changed, 189 insertions(+), 104 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 8608b0dde9..c308cadb7c 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -526,18 +526,6 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) } } else { win_remove(win, win_tp == curtab ? NULL : win_tp); - ui_comp_remove_grid(&win->w_grid_alloc); - if (win->w_config.external) { - for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) { - if (tp == curtab) { - continue; - } - if (tp->tp_curwin == win) { - tp->tp_curwin = tp->tp_firstwin; - } - } - } - win->w_pos_changed = true; } int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index f6c7229485..b013f43ceb 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -117,7 +117,6 @@ # include "buffer.c.generated.h" #endif -static const char *e_auabort = N_("E855: Autocommands caused command to abort"); static const char e_attempt_to_delete_buffer_that_is_in_use_str[] = N_("E937: Attempt to delete a buffer that is in use: %s"); diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index b8aa0c9641..17b8b01963 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -659,55 +659,19 @@ void f_win_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1); } -/// Move the window wp into a new split of targetwin in a given direction -static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags) -{ - int height = wp->w_height; - win_T *oldwin = curwin; - - if (wp == targetwin || is_aucmd_win(wp)) { - return; - } - - // Jump to the target window - if (curwin != targetwin) { - win_goto(targetwin); - } - - // Remove the old window and frame from the tree of frames - int dir; - winframe_remove(wp, &dir, NULL); - win_remove(wp, NULL); - last_status(false); // may need to remove last status line - win_comp_pos(); // recompute window positions - - // Split a window on the desired side and put the old window there - win_split_ins(size, flags, wp, dir); - - // If splitting horizontally, try to preserve height - if (size == 0 && !(flags & WSP_VERT)) { - win_setheight_win(height, wp); - if (p_ea) { - win_equal(wp, true, 'v'); - } - } - - if (oldwin != curwin) { - win_goto(oldwin); - } -} - /// "win_splitmove()" function void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = find_win_by_nr_or_id(&argvars[0]); win_T *targetwin = find_win_by_nr_or_id(&argvars[1]); + win_T *oldwin = curwin; + + rettv->vval.v_number = -1; if (wp == NULL || targetwin == NULL || wp == targetwin || !win_valid(wp) || !win_valid(targetwin) - || win_float_valid(wp) || win_float_valid(targetwin)) { + || targetwin->w_floating) { emsg(_(e_invalwindow)); - rettv->vval.v_number = -1; return; } @@ -732,7 +696,27 @@ void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) size = (int)tv_dict_get_number(d, "size"); } - win_move_into_split(wp, targetwin, size, flags); + // Check if we can split the target before we bother switching windows. + if (is_aucmd_win(wp) || check_split_disallowed(targetwin) == FAIL) { + return; + } + + if (curwin != targetwin) { + win_goto(targetwin); + } + + // Autocommands may have sent us elsewhere or closed "wp" or "oldwin". + if (curwin == targetwin && win_valid(wp)) { + if (win_splitmove(wp, size, flags) == OK) { + rettv->vval.v_number = 0; + } + } else { + emsg(_(e_auabort)); + } + + if (oldwin != curwin && win_valid(oldwin)) { + win_goto(oldwin); + } } /// "win_gettype(nr)" function diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 22f7daa823..c1c9ae456c 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -939,6 +939,7 @@ EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d")); EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); +EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort")); EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); diff --git a/src/nvim/window.c b/src/nvim/window.c index 81f8304b22..cfa28bbc1f 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -455,9 +455,14 @@ newwindow: case 'H': case 'L': CHECK_CMDWIN; - win_totop(Prenum, - ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0) - | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT)); + if (firstwin == curwin && lastwin_nofloating() == curwin) { + beep_flush(); + } else { + const int dir = ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0) + | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT); + + win_splitmove(curwin, Prenum, dir); + } break; // make all windows the same width and/or height @@ -907,7 +912,7 @@ void ui_ext_win_viewport(win_T *wp) /// If "split_disallowed" is set or "wp"s buffer is closing, give an error and return FAIL. /// Otherwise return OK. -static int check_split_disallowed(const win_T *wp) +int check_split_disallowed(const win_T *wp) FUNC_ATTR_NONNULL_ALL { Error err = ERROR_INIT; @@ -1004,13 +1009,12 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) int need_status = 0; int new_size = size; - bool new_in_layout = (new_wp == NULL || new_wp->w_floating); bool vertical = flags & WSP_VERT; bool toplevel = flags & (WSP_TOP | WSP_BOT); // add a status line when p_ls == 1 and splitting the first window if (one_nonfloat() && p_ls == 1 && oldwin->w_status_height == 0) { - if (oldwin->w_height <= p_wmh && new_in_layout) { + if (oldwin->w_height <= p_wmh) { emsg(_(e_noroom)); return NULL; } @@ -1059,7 +1063,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) available = oldwin->w_frame->fr_width; needed += minwidth; } - if (available < needed && new_in_layout) { + if (available < needed) { emsg(_(e_noroom)); return NULL; } @@ -1139,7 +1143,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) available = oldwin->w_frame->fr_height; needed += minheight; } - if (available < needed && new_in_layout) { + if (available < needed) { emsg(_(e_noroom)); return NULL; } @@ -1229,8 +1233,27 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) // make the contents of the new window the same as the current one win_init(wp, curwin, flags); } else if (wp->w_floating) { - new_frame(wp); + ui_comp_remove_grid(&wp->w_grid_alloc); + if (ui_has(kUIMultigrid)) { + wp->w_pos_changed = true; + } else { + // No longer a float, a non-multigrid UI shouldn't draw it as such + ui_call_win_hide(wp->w_grid_alloc.handle); + win_free_grid(wp, true); + } + + // External windows are independent of tabpages, and may have been the curwin of others. + if (wp->w_config.external) { + FOR_ALL_TABS(tp) { + if (tp != curtab && tp->tp_curwin == wp) { + tp->tp_curwin = tp->tp_firstwin; + } + } + } + wp->w_floating = false; + new_frame(wp); + // non-floating window doesn't store float config or have a border. wp->w_config = WIN_CONFIG_INIT; CLEAR_FIELD(wp->w_border_adj); @@ -1874,48 +1897,67 @@ static void win_rotate(bool upwards, int count) redraw_all_later(UPD_NOT_VALID); } -// Move the current window to the very top/bottom/left/right of the screen. -static void win_totop(int size, int flags) +/// Move "wp" into a new split in a given direction, possibly relative to the +/// current window. +/// "wp" must be valid in the current tabpage. +/// Returns FAIL for failure, OK otherwise. +int win_splitmove(win_T *wp, int size, int flags) { int dir = 0; - int height = curwin->w_height; + int height = wp->w_height; - if (firstwin == curwin && lastwin_nofloating() == curwin) { - beep_flush(); - return; - } - if (is_aucmd_win(curwin)) { - return; + if (firstwin == wp && lastwin_nofloating() == wp) { + return OK; // nothing to do } - if (check_split_disallowed(curwin) == FAIL) { - return; + if (is_aucmd_win(wp) || check_split_disallowed(wp) == FAIL) { + return FAIL; } - if (curwin->w_floating) { - ui_comp_remove_grid(&curwin->w_grid_alloc); - if (ui_has(kUIMultigrid)) { - curwin->w_pos_changed = true; - } else { - // No longer a float, a non-multigrid UI shouldn't draw it as such - ui_call_win_hide(curwin->w_grid_alloc.handle); - win_free_grid(curwin, true); - } + frame_T *frp = NULL; + if (wp->w_floating) { + win_remove(wp, NULL); } else { + // Undoing changes to frames if splitting fails is complicated. + // Save a full snapshot to restore instead. + frp = make_full_snapshot(); + // Remove the window and frame from the tree of frames. - winframe_remove(curwin, &dir, NULL); + winframe_remove(wp, &dir, NULL); + win_remove(wp, NULL); + last_status(false); // may need to remove last status line + win_comp_pos(); // recompute window positions + } + + // Split a window on the desired side and put "wp" there. + if (win_split_ins(size, flags, wp, dir) == NULL) { + win_append(wp->w_prev, wp); + if (!wp->w_floating) { + // Restore the previous layout from the snapshot. + xfree(wp->w_frame); + restore_full_snapshot(frp); + + // Vertical separators to the left may have been lost. Restore them. + frp = wp->w_frame; + if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) { + frame_add_vsep(frp->fr_prev); + } + } + return FAIL; } - win_remove(curwin, NULL); - last_status(false); // may need to remove last status line - win_comp_pos(); // recompute window positions + clear_snapshot_rec(frp); - // Split a window on the desired side and put the window there. - win_split_ins(size, flags, curwin, dir); - if (!(flags & WSP_VERT)) { - win_setheight(height); + // If splitting horizontally, try to preserve height. + // Note that win_split_ins autocommands may have immediately made "wp" floating! + if (size == 0 && !(flags & WSP_VERT) && !wp->w_floating) { + win_setheight_win(height, wp); if (p_ea) { - win_equal(curwin, true, 'v'); + // Equalize windows. Note that win_split_ins autocommands may have + // made a window other than "wp" current. + win_equal(curwin, curwin == wp, 'v'); } } + + return OK; } // Move window "win1" to below/right of "win2" and make "win1" the current @@ -2777,13 +2819,10 @@ int win_close(win_T *win, bool free_buf, bool force) ui_comp_remove_grid(&win->w_grid_alloc); assert(first_tabpage != NULL); // suppress clang "Dereference of NULL pointer" if (win->w_config.external) { - for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) { - if (tp == curtab) { - continue; - } - if (tp->tp_curwin == win) { + FOR_ALL_TABS(tp) { + if (tp != curtab && tp->tp_curwin == win) { // NB: an autocmd can still abort the closing of this window, - // bur carring out this change anyway shouldn't be a catastrophe. + // but carrying out this change anyway shouldn't be a catastrophe. tp->tp_curwin = tp->tp_firstwin; } } @@ -7207,23 +7246,23 @@ void reset_lnums(void) void make_snapshot(int idx) { clear_snapshot(curtab, idx); - make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]); + make_snapshot_rec(topframe, &curtab->tp_snapshot[idx], false); } -static void make_snapshot_rec(frame_T *fr, frame_T **frp) +static void make_snapshot_rec(frame_T *fr, frame_T **frp, bool snap_wins) { *frp = xcalloc(1, sizeof(frame_T)); (*frp)->fr_layout = fr->fr_layout; (*frp)->fr_width = fr->fr_width; (*frp)->fr_height = fr->fr_height; if (fr->fr_next != NULL) { - make_snapshot_rec(fr->fr_next, &((*frp)->fr_next)); + make_snapshot_rec(fr->fr_next, &((*frp)->fr_next), snap_wins); } if (fr->fr_child != NULL) { - make_snapshot_rec(fr->fr_child, &((*frp)->fr_child)); + make_snapshot_rec(fr->fr_child, &((*frp)->fr_child), snap_wins); } - if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin) { - (*frp)->fr_win = curwin; + if (fr->fr_layout == FR_LEAF && (snap_wins || fr->fr_win == curwin)) { + (*frp)->fr_win = fr->fr_win; } } @@ -7340,6 +7379,80 @@ static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr) return wp; } +/// Return a snapshot of all frames in the current tabpage and which windows are +/// in them. +/// Use clear_snapshot_rec to free the snapshot. +static frame_T *make_full_snapshot(void) +{ + frame_T *frp; + make_snapshot_rec(topframe, &frp, true); + return frp; +} + +/// Restore all frames in the full snapshot "sn" for the current tabpage. +/// Caller must ensure that the screen size didn't change, no windows with frames +/// in the snapshot were freed, and windows with frames not in the snapshot are +/// removed from their frames! +/// Doesn't restore changed window vertical separators. +/// Frees the old frames. Don't call clear_snapshot_rec on "sn" afterwards! +static void restore_full_snapshot(frame_T *sn) +{ + if (sn == NULL) { + return; + } + + clear_snapshot_rec(topframe); + restore_full_snapshot_rec(sn); + curtab->tp_topframe = topframe = sn; + last_status(false); + + // If the amount of space available changed, first try setting the sizes of + // windows with 'winfix{width,height}'. If that doesn't result in the right + // size, forget about that option. + if (topframe->fr_width != Columns) { + frame_new_width(topframe, Columns, false, true); + if (!frame_check_width(topframe, Columns)) { + frame_new_width(topframe, Columns, false, false); + } + } + if (topframe->fr_height != ROWS_AVAIL) { + frame_new_height(topframe, (int)ROWS_AVAIL, false, true); + if (!frame_check_height(topframe, (int)ROWS_AVAIL)) { + frame_new_height(topframe, (int)ROWS_AVAIL, false, false); + } + } + + win_comp_pos(); +} + +static void restore_full_snapshot_rec(frame_T *sn) +{ + if (sn == NULL) { + return; + } + + if (sn->fr_child != NULL) { + sn->fr_child->fr_parent = sn; + } + if (sn->fr_next != NULL) { + sn->fr_next->fr_parent = sn->fr_parent; + sn->fr_next->fr_prev = sn; + } + if (sn->fr_win != NULL) { + sn->fr_win->w_frame = sn; + // Assume for now that all windows have statuslines, so last_status in restore_full_snapshot + // doesn't resize frames to fit any missing statuslines. + sn->fr_win->w_status_height = STATUS_HEIGHT; + sn->fr_win->w_hsep_height = 0; + + // Resize window to fit the frame. + frame_new_height(sn, sn->fr_height, false, false); + frame_new_width(sn, sn->fr_width, false, false); + } + restore_full_snapshot_rec(sn->fr_child); + restore_full_snapshot_rec(sn->fr_next); +} + /// Check that "topfrp" and its children are at the right height. /// /// @param topfrp top frame pointer -- cgit From 24dfa47e4f4ca41d0c5f8c1c0f851602362c81d3 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sat, 24 Feb 2024 23:18:50 +0000 Subject: vim-patch:partial:9.1.0117: Stop split-moving from firing WinNew and WinNewPre autocommands Problem: win_splitmove fires WinNewPre and possibly WinNew when moving windows, even though no new windows are created. Solution: don't fire WinNew and WinNewPre when inserting an existing window, even if it isn't the current window. Improve the accuracy of related documentation. (Sean Dewar) https://github.com/vim/vim/commit/96cc4aef3d47d0fd70e68908af3d48a0dce8ea70 Partial as WinNewPre has not been ported yet (it currently has problems anyway). --- src/nvim/eval.lua | 8 ++++---- src/nvim/window.c | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index b7120d5dd5..febd022254 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -12699,10 +12699,10 @@ M.funcs = { args = { 2, 3 }, base = 1, desc = [=[ - Move the window {nr} to a new split of the window {target}. - This is similar to moving to {target}, creating a new window - using |:split| but having the same contents as window {nr}, and - then closing {nr}. + Temporarily switch to window {target}, then move window {nr} + to a new split adjacent to {target}. + Unlike commands such as |:split|, no new windows are created + (the |window-ID| of window {nr} is unchanged after the move). Both {nr} and {target} can be window numbers or |window-ID|s. Both must be in the current tab page. diff --git a/src/nvim/window.c b/src/nvim/window.c index cfa28bbc1f..b1135d59fc 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -987,6 +987,8 @@ int win_split(int size, int flags) /// When "new_wp" is NULL: split the current window in two. /// When "new_wp" is not NULL: insert this window at the far /// top/left/right/bottom. +/// On failure, if "new_wp" was not NULL, no changes will have been made to the +/// window layout or sizes. /// @return NULL for failure, or pointer to new window win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) { @@ -1494,7 +1496,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) if (!(flags & WSP_NOENTER)) { // make the new window the current window - win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS | WEE_TRIGGER_ENTER_AUTOCMDS + win_enter_ext(wp, (new_wp == NULL ? WEE_TRIGGER_NEW_AUTOCMDS : 0) | WEE_TRIGGER_ENTER_AUTOCMDS | WEE_TRIGGER_LEAVE_AUTOCMDS); } if (vertical) { -- cgit From 1c6b693ec1592f9d193fc9cc1bb03e738fb2bef6 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:03:26 +0000 Subject: vim-patch:9.1.0118: Use different restoration strategy in win_splitmove Problem: saving and restoring all frames to split-move is overkill now that WinNewPre is not fired when split-moving. Solution: defer the flattening of frames until win_split_ins begins reorganising them, and attempt to restore the layout by undoing our changes. (Sean Dewar) https://github.com/vim/vim/commit/704966c2545897dfcf426dd9ef946aeb6fa80c38 Adjust winframe_restore to account for Nvim's horizontal separators when the global statusline is in use. Add a test. --- src/nvim/api/win_config.c | 14 +-- src/nvim/window.c | 267 +++++++++++++++++++++------------------------- src/nvim/winfloat.c | 2 +- 3 files changed, 132 insertions(+), 151 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index c308cadb7c..978d8515c8 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -260,7 +260,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; if (parent == NULL) { - wp = win_split_ins(0, flags, NULL, 0); + wp = win_split_ins(0, flags, NULL, 0, NULL); } else { tp = win_find_tabpage(parent); switchwin_T switchwin; @@ -268,7 +268,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err const int result = switch_win(&switchwin, parent, tp, true); assert(result == OK); (void)result; - wp = win_split_ins(0, flags, NULL, 0); + wp = win_split_ins(0, flags, NULL, 0, NULL); restore_win(&switchwin, true); } if (wp) { @@ -495,11 +495,11 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) // If the frame doesn't have a parent, the old frame // was the root frame and we need to create a top-level split. int dir; - new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); + new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL); } else if (n_frames == 2) { // There are two windows in the frame, we can just rotate it. int dir; - neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); + neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL); new_curwin = neighbor; } else { // There is only one window in the frame, we can't split it. @@ -511,7 +511,7 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) parent = neighbor; } else { int dir; - new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); + new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL); } win_remove(win, win_tp == curtab ? NULL : win_tp); // move to neighboring window if we're moving the current window to a new tabpage @@ -531,7 +531,7 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; if (parent == NULL) { - if (!win_split_ins(0, flags, win, 0)) { + if (!win_split_ins(0, flags, win, 0, NULL)) { // TODO(willothy): What should this error message say? api_set_error(err, kErrorTypeException, "Failed to split window"); return; @@ -542,7 +542,7 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) const int result = switch_win(&switchwin, parent, win_find_tabpage(parent), true); (void)result; assert(result == OK); - win_split_ins(0, flags, win, 0); + win_split_ins(0, flags, win, 0, NULL); restore_win(&switchwin, true); } if (HAS_KEY_X(config, width)) { diff --git a/src/nvim/window.c b/src/nvim/window.c index b1135d59fc..2d0010ad6c 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -981,16 +981,19 @@ int win_split(int size, int flags) clear_snapshot(curtab, SNAP_HELP_IDX); } - return win_split_ins(size, flags, NULL, 0) == NULL ? FAIL : OK; + return win_split_ins(size, flags, NULL, 0, NULL) == NULL ? FAIL : OK; } /// When "new_wp" is NULL: split the current window in two. /// When "new_wp" is not NULL: insert this window at the far /// top/left/right/bottom. +/// When "to_flatten" is not NULL: flatten this frame before reorganising frames; +/// remains unflattened on failure. +/// /// On failure, if "new_wp" was not NULL, no changes will have been made to the /// window layout or sizes. /// @return NULL for failure, or pointer to new window -win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) +win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_flatten) { win_T *wp = new_wp; @@ -1261,6 +1264,11 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) CLEAR_FIELD(wp->w_border_adj); } + // Going to reorganize frames now, make sure they're flat. + if (to_flatten != NULL) { + frame_flatten(to_flatten); + } + bool before; frame_T *curfrp; @@ -1915,38 +1923,29 @@ int win_splitmove(win_T *wp, int size, int flags) return FAIL; } - frame_T *frp = NULL; + frame_T *unflat_altfr = NULL; if (wp->w_floating) { win_remove(wp, NULL); } else { - // Undoing changes to frames if splitting fails is complicated. - // Save a full snapshot to restore instead. - frp = make_full_snapshot(); - - // Remove the window and frame from the tree of frames. - winframe_remove(wp, &dir, NULL); + // Remove the window and frame from the tree of frames. Don't flatten any + // frames yet so we can restore things if win_split_ins fails. + winframe_remove(wp, &dir, NULL, &unflat_altfr); win_remove(wp, NULL); last_status(false); // may need to remove last status line win_comp_pos(); // recompute window positions } // Split a window on the desired side and put "wp" there. - if (win_split_ins(size, flags, wp, dir) == NULL) { + if (win_split_ins(size, flags, wp, dir, unflat_altfr) == NULL) { win_append(wp->w_prev, wp); if (!wp->w_floating) { - // Restore the previous layout from the snapshot. - xfree(wp->w_frame); - restore_full_snapshot(frp); - - // Vertical separators to the left may have been lost. Restore them. - frp = wp->w_frame; - if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) { - frame_add_vsep(frp->fr_prev); - } + // win_split_ins doesn't change sizes or layout if it fails to insert an + // existing window, so just undo winframe_remove. + winframe_restore(wp, dir, unflat_altfr); + win_comp_pos(); // recompute window positions } return FAIL; } - clear_snapshot_rec(frp); // If splitting horizontally, try to preserve height. // Note that win_split_ins autocommands may have immediately made "wp" floating! @@ -3065,7 +3064,7 @@ static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp) if (!win->w_floating) { // Remove the window and its frame from the tree of frames. frame_T *frp = win->w_frame; - wp = winframe_remove(win, dirp, tp); + wp = winframe_remove(win, dirp, tp, NULL); xfree(frp); } else { *dirp = 'h'; // Dummy value. @@ -3146,9 +3145,11 @@ void win_free_all(void) /// /// @param dirp set to 'v' or 'h' for direction if 'ea' /// @param tp tab page "win" is in, NULL for current +/// @param unflat_altfr if not NULL, set to pointer of frame that got +/// the space, and it is not flattened /// /// @return a pointer to the window that got the freed up space. -win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) +win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_altfr) FUNC_ATTR_NONNULL_ARG(1, 2) { assert(tp == NULL || tp != curtab); @@ -3236,56 +3237,110 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) frame_comp_pos(frp2, &row, &col); } - if (frp2->fr_next == NULL && frp2->fr_prev == NULL) { - // There is no other frame in this list, move its info to the parent - // and remove it. - frp2->fr_parent->fr_layout = frp2->fr_layout; - frp2->fr_parent->fr_child = frp2->fr_child; - frame_T *frp; - FOR_ALL_FRAMES(frp, frp2->fr_child) { - frp->fr_parent = frp2->fr_parent; - } - frp2->fr_parent->fr_win = frp2->fr_win; - if (frp2->fr_win != NULL) { - frp2->fr_win->w_frame = frp2->fr_parent; + if (unflat_altfr == NULL) { + frame_flatten(frp2); + } else { + *unflat_altfr = frp2; + } + + return wp; +} + +/// Flatten "frp" into its parent frame if it's the only child, also merging its +/// list with the grandparent if they share the same layout. +/// Frees "frp" if flattened; also "frp->fr_parent" if it has the same layout. +/// "frp" must be valid in the current tabpage. +static void frame_flatten(frame_T *frp) + FUNC_ATTR_NONNULL_ALL +{ + if (frp->fr_next != NULL || frp->fr_prev != NULL) { + return; + } + + // There is no other frame in this list, move its info to the parent + // and remove it. + frp->fr_parent->fr_layout = frp->fr_layout; + frp->fr_parent->fr_child = frp->fr_child; + frame_T *frp2; + FOR_ALL_FRAMES(frp2, frp->fr_child) { + frp2->fr_parent = frp->fr_parent; + } + frp->fr_parent->fr_win = frp->fr_win; + if (frp->fr_win != NULL) { + frp->fr_win->w_frame = frp->fr_parent; + } + frp2 = frp->fr_parent; + if (topframe->fr_child == frp) { + topframe->fr_child = frp2; + } + xfree(frp); + + frp = frp2->fr_parent; + if (frp != NULL && frp->fr_layout == frp2->fr_layout) { + // The frame above the parent has the same layout, have to merge + // the frames into this list. + if (frp->fr_child == frp2) { + frp->fr_child = frp2->fr_child; + } + assert(frp2->fr_child); + frp2->fr_child->fr_prev = frp2->fr_prev; + if (frp2->fr_prev != NULL) { + frp2->fr_prev->fr_next = frp2->fr_child; + } + for (frame_T *frp3 = frp2->fr_child;; frp3 = frp3->fr_next) { + frp3->fr_parent = frp; + if (frp3->fr_next == NULL) { + frp3->fr_next = frp2->fr_next; + if (frp2->fr_next != NULL) { + frp2->fr_next->fr_prev = frp3; + } + break; + } } - frp = frp2->fr_parent; if (topframe->fr_child == frp2) { topframe->fr_child = frp; } xfree(frp2); + } +} - frp2 = frp->fr_parent; - if (frp2 != NULL && frp2->fr_layout == frp->fr_layout) { - // The frame above the parent has the same layout, have to merge - // the frames into this list. - if (frp2->fr_child == frp) { - frp2->fr_child = frp->fr_child; - } - assert(frp->fr_child); - frp->fr_child->fr_prev = frp->fr_prev; - if (frp->fr_prev != NULL) { - frp->fr_prev->fr_next = frp->fr_child; - } - frame_T *frp3; - for (frp3 = frp->fr_child;; frp3 = frp3->fr_next) { - frp3->fr_parent = frp2; - if (frp3->fr_next == NULL) { - frp3->fr_next = frp->fr_next; - if (frp->fr_next != NULL) { - frp->fr_next->fr_prev = frp3; - } - break; - } - } - if (topframe->fr_child == frp) { - topframe->fr_child = frp2; - } - xfree(frp); +/// Undo changes from a prior call to winframe_remove, also restoring lost +/// vertical separators and statuslines. +/// Caller must ensure no other changes were made to the layout or window sizes! +static void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) + FUNC_ATTR_NONNULL_ALL +{ + frame_T *frp = wp->w_frame; + + // Put "wp"'s frame back where it was. + if (frp->fr_prev != NULL) { + frame_append(frp->fr_prev, frp); + } else { + frame_insert(frp->fr_next, frp); + } + + // Vertical separators to the left may have been lost. Restore them. + if (wp->w_vsep_width == 0 && frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) { + frame_add_vsep(frp->fr_prev); + } + + // Statuslines or horizontal separators above may have been lost. Restore them. + if (frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL) { + if (global_stl_height() == 0 && wp->w_status_height == 0) { + frame_add_statusline(frp->fr_prev); + } else if (wp->w_hsep_height == 0) { + frame_add_hsep(frp->fr_prev); } } - return wp; + // Restore the lost room that was redistributed to the altframe. + if (dir == 'v') { + frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height, + unflat_altfr == frp->fr_next, false); + } else if (dir == 'h') { + frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width, + unflat_altfr == frp->fr_next, false); + } } /// If 'splitbelow' or 'splitright' is set, the space goes above or to the left @@ -7248,23 +7303,23 @@ void reset_lnums(void) void make_snapshot(int idx) { clear_snapshot(curtab, idx); - make_snapshot_rec(topframe, &curtab->tp_snapshot[idx], false); + make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]); } -static void make_snapshot_rec(frame_T *fr, frame_T **frp, bool snap_wins) +static void make_snapshot_rec(frame_T *fr, frame_T **frp) { *frp = xcalloc(1, sizeof(frame_T)); (*frp)->fr_layout = fr->fr_layout; (*frp)->fr_width = fr->fr_width; (*frp)->fr_height = fr->fr_height; if (fr->fr_next != NULL) { - make_snapshot_rec(fr->fr_next, &((*frp)->fr_next), snap_wins); + make_snapshot_rec(fr->fr_next, &((*frp)->fr_next)); } if (fr->fr_child != NULL) { - make_snapshot_rec(fr->fr_child, &((*frp)->fr_child), snap_wins); + make_snapshot_rec(fr->fr_child, &((*frp)->fr_child)); } - if (fr->fr_layout == FR_LEAF && (snap_wins || fr->fr_win == curwin)) { - (*frp)->fr_win = fr->fr_win; + if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin) { + (*frp)->fr_win = curwin; } } @@ -7381,80 +7436,6 @@ static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr) return wp; } -/// Return a snapshot of all frames in the current tabpage and which windows are -/// in them. -/// Use clear_snapshot_rec to free the snapshot. -static frame_T *make_full_snapshot(void) -{ - frame_T *frp; - make_snapshot_rec(topframe, &frp, true); - return frp; -} - -/// Restore all frames in the full snapshot "sn" for the current tabpage. -/// Caller must ensure that the screen size didn't change, no windows with frames -/// in the snapshot were freed, and windows with frames not in the snapshot are -/// removed from their frames! -/// Doesn't restore changed window vertical separators. -/// Frees the old frames. Don't call clear_snapshot_rec on "sn" afterwards! -static void restore_full_snapshot(frame_T *sn) -{ - if (sn == NULL) { - return; - } - - clear_snapshot_rec(topframe); - restore_full_snapshot_rec(sn); - curtab->tp_topframe = topframe = sn; - last_status(false); - - // If the amount of space available changed, first try setting the sizes of - // windows with 'winfix{width,height}'. If that doesn't result in the right - // size, forget about that option. - if (topframe->fr_width != Columns) { - frame_new_width(topframe, Columns, false, true); - if (!frame_check_width(topframe, Columns)) { - frame_new_width(topframe, Columns, false, false); - } - } - if (topframe->fr_height != ROWS_AVAIL) { - frame_new_height(topframe, (int)ROWS_AVAIL, false, true); - if (!frame_check_height(topframe, (int)ROWS_AVAIL)) { - frame_new_height(topframe, (int)ROWS_AVAIL, false, false); - } - } - - win_comp_pos(); -} - -static void restore_full_snapshot_rec(frame_T *sn) -{ - if (sn == NULL) { - return; - } - - if (sn->fr_child != NULL) { - sn->fr_child->fr_parent = sn; - } - if (sn->fr_next != NULL) { - sn->fr_next->fr_parent = sn->fr_parent; - sn->fr_next->fr_prev = sn; - } - if (sn->fr_win != NULL) { - sn->fr_win->w_frame = sn; - // Assume for now that all windows have statuslines, so last_status in restore_full_snapshot - // doesn't resize frames to fit any missing statuslines. - sn->fr_win->w_status_height = STATUS_HEIGHT; - sn->fr_win->w_hsep_height = 0; - - // Resize window to fit the frame. - frame_new_height(sn, sn->fr_height, false, false); - frame_new_width(sn, sn->fr_width, false, false); - } - restore_full_snapshot_rec(sn->fr_child); - restore_full_snapshot_rec(sn->fr_next); -} - /// Check that "topfrp" and its children are at the right height. /// /// @param topfrp top frame pointer diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 8fe0315230..cddc4ed9dd 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -57,7 +57,7 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) return NULL; } int dir; - winframe_remove(wp, &dir, NULL); + winframe_remove(wp, &dir, NULL, NULL); XFREE_CLEAR(wp->w_frame); win_comp_pos(); // recompute window positions win_remove(wp, NULL); -- cgit From 01b27410a347b90820d4255061944c31d20b8f33 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:11:40 +0000 Subject: vim-patch:9.1.0119: can move away from cmdwin using win_splitmove() Problem: can switch windows while textlocked via f_win_gotoid and f_win_splitmove (which also allows switching in the cmdwin). Solution: Check text_or_buf_locked in f_win_splitmove() (Sean Dewar) While at it, call text_or_buf_locked() in f_win_gotoid() instead of testing for cmdwin_type() (which text_buf_locked() does and in addition will also verify that the buffer is not locked). https://github.com/vim/vim/commit/f865895c874b0936b0563ebfef7490aac8cb8a1f --- src/nvim/eval/window.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 17b8b01963..d20fc3f2f2 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -14,6 +14,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/window.h" +#include "nvim/ex_getln.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" #include "nvim/gettext_defs.h" @@ -584,8 +585,7 @@ void f_win_gotoid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int id = (int)tv_get_number(&argvars[0]); - if (cmdwin_type != 0) { - emsg(_(e_cmdwin)); + if (text_or_buf_locked()) { return; } FOR_ALL_TAB_WINDOWS(tp, wp) { @@ -697,7 +697,7 @@ void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } // Check if we can split the target before we bother switching windows. - if (is_aucmd_win(wp) || check_split_disallowed(targetwin) == FAIL) { + if (is_aucmd_win(wp) || text_or_buf_locked() || check_split_disallowed(targetwin) == FAIL) { return; } -- cgit From b2245307f2acfd7b62cf5d0c5b199c87c2d37b23 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:15:30 +0000 Subject: vim-patch:9.1.0121: Infinite loop or signed overflow with 'smoothscroll' Problem: infinite loop in win_update with 'smoothscroll' set when window width is equal to textoff, or signed integer overflow if smaller. Solution: don't revalidate wp->w_skipcol in that case, as no buffer text is being shown. (Sean Dewar) https://github.com/vim/vim/commit/02fcae02a926e4e8379d77fb716da4202029882d Test_window_split_no_room changes were already cherry-picked earlier. --- src/nvim/drawscreen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 1626e46cf6..402f7fa428 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1513,7 +1513,7 @@ static void win_update(win_T *wp) // Make sure skipcol is valid, it depends on various options and the window // width. - if (wp->w_skipcol > 0) { + if (wp->w_skipcol > 0 && wp->w_width_inner > win_col_off(wp)) { int w = 0; int width1 = wp->w_width_inner - win_col_off(wp); int width2 = width1 + win_col_off2(wp); -- cgit From e3d4dfb6c3fcd22205f6843b96f9a043871113ce Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:22:55 +0000 Subject: vim-patch:9.1.0128: win_gotoid() may abort even when not switching a window Problem: win_gotoid() checks for textlock and other things when switching to a window that is already current (after v9.1.0119) Solution: return early with success when attempting to switch to curwin (Sean Dewar) https://github.com/vim/vim/commit/2a65e739447949a7aee966ce8a3b75521b2a79ea --- src/nvim/eval/window.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/nvim') diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index d20fc3f2f2..c2b9574579 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -584,6 +584,11 @@ void f_win_getid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) void f_win_gotoid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int id = (int)tv_get_number(&argvars[0]); + if (curwin->handle == id) { + // Nothing to do. + rettv->vval.v_number = 1; + return; + } if (text_or_buf_locked()) { return; -- cgit From 832bc5c169d8b339ef139ef0bdcefb2e72864e6e Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:30:37 +0000 Subject: vim-patch:9.1.0130: [security]: UAF if win_split_ins autocommands delete "wp" Problem: heap-use-after-free in win_splitmove if Enter/Leave autocommands from win_split_ins immediately closes "wp". Solution: check that "wp" is valid after win_split_ins. (Sean Dewar) https://github.com/vim/vim/commit/abf7030a5c22257f066fa9c4061ad150d5a82577 --- src/nvim/window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/window.c b/src/nvim/window.c index 2d0010ad6c..80cb9ab6a0 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -1948,8 +1948,8 @@ int win_splitmove(win_T *wp, int size, int flags) } // If splitting horizontally, try to preserve height. - // Note that win_split_ins autocommands may have immediately made "wp" floating! - if (size == 0 && !(flags & WSP_VERT) && !wp->w_floating) { + // Note that win_split_ins autocommands may have immediately closed "wp", or made it floating! + if (size == 0 && !(flags & WSP_VERT) && win_valid(wp) && !wp->w_floating) { win_setheight_win(height, wp); if (p_ea) { // Equalize windows. Note that win_split_ins autocommands may have -- cgit From d942c2b9432d81e4b509519bd48fa886e37e9ca8 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:51:31 +0000 Subject: fix(api): handle win_split_ins failure properly Problem: nvim_win_set_config does not handle failure in win_split_ins properly yet, which can cause all sorts of issues. Also nvim_open_win and nvim_win_set_config do not set the error message to the one from win_split_ins. Solution: handle failure by undoing winframe_remove, like in win_splitmove. Make sure autocommands from switching to the altwin fire within a valid window, and ensure they don't screw things up. Set the error message to that of win_split_ins, if any. Also change a few other small things, including: - adjust win_append to take a tabpage_T * argument, which is more consistent with win_remove (and also allows us to undo a call to win_remove). - allow winframe_restore to restore window positions. Useful if `wp` was in a different tabpage, as a call to win_comp_pos (which only works for the current tabpage) after winframe_restore should no longer be needed. Though enter_tabpage calls win_comp_pos anyway, this has the advantage of ensuring w_winrow/col remains accurate even before entering the tabpage (useful for stuff like win_screenpos, if used on a window in another tabpage). (This change should probably also be PR'd to Vim later, even though it doesn't use winframe_restore for a `wp` in a different tabpage yet). --- src/nvim/api/win_config.c | 147 +++++++++++++++++++++++++++++----------------- src/nvim/autocmd.c | 2 +- src/nvim/window.c | 128 ++++++++++++++++++++++++++++------------ src/nvim/winfloat.c | 2 +- 4 files changed, 184 insertions(+), 95 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 978d8515c8..bb28000719 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -259,18 +259,20 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err } int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; - if (parent == NULL) { - wp = win_split_ins(0, flags, NULL, 0, NULL); - } else { - tp = win_find_tabpage(parent); - switchwin_T switchwin; - // `parent` is valid in `tp`, so switch_win should not fail. - const int result = switch_win(&switchwin, parent, tp, true); - assert(result == OK); - (void)result; - wp = win_split_ins(0, flags, NULL, 0, NULL); - restore_win(&switchwin, true); - } + TRY_WRAP(err, { + if (parent == NULL || parent == curwin) { + wp = win_split_ins(0, flags, NULL, 0, NULL); + } else { + tp = win_find_tabpage(parent); + switchwin_T switchwin; + // `parent` is valid in `tp`, so switch_win should not fail. + const int result = switch_win(&switchwin, parent, tp, true); + assert(result == OK); + (void)result; + wp = win_split_ins(0, flags, NULL, 0, NULL); + restore_win(&switchwin, true); + } + }); if (wp) { wp->w_config = fconfig; } @@ -278,7 +280,9 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err wp = win_new_float(NULL, false, fconfig, err); } if (!wp) { - api_set_error(err, kErrorTypeException, "Failed to create window"); + if (!ERROR_SET(err)) { + api_set_error(err, kErrorTypeException, "Failed to create window"); + } return 0; } @@ -448,17 +452,47 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) return; // error already set } - if (was_split) { - win_T *new_curwin = NULL; + bool to_split_ok = false; + // If we are moving curwin to another tabpage, switch windows *before* we remove it from the + // window list or remove its frame (if non-floating), so it's valid for autocommands. + const bool curwin_moving_tp + = win == curwin && parent != NULL && win_tp != win_find_tabpage(parent); + if (curwin_moving_tp) { + if (was_split) { + int dir; + win_goto(winframe_find_altwin(win, &dir, NULL, NULL)); + } else { + win_goto(win_valid(prevwin) && prevwin != win ? prevwin : firstwin); + } + // Autocommands may have been a real nuisance and messed things up... + if (curwin == win) { + api_set_error(err, kErrorTypeException, "Failed to switch away from window %d", + win->handle); + return; + } + win_tp = win_find_tabpage(win); + if (!win_tp || !win_valid_any_tab(parent)) { + api_set_error(err, kErrorTypeException, "Windows to split were closed"); + goto restore_curwin; + } + if (was_split == win->w_floating || parent->w_floating) { + api_set_error(err, kErrorTypeException, "Floating state of windows to split changed"); + goto restore_curwin; + } + } + + int dir = 0; + frame_T *unflat_altfr = NULL; + if (was_split) { // If the window is the last in the tabpage or `fconfig.win` is // a handle to itself, we can't split it. if (win->w_frame->fr_parent == NULL) { // FIXME(willothy): if the window is the last in the tabpage but there is another tabpage // and the target window is in that other tabpage, should we move the window to that // tabpage and close the previous one, or just error? - api_set_error(err, kErrorTypeValidation, "Cannot move last window"); - return; + api_set_error(err, kErrorTypeException, "Cannot move last window"); + goto restore_curwin; } else if (parent != NULL && parent->handle == win->handle) { int n_frames = 0; for (frame_T *fr = win->w_frame->fr_parent->fr_child; fr != NULL; fr = fr->fr_next) { @@ -494,64 +528,67 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) } // If the frame doesn't have a parent, the old frame // was the root frame and we need to create a top-level split. - int dir; - new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL); + winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); } else if (n_frames == 2) { // There are two windows in the frame, we can just rotate it. - int dir; - neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL); - new_curwin = neighbor; + neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); } else { // There is only one window in the frame, we can't split it. - api_set_error(err, kErrorTypeValidation, "Cannot split window into itself"); - return; + api_set_error(err, kErrorTypeException, "Cannot split window into itself"); + goto restore_curwin; } - // Set the parent to whatever the correct - // neighbor window was determined to be. + // Set the parent to whatever the correct neighbor window was determined to be. parent = neighbor; } else { - int dir; - new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL); - } - win_remove(win, win_tp == curtab ? NULL : win_tp); - // move to neighboring window if we're moving the current window to a new tabpage - if (curwin == win && parent != NULL && new_curwin != NULL - && win_tp != win_find_tabpage(parent)) { - win_enter(new_curwin, true); - if (!win_valid_any_tab(parent)) { - // win_enter autocommands closed the `parent` to split from. - api_set_error(err, kErrorTypeException, "Window to split was closed"); - return; - } + winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); } - } else { - win_remove(win, win_tp == curtab ? NULL : win_tp); } + win_remove(win, win_tp == curtab ? NULL : win_tp); int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; + TRY_WRAP(err, { + const bool need_switch = parent != NULL && parent != curwin; + switchwin_T switchwin; + if (need_switch) { + // `parent` is valid in its tabpage, so switch_win should not fail. + const int result = switch_win(&switchwin, parent, win_find_tabpage(parent), true); + (void)result; + assert(result == OK); + } + to_split_ok = win_split_ins(0, flags, win, 0, unflat_altfr) != NULL; + if (!to_split_ok) { + // Restore `win` to the window list now, so it's valid for restore_win (if used). + win_append(win->w_prev, win, win_tp == curtab ? NULL : win_tp); + } + if (need_switch) { + restore_win(&switchwin, true); + } + }); + if (!to_split_ok) { + if (was_split) { + // win_split_ins doesn't change sizes or layout if it fails to insert an existing window, so + // just undo winframe_remove. + winframe_restore(win, dir, unflat_altfr); + } + if (!ERROR_SET(err)) { + api_set_error(err, kErrorTypeException, "Failed to move window %d into split", win->handle); + } - if (parent == NULL) { - if (!win_split_ins(0, flags, win, 0, NULL)) { - // TODO(willothy): What should this error message say? - api_set_error(err, kErrorTypeException, "Failed to split window"); - return; +restore_curwin: + // If `win` was the original curwin, and autocommands didn't move it outside of curtab, be a + // good citizen and try to return to it. + if (curwin_moving_tp && win_valid(win)) { + win_goto(win); } - } else { - switchwin_T switchwin; - // `parent` is valid in its tabpage, so switch_win should not fail. - const int result = switch_win(&switchwin, parent, win_find_tabpage(parent), true); - (void)result; - assert(result == OK); - win_split_ins(0, flags, win, 0, NULL); - restore_win(&switchwin, true); + return; } + if (HAS_KEY_X(config, width)) { win_setwidth_win(fconfig.width, win); } if (HAS_KEY_X(config, height)) { win_setheight_win(fconfig.height, win); } - return; } else { win_config_float(win, fconfig); win->w_pos_changed = true; diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 3f93906942..652b6ba74e 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1333,7 +1333,7 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) block_autocmds(); // We don't want BufEnter/WinEnter autocommands. if (need_append) { - win_append(lastwin, auc_win); + win_append(lastwin, auc_win, NULL); pmap_put(int)(&window_handles, auc_win->handle, auc_win); win_config_float(auc_win, auc_win->w_config); } diff --git a/src/nvim/window.c b/src/nvim/window.c index 80cb9ab6a0..b55dd79260 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -1218,13 +1218,13 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl if (new_wp == NULL) { wp = win_alloc(oldwin, false); } else { - win_append(oldwin, wp); + win_append(oldwin, wp, NULL); } } else { if (new_wp == NULL) { wp = win_alloc(oldwin->w_prev, false); } else { - win_append(oldwin->w_prev, wp); + win_append(oldwin->w_prev, wp, NULL); } } @@ -1783,13 +1783,13 @@ static void win_exchange(int Prenum) if (wp->w_prev != curwin) { win_remove(curwin, NULL); frame_remove(curwin->w_frame); - win_append(wp->w_prev, curwin); + win_append(wp->w_prev, curwin, NULL); frame_insert(frp, curwin->w_frame); } if (wp != wp2) { win_remove(wp, NULL); frame_remove(wp->w_frame); - win_append(wp2, wp); + win_append(wp2, wp, NULL); if (frp2 == NULL) { frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame); } else { @@ -1863,7 +1863,7 @@ static void win_rotate(bool upwards, int count) // find last frame and append removed window/frame after it for (; frp->fr_next != NULL; frp = frp->fr_next) {} - win_append(frp->fr_win, wp1); + win_append(frp->fr_win, wp1, NULL); frame_append(frp, wp1->w_frame); wp2 = frp->fr_win; // previously last window @@ -1878,7 +1878,7 @@ static void win_rotate(bool upwards, int count) assert(frp->fr_parent->fr_child); // append the removed window/frame before the first in the list - win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1); + win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1, NULL); frame_insert(frp->fr_parent->fr_child, frp); } @@ -1937,7 +1937,7 @@ int win_splitmove(win_T *wp, int size, int flags) // Split a window on the desired side and put "wp" there. if (win_split_ins(size, flags, wp, dir, unflat_altfr) == NULL) { - win_append(wp->w_prev, wp); + win_append(wp->w_prev, wp, NULL); if (!wp->w_floating) { // win_split_ins doesn't change sizes or layout if it fails to insert an // existing window, so just undo winframe_remove. @@ -2016,7 +2016,7 @@ void win_move_after(win_T *win1, win_T *win2) } win_remove(win1, NULL); frame_remove(win1->w_frame); - win_append(win2, win1); + win_append(win2, win1, NULL); frame_append(win2->w_frame, win1->w_frame); win_comp_pos(); // recompute w_winrow for all windows @@ -3151,6 +3151,55 @@ void win_free_all(void) /// @return a pointer to the window that got the freed up space. win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_altfr) FUNC_ATTR_NONNULL_ARG(1, 2) +{ + frame_T *altfr; + win_T *wp = winframe_find_altwin(win, dirp, tp, &altfr); + if (wp == NULL) { + return NULL; + } + + frame_T *frp_close = win->w_frame; + // Remove this frame from the list of frames. + frame_remove(frp_close); + + if (*dirp == 'v') { + frame_new_height(altfr, altfr->fr_height + frp_close->fr_height, + altfr == frp_close->fr_next, false); + } else { + assert(*dirp == 'h'); + frame_new_width(altfr, altfr->fr_width + frp_close->fr_width, + altfr == frp_close->fr_next, false); + } + + // If rows/columns go to a window below/right its positions need to be + // updated. Can only be done after the sizes have been updated. + if (altfr == frp_close->fr_next) { + int row = win->w_winrow; + int col = win->w_wincol; + + frame_comp_pos(altfr, &row, &col); + } + + if (unflat_altfr == NULL) { + frame_flatten(altfr); + } else { + *unflat_altfr = altfr; + } + + return wp; +} + +/// Find the window that will get the freed space from a call to `winframe_remove`. +/// Makes no changes to the window layout. +/// +/// @param dirp set to 'v' or 'h' for the direction where "altfr" will be resized +/// to fill the space +/// @param tp tab page "win" is in, NULL for current +/// @param altfr if not NULL, set to pointer of frame that will get the space +/// +/// @return a pointer to the window that will get the freed up space. +win_T *winframe_find_altwin(win_T *win, int *dirp, tabpage_T *tp, frame_T **altfr) + FUNC_ATTR_NONNULL_ARG(1, 2) { assert(tp == NULL || tp != curtab); @@ -3161,13 +3210,10 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al frame_T *frp_close = win->w_frame; - // Remove the window from its frame. + // Find the window and frame that gets the space. frame_T *frp2 = win_altframe(win, tp); win_T *wp = frame2win(frp2); - // Remove this frame from the list of frames. - frame_remove(frp_close); - if (frp_close->fr_parent->fr_layout == FR_COL) { // When 'winfixheight' is set, try to find another frame in the column // (as close to the closed frame as possible) to distribute the height @@ -3194,8 +3240,6 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al } } } - frame_new_height(frp2, frp2->fr_height + frp_close->fr_height, - frp2 == frp_close->fr_next, false); *dirp = 'v'; } else { // When 'winfixwidth' is set, try to find another frame in the column @@ -3223,24 +3267,12 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al } } } - frame_new_width(frp2, frp2->fr_width + frp_close->fr_width, - frp2 == frp_close->fr_next, false); *dirp = 'h'; } - // If rows/columns go to a window below/right its positions need to be - // updated. Can only be done after the sizes have been updated. - if (frp2 == frp_close->fr_next) { - int row = win->w_winrow; - int col = win->w_wincol; - - frame_comp_pos(frp2, &row, &col); - } - - if (unflat_altfr == NULL) { - frame_flatten(frp2); - } else { - *unflat_altfr = frp2; + assert(wp != win && frp2 != frp_close); + if (altfr != NULL) { + *altfr = frp2; } return wp; @@ -3305,9 +3337,10 @@ static void frame_flatten(frame_T *frp) } /// Undo changes from a prior call to winframe_remove, also restoring lost -/// vertical separators and statuslines. +/// vertical separators and statuslines, and changed window positions for +/// windows within "unflat_altfr". /// Caller must ensure no other changes were made to the layout or window sizes! -static void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) +void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) FUNC_ATTR_NONNULL_ALL { frame_T *frp = wp->w_frame; @@ -3333,13 +3366,24 @@ static void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) } } + int row = wp->w_winrow; + int col = wp->w_wincol; + // Restore the lost room that was redistributed to the altframe. if (dir == 'v') { frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height, unflat_altfr == frp->fr_next, false); + row += frp->fr_height; } else if (dir == 'h') { frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width, unflat_altfr == frp->fr_next, false); + col += frp->fr_width; + } + + // If rows/columns went to a window below/right, its positions need to be + // restored. Can only be done after the sizes have been updated. + if (unflat_altfr == frp->fr_next) { + frame_comp_pos(unflat_altfr, &row, &col); } } @@ -4445,7 +4489,7 @@ static void tabpage_check_windows(tabpage_T *old_curtab) if (wp->w_floating) { if (wp->w_config.external) { win_remove(wp, old_curtab); - win_append(lastwin_nofloating(), wp); + win_append(lastwin_nofloating(), wp, NULL); } else { ui_comp_remove_grid(&wp->w_grid_alloc); } @@ -5085,7 +5129,7 @@ win_T *win_alloc(win_T *after, bool hidden) block_autocmds(); // link the window in the window list if (!hidden) { - win_append(after, new_wp); + win_append(after, new_wp, NULL); } new_wp->w_wincol = 0; @@ -5255,21 +5299,29 @@ void win_free_grid(win_T *wp, bool reinit) } } -// Append window "wp" in the window list after window "after". -void win_append(win_T *after, win_T *wp) +/// Append window "wp" in the window list after window "after". +/// +/// @param tp tab page "win" (and "after", if not NULL) is in, NULL for current +void win_append(win_T *after, win_T *wp, tabpage_T *tp) + FUNC_ATTR_NONNULL_ARG(2) { + assert(tp == NULL || tp != curtab); + + win_T **first = tp == NULL ? &firstwin : &tp->tp_firstwin; + win_T **last = tp == NULL ? &lastwin : &tp->tp_lastwin; + // after NULL is in front of the first - win_T *before = after == NULL ? firstwin : after->w_next; + win_T *before = after == NULL ? *first : after->w_next; wp->w_next = before; wp->w_prev = after; if (after == NULL) { - firstwin = wp; + *first = wp; } else { after->w_next = wp; } if (before == NULL) { - lastwin = wp; + *last = wp; } else { before->w_prev = wp; } diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index cddc4ed9dd..10d8c7ac90 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -61,7 +61,7 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) XFREE_CLEAR(wp->w_frame); win_comp_pos(); // recompute window positions win_remove(wp, NULL); - win_append(lastwin_nofloating(), wp); + win_append(lastwin_nofloating(), wp, NULL); } wp->w_floating = true; wp->w_status_height = 0; -- cgit From e7c262f5553c1c6e1de95bcbdc8cfe7cc9d5e55e Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 27 Feb 2024 13:25:44 +0000 Subject: fix(api): patch some cmdwin/textlock holes Problem: there are new ways to escape textlock or break the cmdwin in nvim_win_set_config and nvim_tabpage_set_win. Solution: fix them. Use win_goto to check it in nvim_tabpage_set_win and use the try_start/end pattern like with similar functions such as nvim_set_current_win (which uses the existing msg_list, if set). Careful not to use `wp->handle` when printing the window ID in the error message for nvim_tabpage_set_win, as win_goto autocommands may have freed the window. On a related note, I have a feeling some API functions ought to be checking curbuf_locked... --- src/nvim/api/tabpage.c | 6 +++++- src/nvim/api/win_config.c | 6 ++++++ src/nvim/winfloat.c | 13 +++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index 040abb1e3f..56a3f1cf23 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -146,7 +146,11 @@ void nvim_tabpage_set_win(Tabpage tabpage, Window win, Error *err) } if (tp == curtab) { - win_enter(wp, true); + try_start(); + win_goto(wp); + if (!try_end(err) && curwin != wp) { + api_set_error(err, kErrorTypeException, "Failed to switch to window %d", win); + } } else if (tp->tp_curwin != wp) { tp->tp_prevwin = tp->tp_curwin; tp->tp_curwin = wp; diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index bb28000719..dab1e4e80b 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -451,6 +451,12 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) if (!check_split_disallowed_err(win, err)) { return; // error already set } + // Can't move the cmdwin or its old curwin to a different tabpage. + if ((win == cmdwin_win || win == cmdwin_old_curwin) && parent != NULL + && win_find_tabpage(parent) != win_tp) { + api_set_error(err, kErrorTypeException, "%s", e_cmdwin); + return; + } bool to_split_ok = false; // If we are moving curwin to another tabpage, switch windows *before* we remove it from the diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 10d8c7ac90..3ddff8aa5a 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -55,6 +55,19 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) api_set_error(err, kErrorTypeException, "Cannot change window from different tabpage into float"); return NULL; + } else if (cmdwin_win != NULL && !cmdwin_win->w_floating) { + // cmdwin can't become the only non-float. Check for others. + bool other_nonfloat = false; + for (win_T *wp2 = firstwin; wp2 != NULL && !wp2->w_floating; wp2 = wp2->w_next) { + if (wp2 != wp && wp2 != cmdwin_win) { + other_nonfloat = true; + break; + } + } + if (!other_nonfloat) { + api_set_error(err, kErrorTypeException, "%s", e_cmdwin); + return NULL; + } } int dir; winframe_remove(wp, &dir, NULL, NULL); -- cgit From 54022a2946aca5de991e7fa1ebc2954340ec20a8 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sat, 9 Mar 2024 01:00:33 +0000 Subject: fix(api): win_set_config update statuslines after removing splits Problem: nvim_win_set_config does not update statuslines after removing a split. Solution: call last_status. Didn't realize this was missing in the original nvim_win_set_config for splits PR. As it can only be done for the current tabpage, do it if win_tp == curtab; enter_tabpage will eventually call last_status anyway when the user enters another tabpage. --- src/nvim/api/win_config.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index dab1e4e80b..32b2156313 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -550,6 +550,10 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) } } win_remove(win, win_tp == curtab ? NULL : win_tp); + if (win_tp == curtab) { + last_status(false); // may need to remove last status line + win_comp_pos(); // recompute window positions + } int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; TRY_WRAP(err, { -- cgit From 33dfb5a383d7afacda35b8fd392ad18d57db2870 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 9 Mar 2024 12:47:40 +0800 Subject: fix(window): :close may cause Nvim to quit with autocmd and float Problem: :close may cause Nvim to quit if an autocommand triggered when closing the buffer closes all other non-floating windows and there are floating windows. Solution: Correct the check for the only non-floating window. --- src/nvim/buffer.c | 4 ++-- src/nvim/window.c | 46 +++++++++++----------------------------------- 2 files changed, 13 insertions(+), 37 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index b013f43ceb..7154be36be 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -568,7 +568,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i } buf->b_locked--; buf->b_locked_split--; - if (abort_if_last && last_nonfloat(win)) { + if (abort_if_last && one_window(win)) { // Autocommands made this the only window. emsg(_(e_auabort)); return false; @@ -587,7 +587,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i } buf->b_locked--; buf->b_locked_split--; - if (abort_if_last && last_nonfloat(win)) { + if (abort_if_last && one_window(win)) { // Autocommands made this the only window. emsg(_(e_auabort)); return false; diff --git a/src/nvim/window.c b/src/nvim/window.c index b55dd79260..4dc6ed370e 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -455,7 +455,7 @@ newwindow: case 'H': case 'L': CHECK_CMDWIN; - if (firstwin == curwin && lastwin_nofloating() == curwin) { + if (one_window(curwin)) { beep_flush(); } else { const int dir = ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0) @@ -1018,7 +1018,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl bool toplevel = flags & (WSP_TOP | WSP_BOT); // add a status line when p_ls == 1 and splitting the first window - if (one_nonfloat() && p_ls == 1 && oldwin->w_status_height == 0) { + if (one_window(firstwin) && p_ls == 1 && oldwin->w_status_height == 0) { if (oldwin->w_height <= p_wmh) { emsg(_(e_noroom)); return NULL; @@ -1741,7 +1741,7 @@ static void win_exchange(int Prenum) return; } - if (firstwin == curwin && lastwin_nofloating() == curwin) { + if (one_window(curwin)) { // just one window beep_flush(); return; @@ -1833,7 +1833,7 @@ static void win_rotate(bool upwards, int count) return; } - if (count <= 0 || (firstwin == curwin && lastwin_nofloating() == curwin)) { + if (count <= 0 || one_window(curwin)) { // nothing to do beep_flush(); return; @@ -2495,37 +2495,13 @@ bool last_window(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT } /// Check if "win" is the only non-floating window in the current tabpage. -bool one_window(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (win->w_floating) { - return false; - } - - bool seen_one = false; - - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (!wp->w_floating) { - if (seen_one) { - return false; - } - seen_one = true; - } - } - return true; -} - -/// Like ONE_WINDOW but only considers non-floating windows -bool one_nonfloat(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT -{ - return firstwin->w_next == NULL || firstwin->w_next->w_floating; -} - -/// if wp is the last non-floating window /// -/// always false for a floating window -bool last_nonfloat(win_T *wp) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +/// This should be used in place of ONE_WINDOW when necessary, +/// with "firstwin" or the affected window as argument depending on the situation. +bool one_window(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return wp != NULL && firstwin == wp && !(wp->w_next && !wp->w_floating); + assert(!firstwin->w_floating); + return firstwin == win && (win->w_next == NULL || win->w_next->w_floating); } /// Check if floating windows in the current tab can be closed. @@ -3950,7 +3926,7 @@ void close_others(int message, int forceit) return; } - if (one_nonfloat() && !lastwin->w_floating) { + if (one_window(firstwin) && !lastwin->w_floating) { if (message && !autocmd_busy) { msg(_(m_onlyone), 0); @@ -7224,7 +7200,7 @@ int global_stl_height(void) /// @param morewin pretend there are two or more windows if true. int last_stl_height(bool morewin) { - return (p_ls > 1 || (p_ls == 1 && (morewin || !one_nonfloat()))) ? STATUS_HEIGHT : 0; + return (p_ls > 1 || (p_ls == 1 && (morewin || !one_window(firstwin)))) ? STATUS_HEIGHT : 0; } /// Return the minimal number of rows that is needed on the screen to display -- cgit From b52d15853e89149472c1ecd9cce3a84e4af0785a Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sat, 9 Mar 2024 16:56:32 +0000 Subject: fix(api): win_set_config set tp_curwin of win moved from other tabpage Problem: nvim_win_set_config does not update the tp_curwin of win's original tabpage when moving it to another. Solution: update it if win was the tp_curwin. Add a test. --- src/nvim/api/win_config.c | 23 ++++++++++++++++++----- src/nvim/window.c | 15 +-------------- src/nvim/winfloat.c | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 19 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 32b2156313..8b8eca62ca 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -468,7 +468,7 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) int dir; win_goto(winframe_find_altwin(win, &dir, NULL, NULL)); } else { - win_goto(win_valid(prevwin) && prevwin != win ? prevwin : firstwin); + win_goto(win_float_find_altwin(win, NULL)); } // Autocommands may have been a real nuisance and messed things up... @@ -490,6 +490,8 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) int dir = 0; frame_T *unflat_altfr = NULL; + win_T *altwin = NULL; + if (was_split) { // If the window is the last in the tabpage or `fconfig.win` is // a handle to itself, we can't split it. @@ -534,10 +536,11 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) } // If the frame doesn't have a parent, the old frame // was the root frame and we need to create a top-level split. - winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); + altwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); } else if (n_frames == 2) { // There are two windows in the frame, we can just rotate it. - neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); + altwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); + neighbor = altwin; } else { // There is only one window in the frame, we can't split it. api_set_error(err, kErrorTypeException, "Cannot split window into itself"); @@ -546,9 +549,12 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) // Set the parent to whatever the correct neighbor window was determined to be. parent = neighbor; } else { - winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); + altwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); } + } else { + altwin = win_float_find_altwin(win, win_tp == curtab ? NULL : win_tp); } + win_remove(win, win_tp == curtab ? NULL : win_tp); if (win_tp == curtab) { last_status(false); // may need to remove last status line @@ -556,12 +562,14 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) } int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; + tabpage_T *const parent_tp = parent ? win_find_tabpage(parent) : curtab; + TRY_WRAP(err, { const bool need_switch = parent != NULL && parent != curwin; switchwin_T switchwin; if (need_switch) { // `parent` is valid in its tabpage, so switch_win should not fail. - const int result = switch_win(&switchwin, parent, win_find_tabpage(parent), true); + const int result = switch_win(&switchwin, parent, parent_tp, true); (void)result; assert(result == OK); } @@ -593,6 +601,11 @@ restore_curwin: return; } + // If `win` moved tabpages and was the curwin of its old one, select a new curwin for it. + if (win_tp != parent_tp && win_tp->tp_curwin == win) { + win_tp->tp_curwin = altwin; + } + if (HAS_KEY_X(config, width)) { win_setwidth_win(fconfig.width, win); } diff --git a/src/nvim/window.c b/src/nvim/window.c index 4dc6ed370e..ecd2e83500 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3044,20 +3044,7 @@ static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp) xfree(frp); } else { *dirp = 'h'; // Dummy value. - if (tp == NULL) { - if (win_valid(prevwin) && prevwin != win) { - wp = prevwin; - } else { - wp = firstwin; - } - } else { - assert(tp != curtab); - if (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) { - wp = tp->tp_prevwin; - } else { - wp = tp->tp_firstwin; - } - } + wp = win_float_find_altwin(win, tp); } win_free(win, tp); diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 3ddff8aa5a..65d2c1306b 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -319,3 +319,21 @@ win_T *win_float_find_preview(void) } return NULL; } + +/// Select an alternative window to `win` (assumed floating) in tabpage `tp`. +/// +/// Useful for finding a window to switch to if `win` is the current window, but is then closed or +/// moved to a different tabpage. +/// +/// @param tp `win`'s original tabpage, or NULL for current. +win_T *win_float_find_altwin(const win_T *win, const tabpage_T *tp) + FUNC_ATTR_NONNULL_ARG(1) +{ + if (tp == NULL) { + return (win_valid(prevwin) && prevwin != win) ? prevwin : firstwin; + } + + assert(tp != curtab); + return (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) ? tp->tp_prevwin + : tp->tp_firstwin; +} -- cgit From c3d22d32ee4b4c1911ec15f2a77683d09b09f845 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sat, 9 Mar 2024 20:24:08 +0000 Subject: vim-patch:8.2.3862: crash on exit with EXITFREE and using win_execute() Problem: Crash on exit with EXITFREE and using win_execute(). Solution: Also save and restore tp_topframe. (issue vim/vim#9374) https://github.com/vim/vim/commit/dab17a0689a2f31f69f428975f84b0c3c7ba3030 Couldn't repro the crash in the test, but I only care about this patch so switch_win sets topframe properly for win_split_ins in nvim_open_win and nvim_win_set_config. Add a test using nvim_win_call and :wincmd, as I couldn't repro the issue via nvim_open_win or nvim_win_set_config (though it's clear they're affected by this patch). That said, at that point, could just use {un}use_tabpage inside switch_win instead, which also updates tp_curwin (though maybe continue to not set it in restore_win). That would also fix possible inconsistent behaviour such as: :call win_execute(w, "let curwin_nr1 = tabpagewinnr(1)") :let curwin_nr2 = tabpagewinnr(1) Where it's possible for curwin_nr1 != curwin_nr2 if these commands are run from the 1st tabpage, but window "w" is in the 2nd (as the 1st tabpage's tp_curwin may still be invalid). I'll probably PR a fix for that later in Vim. Co-authored-by: Bram Moolenaar --- src/nvim/eval/window.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/nvim') diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index c2b9574579..e54f46dcc3 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -958,9 +958,11 @@ int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool n if (no_display) { curtab->tp_firstwin = firstwin; curtab->tp_lastwin = lastwin; + curtab->tp_topframe = topframe; curtab = tp; firstwin = curtab->tp_firstwin; lastwin = curtab->tp_lastwin; + topframe = curtab->tp_topframe; } else { goto_tabpage_tp(tp, false, false); } @@ -989,9 +991,11 @@ void restore_win_noblock(switchwin_T *switchwin, bool no_display) if (no_display) { curtab->tp_firstwin = firstwin; curtab->tp_lastwin = lastwin; + curtab->tp_topframe = topframe; curtab = switchwin->sw_curtab; firstwin = curtab->tp_firstwin; lastwin = curtab->tp_lastwin; + topframe = curtab->tp_topframe; } else { goto_tabpage_tp(switchwin->sw_curtab, false, false); } -- cgit From 241c16129919e169b71ef1e788420224b358fbb3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Mar 2024 06:47:09 +0800 Subject: vim-patch:9.1.0161: expand() removes slash after env variable that ends with colon (#27791) Problem: expand() removes a slash after an environment variable that ends with a colon on Windows. Solution: Check the correct char for a colon (zeertzjq) closes: vim/vim#14161 Note: Vim still removes the path-separator at the end, if another path separator follows directly after it, e.g. on: ``` echo $FOO='/usr/' echo expand('$FOO/bar') == '/usr/bar' ``` see: ,----[ misc1.c:1630 ] | // if var[] ends in a path separator and tail[] starts | // with it, skip a character | if (after_pathsep(dst, dst + c) | #if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) | && (dst == save_dst || dst[-1] != ':') | #endif | && vim_ispathsep(*tail)) | ++tail; `---- https://github.com/vim/vim/commit/13a014452a7a020a119ac555a690c65b41f3126d Cherry-pick test_expand.vim change from patch 9.0.1257. --- src/nvim/os/env.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 5b1cb01976..8a81f6e928 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -586,9 +586,6 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es bool copy_char; bool mustfree; // var was allocated, need to free it later bool at_start = true; // at start of a name -#if defined(BACKSLASH_IN_FILENAME) - char *const save_dst = dst; -#endif int prefix_len = (prefix == NULL) ? 0 : (int)strlen(prefix); @@ -729,7 +726,7 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es // with it, skip a character if (after_pathsep(dst, dst + c) #if defined(BACKSLASH_IN_FILENAME) - && (dst == save_dst || dst[-1] != ':') + && dst[c - 1] != ':' #endif && vim_ispathsep(*tail)) { tail++; -- cgit From 448cf10c47e0678cee080baaf75f395511e13269 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Mar 2024 07:03:36 +0800 Subject: vim-patch:9.1.0159: Crash in WinClosed after BufUnload closes other windows (#27792) Problem: Crash in WinClosed after BufUnload closes other windows Solution: Don't trigger WinClosed if the buffer is NULL (zeertzjq) Now win_close_othertab() doesn't trigger any autocommands if the buffer is NULL, so remove the autocmd blocking above (which was added not long ago in patch v9.0.0550) for consistency. Also remove an unreachable close_last_window_tabpage() above: - It is only reached if only_one_window() returns TRUE and last_window() returns FALSE. - If only_one_window() returns TRUE, there is only one tabpage. - If there is only one tabpage and last_window() returns FALSE, the one_window() in last_window() must return FALSE, and the ONE_WINDOW in close_last_window_tabpage() must also be FALSE. - So close_last_window_tabpage() doesn't do anything and returns FALSE. Then the curtab != prev_curtab check also doesn't make much sense, and the only_one_window() can be replaced with a check for popup and a call to last_window() since this is a stricter check than only_one_window(). closes: vim/vim#14166 https://github.com/vim/vim/commit/b2ec0da080fb24f12a8d6f54bd7318a078ca4e6c --- src/nvim/window.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/window.c b/src/nvim/window.c index ecd2e83500..6c7ca86636 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2546,7 +2546,7 @@ bool can_close_in_cmdwin(win_T *win, Error *err) /// @param prev_curtab previous tabpage that will be closed if "win" is the /// last window in the tabpage /// -/// @return true when the window was closed already. +/// @return false if there are other windows and nothing is done, true otherwise. static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev_curtab) FUNC_ATTR_NONNULL_ARG(1) { @@ -2751,10 +2751,8 @@ int win_close(win_T *win, bool free_buf, bool force) win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, true); - if (only_one_window() && win_valid(win) && win->w_buffer == NULL - && (last_window(win) || curtab != prev_curtab - || close_last_window_tabpage(win, free_buf, prev_curtab)) - && !win->w_floating) { + if (win_valid(win) && win->w_buffer == NULL + && !win->w_floating && last_window(win)) { // Autocommands have closed all windows, quit now. Restore // curwin->w_buffer, otherwise writing ShaDa file may fail. if (curwin->w_buffer == NULL) { @@ -2766,10 +2764,7 @@ int win_close(win_T *win, bool free_buf, bool force) if (curtab != prev_curtab && win_valid_any_tab(win) && win->w_buffer == NULL) { // Need to close the window anyway, since the buffer is NULL. - // Don't trigger autocmds with a NULL buffer. - block_autocmds(); win_close_othertab(win, false, prev_curtab); - unblock_autocmds(); return FAIL; } @@ -2940,10 +2935,14 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) } // Fire WinClosed just before starting to free window-related resources. - do_autocmd_winclosed(win); - // autocmd may have freed the window already. - if (!win_valid_any_tab(win)) { - return; + // If the buffer is NULL, it isn't safe to trigger autocommands, + // and win_close() should have already triggered WinClosed. + if (win->w_buffer != NULL) { + do_autocmd_winclosed(win); + // autocmd may have freed the window already. + if (!win_valid_any_tab(win)) { + return; + } } if (win->w_buffer != NULL) { -- cgit From 731e7f51ee40778b5baeec99aaf1d551b0855667 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Mar 2024 07:55:04 +0800 Subject: fix(window): :close crash with autocmd, floats and tabpage (#27793) Problem: :close crash with autocmd, floats and tabpage. Solution: Close floating windows in one more case. --- src/nvim/window.c | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/window.c b/src/nvim/window.c index 6c7ca86636..c0a9b1e39b 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -1916,7 +1916,7 @@ int win_splitmove(win_T *wp, int size, int flags) int dir = 0; int height = wp->w_height; - if (firstwin == wp && lastwin_nofloating() == wp) { + if (one_window(wp)) { return OK; // nothing to do } if (is_aucmd_win(wp) || check_split_disallowed(wp) == FAIL) { @@ -2539,21 +2539,42 @@ bool can_close_in_cmdwin(win_T *win, Error *err) return true; } -/// Close the possibly last window in a tab page. +/// Close the possibly last non-floating window in a tab page. /// /// @param win window to close /// @param free_buf whether to free the window's current buffer +/// @param force close floating windows even if they are modified /// @param prev_curtab previous tabpage that will be closed if "win" is the /// last window in the tabpage /// -/// @return false if there are other windows and nothing is done, true otherwise. -static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev_curtab) +/// @return false if there are other non-floating windows and nothing is done, true otherwise. +static bool close_last_window_tabpage(win_T *win, bool free_buf, bool force, tabpage_T *prev_curtab) FUNC_ATTR_NONNULL_ARG(1) { - if (!ONE_WINDOW) { + if (!one_window(win)) { return false; } + if (lastwin->w_floating && one_window(win)) { + if (is_aucmd_win(lastwin)) { + emsg(_("E814: Cannot close window, only autocmd window would remain")); + return true; + } + if (force || can_close_floating_windows()) { + // close the last window until the there are no floating windows + while (lastwin->w_floating) { + // `force` flag isn't actually used when closing a floating window. + if (win_close(lastwin, free_buf, true) == FAIL) { + // If closing the window fails give up, to avoid looping forever. + return true; + } + } + } else { + emsg(e_floatonly); + return true; + } + } + buf_T *old_curbuf = curbuf; Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL; @@ -2653,30 +2674,11 @@ int win_close(win_T *win, bool free_buf, bool force) emsg(_(e_autocmd_close)); return FAIL; } - if (lastwin->w_floating && one_window(win)) { - if (is_aucmd_win(lastwin)) { - emsg(_("E814: Cannot close window, only autocmd window would remain")); - return FAIL; - } - if (force || can_close_floating_windows()) { - // close the last window until the there are no floating windows - while (lastwin->w_floating) { - // `force` flag isn't actually used when closing a floating window. - if (win_close(lastwin, free_buf, true) == FAIL) { - // If closing the window fails give up, to avoid looping forever. - return FAIL; - } - } - } else { - emsg(e_floatonly); - return FAIL; - } - } // When closing the last window in a tab page first go to another tab page // and then close the window and the tab page to avoid that curwin and // curtab are invalid while we are freeing memory. - if (close_last_window_tabpage(win, free_buf, prev_curtab)) { + if (close_last_window_tabpage(win, free_buf, force, prev_curtab)) { return FAIL; } @@ -2771,7 +2773,7 @@ int win_close(win_T *win, bool free_buf, bool force) // Autocommands may have closed the window already, or closed the only // other window or moved to another tab page. if (!win_valid(win) || (!win->w_floating && last_window(win)) - || close_last_window_tabpage(win, free_buf, prev_curtab)) { + || close_last_window_tabpage(win, free_buf, force, prev_curtab)) { return FAIL; } -- cgit From 9bd4a2807960ea3e82b0454861b399f4ac6d8a92 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Mar 2024 08:37:16 +0800 Subject: fix(window): :close crash if WinClosed from float closes window (#27794) Problem: :close crash if WinClosed from float closes window. Solution: Check if window has already been closed. --- src/nvim/window.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/window.c b/src/nvim/window.c index c0a9b1e39b..a76953d900 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2560,6 +2560,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, bool force, tab emsg(_("E814: Cannot close window, only autocmd window would remain")); return true; } + if (force || can_close_floating_windows()) { // close the last window until the there are no floating windows while (lastwin->w_floating) { @@ -2573,6 +2574,10 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, bool force, tab emsg(e_floatonly); return true; } + + if (!win_valid_any_tab(win)) { + return true; // window already closed by autocommands + } } buf_T *old_curbuf = curbuf; @@ -2591,10 +2596,6 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, bool force, tab // that below. goto_tabpage_tp(alt_tabpage(), false, true); - // save index for tabclosed event - char prev_idx[NUMBUFLEN]; - snprintf(prev_idx, NUMBUFLEN, "%i", tabpage_index(prev_curtab)); - // Safety check: Autocommands may have closed the window when jumping // to the other tab page. if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win) { -- cgit From 6052b346f1b7a3fb616dfcefe3bc05cb6fe3f2f3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Mar 2024 10:33:10 +0800 Subject: revert: "fix(window): :close crash with autocmd, floats and tabpage" (#27796) This reverts PR #27793. On second thought, this solution may still crash, because it can leave a window with a NULL buffer if there are autocommand windows or if closing a floating window fails. It also makes close_last_window_tabpage() more complicated, so revert it. --- src/nvim/window.c | 60 ++++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/window.c b/src/nvim/window.c index a76953d900..ff40a9adef 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2539,47 +2539,21 @@ bool can_close_in_cmdwin(win_T *win, Error *err) return true; } -/// Close the possibly last non-floating window in a tab page. +/// Close the possibly last window in a tab page. /// /// @param win window to close /// @param free_buf whether to free the window's current buffer -/// @param force close floating windows even if they are modified /// @param prev_curtab previous tabpage that will be closed if "win" is the /// last window in the tabpage /// -/// @return false if there are other non-floating windows and nothing is done, true otherwise. -static bool close_last_window_tabpage(win_T *win, bool free_buf, bool force, tabpage_T *prev_curtab) +/// @return false if there are other windows and nothing is done, true otherwise. +static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev_curtab) FUNC_ATTR_NONNULL_ARG(1) { - if (!one_window(win)) { + if (!ONE_WINDOW) { return false; } - if (lastwin->w_floating && one_window(win)) { - if (is_aucmd_win(lastwin)) { - emsg(_("E814: Cannot close window, only autocmd window would remain")); - return true; - } - - if (force || can_close_floating_windows()) { - // close the last window until the there are no floating windows - while (lastwin->w_floating) { - // `force` flag isn't actually used when closing a floating window. - if (win_close(lastwin, free_buf, true) == FAIL) { - // If closing the window fails give up, to avoid looping forever. - return true; - } - } - } else { - emsg(e_floatonly); - return true; - } - - if (!win_valid_any_tab(win)) { - return true; // window already closed by autocommands - } - } - buf_T *old_curbuf = curbuf; Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL; @@ -2675,11 +2649,33 @@ int win_close(win_T *win, bool free_buf, bool force) emsg(_(e_autocmd_close)); return FAIL; } + if (lastwin->w_floating && one_window(win)) { + if (is_aucmd_win(lastwin)) { + emsg(_("E814: Cannot close window, only autocmd window would remain")); + return FAIL; + } + if (force || can_close_floating_windows()) { + // close the last window until the there are no floating windows + while (lastwin->w_floating) { + // `force` flag isn't actually used when closing a floating window. + if (win_close(lastwin, free_buf, true) == FAIL) { + // If closing the window fails give up, to avoid looping forever. + return FAIL; + } + } + if (!win_valid_any_tab(win)) { + return FAIL; // window already closed by autocommands + } + } else { + emsg(e_floatonly); + return FAIL; + } + } // When closing the last window in a tab page first go to another tab page // and then close the window and the tab page to avoid that curwin and // curtab are invalid while we are freeing memory. - if (close_last_window_tabpage(win, free_buf, force, prev_curtab)) { + if (close_last_window_tabpage(win, free_buf, prev_curtab)) { return FAIL; } @@ -2774,7 +2770,7 @@ int win_close(win_T *win, bool free_buf, bool force) // Autocommands may have closed the window already, or closed the only // other window or moved to another tab page. if (!win_valid(win) || (!win->w_floating && last_window(win)) - || close_last_window_tabpage(win, free_buf, force, prev_curtab)) { + || close_last_window_tabpage(win, free_buf, prev_curtab)) { return FAIL; } -- cgit From a441bdc936f9258851be3fa04c108c37e0a497ab Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Mar 2024 16:58:01 +0800 Subject: vim-patch:9.1.0162: problem with writing extended attributes on failure (#27800) Problem: problem with writing extended attributes on failure Solution: Change return type to ssize_t and check listxattr's return value correctly on failure (Paul Tagliamonte) The existing logic will return when the listxattr call returns with the errno set to ENOTSUP (or a size of 0 bytes), without checking to see if listxattr actually failed. listxattr can fail with at least E2BIG, ENOTSUP, ERANGE, or anything that `stat(2)` can fail with (in my case; ENOENT from stat). The returned size is stored to a size_t, but the return type is a ssize_t. On failure, listxattr returns -1, which will get translated to size_t's MAX. If the listxattr call failed with anything other than ENOTSUP, this triggers a request for size_t MAX bytes. This means that, if the listxattr call fails with anything other than ENOTSUP on save, vim will error with `E342: Out of memory! (allocating 18446744073709551615 bytes)` (keen observers will note 18446744073709551615 is 0xffffffffffffffff) In reality, this is likely masking a different (usually filesystem?) error -- but at least it's an error being pushed to the user now, and we don't try to allocate size_t MAX bytes. I've opted to change the type that we store listxattr to from size_t to ssize_t, to match listxattr(2)'s signature, and to check for the -1 return value. Additionally, I've removed the errno check -- if we get a listxattr failure for any reason, we may as well bail without trying; it's not like we can even recover. closes: vim/vim#14169 https://github.com/vim/vim/commit/14759ded57447345ba11c11a99fd84344797862c Co-authored-by: Paul R. Tagliamonte --- src/nvim/os/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index ade745df2c..85caf4aa43 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -789,7 +789,7 @@ void os_copy_xattr(const char *from_file, const char *to_file) // get the length of the extended attributes ssize_t size = listxattr((char *)from_file, NULL, 0); // not supported or no attributes to copy - if (errno == ENOTSUP || size <= 0) { + if (size <= 0) { return; } char *xattr_buf = xmalloc((size_t)size); -- cgit From b465ede2c7a4fb39cf84682d645a3acd08631010 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Mar 2024 17:08:00 +0800 Subject: vim-patch:9.1.0138: too many STRLEN calls when getting a memline (#27799) Problem: too many STRLEN calls when getting a memline Solution: Optimize calls to STRLEN(), add a few functions in memline.c that return the byte length instead of relying on STRLEN() (John Marriott) closes: vim/vim#14052 https://github.com/vim/vim/commit/02d7a6c6cfceb3faf9c98fcb7c458760cd50d269 Cherry-pick line break changes from patch 8.1.0226. Cherry-pick ml_line_len from patch 8.1.0579. Cherry-pick test_comments.vim change from patch 9.1.0153. Co-authored-by: John Marriott --- src/nvim/change.c | 11 +++++++---- src/nvim/cursor.c | 12 ++++++++++++ src/nvim/edit.c | 10 +++++----- src/nvim/memline.c | 40 +++++++++++++++++++++++++++++++++------- src/nvim/memline_defs.h | 1 + src/nvim/normal.c | 14 ++++++-------- src/nvim/textformat.c | 3 +-- 7 files changed, 65 insertions(+), 26 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/change.c b/src/nvim/change.c index 1c7724f010..b914bc29fe 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -926,21 +926,24 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) count = oldlen - col; movelen = 1; } + colnr_T newlen = oldlen - count; // If the old line has been allocated the deletion can be done in the // existing line. Otherwise a new line has to be allocated. - bool was_alloced = ml_line_alloced(); // check if oldp was allocated + bool alloc_newp = !ml_line_alloced(); // check if oldp was allocated char *newp; - if (was_alloced) { + if (!alloc_newp) { ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, oldlen); newp = oldp; // use same allocated memory } else { // need to allocate a new line - newp = xmalloc((size_t)(oldlen + 1 - count)); + newp = xmalloc((size_t)newlen + 1); memmove(newp, oldp, (size_t)col); } memmove(newp + col, oldp + col + count, (size_t)movelen); - if (!was_alloced) { + if (alloc_newp) { ml_replace(lnum, newp, false); + } else { + curbuf->b_ml.ml_line_len -= count; } // mark the buffer as changed and prepare for displaying diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index e93e658f1e..ab99d1b854 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -514,3 +514,15 @@ char *get_cursor_pos_ptr(void) { return ml_get_buf(curbuf, curwin->w_cursor.lnum) + curwin->w_cursor.col; } + +/// @return length (excluding the NUL) of the cursor line. +colnr_T get_cursor_line_len(void) +{ + return ml_get_buf_len(curbuf, curwin->w_cursor.lnum); +} + +/// @return length (excluding the NUL) of the cursor position. +colnr_T get_cursor_pos_len(void) +{ + return ml_get_buf_len(curbuf, curwin->w_cursor.lnum) - curwin->w_cursor.col; +} diff --git a/src/nvim/edit.c b/src/nvim/edit.c index b7b32883c2..54deb0f1c3 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -3785,9 +3785,10 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) if (has_format_option(FO_AUTO) && has_format_option(FO_WHITE_PAR)) { char *ptr = ml_get_buf_mut(curbuf, curwin->w_cursor.lnum); - int len = (int)strlen(ptr); + int len = get_cursor_line_len(); if (len > 0 && ptr[len - 1] == ' ') { ptr[len - 1] = NUL; + curbuf->b_ml.ml_line_len--; } } @@ -4411,13 +4412,13 @@ static bool ins_tab(void) if (i > 0) { STRMOVE(ptr, ptr + i); // correct replace stack. - if ((State & REPLACE_FLAG) - && !(State & VREPLACE_FLAG)) { + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { for (temp = i; --temp >= 0;) { replace_join(repl_off); } } if (!(State & VREPLACE_FLAG)) { + curbuf->b_ml.ml_line_len -= i; inserted_bytes(fpos.lnum, change_col, cursor->col - change_col, fpos.col - change_col); } @@ -4462,8 +4463,7 @@ bool ins_eol(int c) // Strange Vi behaviour: In Replace mode, typing a NL will not delete the // character under the cursor. Only push a NUL on the replace stack, // nothing to put back when the NL is deleted. - if ((State & REPLACE_FLAG) - && !(State & VREPLACE_FLAG)) { + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { replace_push(NUL); } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 6b2f26b2d8..a63c23f0a3 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1174,7 +1174,7 @@ void ml_recover(bool checkext) } else { for (idx = 1; idx <= lnum; idx++) { // Need to copy one line, fetching the other one may flush it. - p = xstrdup(ml_get(idx)); + p = xstrnsave(ml_get(idx), (size_t)ml_get_len(idx)); int i = strcmp(p, ml_get(idx + lnum)); xfree(p); if (i != 0) { @@ -1834,6 +1834,22 @@ char *ml_get_pos(const pos_T *pos) return ml_get_buf(curbuf, pos->lnum) + pos->col; } +/// @return length (excluding the NUL) of the given line. +colnr_T ml_get_len(linenr_T lnum) +{ + return ml_get_buf_len(curbuf, lnum); +} + +/// @return length (excluding the NUL) of the given line in the given buffer. +colnr_T ml_get_buf_len(buf_T *buf, linenr_T lnum) +{ + if (*ml_get_buf(buf, lnum) == NUL) { + return 0; + } + + return buf->b_ml.ml_line_len - 1; +} + /// @return codepoint at pos. pos must be either valid or have col set to MAXCOL! int gchar_pos(pos_T *pos) FUNC_ATTR_NONNULL_ARG(1) @@ -1865,6 +1881,7 @@ static char *ml_get_buf_impl(buf_T *buf, linenr_T lnum, bool will_change) ml_flush_line(buf, false); errorret: STRCPY(questions, "???"); + buf->b_ml.ml_line_len = 4; buf->b_ml.ml_line_lnum = lnum; return questions; } @@ -1873,6 +1890,7 @@ errorret: } if (buf->b_ml.ml_mfp == NULL) { // there are no lines + buf->b_ml.ml_line_len = 1; return ""; } @@ -1903,8 +1921,14 @@ errorret: DataBlock *dp = hp->bh_data; - char *ptr = (char *)dp + (dp->db_index[lnum - buf->b_ml.ml_locked_low] & DB_INDEX_MASK); - buf->b_ml.ml_line_ptr = ptr; + int idx = lnum - buf->b_ml.ml_locked_low; + unsigned start = (dp->db_index[idx] & DB_INDEX_MASK); + // The text ends where the previous line starts. The first line ends + // at the end of the block. + unsigned end = idx == 0 ? dp->db_txt_end : (dp->db_index[idx - 1] & DB_INDEX_MASK); + + buf->b_ml.ml_line_ptr = (char *)dp + start; + buf->b_ml.ml_line_len = (colnr_T)(end - start); buf->b_ml.ml_line_lnum = lnum; buf->b_ml.ml_flags &= ~(ML_LINE_DIRTY | ML_ALLOCATED); } @@ -1922,7 +1946,8 @@ errorret: #ifdef ML_GET_ALLOC_LINES if ((buf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) == 0) { // make sure the text is in allocated memory - buf->b_ml.ml_line_ptr = xstrdup(buf->b_ml.ml_line_ptr); + buf->b_ml.ml_line_ptr = xmemdup(buf->b_ml.ml_line_ptr, + (size_t)buf->b_ml.ml_line_len); buf->b_ml.ml_flags |= ML_ALLOCATED; if (will_change) { // can't make the change in the data block @@ -2468,6 +2493,7 @@ int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy, bool noallo } buf->b_ml.ml_line_ptr = line; + buf->b_ml.ml_line_len = (colnr_T)strlen(line) + 1; buf->b_ml.ml_line_lnum = lnum; buf->b_ml.ml_flags = (buf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; if (noalloc) { @@ -2765,7 +2791,7 @@ static void ml_flush_line(buf_T *buf, bool noalloc) } else { // text of previous line follows old_len = (int)(dp->db_index[idx - 1] & DB_INDEX_MASK) - start; } - colnr_T new_len = (colnr_T)strlen(new_line) + 1; + colnr_T new_len = buf->b_ml.ml_line_len; int extra = new_len - old_len; // negative if lines gets smaller // if new line fits in data block, replace directly @@ -3456,7 +3482,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ char *const name = xmalloc(name_len); memcpy(name, sw_msg_1, sw_msg_1_len + 1); - home_replace(NULL, fname, &name[sw_msg_1_len], fname_len, true); + home_replace(NULL, fname, name + sw_msg_1_len, fname_len, true); xstrlcat(name, sw_msg_2, name_len); int dialog_result = do_dialog(VIM_WARNING, @@ -3734,7 +3760,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, int len, int updtype) // First line in empty buffer from ml_flush_line() -- reset buf->b_ml.ml_usedchunks = 1; buf->b_ml.ml_chunksize[0].mlcs_numlines = 1; - buf->b_ml.ml_chunksize[0].mlcs_totalsize = (int)strlen(buf->b_ml.ml_line_ptr) + 1; + buf->b_ml.ml_chunksize[0].mlcs_totalsize = buf->b_ml.ml_line_len; return; } diff --git a/src/nvim/memline_defs.h b/src/nvim/memline_defs.h index 1a217c96d4..f675a2b15f 100644 --- a/src/nvim/memline_defs.h +++ b/src/nvim/memline_defs.h @@ -56,6 +56,7 @@ typedef struct { #define ML_ALLOCATED 0x10 // ml_line_ptr is an allocated copy int ml_flags; + colnr_T ml_line_len; // length of the cached line + NUL linenr_T ml_line_lnum; // line number of cached line, 0 if not valid char *ml_line_ptr; // pointer to cached line size_t ml_line_offset; // cached byte offset of ml_line_lnum diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 8ff47097fa..f586ad6704 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3223,8 +3223,7 @@ static void nv_colon(cmdarg_T *cap) clearop(cap->oap); } else if (cap->oap->op_type != OP_NOP && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count - || cap->oap->start.col > - (colnr_T)strlen(ml_get(cap->oap->start.lnum)) + || cap->oap->start.col > ml_get_len(cap->oap->start.lnum) || did_emsg)) { // The start of the operator has become invalid by the Ex command. clearopbeep(cap->oap); @@ -3592,7 +3591,7 @@ bool get_visual_text(cmdarg_T *cap, char **pp, size_t *lenp) } if (VIsual_mode == 'V') { *pp = get_cursor_line_ptr(); - *lenp = strlen(*pp); + *lenp = (size_t)get_cursor_line_len(); } else { if (lt(curwin->w_cursor, VIsual)) { *pp = ml_get_pos(&curwin->w_cursor); @@ -4527,9 +4526,8 @@ static void nv_replace(cmdarg_T *cap) } // Abort if not enough characters to replace. - char *ptr = get_cursor_pos_ptr(); - if (strlen(ptr) < (unsigned)cap->count1 - || (mb_charlen(ptr) < cap->count1)) { + if ((size_t)get_cursor_pos_len() < (unsigned)cap->count1 + || (mb_charlen(get_cursor_pos_ptr()) < cap->count1)) { clearopbeep(cap->oap); return; } @@ -5347,7 +5345,7 @@ static void nv_gi_cmd(cmdarg_T *cap) if (curbuf->b_last_insert.mark.lnum != 0) { curwin->w_cursor = curbuf->b_last_insert.mark; check_cursor_lnum(curwin); - int i = (int)strlen(get_cursor_line_ptr()); + int i = (int)get_cursor_line_len(); if (curwin->w_cursor.col > (colnr_T)i) { if (virtual_active()) { curwin->w_cursor.coladd += curwin->w_cursor.col - i; @@ -6036,7 +6034,7 @@ bool unadjust_for_sel(void) mark_mb_adjustpos(curbuf, pp); } else if (pp->lnum > 1) { pp->lnum--; - pp->col = (colnr_T)strlen(ml_get(pp->lnum)); + pp->col = ml_get_len(pp->lnum); return true; } } diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index bfe3ed5972..2cb08df7b5 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -86,8 +86,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on // When 'ai' is off we don't want a space under the cursor to be // deleted. Replace it with an 'x' temporarily. - if (!curbuf->b_p_ai - && !(State & VREPLACE_FLAG)) { + if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG)) { cc = gchar_cursor(); if (ascii_iswhite(cc)) { save_char = (char)cc; -- cgit From 92d4dbbd8cd330606d8a4e1ce1fc550eb6a70d9b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 11 Mar 2024 06:21:32 +0800 Subject: vim-patch:9.1.0164: Internal error when passing invalid position to getregion() (#27805) Problem: Internal error or crash when passing invalid position to getregion(). Solution: Give an error for invalid position (zeertzjq). closes: vim/vim#14172 https://github.com/vim/vim/commit/26dd09ad5e86f4e2179be0181421bfab9a6b3b75 --- src/nvim/eval/funcs.c | 26 +++++++++++++++++++++++--- src/nvim/globals.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 2f9472f158..f37542890b 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2859,20 +2859,40 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } else if (type[0] == Ctrl_V && type[1] == NUL) { region_type = kMTBlockWise; } else { + semsg(_(e_invargNval), "type", type); return; } buf_T *const save_curbuf = curbuf; + buf_T *findbuf = curbuf; if (fnum1 != 0) { - buf_T *findbuf = buflist_findnr(fnum1); + findbuf = buflist_findnr(fnum1); // buffer not loaded if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL) { + emsg(_(e_buffer_is_not_loaded)); return; } - curbuf = findbuf; } + if (p1.lnum < 1 || p1.lnum > findbuf->b_ml.ml_line_count) { + semsg(_(e_invalid_line_number_nr), p1.lnum); + return; + } + if (p1.col < 1 || p1.col > ml_get_buf_len(findbuf, p1.lnum) + 1) { + semsg(_(e_invalid_column_number_nr), p1.col); + return; + } + if (p2.lnum < 1 || p2.lnum > findbuf->b_ml.ml_line_count) { + semsg(_(e_invalid_line_number_nr), p2.lnum); + return; + } + if (p2.col < 1 || p2.col > ml_get_buf_len(findbuf, p2.lnum) + 1) { + semsg(_(e_invalid_column_number_nr), p2.col); + return; + } + + curbuf = findbuf; const TriState save_virtual = virtual_op; virtual_op = virtual_active(); @@ -2900,7 +2920,7 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) mark_mb_adjustpos(curbuf, &p2); } else if (p2.lnum > 1) { p2.lnum--; - p2.col = (colnr_T)strlen(ml_get(p2.lnum)); + p2.col = ml_get_len(p2.lnum); if (p2.col > 0) { p2.col--; mark_mb_adjustpos(curbuf, &p2); diff --git a/src/nvim/globals.h b/src/nvim/globals.h index c1c9ae456c..113985cb52 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -958,6 +958,7 @@ EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invali EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); +EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld")); EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); EXTERN const char e_stray_closing_curly_str[] -- cgit From 74b2f6c3d95647ad07f56bf9ed6865a8db3dfb97 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 10 Mar 2024 19:58:35 -0400 Subject: fix: ignore non-existent properties during header generation `get_target_property( ...)` sets `` to `-NOTFOUND` if the property doesn't exist for the given target. Detect this situation to avoid adding various `-Dprop-NOTFOUND` and `-Iprop-NOTFOUND` to the command-line when generating the headers. --- src/nvim/CMakeLists.txt | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 047b22edcc..7aa7904286 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -450,18 +450,23 @@ endif() #------------------------------------------------------------------------------- get_target_property(prop main_lib INTERFACE_COMPILE_DEFINITIONS) -foreach(gen_cdef ${prop}) - if(NOT ${gen_cdef} MATCHES "INCLUDE_GENERATED_DECLARATIONS") - list(APPEND gen_cflags "-D${gen_cdef}") - endif() -endforeach() +if(NOT "${prop}" STREQUAL "prop-NOTFOUND") + foreach(gen_cdef ${prop}) + if(NOT ${gen_cdef} MATCHES "INCLUDE_GENERATED_DECLARATIONS") + list(APPEND gen_cflags "-D${gen_cdef}") + endif() + endforeach() +endif() get_directory_property(targets BUILDSYSTEM_TARGETS) foreach(target ${targets}) get_target_property(prop ${target} INTERFACE_INCLUDE_DIRECTORIES) - foreach(gen_include ${prop}) - list(APPEND gen_cflags "-I${gen_include}") - endforeach() + if(NOT "${prop}" STREQUAL "prop-NOTFOUND") + message(STATUS "${target} props '${prop}'") + foreach(gen_include ${prop}) + list(APPEND gen_cflags "-I${gen_include}") + endforeach() + endif() endforeach() if(APPLE AND CMAKE_OSX_SYSROOT) -- cgit From 118fd8367c3953abb43800a7c1ea0bcc0221e9cd Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 10 Mar 2024 20:02:32 -0400 Subject: fix: deduplicate gen_cflags Since many of the targets have common include paths, `gen_cflags` accumulates a lot of duplicate flags. --- src/nvim/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 7aa7904286..7e22203aba 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -469,6 +469,8 @@ foreach(target ${targets}) endif() endforeach() +list(REMOVE_DUPLICATES gen_cflags) + if(APPLE AND CMAKE_OSX_SYSROOT) list(APPEND gen_cflags "-isysroot" "${CMAKE_OSX_SYSROOT}") endif() -- cgit From 141182d6c6c06ad56413b81a518ba9b777a0cbe0 Mon Sep 17 00:00:00 2001 From: Colin Kennedy Date: Mon, 25 Dec 2023 20:41:09 -0800 Subject: vim-patch:9.1.0147: Cannot keep a buffer focused in a window Problem: Cannot keep a buffer focused in a window (Amit Levy) Solution: Add the 'winfixbuf' window-local option (Colin Kennedy) fixes: vim/vim#6445 closes: vim/vim#13903 https://github.com/vim/vim/commit/215703563757a4464907ead6fb9edaeb7f430bea N/A patch: vim-patch:58f1e5c0893a --- src/nvim/api/vim.c | 5 +++++ src/nvim/api/window.c | 6 ++++++ src/nvim/arglist.c | 10 +++++++++- src/nvim/buffer.c | 6 ++++++ src/nvim/buffer_defs.h | 2 ++ src/nvim/ex_cmds.c | 4 ++++ src/nvim/ex_cmds.lua | 2 +- src/nvim/ex_cmds2.c | 21 +++++++++++++++++++++ src/nvim/ex_docmd.c | 16 ++++++++++++++-- src/nvim/globals.h | 3 +++ src/nvim/insexpand.c | 2 +- src/nvim/normal.c | 7 ++++++- src/nvim/option.c | 2 ++ src/nvim/options.lua | 19 +++++++++++++++++++ src/nvim/quickfix.c | 33 +++++++++++++++++++++++++++++++-- src/nvim/search.c | 8 +++++--- src/nvim/tag.c | 8 ++++++++ src/nvim/window.c | 31 ++++++++++++++++++++++++++++++- 18 files changed, 173 insertions(+), 12 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 84a2f24dbc..24ad7d5fbc 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -876,6 +876,11 @@ void nvim_set_current_buf(Buffer buffer, Error *err) return; } + if (curwin->w_p_wfb) { + api_set_error(err, kErrorTypeException, "%s", e_winfixbuf_cannot_go_to_buffer); + return; + } + try_start(); int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0); if (!try_end(err) && result == FAIL) { diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index ed51eedf1b..1a80e9ea16 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -61,6 +61,12 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) if (!win || !buf) { return; } + + if (win->w_p_wfb) { + api_set_error(err, kErrorTypeException, "%s", e_winfixbuf_cannot_go_to_buffer); + return; + } + if (win == cmdwin_win || win == cmdwin_old_curwin || buf == cmdwin_buf) { api_set_error(err, kErrorTypeException, "%s", e_cmdwin); return; diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c index a02c22deae..4d493c9d03 100644 --- a/src/nvim/arglist.c +++ b/src/nvim/arglist.c @@ -623,6 +623,8 @@ void ex_argument(exarg_T *eap) /// Edit file "argn" of the argument lists. void do_argfile(exarg_T *eap, int argn) { + bool is_split_cmd = *eap->cmd == 's'; + int old_arg_idx = curwin->w_arg_idx; if (argn < 0 || argn >= ARGCOUNT) { @@ -637,10 +639,16 @@ void do_argfile(exarg_T *eap, int argn) return; } + if (!is_split_cmd + && (&ARGLIST[argn])->ae_fnum != curbuf->b_fnum + && !check_can_set_curbuf_forceit(eap->forceit)) { + return; + } + setpcmark(); // split window or create new tab page first - if (*eap->cmd == 's' || cmdmod.cmod_tab != 0) { + if (is_split_cmd || cmdmod.cmod_tab != 0) { if (win_split(0, 0) == FAIL) { return; } diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 7154be36be..e141706edd 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1305,6 +1305,12 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } return FAIL; } + + if (action == DOBUF_GOTO && buf != curbuf && !check_can_set_curbuf_forceit(forceit)) { + // disallow navigating to another buffer when 'winfixbuf' is applied + return FAIL; + } + if ((action == DOBUF_GOTO || action == DOBUF_SPLIT) && (buf->b_flags & BF_DUMMY)) { // disallow navigating to the dummy buffer semsg(_(e_nobufnr), count); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 1e5086309c..7f7300706c 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -139,6 +139,8 @@ typedef struct { #define w_ve_flags w_onebuf_opt.wo_ve_flags // flags for 'virtualedit' OptInt wo_nuw; #define w_p_nuw w_onebuf_opt.wo_nuw // 'numberwidth' + int wo_wfb; +#define w_p_wfb w_onebuf_opt.wo_wfb // 'winfixbuf' int wo_wfh; #define w_p_wfh w_onebuf_opt.wo_wfh // 'winfixheight' int wo_wfw; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 74ad8e95a2..14bd2b87e3 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2008,6 +2008,10 @@ static int check_readonly(int *forceit, buf_T *buf) /// GETFILE_OPEN_OTHER for successfully opening another file. int getfile(int fnum, char *ffname_arg, char *sfname_arg, bool setpm, linenr_T lnum, bool forceit) { + if (!check_can_set_curbuf_forceit(forceit)) { + return GETFILE_ERROR; + } + char *ffname = ffname_arg; char *sfname = sfname_arg; bool other; diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 1318eda5eb..e2196f99ec 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -812,7 +812,7 @@ module.cmds = { }, { command = 'drop', - flags = bit.bor(FILES, CMDARG, NEEDARG, ARGOPT, TRLBAR), + flags = bit.bor(BANG, FILES, CMDARG, NEEDARG, ARGOPT, TRLBAR), addr_type = 'ADDR_NONE', func = 'ex_drop', }, diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 8016e37ca7..3120868350 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -444,6 +444,27 @@ int buf_write_all(buf_T *buf, bool forceit) /// ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" void ex_listdo(exarg_T *eap) { + if (curwin->w_p_wfb) { + if ((eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) && !eap->forceit) { + // Disallow :ldo if 'winfixbuf' is applied + semsg("%s", e_winfixbuf_cannot_go_to_buffer); + return; + } + + if (win_valid(prevwin)) { + // Change the current window to another because 'winfixbuf' is enabled + curwin = prevwin; + } else { + // Split the window, which will be 'nowinfixbuf', and set curwin to that + exarg_T new_eap = { + .cmdidx = CMD_split, + .cmd = "split", + .arg = "", + }; + ex_splitview(&new_eap); + } + } + char *save_ei = NULL; // Temporarily override SHM_OVER and SHM_OVERALL to avoid that file diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2913f6d4e9..1b4e83d392 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5334,6 +5334,10 @@ static void ex_resize(exarg_T *eap) /// ":find [+command] " command. static void ex_find(exarg_T *eap) { + if (!check_can_set_curbuf_forceit(eap->forceit)) { + return; + } + char *file_to_find = NULL; char *search_ctx = NULL; char *fname = find_file_in_path(eap->arg, strlen(eap->arg), @@ -5364,6 +5368,14 @@ static void ex_find(exarg_T *eap) /// ":edit", ":badd", ":balt", ":visual". static void ex_edit(exarg_T *eap) { + // Exclude commands which keep the window's current buffer + if (eap->cmdidx != CMD_badd + && eap->cmdidx != CMD_balt + // All other commands must obey 'winfixbuf' / ! rules + && !check_can_set_curbuf_forceit(eap->forceit)) { + return; + } + do_exedit(eap, NULL); } @@ -6670,7 +6682,7 @@ static void ex_checkpath(exarg_T *eap) { find_pattern_in_path(NULL, 0, 0, false, false, CHECK_PATH, 1, eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW, - 1, (linenr_T)MAXLNUM); + 1, (linenr_T)MAXLNUM, eap->forceit); } /// ":psearch" @@ -6729,7 +6741,7 @@ static void ex_findpat(exarg_T *eap) if (!eap->skip) { find_pattern_in_path(eap->arg, 0, strlen(eap->arg), whole, !eap->forceit, *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, - n, action, eap->line1, eap->line2); + n, action, eap->line1, eap->line2, eap->forceit); } } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 113985cb52..aecb9d1116 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -971,6 +971,9 @@ EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s")); EXTERN const char e_undobang_cannot_redo_or_move_branch[] INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); +EXTERN const char e_winfixbuf_cannot_go_to_buffer[] +INIT(= N_("E1513: Cannot edit buffer. 'winfixbuf' is enabled")); + EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s")); diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 41b964323e..d0cd24773f 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -3027,7 +3027,7 @@ static void get_next_include_file_completion(int compl_type) ((compl_type == CTRL_X_PATH_DEFINES && !(compl_cont_status & CONT_SOL)) ? FIND_DEFINE : FIND_ANY), - 1, ACTION_EXPAND, 1, MAXLNUM); + 1, ACTION_EXPAND, 1, MAXLNUM, false); } /// Get the next set of words matching "compl_pattern" in dictionary or diff --git a/src/nvim/normal.c b/src/nvim/normal.c index f586ad6704..aae9621d4a 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3896,6 +3896,10 @@ static void nv_gotofile(cmdarg_T *cap) return; } + if (!check_can_set_curbuf_disabled()) { + return; + } + char *ptr = grab_file_name(cap->count1, &lnum); if (ptr != NULL) { @@ -4232,7 +4236,8 @@ static void nv_brackets(cmdarg_T *cap) (cap->cmdchar == ']' ? curwin->w_cursor.lnum + 1 : 1), - MAXLNUM); + MAXLNUM, + false); xfree(ptr); curwin->w_set_curswant = true; } diff --git a/src/nvim/option.c b/src/nvim/option.c index 0ac65ed95d..fcc5b5eb06 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4629,6 +4629,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) return &(win->w_p_rnu); case PV_NUW: return &(win->w_p_nuw); + case PV_WFB: + return &(win->w_p_wfb); case PV_WFH: return &(win->w_p_wfh); case PV_WFW: diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 72f9ff849d..5e8bc1361c 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -8406,6 +8406,8 @@ return { "split" when both are present. uselast If included, jump to the previously used window when jumping to errors with |quickfix| commands. + If a window has 'winfixbuf' enabled, 'switchbuf' is currently not + applied to the split window. ]=], expand_cb = 'expand_set_switchbuf', full_name = 'switchbuf', @@ -9816,6 +9818,23 @@ return { type = 'number', varname = 'p_window', }, + { + abbreviation = 'wfb', + defaults = { if_true = false }, + desc = [=[ + If enabled, the buffer and any window that displays it are paired. + For example, attempting to change the buffer with |:edit| will fail. + Other commands which change a window's buffer such as |:cnext| will + also skip any window with 'winfixbuf' enabled. However if a command + has an "!" option, a window can be forced to switch buffers. + ]=], + full_name = 'winfixbuf', + pv_name = 'p_wfb', + redraw = { 'current_window' }, + scope = { 'window' }, + short_desc = N_('pin a window to a specific buffer'), + type = 'boolean', + }, { abbreviation = 'wfh', defaults = { if_true = false }, diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 651ebc9f93..a88b781f32 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2699,7 +2699,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum) // Didn't find it, go to the window before the quickfix // window, unless 'switchbuf' contains 'uselast': in this case we // try to jump to the previously used window first. - if ((swb_flags & SWB_USELAST) && win_valid(prevwin)) { + if ((swb_flags & SWB_USELAST) && !prevwin->w_p_wfb && win_valid(prevwin)) { win = prevwin; } else if (altwin != NULL) { win = altwin; @@ -2714,6 +2714,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum) // Remember a usable window. if (altwin == NULL && !win->w_p_pvw + && !win->w_p_wfb && bt_normal(win->w_buffer)) { altwin = win; } @@ -2802,6 +2803,25 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int ECMD_HIDE + ECMD_SET_HELP, prev_winid == curwin->handle ? curwin : NULL); } else { + if (!forceit && curwin->w_p_wfb) { + if (qi->qfl_type == QFLT_LOCATION) { + // Location lists cannot split or reassign their window + // so 'winfixbuf' windows must fail + semsg("%s", e_winfixbuf_cannot_go_to_buffer); + return QF_ABORT; + } + + if (!win_valid(prevwin)) { + // Split the window, which will be 'nowinfixbuf', and set curwin to that + exarg_T new_eap = { + .cmdidx = CMD_split, + .cmd = "split", + .arg = "", + }; + ex_splitview(&new_eap); + } + } + retval = buflist_getfile(qf_ptr->qf_fnum, 1, GETF_SETMARK | GETF_SWITCH, forceit); } @@ -4297,6 +4317,11 @@ static void qf_jump_first(qf_info_T *qi, unsigned save_qfid, int forceit) if (qf_restore_list(qi, save_qfid) == FAIL) { return; } + + if (!check_can_set_curbuf_forceit(forceit)) { + return; + } + // Autocommands might have cleared the list, check for that if (!qf_list_empty(qf_get_curlist(qi))) { qf_jump(qi, 0, 0, forceit); @@ -5125,7 +5150,7 @@ void ex_cfile(exarg_T *eap) // This function is used by the :cfile, :cgetfile and :caddfile // commands. - // :cfile always creates a new quickfix list and jumps to the + // :cfile always creates a new quickfix list and may jump to the // first error. // :cgetfile creates a new quickfix list but doesn't jump to the // first error. @@ -5587,6 +5612,10 @@ theend: /// ":lvimgrepadd {pattern} file(s)" void ex_vimgrep(exarg_T *eap) { + if (!check_can_set_curbuf_forceit(eap->forceit)) { + return; + } + char *au_name = vgr_get_auname(eap->cmdidx); if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, curbuf->b_fname, true, curbuf)) { diff --git a/src/nvim/search.c b/src/nvim/search.c index 48e41c290d..2fea28ba7c 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3564,8 +3564,10 @@ static char *get_line_and_copy(linenr_T lnum, char *buf) /// @param action What to do when we find it /// @param start_lnum first line to start searching /// @param end_lnum last line for searching +/// @param forceit If true, always switch to the found path void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool skip_comments, - int type, int count, int action, linenr_T start_lnum, linenr_T end_lnum) + int type, int count, int action, linenr_T start_lnum, linenr_T end_lnum, + int forceit) { SearchedFile *files; // Stack of included files SearchedFile *bigger; // When we need more space @@ -4025,7 +4027,7 @@ search_line: break; } if (!GETFILE_SUCCESS(getfile(curwin_save->w_buffer->b_fnum, NULL, - NULL, true, lnum, false))) { + NULL, true, lnum, forceit))) { break; // failed to jump to file } } else { @@ -4035,7 +4037,7 @@ search_line: check_cursor(); } else { if (!GETFILE_SUCCESS(getfile(0, files[depth].name, NULL, true, - files[depth].lnum, false))) { + files[depth].lnum, forceit))) { break; // failed to jump to file } // autocommands may have changed the lnum, we don't diff --git a/src/nvim/tag.c b/src/nvim/tag.c index ab5bfc6773..776498fa29 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -290,6 +290,10 @@ void set_buflocal_tfu_callback(buf_T *buf) /// @param verbose print "tag not found" message void do_tag(char *tag, int type, int count, int forceit, bool verbose) { + if (postponed_split == 0 && !check_can_set_curbuf_forceit(forceit)) { + return; + } + taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; int tagstacklen = curwin->w_tagstacklen; @@ -2784,6 +2788,10 @@ static char *tag_full_fname(tagptrs_T *tagp) /// @return OK for success, NOTAGFILE when file not found, FAIL otherwise. static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) { + if (postponed_split == 0 && !check_can_set_curbuf_forceit(forceit)) { + return FAIL; + } + char *pbuf_end; char *tofree_fname = NULL; tagptrs_T tagp; diff --git a/src/nvim/window.c b/src/nvim/window.c index ff40a9adef..9f84713ee7 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -133,6 +133,35 @@ static void log_frame_layout(frame_T *frame) } #endif +/// Check if the current window is allowed to move to a different buffer. +/// +/// @return If the window has 'winfixbuf', or this function will return false. +bool check_can_set_curbuf_disabled(void) +{ + if (curwin->w_p_wfb) { + semsg("%s", e_winfixbuf_cannot_go_to_buffer); + return false; + } + + return true; +} + +/// Check if the current window is allowed to move to a different buffer. +/// +/// @param forceit If true, do not error. If false and 'winfixbuf' is enabled, error. +/// +/// @return If the window has 'winfixbuf', then forceit must be true +/// or this function will return false. +bool check_can_set_curbuf_forceit(int forceit) +{ + if (!forceit && curwin->w_p_wfb) { + semsg("%s", e_winfixbuf_cannot_go_to_buffer); + return false; + } + + return true; +} + /// @return the current window, unless in the cmdline window and "prevwin" is /// set, then return "prevwin". win_T *prevwin_curwin(void) @@ -597,7 +626,7 @@ wingotofile: ptr = xmemdupz(ptr, len); find_pattern_in_path(ptr, 0, len, true, Prenum == 0, - type, Prenum1, ACTION_SPLIT, 1, MAXLNUM); + type, Prenum1, ACTION_SPLIT, 1, MAXLNUM, false); xfree(ptr); curwin->w_set_curswant = true; break; -- cgit From e8bc23db62c37e91d0c277b4bddf652db6a9d5f1 Mon Sep 17 00:00:00 2001 From: Colin Kennedy Date: Mon, 4 Mar 2024 21:25:15 -0800 Subject: vim-patch:9.1.0149: null pointer member access when accessing 'winfixbuf' property Problem: qf_goto_win_with_qfl_file may check if prevwin has 'winfixbuf' set without checking if it's valid first. Solution: Reverse the condition. Add a test, a modeline, and a missing CheckFeature. (Searn Dewar) closes: vim/vim#14140 https://github.com/vim/vim/commit/5131f224da93f2e042a4b22545ef62b1b2ab8460 Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com> --- src/nvim/quickfix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index a88b781f32..3dd4e35f65 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2699,7 +2699,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum) // Didn't find it, go to the window before the quickfix // window, unless 'switchbuf' contains 'uselast': in this case we // try to jump to the previously used window first. - if ((swb_flags & SWB_USELAST) && !prevwin->w_p_wfb && win_valid(prevwin)) { + if ((swb_flags & SWB_USELAST) && win_valid(prevwin) && !prevwin->w_p_wfb) { win = prevwin; } else if (altwin != NULL) { win = altwin; -- cgit From 5931f2bc4ac319e5fa617b36cbe5305228125c11 Mon Sep 17 00:00:00 2001 From: Colin Kennedy Date: Tue, 5 Mar 2024 23:39:30 -0800 Subject: vim-patch:9.1.0150: Several minor 'winfixbuf' issues Problem: several minor 'winfixbuf' issues exist, mostly relating to the quickfix list Solution: address them and adjust tests. Retab and reflow a few things too. (Sean Dewar) Things touched include: - Replace the semsgs with gettext'd emsgs. - Handle window switching in ex_listdo properly, so curbuf and curwin are kept in-sync and trigger autocommands; handle those properly. - Don't change the list entry index in qf_jump_edit_buffer if we fail due to 'wfb' (achieved by returning FAIL; QF_ABORT should only be used if the list was changed). - Make qf_jump_edit_buffer actually switch to prevwin when using `:cXX` commands **outside** of the list window if 'wfb' is set in curwin. Handle autocommands properly in case they mess with the list. NOTE: previously, it seemed to split if 'wfb' was set, but do nothing and fail if prevwin is *valid*. This behaviour seemed strange, and maybe unintentional? Now it aligns more with what's described for the `:cXX` commands in the original PR description when used outside a list window, I think. - In both functions, only consider prevwin if 'wfb' isn't set for it; fallback to splitting otherwise. - Use win_split to split. Not sure if there was a specific reason for using ex_splitview. win_split is simpler and respects modifiers like :vertical that may have been used. Plus, its return value can be checked for setting opened_window in qf code (technically win_split_ins autocmds could immediately close it or change windows, in which the qf code might close some other window on failure; it's already the case elsewhere, though). closes: vim/vim#14142 https://github.com/vim/vim/commit/4bb505e28cac0389561fff78d8bbe0319c2bcf2f Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com> --- src/nvim/ex_cmds2.c | 25 ++++++++++++++----------- src/nvim/quickfix.c | 44 ++++++++++++++++++++++++++++++-------------- src/nvim/window.c | 4 ++-- 3 files changed, 46 insertions(+), 27 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 3120868350..dacdb27b08 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -447,21 +447,24 @@ void ex_listdo(exarg_T *eap) if (curwin->w_p_wfb) { if ((eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) && !eap->forceit) { // Disallow :ldo if 'winfixbuf' is applied - semsg("%s", e_winfixbuf_cannot_go_to_buffer); + emsg(_(e_winfixbuf_cannot_go_to_buffer)); return; } - if (win_valid(prevwin)) { - // Change the current window to another because 'winfixbuf' is enabled - curwin = prevwin; - } else { + if (win_valid(prevwin) && !prevwin->w_p_wfb) { + // 'winfixbuf' is set; attempt to change to a window without it. + win_goto(prevwin); + } + if (curwin->w_p_wfb) { // Split the window, which will be 'nowinfixbuf', and set curwin to that - exarg_T new_eap = { - .cmdidx = CMD_split, - .cmd = "split", - .arg = "", - }; - ex_splitview(&new_eap); + win_split(0, 0); + + if (curwin->w_p_wfb) { + // Autocommands set 'winfixbuf' or sent us to another window + // with it set. Give up. + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + return; + } } } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 3dd4e35f65..28691914bb 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2699,7 +2699,8 @@ static void qf_goto_win_with_qfl_file(int qf_fnum) // Didn't find it, go to the window before the quickfix // window, unless 'switchbuf' contains 'uselast': in this case we // try to jump to the previously used window first. - if ((swb_flags & SWB_USELAST) && win_valid(prevwin) && !prevwin->w_p_wfb) { + if ((swb_flags & SWB_USELAST) && win_valid(prevwin) + && !prevwin->w_p_wfb) { win = prevwin; } else if (altwin != NULL) { win = altwin; @@ -2803,27 +2804,42 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int ECMD_HIDE + ECMD_SET_HELP, prev_winid == curwin->handle ? curwin : NULL); } else { - if (!forceit && curwin->w_p_wfb) { + int fnum = qf_ptr->qf_fnum; + + if (!forceit && curwin->w_p_wfb && curbuf->b_fnum != fnum) { if (qi->qfl_type == QFLT_LOCATION) { // Location lists cannot split or reassign their window // so 'winfixbuf' windows must fail - semsg("%s", e_winfixbuf_cannot_go_to_buffer); - return QF_ABORT; + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + return FAIL; } - if (!win_valid(prevwin)) { - // Split the window, which will be 'nowinfixbuf', and set curwin to that - exarg_T new_eap = { - .cmdidx = CMD_split, - .cmd = "split", - .arg = "", - }; - ex_splitview(&new_eap); + if (win_valid(prevwin) && !prevwin->w_p_wfb + && !bt_quickfix(prevwin->w_buffer)) { + // 'winfixbuf' is set; attempt to change to a window without it + // that isn't a quickfix/location list window. + win_goto(prevwin); + } + if (curwin->w_p_wfb) { + // Split the window, which will be 'nowinfixbuf', and set curwin + // to that + if (win_split(0, 0) == OK) { + *opened_window = true; + } + if (curwin->w_p_wfb) { + // Autocommands set 'winfixbuf' or sent us to another window + // with it set. Give up, but don't return immediately, as + // they may have messed with the list. + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + retval = FAIL; + } } } - retval = buflist_getfile(qf_ptr->qf_fnum, 1, - GETF_SETMARK | GETF_SWITCH, forceit); + if (retval == OK) { + retval = buflist_getfile(fnum, 1, + GETF_SETMARK | GETF_SWITCH, forceit); + } } // If a location list, check whether the associated window is still // present. diff --git a/src/nvim/window.c b/src/nvim/window.c index 9f84713ee7..521699f2f0 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -139,7 +139,7 @@ static void log_frame_layout(frame_T *frame) bool check_can_set_curbuf_disabled(void) { if (curwin->w_p_wfb) { - semsg("%s", e_winfixbuf_cannot_go_to_buffer); + emsg(_(e_winfixbuf_cannot_go_to_buffer)); return false; } @@ -155,7 +155,7 @@ bool check_can_set_curbuf_disabled(void) bool check_can_set_curbuf_forceit(int forceit) { if (!forceit && curwin->w_p_wfb) { - semsg("%s", e_winfixbuf_cannot_go_to_buffer); + emsg(_(e_winfixbuf_cannot_go_to_buffer)); return false; } -- cgit From d71791a11a260ca81067d63d69b5970078fffb6d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 11 Mar 2024 11:25:00 +0800 Subject: vim-patch:9.1.0152: Coverity complains about ignoring return value Problem: Coverity complains about ignoring return value of win_split() (after v9.1.150) Solution: Check if win_split() failed, add winfixbuf.res to Makefile https://github.com/vim/vim/commit/af7ae8160041e2d17c56945381e9370e7178e596 Co-authored-by: Christian Brabandt --- src/nvim/ex_cmds2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index dacdb27b08..732631b678 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -457,8 +457,9 @@ void ex_listdo(exarg_T *eap) } if (curwin->w_p_wfb) { // Split the window, which will be 'nowinfixbuf', and set curwin to that - win_split(0, 0); - + if (win_split(0, 0) == FAIL) { + return; // error message already given + } if (curwin->w_p_wfb) { // Autocommands set 'winfixbuf' or sent us to another window // with it set. Give up. -- cgit From 3b3511c4d9f1855d4240da0d844ce7875176c607 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 11 Mar 2024 11:26:02 +0800 Subject: vim-patch:9.1.0156: Make 'wfb' failing to split still report E1513 Problem: may not be clear why failing to split causes an ":Xdo" command to abort if 'wfb' is set. Solution: do not return immediately if win_split fails, so E1513 is still given. Expect both errors in the test. Also fix tests to pass CI. (Sean Dewar) closes: vim/vim#14152 https://github.com/vim/vim/commit/769eb2d0c3614f9ea6fffa82329558f1a4af384f Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com> --- src/nvim/ex_cmds2.c | 7 +++---- src/nvim/quickfix.c | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 732631b678..12687d0ea8 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -457,12 +457,11 @@ void ex_listdo(exarg_T *eap) } if (curwin->w_p_wfb) { // Split the window, which will be 'nowinfixbuf', and set curwin to that - if (win_split(0, 0) == FAIL) { - return; // error message already given - } + (void)win_split(0, 0); + if (curwin->w_p_wfb) { // Autocommands set 'winfixbuf' or sent us to another window - // with it set. Give up. + // with it set, or we failed to split the window. Give up. emsg(_(e_winfixbuf_cannot_go_to_buffer)); return; } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 28691914bb..0a4427f3c1 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2828,8 +2828,9 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int } if (curwin->w_p_wfb) { // Autocommands set 'winfixbuf' or sent us to another window - // with it set. Give up, but don't return immediately, as - // they may have messed with the list. + // with it set, or we failed to split the window. Give up, + // but don't return immediately, as they may have messed + // with the list. emsg(_(e_winfixbuf_cannot_go_to_buffer)); retval = FAIL; } -- cgit From b72931e7040794f8c6adf6c0a446758f14107dda Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 11 Mar 2024 07:13:48 +0100 Subject: feat(ui): allow non-zero 'cmdheight' with ext_messages Problem: Arbitrary restriction on 'cmdheight' with ext_messages. The 'cmdheight'-area may be desirable for the replacing cmdline. Solution: Allow non-zero 'cmdheight' with ext_messages. --- src/nvim/option.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/option.c b/src/nvim/option.c index fcc5b5eb06..4f1ec59e77 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2024,9 +2024,6 @@ static const char *did_set_cmdheight(optset_T *args) { OptInt old_value = args->os_oldval.number; - if (ui_has(kUIMessages)) { - p_ch = 0; - } if (p_ch > Rows - min_rows() + 1) { p_ch = Rows - min_rows() + 1; } -- cgit From 9cc755ad6a60e2b028d61c1dca62f8fe20f652d7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 12 Mar 2024 05:39:21 +0800 Subject: vim-patch:0049a495c8d4 (#27817) runtime(doc): improve 'winfixbuf' docs (vim/vim#14180) - Make it not sound like a buffer option. - "!" is called a modifier, not an option. https://github.com/vim/vim/commit/0049a495c8d4a597773587f622d8cc8573c2eb75 --- src/nvim/options.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 5e8bc1361c..411acbcc82 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -9822,11 +9822,11 @@ return { abbreviation = 'wfb', defaults = { if_true = false }, desc = [=[ - If enabled, the buffer and any window that displays it are paired. + If enabled, the window and the buffer it is displaying are paired. For example, attempting to change the buffer with |:edit| will fail. Other commands which change a window's buffer such as |:cnext| will - also skip any window with 'winfixbuf' enabled. However if a command - has an "!" option, a window can be forced to switch buffers. + also skip any window with 'winfixbuf' enabled. However if an Ex + command has a "!" modifier, it can force switching buffers. ]=], full_name = 'winfixbuf', pv_name = 'p_wfb', -- cgit From cf156377e80232aa904b92e4af29dd6c61952401 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 12 Mar 2024 06:56:06 +0800 Subject: vim-patch:8.2.4944: text properties are wrong after "cc" (#27821) Problem: Text properties are wrong after "cc". (Axel Forsman) Solution: Pass the deleted byte count to inserted_bytes(). (closes vim/vim#10412, closes vim/vim#7737, closes vim/vim#5763) https://github.com/vim/vim/commit/d0b1a09f44654bb5e29b09de1311845200f17d90 Co-authored-by: LemonBoy --- src/nvim/change.c | 11 ++++------- src/nvim/ops.c | 11 ++--------- 2 files changed, 6 insertions(+), 16 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/change.c b/src/nvim/change.c index b914bc29fe..3d06c6956e 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -1935,19 +1935,16 @@ theend: /// If "fixpos" is true fix the cursor position when done. void truncate_line(int fixpos) { - char *newp; linenr_T lnum = curwin->w_cursor.lnum; colnr_T col = curwin->w_cursor.col; + char *old_line = ml_get(lnum); + char *newp = col == 0 ? xstrdup("") : xstrnsave(old_line, (size_t)col); + int deleted = (int)strlen(old_line) - col; - if (col == 0) { - newp = xstrdup(""); - } else { - newp = xstrnsave(ml_get(lnum), (size_t)col); - } ml_replace(lnum, newp, false); // mark the buffer as changed and prepare for displaying - changed_bytes(lnum, curwin->w_cursor.col); + inserted_bytes(lnum, curwin->w_cursor.col, deleted, 0); // If "fixpos" is true we don't want to end up positioned at the NUL. if (fixpos && curwin->w_cursor.col > 0) { diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 5a0ef66e91..4e27c44262 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1613,15 +1613,8 @@ int op_delete(oparg_T *oap) } else { beginline(0); // cursor in column 0 } - - int old_len = (int)strlen(ml_get(curwin->w_cursor.lnum)); - truncate_line(false); // delete the rest of the line - - extmark_splice_cols(curbuf, - (int)curwin->w_cursor.lnum - 1, curwin->w_cursor.col, - old_len - curwin->w_cursor.col, 0, kExtmarkUndo); - - // leave cursor past last char in line + truncate_line(false); // delete the rest of the line, + // leave cursor past last char in line if (oap->line_count > 1) { u_clearline(curbuf); // "U" command not possible after "2cc" } -- cgit From 6481da3015fd6cf136e752c9123078223c50d91c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 12 Mar 2024 07:19:30 +0800 Subject: vim-patch:9.1.0166: Internal error with blockwise getregion() in another buffer (#27819) Problem: Internal error with blockwise getregion() in another buffer Solution: Also change curwin->w_buffer when changing curbuf (zeertzjq) closes: vim/vim#14179 https://github.com/vim/vim/commit/5406eb8722bddb6a04876956f9a53c1752994851 --- src/nvim/eval/funcs.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f37542890b..ab92aa7b34 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2863,16 +2863,10 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - buf_T *const save_curbuf = curbuf; - buf_T *findbuf = curbuf; - - if (fnum1 != 0) { - findbuf = buflist_findnr(fnum1); - // buffer not loaded - if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL) { - emsg(_(e_buffer_is_not_loaded)); - return; - } + buf_T *findbuf = fnum1 != 0 ? buflist_findnr(fnum1) : curbuf; + if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL) { + emsg(_(e_buffer_is_not_loaded)); + return; } if (p1.lnum < 1 || p1.lnum > findbuf->b_ml.ml_line_count) { @@ -2892,7 +2886,9 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } + buf_T *const save_curbuf = curbuf; curbuf = findbuf; + curwin->w_buffer = curbuf; const TriState save_virtual = virtual_op; virtual_op = virtual_active(); @@ -2975,10 +2971,8 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_list_append_allocated_string(rettv->vval.v_list, akt); } - if (curbuf != save_curbuf) { - curbuf = save_curbuf; - } - + curbuf = save_curbuf; + curwin->w_buffer = curbuf; virtual_op = save_virtual; } -- cgit From b02a4d8ac39bafdbfd490bfbab35e3202e6f709c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 12 Mar 2024 07:20:22 +0800 Subject: vim-patch:9.1.0168: too many STRLEN() calls (#27823) Problem: too many STRLEN() calls Solution: Make use of ml_get_len() calls instead (John Marriott) closes: vim/vim#14123 https://github.com/vim/vim/commit/bfcc895482c717c9f6d86890d789ec739c3016b4 Co-authored-by: John Marriott --- src/nvim/change.c | 15 ++++++++------- src/nvim/edit.c | 2 +- src/nvim/eval.c | 4 ++-- src/nvim/eval/funcs.c | 20 +++++++++----------- 4 files changed, 20 insertions(+), 21 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/change.c b/src/nvim/change.c index 3d06c6956e..8b1e7587de 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -714,7 +714,7 @@ void ins_char_bytes(char *buf, size_t charlen) size_t col = (size_t)curwin->w_cursor.col; linenr_T lnum = curwin->w_cursor.lnum; char *oldp = ml_get(lnum); - size_t linelen = strlen(oldp) + 1; // length of old line including NUL + size_t linelen = (size_t)ml_get_len(lnum) + 1; // length of old line including NUL // The lengths default to the values for when not replacing. size_t oldlen = 0; // nr of bytes inserted @@ -821,7 +821,7 @@ void ins_str(char *s) colnr_T col = curwin->w_cursor.col; char *oldp = ml_get(lnum); - int oldlen = (int)strlen(oldp); + int oldlen = ml_get_len(lnum); char *newp = xmalloc((size_t)oldlen + (size_t)newlen + 1); if (col > 0) { @@ -879,7 +879,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) colnr_T col = curwin->w_cursor.col; bool fixpos = fixpos_arg; char *oldp = ml_get(lnum); - colnr_T oldlen = (colnr_T)strlen(oldp); + colnr_T oldlen = ml_get_len(lnum); // Can't do anything when the cursor is on the NUL after the line. if (col >= oldlen) { @@ -1117,7 +1117,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) colnr_T mincol = curwin->w_cursor.col + 1; // make a copy of the current line so we can mess with it - char *saved_line = xstrdup(get_cursor_line_ptr()); + char *saved_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); if (State & VREPLACE_FLAG) { // With MODE_VREPLACE we make a copy of the next line, which we will be @@ -1128,7 +1128,8 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // the line, replacing what was there before and pushing the right // stuff onto the replace stack. -- webb. if (curwin->w_cursor.lnum < orig_line_count) { - next_line = xstrdup(ml_get(curwin->w_cursor.lnum + 1)); + next_line = xstrnsave(ml_get(curwin->w_cursor.lnum + 1), + (size_t)ml_get_len(curwin->w_cursor.lnum + 1)); } else { next_line = xstrdup(""); } @@ -1908,7 +1909,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // stuff onto the replace stack (via ins_char()). if (State & VREPLACE_FLAG) { // Put new line in p_extra - p_extra = xstrdup(get_cursor_line_ptr()); + p_extra = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); // Put back original line ml_replace(curwin->w_cursor.lnum, next_line, false); @@ -1939,7 +1940,7 @@ void truncate_line(int fixpos) colnr_T col = curwin->w_cursor.col; char *old_line = ml_get(lnum); char *newp = col == 0 ? xstrdup("") : xstrnsave(old_line, (size_t)col); - int deleted = (int)strlen(old_line) - col; + int deleted = ml_get_len(lnum) - col; ml_replace(lnum, newp, false); diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 54deb0f1c3..a0d6f7125e 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -4331,7 +4331,7 @@ static bool ins_tab(void) if (State & VREPLACE_FLAG) { pos = curwin->w_cursor; cursor = &pos; - saved_line = xstrdup(get_cursor_line_ptr()); + saved_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); ptr = saved_line + pos.col; } else { ptr = get_cursor_pos_ptr(); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3d224bfa0f..e4ee254193 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6699,7 +6699,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret if (charcol) { len = mb_charlen(ml_get(pos.lnum)); } else { - len = (int)strlen(ml_get(pos.lnum)); + len = ml_get_len(pos.lnum); } // We accept "$" for the column number: last column. @@ -6789,7 +6789,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret if (charcol) { pos.col = (colnr_T)mb_charlen(get_cursor_line_ptr()); } else { - pos.col = (colnr_T)strlen(get_cursor_line_ptr()); + pos.col = get_cursor_line_len(); } } return &pos; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index ab92aa7b34..1d5835c9bf 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -738,7 +738,7 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) if (fp->col == MAXCOL) { // '> can be MAXCOL, get the length of the line then if (fp->lnum <= curbuf->b_ml.ml_line_count) { - col = (colnr_T)strlen(ml_get(fp->lnum)) + 1; + col = ml_get_len(fp->lnum) + 1; } else { col = MAXCOL; } @@ -8688,7 +8688,7 @@ static void f_synID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) int id = 0; if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count - && col >= 0 && (size_t)col < strlen(ml_get(lnum))) { + && col >= 0 && col < ml_get_len(lnum)) { id = syn_get_id(curwin, lnum, col, trans, NULL, false); } @@ -8811,8 +8811,8 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr CLEAR_FIELD(str); - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0 - && (size_t)col <= strlen(ml_get(lnum)) && curwin->w_p_cole > 0) { + if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count + && col >= 0 && col <= ml_get_len(lnum) && curwin->w_p_cole > 0) { syn_get_id(curwin, lnum, col, false, NULL, false); syntax_flags = get_syntax_info(&matchid); @@ -8845,10 +8845,8 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const linenr_T lnum = tv_get_lnum(argvars); const colnr_T col = (colnr_T)tv_get_number(&argvars[1]) - 1; - if (lnum >= 1 - && lnum <= curbuf->b_ml.ml_line_count - && col >= 0 - && (size_t)col <= strlen(ml_get(lnum))) { + if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count + && col >= 0 && col <= ml_get_len(lnum)) { tv_list_alloc_ret(rettv, kListLenMayKnow); syn_get_id(curwin, lnum, col, false, NULL, true); @@ -9218,9 +9216,9 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (fp->col < 0) { fp->col = 0; } else { - const size_t len = strlen(ml_get(fp->lnum)); - if (fp->col > (colnr_T)len) { - fp->col = (colnr_T)len; + const colnr_T len = ml_get_len(fp->lnum); + if (fp->col > len) { + fp->col = len; } } getvvcol(curwin, fp, &vcol_start, NULL, &vcol_end); -- cgit From ac8cd5368db83cced9bc049ceb50c21cb8a4f743 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 12 Mar 2024 10:44:53 +0800 Subject: refactor: use ml_get_buf_len() in API code (#27825) --- src/nvim/api/buffer.c | 29 ++++++++++++++--------------- src/nvim/api/extmark.c | 16 ++++++++-------- src/nvim/api/private/helpers.c | 8 ++++---- src/nvim/lua/executor.c | 4 ++-- src/nvim/lua/stdlib.c | 6 +++--- src/nvim/lua/treesitter.c | 2 +- 6 files changed, 32 insertions(+), 33 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 7f195de959..035e36a2dd 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -529,18 +529,18 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // Another call to ml_get_buf() may free the lines, so we make copies char *str_at_start = ml_get_buf(buf, (linenr_T)start_row); - size_t len_at_start = strlen(str_at_start); - str_at_start = arena_memdupz(arena, str_at_start, len_at_start); - start_col = start_col < 0 ? (int64_t)len_at_start + start_col + 1 : start_col; - VALIDATE_RANGE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col", { + colnr_T len_at_start = ml_get_buf_len(buf, (linenr_T)start_row); + str_at_start = arena_memdupz(arena, str_at_start, (size_t)len_at_start); + start_col = start_col < 0 ? len_at_start + start_col + 1 : start_col; + VALIDATE_RANGE((start_col >= 0 && start_col <= len_at_start), "start_col", { return; }); char *str_at_end = ml_get_buf(buf, (linenr_T)end_row); - size_t len_at_end = strlen(str_at_end); - str_at_end = arena_memdupz(arena, str_at_end, len_at_end); - end_col = end_col < 0 ? (int64_t)len_at_end + end_col + 1 : end_col; - VALIDATE_RANGE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col", { + colnr_T len_at_end = ml_get_buf_len(buf, (linenr_T)end_row); + str_at_end = arena_memdupz(arena, str_at_end, (size_t)len_at_end); + end_col = end_col < 0 ? len_at_end + end_col + 1 : end_col; + VALIDATE_RANGE((end_col >= 0 && end_col <= len_at_end), "end_col", { return; }); @@ -563,12 +563,10 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In if (start_row == end_row) { old_byte = (bcount_t)end_col - start_col; } else { - old_byte += (bcount_t)len_at_start - start_col; + old_byte += len_at_start - start_col; for (int64_t i = 1; i < end_row - start_row; i++) { int64_t lnum = start_row + i; - - const char *bufline = ml_get_buf(buf, (linenr_T)lnum); - old_byte += (bcount_t)(strlen(bufline)) + 1; + old_byte += ml_get_buf_len(buf, (linenr_T)lnum) + 1; } old_byte += (bcount_t)end_col + 1; } @@ -577,7 +575,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In String last_item = replacement.items[replacement.size - 1].data.string; size_t firstlen = (size_t)start_col + first_item.size; - size_t last_part_len = len_at_end - (size_t)end_col; + size_t last_part_len = (size_t)len_at_end - (size_t)end_col; if (replacement.size == 1) { firstlen += last_part_len; } @@ -1324,7 +1322,7 @@ static void fix_cursor_cols(win_T *win, linenr_T start_row, colnr_T start_col, l // it already (in case virtualedit is active) // column might be additionally adjusted below // to keep it inside col range if needed - colnr_T len = (colnr_T)strlen(ml_get_buf(win->w_buffer, new_end_row)); + colnr_T len = ml_get_buf_len(win->w_buffer, new_end_row); if (win->w_cursor.col < len) { win->w_cursor.col = len; } @@ -1424,6 +1422,7 @@ void buf_collect_lines(buf_T *buf, size_t n, linenr_T start, int start_idx, bool for (size_t i = 0; i < n; i++) { linenr_T lnum = start + (linenr_T)i; char *bufstr = ml_get_buf(buf, lnum); - push_linestr(lstate, l, bufstr, strlen(bufstr), start_idx + (int)i, replace_nl, arena); + size_t bufstrlen = (size_t)ml_get_buf_len(buf, lnum); + push_linestr(lstate, l, bufstr, bufstrlen, start_idx + (int)i, replace_nl, arena); } } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 1b03a97edb..a21cf5b337 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -682,7 +682,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; }); - size_t len = 0; + colnr_T len = 0; if (HAS_KEY(opts, set_extmark, spell)) { hl.flags |= (opts->spell) ? kSHSpellOn : kSHSpellOff; @@ -712,16 +712,16 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer }); line = buf->b_ml.ml_line_count; } else if (line < buf->b_ml.ml_line_count) { - len = opts->ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line + 1)); + len = opts->ephemeral ? MAXCOL : ml_get_buf_len(buf, (linenr_T)line + 1); } if (col == -1) { - col = (Integer)len; - } else if (col > (Integer)len) { + col = len; + } else if (col > len) { VALIDATE_RANGE(!strict, "col", { goto error; }); - col = (Integer)len; + col = len; } else if (col < -1) { VALIDATE_RANGE(false, "col", { goto error; @@ -730,7 +730,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (col2 >= 0) { if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) { - len = opts->ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line2 + 1)); + len = opts->ephemeral ? MAXCOL : ml_get_buf_len(buf, (linenr_T)line2 + 1); } else if (line2 == buf->b_ml.ml_line_count) { // We are trying to add an extmark past final newline len = 0; @@ -738,11 +738,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer // reuse len from before line2 = (int)line; } - if (col2 > (Integer)len) { + if (col2 > len) { VALIDATE_RANGE(!strict, "end_col", { goto error; }); - col2 = (int)len; + col2 = len; } } else if (line2 >= 0) { col2 = 0; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 1cd98aa0c4..a17e78cc31 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -524,10 +524,10 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col } char *bufstr = ml_get_buf(buf, (linenr_T)lnum); - size_t line_length = strlen(bufstr); + colnr_T line_length = ml_get_buf_len(buf, (linenr_T)lnum); - start_col = start_col < 0 ? (int64_t)line_length + start_col + 1 : start_col; - end_col = end_col < 0 ? (int64_t)line_length + end_col + 1 : end_col; + start_col = start_col < 0 ? line_length + start_col + 1 : start_col; + end_col = end_col < 0 ? line_length + end_col + 1 : end_col; if (start_col >= MAXCOL || end_col >= MAXCOL) { api_set_error(err, kErrorTypeValidation, "Column index is too high"); @@ -539,7 +539,7 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col return rv; } - if ((size_t)start_col >= line_length) { + if (start_col >= line_length) { return rv; } diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1a9bd026b5..08677b77b0 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1767,7 +1767,7 @@ void ex_luado(exarg_T *const eap) lua_pushvalue(lstate, -1); const char *const old_line = ml_get_buf(curbuf, l); // Get length of old_line here as calling Lua code may free it. - const size_t old_line_len = strlen(old_line); + const colnr_T old_line_len = ml_get_buf_len(curbuf, l); lua_pushstring(lstate, old_line); lua_pushnumber(lstate, (lua_Number)l); if (nlua_pcall(lstate, 2, 1)) { @@ -1791,7 +1791,7 @@ void ex_luado(exarg_T *const eap) } } ml_replace(l, new_line_transformed, false); - inserted_bytes(l, 0, (int)old_line_len, (int)new_line_len); + inserted_bytes(l, 0, old_line_len, (int)new_line_len); } lua_pop(lstate, 1); } diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 8f58fd1a1a..a5262efcfa 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -107,15 +107,15 @@ static int regex_match_line(lua_State *lstate) } char *line = ml_get_buf(buf, rownr + 1); - size_t len = strlen(line); + colnr_T len = ml_get_buf_len(buf, rownr + 1); - if (start < 0 || (size_t)start > len) { + if (start < 0 || start > len) { return luaL_error(lstate, "invalid start"); } char save = NUL; if (end >= 0) { - if ((size_t)end > len || end < start) { + if (end > len || end < start) { return luaL_error(lstate, "invalid end"); } save = line[end]; diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 25a753b179..6d6ef6c7b9 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -371,7 +371,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position return ""; } char *line = ml_get_buf(bp, (linenr_T)position.row + 1); - size_t len = strlen(line); + size_t len = (size_t)ml_get_buf_len(bp, (linenr_T)position.row + 1); if (position.column > len) { *bytes_read = 0; return ""; -- cgit From a74e869ffa503cc9c2d21836e24fec7a7ffca147 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 12 Mar 2024 06:51:53 +0100 Subject: docs: small fixes (#27364) Co-authored-by: C.D. MacEachern Co-authored-by: Ynda Jas Co-authored-by: Owen Hines Co-authored-by: Wanten <41904684+WantenMN@users.noreply.github.com> Co-authored-by: lukasvrenner <118417051+lukasvrenner@users.noreply.github.com> Co-authored-by: cuinix <915115094@qq.com> --- src/nvim/generators/gen_api_dispatch.lua | 2 +- src/nvim/marktree.c | 4 ++-- src/nvim/move.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 04b4363e42..e9bc5e5fe3 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -259,7 +259,7 @@ put('version') fixdict(1 + #version) for _, item in ipairs(version) do -- NB: all items are mandatory. But any error will be less confusing - -- with placholder vim.NIL (than invalid mpack data) + -- with placeholder vim.NIL (than invalid mpack data) put(item[1], item[2] or vim.NIL) end put('build', version_build) diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 0ebebf409e..34d6cd118f 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -460,7 +460,7 @@ static void meta_describe_key(uint32_t *meta_inc, MTKey k) meta_describe_key_inc(meta_inc, &k); } -// if x is internal, asumes x->meta[..] of children are correct +// if x is internal, assumes x->meta[..] of children are correct static void meta_describe_node(uint32_t *meta_node, MTNode *x) { memset(meta_node, 0, kMTMetaCount * sizeof(meta_node[0])); @@ -1425,7 +1425,7 @@ bool marktree_itr_get_ext(MarkTree *b, MTPos p, MarkTreeIter *itr, bool last, bo } if (meta_filter) { if (!meta_has(itr->x->meta[itr->i], meta_filter)) { - // this takes us to the interal position after the first rejected node + // this takes us to the internal position after the first rejected node break; } } diff --git a/src/nvim/move.c b/src/nvim/move.c index 551aa1bd4d..0f7f4d8719 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -239,7 +239,7 @@ static void reset_skipcol(win_T *wp) redraw_later(wp, UPD_SOME_VALID); } -// Update curwin->w_topline to move the cursor onto the screen. +// Update wp->w_topline to move the cursor onto the screen. void update_topline(win_T *wp) { bool check_botline = false; @@ -595,7 +595,7 @@ void changed_line_abv_curs_win(win_T *wp) |VALID_CHEIGHT|VALID_TOPLINE); } -// Make sure the value of curwin->w_botline is valid. +// Make sure the value of wp->w_botline is valid. void validate_botline(win_T *wp) { if (!(wp->w_valid & VALID_BOTLINE)) { -- cgit From 3bd84317fb59ed4f7ec6585c516f9f8f4d823fd6 Mon Sep 17 00:00:00 2001 From: James <89495599+IAKOBVS@users.noreply.github.com> Date: Tue, 12 Mar 2024 13:35:53 +0700 Subject: refactor: avoid quadratic behavior in backslash_halve() (#27827) The original implementation has a worst-case of O(n^2). Every time rem_backslash() is true, it calculates the length of the rest of the string, and shift the rest of it to the left; backslash_halve_save() copies the original string before doing backslash_halve(). The new implementation is O(n). It will find the first character where rem_backslash() is true (it will do nothing if it's always false), and shift the characters in-place; backslash_halve_save() avoids copying the original string before doing backslash_halve(). --- src/nvim/charset.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 20bd364c7e..2e6f24b2d5 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1457,10 +1457,20 @@ bool rem_backslash(const char *str) /// @param p void backslash_halve(char *p) { - for (; *p; p++) { - if (rem_backslash(p)) { - STRMOVE(p, p + 1); + for (; *p && !rem_backslash(p); p++) {} + if (*p != NUL) { + char *dst = p; + goto start; + while (*p != NUL) { + if (rem_backslash(p)) { +start: + *dst++ = *(p + 1); + p += 2; + } else { + *dst++ = *p++; + } } + *dst = '\0'; } } @@ -1472,8 +1482,16 @@ void backslash_halve(char *p) char *backslash_halve_save(const char *p) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - // TODO(philix): simplify and improve backslash_halve_save algorithm - char *res = xstrdup(p); - backslash_halve(res); + char *res = xmalloc(strlen(p) + 1); + char *dst = res; + while (*p != NUL) { + if (rem_backslash(p)) { + *dst++ = *(p + 1); + p += 2; + } else { + *dst++ = *p++; + } + } + *dst = '\0'; return res; } -- cgit From 119390e7ce3fe4f4f3da8bdd963ea10ec8976a3a Mon Sep 17 00:00:00 2001 From: James <89495599+IAKOBVS@users.noreply.github.com> Date: Wed, 13 Mar 2024 03:34:59 +0700 Subject: refactor: avoid copying before vim_strup() if possible (#27830) Current uses of vim_strup() calls memcpy()/strcpy() before calling vim_strup(). This results in 2 * strlen(string) operations. We can trivially convert to lowercase while copying the string instead. --- src/nvim/highlight_group.c | 8 +++----- src/nvim/strings.c | 41 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 9 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 75c23c5bc4..1474a2ba06 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -1149,9 +1149,8 @@ void do_highlight(const char *line, const bool forceit, const bool init) error = true; break; } - memcpy(key, key_start, key_len); - key[key_len] = NUL; - vim_strup(key); + vim_memcpy_up(key, key_start, key_len); + key[key_len] = '\0'; linep = skipwhite(linep); if (strcmp(key, "NONE") == 0) { @@ -1943,9 +1942,8 @@ int syn_name2id_len(const char *name, size_t len) // Avoid using stricmp() too much, it's slow on some systems */ // Avoid alloc()/free(), these are slow too. - memcpy(name_u, name, len); + vim_memcpy_up(name_u, name, len); name_u[len] = '\0'; - vim_strup(name_u); // map_get(..., int) returns 0 when no key is present, which is // the expected value for missing highlight group. diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 01bd610292..f9b945f1da 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -299,8 +299,8 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli char *vim_strsave_up(const char *string) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char *p1 = xstrdup(string); - vim_strup(p1); + char *p1 = xmalloc(strlen(string) + 1); + vim_strcpy_up(p1, string); return p1; } @@ -309,8 +309,8 @@ char *vim_strsave_up(const char *string) char *vim_strnsave_up(const char *string, size_t len) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char *p1 = xstrnsave(string, len); - vim_strup(p1); + char *p1 = xmalloc(len + 1); + vim_strncpy_up(p1, string, len); return p1; } @@ -324,6 +324,39 @@ void vim_strup(char *p) } } +// strcpy plus vim_strup. +void vim_strcpy_up(char *restrict dst, const char *restrict src) + FUNC_ATTR_NONNULL_ALL +{ + uint8_t c; + while ((c = (uint8_t)(*src++)) != NUL) { + *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); + } + *dst = '\0'; +} + +// strncpy (NUL-terminated) plus vim_strup. +void vim_strncpy_up(char *restrict dst, const char *restrict src, size_t n) + FUNC_ATTR_NONNULL_ALL +{ + uint8_t c; + while (n-- && (c = (uint8_t)(*src++)) != NUL) { + *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); + } + *dst = '\0'; +} + +// memcpy (does not NUL-terminate) plus vim_strup. +void vim_memcpy_up(char *restrict dst, const char *restrict src, size_t n) + FUNC_ATTR_NONNULL_ALL +{ + uint8_t c; + while (n--) { + c = (uint8_t)(*src++); + *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); + } +} + /// Make given string all upper-case or all lower-case /// /// Handles multi-byte characters as good as possible. -- cgit From 29d0ed577c7d283402c84df602a031a25349eb59 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:02:29 +0000 Subject: vim-patch:9.1.0169: current window number returned by tabpagewinnr may be outdated Problem: current window number returned by tabpagewinnr may be outdated when called from win_execute for the original tabpage. Solution: update the original tabpage's tp_curwin in switch_win; use {un}use_tabpage instead. Don't do it in restore_win to ensure tp_curwin of the temporarily visited tabpage is unchanged from switch_win visiting it, as before. (Sean Dewar) Maybe restore_win should only restore tp_curwin if `curtab == switchwin->sw_curtab`, in case the user changed tabpages from within win_execute, but not doing that is consistent with the old behaviour. related: vim/vim#14186 https://github.com/vim/vim/commit/e101028a5c896480c61fef7ea16855255925709b --- src/nvim/eval/window.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index e54f46dcc3..26624c8dd7 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -956,13 +956,8 @@ int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool n if (tp != NULL) { switchwin->sw_curtab = curtab; if (no_display) { - curtab->tp_firstwin = firstwin; - curtab->tp_lastwin = lastwin; - curtab->tp_topframe = topframe; - curtab = tp; - firstwin = curtab->tp_firstwin; - lastwin = curtab->tp_lastwin; - topframe = curtab->tp_topframe; + unuse_tabpage(curtab); + use_tabpage(tp); } else { goto_tabpage_tp(tp, false, false); } @@ -989,13 +984,12 @@ void restore_win_noblock(switchwin_T *switchwin, bool no_display) { if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) { if (no_display) { - curtab->tp_firstwin = firstwin; - curtab->tp_lastwin = lastwin; - curtab->tp_topframe = topframe; - curtab = switchwin->sw_curtab; - firstwin = curtab->tp_firstwin; - lastwin = curtab->tp_lastwin; - topframe = curtab->tp_topframe; + win_T *const old_tp_curwin = curtab->tp_curwin; + + unuse_tabpage(curtab); + // Don't change the curwin of the tabpage we temporarily visited. + curtab->tp_curwin = old_tp_curwin; + use_tabpage(switchwin->sw_curtab); } else { goto_tabpage_tp(switchwin->sw_curtab, false, false); } -- cgit From ca7b603d02ecd1ed4098f487cd01acd470ca6a74 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:08:50 +0000 Subject: vim-patch:9.1.0170: Re-allow curwin == prevwin, but document it instead Problem: more places exist where curwin == prevwin, and it may even be expected in some cases. Solution: revert v9.1.0001, but document that it's possible instead. (Sean Dewar) I've had a change of heart for the following reasons: - A quick 'n dirty [GitHub code search](https://github.com/search?q=%2F%28winnr%5C%28%5C%29%5Cs*%3D%3D%5Cs*winnr%5C%28%5B%27%22%5D%23%5B%27%22%5D%5C%29%7Cwinnr%5C%28%5B%27%22%5D%23%5B%27%22%5D%5C%29%5Cs*%3D%3D%5Cs*winnr%5C%28%5C%29%29%2F&type=code) reveals some cases where it's expected in the wild. Particularly, it made me aware `winnr() == winnr('#')` is possible when curwin is changed temporarily during the evaluation of a &statusline expression item (`%{...}`), and is used to show something different on the statusline belonging to the previous window; that behaviour wasn't changed in v9.1.0001, but it means curwin == prevwin makes sense in some cases. - The definition and call sites of back_to_prevwin imply some expectation that prevwin == wp (== curwin) is possible, as it's used to skip entering the prevwin in that case. - Prior to v9.1.0001, `:wincmd p` would not beep in the case that was patched in v9.1.0001, but now does. That resulted in vim/vim#14047 being opened, as it affected the CtrlP plugin. I find it odd that `:wincmd p` had cases where it wouldn't beep despite doing nothing, but it may be preferable to keep things that way (or instead also beep if curwin == prevwin, if that's preferred). - After more digging, I found cases in win_free_mem, enter_tabpage, aucmd_restbuf and qf_open_new_cwindow where curwin == prevwin is possible (many of them from autocommands). Others probably exist too, especially in places where curwin is changed temporarily. fixes: vim/vim#14047 closes: vim/vim#14186 https://github.com/vim/vim/commit/d64801e913314d2e19dbb38f60e6d285238debff --- src/nvim/eval.lua | 4 +++- src/nvim/globals.h | 2 +- src/nvim/window.c | 4 ---- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index febd022254..73715e2631 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -12856,7 +12856,9 @@ M.funcs = { # the number of the last accessed window (where |CTRL-W_p| goes to). If there is no previous window or it is in another tab page 0 is - returned. + returned. May refer to the current window in + some cases (e.g. when evaluating 'statusline' + expressions). {N}j the number of the Nth window below the current window (where |CTRL-W_j| goes to). {N}k the number of the Nth window above the current diff --git a/src/nvim/globals.h b/src/nvim/globals.h index aecb9d1116..06fb95b577 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -363,7 +363,7 @@ EXTERN bool sys_menu INIT( = false); // currently active window. EXTERN win_T *firstwin; // first window EXTERN win_T *lastwin; // last window -EXTERN win_T *prevwin INIT( = NULL); // previous window +EXTERN win_T *prevwin INIT( = NULL); // previous window (may equal curwin) #define ONE_WINDOW (firstwin == lastwin) #define FOR_ALL_FRAMES(frp, first_frame) \ for ((frp) = first_frame; (frp) != NULL; (frp) = (frp)->fr_next) diff --git a/src/nvim/window.c b/src/nvim/window.c index 521699f2f0..843cf154a7 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4915,14 +4915,10 @@ static void win_enter_ext(win_T *const wp, const int flags) if (wp->w_buffer != curbuf) { buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP); } - if (!curwin_invalid) { prevwin = curwin; // remember for CTRL-W p curwin->w_redr_status = true; - } else if (wp == prevwin) { - prevwin = NULL; // don't want it to be the new curwin } - curwin = wp; curbuf = wp->w_buffer; -- cgit From 6bbb02d9ba76551dd4856ad50a237e92c678702d Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:19:18 +0000 Subject: vim-patch:9.1.0171: Small split-move related improvements Problem: small improvements can be made to split-move related functions. Solution: apply them (Sean Dewar): Some of these changes were already applied to Nvim. Here are the ones which were missing: - Improve some doc comments (frame_flatten should still work for non-current tabpages, despite the topframe check, which looks benign, though I'm unsure if it's still needed; see vim/vim#2467). - f_win_splitmove should check_split_disallowed on wp, not targetwin, as that's what win_splitmove checks (though it's probably unnecessary to check b_locked_split at all; see vim/vim#14109, which I hope to get around to finishing at some point). - Apply the winframe_restore comment changes, and remove win_comp_pos from after winframe_restore in win_splitmove, as it shouldn't be necessary (no need to remove it from nvim_win_set_config too, as it was already omitted). Move win_append after winframe_restore in win_splitmove to match Vim. closes: vim/vim#14185 https://github.com/vim/vim/commit/5cac1a9bee0798d70a7fd80363a1f697759638e8 --- src/nvim/eval/window.c | 4 ++-- src/nvim/window.c | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 26624c8dd7..3e2f6301ca 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -701,8 +701,8 @@ void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) size = (int)tv_dict_get_number(d, "size"); } - // Check if we can split the target before we bother switching windows. - if (is_aucmd_win(wp) || text_or_buf_locked() || check_split_disallowed(targetwin) == FAIL) { + // Check if we're allowed to continue before we bother switching windows. + if (is_aucmd_win(wp) || text_or_buf_locked() || check_split_disallowed(wp) == FAIL) { return; } diff --git a/src/nvim/window.c b/src/nvim/window.c index 843cf154a7..9468207d41 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -939,7 +939,7 @@ void ui_ext_win_viewport(win_T *wp) } } -/// If "split_disallowed" is set or "wp"s buffer is closing, give an error and return FAIL. +/// If "split_disallowed" is set, or "wp"'s buffer is closing, give an error and return FAIL. /// Otherwise return OK. int check_split_disallowed(const win_T *wp) FUNC_ATTR_NONNULL_ALL @@ -1966,13 +1966,12 @@ int win_splitmove(win_T *wp, int size, int flags) // Split a window on the desired side and put "wp" there. if (win_split_ins(size, flags, wp, dir, unflat_altfr) == NULL) { - win_append(wp->w_prev, wp, NULL); if (!wp->w_floating) { // win_split_ins doesn't change sizes or layout if it fails to insert an // existing window, so just undo winframe_remove. winframe_restore(wp, dir, unflat_altfr); - win_comp_pos(); // recompute window positions } + win_append(wp->w_prev, wp, NULL); return FAIL; } @@ -3271,7 +3270,6 @@ win_T *winframe_find_altwin(win_T *win, int *dirp, tabpage_T *tp, frame_T **altf /// Flatten "frp" into its parent frame if it's the only child, also merging its /// list with the grandparent if they share the same layout. /// Frees "frp" if flattened; also "frp->fr_parent" if it has the same layout. -/// "frp" must be valid in the current tabpage. static void frame_flatten(frame_T *frp) FUNC_ATTR_NONNULL_ALL { @@ -3359,7 +3357,8 @@ void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) int row = wp->w_winrow; int col = wp->w_wincol; - // Restore the lost room that was redistributed to the altframe. + // Restore the lost room that was redistributed to the altframe. Also + // adjusts window sizes to fit restored statuslines/separators, if needed. if (dir == 'v') { frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height, unflat_altfr == frp->fr_next, false); -- cgit From c048beef6c034a46e324fcea7210082d48db32ee Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:41:35 +0000 Subject: vim-patch:9a660d2883f9 runtime(doc): add reference to matchbufline() at :h search() related: vim/vim#14173 https://github.com/vim/vim/commit/9a660d2883f92b3a3761c964dc14363a8f70c8d8 Co-authored-by: Christian Brabandt --- src/nvim/eval.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 73715e2631..96dc32259f 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -8746,6 +8746,7 @@ M.funcs = { When a match has been found its line number is returned. If there is no match a 0 is returned and the cursor doesn't move. No error message is given. + To get the matched string, use |matchbufline()|. {flags} is a String, which can contain these character flags: 'b' search Backward instead of forward -- cgit From 93c93a0e3646a205013f439013e22d674b224cdb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 13 Mar 2024 11:27:04 +0800 Subject: refactor: remove "once" argument of loop_uv_run() (#27841) It is always set to true when used, and makes the code a bit confusing. --- src/nvim/event/loop.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c index 93948d3eaa..e1ebcecbd6 100644 --- a/src/nvim/event/loop.c +++ b/src/nvim/event/loop.c @@ -39,10 +39,8 @@ void loop_init(Loop *loop, void *data) /// @param ms 0: non-blocking poll. /// > 0: timeout after `ms`. /// < 0: wait forever. -/// @param once true: process at most one `Loop.uv` event. -/// false: process until `ms` timeout (only has effect if `ms` > 0). /// @return true if `ms` > 0 and was reached -bool loop_uv_run(Loop *loop, int64_t ms, bool once) +static bool loop_uv_run(Loop *loop, int64_t ms) { if (loop->recursive++) { abort(); // Should not re-enter uv_run @@ -60,9 +58,7 @@ bool loop_uv_run(Loop *loop, int64_t ms, bool once) mode = UV_RUN_NOWAIT; } - do { - uv_run(&loop->uv, mode); - } while (ms > 0 && !once && !*timeout_expired); + uv_run(&loop->uv, mode); if (ms > 0) { uv_timer_stop(&loop->poll_timer); @@ -83,7 +79,7 @@ bool loop_uv_run(Loop *loop, int64_t ms, bool once) /// @return true if `ms` > 0 and was reached bool loop_poll_events(Loop *loop, int64_t ms) { - bool timeout_expired = loop_uv_run(loop, ms, true); + bool timeout_expired = loop_uv_run(loop, ms); multiqueue_process_events(loop->fast_events); return timeout_expired; } -- cgit From d5488633f68fcfd58b4bcad654ab103b4746204b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 13 Mar 2024 11:36:41 +0800 Subject: fix(drawline): initialize linebuf_attr to 0 instead of -1 (#27840) This also obviates the end-of-line loop when there is virtual text. --- src/nvim/drawline.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 4281cdff33..c5f6ce2e36 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -288,26 +288,23 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int if (item->draw_col < 0) { continue; } - int col = 0; if (item->kind == kDecorKindUIWatched) { // send mark position to UI - col = item->draw_col; - WinExtmark m = { (NS)item->data.ui.ns_id, item->data.ui.mark_id, win_row, col }; + WinExtmark m = { (NS)item->data.ui.ns_id, item->data.ui.mark_id, win_row, item->draw_col }; kv_push(win_extmark_arr, m); } if (vt) { int vcol = item->draw_col - col_off; - col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text, - vt->hl_mode, max_col, vcol); + int col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text, + vt->hl_mode, max_col, vcol); if (vt->pos == kVPosEndOfLine && do_eol) { state->eol_col = col + 1; } + *end_col = MAX(*end_col, col); } if (!vt || !(vt->flags & kVTRepeatLinebreak)) { item->draw_col = INT_MIN; // deactivate } - - *end_col = MAX(*end_col, col); } } @@ -898,7 +895,7 @@ static void win_line_start(win_T *wp, winlinevars_T *wlv) wlv->need_lbr = false; for (int i = 0; i < wp->w_grid.cols; i++) { linebuf_char[i] = schar_from_ascii(' '); - linebuf_attr[i] = -1; + linebuf_attr[i] = 0; linebuf_vcol[i] = -1; } } @@ -2569,13 +2566,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s advance_color_col(&wlv, vcol_hlc(wlv)); - bool has_virttext = false; // Make sure alignment is the same regardless // if listchars=eol:X is used or not. const int eol_skip = (lcs_eol_todo && eol_hl_off == 0 ? 1 : 0); if (has_decor) { - has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip); + decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip); } if (((wp->w_p_cuc @@ -2583,7 +2579,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && wp->w_virtcol < grid->cols * (ptrdiff_t)(wlv.row - startrow + 1) + start_col && lnum != wp->w_cursor.lnum) || wlv.color_cols || wlv.line_attr_lowprio || wlv.line_attr - || wlv.diff_hlf != 0 || has_virttext)) { + || wlv.diff_hlf != 0)) { int rightmost_vcol = get_rightmost_vcol(wp, wlv.color_cols); const int cuc_attr = win_hl_attr(wp, HLF_CUC); const int mc_attr = win_hl_attr(wp, HLF_MC); @@ -2597,7 +2593,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s : 0; const int base_attr = hl_combine_attr(wlv.line_attr_lowprio, diff_attr); - if (base_attr || wlv.line_attr || has_virttext) { + if (base_attr || wlv.line_attr) { rightmost_vcol = INT_MAX; } @@ -2624,7 +2620,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s break; } - wlv.vcol += 1; + wlv.vcol++; } } -- cgit From 08fc1ebbaa49e3110b65bddeed28d2e61a96f5d9 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 11 Mar 2024 13:19:49 +0100 Subject: fix(api/buffer): fix handling of viewport of non-current buffer A lot of functions in move.c only worked for curwin, alternatively took a `wp` arg but still only work if that happens to be curwin. Refactor those that are needed for update_topline(wp) to work for any window. fixes #27723 fixes #27720 --- src/nvim/api/buffer.c | 11 +- src/nvim/api/extmark.c | 4 +- src/nvim/api/window.c | 4 +- src/nvim/autocmd.c | 6 +- src/nvim/buffer.c | 8 +- src/nvim/change.c | 6 +- src/nvim/cursor.c | 87 +++--- src/nvim/decoration.c | 4 +- src/nvim/diff.c | 13 +- src/nvim/drawline.c | 6 +- src/nvim/drawscreen.c | 14 +- src/nvim/edit.c | 70 ++--- src/nvim/eval/buffer.c | 6 +- src/nvim/eval/funcs.c | 16 +- src/nvim/eval/window.c | 12 +- src/nvim/ex_cmds.c | 12 +- src/nvim/ex_cmds2.c | 2 +- src/nvim/ex_docmd.c | 54 ++-- src/nvim/ex_getln.c | 10 +- src/nvim/fileio.c | 2 +- src/nvim/fold.c | 34 +-- src/nvim/getchar.c | 4 +- src/nvim/indent.c | 4 +- src/nvim/insexpand.c | 4 +- src/nvim/lua/executor.c | 2 +- src/nvim/mark.c | 2 +- src/nvim/match.c | 2 +- src/nvim/memline.c | 6 +- src/nvim/menu.c | 4 +- src/nvim/mouse.c | 12 +- src/nvim/move.c | 795 +++++++++++++++++++++++------------------------- src/nvim/normal.c | 184 +++++------ src/nvim/ops.c | 68 ++--- src/nvim/option.c | 10 +- src/nvim/optionstr.c | 5 +- src/nvim/plines.c | 8 +- src/nvim/popupmenu.c | 6 +- src/nvim/quickfix.c | 6 +- src/nvim/search.c | 10 +- src/nvim/state.c | 4 +- src/nvim/state.h | 1 + src/nvim/tag.c | 6 +- src/nvim/terminal.c | 4 +- src/nvim/textformat.c | 12 +- src/nvim/textobject.c | 12 +- src/nvim/undo.c | 10 +- src/nvim/window.c | 14 +- 47 files changed, 772 insertions(+), 804 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 035e36a2dd..42467d1562 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1269,10 +1269,13 @@ static void fix_cursor(win_T *win, linenr_T lo, linenr_T hi, linenr_T extra) } else if (extra < 0) { check_cursor_lnum(win); } - check_cursor_col_win(win); + check_cursor_col(win); changed_cline_bef_curs(win); + win->w_valid &= ~(VALID_BOTLINE_AP); + update_topline(win); + } else { + invalidate_botline(win); } - invalidate_botline(win); } /// Fix cursor position after replacing text @@ -1307,7 +1310,7 @@ static void fix_cursor_cols(win_T *win, linenr_T start_row, colnr_T start_col, l // it's easier to work with a single value here. // col and coladd are fixed by a later call - // to check_cursor_col_win when necessary + // to check_cursor_col when necessary win->w_cursor.col += win->w_cursor.coladd; win->w_cursor.coladd = 0; @@ -1343,7 +1346,7 @@ static void fix_cursor_cols(win_T *win, linenr_T start_row, colnr_T start_col, l } } - check_cursor_col_win(win); + check_cursor_col(win); changed_cline_bef_curs(win); invalidate_botline(win); } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index a21cf5b337..b5f56d270c 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1246,7 +1246,7 @@ Boolean nvim_win_add_ns(Window window, Integer ns_id, Error *err) set_put(uint32_t, &win->w_ns_set, (uint32_t)ns_id); - changed_window_setting_win(win); + changed_window_setting(win); return true; } @@ -1291,7 +1291,7 @@ Boolean nvim_win_remove_ns(Window window, Integer ns_id, Error *err) set_del(uint32_t, &win->w_ns_set, (uint32_t)ns_id); - changed_window_setting_win(win); + changed_window_setting(win); return true; } diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 1a80e9ea16..026d09d9a9 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -138,7 +138,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) win->w_cursor.col = (colnr_T)col; win->w_cursor.coladd = 0; // When column is out of range silently correct it. - check_cursor_col_win(win); + check_cursor_col(win); // Make sure we stick in this column. win->w_set_curswant = true; @@ -148,7 +148,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) switchwin_T switchwin; switch_win(&switchwin, win, NULL, true); update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); restore_win(&switchwin, true); redraw_later(win, UPD_VALID); diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 652b6ba74e..285ef538b9 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1432,7 +1432,7 @@ win_found: // the buffer contents may have changed VIsual_active = aco->save_VIsual_active; - check_cursor(); + check_cursor(curwin); if (curwin->w_topline > curbuf->b_ml.ml_line_count) { curwin->w_topline = curbuf->b_ml.ml_line_count; curwin->w_topfill = 0; @@ -1464,12 +1464,12 @@ win_found: // In case the autocommand moves the cursor to a position that does not // exist in curbuf VIsual_active = aco->save_VIsual_active; - check_cursor(); + check_cursor(curwin); } } VIsual_active = aco->save_VIsual_active; - check_cursor(); // just in case lines got deleted + check_cursor(curwin); // just in case lines got deleted if (VIsual_active) { check_pos(curbuf, &VIsual); } diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index e141706edd..3c2d52e6ad 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1752,7 +1752,7 @@ void enter_buffer(buf_T *buf) maketitle(); // when autocmds didn't change it if (curwin->w_topline == 1 && !curwin->w_topline_was_set) { - scroll_cursor_halfway(false, false); // redisplay at correct position + scroll_cursor_halfway(curwin, false, false); // redisplay at correct position } // Change directories when the 'acd' option is set. @@ -2172,7 +2172,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit) // cursor is at to BOL and w_cursor.lnum is checked due to getfile() if (!p_sol && col != 0) { curwin->w_cursor.col = col; - check_cursor_col(); + check_cursor_col(curwin); curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; } @@ -2197,7 +2197,7 @@ void buflist_getfpos(void) curwin->w_cursor.col = 0; } else { curwin->w_cursor.col = fpos->col; - check_cursor_col(); + check_cursor_col(curwin); curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; } @@ -3257,7 +3257,7 @@ void fileinfo(int fullname, int shorthelp, bool dont_truncate) (int64_t)curwin->w_cursor.lnum, (int64_t)curbuf->b_ml.ml_line_count, n); - validate_virtcol(); + validate_virtcol(curwin); size_t len = strlen(buffer); col_print(buffer + len, IOSIZE - len, (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); diff --git a/src/nvim/change.c b/src/nvim/change.c index 8b1e7587de..673907fa27 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -707,7 +707,7 @@ void ins_char(int c) void ins_char_bytes(char *buf, size_t charlen) { // Break tabs if needed. - if (virtual_active() && curwin->w_cursor.coladd > 0) { + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { coladvance_force(getviscol()); } @@ -815,7 +815,7 @@ void ins_str(char *s) int newlen = (int)strlen(s); linenr_T lnum = curwin->w_cursor.lnum; - if (virtual_active() && curwin->w_cursor.coladd > 0) { + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { coladvance_force(getviscol()); } @@ -918,7 +918,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) // fixpos is true, we don't want to end up positioned at the NUL, // unless "restart_edit" is set or 'virtualedit' contains "onemore". if (col > 0 && fixpos && restart_edit == 0 - && (get_ve_flags() & VE_ONEMORE) == 0) { + && (get_ve_flags(curwin) & VE_ONEMORE) == 0) { curwin->w_cursor.col--; curwin->w_cursor.coladd = 0; curwin->w_cursor.col -= utf_head_off(oldp, oldp + curwin->w_cursor.col); diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index ab99d1b854..c3f5a36500 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -57,7 +57,7 @@ int getviscol2(colnr_T col, colnr_T coladd) /// The caller must have saved the cursor line for undo! int coladvance_force(colnr_T wcol) { - int rc = coladvance2(&curwin->w_cursor, true, false, wcol); + int rc = coladvance2(curwin, &curwin->w_cursor, true, false, wcol); if (wcol == MAXCOL) { curwin->w_valid &= ~VALID_VIRTCOL; @@ -76,25 +76,26 @@ int coladvance_force(colnr_T wcol) /// beginning at coladd 0. /// /// @return OK if desired column is reached, FAIL if not -int coladvance(colnr_T wcol) +int coladvance(win_T *wp, colnr_T wcol) { - int rc = getvpos(&curwin->w_cursor, wcol); + int rc = getvpos(wp, &wp->w_cursor, wcol); if (wcol == MAXCOL || rc == FAIL) { - curwin->w_valid &= ~VALID_VIRTCOL; - } else if (*get_cursor_pos_ptr() != TAB) { + wp->w_valid &= ~VALID_VIRTCOL; + } else if (*(ml_get_buf(wp->w_buffer, wp->w_cursor.lnum) + wp->w_cursor.col) != TAB) { // Virtcol is valid when not on a TAB - curwin->w_valid |= VALID_VIRTCOL; - curwin->w_virtcol = wcol; + wp->w_valid |= VALID_VIRTCOL; + wp->w_virtcol = wcol; } return rc; } -/// @param addspaces change the text to achieve our goal? +/// @param addspaces change the text to achieve our goal? only for wp=curwin! /// @param finetune change char offset for the exact column /// @param wcol_arg column to move to (can be negative) -static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_arg) +static int coladvance2(win_T *wp, pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_arg) { + assert(wp == curwin || !addspaces); colnr_T wcol = wcol_arg; int idx; colnr_T col = 0; @@ -104,30 +105,30 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a || (State & MODE_TERMINAL) || restart_edit != NUL || (VIsual_active && *p_sel != 'o') - || ((get_ve_flags() & VE_ONEMORE) && wcol < MAXCOL); + || ((get_ve_flags(wp) & VE_ONEMORE) && wcol < MAXCOL); - char *line = ml_get_buf(curbuf, pos->lnum); + char *line = ml_get_buf(wp->w_buffer, pos->lnum); if (wcol >= MAXCOL) { idx = (int)strlen(line) - 1 + one_more; col = wcol; if ((addspaces || finetune) && !VIsual_active) { - curwin->w_curswant = linetabsize(curwin, pos->lnum) + one_more; - if (curwin->w_curswant > 0) { - curwin->w_curswant--; + wp->w_curswant = linetabsize(wp, pos->lnum) + one_more; + if (wp->w_curswant > 0) { + wp->w_curswant--; } } } else { - int width = curwin->w_width_inner - win_col_off(curwin); + int width = wp->w_width_inner - win_col_off(wp); int csize = 0; if (finetune - && curwin->w_p_wrap - && curwin->w_width_inner != 0 + && wp->w_p_wrap + && wp->w_width_inner != 0 && wcol >= (colnr_T)width && width > 0) { - csize = linetabsize(curwin, pos->lnum); + csize = linetabsize(wp, pos->lnum); if (csize > 0) { csize--; } @@ -143,7 +144,7 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a } CharsizeArg csarg; - CSType cstype = init_charsize_arg(&csarg, curwin, pos->lnum, line); + CSType cstype = init_charsize_arg(&csarg, wp, pos->lnum, line); StrCharInfo ci = utf_ptr2StrCharInfo(line); col = 0; while (col <= wcol && *ci.ptr != NUL) { @@ -159,14 +160,14 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a // is needed to ensure that a virtual position off the end of // a line has the correct indexing. The one_more comparison // replaces an explicit add of one_more later on. - if (col > wcol || (!virtual_active() && one_more == 0)) { + if (col > wcol || (!virtual_active(wp) && one_more == 0)) { idx -= 1; // Don't count the chars from 'showbreak'. csize -= head; col -= csize; } - if (virtual_active() + if (virtual_active(wp) && addspaces && wcol >= 0 && ((col != wcol && col != wcol + 1) || csize > 1)) { @@ -229,14 +230,14 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a if (!one_more) { colnr_T scol, ecol; - getvcol(curwin, pos, &scol, NULL, &ecol); + getvcol(wp, pos, &scol, NULL, &ecol); pos->coladd = ecol - scol; } } else { int b = (int)wcol - (int)col; // The difference between wcol and col is used to set coladd. - if (b > 0 && b < (MAXCOL - 2 * curwin->w_width_inner)) { + if (b > 0 && b < (MAXCOL - 2 * wp->w_width_inner)) { pos->coladd = b; } @@ -245,7 +246,7 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a } // Prevent from moving onto a trail byte. - mark_mb_adjustpos(curbuf, pos); + mark_mb_adjustpos(wp->w_buffer, pos); if (wcol < 0 || col < wcol) { return FAIL; @@ -256,9 +257,9 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a /// Return in "pos" the position of the cursor advanced to screen column "wcol". /// /// @return OK if desired column is reached, FAIL if not -int getvpos(pos_T *pos, colnr_T wcol) +int getvpos(win_T *wp, pos_T *pos, colnr_T wcol) { - return coladvance2(pos, false, virtual_active(), wcol); + return coladvance2(wp, pos, false, virtual_active(wp), wcol); } /// Increment the cursor position. See inc() for return values. @@ -294,7 +295,7 @@ linenr_T get_cursor_rel_lnum(win_T *wp, linenr_T lnum) // Loop until we reach to_line, skipping folds. for (; from_line < to_line; from_line++, retval++) { // If from_line is in a fold, set it to the last line of that fold. - hasFoldingWin(wp, from_line, NULL, &from_line, true, NULL); + hasFolding(wp, from_line, NULL, &from_line); } // If to_line is in a closed fold, the line count is off by +1. Correct it. @@ -329,7 +330,7 @@ void check_cursor_lnum(win_T *win) if (win->w_cursor.lnum > buf->b_ml.ml_line_count) { // If there is a closed fold at the end of the file, put the cursor in // its first line. Otherwise in the last line. - if (!hasFolding(buf->b_ml.ml_line_count, &win->w_cursor.lnum, NULL)) { + if (!hasFolding(win, buf->b_ml.ml_line_count, &win->w_cursor.lnum, NULL)) { win->w_cursor.lnum = buf->b_ml.ml_line_count; } } @@ -338,19 +339,13 @@ void check_cursor_lnum(win_T *win) } } -/// Make sure curwin->w_cursor.col is valid. -void check_cursor_col(void) -{ - check_cursor_col_win(curwin); -} - /// Make sure win->w_cursor.col is valid. Special handling of insert-mode. /// @see mb_check_adjust_col -void check_cursor_col_win(win_T *win) +void check_cursor_col(win_T *win) { colnr_T oldcol = win->w_cursor.col; colnr_T oldcoladd = win->w_cursor.col + win->w_cursor.coladd; - unsigned cur_ve_flags = get_ve_flags(); + unsigned cur_ve_flags = get_ve_flags(win); colnr_T len = (colnr_T)strlen(ml_get_buf(win->w_buffer, win->w_cursor.lnum)); if (len == 0) { @@ -363,7 +358,7 @@ void check_cursor_col_win(win_T *win) if ((State & MODE_INSERT) || restart_edit || (VIsual_active && *p_sel != 'o') || (cur_ve_flags & VE_ONEMORE) - || virtual_active()) { + || virtual_active(win)) { win->w_cursor.col = len; } else { win->w_cursor.col = len - 1; @@ -403,10 +398,10 @@ void check_cursor_col_win(win_T *win) } /// Make sure curwin->w_cursor in on a valid character -void check_cursor(void) +void check_cursor(win_T *wp) { - check_cursor_lnum(curwin); - check_cursor_col(); + check_cursor_lnum(wp); + check_cursor_col(wp); } /// Check if VIsual position is valid, correct it if not. @@ -453,8 +448,8 @@ bool set_leftcol(colnr_T leftcol) changed_cline_bef_curs(curwin); // TODO(hinidu): I think it should be colnr_T or int, but p_siso is long. // Perhaps we can change p_siso to int. - int64_t lastcol = curwin->w_leftcol + curwin->w_width_inner - curwin_col_off() - 1; - validate_virtcol(); + int64_t lastcol = curwin->w_leftcol + curwin->w_width_inner - win_col_off(curwin) - 1; + validate_virtcol(curwin); bool retval = false; // If the cursor is right or left of the screen, move it to last or first @@ -462,10 +457,10 @@ bool set_leftcol(colnr_T leftcol) int siso = get_sidescrolloff_value(curwin); if (curwin->w_virtcol > (colnr_T)(lastcol - siso)) { retval = true; - coladvance((colnr_T)(lastcol - siso)); + coladvance(curwin, (colnr_T)(lastcol - siso)); } else if (curwin->w_virtcol < curwin->w_leftcol + siso) { retval = true; - coladvance((colnr_T)(curwin->w_leftcol + siso)); + coladvance(curwin, (colnr_T)(curwin->w_leftcol + siso)); } // If the start of the character under the cursor is not on the screen, @@ -475,10 +470,10 @@ bool set_leftcol(colnr_T leftcol) getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e); if (e > (colnr_T)lastcol) { retval = true; - coladvance(s - 1); + coladvance(curwin, s - 1); } else if (s < curwin->w_leftcol) { retval = true; - if (coladvance(e + 1) == FAIL) { // there isn't another character + if (coladvance(curwin, e + 1) == FAIL) { // there isn't another character curwin->w_leftcol = s; // adjust w_leftcol instead changed_cline_bef_curs(curwin); } diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 51d5d08f78..41ef1aceaf 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -890,9 +890,9 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo } assert(lnum > 0); - bool below_fold = lnum > 1 && hasFoldingWin(wp, lnum - 1, NULL, NULL, true, NULL); + bool below_fold = lnum > 1 && hasFolding(wp, lnum - 1, NULL, NULL); if (has_fold == kNone) { - has_fold = hasFoldingWin(wp, lnum, NULL, NULL, true, NULL); + has_fold = hasFolding(wp, lnum, NULL, NULL); } const int row = lnum - 1; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 2b3010e063..bc91c1e4c2 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1347,7 +1347,7 @@ void ex_diffsplit(exarg_T *eap) set_bufref(&old_curbuf, curbuf); // Need to compute w_fraction when no redraw happened yet. - validate_cursor(); + validate_cursor(curwin); set_fraction(curwin); // don't use a new tab page, each tab page has its own diffs @@ -1457,7 +1457,7 @@ void diff_win_options(win_T *wp, bool addbuf) foldUpdateAll(wp); // make sure topline is not halfway through a fold - changed_window_setting_win(wp); + changed_window_setting(wp); if (vim_strchr(p_sbo, 'h') == NULL) { do_cmdline_cmd("set sbo+=hor"); } @@ -1522,7 +1522,7 @@ void ex_diffoff(exarg_T *eap) // make sure topline is not halfway a fold and cursor is // invalidated - changed_window_setting_win(wp); + changed_window_setting(wp); // Note: 'sbo' is not restored, it's a global option. diff_buf_adjust(wp); @@ -2137,7 +2137,7 @@ int diff_check_with_linestatus(win_T *wp, linenr_T lnum, int *linestatus) } // A closed fold never has filler lines. - if (hasFoldingWin(wp, lnum, NULL, NULL, true, NULL)) { + if (hasFolding(wp, lnum, NULL, NULL)) { return 0; } @@ -2451,8 +2451,7 @@ void diff_set_topline(win_T *fromwin, win_T *towin) changed_line_abv_curs_win(towin); check_topfill(towin, false); - hasFoldingWin(towin, towin->w_topline, &towin->w_topline, - NULL, true, NULL); + hasFolding(towin, towin->w_topline, &towin->w_topline, NULL); } /// This is called when 'diffopt' is changed. @@ -2988,7 +2987,7 @@ theend: // Check that the cursor is on a valid character and update its // position. When there were filler lines the topline has become // invalid. - check_cursor(); + check_cursor(curwin); changed_line_abv_curs(); if (diff_need_update) { diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index c5f6ce2e36..a7b1d561b6 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -1393,7 +1393,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // the end of the line may be before the start of the displayed part. if (wlv.vcol < start_col && (wp->w_p_cuc || wlv.color_cols - || virtual_active() + || virtual_active(wp) || (VIsual_active && wp->w_buffer == curwin->w_buffer))) { wlv.vcol = start_col; } @@ -2339,7 +2339,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && wlv.line_attr == 0 && wlv.line_attr_lowprio == 0) { // In virtualedit, visual selections may extend beyond end of line - if (!(area_highlighting && virtual_active() + if (!(area_highlighting && virtual_active(wp) && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol)) { wlv.p_extra = ""; } @@ -2382,7 +2382,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s mb_schar = schar_from_ascii(mb_c); } else if (VIsual_active && (VIsual_mode == Ctrl_V || VIsual_mode == 'v') - && virtual_active() + && virtual_active(wp) && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol && wlv.col < grid->cols) { diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 402f7fa428..f2ad4ca77e 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -823,7 +823,7 @@ void setcursor(void) void setcursor_mayforce(bool force) { if (force || redrawing()) { - validate_cursor(); + validate_cursor(curwin); ScreenGrid *grid = &curwin->w_grid; int row = curwin->w_wrow; @@ -851,7 +851,7 @@ void show_cursor_info_later(bool force) && *ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum) == NUL; // Only draw when something changed. - validate_virtcol_win(curwin); + validate_virtcol(curwin); if (force || curwin->w_cursor.lnum != curwin->w_stl_cursor.lnum || curwin->w_cursor.col != curwin->w_stl_cursor.col @@ -1611,14 +1611,14 @@ static void win_update(win_T *wp) } } - hasFoldingWin(wp, mod_top, &mod_top, NULL, true, NULL); + hasFolding(wp, mod_top, &mod_top, NULL); if (mod_top > lnumt) { mod_top = lnumt; } // Now do the same for the bottom line (one above mod_bot). mod_bot--; - hasFoldingWin(wp, mod_bot, NULL, &mod_bot, true, NULL); + hasFolding(wp, mod_bot, NULL, &mod_bot); mod_bot++; if (mod_bot < lnumb) { mod_bot = lnumb; @@ -1691,7 +1691,7 @@ static void win_update(win_T *wp) if (j >= wp->w_grid.rows - 2) { break; } - hasFoldingWin(wp, ln, NULL, &ln, true, NULL); + hasFolding(wp, ln, NULL, &ln); } } else { j = wp->w_lines[0].wl_lnum - wp->w_topline; @@ -1903,7 +1903,7 @@ static void win_update(win_T *wp) // Highlight to the end of the line, unless 'virtualedit' has // "block". if (curwin->w_curswant == MAXCOL) { - if (get_ve_flags() & VE_BLOCK) { + if (get_ve_flags(curwin) & VE_BLOCK) { pos_T pos; int cursor_above = curwin->w_cursor.lnum < VIsual.lnum; @@ -2148,7 +2148,7 @@ static void win_update(win_T *wp) // rows, and may insert/delete lines int j = idx; for (l = lnum; l < mod_bot; l++) { - if (hasFoldingWin(wp, l, NULL, &l, true, NULL)) { + if (hasFolding(wp, l, NULL, &l)) { new_rows++; } else if (l == wp->w_topline) { int n = plines_win_nofill(wp, l, false) + wp->w_topfill; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index a0d6f7125e..5b62ab4215 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -185,7 +185,7 @@ static void insert_enter(InsertState *s) curwin->w_cursor = save_cursor; State = MODE_INSERT; - check_cursor_col(); + check_cursor_col(curwin); State = save_state; } } @@ -282,7 +282,7 @@ static void insert_enter(InsertState *s) // correct in very rare cases). // Also do this if curswant is greater than the current virtual // column. Eg after "^O$" or "^O80|". - validate_virtcol(); + validate_virtcol(curwin); update_curswant(); if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum) || curwin->w_curswant > curwin->w_virtcol) @@ -468,7 +468,7 @@ static int insert_check(VimState *state) && curwin->w_topline == s->old_topline && curwin->w_topfill == s->old_topfill) { s->mincol = curwin->w_wcol; - validate_cursor_col(); + validate_cursor_col(curwin); if (curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(), curbuf->b_p_ts, @@ -478,7 +478,7 @@ static int insert_check(VimState *state) || curwin->w_topfill > 0)) { if (curwin->w_topfill > 0) { curwin->w_topfill--; - } else if (hasFolding(curwin->w_topline, NULL, &s->old_topline)) { + } else if (hasFolding(curwin, curwin->w_topline, NULL, &s->old_topline)) { set_topline(curwin, s->old_topline + 1); } else { set_topline(curwin, curwin->w_topline + 1); @@ -491,7 +491,7 @@ static int insert_check(VimState *state) s->did_backspace = false; - validate_cursor(); // may set must_redraw + validate_cursor(curwin); // may set must_redraw // Redraw the display when no characters are waiting. // Also shows mode, ruler and positions cursor. @@ -743,7 +743,7 @@ static int insert_handle_key(InsertState *s) ins_ctrl_o(); // don't move the cursor left when 'virtualedit' has "onemore". - if (get_ve_flags() & VE_ONEMORE) { + if (get_ve_flags(curwin) & VE_ONEMORE) { ins_at_eol = false; s->nomove = true; } @@ -1451,7 +1451,7 @@ void edit_putchar(int c, bool highlight) int attr; update_topline(curwin); // just in case w_topline isn't valid - validate_cursor(); + validate_cursor(curwin); if (highlight) { attr = HL_ATTR(HLF_8); } else { @@ -1521,7 +1521,7 @@ static void init_prompt(int cmdchar_todo) ml_append(curbuf->b_ml.ml_line_count, prompt, 0, false); } curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); inserted_bytes(curbuf->b_ml.ml_line_count, 0, 0, (colnr_T)strlen(prompt)); } @@ -1536,13 +1536,13 @@ static void init_prompt(int cmdchar_todo) } if (cmdchar_todo == 'A') { - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } if (curwin->w_cursor.col < (colnr_T)strlen(prompt)) { curwin->w_cursor.col = (colnr_T)strlen(prompt); } // Make sure the cursor is in a valid position. - check_cursor(); + check_cursor(curwin); } /// @return true if the cursor is in the editable position of the prompt line. @@ -2394,7 +2394,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) pos_T tpos = curwin->w_cursor; curwin->w_cursor = *end_insert_pos; - check_cursor_col(); // make sure it is not past the line + check_cursor_col(curwin); // make sure it is not past the line while (true) { if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) { curwin->w_cursor.col--; @@ -2471,7 +2471,7 @@ void free_last_insert(void) void beginline(int flags) { if ((flags & BL_SOL) && !p_sol) { - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } else { curwin->w_cursor.col = 0; curwin->w_cursor.coladd = 0; @@ -2497,13 +2497,13 @@ int oneright(void) { char *ptr; - if (virtual_active()) { + if (virtual_active(curwin)) { pos_T prevpos = curwin->w_cursor; // Adjust for multi-wide char (excluding TAB) ptr = get_cursor_pos_ptr(); - coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) - ? ptr2cells(ptr) : 1)); + coladvance(curwin, getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) + ? ptr2cells(ptr) : 1)); curwin->w_set_curswant = true; // Return OK if the cursor moved, FAIL otherwise (at window edge). return (prevpos.col != curwin->w_cursor.col @@ -2519,7 +2519,7 @@ int oneright(void) // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit' // contains "onemore". - if (ptr[l] == NUL && (get_ve_flags() & VE_ONEMORE) == 0) { + if (ptr[l] == NUL && (get_ve_flags(curwin) & VE_ONEMORE) == 0) { return FAIL; } curwin->w_cursor.col += l; @@ -2531,7 +2531,7 @@ int oneright(void) int oneleft(void) { - if (virtual_active()) { + if (virtual_active(curwin)) { int v = getviscol(); if (v == 0) { @@ -2541,7 +2541,7 @@ int oneleft(void) // We might get stuck on 'showbreak', skip over it. int width = 1; while (true) { - coladvance(v - width); + coladvance(curwin, v - width); // getviscol() is slow, skip it when 'showbreak' is empty, // 'breakindent' is not set and there are no multi-byte // characters @@ -2590,7 +2590,7 @@ void cursor_up_inner(win_T *wp, linenr_T n) // Count each sequence of folded lines as one logical line. // go to the start of the current fold - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); while (n--) { // move up one line @@ -2602,7 +2602,7 @@ void cursor_up_inner(win_T *wp, linenr_T n) // Insert mode or when 'foldopen' contains "all": it will open // in a moment. if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL))) { - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); } } if (lnum < 1) { @@ -2625,7 +2625,7 @@ int cursor_up(linenr_T n, bool upd_topline) cursor_up_inner(curwin, n); // try to advance to the column we want to be at - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); if (upd_topline) { update_topline(curwin); // make sure curwin->w_topline is valid @@ -2678,7 +2678,7 @@ int cursor_down(int n, bool upd_topline) cursor_down_inner(curwin, n); // try to advance to the column we want to be at - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); if (upd_topline) { update_topline(curwin); // make sure curwin->w_topline is valid @@ -3274,7 +3274,7 @@ static void ins_reg(void) // Cursor may be moved back a column. curwin->w_cursor = curpos; - check_cursor(); + check_cursor(curwin); } if (regname == NUL || !valid_yank_reg(regname, false)) { vim_beep(BO_REG); @@ -3466,7 +3466,7 @@ static bool ins_esc(int *count, int cmdchar, bool nomove) && (curwin->w_cursor.col != 0 || curwin->w_cursor.coladd > 0) && (restart_edit == NUL || (gchar_cursor() == NUL && !VIsual_active)) && !revins_on) { - if (curwin->w_cursor.coladd > 0 || get_ve_flags() == VE_ALL) { + if (curwin->w_cursor.coladd > 0 || get_ve_flags(curwin) == VE_ALL) { oneleft(); if (restart_edit != NUL) { curwin->w_cursor.coladd++; @@ -3598,7 +3598,7 @@ static void ins_ctrl_o(void) } else { restart_edit = 'I'; } - if (virtual_active()) { + if (virtual_active(curwin)) { ins_at_eol = false; // cursor always keeps its column } else { ins_at_eol = (gchar_cursor() == NUL); @@ -4028,7 +4028,7 @@ static void ins_left(void) // always break undo when moving upwards/downwards, else undo may break start_arrow(&tpos); curwin->w_cursor.lnum--; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); curwin->w_set_curswant = true; // so we stay at the end } else { vim_beep(BO_CRSR); @@ -4062,7 +4062,7 @@ static void ins_end(int c) if (c == K_C_END) { curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; } - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); curwin->w_curswant = MAXCOL; start_arrow(&tpos); @@ -4096,13 +4096,13 @@ static void ins_right(void) foldOpenCursor(); } undisplay_dollar(); - if (gchar_cursor() != NUL || virtual_active()) { + if (gchar_cursor() != NUL || virtual_active(curwin)) { start_arrow_with_change(&curwin->w_cursor, end_change); if (!end_change) { AppendCharToRedobuff(K_RIGHT); } curwin->w_set_curswant = true; - if (virtual_active()) { + if (virtual_active(curwin)) { oneright(); } else { curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr()); @@ -4157,7 +4157,7 @@ static void ins_up(bool startcol) pos_T tpos = curwin->w_cursor; if (cursor_up(1, true) == OK) { if (startcol) { - coladvance(getvcol_nolist(&Insstart)); + coladvance(curwin, getvcol_nolist(&Insstart)); } if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill) { @@ -4202,7 +4202,7 @@ static void ins_down(bool startcol) pos_T tpos = curwin->w_cursor; if (cursor_down(1, true) == OK) { if (startcol) { - coladvance(getvcol_nolist(&Insstart)); + coladvance(curwin, getvcol_nolist(&Insstart)); } if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill) { @@ -4474,8 +4474,8 @@ bool ins_eol(int c) // Put cursor on NUL if on the last char and coladd is 1 (happens after // CTRL-O). - if (virtual_active() && curwin->w_cursor.coladd > 0) { - coladvance(getviscol()); + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { + coladvance(curwin, getviscol()); } // NL in reverse insert will always start in the end of current line. @@ -4574,7 +4574,7 @@ int ins_copychar(linenr_T lnum) } // try to advance to the cursor column - validate_virtcol(); + validate_virtcol(curwin); int const end_vcol = curwin->w_virtcol; char *line = ml_get(lnum); @@ -4720,7 +4720,7 @@ colnr_T get_nolist_virtcol(void) if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) { return getvcol_nolist(&curwin->w_cursor); } - validate_virtcol(); + validate_virtcol(curwin); return curwin->w_virtcol; } diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c index 7b8f71ef3f..73bfd6db2a 100644 --- a/src/nvim/eval/buffer.c +++ b/src/nvim/eval/buffer.c @@ -197,7 +197,7 @@ static void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, typval_ && ml_replace(lnum, line, true) == OK) { inserted_bytes(lnum, 0, old_len, (int)strlen(line)); if (is_curbuf && lnum == curwin->w_cursor.lnum) { - check_cursor_col(); + check_cursor_col(curwin); } rettv->vval.v_number = 0; // OK } @@ -229,7 +229,7 @@ static void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, typval_ wp->w_cursor.lnum += (linenr_T)added; } } - check_cursor_col(); + check_cursor_col(curwin); update_topline(curwin); } @@ -469,7 +469,7 @@ void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } } - check_cursor_col(); + check_cursor_col(curwin); deleted_lines_mark(first, count); rettv->vval.v_number = 0; // OK diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1d5835c9bf..99da15ddd7 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -727,7 +727,7 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) return; } - check_cursor(); + check_cursor(curwin); winchanged = true; } @@ -746,7 +746,7 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) col = fp->col + 1; // col(".") when the cursor is on the NUL at the end of the line // because of "coladd" can be seen as an extra column. - if (virtual_active() && fp == &curwin->w_cursor) { + if (virtual_active(curwin) && fp == &curwin->w_cursor) { char *p = get_cursor_pos_ptr(); if (curwin->w_cursor.coladd >= (colnr_T)win_chartabsize(curwin, p, @@ -1191,7 +1191,7 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) curwin->w_cursor.coladd = coladd; // Make sure the cursor is in a valid position. - check_cursor(); + check_cursor(curwin); // Correct cursor for multi-byte character. mb_adjust_cursor(); @@ -2890,7 +2890,7 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) curbuf = findbuf; curwin->w_buffer = curbuf; const TriState save_virtual = virtual_op; - virtual_op = virtual_active(); + virtual_op = virtual_active(curwin); // NOTE: Adjust is needed. p1.col--; @@ -4643,7 +4643,7 @@ static void f_line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (wp != NULL && tp != NULL) { switchwin_T switchwin; if (switch_win_noblock(&switchwin, wp, tp, true) == OK) { - check_cursor(); + check_cursor(curwin); fp = var2fpos(&argvars[0], true, &fnum, false); } restore_win_noblock(&switchwin, true); @@ -7029,7 +7029,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) } // "/$" will put the cursor after the end of the line, may need to // correct that here - check_cursor(); + check_cursor(curwin); } // If 'n' flag is used: restore cursor position. @@ -7791,7 +7791,7 @@ static void set_position(typval_T *argvars, typval_T *rettv, bool charpos) curwin->w_curswant = curswant - 1; curwin->w_set_curswant = false; } - check_cursor(); + check_cursor(curwin); rettv->vval.v_number = 0; } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) { // set mark @@ -9204,7 +9204,7 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) goto theend; } - check_cursor(); + check_cursor(curwin); winchanged = true; } diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 3e2f6301ca..68de40f983 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -516,7 +516,7 @@ bool win_execute_before(win_execute_T *args, win_T *wp, tabpage_T *tp) } if (switch_win_noblock(&args->switchwin, wp, tp, true) == OK) { - check_cursor(); + check_cursor(curwin); return true; } return false; @@ -540,7 +540,7 @@ void win_execute_after(win_execute_T *args) // In case the command moved the cursor or changed the Visual area, // check it is valid. - check_cursor(); + check_cursor(curwin); if (VIsual_active) { check_pos(curbuf, &VIsual); } @@ -774,7 +774,7 @@ void f_winbufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "wincol()" function void f_wincol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - validate_cursor(); + validate_cursor(curwin); rettv->vval.v_number = curwin->w_wcol + 1; } @@ -811,7 +811,7 @@ void f_winlayout(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "winline()" function void f_winline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - validate_cursor(); + validate_cursor(curwin); rettv->vval.v_number = curwin->w_wrow + 1; } @@ -883,10 +883,10 @@ void f_winrestview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) curwin->w_skipcol = (colnr_T)tv_get_number(&di->di_tv); } - check_cursor(); + check_cursor(curwin); win_new_height(curwin, curwin->w_height); win_new_width(curwin, curwin->w_width); - changed_window_setting(); + changed_window_setting(curwin); if (curwin->w_topline <= 0) { curwin->w_topline = 1; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 14bd2b87e3..9f48312ec6 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2638,14 +2638,14 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum if (newcol >= 0) { // position set by autocommands curwin->w_cursor.lnum = newlnum; curwin->w_cursor.col = newcol; - check_cursor(); + check_cursor(curwin); } else if (newlnum > 0) { // line number from caller or old position curwin->w_cursor.lnum = newlnum; check_cursor_lnum(curwin); if (solcol >= 0 && !p_sol) { // 'sol' is off: Use last known column. curwin->w_cursor.col = solcol; - check_cursor_col(); + check_cursor_col(curwin); curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; } else { @@ -3787,7 +3787,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n highlight_match = true; update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_SOME_VALID); show_cursor_info_later(true); update_screen(); @@ -4247,7 +4247,7 @@ skip: // when interactive leave cursor on the match if (!subflags.do_ask) { if (endcolumn) { - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } else { beginline(BL_WHITE | BL_FIX); } @@ -4278,7 +4278,7 @@ skip: if (subflags.do_ask && hasAnyFolding(curwin)) { // Cursor position may require updating - changed_window_setting(); + changed_window_setting(curwin); } vim_regfree(regmatch.regprog); @@ -4514,7 +4514,7 @@ void global_exe(char *cmd) if (global_need_beginline) { beginline(BL_WHITE | BL_FIX); } else { - check_cursor(); // cursor may be beyond the end of the line + check_cursor(curwin); // cursor may be beyond the end of the line } // the cursor may not have moved in the text but a change in a previous diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 12687d0ea8..a34eb0232b 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -654,7 +654,7 @@ void ex_listdo(exarg_T *eap) } if (eap->cmdidx == CMD_windo && execute) { - validate_cursor(); // cursor may have moved + validate_cursor(curwin); // cursor may have moved // required when 'scrollbind' has been set if (curwin->w_p_scb) { do_check_scrollbind(true); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1b4e83d392..6db72ff2d1 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1743,8 +1743,8 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) && eap->addr_type == ADDR_LINES) { // Put the first line at the start of a closed fold, put the last line // at the end of a closed fold. - hasFolding(eap->line1, &eap->line1, NULL); - hasFolding(eap->line2, NULL, &eap->line2); + hasFolding(curwin, eap->line1, &eap->line1, NULL); + hasFolding(curwin, eap->line2, NULL, &eap->line2); } // Use first argument as count when possible @@ -2213,8 +2213,8 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter && ea.addr_type == ADDR_LINES) { // Put the first line at the start of a closed fold, put the last line // at the end of a closed fold. - hasFolding(ea.line1, &ea.line1, NULL); - hasFolding(ea.line2, NULL, &ea.line2); + hasFolding(curwin, ea.line1, &ea.line1, NULL); + hasFolding(curwin, ea.line2, NULL, &ea.line2); } // For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg' @@ -2875,9 +2875,9 @@ int parse_cmd_address(exarg_T *eap, const char **errormsg, bool silent) // (where zero usually means to use the first line). // Check the cursor position before returning. if (eap->line2 > 0) { - check_cursor(); + check_cursor(curwin); } else { - check_cursor_col(); + check_cursor_col(curwin); } need_check_cursor = true; } @@ -2899,7 +2899,7 @@ int parse_cmd_address(exarg_T *eap, const char **errormsg, bool silent) theend: if (need_check_cursor) { - check_cursor(); + check_cursor(curwin); } return ret; } @@ -3596,7 +3596,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool // closed fold after the first address. if (addr_type == ADDR_LINES && (i == '-' || i == '+') && address_count >= 2) { - hasFolding(lnum, NULL, &lnum); + hasFolding(curwin, lnum, NULL, &lnum); } if (i == '-') { lnum -= n; @@ -5528,8 +5528,6 @@ static void ex_swapname(exarg_T *eap) /// (1998-11-02 16:21:01 R. Edward Ralston ) static void ex_syncbind(exarg_T *eap) { - win_T *save_curwin = curwin; - buf_T *save_curbuf = curbuf; linenr_T topline; int y; linenr_T old_linenr = curwin->w_cursor.lnum; @@ -5556,23 +5554,19 @@ static void ex_syncbind(exarg_T *eap) // Set all scrollbind windows to the same topline. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - curwin = wp; - if (curwin->w_p_scb) { - curbuf = curwin->w_buffer; - y = topline - curwin->w_topline; + if (wp->w_p_scb) { + y = topline - wp->w_topline; if (y > 0) { - scrollup(y, true); + scrollup(wp, y, true); } else { - scrolldown(-y, true); + scrolldown(wp, -y, true); } - curwin->w_scbind_pos = topline; - redraw_later(curwin, UPD_VALID); - cursor_correct(); - curwin->w_redr_status = true; + wp->w_scbind_pos = topline; + redraw_later(wp, UPD_VALID); + cursor_correct(wp); + wp->w_redr_status = true; } } - curwin = save_curwin; - curbuf = save_curbuf; if (curwin->w_p_scb) { did_syncbind = true; checkpcmark(); @@ -5854,7 +5848,7 @@ static void ex_equal(exarg_T *eap) static void ex_sleep(exarg_T *eap) { - if (cursor_valid()) { + if (cursor_valid(curwin)) { setcursor_mayforce(true); } @@ -5990,7 +5984,7 @@ static void ex_put(exarg_T *eap) eap->forceit = true; } curwin->w_cursor.lnum = eap->line2; - check_cursor_col(); + check_cursor_col(curwin); do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1, PUT_LINE|PUT_CURSLINE); } @@ -6084,7 +6078,7 @@ static void ex_at(exarg_T *eap) int prev_len = typebuf.tb_len; curwin->w_cursor.lnum = eap->line2; - check_cursor_col(); + check_cursor_col(curwin); // Get the register name. No name means use the previous one. int c = (uint8_t)(*eap->arg); @@ -6306,7 +6300,7 @@ static void ex_redraw(exarg_T *eap) RedrawingDisabled = 0; p_lz = false; - validate_cursor(); + validate_cursor(curwin); update_topline(curwin); if (eap->forceit) { redraw_all_later(UPD_NOT_VALID); @@ -6459,10 +6453,10 @@ static void ex_mark(exarg_T *eap) /// Update w_topline, w_leftcol and the cursor position. void update_topline_cursor(void) { - check_cursor(); // put cursor on valid line + check_cursor(curwin); // put cursor on valid line update_topline(curwin); if (!curwin->w_p_wrap) { - validate_cursor(); + validate_cursor(curwin); } update_curswant(); } @@ -6766,7 +6760,7 @@ static void ex_pedit(exarg_T *eap) if (curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } @@ -7408,7 +7402,7 @@ static void ex_folddo(exarg_T *eap) { // First set the marks for all lines closed/open. for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { - if (hasFolding(lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed)) { + if (hasFolding(curwin, lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed)) { ml_setmarked(lnum); } } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 44a78711d2..303337ae98 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -510,7 +510,7 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state s->match_start = curwin->w_cursor; set_search_match(&curwin->w_cursor); - validate_cursor(); + validate_cursor(curwin); end_pos = curwin->w_cursor; s->match_end = end_pos; curwin->w_cursor = save_pos; @@ -530,7 +530,7 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state ccline.cmdbuff[skiplen + patlen] = next_char; } - validate_cursor(); + validate_cursor(curwin); // May redraw the status line to show the cursor position. if (p_ru && (curwin->w_status_height > 0 || global_stl_height() > 0)) { @@ -626,7 +626,7 @@ static void finish_incsearch_highlighting(bool gotesc, incsearch_state_T *s, magic_overruled = s->magic_overruled_save; - validate_cursor(); // needed for TAB + validate_cursor(curwin); // needed for TAB status_redraw_all(); redraw_all_later(UPD_SOME_VALID); if (call_update_screen) { @@ -1483,7 +1483,7 @@ static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_s curwin->w_cursor = s->match_start; changed_cline_bef_curs(curwin); update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); highlight_match = true; save_viewstate(curwin, &s->old_viewstate); redraw_later(curwin, UPD_NOT_VALID); @@ -4623,6 +4623,6 @@ static void set_search_match(pos_T *t) t->col = search_match_endcol; if (t->lnum > curbuf->b_ml.ml_line_count) { t->lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 3b715e2c0b..4150d0997d 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3197,7 +3197,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) curwin->w_topline = old_topline; } curwin->w_cursor = old_cursor; - check_cursor(); + check_cursor(curwin); update_topline(curwin); keep_filetype = false; diff --git a/src/nvim/fold.c b/src/nvim/fold.c index c571aaf0a4..15aba432c4 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -143,7 +143,7 @@ void copyFoldingState(win_T *wp_from, win_T *wp_to) } // hasAnyFolding() {{{2 -/// @return true if there may be folded lines in the current window. +/// @return true if there may be folded lines in window "win". int hasAnyFolding(win_T *win) { // very simple now, but can become more complex later @@ -155,10 +155,10 @@ int hasAnyFolding(win_T *win) /// When returning true, *firstp and *lastp are set to the first and last /// lnum of the sequence of folded lines (skipped when NULL). /// -/// @return true if line "lnum" in the current window is part of a closed fold. -bool hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp) +/// @return true if line "lnum" in window "win" is part of a closed fold. +bool hasFolding(win_T *win, linenr_T lnum, linenr_T *firstp, linenr_T *lastp) { - return hasFoldingWin(curwin, lnum, firstp, lastp, true, NULL); + return hasFoldingWin(win, lnum, firstp, lastp, true, NULL); } // hasFoldingWin() {{{2 @@ -398,13 +398,13 @@ void opFoldRange(pos_T firstpos, pos_T lastpos, int opening, int recurse, bool h // Opening one level only: next fold to open is after the one going to // be opened. if (opening && !recurse) { - hasFolding(lnum, NULL, &lnum_next); + hasFolding(curwin, lnum, NULL, &lnum_next); } setManualFold(temp, opening, recurse, &done); // Closing one level only: next line to close a fold is after just // closed fold. if (!opening && !recurse) { - hasFolding(lnum, NULL, &lnum_next); + hasFolding(curwin, lnum, NULL, &lnum_next); } } if (done == DONE_NOTHING) { @@ -477,7 +477,7 @@ static void newFoldLevelWin(win_T *wp) } wp->w_fold_manual = false; } - changed_window_setting_win(wp); + changed_window_setting(wp); } // foldCheckClose() {{{2 @@ -492,7 +492,7 @@ void foldCheckClose(void) checkupdate(curwin); if (checkCloseRec(&curwin->w_folds, curwin->w_cursor.lnum, (int)curwin->w_p_fdl)) { - changed_window_setting(); + changed_window_setting(curwin); } } @@ -661,7 +661,7 @@ void foldCreate(win_T *wp, pos_T start, pos_T end) fp->fd_small = kNone; // redraw - changed_window_setting_win(wp); + changed_window_setting(wp); } } @@ -735,7 +735,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const did_one = true; // redraw window - changed_window_setting_win(wp); + changed_window_setting(wp); } } if (!did_one) { @@ -746,7 +746,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const } } else { // Deleting markers may make cursor column invalid - check_cursor_col_win(wp); + check_cursor_col(wp); } if (last_lnum > 0) { @@ -1009,11 +1009,11 @@ void foldAdjustVisual(void) start = &curwin->w_cursor; end = &VIsual; } - if (hasFolding(start->lnum, &start->lnum, NULL)) { + if (hasFolding(curwin, start->lnum, &start->lnum, NULL)) { start->col = 0; } - if (!hasFolding(end->lnum, NULL, &end->lnum)) { + if (!hasFolding(curwin, end->lnum, NULL, &end->lnum)) { return; } @@ -1028,9 +1028,9 @@ void foldAdjustVisual(void) // cursor_foldstart() {{{2 /// Move the cursor to the first line of a closed fold. -void foldAdjustCursor(void) +void foldAdjustCursor(win_T *wp) { - hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); + hasFolding(wp, wp->w_cursor.lnum, &wp->w_cursor.lnum, NULL); } // Internal functions for "fold_T" {{{1 @@ -1269,7 +1269,7 @@ static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, bool opening, bool re } wp->w_fold_manual = true; if (done & DONE_ACTION) { - changed_window_setting_win(wp); + changed_window_setting(wp); } done |= DONE_FOLD; } else if (donep == NULL && wp == curwin) { @@ -2117,7 +2117,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) // If some fold changed, need to redraw and position cursor. if (fold_changed && wp->w_p_fen) { - changed_window_setting_win(wp); + changed_window_setting(wp); } // If we updated folds past "bot", need to redraw more lines. Don't do diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 64c9c5a8c3..f68bd7098b 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2508,7 +2508,7 @@ static int vgetorpeek(bool advance) unshowmode(true); mode_deleted = true; } - validate_cursor(); + validate_cursor(curwin); int old_wcol = curwin->w_wcol; int old_wrow = curwin->w_wrow; @@ -2541,7 +2541,7 @@ static int vgetorpeek(bool advance) curwin->w_wrow = curwin->w_cline_row + curwin->w_wcol / curwin->w_width_inner; curwin->w_wcol %= curwin->w_width_inner; - curwin->w_wcol += curwin_col_off(); + curwin->w_wcol += win_col_off(curwin); col = 0; // no correction needed } else { curwin->w_wcol--; diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 14247b6d86..6cbb86866e 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -1116,7 +1116,7 @@ void ex_retab(exarg_T *eap) } xfree(new_ts_str); } - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); u_clearline(curbuf); } @@ -1160,7 +1160,7 @@ int get_expr_indent(void) curwin->w_cursor = save_pos; curwin->w_curswant = save_curswant; curwin->w_set_curswant = save_set_curswant; - check_cursor(); + check_cursor(curwin); State = save_State; // Reset did_throw, unless 'debug' has "throw" and inside a try/catch. diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index d0cd24773f..a1f341f404 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -2436,7 +2436,7 @@ static void expand_by_function(int type, char *base) textlock--; curwin->w_cursor = pos; // restore the cursor position - validate_cursor(); + validate_cursor(curwin); if (!equalpos(curwin->w_cursor, pos)) { emsg(_(e_compldel)); goto theend; @@ -4096,7 +4096,7 @@ static int get_userdefined_compl_info(colnr_T curs_col) State = save_State; curwin->w_cursor = pos; // restore the cursor position - validate_cursor(); + validate_cursor(curwin); if (!equalpos(curwin->w_cursor, pos)) { emsg(_(e_compldel)); return FAIL; diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 08677b77b0..78c746d169 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1797,7 +1797,7 @@ void ex_luado(exarg_T *const eap) } lua_pop(lstate, 1); - check_cursor(); + check_cursor(curwin); redraw_curbuf_later(UPD_NOT_VALID); } diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 34e35a8277..0ecdd88ebd 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -588,7 +588,7 @@ MarkMoveRes mark_move_to(fmark_T *fm, MarkMove flags) } if (res & kMarkSwitchedBuf || res & kMarkChangedCursor) { - check_cursor(); + check_cursor(curwin); } end: return res; diff --git a/src/nvim/match.c b/src/nvim/match.c index c8837969b6..ea8a1a05f4 100644 --- a/src/nvim/match.c +++ b/src/nvim/match.c @@ -533,7 +533,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) for (shl->first_lnum = lnum; shl->first_lnum > wp->w_topline; shl->first_lnum--) { - if (hasFoldingWin(wp, shl->first_lnum - 1, NULL, NULL, true, NULL)) { + if (hasFolding(wp, shl->first_lnum - 1, NULL, NULL)) { break; } } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index a63c23f0a3..ca47f6aa98 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1192,7 +1192,7 @@ void ml_recover(bool checkext) ml_delete(curbuf->b_ml.ml_line_count, false); } curbuf->b_flags |= BF_RECOVERED; - check_cursor(); + check_cursor(curwin); recoverymode = false; if (got_int) { @@ -4076,14 +4076,14 @@ void goto_byte(int cnt) if (lnum < 1) { // past the end curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; curwin->w_curswant = MAXCOL; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } else { curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = (colnr_T)boff; curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; } - check_cursor(); + check_cursor(curwin); // Make sure the cursor is on the first byte of a multi-byte char. mb_adjust_cursor(); diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 4ca2a61ab1..ab28eeca1c 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -1478,11 +1478,11 @@ void execute_menu(const exarg_T *eap, vimmenu_T *menu, int mode_idx) // Activate visual mode VIsual_active = true; VIsual_reselect = true; - check_cursor(); + check_cursor(curwin); VIsual = curwin->w_cursor; curwin->w_cursor = tpos; - check_cursor(); + check_cursor(curwin); // Adjust the cursor to make sure it is in the correct pos // for exclusive mode diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 506a428243..d82ba58918 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -771,7 +771,7 @@ popupexit: // move VIsual to the right column start_visual = curwin->w_cursor; // save the cursor pos curwin->w_cursor = end_visual; - coladvance(end_visual.col); + coladvance(curwin, end_visual.col); VIsual = curwin->w_cursor; curwin->w_cursor = start_visual; // restore the cursor } else { @@ -1430,7 +1430,7 @@ retnomove: break; } first = false; - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { curwin->w_topfill++; } else { @@ -1460,7 +1460,7 @@ retnomove: if (curwin->w_topfill > 0) { curwin->w_topfill--; } else { - if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline) + if (hasFolding(curwin, curwin->w_topline, NULL, &curwin->w_topline) && curwin->w_topline == curbuf->b_ml.ml_line_count) { break; } @@ -1515,7 +1515,7 @@ retnomove: curwin->w_curswant = col; curwin->w_set_curswant = false; // May still have been true - if (coladvance(col) == FAIL) { // Mouse click beyond end of line + if (coladvance(curwin, col) == FAIL) { // Mouse click beyond end of line if (inclusive != NULL) { *inclusive = true; } @@ -1548,7 +1548,7 @@ static bool do_mousescroll_horiz(colnr_T leftcol) // When the line of the cursor is too short, move the cursor to the // longest visible line. - if (!virtual_active() + if (!virtual_active(curwin) && leftcol > scroll_line_len(curwin->w_cursor.lnum)) { curwin->w_cursor.lnum = find_longest_lnum(); curwin->w_cursor.col = 0; @@ -1637,7 +1637,7 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) break; // Position is in this buffer line. } - hasFoldingWin(win, lnum, NULL, &lnum, true, NULL); + hasFolding(win, lnum, NULL, &lnum); if (lnum == win->w_buffer->b_ml.ml_line_count) { retval = true; diff --git a/src/nvim/move.c b/src/nvim/move.c index 0f7f4d8719..3c4da7f8ac 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -182,7 +182,7 @@ static void redraw_for_cursorcolumn(win_T *wp) // When current buffer's cursor moves in Visual mode, redraw it with UPD_INVERTED. if (VIsual_active && wp->w_buffer == curbuf) { - redraw_curbuf_later(UPD_INVERTED); + redraw_buf_later(curbuf, UPD_INVERTED); } } @@ -332,7 +332,7 @@ void update_topline(win_T *wp) if (lnum >= wp->w_buffer->b_ml.ml_line_count || n >= halfheight) { break; } - hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL); + hasFolding(wp, lnum, NULL, &lnum); } } else { n = wp->w_topline + *so_ptr - wp->w_cursor.lnum; @@ -342,14 +342,14 @@ void update_topline(win_T *wp) // cursor in the middle of the window. Otherwise put the cursor // near the top of the window. if (n >= halfheight) { - scroll_cursor_halfway(false, false); + scroll_cursor_halfway(wp, false, false); } else { - scroll_cursor_top(scrolljump_value(), false); + scroll_cursor_top(wp, scrolljump_value(), false); check_botline = true; } } else { // Make sure topline is the first line of a fold. - hasFoldingWin(wp, wp->w_topline, &wp->w_topline, NULL, true, NULL); + hasFolding(wp, wp->w_topline, &wp->w_topline, NULL); check_botline = true; } } @@ -377,7 +377,7 @@ void update_topline(win_T *wp) int n = wp->w_empty_rows; loff.lnum = wp->w_cursor.lnum; // In a fold go to its last line. - hasFoldingWin(wp, loff.lnum, NULL, &loff.lnum, true, NULL); + hasFolding(wp, loff.lnum, NULL, &loff.lnum); loff.fill = 0; n += wp->w_filler_rows; loff.height = 0; @@ -411,15 +411,15 @@ void update_topline(win_T *wp) if (lnum <= 0 || line_count > wp->w_height_inner + 1) { break; } - hasFolding(lnum, &lnum, NULL); + hasFolding(wp, lnum, &lnum, NULL); } } else { line_count = wp->w_cursor.lnum - wp->w_botline + 1 + (int)(*so_ptr); } if (line_count <= wp->w_height_inner + 1) { - scroll_cursor_bot(scrolljump_value(), false); + scroll_cursor_bot(wp, scrolljump_value(), false); } else { - scroll_cursor_halfway(false, false); + scroll_cursor_halfway(wp, false, false); } } } @@ -443,7 +443,7 @@ void update_topline(win_T *wp) // May need to set w_skipcol when cursor in w_topline. if (wp->w_cursor.lnum == wp->w_topline) { - validate_cursor(); + validate_cursor(wp); } } @@ -491,7 +491,7 @@ static bool check_top_offset(void) /// Update w_curswant. void update_curswant_force(void) { - validate_virtcol(); + validate_virtcol(curwin); curwin->w_curswant = curwin->w_virtcol; curwin->w_set_curswant = false; } @@ -536,12 +536,7 @@ void check_cursor_moved(win_T *wp) // Call this function when some window settings have changed, which require // the cursor position, botline and topline to be recomputed and the window to // be redrawn. E.g, when changing the 'wrap' option or folding. -void changed_window_setting(void) -{ - changed_window_setting_win(curwin); -} - -void changed_window_setting_win(win_T *wp) +void changed_window_setting(win_T *wp) { wp->w_lines_valid = 0; changed_line_abv_curs_win(wp); @@ -555,7 +550,7 @@ void set_topline(win_T *wp, linenr_T lnum) linenr_T prev_topline = wp->w_topline; // go to first of folded lines - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); // Approximate the value of w_botline wp->w_botline += lnum - wp->w_topline; wp->w_topline = lnum; @@ -614,21 +609,21 @@ void approximate_botline_win(win_T *wp) wp->w_valid &= ~VALID_BOTLINE; } -// Return true if curwin->w_wrow and curwin->w_wcol are valid. -int cursor_valid(void) +// Return true if wp->w_wrow and wp->w_wcol are valid. +int cursor_valid(win_T *wp) { - check_cursor_moved(curwin); - return (curwin->w_valid & (VALID_WROW|VALID_WCOL)) == (VALID_WROW|VALID_WCOL); + check_cursor_moved(wp); + return (wp->w_valid & (VALID_WROW|VALID_WCOL)) == (VALID_WROW|VALID_WCOL); } // Validate cursor position. Makes sure w_wrow and w_wcol are valid. // w_topline must be valid, you may need to call update_topline() first! -void validate_cursor(void) +void validate_cursor(win_T *wp) { - check_cursor(); - check_cursor_moved(curwin); - if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) { - curs_columns(curwin, true); + check_cursor(wp); + check_cursor_moved(wp); + if ((wp->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) { + curs_columns(wp, true); } } @@ -692,26 +687,19 @@ static void curs_rows(win_T *wp) } else if (i > wp->w_lines_valid) { // a line that is too long to fit on the last screen line wp->w_cline_height = 0; - wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum, NULL, - NULL, true, NULL); + wp->w_cline_folded = hasFolding(wp, wp->w_cursor.lnum, NULL, NULL); } else { wp->w_cline_height = wp->w_lines[i].wl_size; wp->w_cline_folded = wp->w_lines[i].wl_folded; } } - redraw_for_cursorline(curwin); + redraw_for_cursorline(wp); wp->w_valid |= VALID_CROW|VALID_CHEIGHT; } -// Validate curwin->w_virtcol only. -void validate_virtcol(void) -{ - validate_virtcol_win(curwin); -} - // Validate wp->w_virtcol only. -void validate_virtcol_win(win_T *wp) +void validate_virtcol(win_T *wp) { check_cursor_moved(wp); @@ -724,49 +712,48 @@ void validate_virtcol_win(win_T *wp) wp->w_valid |= VALID_VIRTCOL; } -// Validate curwin->w_cline_height only. -void validate_cheight(void) +// Validate wp->w_cline_height only. +void validate_cheight(win_T *wp) { - check_cursor_moved(curwin); + check_cursor_moved(wp); - if (curwin->w_valid & VALID_CHEIGHT) { + if (wp->w_valid & VALID_CHEIGHT) { return; } - curwin->w_cline_height = plines_win_full(curwin, curwin->w_cursor.lnum, - NULL, &curwin->w_cline_folded, - true, true); - curwin->w_valid |= VALID_CHEIGHT; + wp->w_cline_height = plines_win_full(wp, wp->w_cursor.lnum, + NULL, &wp->w_cline_folded, + true, true); + wp->w_valid |= VALID_CHEIGHT; } // Validate w_wcol and w_virtcol only. -void validate_cursor_col(void) +void validate_cursor_col(win_T *wp) { - validate_virtcol(); + validate_virtcol(wp); - if (curwin->w_valid & VALID_WCOL) { + if (wp->w_valid & VALID_WCOL) { return; } - colnr_T col = curwin->w_virtcol; - colnr_T off = curwin_col_off(); + colnr_T col = wp->w_virtcol; + colnr_T off = win_col_off(wp); col += off; - int width = curwin->w_width_inner - off + curwin_col_off2(); + int width = wp->w_width_inner - off + win_col_off2(wp); - // long line wrapping, adjust curwin->w_wrow - if (curwin->w_p_wrap && col >= (colnr_T)curwin->w_width_inner - && width > 0) { + // long line wrapping, adjust wp->w_wrow + if (wp->w_p_wrap && col >= (colnr_T)wp->w_width_inner && width > 0) { // use same formula as what is used in curs_columns() - col -= ((col - curwin->w_width_inner) / width + 1) * width; + col -= ((col - wp->w_width_inner) / width + 1) * width; } - if (col > (int)curwin->w_leftcol) { - col -= curwin->w_leftcol; + if (col > (int)wp->w_leftcol) { + col -= wp->w_leftcol; } else { col = 0; } - curwin->w_wcol = col; + wp->w_wcol = col; - curwin->w_valid |= VALID_WCOL; + wp->w_valid |= VALID_WCOL; } // Compute offset of a window, occupied by absolute or relative line number, @@ -779,11 +766,6 @@ int win_col_off(win_T *wp) + win_fdccol_count(wp) + (wp->w_scwidth * SIGN_WIDTH); } -int curwin_col_off(void) -{ - return win_col_off(curwin); -} - // Return the difference in column offset for the second screen line of a // wrapped line. It's positive if 'number' or 'relativenumber' is on and 'n' // is in 'cpoptions'. @@ -796,11 +778,6 @@ int win_col_off2(win_T *wp) return 0; } -int curwin_col_off2(void) -{ - return win_col_off2(curwin); -} - // Compute wp->w_wcol and wp->w_virtcol. // Also updates wp->w_wrow and wp->w_cline_row. // Also updates wp->w_leftcol. @@ -896,7 +873,7 @@ void curs_columns(win_T *wp, int may_scroll) // middle of window. int new_leftcol; if (p_ss == 0 || diff >= width1 / 2 || off_right >= off_left) { - new_leftcol = curwin->w_wcol - extra - width1 / 2; + new_leftcol = wp->w_wcol - extra - width1 / 2; } else { if (diff < p_ss) { assert(p_ss <= INT_MAX); @@ -984,9 +961,9 @@ void curs_columns(win_T *wp, int may_scroll) n = plines - wp->w_height_inner + 1; } if (n > 0) { - curwin->w_skipcol = width1 + (n - 1) * width2; + wp->w_skipcol = width1 + (n - 1) * width2; } else { - curwin->w_skipcol = 0; + wp->w_skipcol = 0; } } else if (extra == 1) { // less than 'scrolloff' lines above, decrease skipcol @@ -1063,7 +1040,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp, linenr_T lnum = pos->lnum; if (lnum >= wp->w_topline && lnum <= wp->w_botline) { - is_folded = hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + is_folded = hasFolding(wp, lnum, &lnum, NULL); row = plines_m_win(wp, wp->w_topline, lnum - 1, false); // "row" should be the screen line where line "lnum" begins, which can // be negative if "lnum" is "w_topline" and "w_skipcol" is non-zero. @@ -1207,128 +1184,128 @@ void f_virtcol2col(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = virtcol2col(wp, lnum, screencol); } -/// Scroll the current window down by "line_count" logical lines. "CTRL-Y" +/// Scroll a window down by "line_count" logical lines. "CTRL-Y" /// /// @param line_count number of lines to scroll /// @param byfold if true, count a closed fold as one line -bool scrolldown(linenr_T line_count, int byfold) +bool scrolldown(win_T *wp, linenr_T line_count, int byfold) { int done = 0; // total # of physical lines done int width1 = 0; int width2 = 0; - bool do_sms = curwin->w_p_wrap && curwin->w_p_sms; + bool do_sms = wp->w_p_wrap && wp->w_p_sms; if (do_sms) { - width1 = curwin->w_width_inner - curwin_col_off(); - width2 = width1 + curwin_col_off2(); + width1 = wp->w_width_inner - win_col_off(wp); + width2 = width1 + win_col_off2(wp); } // Make sure w_topline is at the first of a sequence of folded lines. - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); - validate_cursor(); // w_wrow needs to be valid + hasFolding(wp, wp->w_topline, &wp->w_topline, NULL); + validate_cursor(wp); // w_wrow needs to be valid for (int todo = line_count; todo > 0; todo--) { - if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline) - && curwin->w_topfill < curwin->w_height_inner - 1) { - curwin->w_topfill++; + if (wp->w_topfill < win_get_fill(wp, wp->w_topline) + && wp->w_topfill < wp->w_height_inner - 1) { + wp->w_topfill++; done++; } else { // break when at the very top - if (curwin->w_topline == 1 && (!do_sms || curwin->w_skipcol < width1)) { + if (wp->w_topline == 1 && (!do_sms || wp->w_skipcol < width1)) { break; } - if (do_sms && curwin->w_skipcol >= width1) { + if (do_sms && wp->w_skipcol >= width1) { // scroll a screen line down - if (curwin->w_skipcol >= width1 + width2) { - curwin->w_skipcol -= width2; + if (wp->w_skipcol >= width1 + width2) { + wp->w_skipcol -= width2; } else { - curwin->w_skipcol -= width1; + wp->w_skipcol -= width1; } - redraw_later(curwin, UPD_NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); done++; } else { // scroll a text line down - curwin->w_topline--; - curwin->w_skipcol = 0; - curwin->w_topfill = 0; + wp->w_topline--; + wp->w_skipcol = 0; + wp->w_topfill = 0; // A sequence of folded lines only counts for one logical line linenr_T first; - if (hasFolding(curwin->w_topline, &first, NULL)) { + if (hasFolding(wp, wp->w_topline, &first, NULL)) { done++; if (!byfold) { - todo -= curwin->w_topline - first - 1; + todo -= wp->w_topline - first - 1; } - curwin->w_botline -= curwin->w_topline - first; - curwin->w_topline = first; + wp->w_botline -= wp->w_topline - first; + wp->w_topline = first; } else { if (do_sms) { - int size = win_linetabsize(curwin, curwin->w_topline, - ml_get(curwin->w_topline), MAXCOL); + int size = win_linetabsize(wp, wp->w_topline, + ml_get(wp->w_topline), MAXCOL); if (size > width1) { - curwin->w_skipcol = width1; + wp->w_skipcol = width1; size -= width1; - redraw_later(curwin, UPD_NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } while (size > width2) { - curwin->w_skipcol += width2; + wp->w_skipcol += width2; size -= width2; } done++; } else { - done += plines_win_nofill(curwin, curwin->w_topline, true); + done += plines_win_nofill(wp, wp->w_topline, true); } } } } - curwin->w_botline--; // approximate w_botline - invalidate_botline(curwin); + wp->w_botline--; // approximate w_botline + invalidate_botline(wp); } - curwin->w_wrow += done; // keep w_wrow updated - curwin->w_cline_row += done; // keep w_cline_row updated + wp->w_wrow += done; // keep w_wrow updated + wp->w_cline_row += done; // keep w_cline_row updated - if (curwin->w_cursor.lnum == curwin->w_topline) { - curwin->w_cline_row = 0; + if (wp->w_cursor.lnum == wp->w_topline) { + wp->w_cline_row = 0; } - check_topfill(curwin, true); + check_topfill(wp, true); // Compute the row number of the last row of the cursor line // and move the cursor onto the displayed part of the window. - int wrow = curwin->w_wrow; - if (curwin->w_p_wrap && curwin->w_width_inner != 0) { - validate_virtcol(); - validate_cheight(); - wrow += curwin->w_cline_height - 1 - - curwin->w_virtcol / curwin->w_width_inner; + int wrow = wp->w_wrow; + if (wp->w_p_wrap && wp->w_width_inner != 0) { + validate_virtcol(wp); + validate_cheight(wp); + wrow += wp->w_cline_height - 1 - + wp->w_virtcol / wp->w_width_inner; } bool moved = false; - while (wrow >= curwin->w_height_inner && curwin->w_cursor.lnum > 1) { + while (wrow >= wp->w_height_inner && wp->w_cursor.lnum > 1) { linenr_T first; - if (hasFolding(curwin->w_cursor.lnum, &first, NULL)) { + if (hasFolding(wp, wp->w_cursor.lnum, &first, NULL)) { wrow--; if (first == 1) { - curwin->w_cursor.lnum = 1; + wp->w_cursor.lnum = 1; } else { - curwin->w_cursor.lnum = first - 1; + wp->w_cursor.lnum = first - 1; } } else { - wrow -= plines_win(curwin, curwin->w_cursor.lnum--, true); + wrow -= plines_win(wp, wp->w_cursor.lnum--, true); } - curwin->w_valid &= + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); moved = true; } if (moved) { // Move cursor to first line of closed fold. - foldAdjustCursor(); - coladvance(curwin->w_curswant); + foldAdjustCursor(wp); + coladvance(wp, wp->w_curswant); } - if (curwin->w_cursor.lnum == curwin->w_topline && do_sms) { - int so = get_scrolloff_value(curwin); + if (wp->w_cursor.lnum == wp->w_topline && do_sms) { + int so = get_scrolloff_value(wp); colnr_T scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; // make sure the cursor is in the visible text - validate_virtcol(); - colnr_T col = curwin->w_virtcol - curwin->w_skipcol + scrolloff_cols; + validate_virtcol(wp); + colnr_T col = wp->w_virtcol - wp->w_skipcol + scrolloff_cols; int row = 0; if (col >= width1) { col -= width1; @@ -1337,32 +1314,32 @@ bool scrolldown(linenr_T line_count, int byfold) if (col > width2 && width2 > 0) { row += (int)col / width2; } - if (row >= curwin->w_height_inner) { - curwin->w_curswant = curwin->w_virtcol - (row - curwin->w_height_inner + 1) * width2; - coladvance(curwin->w_curswant); + if (row >= wp->w_height_inner) { + wp->w_curswant = wp->w_virtcol - (row - wp->w_height_inner + 1) * width2; + coladvance(wp, wp->w_curswant); } } return moved; } -/// Scroll the current window up by "line_count" logical lines. "CTRL-E" +/// Scroll a window up by "line_count" logical lines. "CTRL-E" /// /// @param line_count number of lines to scroll /// @param byfold if true, count a closed fold as one line -bool scrollup(linenr_T line_count, bool byfold) +bool scrollup(win_T *wp, linenr_T line_count, bool byfold) { - linenr_T topline = curwin->w_topline; - linenr_T botline = curwin->w_botline; - bool do_sms = curwin->w_p_wrap && curwin->w_p_sms; + linenr_T topline = wp->w_topline; + linenr_T botline = wp->w_botline; + bool do_sms = wp->w_p_wrap && wp->w_p_sms; - if (do_sms || (byfold && hasAnyFolding(curwin)) || win_may_fill(curwin)) { - int width1 = curwin->w_width_inner - curwin_col_off(); - int width2 = width1 + curwin_col_off2(); + if (do_sms || (byfold && hasAnyFolding(wp)) || win_may_fill(wp)) { + int width1 = wp->w_width_inner - win_col_off(wp); + int width2 = width1 + win_col_off2(wp); int size = 0; - const colnr_T prev_skipcol = curwin->w_skipcol; + const colnr_T prev_skipcol = wp->w_skipcol; if (do_sms) { - size = linetabsize(curwin, curwin->w_topline); + size = linetabsize(wp, wp->w_topline); } // diff mode: first consume "topfill" @@ -1370,93 +1347,93 @@ bool scrollup(linenr_T line_count, bool byfold) // the line, then advance to the next line. // folding: count each sequence of folded lines as one logical line. for (int todo = line_count; todo > 0; todo--) { - if (curwin->w_topfill > 0) { - curwin->w_topfill--; + if (wp->w_topfill > 0) { + wp->w_topfill--; } else { - linenr_T lnum = curwin->w_topline; + linenr_T lnum = wp->w_topline; if (byfold) { // for a closed fold: go to the last line in the fold - hasFolding(lnum, NULL, &lnum); + hasFolding(wp, lnum, NULL, &lnum); } - if (lnum == curwin->w_topline && do_sms) { + if (lnum == wp->w_topline && do_sms) { // 'smoothscroll': increase "w_skipcol" until it goes over // the end of the line, then advance to the next line. - int add = curwin->w_skipcol > 0 ? width2 : width1; - curwin->w_skipcol += add; - if (curwin->w_skipcol >= size) { - if (lnum == curbuf->b_ml.ml_line_count) { + int add = wp->w_skipcol > 0 ? width2 : width1; + wp->w_skipcol += add; + if (wp->w_skipcol >= size) { + if (lnum == wp->w_buffer->b_ml.ml_line_count) { // at the last screen line, can't scroll further - curwin->w_skipcol -= add; + wp->w_skipcol -= add; break; } lnum++; } } else { - if (lnum >= curbuf->b_ml.ml_line_count) { + if (lnum >= wp->w_buffer->b_ml.ml_line_count) { break; } lnum++; } - if (lnum > curwin->w_topline) { + if (lnum > wp->w_topline) { // approximate w_botline - curwin->w_botline += lnum - curwin->w_topline; - curwin->w_topline = lnum; - curwin->w_topfill = win_get_fill(curwin, lnum); - curwin->w_skipcol = 0; + wp->w_botline += lnum - wp->w_topline; + wp->w_topline = lnum; + wp->w_topfill = win_get_fill(wp, lnum); + wp->w_skipcol = 0; if (todo > 1 && do_sms) { - size = linetabsize(curwin, curwin->w_topline); + size = linetabsize(wp, wp->w_topline); } } } } - if (prev_skipcol > 0 || curwin->w_skipcol > 0) { + if (prev_skipcol > 0 || wp->w_skipcol > 0) { // need to redraw more, because wl_size of the (new) topline may // now be invalid - redraw_later(curwin, UPD_NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } } else { - curwin->w_topline += line_count; - curwin->w_botline += line_count; // approximate w_botline + wp->w_topline += line_count; + wp->w_botline += line_count; // approximate w_botline } - if (curwin->w_topline > curbuf->b_ml.ml_line_count) { - curwin->w_topline = curbuf->b_ml.ml_line_count; + if (wp->w_topline > wp->w_buffer->b_ml.ml_line_count) { + wp->w_topline = wp->w_buffer->b_ml.ml_line_count; } - if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1) { - curwin->w_botline = curbuf->b_ml.ml_line_count + 1; + if (wp->w_botline > wp->w_buffer->b_ml.ml_line_count + 1) { + wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1; } - check_topfill(curwin, false); + check_topfill(wp, false); - if (hasAnyFolding(curwin)) { + if (hasAnyFolding(wp)) { // Make sure w_topline is at the first of a sequence of folded lines. - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(wp, wp->w_topline, &wp->w_topline, NULL); } - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - if (curwin->w_cursor.lnum < curwin->w_topline) { - curwin->w_cursor.lnum = curwin->w_topline; - curwin->w_valid &= + wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); + if (wp->w_cursor.lnum < wp->w_topline) { + wp->w_cursor.lnum = wp->w_topline; + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); - coladvance(curwin->w_curswant); + coladvance(wp, wp->w_curswant); } - if (curwin->w_cursor.lnum == curwin->w_topline && do_sms && curwin->w_skipcol > 0) { - int col_off = curwin_col_off(); - int col_off2 = curwin_col_off2(); + if (wp->w_cursor.lnum == wp->w_topline && do_sms && wp->w_skipcol > 0) { + int col_off = win_col_off(wp); + int col_off2 = win_col_off2(wp); - int width1 = curwin->w_width_inner - col_off; + int width1 = wp->w_width_inner - col_off; int width2 = width1 + col_off2; int extra2 = col_off - col_off2; - int so = get_scrolloff_value(curwin); + int so = get_scrolloff_value(wp); colnr_T scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; - int space_cols = (curwin->w_height_inner - 1) * width2; + int space_cols = (wp->w_height_inner - 1) * width2; // If we have non-zero scrolloff, just ignore the marker as we are // going past it anyway. - int overlap = scrolloff_cols != 0 ? 0 : sms_marker_overlap(curwin, extra2); + int overlap = scrolloff_cols != 0 ? 0 : sms_marker_overlap(wp, extra2); // Make sure the cursor is in a visible part of the line, taking // 'scrolloff' into account, but using screen lines. @@ -1464,26 +1441,26 @@ bool scrollup(linenr_T line_count, bool byfold) if (scrolloff_cols > space_cols / 2) { scrolloff_cols = space_cols / 2; } - validate_virtcol(); - if (curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) { - colnr_T col = curwin->w_virtcol; + validate_virtcol(wp); + if (wp->w_virtcol < wp->w_skipcol + overlap + scrolloff_cols) { + colnr_T col = wp->w_virtcol; if (col < width1) { col += width1; } - while (col < curwin->w_skipcol + overlap + scrolloff_cols) { + while (col < wp->w_skipcol + overlap + scrolloff_cols) { col += width2; } - curwin->w_curswant = col; - coladvance(curwin->w_curswant); + wp->w_curswant = col; + coladvance(wp, wp->w_curswant); // validate_virtcol() marked various things as valid, but after // moving the cursor they need to be recomputed - curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); } } - bool moved = topline != curwin->w_topline || botline != curwin->w_botline; + bool moved = topline != wp->w_topline || botline != wp->w_botline; return moved; } @@ -1496,16 +1473,16 @@ void adjust_skipcol(void) return; } - int width1 = curwin->w_width_inner - curwin_col_off(); + int width1 = curwin->w_width_inner - win_col_off(curwin); if (width1 <= 0) { return; // no text will be displayed } - int width2 = width1 + curwin_col_off2(); + int width2 = width1 + win_col_off2(curwin); int so = get_scrolloff_value(curwin); colnr_T scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; bool scrolled = false; - validate_cheight(); + validate_cheight(curwin); if (curwin->w_cline_height == curwin->w_height_inner // w_cline_height may be capped at w_height_inner, check there aren't // actually more lines. @@ -1515,8 +1492,8 @@ void adjust_skipcol(void) return; } - validate_virtcol(); - int overlap = sms_marker_overlap(curwin, curwin_col_off() - curwin_col_off2()); + validate_virtcol(curwin); + int overlap = sms_marker_overlap(curwin, win_col_off(curwin) - win_col_off2(curwin)); while (curwin->w_skipcol > 0 && curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) { // scroll a screen line down @@ -1528,7 +1505,7 @@ void adjust_skipcol(void) scrolled = true; } if (scrolled) { - validate_virtcol(); + validate_virtcol(curwin); redraw_later(curwin, UPD_NOT_VALID); return; // don't scroll in the other direction now } @@ -1572,7 +1549,7 @@ void check_topfill(win_T *wp, bool down) } } } - win_check_anchored_floats(curwin); + win_check_anchored_floats(wp); } // Use as many filler lines as possible for w_topline. Make sure w_topline @@ -1601,7 +1578,7 @@ void scrolldown_clamp(void) return; } - validate_cursor(); // w_wrow needs to be valid + validate_cursor(curwin); // w_wrow needs to be valid // Compute the row number of the last row of the cursor line // and make sure it doesn't go off the screen. Make sure the cursor @@ -1613,8 +1590,8 @@ void scrolldown_clamp(void) end_row += plines_win_nofill(curwin, curwin->w_topline - 1, true); } if (curwin->w_p_wrap && curwin->w_width_inner != 0) { - validate_cheight(); - validate_virtcol(); + validate_cheight(curwin); + validate_virtcol(curwin); end_row += curwin->w_cline_height - 1 - curwin->w_virtcol / curwin->w_width_inner; } @@ -1626,7 +1603,7 @@ void scrolldown_clamp(void) curwin->w_topline--; curwin->w_topfill = 0; } - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); curwin->w_botline--; // approximate w_botline curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); } @@ -1641,7 +1618,7 @@ void scrollup_clamp(void) return; } - validate_cursor(); // w_wrow needs to be valid + validate_cursor(curwin); // w_wrow needs to be valid // Compute the row number of the first row of the cursor line // and make sure it doesn't go off the screen. Make sure the cursor @@ -1650,14 +1627,14 @@ void scrollup_clamp(void) - plines_win_nofill(curwin, curwin->w_topline, true) - curwin->w_topfill); if (curwin->w_p_wrap && curwin->w_width_inner != 0) { - validate_virtcol(); + validate_virtcol(curwin); start_row -= curwin->w_virtcol / curwin->w_width_inner; } if (start_row >= get_scrolloff_value(curwin)) { if (curwin->w_topfill > 0) { curwin->w_topfill--; } else { - hasFolding(curwin->w_topline, NULL, &curwin->w_topline); + hasFolding(curwin, curwin->w_topline, NULL, &curwin->w_topline); curwin->w_topline++; } curwin->w_botline++; // approximate w_botline @@ -1681,7 +1658,7 @@ static void topline_back_winheight(win_T *wp, lineoff_T *lp, int winheight) lp->fill = 0; if (lp->lnum < 1) { lp->height = MAXCOL; - } else if (hasFolding(lp->lnum, &lp->lnum, NULL)) { + } else if (hasFolding(wp, lp->lnum, &lp->lnum, NULL)) { // Add a closed fold lp->height = 1; } else { @@ -1711,7 +1688,7 @@ static void botline_forw(win_T *wp, lineoff_T *lp) assert(wp->w_buffer != 0); if (lp->lnum > wp->w_buffer->b_ml.ml_line_count) { lp->height = MAXCOL; - } else if (hasFoldingWin(wp, lp->lnum, NULL, &lp->lnum, true, NULL)) { + } else if (hasFolding(wp, lp->lnum, NULL, &lp->lnum)) { // Add a closed fold lp->height = 1; } else { @@ -1745,12 +1722,12 @@ static void topline_botline(lineoff_T *lp) // Recompute topline to put the cursor at the top of the window. // Scroll at least "min_scroll" lines. // If "always" is true, always set topline (for "zt"). -void scroll_cursor_top(int min_scroll, int always) +void scroll_cursor_top(win_T *wp, int min_scroll, int always) { - linenr_T old_topline = curwin->w_topline; - int old_skipcol = curwin->w_skipcol; - linenr_T old_topfill = curwin->w_topfill; - int off = get_scrolloff_value(curwin); + linenr_T old_topline = wp->w_topline; + int old_skipcol = wp->w_skipcol; + linenr_T old_topfill = wp->w_topfill; + int off = get_scrolloff_value(wp); if (mouse_dragging > 0) { off = mouse_dragging - 1; @@ -1761,54 +1738,54 @@ void scroll_cursor_top(int min_scroll, int always) // - (part of) the cursor line is moved off the screen or // - moved at least 'scrolljump' lines and // - at least 'scrolloff' lines above and below the cursor - validate_cheight(); + validate_cheight(wp); int scrolled = 0; - int used = curwin->w_cline_height; // includes filler lines above - if (curwin->w_cursor.lnum < curwin->w_topline) { + int used = wp->w_cline_height; // includes filler lines above + if (wp->w_cursor.lnum < wp->w_topline) { scrolled = used; } linenr_T top; // just above displayed lines linenr_T bot; // just below displayed lines - if (hasFolding(curwin->w_cursor.lnum, &top, &bot)) { + if (hasFolding(wp, wp->w_cursor.lnum, &top, &bot)) { top--; bot++; } else { - top = curwin->w_cursor.lnum - 1; - bot = curwin->w_cursor.lnum + 1; + top = wp->w_cursor.lnum - 1; + bot = wp->w_cursor.lnum + 1; } linenr_T new_topline = top + 1; // "used" already contains the number of filler lines above, don't add it // again. // Hide filler lines above cursor line by adding them to "extra". - int extra = win_get_fill(curwin, curwin->w_cursor.lnum); + int extra = win_get_fill(wp, wp->w_cursor.lnum); // Check if the lines from "top" to "bot" fit in the window. If they do, // set new_topline and advance "top" and "bot" to include more lines. while (top > 0) { - int i = hasFolding(top, &top, NULL) + int i = hasFolding(wp, top, &top, NULL) ? 1 // count one logical line for a sequence of folded lines - : plines_win_nofill(curwin, top, true); - if (top < curwin->w_topline) { + : plines_win_nofill(wp, top, true); + if (top < wp->w_topline) { scrolled += i; } // If scrolling is needed, scroll at least 'sj' lines. - if ((new_topline >= curwin->w_topline || scrolled > min_scroll) && extra >= off) { + if ((new_topline >= wp->w_topline || scrolled > min_scroll) && extra >= off) { break; } used += i; - if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) { - if (hasFolding(bot, NULL, &bot)) { + if (extra + i <= off && bot < wp->w_buffer->b_ml.ml_line_count) { + if (hasFolding(wp, bot, NULL, &bot)) { // count one logical line for a sequence of folded lines used++; } else { - used += plines_win(curwin, bot, true); + used += plines_win(wp, bot, true); } } - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { break; } @@ -1821,43 +1798,43 @@ void scroll_cursor_top(int min_scroll, int always) // If we don't have enough space, put cursor in the middle. // This makes sure we get the same position when using "k" and "j" // in a small window. - if (used > curwin->w_height_inner) { - scroll_cursor_halfway(false, false); + if (used > wp->w_height_inner) { + scroll_cursor_halfway(wp, false, false); } else { // If "always" is false, only adjust topline to a lower value, higher // value may happen with wrapping lines. - if (new_topline < curwin->w_topline || always) { - curwin->w_topline = new_topline; + if (new_topline < wp->w_topline || always) { + wp->w_topline = new_topline; } - if (curwin->w_topline > curwin->w_cursor.lnum) { - curwin->w_topline = curwin->w_cursor.lnum; + if (wp->w_topline > wp->w_cursor.lnum) { + wp->w_topline = wp->w_cursor.lnum; } - curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); - if (curwin->w_topfill > 0 && extra > off) { - curwin->w_topfill -= extra - off; - if (curwin->w_topfill < 0) { - curwin->w_topfill = 0; + wp->w_topfill = win_get_fill(wp, wp->w_topline); + if (wp->w_topfill > 0 && extra > off) { + wp->w_topfill -= extra - off; + if (wp->w_topfill < 0) { + wp->w_topfill = 0; } } - check_topfill(curwin, false); - if (curwin->w_topline != old_topline) { - reset_skipcol(curwin); - } else if (curwin->w_topline == curwin->w_cursor.lnum) { - validate_virtcol(); - if (curwin->w_skipcol >= curwin->w_virtcol) { + check_topfill(wp, false); + if (wp->w_topline != old_topline) { + reset_skipcol(wp); + } else if (wp->w_topline == wp->w_cursor.lnum) { + validate_virtcol(wp); + if (wp->w_skipcol >= wp->w_virtcol) { // TODO(vim): if the line doesn't fit may optimize w_skipcol instead // of making it zero - reset_skipcol(curwin); + reset_skipcol(wp); } } - if (curwin->w_topline != old_topline - || curwin->w_skipcol != old_skipcol - || curwin->w_topfill != old_topfill) { - curwin->w_valid &= + if (wp->w_topline != old_topline + || wp->w_skipcol != old_skipcol + || wp->w_topfill != old_topfill) { + wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); } - curwin->w_valid |= VALID_TOPLINE; - curwin->w_viewport_invalid = true; + wp->w_valid |= VALID_TOPLINE; + wp->w_viewport_invalid = true; } } @@ -1886,79 +1863,79 @@ void set_empty_rows(win_T *wp, int used) /// When scrolling scroll at least "min_scroll" lines. /// If "set_topbot" is true, set topline and botline first (for "zb"). /// This is messy stuff!!! -void scroll_cursor_bot(int min_scroll, bool set_topbot) +void scroll_cursor_bot(win_T *wp, int min_scroll, bool set_topbot) { lineoff_T loff; - linenr_T old_topline = curwin->w_topline; - int old_skipcol = curwin->w_skipcol; - int old_topfill = curwin->w_topfill; - linenr_T old_botline = curwin->w_botline; - int old_valid = curwin->w_valid; - int old_empty_rows = curwin->w_empty_rows; - linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number - bool do_sms = curwin->w_p_wrap && curwin->w_p_sms; + linenr_T old_topline = wp->w_topline; + int old_skipcol = wp->w_skipcol; + int old_topfill = wp->w_topfill; + linenr_T old_botline = wp->w_botline; + int old_valid = wp->w_valid; + int old_empty_rows = wp->w_empty_rows; + linenr_T cln = wp->w_cursor.lnum; // Cursor Line Number + bool do_sms = wp->w_p_wrap && wp->w_p_sms; if (set_topbot) { bool set_skipcol = false; int used = 0; - curwin->w_botline = cln + 1; + wp->w_botline = cln + 1; loff.fill = 0; - for (curwin->w_topline = curwin->w_botline; - curwin->w_topline > 1; - curwin->w_topline = loff.lnum) { - loff.lnum = curwin->w_topline; - topline_back_winheight(curwin, &loff, false); + for (wp->w_topline = wp->w_botline; + wp->w_topline > 1; + wp->w_topline = loff.lnum) { + loff.lnum = wp->w_topline; + topline_back_winheight(wp, &loff, false); if (loff.height == MAXCOL) { break; } - if (used + loff.height > curwin->w_height_inner) { + if (used + loff.height > wp->w_height_inner) { if (do_sms) { // 'smoothscroll' and 'wrap' are set. The above line is // too long to show in its entirety, so we show just a part // of it. - if (used < curwin->w_height_inner) { - int plines_offset = used + loff.height - curwin->w_height_inner; - used = curwin->w_height_inner; - curwin->w_topfill = loff.fill; - curwin->w_topline = loff.lnum; - curwin->w_skipcol = skipcol_from_plines(curwin, plines_offset); + if (used < wp->w_height_inner) { + int plines_offset = used + loff.height - wp->w_height_inner; + used = wp->w_height_inner; + wp->w_topfill = loff.fill; + wp->w_topline = loff.lnum; + wp->w_skipcol = skipcol_from_plines(wp, plines_offset); set_skipcol = true; } } break; } used += loff.height; - curwin->w_topfill = loff.fill; + wp->w_topfill = loff.fill; } - set_empty_rows(curwin, used); - curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; - if (curwin->w_topline != old_topline - || curwin->w_topfill != old_topfill + set_empty_rows(wp, used); + wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; + if (wp->w_topline != old_topline + || wp->w_topfill != old_topfill || set_skipcol - || curwin->w_skipcol != 0) { - curwin->w_valid &= ~(VALID_WROW|VALID_CROW); + || wp->w_skipcol != 0) { + wp->w_valid &= ~(VALID_WROW|VALID_CROW); if (set_skipcol) { - redraw_later(curwin, UPD_NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } else { - reset_skipcol(curwin); + reset_skipcol(wp); } } } else { - validate_botline(curwin); + validate_botline(wp); } // The lines of the cursor line itself are always used. - int used = plines_win_nofill(curwin, cln, true); + int used = plines_win_nofill(wp, cln, true); int scrolled = 0; // If the cursor is on or below botline, we will at least scroll by the // height of the cursor line, which is "used". Correct for empty lines, // which are really part of botline. - if (cln >= curwin->w_botline) { + if (cln >= wp->w_botline) { scrolled = used; - if (cln == curwin->w_botline) { - scrolled -= curwin->w_empty_rows; + if (cln == wp->w_botline) { + scrolled -= wp->w_empty_rows; } if (do_sms) { // 'smoothscroll' and 'wrap' are set. @@ -1966,21 +1943,21 @@ void scroll_cursor_bot(int min_scroll, bool set_topbot) // occupies. If it is occupying more than the entire window, we // need to scroll the additional clipped lines to scroll past the // top line before we can move on to the other lines. - int top_plines = plines_win_nofill(curwin, curwin->w_topline, false); + int top_plines = plines_win_nofill(wp, wp->w_topline, false); int skip_lines = 0; - int width1 = curwin->w_width_inner - curwin_col_off(); + int width1 = wp->w_width_inner - win_col_off(wp); if (width1 > 0) { - int width2 = width1 + curwin_col_off2(); + int width2 = width1 + win_col_off2(wp); // similar formula is used in curs_columns() - if (curwin->w_skipcol > width1) { - skip_lines += (curwin->w_skipcol - width1) / width2 + 1; - } else if (curwin->w_skipcol > 0) { + if (wp->w_skipcol > width1) { + skip_lines += (wp->w_skipcol - width1) / width2 + 1; + } else if (wp->w_skipcol > 0) { skip_lines = 1; } top_plines -= skip_lines; - if (top_plines > curwin->w_height_inner) { - scrolled += (top_plines - curwin->w_height_inner); + if (top_plines > wp->w_height_inner) { + scrolled += (top_plines - wp->w_height_inner); } } } @@ -1992,67 +1969,67 @@ void scroll_cursor_bot(int min_scroll, bool set_topbot) // - scrolled nothing or at least 'sj' lines // - at least 'so' lines below the cursor // - lines between botline and cursor have been counted - if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum)) { + if (!hasFolding(wp, wp->w_cursor.lnum, &loff.lnum, &boff.lnum)) { loff.lnum = cln; boff.lnum = cln; } loff.fill = 0; boff.fill = 0; - int fill_below_window = win_get_fill(curwin, curwin->w_botline) - curwin->w_filler_rows; + int fill_below_window = win_get_fill(wp, wp->w_botline) - wp->w_filler_rows; int extra = 0; - int so = get_scrolloff_value(curwin); + int so = get_scrolloff_value(wp); while (loff.lnum > 1) { // Stop when scrolled nothing or at least "min_scroll", found "extra" // context for 'scrolloff' and counted all lines below the window. if ((((scrolled <= 0 || scrolled >= min_scroll) && extra >= (mouse_dragging > 0 ? mouse_dragging - 1 : so)) - || boff.lnum + 1 > curbuf->b_ml.ml_line_count) - && loff.lnum <= curwin->w_botline - && (loff.lnum < curwin->w_botline + || boff.lnum + 1 > wp->w_buffer->b_ml.ml_line_count) + && loff.lnum <= wp->w_botline + && (loff.lnum < wp->w_botline || loff.fill >= fill_below_window)) { break; } // Add one line above - topline_back(curwin, &loff); + topline_back(wp, &loff); if (loff.height == MAXCOL) { used = MAXCOL; } else { used += loff.height; } - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { break; } - if (loff.lnum >= curwin->w_botline - && (loff.lnum > curwin->w_botline + if (loff.lnum >= wp->w_botline + && (loff.lnum > wp->w_botline || loff.fill <= fill_below_window)) { // Count screen lines that are below the window. scrolled += loff.height; - if (loff.lnum == curwin->w_botline + if (loff.lnum == wp->w_botline && loff.fill == 0) { - scrolled -= curwin->w_empty_rows; + scrolled -= wp->w_empty_rows; } } - if (boff.lnum < curbuf->b_ml.ml_line_count) { + if (boff.lnum < wp->w_buffer->b_ml.ml_line_count) { // Add one line below - botline_forw(curwin, &boff); + botline_forw(wp, &boff); used += boff.height; - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { break; } if (extra < (mouse_dragging > 0 ? mouse_dragging - 1 : so) || scrolled < min_scroll) { extra += boff.height; - if (boff.lnum >= curwin->w_botline - || (boff.lnum + 1 == curwin->w_botline - && boff.fill > curwin->w_filler_rows)) { + if (boff.lnum >= wp->w_botline + || (boff.lnum + 1 == wp->w_botline + && boff.fill > wp->w_filler_rows)) { // Count screen lines that are below the window. scrolled += boff.height; - if (boff.lnum == curwin->w_botline + if (boff.lnum == wp->w_botline && boff.fill == 0) { - scrolled -= curwin->w_empty_rows; + scrolled -= wp->w_empty_rows; } } } @@ -2060,77 +2037,77 @@ void scroll_cursor_bot(int min_scroll, bool set_topbot) } linenr_T line_count; - // curwin->w_empty_rows is larger, no need to scroll + // wp->w_empty_rows is larger, no need to scroll if (scrolled <= 0) { line_count = 0; // more than a screenfull, don't scroll but redraw - } else if (used > curwin->w_height_inner) { + } else if (used > wp->w_height_inner) { line_count = used; // scroll minimal number of lines } else { line_count = 0; - boff.fill = curwin->w_topfill; - boff.lnum = curwin->w_topline - 1; + boff.fill = wp->w_topfill; + boff.lnum = wp->w_topline - 1; int i; - for (i = 0; i < scrolled && boff.lnum < curwin->w_botline;) { - botline_forw(curwin, &boff); + for (i = 0; i < scrolled && boff.lnum < wp->w_botline;) { + botline_forw(wp, &boff); i += boff.height; line_count++; } - if (i < scrolled) { // below curwin->w_botline, don't scroll + if (i < scrolled) { // below wp->w_botline, don't scroll line_count = 9999; } } // Scroll up if the cursor is off the bottom of the screen a bit. // Otherwise put it at 1/2 of the screen. - if (line_count >= curwin->w_height_inner && line_count > min_scroll) { - scroll_cursor_halfway(false, true); + if (line_count >= wp->w_height_inner && line_count > min_scroll) { + scroll_cursor_halfway(wp, false, true); } else if (line_count > 0) { if (do_sms) { - scrollup(scrolled, true); // TODO(vim): + scrollup(wp, scrolled, true); // TODO(vim): } else { - scrollup(line_count, true); + scrollup(wp, line_count, true); } } // If topline didn't change we need to restore w_botline and w_empty_rows // (we changed them). // If topline did change, update_screen() will set botline. - if (curwin->w_topline == old_topline && curwin->w_skipcol == old_skipcol && set_topbot) { - curwin->w_botline = old_botline; - curwin->w_empty_rows = old_empty_rows; - curwin->w_valid = old_valid; + if (wp->w_topline == old_topline && wp->w_skipcol == old_skipcol && set_topbot) { + wp->w_botline = old_botline; + wp->w_empty_rows = old_empty_rows; + wp->w_valid = old_valid; } - curwin->w_valid |= VALID_TOPLINE; - curwin->w_viewport_invalid = true; + wp->w_valid |= VALID_TOPLINE; + wp->w_viewport_invalid = true; } /// Recompute topline to put the cursor halfway across the window /// /// @param atend if true, also put the cursor halfway to the end of the file. /// -void scroll_cursor_halfway(bool atend, bool prefer_above) +void scroll_cursor_halfway(win_T *wp, bool atend, bool prefer_above) { - linenr_T old_topline = curwin->w_topline; - lineoff_T loff = { .lnum = curwin->w_cursor.lnum }; - lineoff_T boff = { .lnum = curwin->w_cursor.lnum }; - hasFolding(loff.lnum, &loff.lnum, &boff.lnum); - int used = plines_win_nofill(curwin, loff.lnum, true); + linenr_T old_topline = wp->w_topline; + lineoff_T loff = { .lnum = wp->w_cursor.lnum }; + lineoff_T boff = { .lnum = wp->w_cursor.lnum }; + hasFolding(wp, loff.lnum, &loff.lnum, &boff.lnum); + int used = plines_win_nofill(wp, loff.lnum, true); loff.fill = 0; boff.fill = 0; linenr_T topline = loff.lnum; colnr_T skipcol = 0; int want_height; - bool do_sms = curwin->w_p_wrap && curwin->w_p_sms; + bool do_sms = wp->w_p_wrap && wp->w_p_sms; if (do_sms) { // 'smoothscroll' and 'wrap' are set if (atend) { - want_height = (curwin->w_height_inner - used) / 2; + want_height = (wp->w_height_inner - used) / 2; used = 0; } else { - want_height = curwin->w_height_inner; + want_height = wp->w_height_inner; } } @@ -2139,20 +2116,20 @@ void scroll_cursor_halfway(bool atend, bool prefer_above) // If using smoothscroll, we can precisely scroll to the // exact point where the cursor is halfway down the screen. if (do_sms) { - topline_back_winheight(curwin, &loff, false); + topline_back_winheight(wp, &loff, false); if (loff.height == MAXCOL) { break; } used += loff.height; - if (!atend && boff.lnum < curbuf->b_ml.ml_line_count) { - botline_forw(curwin, &boff); + if (!atend && boff.lnum < wp->w_buffer->b_ml.ml_line_count) { + botline_forw(wp, &boff); used += boff.height; } if (used > want_height) { if (used - loff.height < want_height) { topline = loff.lnum; topfill = loff.fill; - skipcol = skipcol_from_plines(curwin, used - want_height); + skipcol = skipcol_from_plines(wp, used - want_height); } break; } @@ -2176,10 +2153,10 @@ void scroll_cursor_halfway(bool atend, bool prefer_above) ? (round == 2 && below < above) : (round == 1 && below <= above)) { // add a line below the cursor - if (boff.lnum < curbuf->b_ml.ml_line_count) { - botline_forw(curwin, &boff); + if (boff.lnum < wp->w_buffer->b_ml.ml_line_count) { + botline_forw(wp, &boff); used += boff.height; - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { done = true; break; } @@ -2196,13 +2173,13 @@ void scroll_cursor_halfway(bool atend, bool prefer_above) ? (round == 1 && below >= above) : (round == 1 && below > above)) { // add a line above the cursor - topline_back(curwin, &loff); + topline_back(wp, &loff); if (loff.height == MAXCOL) { used = MAXCOL; } else { used += loff.height; } - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { done = true; break; } @@ -2216,51 +2193,51 @@ void scroll_cursor_halfway(bool atend, bool prefer_above) } } - if (!hasFolding(topline, &curwin->w_topline, NULL) - && (curwin->w_topline != topline || skipcol != 0 || curwin->w_skipcol != 0)) { - curwin->w_topline = topline; + if (!hasFolding(wp, topline, &wp->w_topline, NULL) + && (wp->w_topline != topline || skipcol != 0 || wp->w_skipcol != 0)) { + wp->w_topline = topline; if (skipcol != 0) { - curwin->w_skipcol = skipcol; - redraw_later(curwin, UPD_NOT_VALID); + wp->w_skipcol = skipcol; + redraw_later(wp, UPD_NOT_VALID); } else if (do_sms) { - reset_skipcol(curwin); + reset_skipcol(wp); } } - curwin->w_topfill = topfill; - if (old_topline > curwin->w_topline + curwin->w_height_inner) { - curwin->w_botfill = false; + wp->w_topfill = topfill; + if (old_topline > wp->w_topline + wp->w_height_inner) { + wp->w_botfill = false; } - check_topfill(curwin, false); - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); - curwin->w_valid |= VALID_TOPLINE; + check_topfill(wp, false); + wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); + wp->w_valid |= VALID_TOPLINE; } // Correct the cursor position so that it is in a part of the screen at least // 'so' lines from the top and bottom, if possible. // If not possible, put it at the same position as scroll_cursor_halfway(). // When called topline must be valid! -void cursor_correct(void) +void cursor_correct(win_T *wp) { // How many lines we would like to have above/below the cursor depends on // whether the first/last line of the file is on screen. - int above_wanted = get_scrolloff_value(curwin); - int below_wanted = get_scrolloff_value(curwin); + int above_wanted = get_scrolloff_value(wp); + int below_wanted = get_scrolloff_value(wp); if (mouse_dragging > 0) { above_wanted = mouse_dragging - 1; below_wanted = mouse_dragging - 1; } - if (curwin->w_topline == 1) { + if (wp->w_topline == 1) { above_wanted = 0; - int max_off = curwin->w_height_inner / 2; + int max_off = wp->w_height_inner / 2; if (below_wanted > max_off) { below_wanted = max_off; } } - validate_botline(curwin); - if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1 + validate_botline(wp); + if (wp->w_botline == wp->w_buffer->b_ml.ml_line_count + 1 && mouse_dragging == 0) { below_wanted = 0; - int max_off = (curwin->w_height_inner - 1) / 2; + int max_off = (wp->w_height_inner - 1) / 2; if (above_wanted > max_off) { above_wanted = max_off; } @@ -2268,18 +2245,18 @@ void cursor_correct(void) // If there are sufficient file-lines above and below the cursor, we can // return now. - linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number - if (cln >= curwin->w_topline + above_wanted - && cln < curwin->w_botline - below_wanted - && !hasAnyFolding(curwin)) { + linenr_T cln = wp->w_cursor.lnum; // Cursor Line Number + if (cln >= wp->w_topline + above_wanted + && cln < wp->w_botline - below_wanted + && !hasAnyFolding(wp)) { return; } - if (curwin->w_p_sms && !curwin->w_p_wrap) { + if (wp->w_p_sms && !wp->w_p_wrap) { // 'smoothscroll' is active - if (curwin->w_cline_height == curwin->w_height_inner) { + if (wp->w_cline_height == wp->w_height_inner) { // The cursor line just fits in the window, don't scroll. - reset_skipcol(curwin); + reset_skipcol(wp); return; } // TODO(vim): If the cursor line doesn't fit in the window then only adjust w_skipcol. @@ -2289,52 +2266,52 @@ void cursor_correct(void) // the top and the bottom until: // - the desired context lines are found // - the lines from the top is past the lines from the bottom - linenr_T topline = curwin->w_topline; - linenr_T botline = curwin->w_botline - 1; + linenr_T topline = wp->w_topline; + linenr_T botline = wp->w_botline - 1; // count filler lines as context - int above = curwin->w_topfill; // screen lines above topline - int below = curwin->w_filler_rows; // screen lines below botline + int above = wp->w_topfill; // screen lines above topline + int below = wp->w_filler_rows; // screen lines below botline while ((above < above_wanted || below < below_wanted) && topline < botline) { if (below < below_wanted && (below <= above || above >= above_wanted)) { - if (hasFolding(botline, &botline, NULL)) { + if (hasFolding(wp, botline, &botline, NULL)) { below++; } else { - below += plines_win(curwin, botline, true); + below += plines_win(wp, botline, true); } botline--; } if (above < above_wanted && (above < below || below >= below_wanted)) { - if (hasFolding(topline, NULL, &topline)) { + if (hasFolding(wp, topline, NULL, &topline)) { above++; } else { - above += plines_win_nofill(curwin, topline, true); + above += plines_win_nofill(wp, topline, true); } // Count filler lines below this line as context. if (topline < botline) { - above += win_get_fill(curwin, topline + 1); + above += win_get_fill(wp, topline + 1); } topline++; } } if (topline == botline || botline == 0) { - curwin->w_cursor.lnum = topline; + wp->w_cursor.lnum = topline; } else if (topline > botline) { - curwin->w_cursor.lnum = botline; + wp->w_cursor.lnum = botline; } else { - if (cln < topline && curwin->w_topline > 1) { - curwin->w_cursor.lnum = topline; - curwin->w_valid &= + if (cln < topline && wp->w_topline > 1) { + wp->w_cursor.lnum = topline; + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW); } - if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = botline; - curwin->w_valid &= + if (cln > botline && wp->w_botline <= wp->w_buffer->b_ml.ml_line_count) { + wp->w_cursor.lnum = botline; + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW); } } - curwin->w_valid |= VALID_TOPLINE; - curwin->w_viewport_invalid = true; + wp->w_valid |= VALID_TOPLINE; + wp->w_viewport_invalid = true; } /// Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD) @@ -2461,7 +2438,7 @@ int onepage(Direction dir, int count) botline_forw(curwin, &loff); botline_topline(&loff); // We're at the wrong end of a fold now. - hasFoldingWin(curwin, loff.lnum, &loff.lnum, NULL, true, NULL); + hasFolding(curwin, loff.lnum, &loff.lnum, NULL); // Always scroll at least one line. Avoid getting stuck on // very long lines. @@ -2491,9 +2468,9 @@ int onepage(Direction dir, int count) } } } - foldAdjustCursor(); - cursor_correct(); - check_cursor_col(); + foldAdjustCursor(curwin); + cursor_correct(curwin); + check_cursor_col(curwin); if (retval == OK) { beginline(BL_SOL | BL_FIX); } @@ -2504,14 +2481,14 @@ int onepage(Direction dir, int count) // But make sure we scroll at least one line (happens with mix of long // wrapping lines and non-wrapping line). if (check_top_offset()) { - scroll_cursor_top(1, false); + scroll_cursor_top(curwin, 1, false); if (curwin->w_topline <= old_topline && old_topline < curbuf->b_ml.ml_line_count) { curwin->w_topline = old_topline + 1; - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); } } else if (curwin->w_botline > curbuf->b_ml.ml_line_count) { - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); } } @@ -2610,7 +2587,7 @@ void halfpage(bool flag, linenr_T Prenum) if (n < 0 && scrolled > 0) { break; } - hasFolding(curwin->w_topline, NULL, &curwin->w_topline); + hasFolding(curwin, curwin->w_topline, NULL, &curwin->w_topline); curwin->w_topline++; curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); @@ -2634,7 +2611,7 @@ void halfpage(bool flag, linenr_T Prenum) if (i > room) { break; } - hasFolding(curwin->w_botline, NULL, &curwin->w_botline); + hasFolding(curwin, curwin->w_botline, NULL, &curwin->w_botline); curwin->w_botline++; room -= i; } while (curwin->w_botline <= curbuf->b_ml.ml_line_count); @@ -2646,7 +2623,7 @@ void halfpage(bool flag, linenr_T Prenum) if (hasAnyFolding(curwin)) { while (--n >= 0 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - hasFolding(curwin->w_cursor.lnum, NULL, + hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum); curwin->w_cursor.lnum++; } @@ -2669,7 +2646,7 @@ void halfpage(bool flag, linenr_T Prenum) break; } curwin->w_topline--; - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); curwin->w_topfill = 0; } curwin->w_valid &= ~(VALID_CROW|VALID_WROW| @@ -2688,7 +2665,7 @@ void halfpage(bool flag, linenr_T Prenum) } else if (hasAnyFolding(curwin)) { while (--n >= 0 && curwin->w_cursor.lnum > 1) { curwin->w_cursor.lnum--; - hasFolding(curwin->w_cursor.lnum, + hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); } } else { @@ -2697,9 +2674,9 @@ void halfpage(bool flag, linenr_T Prenum) } } // Move cursor to first line of closed fold. - foldAdjustCursor(); + foldAdjustCursor(curwin); check_topfill(curwin, !flag); - cursor_correct(); + cursor_correct(curwin); beginline(BL_SOL | BL_FIX); redraw_later(curwin, UPD_VALID); } @@ -2748,12 +2725,12 @@ void do_check_cursorbind(void) { int restart_edit_save = restart_edit; restart_edit = true; - check_cursor(); + check_cursor(curwin); // Avoid a scroll here for the cursor position, 'scrollbind' is // more important. if (!curwin->w_p_scb) { - validate_cursor(); + validate_cursor(curwin); } restart_edit = restart_edit_save; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index aae9621d4a..3603a054b6 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1009,12 +1009,12 @@ normal_end: mb_check_adjust_col(curwin); // #6203 if (curwin->w_p_scb && s->toplevel) { - validate_cursor(); // may need to update w_leftcol + validate_cursor(curwin); // may need to update w_leftcol do_check_scrollbind(true); } if (curwin->w_p_crb && s->toplevel) { - validate_cursor(); // may need to update w_leftcol + validate_cursor(curwin); // may need to update w_leftcol do_check_cursorbind(); } @@ -1343,7 +1343,7 @@ static void normal_redraw(NormalState *s) // Before redrawing, make sure w_topline is correct, and w_leftcol // if lines don't wrap, and w_skipcol if lines wrap. update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); show_cursor_info_later(false); @@ -1420,7 +1420,7 @@ static int normal_check(VimState *state) // Ensure curwin->w_topline and curwin->w_leftcol are up to date // before triggering a WinScrolled autocommand. update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); normal_check_cursor_moved(s); normal_check_text_changed(s); @@ -1515,7 +1515,7 @@ void end_visual_mode(void) curbuf->b_visual.vi_end = curwin->w_cursor; curbuf->b_visual.vi_curswant = curwin->w_curswant; curbuf->b_visual_mode_eval = VIsual_mode; - if (!virtual_active()) { + if (!virtual_active(curwin)) { curwin->w_cursor.coladd = 0; } @@ -1863,8 +1863,8 @@ void clear_showcmd(void) bot = VIsual.lnum; } // Include closed folds as a whole. - hasFolding(top, &top, NULL); - hasFolding(bot, NULL, &bot); + hasFolding(curwin, top, &top, NULL); + hasFolding(curwin, bot, NULL, &bot); lines = bot - top + 1; if (VIsual_mode == Ctrl_V) { @@ -2174,14 +2174,14 @@ void check_scrollbind(linenr_T topline_diff, int leftcol_diff) y = topline - curwin->w_topline; if (y > 0) { - scrollup(y, false); + scrollup(curwin, y, false); } else { - scrolldown(-y, false); + scrolldown(curwin, -y, false); } } redraw_later(curwin, UPD_VALID); - cursor_correct(); + cursor_correct(curwin); curwin->w_redr_status = true; } @@ -2466,8 +2466,8 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) oap->motion_type = kMTCharWise; oap->inclusive = (curwin->w_curswant == MAXCOL); - col_off1 = curwin_col_off(); - col_off2 = col_off1 - curwin_col_off2(); + col_off1 = win_col_off(curwin); + col_off2 = col_off1 - win_col_off2(curwin); width1 = curwin->w_width_inner - col_off1; width2 = curwin->w_width_inner - col_off2; @@ -2481,7 +2481,7 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) // try to stick in the last column of the screen. if (curwin->w_curswant == MAXCOL) { atend = true; - validate_virtcol(); + validate_virtcol(curwin); if (width1 <= 0) { curwin->w_curswant = 0; } else { @@ -2506,7 +2506,7 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) while (dist--) { if (dir == BACKWARD) { if (curwin->w_curswant >= width1 - && !hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + && !hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { // Move back within the line. This can give a negative value // for w_curswant if width1 < width2 (with cpoptions+=n), // which will get clipped to column 0. @@ -2533,7 +2533,7 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) n = width1; } if (curwin->w_curswant + width2 < (colnr_T)n - && !hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + && !hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { // move forward within line curwin->w_curswant += width2; } else { @@ -2558,17 +2558,17 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) } } - if (virtual_active() && atend) { - coladvance(MAXCOL); + if (virtual_active(curwin) && atend) { + coladvance(curwin, MAXCOL); } else { - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } if (curwin->w_cursor.col > 0 && curwin->w_p_wrap) { // Check for landing on a character that got split at the end of the // last line. We want to advance a screenline, not end up in the same // screenline or move two screenlines. - validate_virtcol(); + validate_virtcol(curwin); colnr_T virtcol = curwin->w_virtcol; if (virtcol > (colnr_T)width1 && *get_showbreak_value(curwin) != NUL) { virtcol -= vim_strsize(get_showbreak_value(curwin)); @@ -2616,13 +2616,13 @@ void scroll_redraw(bool up, linenr_T count) linenr_T prev_lnum = curwin->w_cursor.lnum; bool moved = up - ? scrollup(count, true) - : scrolldown(count, true); + ? scrollup(curwin, count, true) + : scrolldown(curwin, count, true); if (get_scrolloff_value(curwin) > 0) { // Adjust the cursor position for 'scrolloff'. Mark w_topline as // valid, otherwise the screen jumps back at the end of the file. - cursor_correct(); + cursor_correct(curwin); check_cursor_moved(curwin); curwin->w_valid |= VALID_TOPLINE; @@ -2651,7 +2651,7 @@ void scroll_redraw(bool up, linenr_T count) } } if (curwin->w_cursor.lnum != prev_lnum) { - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } if (moved) { curwin->w_viewport_invalid = true; @@ -2803,7 +2803,7 @@ static void nv_zet(cmdarg_T *cap) } else { curwin->w_cursor.lnum = cap->count0; } - check_cursor_col(); + check_cursor_col(curwin); } switch (nchar) { @@ -2826,7 +2826,7 @@ static void nv_zet(cmdarg_T *cap) FALLTHROUGH; case 't': - scroll_cursor_top(0, true); + scroll_cursor_top(curwin, 0, true); redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -2837,7 +2837,7 @@ static void nv_zet(cmdarg_T *cap) FALLTHROUGH; case 'z': - scroll_cursor_halfway(true, false); + scroll_cursor_halfway(curwin, true, false); redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -2847,7 +2847,7 @@ static void nv_zet(cmdarg_T *cap) // when is at bottom of window, and puts that one at // bottom of window. if (cap->count0 != 0) { - scroll_cursor_bot(0, true); + scroll_cursor_bot(curwin, 0, true); curwin->w_cursor.lnum = curwin->w_topline; } else if (curwin->w_topline == 1) { curwin->w_cursor.lnum = 1; @@ -2860,7 +2860,7 @@ static void nv_zet(cmdarg_T *cap) FALLTHROUGH; case 'b': - scroll_cursor_bot(0, true); + scroll_cursor_bot(curwin, 0, true); redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -2895,7 +2895,7 @@ static void nv_zet(cmdarg_T *cap) // "zs" - scroll screen, cursor at the start case 's': if (!curwin->w_p_wrap) { - if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { col = 0; // like the cursor is in col 0 } else { getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL); @@ -2915,12 +2915,12 @@ static void nv_zet(cmdarg_T *cap) // "ze" - scroll screen, cursor at the end case 'e': if (!curwin->w_p_wrap) { - if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { col = 0; // like the cursor is in col 0 } else { getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); } - int n = curwin->w_width_inner - curwin_col_off(); + int n = curwin->w_width_inner - win_col_off(curwin); if (col + siso < n) { col = 0; } else { @@ -2980,7 +2980,7 @@ static void nv_zet(cmdarg_T *cap) case 'E': if (foldmethodIsManual(curwin)) { clearFolding(curwin); - changed_window_setting(); + changed_window_setting(curwin); } else if (foldmethodIsMarker(curwin)) { deleteFold(curwin, 1, curbuf->b_ml.ml_line_count, true, false); } else { @@ -3005,7 +3005,7 @@ static void nv_zet(cmdarg_T *cap) // "za": open closed fold or close open fold at cursor case 'a': - if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { openFold(curwin->w_cursor, cap->count1); } else { closeFold(curwin->w_cursor, cap->count1); @@ -3015,7 +3015,7 @@ static void nv_zet(cmdarg_T *cap) // "zA": open fold at cursor recursively case 'A': - if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { openFoldRecurse(curwin->w_cursor); } else { closeFoldRecurse(curwin->w_cursor); @@ -3151,11 +3151,11 @@ static void nv_zet(cmdarg_T *cap) FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb) { wp->w_p_fen = curwin->w_p_fen; - changed_window_setting_win(wp); + changed_window_setting(wp); } } } - changed_window_setting(); + changed_window_setting(curwin); } // Redraw when 'foldlevel' changed. @@ -3639,7 +3639,7 @@ static void nv_scroll(cmdarg_T *cap) // Count a fold for one screen line. for (n = cap->count1 - 1; n > 0 && curwin->w_cursor.lnum > curwin->w_topline; n--) { - hasFolding(curwin->w_cursor.lnum, + hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); if (curwin->w_cursor.lnum > curwin->w_topline) { curwin->w_cursor.lnum--; @@ -3668,7 +3668,7 @@ static void nv_scroll(cmdarg_T *cap) if (used >= half) { break; } - if (hasFolding(curwin->w_topline + n, NULL, &lnum)) { + if (hasFolding(curwin, curwin->w_topline + n, NULL, &lnum)) { n = lnum - curwin->w_topline; } } @@ -3681,7 +3681,7 @@ static void nv_scroll(cmdarg_T *cap) // Count a fold for one screen line. lnum = curwin->w_topline; while (n-- > 0 && lnum < curwin->w_botline - 1) { - hasFolding(lnum, NULL, &lnum); + hasFolding(curwin, lnum, NULL, &lnum); lnum++; } n = lnum - curwin->w_topline; @@ -3695,7 +3695,7 @@ static void nv_scroll(cmdarg_T *cap) // Correct for 'so', except when an operator is pending. if (cap->oap->op_type == OP_NOP) { - cursor_correct(); + cursor_correct(curwin); } beginline(BL_SOL | BL_FIX); } @@ -3720,7 +3720,7 @@ static void nv_right(cmdarg_T *cap) // In virtual edit mode, there's no such thing as "past_line", as lines // are (theoretically) infinitely long. - if (virtual_active()) { + if (virtual_active(curwin)) { past_line = false; } @@ -3763,7 +3763,7 @@ static void nv_right(cmdarg_T *cap) break; } else if (past_line) { curwin->w_set_curswant = true; - if (virtual_active()) { + if (virtual_active(curwin)) { oneright(); } else { curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr()); @@ -3805,7 +3805,7 @@ static void nv_left(cmdarg_T *cap) || (cap->cmdchar == K_LEFT && vim_strchr(p_ww, '<') != NULL)) && curwin->w_cursor.lnum > 1) { curwin->w_cursor.lnum--; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); curwin->w_set_curswant = true; // When the NL before the first char has to be deleted we @@ -3940,7 +3940,7 @@ static void nv_dollar(cmdarg_T *cap) // In virtual mode when off the edge of a line and an operator // is pending (whew!) keep the cursor where it is. // Otherwise, send it to the end of the line. - if (!virtual_active() || gchar_cursor() != NUL + if (!virtual_active(curwin) || gchar_cursor() != NUL || cap->oap->op_type == OP_NOP) { curwin->w_curswant = MAXCOL; // so we stay at the end } @@ -4034,7 +4034,7 @@ static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrappe // "/$" will put the cursor after the end of the line, may need to // correct that here - check_cursor(); + check_cursor(curwin); return i; } @@ -4060,7 +4060,7 @@ static void nv_csearch(cmdarg_T *cap) curwin->w_set_curswant = true; // Include a Tab for "tx" and for "dfx". - if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD + if (gchar_cursor() == TAB && virtual_active(curwin) && cap->arg == FORWARD && (t_cmd || cap->oap->op_type != OP_NOP)) { colnr_T scol, ecol; @@ -4516,7 +4516,7 @@ static void nv_replace(cmdarg_T *cap) } // Break tabs, etc. - if (virtual_active()) { + if (virtual_active(curwin)) { if (u_save_cursor() == false) { return; } @@ -4628,7 +4628,7 @@ static void v_swap_corners(int cmdchar) pos_T old_cursor = curwin->w_cursor; getvcols(curwin, &old_cursor, &VIsual, &left, &right); curwin->w_cursor.lnum = VIsual.lnum; - coladvance(left); + coladvance(curwin, left); VIsual = curwin->w_cursor; curwin->w_cursor.lnum = old_cursor.lnum; @@ -4638,20 +4638,20 @@ static void v_swap_corners(int cmdchar) if (old_cursor.lnum >= VIsual.lnum && *p_sel == 'e') { curwin->w_curswant++; } - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); if (curwin->w_cursor.col == old_cursor.col - && (!virtual_active() + && (!virtual_active(curwin) || curwin->w_cursor.coladd == old_cursor.coladd)) { curwin->w_cursor.lnum = VIsual.lnum; if (old_cursor.lnum <= VIsual.lnum && *p_sel == 'e') { right++; } - coladvance(right); + coladvance(curwin, right); VIsual = curwin->w_cursor; curwin->w_cursor.lnum = old_cursor.lnum; - coladvance(left); + coladvance(curwin, left); curwin->w_curswant = left; } } else { @@ -4681,8 +4681,8 @@ static void nv_Replace(cmdarg_T *cap) if (!MODIFIABLE(curbuf)) { emsg(_(e_modifiable)); } else { - if (virtual_active()) { - coladvance(getviscol()); + if (virtual_active(curwin)) { + coladvance(curwin, getviscol()); } invoke_edit(cap, false, cap->arg ? 'V' : 'R', false); } @@ -4716,8 +4716,8 @@ static void nv_vreplace(cmdarg_T *cap) } stuffcharReadbuff(cap->extra_char); stuffcharReadbuff(ESC); - if (virtual_active()) { - coladvance(getviscol()); + if (virtual_active(curwin)) { + coladvance(curwin, getviscol()); } invoke_edit(cap, true, 'v', false); } @@ -4764,7 +4764,7 @@ static void n_swapchar(cmdarg_T *cap) } } - check_cursor(); + check_cursor(curwin); curwin->w_set_curswant = true; if (did_change) { changed_lines(curbuf, startpos.lnum, startpos.col, curwin->w_cursor.lnum + 1, @@ -4896,7 +4896,7 @@ static void nv_gomark(cmdarg_T *cap) move_res = nv_mark_move_to(cap, flags, fm); // May need to clear the coladd that a mark includes. - if (!virtual_active()) { + if (!virtual_active(curwin)) { curwin->w_cursor.coladd = 0; } @@ -5025,7 +5025,7 @@ static void nv_visual(cmdarg_T *cap) // was only one -- webb if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1) { curwin->w_cursor.lnum += resel_VIsual_line_count * cap->count0 - 1; - check_cursor(); + check_cursor(curwin); } VIsual_mode = resel_VIsual_mode; if (VIsual_mode == 'v') { @@ -5039,11 +5039,11 @@ static void nv_visual(cmdarg_T *cap) } else { curwin->w_curswant = resel_VIsual_vcol; } - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } if (resel_VIsual_vcol == MAXCOL) { curwin->w_curswant = MAXCOL; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } else if (VIsual_mode == Ctrl_V) { // Update curswant on the original line, that is where "col" is valid. linenr_T lnum = curwin->w_cursor.lnum; @@ -5052,7 +5052,7 @@ static void nv_visual(cmdarg_T *cap) assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX); curwin->w_curswant += resel_VIsual_vcol * cap->count0 - 1; curwin->w_cursor.lnum = lnum; - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } else { curwin->w_set_curswant = true; } @@ -5104,9 +5104,9 @@ static void n_start_visual_mode(int c) // Corner case: the 0 position in a tab may change when going into // virtualedit. Recalculate curwin->w_cursor to avoid bad highlighting. // - if (c == Ctrl_V && (get_ve_flags() & VE_BLOCK) && gchar_cursor() == TAB) { - validate_virtcol(); - coladvance(curwin->w_virtcol); + if (c == Ctrl_V && (get_ve_flags(curwin) & VE_BLOCK) && gchar_cursor() == TAB) { + validate_virtcol(curwin); + coladvance(curwin, curwin->w_virtcol); } VIsual = curwin->w_cursor; @@ -5194,10 +5194,10 @@ static void nv_gv_cmd(cmdarg_T *cap) // Set Visual to the start and w_cursor to the end of the Visual // area. Make sure they are on an existing character. - check_cursor(); + check_cursor(curwin); VIsual = curwin->w_cursor; curwin->w_cursor = tpos; - check_cursor(); + check_cursor(curwin); update_topline(curwin); // When called from normal "g" command: start Select mode when @@ -5224,10 +5224,10 @@ static void nv_g_home_m_cmd(cmdarg_T *cap) cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; if (curwin->w_p_wrap && curwin->w_width_inner != 0) { - int width1 = curwin->w_width_inner - curwin_col_off(); - int width2 = width1 + curwin_col_off2(); + int width1 = curwin->w_width_inner - win_col_off(curwin); + int width2 = width1 + win_col_off2(curwin); - validate_virtcol(); + validate_virtcol(curwin); i = 0; if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0) { i = (curwin->w_virtcol - width1) / width2 * width2 + width1; @@ -5239,10 +5239,10 @@ static void nv_g_home_m_cmd(cmdarg_T *cap) // 'relativenumber' is on and lines are wrapping the middle can be more // to the left. if (cap->nchar == 'm') { - i += (curwin->w_width_inner - curwin_col_off() - + ((curwin->w_p_wrap && i > 0) ? curwin_col_off2() : 0)) / 2; + i += (curwin->w_width_inner - win_col_off(curwin) + + ((curwin->w_p_wrap && i > 0) ? win_col_off2(curwin) : 0)) / 2; } - coladvance((colnr_T)i); + coladvance(curwin, (colnr_T)i); if (flag) { do { i = gchar_cursor(); @@ -5284,7 +5284,7 @@ static void nv_g_dollar_cmd(cmdarg_T *cap) { oparg_T *oap = cap->oap; int i; - int col_off = curwin_col_off(); + int col_off = win_col_off(curwin); const bool flag = cap->nchar == K_END || cap->nchar == K_KEND; oap->motion_type = kMTCharWise; @@ -5293,14 +5293,14 @@ static void nv_g_dollar_cmd(cmdarg_T *cap) curwin->w_curswant = MAXCOL; // so we stay at the end if (cap->count1 == 1) { int width1 = curwin->w_width_inner - col_off; - int width2 = width1 + curwin_col_off2(); + int width2 = width1 + win_col_off2(curwin); - validate_virtcol(); + validate_virtcol(curwin); i = width1 - 1; if (curwin->w_virtcol >= (colnr_T)width1) { i += ((curwin->w_virtcol - width1) / width2 + 1) * width2; } - coladvance((colnr_T)i); + coladvance(curwin, (colnr_T)i); // Make sure we stick in this column. update_curswant_force(); @@ -5321,7 +5321,7 @@ static void nv_g_dollar_cmd(cmdarg_T *cap) cursor_down(cap->count1 - 1, false); } i = curwin->w_leftcol + curwin->w_width_inner - col_off - 1; - coladvance((colnr_T)i); + coladvance(curwin, (colnr_T)i); // if the character doesn't fit move one back if (curwin->w_cursor.col > 0 && utf_ptr2cells(get_cursor_pos_ptr()) > 1) { @@ -5352,7 +5352,7 @@ static void nv_gi_cmd(cmdarg_T *cap) check_cursor_lnum(curwin); int i = (int)get_cursor_line_len(); if (curwin->w_cursor.col > (colnr_T)i) { - if (virtual_active()) { + if (virtual_active(curwin)) { curwin->w_cursor.coladd += curwin->w_cursor.col - i; } curwin->w_cursor.col = i; @@ -5480,9 +5480,9 @@ static void nv_g_cmd(cmdarg_T *cap) oap->inclusive = false; i = linetabsize(curwin, curwin->w_cursor.lnum); if (cap->count0 > 0 && cap->count0 <= 100) { - coladvance((colnr_T)(i * cap->count0 / 100)); + coladvance(curwin, (colnr_T)(i * cap->count0 / 100)); } else { - coladvance((colnr_T)(i / 2)); + coladvance(curwin, (colnr_T)(i / 2)); } curwin->w_set_curswant = true; break; @@ -5705,11 +5705,11 @@ static void n_opencmd(cmdarg_T *cap) if (cap->cmdchar == 'O') { // Open above the first line of a folded sequence of lines - hasFolding(curwin->w_cursor.lnum, + hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); } else { // Open below the last line of a folded sequence of lines - hasFolding(curwin->w_cursor.lnum, + hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum); } // trigger TextChangedI for the 'o/O' command @@ -5890,7 +5890,7 @@ static void nv_pipe(cmdarg_T *cap) cap->oap->inclusive = false; beginline(0); if (cap->count0 > 0) { - coladvance((colnr_T)(cap->count0 - 1)); + coladvance(curwin, (colnr_T)(cap->count0 - 1)); curwin->w_curswant = (colnr_T)(cap->count0 - 1); } else { curwin->w_curswant = 0; @@ -5986,8 +5986,8 @@ static void adjust_cursor(oparg_T *oap) // - 'virtualedit' is not "all" and not "onemore". if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL && (!VIsual_active || *p_sel == 'o') - && !virtual_active() - && (get_ve_flags() & VE_ONEMORE) == 0) { + && !virtual_active(curwin) + && (get_ve_flags(curwin) & VE_ONEMORE) == 0) { curwin->w_cursor.col--; // prevent cursor from moving on the trail byte mb_adjust_cursor(); @@ -6150,7 +6150,7 @@ static void nv_esc(cmdarg_T *cap) if (VIsual_active) { end_visual_mode(); // stop Visual - check_cursor_col(); // make sure cursor is not beyond EOL + check_cursor_col(curwin); // make sure cursor is not beyond EOL curwin->w_set_curswant = true; redraw_curbuf_later(UPD_INVERTED); } else if (no_reason) { @@ -6163,12 +6163,12 @@ static void nv_esc(cmdarg_T *cap) void set_cursor_for_append_to_line(void) { curwin->w_set_curswant = true; - if (get_ve_flags() == VE_ALL) { + if (get_ve_flags(curwin) == VE_ALL) { const int save_State = State; // Pretend Insert mode here to allow the cursor on the // character past the end of the line State = MODE_INSERT; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); State = save_State; } else { curwin->w_cursor.col += (colnr_T)strlen(get_cursor_pos_ptr()); @@ -6206,7 +6206,7 @@ static void nv_edit(cmdarg_T *cap) case 'a': // "a"ppend is like "i"nsert on the next character. // increment coladd when in virtual space, increment the // column otherwise, also to append after an unprintable char - if (virtual_active() + if (virtual_active(curwin) && (curwin->w_cursor.coladd > 0 || *get_cursor_pos_ptr() == NUL || *get_cursor_pos_ptr() == TAB)) { @@ -6223,7 +6223,7 @@ static void nv_edit(cmdarg_T *cap) // Pretend Insert mode here to allow the cursor on the // character past the end of the line State = MODE_INSERT; - coladvance(getviscol()); + coladvance(curwin, getviscol()); State = save_State; } @@ -6578,7 +6578,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) // line. if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } } auto_format(false, true); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 4e27c44262..af5f2fae34 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1587,7 +1587,7 @@ int op_delete(oparg_T *oap) kExtmarkUndo); } - check_cursor_col(); + check_cursor_col(curwin); changed_lines(curbuf, curwin->w_cursor.lnum, curwin->w_cursor.col, oap->end.lnum + 1, 0, true); oap->line_count = 0; // no lines deleted @@ -1637,7 +1637,7 @@ int op_delete(oparg_T *oap) coladvance_force(getviscol2(oap->start.col, oap->start.coladd)); oap->start = curwin->w_cursor; if (oap->line_count == 1) { - coladvance(endcol); + coladvance(curwin, endcol); oap->end.col = curwin->w_cursor.col; oap->end.coladd = curwin->w_cursor.coladd; curwin->w_cursor = oap->start; @@ -1840,7 +1840,7 @@ static int op_replace(oparg_T *oap, int c) pos_T vpos; vpos.lnum = curwin->w_cursor.lnum; - getvpos(&vpos, oap->start_vcol); + getvpos(curwin, &vpos, oap->start_vcol); bd.startspaces += vpos.coladd; n = bd.startspaces; } else { @@ -1975,7 +1975,7 @@ static int op_replace(oparg_T *oap, int c) } coladvance_force(getviscol()); if (curwin->w_cursor.lnum == oap->end.lnum) { - getvpos(&oap->end, end_vcol); + getvpos(curwin, &oap->end, end_vcol); } } // with "coladd" set may move to just after a TAB @@ -2018,7 +2018,7 @@ static int op_replace(oparg_T *oap, int c) } curwin->w_cursor = oap->start; - check_cursor(); + check_cursor(curwin); changed_lines(curbuf, oap->start.lnum, oap->start.col, oap->end.lnum + 1, 0, true); if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { @@ -2260,7 +2260,7 @@ void op_insert(oparg_T *oap, int count1) } } else { curwin->w_cursor = oap->end; - check_cursor_col(); + check_cursor_col(curwin); // Works just like an 'i'nsert on the next character. if (!LINEEMPTY(curwin->w_cursor.lnum) @@ -2393,7 +2393,7 @@ void op_insert(oparg_T *oap, int count1) } curwin->w_cursor.col = oap->start.col; - check_cursor(); + check_cursor(curwin); xfree(ins_text); } } @@ -2488,7 +2488,7 @@ int op_change(oparg_T *oap) // initial coladd offset as part of "startspaces" if (bd.is_short) { vpos.lnum = linenr; - getvpos(&vpos, oap->start_vcol); + getvpos(curwin, &vpos, oap->start_vcol); } else { vpos.coladd = 0; } @@ -2509,7 +2509,7 @@ int op_change(oparg_T *oap) 0, vpos.coladd + ins_len, kExtmarkUndo); } } - check_cursor(); + check_cursor(curwin); changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0, true); xfree(ins_text); } @@ -2843,7 +2843,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) bool allocated = false; const pos_T orig_start = curbuf->b_op_start; const pos_T orig_end = curbuf->b_op_end; - unsigned cur_ve_flags = get_ve_flags(); + unsigned cur_ve_flags = get_ve_flags(curwin); if (flags & PUT_FIXINDENT) { orig_indent = get_indent(); @@ -3064,9 +3064,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // Correct line number for closed fold. Don't move the cursor yet, // u_save() uses it. if (dir == BACKWARD) { - hasFolding(lnum, &lnum, NULL); + hasFolding(curwin, lnum, &lnum, NULL); } else { - hasFolding(lnum, NULL, &lnum); + hasFolding(curwin, lnum, NULL, &lnum); } if (dir == FORWARD) { lnum++; @@ -3362,7 +3362,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) pos_T pos = { .lnum = lnum, }; - if (getvpos(&pos, vcol) == OK) { + if (getvpos(curwin, &pos, vcol) == OK) { col = pos.col; } else { col = MAXCOL; @@ -3616,7 +3616,7 @@ end: /// there move it left. void adjust_cursor_eol(void) { - unsigned cur_ve_flags = get_ve_flags(); + unsigned cur_ve_flags = get_ve_flags(curwin); const bool adj_cursor = (curwin->w_cursor.col > 0 && gchar_cursor() == NUL @@ -4078,7 +4078,7 @@ int do_join(size_t count, bool insert_space, bool save_undo, bool use_formatopti // vim: use the column of the last join curwin->w_cursor.col = (vim_strchr(p_cpo, CPO_JOINCOL) != NULL ? currsize : col); - check_cursor_col(); + check_cursor_col(curwin); curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; @@ -4445,7 +4445,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // "Unsigned" const bool do_unsigned = vim_strchr(curbuf->b_p_nf, 'u') != NULL; - if (virtual_active()) { + if (virtual_active(curwin)) { save_coladd = pos->coladd; pos->coladd = 0; } @@ -4767,7 +4767,7 @@ theend: curwin->w_cursor = save_cursor; } else if (did_change) { curwin->w_set_curswant = true; - } else if (virtual_active()) { + } else if (virtual_active(curwin)) { curwin->w_cursor.coladd = save_coladd; } @@ -5349,7 +5349,7 @@ void cursor_pos_info(dict_T *dict) switch (l_VIsual_mode) { case Ctrl_V: - virtual_op = virtual_active(); + virtual_op = virtual_active(curwin); block_prep(&oparg, &bd, lnum, false); virtual_op = kNone; s = bd.textstart; @@ -5438,7 +5438,7 @@ void cursor_pos_info(dict_T *dict) } } else { char *p = get_cursor_line_ptr(); - validate_virtcol(); + validate_virtcol(curwin); col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); col_print(buf2, sizeof(buf2), (int)strlen(p), linetabsize_str(p)); @@ -5523,7 +5523,7 @@ static void op_colon(oparg_T *oap) // When using !! on a closed fold the range ".!" works best to operate // on, it will be made the whole closed fold later. linenr_T endOfStartFold = oap->start.lnum; - hasFolding(oap->start.lnum, NULL, &endOfStartFold); + hasFolding(curwin, oap->start.lnum, NULL, &endOfStartFold); if (oap->end.lnum != oap->start.lnum && oap->end.lnum != endOfStartFold) { // Make it a range with the end line. stuffcharReadbuff(','); @@ -5534,7 +5534,7 @@ static void op_colon(oparg_T *oap) } else if (oap->start.lnum == curwin->w_cursor.lnum // do not use ".+number" for a closed fold, it would count // folded lines twice - && !hasFolding(oap->end.lnum, NULL, NULL)) { + && !hasFolding(curwin, oap->end.lnum, NULL, NULL)) { stuffReadbuff(".+"); stuffnumReadbuff(oap->line_count - 1); } else { @@ -5696,11 +5696,11 @@ static void get_op_vcol(oparg_T *oap, colnr_T redo_VIsual_vcol, bool initial) // (Actually, this does convert column positions into character // positions) curwin->w_cursor.lnum = oap->end.lnum; - coladvance(oap->end_vcol); + coladvance(curwin, oap->end_vcol); oap->end = curwin->w_cursor; curwin->w_cursor = oap->start; - coladvance(oap->start_vcol); + coladvance(curwin, oap->start_vcol); oap->start = curwin->w_cursor; } @@ -5825,7 +5825,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (redo_VIsual.rv_vcol == MAXCOL || VIsual_mode == 'v') { if (VIsual_mode == 'v') { if (redo_VIsual.rv_line_count <= 1) { - validate_virtcol(); + validate_virtcol(curwin); curwin->w_curswant = curwin->w_virtcol + redo_VIsual.rv_vcol - 1; } else { curwin->w_curswant = redo_VIsual.rv_vcol; @@ -5833,7 +5833,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { curwin->w_curswant = MAXCOL; } - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } cap->count0 = redo_VIsual.rv_count; cap->count1 = (cap->count0 == 0 ? 1 : cap->count0); @@ -5880,13 +5880,13 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (lt(oap->start, curwin->w_cursor)) { // Include folded lines completely. if (!VIsual_active) { - if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL)) { + if (hasFolding(curwin, oap->start.lnum, &oap->start.lnum, NULL)) { oap->start.col = 0; } if ((curwin->w_cursor.col > 0 || oap->inclusive || oap->motion_type == kMTLineWise) - && hasFolding(curwin->w_cursor.lnum, NULL, + && hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { curwin->w_cursor.col = (colnr_T)strlen(get_cursor_line_ptr()); } @@ -5901,11 +5901,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { // Include folded lines completely. if (!VIsual_active && oap->motion_type == kMTLineWise) { - if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, + if (hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) { curwin->w_cursor.col = 0; } - if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) { + if (hasFolding(curwin, oap->start.lnum, NULL, &oap->start.lnum)) { oap->start.col = (colnr_T)strlen(ml_get(oap->start.lnum)); } } @@ -5918,7 +5918,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) oap->line_count = oap->end.lnum - oap->start.lnum + 1; // Set "virtual_op" before resetting VIsual_active. - virtual_op = virtual_active(); + virtual_op = virtual_active(curwin); if (VIsual_active || redo_VIsual_busy) { get_op_vcol(oap, redo_VIsual.rv_vcol, true); @@ -6149,7 +6149,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) oap->excl_tr_ws = cap->cmdchar == 'z'; op_yank(oap, !gui_yank); } - check_cursor_col(); + check_cursor_col(curwin); break; case OP_CHANGE: @@ -6223,7 +6223,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { op_tilde(oap); } - check_cursor_col(); + check_cursor_col(curwin); break; case OP_FORMAT: @@ -6341,7 +6341,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) op_addsub(oap, (linenr_T)cap->count1, redo_VIsual.rv_arg); VIsual_active = false; } - check_cursor_col(); + check_cursor_col(curwin); break; default: clearopbeep(oap); @@ -6353,7 +6353,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT || oap->op_type == OP_DELETE)) { reset_lbr(); - coladvance(curwin->w_curswant = old_col); + coladvance(curwin, curwin->w_curswant = old_col); } } else { curwin->w_cursor = old_cursor; diff --git a/src/nvim/option.c b/src/nvim/option.c index 4f1ec59e77..3d7fdefdeb 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1937,7 +1937,7 @@ static const char *did_set_arabic(optset_T *args) // set rightleft mode if (!win->w_p_rl) { win->w_p_rl = true; - changed_window_setting(); + changed_window_setting(curwin); } // Enable Arabic shaping (major part of what Arabic requires) @@ -1968,7 +1968,7 @@ static const char *did_set_arabic(optset_T *args) // reset rightleft mode if (win->w_p_rl) { win->w_p_rl = false; - changed_window_setting(); + changed_window_setting(curwin); } // 'arabicshape' isn't reset, it is a global option and @@ -3029,7 +3029,7 @@ void check_redraw_for(buf_T *buf, win_T *win, uint32_t flags) if (flags & P_HLONLY) { redraw_later(win, UPD_NOT_VALID); } else { - changed_window_setting_win(win); + changed_window_setting(win); } } if (flags & P_RBUF) { @@ -6104,9 +6104,9 @@ char *get_flp_value(buf_T *buf) } /// Get the local or global value of the 'virtualedit' flags. -unsigned get_ve_flags(void) +unsigned get_ve_flags(win_T *wp) { - return (curwin->w_ve_flags ? curwin->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU); + return (wp->w_ve_flags ? wp->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU); } /// Get the local or global value of 'showbreak'. diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 4be08b28f5..f80926726a 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -2479,9 +2479,8 @@ const char *did_set_virtualedit(optset_T *args) } else if (strcmp(ve, args->os_oldval.string.data) != 0) { // Recompute cursor position in case the new 've' setting // changes something. - validate_virtcol_win(win); - // XXX: this only works when win == curwin - coladvance(win->w_virtcol); + validate_virtcol(win); + coladvance(win, win->w_virtcol); } } return NULL; diff --git a/src/nvim/plines.c b/src/nvim/plines.c index eca07f0144..ec13e5b5b7 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -540,7 +540,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en if (ci.chr.value == TAB && (State & MODE_NORMAL) && !wp->w_p_list - && !virtual_active() + && !virtual_active(wp) && !(VIsual_active && ((*p_sel == 'e') || ltoreq(*pos, VIsual)))) { // cursor at end *cursor = vcol + incr - 1; @@ -583,7 +583,7 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *e { colnr_T col; - if (virtual_active()) { + if (virtual_active(wp)) { // For virtual mode, only want one value getvcol(wp, pos, &col, NULL, NULL); @@ -902,7 +902,7 @@ int64_t win_text_height(win_T *const wp, const linenr_T start_lnum, const int64_ if (start_vcol >= 0) { linenr_T lnum_next = lnum; - const bool folded = hasFoldingWin(wp, lnum, &lnum, &lnum_next, true, NULL); + const bool folded = hasFolding(wp, lnum, &lnum, &lnum_next); height_cur_nofill = folded ? 1 : plines_win_nofill(wp, lnum, false); height_sum_nofill += height_cur_nofill; const int64_t row_off = (start_vcol < width1 || width2 <= 0) @@ -914,7 +914,7 @@ int64_t win_text_height(win_T *const wp, const linenr_T start_lnum, const int64_ while (lnum <= end_lnum) { linenr_T lnum_next = lnum; - const bool folded = hasFoldingWin(wp, lnum, &lnum, &lnum_next, true, NULL); + const bool folded = hasFolding(wp, lnum, &lnum, &lnum_next); height_sum_fill += win_get_fill(wp, lnum); height_cur_nofill = folded ? 1 : plines_win_nofill(wp, lnum, false); height_sum_nofill += height_cur_nofill; diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index e34d6fd97f..5e8fb7f5de 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -140,7 +140,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i // to avoid that must_redraw is set when 'cursorcolumn' is on. pum_is_visible = true; pum_is_drawn = true; - validate_cursor_col(); + validate_cursor_col(curwin); int above_row = 0; int below_row = cmdline_row; @@ -273,7 +273,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i context_lines = 0; } else { // Leave two lines of context if possible - validate_cheight(); + validate_cheight(curwin); if (curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow >= 3) { context_lines = 3; } else { @@ -995,7 +995,7 @@ static bool pum_set_selected(int n, int repeat) } // Return cursor to where we were - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_SOME_VALID); // When the preview window was resized we need to diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 0a4427f3c1..bf53dca167 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2889,12 +2889,12 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char if (qf_col > 0) { curwin->w_cursor.coladd = 0; if (qf_viscol == true) { - coladvance(qf_col - 1); + coladvance(curwin, qf_col - 1); } else { curwin->w_cursor.col = qf_col - 1; } curwin->w_set_curswant = true; - check_cursor(); + check_cursor(curwin); } else { beginline(BL_WHITE | BL_FIX); } @@ -3831,7 +3831,7 @@ void ex_copen(exarg_T *eap) curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = 0; - check_cursor(); + check_cursor(curwin); update_topline(curwin); // scroll to show the line } diff --git a/src/nvim/search.c b/src/nvim/search.c index 2fea28ba7c..a3c9da8e3b 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -1076,11 +1076,11 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in // If the cursor is in a closed fold, don't find another match in the same // fold. if (dirc == '/') { - if (hasFolding(pos.lnum, NULL, &pos.lnum)) { + if (hasFolding(curwin, pos.lnum, NULL, &pos.lnum)) { pos.col = MAXCOL - 2; // avoid overflow when adding 1 } } else { - if (hasFolding(pos.lnum, &pos.lnum, NULL)) { + if (hasFolding(curwin, pos.lnum, &pos.lnum, NULL)) { pos.col = 0; } } @@ -1389,7 +1389,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in show_top_bot_msg, msgbuf, (count != 1 || has_offset || (!(fdo_flags & FDO_SEARCH) - && hasFolding(curwin->w_cursor.lnum, NULL, + && hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL))), SEARCH_STAT_DEF_MAX_COUNT, SEARCH_STAT_DEF_TIMEOUT); @@ -4034,7 +4034,7 @@ search_line: setpcmark(); } curwin->w_cursor.lnum = lnum; - check_cursor(); + check_cursor(curwin); } else { if (!GETFILE_SUCCESS(getfile(0, files[depth].name, NULL, true, files[depth].lnum, forceit))) { @@ -4053,7 +4053,7 @@ search_line: if (l_g_do_tagpreview != 0 && curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } diff --git a/src/nvim/state.c b/src/nvim/state.c index 0df060ecf4..baa1e75775 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -135,9 +135,9 @@ void state_handle_k_event(void) } /// Return true if in the current mode we need to use virtual. -bool virtual_active(void) +bool virtual_active(win_T *wp) { - unsigned cur_ve_flags = get_ve_flags(); + unsigned cur_ve_flags = get_ve_flags(wp); // While an operator is being executed we return "virtual_op", because // VIsual_active has already been reset, thus we can't check for "block" diff --git a/src/nvim/state.h b/src/nvim/state.h index 9002f018d2..8220d90a67 100644 --- a/src/nvim/state.h +++ b/src/nvim/state.h @@ -1,6 +1,7 @@ #pragma once #include "nvim/state_defs.h" // IWYU pragma: keep +#include "nvim/types_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "state.h.generated.h" diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 776498fa29..0265d2d822 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -449,7 +449,7 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) } curwin->w_cursor.col = saved_fmark.mark.col; curwin->w_set_curswant = true; - check_cursor(); + check_cursor(curwin); if ((fdo_flags & FDO_TAG) && old_KeyTyped) { foldOpenCursor(); } @@ -3002,7 +3002,7 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) // A search command may have positioned the cursor beyond the end // of the line. May need to correct that here. - check_cursor(); + check_cursor(curwin); } else { const int save_secure = secure; @@ -3047,7 +3047,7 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) if (l_g_do_tagpreview != 0 && curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index b5a3cffe2f..5a343b4972 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -612,7 +612,7 @@ static void terminal_check_cursor(void) row_to_linenr(term, term->cursor.row)); // Nudge cursor when returning to normal-mode. int off = is_focused(term) ? 0 : (curwin->w_p_rl ? 1 : -1); - coladvance(MAX(0, term->cursor.col + off)); + coladvance(curwin, MAX(0, term->cursor.col + off)); } // Function executed before each iteration of terminal mode. @@ -626,7 +626,7 @@ static int terminal_check(VimState *state) } terminal_check_cursor(); - validate_cursor(); + validate_cursor(curwin); if (must_redraw) { update_screen(); diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index 2cb08df7b5..41fb543994 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -157,7 +157,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on } // find column of textwidth border - coladvance((colnr_T)textwidth); + coladvance(curwin, (colnr_T)textwidth); wantcol = curwin->w_cursor.col; // If startcol is large (a long line), formatting takes too much @@ -690,9 +690,9 @@ void auto_format(bool trailblank, bool prev_line) if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { // "cannot happen" curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } else { - check_cursor_col(); + check_cursor_col(curwin); } // Insert mode: If the cursor is now after the end of the line while it @@ -715,7 +715,7 @@ void auto_format(bool trailblank, bool prev_line) } } - check_cursor(); + check_cursor(curwin); } /// When an extra space was added to continue a paragraph for auto-formatting, @@ -839,7 +839,7 @@ void op_format(oparg_T *oap, bool keep_cursor) saved_cursor.lnum = 0; // formatting may have made the cursor position invalid - check_cursor(); + check_cursor(curwin); } if (oap->is_VIsual) { @@ -1063,7 +1063,7 @@ void format_lines(linenr_T line_count, bool avoid_fex) // put cursor on last non-space State = MODE_NORMAL; // don't go past end-of-line - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); while (curwin->w_cursor.col && ascii_isspace(gchar_cursor())) { dec_cursor(); } diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c index d9c2b3b111..8ac63aad16 100644 --- a/src/nvim/textobject.c +++ b/src/nvim/textobject.c @@ -187,7 +187,7 @@ bool findpar(bool *pincl, int dir, int count, int what, bool both) // skip folded lines fold_skipped = false; - if (first && hasFolding(curr, &fold_first, &fold_last)) { + if (first && hasFolding(curwin, curr, &fold_first, &fold_last)) { curr = ((dir > 0) ? fold_last : fold_first) + dir; fold_skipped = true; } @@ -318,8 +318,8 @@ int fwd_word(int count, bool bigword, bool eol) while (--count >= 0) { // When inside a range of folded lines, move to the last char of the // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - coladvance(MAXCOL); + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { + coladvance(curwin, MAXCOL); } int sclass = cls(); // starting class @@ -374,7 +374,7 @@ int bck_word(int count, bool bigword, bool stop) while (--count >= 0) { // When inside a range of folded lines, move to the first char of the // first line. - if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) { curwin->w_cursor.col = 0; } sclass = cls(); @@ -431,8 +431,8 @@ int end_word(int count, bool bigword, bool stop, bool empty) while (--count >= 0) { // When inside a range of folded lines, move to the last char of the // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - coladvance(MAXCOL); + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { + coladvance(curwin, MAXCOL); } sclass = cls(); if (inc_cursor() == -1) { diff --git a/src/nvim/undo.c b/src/nvim/undo.c index e9170ba858..ba720c9f6a 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -477,7 +477,7 @@ int u_savecommon(buf_T *buf, linenr_T top, linenr_T bot, linenr_T newbot, bool r uhp->uh_entry = NULL; uhp->uh_getbot_entry = NULL; uhp->uh_cursor = curwin->w_cursor; // save cursor pos. for undo - if (virtual_active() && curwin->w_cursor.coladd > 0) { + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { uhp->uh_cursor_vcol = getviscol(); } else { uhp->uh_cursor_vcol = -1; @@ -2488,8 +2488,8 @@ static void u_undoredo(bool undo, bool do_buf_event) if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count) { if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum) { curwin->w_cursor.col = curhead->uh_cursor.col; - if (virtual_active() && curhead->uh_cursor_vcol >= 0) { - coladvance(curhead->uh_cursor_vcol); + if (virtual_active(curwin) && curhead->uh_cursor_vcol >= 0) { + coladvance(curwin, curhead->uh_cursor_vcol); } else { curwin->w_cursor.coladd = 0; } @@ -2506,7 +2506,7 @@ static void u_undoredo(bool undo, bool do_buf_event) } // Make sure the cursor is on an existing line and column. - check_cursor(); + check_cursor(curwin); // Remember where we are for "g-" and ":earlier 10s". curbuf->b_u_seq_cur = curhead->uh_seq; @@ -3073,7 +3073,7 @@ void u_undoline(void) } curwin->w_cursor.col = t; curwin->w_cursor.lnum = curbuf->b_u_line_lnum; - check_cursor_col(); + check_cursor_col(curwin); } /// Allocate memory and copy curbuf line into it. diff --git a/src/nvim/window.c b/src/nvim/window.c index 9468207d41..6eee98fc35 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -766,7 +766,7 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err) // If window is not current, state logic will not validate its cursor. So do it now. // Still needed if do_buffer returns FAIL (e.g: autocmds abort script after buffer was set). - validate_cursor(); + validate_cursor(curwin); cleanup: restore_win_noblock(&switchwin, true); @@ -2872,7 +2872,7 @@ int win_close(win_T *win, bool free_buf, bool force) // The cursor position may be invalid if the buffer changed after last // using the window. - check_cursor(); + check_cursor(curwin); } if (!was_floating) { @@ -4921,8 +4921,8 @@ static void win_enter_ext(win_T *const wp, const int flags) curwin = wp; curbuf = wp->w_buffer; - check_cursor(); - if (!virtual_active()) { + check_cursor(curwin); + if (!virtual_active(curwin)) { curwin->w_cursor.coladd = 0; } if (*p_spk == 'c') { @@ -6638,7 +6638,7 @@ void scroll_to_fraction(win_T *wp, int prev_height) } } else if (sline > 0) { while (sline > 0 && lnum > 1) { - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); if (lnum == 1) { // first line in buffer is folded line_size = 1; @@ -6658,7 +6658,7 @@ void scroll_to_fraction(win_T *wp, int prev_height) if (sline < 0) { // Line we want at top would go off top of screen. Use next // line instead. - hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL); + hasFolding(wp, lnum, NULL, &lnum); lnum++; wp->w_wrow -= line_size + sline; } else if (sline > 0) { @@ -6699,7 +6699,7 @@ void win_set_inner_size(win_T *wp, bool valid_cursor) if (wp == curwin && *p_spk == 'c') { // w_wrow needs to be valid. When setting 'laststatus' this may // call win_new_height() recursively. - validate_cursor(); + validate_cursor(curwin); } if (wp->w_height_inner != prev_height) { return; // Recursive call already changed the size, bail out. -- cgit From bbb68e2a034ad3aaea99178c09301ca458ee8dff Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Wed, 13 Mar 2024 22:06:39 +0000 Subject: vim-patch:9.1.0175: wrong window positions with 'winfix{width,height}' (#27845) Problem: winframe functions incorrectly recompute window positions if the altframe wasn't adjacent to the closed frame, which is possible if adjacent windows had 'winfix{width,height}' set. Solution: recompute for windows within the parent of the altframe and closed frame. Skip this (as before) if the altframe was top/left, but only if adjacent to the closed frame, as positions won't change in that case. Also correct the return value documentation for win_screenpos. (Sean Dewar) The issue revealed itself after removing the win_comp_pos call below winframe_restore in win_splitmove. Similarly, wrong positions could result from windows closed in other tabpages, as win_free_mem uses winframe_remove (at least until it is entered later, where enter_tabpage calls win_comp_pos). NOTE: As win_comp_pos handles only curtab, it's possible via other means for positions in non-current tabpages to be wrong (e.g: after changing 'laststatus', 'showtabline', etc.). Given enter_tabpage recomputes it, maybe it's intentional as an optimization? Should probably be documented in win_screenpos then, but I won't address that here. closes: vim/vim#14191 Nvim: don't reuse "wp" for "topleft" in winframe_remove, so the change integrates better with the call to winframe_find_altwin before it. https://github.com/vim/vim/commit/5866bc3a0f54115d5982fdc09bdbe4c45069265a --- src/nvim/eval.lua | 4 +--- src/nvim/window.c | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 19 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 96dc32259f..810cd2286b 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -12688,9 +12688,7 @@ M.funcs = { [1, 1], unless there is a tabline, then it is [2, 1]. {nr} can be the window number or the |window-ID|. Use zero for the current window. - Returns [0, 0] if the window cannot be found in the current - tabpage. - + Returns [0, 0] if the window cannot be found. ]=], name = 'win_screenpos', params = { { 'nr', 'integer' } }, diff --git a/src/nvim/window.c b/src/nvim/window.c index 6eee98fc35..c9c2124730 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3148,6 +3148,13 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al } frame_T *frp_close = win->w_frame; + + // Save the position of the containing frame (which will also contain the + // altframe) before we remove anything, to recompute window positions later. + const win_T *const topleft = frame2win(frp_close->fr_parent); + int row = topleft->w_winrow; + int col = topleft->w_wincol; + // Remove this frame from the list of frames. frame_remove(frp_close); @@ -3160,13 +3167,10 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al altfr == frp_close->fr_next, false); } - // If rows/columns go to a window below/right its positions need to be - // updated. Can only be done after the sizes have been updated. - if (altfr == frp_close->fr_next) { - int row = win->w_winrow; - int col = win->w_wincol; - - frame_comp_pos(altfr, &row, &col); + // If the altframe wasn't adjacent and left/above, resizing it will have + // changed window positions within the parent frame. Recompute them. + if (altfr != frp_close->fr_prev) { + frame_comp_pos(frp_close->fr_parent, &row, &col); } if (unflat_altfr == NULL) { @@ -3354,25 +3358,24 @@ void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) } } - int row = wp->w_winrow; - int col = wp->w_wincol; - // Restore the lost room that was redistributed to the altframe. Also // adjusts window sizes to fit restored statuslines/separators, if needed. if (dir == 'v') { frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height, unflat_altfr == frp->fr_next, false); - row += frp->fr_height; } else if (dir == 'h') { frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width, unflat_altfr == frp->fr_next, false); - col += frp->fr_width; } - // If rows/columns went to a window below/right, its positions need to be - // restored. Can only be done after the sizes have been updated. - if (unflat_altfr == frp->fr_next) { - frame_comp_pos(unflat_altfr, &row, &col); + // Recompute window positions within the parent frame to restore them. + // Positions were unchanged if the altframe was adjacent and left/above. + if (unflat_altfr != frp->fr_prev) { + const win_T *const topleft = frame2win(frp->fr_parent); + int row = topleft->w_winrow; + int col = topleft->w_wincol; + + frame_comp_pos(frp->fr_parent, &row, &col); } } -- cgit From b17be231a61f69b52eb809b6c72b20d3b089495d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 14 Mar 2024 06:44:50 +0800 Subject: vim-patch:9.1.0178: E1513 might be confusing (#27846) Problem: E1513 might be confusing (Christoph Thoma) Solution: reword error message, fix test to not depend on the actual message fixes: vim/vim#14189 https://github.com/vim/vim/commit/0a32b8854b52381fd17a6fcc5e38a3b9e77c8923 Co-authored-by: Christian Brabandt --- src/nvim/globals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 06fb95b577..bb9aca38b7 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -972,7 +972,7 @@ EXTERN const char e_undobang_cannot_redo_or_move_branch[] INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); EXTERN const char e_winfixbuf_cannot_go_to_buffer[] -INIT(= N_("E1513: Cannot edit buffer. 'winfixbuf' is enabled")); +INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); -- cgit From 9599e5d28d31cfb0cb16e878f123b74283cca26b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 14 Mar 2024 06:23:10 +0800 Subject: vim-patch:9.1.0174: 'cursorline' and 'wincolor' hl missing with conceal and wrap Problem: 'cursorline' and 'wincolor' highlight missing with concealed and wrapped lines. Solution: Apply 'cursorline' and 'wincolor' highlight to boguscols. (zeertzjq) Since 'cursorline' and 'wincolor' highlight apply after the end of the line, it is more consistent to have them also apply to boguscols. Assigning MAXCOL to values in ScreenCols[] make mouse click behave the same with 'cursorline' and 'nocursorline', but such behavior may be incorrect, as it puts the cursor on the next screen line. That may be fixed in a future PR. closes: vim/vim#14192 https://github.com/vim/vim/commit/21b0a3df8c4abb884489dfcc0c92b1bbe058f291 --- src/nvim/drawline.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/nvim') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index a7b1d561b6..8b8932be2d 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2851,6 +2851,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && !wp->w_p_rl; // Not right-to-left. int draw_col = wlv.col - wlv.boguscols; + + // Apply 'cursorline' highlight. + if (wlv.boguscols != 0 && (wlv.line_attr_lowprio != 0 || wlv.line_attr != 0)) { + int attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.line_attr); + while (draw_col < grid->cols) { + linebuf_char[wlv.off] = schar_from_char(' '); + linebuf_attr[wlv.off] = attr; + linebuf_vcol[wlv.off] = MAXCOL; // TODO(zeertzjq): this is wrong + wlv.off++; + draw_col++; + } + } + if (virt_line_offset >= 0) { draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line, kHlModeReplace, grid->cols, 0); -- cgit From 2af1dc0116c1914684fa0c3d94032c2698a5230d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 14 Mar 2024 06:44:41 +0800 Subject: vim-patch:9.1.0176: Cursor column wrong with 'virtualedit' and conceal Problem: Cursor column wrong with 'virtualedit' and conceal. Solution: Correct cursor column at end of line if never reached. (zeertzjq) closes: vim/vim#14190 https://github.com/vim/vim/commit/253ff4dece4e6cc4a9ff3ed935bc78f832b6fb7c --- src/nvim/drawline.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 8b8932be2d..8b6c3d58b2 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2451,11 +2451,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // In the cursor line and we may be concealing characters: correct // the cursor column when we reach its position. + // With 'virtualedit' we may never reach cursor position, but we still + // need to correct the cursor column, so do that at end of line. if (!did_wcol && wp == curwin && lnum == wp->w_cursor.lnum && conceal_cursor_line(wp) - && (int)wp->w_virtcol <= wlv.vcol + wlv.skip_cells) { + && (wlv.vcol + wlv.skip_cells >= wp->w_virtcol || mb_schar == NUL)) { wp->w_wcol = wlv.col - wlv.boguscols; + if (wlv.vcol + wlv.skip_cells < wp->w_virtcol) { + // Cursor beyond end of the line with 'virtualedit'. + wp->w_wcol += wp->w_virtcol - wlv.vcol - wlv.skip_cells; + } wp->w_wrow = wlv.row; did_wcol = true; wp->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; -- cgit From 3502aa63f0f4ea8d8982aea81a819424e71029bc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 14 Mar 2024 12:40:17 +0800 Subject: vim-patch:8.2.4950: text properties position wrong after shifting text (#27849) Problem: Text properties position wrong after shifting text. Solution: Adjust the text properties when shifting a block of text. (closes vim/vim#10418) https://github.com/vim/vim/commit/4b93674159d60c985de906c30f45dbaf2b64056f Most of the patch is already merged. Add an assertion in place of "added". Co-authored-by: LemonBoy --- src/nvim/ops.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim') diff --git a/src/nvim/ops.c b/src/nvim/ops.c index af5f2fae34..3dcbe597fe 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -408,6 +408,7 @@ static void shift_block(oparg_T *oap, int amount) memset(newp + bd.textcol + tabs, ' ', (size_t)spaces); // Note that STRMOVE() copies the trailing NUL. STRMOVE(newp + bd.textcol + tabs + spaces, bd.textstart); + assert(newlen - oldlen == (colnr_T)new_line_len - get_cursor_line_len()); } else { // left char *verbatim_copy_end; // end of the part of the line which is // copied verbatim @@ -494,6 +495,7 @@ static void shift_block(oparg_T *oap, int amount) memset(newp + verbatim_diff, ' ', fill); // Note that STRMOVE() copies the trailing NUL. STRMOVE(newp + verbatim_diff + fill, non_white); + assert(newlen - oldlen == (colnr_T)new_line_len - get_cursor_line_len()); } // replace the line ml_replace(curwin->w_cursor.lnum, newp, false); -- cgit From 090d1fd0b86897d2f5a80a600becf1525398ef30 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 13 Mar 2024 15:00:43 +0800 Subject: vim-patch:9.1.0172: More code can use ml_get_buf_len() instead of STRLEN() Problem: More code can use ml_get_buf_len() instead of STRLEN(). Solution: Change more STRLEN() calls to ml_get_buf_len(). Also do not set ml_line_textlen in ml_replace_len() if "has_props" is set, because "len_arg" also includes the size of text properties in that case. (zeertzjq) closes: vim/vim#14183 https://github.com/vim/vim/commit/94b7c3233ef534acc669b3083ed1fe59cf3a090b --- src/nvim/change.c | 4 +-- src/nvim/cursor.c | 11 +++--- src/nvim/diff.c | 2 +- src/nvim/drawline.c | 69 ++++++++++++++----------------------- src/nvim/edit.c | 8 ++--- src/nvim/ex_cmds.c | 35 ++++++++++--------- src/nvim/fileio.c | 2 +- src/nvim/fold.c | 7 ++-- src/nvim/insexpand.c | 2 +- src/nvim/mark.c | 2 +- src/nvim/memline.c | 10 ++++-- src/nvim/ops.c | 92 +++++++++++++++++++++++-------------------------- src/nvim/plines.c | 2 +- src/nvim/quickfix.c | 7 ++-- src/nvim/search.c | 14 ++++---- src/nvim/spell.c | 4 +-- src/nvim/spellfile.c | 7 ++-- src/nvim/spellsuggest.c | 7 ++-- src/nvim/statusline.c | 6 ++-- src/nvim/syntax.c | 10 +++--- src/nvim/textformat.c | 13 ++++--- src/nvim/textobject.c | 2 +- 22 files changed, 148 insertions(+), 168 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/change.c b/src/nvim/change.c index 673907fa27..b6f2be547f 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -1044,7 +1044,7 @@ bool copy_indent(int size, char *src) if (p == NULL) { // Allocate memory for the result: the copied indent, new indent // and the rest of the line. - line_len = (int)strlen(get_cursor_line_ptr()) + 1; + line_len = get_cursor_line_len() + 1; assert(ind_len + line_len >= 0); size_t line_size; STRICT_ADD(ind_len, line_len, &line_size, size_t); @@ -1865,7 +1865,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) } if (did_append) { // bail out and just get the final length of the line we just manipulated - bcount_t extra = (bcount_t)strlen(ml_get(curwin->w_cursor.lnum)); + bcount_t extra = ml_get_len(curwin->w_cursor.lnum); extmark_splice(curbuf, (int)curwin->w_cursor.lnum - 1, 0, 0, 0, 0, 1, 0, 1 + extra, kExtmarkUndo); changed_lines(curbuf, curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1, true); diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index c3f5a36500..91bd217ae8 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -108,9 +108,10 @@ static int coladvance2(win_T *wp, pos_T *pos, bool addspaces, bool finetune, col || ((get_ve_flags(wp) & VE_ONEMORE) && wcol < MAXCOL); char *line = ml_get_buf(wp->w_buffer, pos->lnum); + int linelen = ml_get_buf_len(wp->w_buffer, pos->lnum); if (wcol >= MAXCOL) { - idx = (int)strlen(line) - 1 + one_more; + idx = linelen - 1 + one_more; col = wcol; if ((addspaces || finetune) && !VIsual_active) { @@ -188,7 +189,6 @@ static int coladvance2(win_T *wp, pos_T *pos, bool addspaces, bool finetune, col col = wcol; } else { // Break a tab - int linelen = (int)strlen(line); int correct = wcol - col - csize + 1; // negative!! char *newline; @@ -315,8 +315,7 @@ void check_pos(buf_T *buf, pos_T *pos) } if (pos->col > 0) { - char *line = ml_get_buf(buf, pos->lnum); - colnr_T len = (colnr_T)strlen(line); + colnr_T len = ml_get_buf_len(buf, pos->lnum); if (pos->col > len) { pos->col = len; } @@ -347,7 +346,7 @@ void check_cursor_col(win_T *win) colnr_T oldcoladd = win->w_cursor.col + win->w_cursor.coladd; unsigned cur_ve_flags = get_ve_flags(win); - colnr_T len = (colnr_T)strlen(ml_get_buf(win->w_buffer, win->w_cursor.lnum)); + colnr_T len = ml_get_buf_len(win->w_buffer, win->w_cursor.lnum); if (len == 0) { win->w_cursor.col = 0; } else if (win->w_cursor.col >= len) { @@ -413,7 +412,7 @@ void check_visual_pos(void) VIsual.col = 0; VIsual.coladd = 0; } else { - int len = (int)strlen(ml_get(VIsual.lnum)); + int len = ml_get_len(VIsual.lnum); if (VIsual.col > len) { VIsual.col = len; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index bc91c1e4c2..c680600d39 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -756,7 +756,7 @@ static int diff_write_buffer(buf_T *buf, mmfile_t *m, linenr_T start, linenr_T e // xdiff requires one big block of memory with all the text. for (linenr_T lnum = start; lnum <= end; lnum++) { - len += strlen(ml_get_buf(buf, lnum)) + 1; + len += (size_t)ml_get_buf_len(buf, lnum) + 1; } char *ptr = try_malloc(len); if (ptr == NULL) { diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 8b6c3d58b2..4eaea4c6be 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -850,43 +850,6 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t } } -static colnr_T get_trailcol(win_T *wp, const char *ptr, const char *line) -{ - colnr_T trailcol = MAXCOL; - // find start of trailing whitespace - if (wp->w_p_lcs_chars.trail) { - trailcol = (colnr_T)strlen(ptr); - while (trailcol > 0 && ascii_iswhite(ptr[trailcol - 1])) { - trailcol--; - } - trailcol += (colnr_T)(ptr - line); - } - - return trailcol; -} - -static colnr_T get_leadcol(win_T *wp, const char *ptr, const char *line) -{ - colnr_T leadcol = 0; - - // find end of leading whitespace - if (wp->w_p_lcs_chars.lead || wp->w_p_lcs_chars.leadmultispace != NULL) { - leadcol = 0; - while (ascii_iswhite(ptr[leadcol])) { - leadcol++; - } - if (ptr[leadcol] == NUL) { - // in a line full of spaces all of them are treated as trailing - leadcol = 0; - } else { - // keep track of the first column not filled with spaces - leadcol += (colnr_T)(ptr - line + 1); - } - } - - return leadcol; -} - /// Start a screen line at column zero. static void win_line_start(win_T *wp, winlinevars_T *wlv) { @@ -1298,17 +1261,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s nextlinecol = MAXCOL; nextline_idx = 0; } else { - const size_t line_len = strlen(line); + const colnr_T line_len = ml_get_buf_len(wp->w_buffer, lnum); if (line_len < SPWORDLEN) { // Short line, use it completely and append the start of the // next line. nextlinecol = 0; - memmove(nextline, line, line_len); + memmove(nextline, line, (size_t)line_len); STRMOVE(nextline + line_len, nextline + SPWORDLEN); - nextline_idx = (int)line_len + 1; + nextline_idx = line_len + 1; } else { // Long line, use only the last SPWORDLEN bytes. - nextlinecol = (int)line_len - SPWORDLEN; + nextlinecol = line_len - SPWORDLEN; memmove(nextline, line + nextlinecol, SPWORDLEN); nextline_idx = SPWORDLEN + 1; } @@ -1336,8 +1299,28 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s || wp->w_p_lcs_chars.nbsp) { extra_check = true; } - trailcol = get_trailcol(wp, ptr, line); - leadcol = get_leadcol(wp, ptr, line); + // find start of trailing whitespace + if (wp->w_p_lcs_chars.trail) { + trailcol = ml_get_buf_len(wp->w_buffer, lnum); + while (trailcol > 0 && ascii_iswhite(ptr[trailcol - 1])) { + trailcol--; + } + trailcol += (colnr_T)(ptr - line); + } + // find end of leading whitespace + if (wp->w_p_lcs_chars.lead || wp->w_p_lcs_chars.leadmultispace != NULL) { + leadcol = 0; + while (ascii_iswhite(ptr[leadcol])) { + leadcol++; + } + if (ptr[leadcol] == NUL) { + // in a line full of spaces all of them are treated as trailing + leadcol = 0; + } else { + // keep track of the first column not filled with spaces + leadcol += (colnr_T)(ptr - line + 1); + } + } } // 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 5b62ab4215..df0c075306 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -2968,7 +2968,7 @@ static void replace_do_bs(int limit_col) } del_char_after_col(limit_col); if (l_State & VREPLACE_FLAG) { - orig_len = (int)strlen(get_cursor_pos_ptr()); + orig_len = get_cursor_pos_len(); } replace_push(cc); replace_pop_ins(); @@ -2976,7 +2976,7 @@ static void replace_do_bs(int limit_col) if (l_State & VREPLACE_FLAG) { // Get the number of screen cells used by the inserted characters char *p = get_cursor_pos_ptr(); - int ins_len = (int)strlen(p) - orig_len; + int ins_len = get_cursor_pos_len() - orig_len; int vcol = start_vcol; for (int i = 0; i < ins_len; i++) { vcol += win_chartabsize(curwin, p + i, vcol); @@ -3760,7 +3760,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) return false; } Insstart.lnum--; - Insstart.col = (colnr_T)strlen(ml_get(Insstart.lnum)); + Insstart.col = ml_get_len(Insstart.lnum); } // In replace mode: // cc < 0: NL was inserted, delete it @@ -4480,7 +4480,7 @@ bool ins_eol(int c) // NL in reverse insert will always start in the end of current line. if (revins_on) { - curwin->w_cursor.col += (colnr_T)strlen(get_cursor_pos_ptr()); + curwin->w_cursor.col += get_cursor_pos_len(); } AppendToRedobuff(NL_STR); diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 9f48312ec6..7c49189602 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -541,7 +541,7 @@ void ex_sort(exarg_T *eap) // Also get the longest line length for allocating "sortbuf". for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { char *s = ml_get(lnum); - int len = (int)strlen(s); + int len = ml_get_len(lnum); if (maxlen < len) { maxlen = len; } @@ -643,8 +643,8 @@ void ex_sort(exarg_T *eap) } char *s = ml_get(get_lnum); - size_t bytelen = strlen(s) + 1; // include EOL in bytelen - old_count += (bcount_t)bytelen; + colnr_T bytelen = ml_get_len(get_lnum) + 1; // include EOL in bytelen + old_count += bytelen; if (!unique || i == 0 || string_compare(s, sortbuf1) != 0) { // Copy the line into a buffer, it may become invalid in // ml_append(). And it's needed for "unique". @@ -652,7 +652,7 @@ void ex_sort(exarg_T *eap) if (ml_append(lnum++, sortbuf1, 0, false) == FAIL) { break; } - new_count += (bcount_t)bytelen; + new_count += bytelen; } fast_breakcheck(); if (got_int) { @@ -740,7 +740,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) return FAIL; } for (extra = 0, l = line1; l <= line2; l++) { - char *str = xstrdup(ml_get(l + extra)); + char *str = xstrnsave(ml_get(l + extra), (size_t)ml_get_len(l + extra)); ml_append(dest + l - line1, str, 0, false); xfree(str); if (dest < line1) { @@ -876,9 +876,8 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) curwin->w_cursor.lnum = n; while (line1 <= line2) { - // need to use xstrdup() because the line will be unlocked within - // ml_append() - char *p = xstrdup(ml_get(line1)); + // need to make a copy because the line will be unlocked within ml_append() + char *p = xstrnsave(ml_get(line1), (size_t)ml_get_len(line1)); ml_append(curwin->w_cursor.lnum, p, 0, false); xfree(p); @@ -3300,7 +3299,8 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n if (nmatch > 1) { \ sub_firstlnum += (linenr_T)nmatch - 1; \ xfree(sub_firstline); \ - sub_firstline = xstrdup(ml_get(sub_firstlnum)); \ + sub_firstline = xstrnsave(ml_get(sub_firstlnum), \ + (size_t)ml_get_len(sub_firstlnum)); \ /* When going beyond the last line, stop substituting. */ \ if (sub_firstlnum <= line2) { \ do_again = true; \ @@ -3628,7 +3628,8 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n break; } if (sub_firstline == NULL) { - sub_firstline = xstrdup(ml_get(sub_firstlnum)); + sub_firstline = xstrnsave(ml_get(sub_firstlnum), + (size_t)ml_get_len(sub_firstlnum)); } // Save the line number of the last change for the final @@ -3765,7 +3766,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n // really update the line, it would change // what matches. Temporarily replace the line // and change it back afterwards. - orig_line = xstrdup(ml_get(lnum)); + orig_line = xstrnsave(ml_get(lnum), (size_t)ml_get_len(lnum)); char *new_line = concat_str(new_start, sub_firstline + copycol); // Position the cursor relative to the end of the line, the @@ -4626,8 +4627,8 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i } char *str = NULL; // construct the line to show in here - size_t old_line_size = 0; - size_t line_size = 0; + colnr_T old_line_size = 0; + colnr_T line_size = 0; linenr_T linenr_preview = 0; // last line added to preview buffer linenr_T linenr_origbuf = 0; // last line added to original buffer linenr_T next_linenr = 0; // next line to show for the match @@ -4666,21 +4667,21 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i line = ""; } else { line = ml_get_buf(orig_buf, next_linenr); - line_size = strlen(line) + (size_t)col_width + 1; + line_size = ml_get_buf_len(orig_buf, next_linenr) + col_width + 1; // Reallocate if line not long enough if (line_size > old_line_size) { - str = xrealloc(str, line_size * sizeof(char)); + str = xrealloc(str, (size_t)line_size * sizeof(char)); old_line_size = line_size; } } // Put "|lnum| line" into `str` and append it to the preview buffer. - snprintf(str, line_size, "|%*" PRIdLINENR "| %s", col_width - 3, + snprintf(str, (size_t)line_size, "|%*" PRIdLINENR "| %s", col_width - 3, next_linenr, line); if (linenr_preview == 0) { ml_replace_buf(cmdpreview_buf, 1, str, true, false); } else { - ml_append_buf(cmdpreview_buf, linenr_preview, str, (colnr_T)line_size, false); + ml_append_buf(cmdpreview_buf, linenr_preview, str, line_size, false); } linenr_preview += 1; } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 4150d0997d..f032604a59 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -957,7 +957,7 @@ retry: int tlen = 0; while (true) { p = (uint8_t *)ml_get(read_buf_lnum) + read_buf_col; - int n = (int)strlen((char *)p); + int n = ml_get_len(read_buf_lnum) - read_buf_col; if (tlen + n + 1 > size) { // Filled up to "size", append partial line. // Change NL to NUL to reverse the effect done diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 15aba432c4..e70a05ed9a 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -1017,8 +1017,7 @@ void foldAdjustVisual(void) return; } - char *ptr = ml_get(end->lnum); - end->col = (colnr_T)strlen(ptr); + end->col = ml_get_len(end->lnum); if (end->col > 0 && *p_sel == 'o') { end->col--; } @@ -1605,7 +1604,7 @@ static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t mark // Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end char *line = ml_get_buf(buf, lnum); - size_t line_len = strlen(line); + size_t line_len = (size_t)ml_get_buf_len(buf, lnum); size_t added = 0; if (u_save(lnum - 1, lnum + 1) != OK) { @@ -1686,7 +1685,7 @@ static void foldDelMarker(buf_T *buf, linenr_T lnum, char *marker, size_t marker } if (u_save(lnum - 1, lnum + 1) == OK) { // Make new line: text-before-marker + text-after-marker - char *newline = xmalloc(strlen(line) - len + 1); + char *newline = xmalloc((size_t)ml_get_buf_len(buf, lnum) - len + 1); assert(p >= line); memcpy(newline, line, (size_t)(p - line)); STRCPY(newline + (p - line), p + len); diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index a1f341f404..526a17cfd4 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -2937,7 +2937,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar // buffer, so that word at start of buffer is found // correctly. st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count; - st->first_match_pos.col = (colnr_T)strlen(ml_get(st->first_match_pos.lnum)); + st->first_match_pos.col = ml_get_len(st->first_match_pos.lnum); } st->last_match_pos = st->first_match_pos; compl_type = 0; diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 0ecdd88ebd..1273093d8b 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1715,7 +1715,7 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) { if (lp->col > 0 || lp->coladd > 1) { const char *const p = ml_get_buf(buf, lp->lnum); - if (*p == NUL || (int)strlen(p) < lp->col) { + if (*p == NUL || ml_get_buf_len(buf, lp->lnum) < lp->col) { lp->col = 0; } else { lp->col -= utf_head_off(p, p + lp->col); diff --git a/src/nvim/memline.c b/src/nvim/memline.c index ca47f6aa98..9fa6261987 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1840,6 +1840,12 @@ colnr_T ml_get_len(linenr_T lnum) return ml_get_buf_len(curbuf, lnum); } +/// @return length (excluding the NUL) of the text after position "pos". +colnr_T ml_get_pos_len(pos_T *pos) +{ + return ml_get_buf_len(curbuf, curwin->w_cursor.lnum) - pos->col; +} + /// @return length (excluding the NUL) of the given line in the given buffer. colnr_T ml_get_buf_len(buf_T *buf, linenr_T lnum) { @@ -4133,7 +4139,7 @@ int dec(pos_T *lp) if (lp->col == MAXCOL) { // past end of line char *p = ml_get(lp->lnum); - lp->col = (colnr_T)strlen(p); + lp->col = ml_get_len(lp->lnum); lp->col -= utf_head_off(p, p + lp->col); return 0; } @@ -4149,7 +4155,7 @@ int dec(pos_T *lp) // there is a prior line lp->lnum--; char *p = ml_get(lp->lnum); - lp->col = (colnr_T)strlen(p); + lp->col = ml_get_len(lp->lnum); lp->col -= utf_head_off(p, p + lp->col); return 1; } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 3dcbe597fe..81b10f30a9 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -266,7 +266,7 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) // Set "'[" and "']" marks. curbuf->b_op_start = oap->start; curbuf->b_op_end.lnum = oap->end.lnum; - curbuf->b_op_end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); + curbuf->b_op_end.col = ml_get_len(oap->end.lnum); if (curbuf->b_op_end.col > 0) { curbuf->b_op_end.col--; } @@ -564,8 +564,8 @@ static void block_insert(oparg_T *oap, char *s, bool b_insert, struct block_def assert(count >= 0); // Make sure the allocated size matches what is actually copied below. - newp = xmalloc(strlen(oldp) + (size_t)spaces + s_len - + (spaces > 0 && !bdp->is_short ? (size_t)ts_val - (size_t)spaces : 0) + newp = xmalloc((size_t)ml_get_len(lnum) + (size_t)spaces + s_len + + (spaces > 0 && !bdp->is_short ? (size_t)(ts_val - spaces) : 0) + (size_t)count + 1); // copy up to shifted part @@ -1572,7 +1572,7 @@ int op_delete(oparg_T *oap) // Thus the number of characters may increase! int n = bd.textlen - bd.startspaces - bd.endspaces; char *oldp = ml_get(lnum); - char *newp = xmalloc(strlen(oldp) - (size_t)n + 1); + char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)n + 1); // copy up to deleted part memmove(newp, oldp, (size_t)bd.textcol); // insert spaces @@ -1681,8 +1681,7 @@ int op_delete(oparg_T *oap) if (virtual_op) { // fix up things for virtualedit-delete: // break the tabs which are going to get in our way - char *curline = get_cursor_line_ptr(); - int len = (int)strlen(curline); + int len = get_cursor_line_len(); if (oap->end.coladd != 0 && (int)oap->end.col >= len - 1 @@ -1875,7 +1874,7 @@ static int op_replace(oparg_T *oap, int c) numc *= utf_char2len(c); char *oldp = get_cursor_line_ptr(); - colnr_T oldlen = (int)strlen(oldp); + colnr_T oldlen = get_cursor_line_len(); size_t newp_size = (size_t)bd.textcol + (size_t)bd.startspaces; if (had_ctrl_v_cr || (c != '\r' && c != '\n')) { @@ -1939,7 +1938,7 @@ static int op_replace(oparg_T *oap, int c) if (oap->motion_type == kMTLineWise) { oap->start.col = 0; curwin->w_cursor.col = 0; - oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); + oap->end.col = ml_get_len(oap->end.lnum); if (oap->end.col) { oap->end.col--; } @@ -2058,7 +2057,7 @@ void op_tilde(oparg_T *oap) if (oap->motion_type == kMTLineWise) { oap->start.col = 0; pos.col = 0; - oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); + oap->end.col = ml_get_len(oap->end.lnum); if (oap->end.col) { oap->end.col--; } @@ -2073,7 +2072,7 @@ void op_tilde(oparg_T *oap) while (true) { did_change |= swapchars(oap->op_type, &pos, pos.lnum == oap->end.lnum ? oap->end.col + 1 - : (int)strlen(ml_get_pos(&pos))); + : ml_get_pos_len(&pos)); if (ltoreq(oap->end, pos) || inc(&pos) == -1) { break; } @@ -2232,12 +2231,11 @@ void op_insert(oparg_T *oap, int count1) // Get indent information ind_pre_col = (colnr_T)getwhitecols_curline(); ind_pre_vcol = get_indent(); - char *firstline = ml_get(oap->start.lnum) + bd.textcol; + pre_textlen = ml_get_len(oap->start.lnum) - bd.textcol; if (oap->op_type == OP_APPEND) { - firstline += bd.textlen; + pre_textlen -= bd.textlen; } - pre_textlen = (int)strlen(firstline); } if (oap->op_type == OP_APPEND) { @@ -2364,7 +2362,7 @@ void op_insert(oparg_T *oap, int count1) // Subsequent calls to ml_get() flush the firstline data - take a // copy of the required string. char *firstline = ml_get(oap->start.lnum); - const size_t len = strlen(firstline); + colnr_T len = ml_get_len(oap->start.lnum); colnr_T add = bd.textcol; colnr_T offset = 0; // offset when cursor was moved in insert mode if (oap->op_type == OP_APPEND) { @@ -2381,12 +2379,12 @@ void op_insert(oparg_T *oap, int count1) } } } - if ((size_t)add > len) { - firstline += len; // short line, point to the NUL - } else { - firstline += add; + if (add > len) { + add = len; // short line, point to the NUL } - int ins_len = (int)strlen(firstline) - pre_textlen - offset; + firstline += add; + len -= add; + int ins_len = len - pre_textlen - offset; if (pre_textlen >= 0 && ins_len > 0) { char *ins_text = xmemdupz(firstline, (size_t)ins_len); // block handled here @@ -2441,7 +2439,7 @@ int op_change(oparg_T *oap) coladvance_force(getviscol()); } firstline = ml_get(oap->start.lnum); - pre_textlen = (int)strlen(firstline); + pre_textlen = ml_get_len(oap->start.lnum); pre_indent = (int)getwhitecols(firstline); bd.textcol = curwin->w_cursor.col; } @@ -2474,7 +2472,7 @@ int op_change(oparg_T *oap) bd.textcol += (colnr_T)(new_indent - pre_indent); } - ins_len = (int)strlen(firstline) - pre_textlen; + ins_len = ml_get_len(oap->start.lnum) - pre_textlen; if (ins_len > 0) { // Subsequent calls to ml_get() flush the firstline data - take a // copy of the inserted text. @@ -2495,8 +2493,8 @@ int op_change(oparg_T *oap) vpos.coladd = 0; } char *oldp = ml_get(linenr); - char *newp = xmalloc(strlen(oldp) + (size_t)vpos.coladd - + (size_t)ins_len + 1); + char *newp = xmalloc((size_t)ml_get_len(linenr) + + (size_t)vpos.coladd + (size_t)ins_len + 1); // copy up to block start memmove(newp, oldp, (size_t)bd.textcol); int offset = bd.textcol; @@ -3173,6 +3171,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } // get the old line and advance to the position to insert at char *oldp = get_cursor_line_ptr(); + colnr_T oldlen = get_cursor_line_len(); CharsizeArg csarg; CSType cstype = init_charsize_arg(&csarg, curwin, curwin->w_cursor.lnum, oldp); @@ -3183,7 +3182,6 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) vcol += incr; ci = utfc_next(ci); } - size_t oldlen = (size_t)(ci.ptr - oldp) + strlen(ci.ptr); char *ptr = ci.ptr; bd.textcol = (colnr_T)(ptr - oldp); @@ -3233,7 +3231,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) totlen = (size_t)count * (size_t)(yanklen + spaces) + (size_t)bd.startspaces + (size_t)bd.endspaces; - char *newp = xmalloc(totlen + oldlen + 1); + char *newp = xmalloc(totlen + (size_t)oldlen + 1); // copy part up to cursor to new line ptr = newp; @@ -3263,7 +3261,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) ptr += bd.endspaces; // move the text after the cursor to the end of the line. - int columns = (int)oldlen - bd.textcol - delcount + 1; + int columns = oldlen - bd.textcol - delcount + 1; assert(columns >= 0); memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns); ml_replace(curwin->w_cursor.lnum, newp, false); @@ -3295,7 +3293,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) curwin->w_cursor.col++; // in Insert mode we might be after the NUL, correct for that - colnr_T len = (colnr_T)strlen(get_cursor_line_ptr()); + colnr_T len = get_cursor_line_len(); if (curwin->w_cursor.col > len) { curwin->w_cursor.col = len; } @@ -3359,7 +3357,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) totlen = (size_t)count * (size_t)yanklen; do { char *oldp = ml_get(lnum); - size_t oldlen = strlen(oldp); + colnr_T oldlen = ml_get_len(lnum); if (lnum > start_lnum) { pos_T pos = { .lnum = lnum, @@ -3370,11 +3368,11 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) col = MAXCOL; } } - if (VIsual_active && col > (colnr_T)oldlen) { + if (VIsual_active && col > oldlen) { lnum++; continue; } - char *newp = xmalloc(totlen + oldlen + 1); + char *newp = xmalloc(totlen + (size_t)oldlen + 1); memmove(newp, oldp, (size_t)col); char *ptr = newp + col; for (size_t i = 0; i < (size_t)count; i++) { @@ -3431,7 +3429,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) lnum = new_cursor.lnum; char *ptr = ml_get(lnum) + col; totlen = strlen(y_array[y_size - 1]); - char *newp = xmalloc((size_t)(strlen(ptr) + totlen + 1)); + char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1); STRCPY(newp, y_array[y_size - 1]); STRCAT(newp, ptr); // insert second line @@ -3465,7 +3463,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) curwin->w_cursor.lnum = lnum; char *ptr = ml_get(lnum); if (cnt == count && i == y_size - 1) { - lendiff = (int)strlen(ptr); + lendiff = ml_get_len(lnum); } if (*ptr == '#' && preprocs_left()) { indent = 0; // Leave # lines at start @@ -3482,7 +3480,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) curwin->w_cursor = old_pos; // remember how many chars were removed if (cnt == count && i == y_size - 1) { - lendiff -= (int)strlen(ml_get(lnum)); + lendiff -= ml_get_len(lnum); } } } @@ -3588,7 +3586,7 @@ error: curwin->w_set_curswant = true; // Make sure the cursor is not after the NUL. - int len = (int)strlen(get_cursor_line_ptr()); + int len = get_cursor_line_len(); if (curwin->w_cursor.col > len) { if (cur_ve_flags == VE_ALL) { curwin->w_cursor.coladd = curwin->w_cursor.col - len; @@ -4301,7 +4299,7 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T } } if (endcol == MAXCOL) { - endcol = (colnr_T)strlen(p); + endcol = ml_get_len(lnum); } if (startcol > endcol || is_oneChar) { bdp->textlen = 0; @@ -4358,20 +4356,20 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) } else if (oap->motion_type == kMTLineWise) { curwin->w_cursor.col = 0; pos.col = 0; - length = (colnr_T)strlen(ml_get(pos.lnum)); + length = ml_get_len(pos.lnum); } else { // oap->motion_type == kMTCharWise if (pos.lnum == oap->start.lnum && !oap->inclusive) { dec(&(oap->end)); } - length = (colnr_T)strlen(ml_get(pos.lnum)); + length = ml_get_len(pos.lnum); pos.col = 0; if (pos.lnum == oap->start.lnum) { pos.col += oap->start.col; length -= oap->start.col; } if (pos.lnum == oap->end.lnum) { - length = (int)strlen(ml_get(oap->end.lnum)); + length = ml_get_len(oap->end.lnum); if (oap->end.col >= length) { oap->end.col = length - 1; } @@ -5443,7 +5441,7 @@ void cursor_pos_info(dict_T *dict) validate_virtcol(curwin); col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); - col_print(buf2, sizeof(buf2), (int)strlen(p), linetabsize_str(p)); + col_print(buf2, sizeof(buf2), get_cursor_line_len(), linetabsize_str(p)); if (char_count_cursor == byte_count_cursor && char_count == byte_count) { @@ -5857,11 +5855,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) && cap->oap->op_type != OP_DELETE) { if (lt(VIsual, curwin->w_cursor)) { VIsual.col = 0; - curwin->w_cursor.col = - (colnr_T)strlen(ml_get(curwin->w_cursor.lnum)); + curwin->w_cursor.col = ml_get_len(curwin->w_cursor.lnum); } else { curwin->w_cursor.col = 0; - VIsual.col = (colnr_T)strlen(ml_get(VIsual.lnum)); + VIsual.col = ml_get_len(VIsual.lnum); } VIsual_mode = 'v'; } else if (VIsual_mode == 'v') { @@ -5890,7 +5887,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) || oap->motion_type == kMTLineWise) && hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - curwin->w_cursor.col = (colnr_T)strlen(get_cursor_line_ptr()); + curwin->w_cursor.col = get_cursor_line_len(); } } oap->end = curwin->w_cursor; @@ -5908,7 +5905,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) curwin->w_cursor.col = 0; } if (hasFolding(curwin, oap->start.lnum, NULL, &oap->start.lnum)) { - oap->start.col = (colnr_T)strlen(ml_get(oap->start.lnum)); + oap->start.col = ml_get_len(oap->start.lnum); } } oap->end = oap->start; @@ -6092,7 +6089,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (inindent(0)) { oap->motion_type = kMTLineWise; } else { - oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); + oap->end.col = ml_get_len(oap->end.lnum); if (oap->end.col) { oap->end.col--; oap->inclusive = true; @@ -6866,14 +6863,13 @@ bcount_t get_region_bytecount(buf_T *buf, linenr_T start_lnum, linenr_T end_lnum if (start_lnum == end_lnum) { return end_col - start_col; } - const char *first = ml_get_buf(buf, start_lnum); - bcount_t deleted_bytes = (bcount_t)strlen(first) - start_col + 1; + bcount_t deleted_bytes = ml_get_buf_len(buf, start_lnum) - start_col + 1; for (linenr_T i = 1; i <= end_lnum - start_lnum - 1; i++) { if (start_lnum + i > max_lnum) { return deleted_bytes; } - deleted_bytes += (bcount_t)strlen(ml_get_buf(buf, start_lnum + i)) + 1; + deleted_bytes += ml_get_buf_len(buf, start_lnum + i) + 1; } if (end_lnum > max_lnum) { return deleted_bytes; diff --git a/src/nvim/plines.c b/src/nvim/plines.c index ec13e5b5b7..44b06a0403 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -593,7 +593,7 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *e // Cannot put the cursor on part of a wide character. char *ptr = ml_get_buf(wp->w_buffer, pos->lnum); - if (pos->col < (colnr_T)strlen(ptr)) { + if (pos->col < ml_get_buf_len(wp->w_buffer, pos->lnum)) { int c = utf_ptr2char(ptr + pos->col); if ((c != TAB) && vim_isprintc(c)) { endadd = (colnr_T)(char2cells(c) - 1); diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index bf53dca167..a2029a6ae5 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -773,9 +773,9 @@ static int qf_get_next_buf_line(qfstate_T *state) return QF_END_OF_INPUT; } char *p_buf = ml_get_buf(state->buf, state->buflnum); + size_t len = (size_t)ml_get_buf_len(state->buf, state->buflnum); state->buflnum += 1; - size_t len = strlen(p_buf); if (len > IOSIZE - 2) { state->linebuf = qf_grow_linebuf(state, len); } else { @@ -5356,12 +5356,13 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp break; } col = regmatch->endpos[0].col + (col == regmatch->endpos[0].col); - if (col > (colnr_T)strlen(ml_get_buf(buf, lnum))) { + if (col > ml_get_buf_len(buf, lnum)) { break; } } } else { char *const str = ml_get_buf(buf, lnum); + const int line_len = ml_get_buf_len(buf, lnum); int score; uint32_t matches[MAX_FUZZY_MATCHES]; const size_t sz = sizeof(matches) / sizeof(matches[0]); @@ -5400,7 +5401,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp break; } col = (colnr_T)matches[pat_len - 1] + col + 1; - if (col > (colnr_T)strlen(str)) { + if (col > line_len) { break; } } diff --git a/src/nvim/search.c b/src/nvim/search.c index a3c9da8e3b..1720274e61 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -604,7 +604,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, && pos->col < MAXCOL - 2) { // Watch out for the "col" being MAXCOL - 2, used in a closed fold. ptr = ml_get_buf(buf, pos->lnum); - if ((int)strlen(ptr) <= pos->col) { + if (ml_get_buf_len(buf, pos->lnum) <= pos->col) { start_char_len = 1; } else { start_char_len = utfc_ptr2len(ptr + pos->col); @@ -851,7 +851,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, if (endpos.col == 0) { if (pos->lnum > 1) { // just in case pos->lnum--; - pos->col = (colnr_T)strlen(ml_get_buf(buf, pos->lnum)); + pos->col = ml_get_buf_len(buf, pos->lnum); } } else { pos->col--; @@ -969,7 +969,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, // A pattern like "\n\zs" may go past the last line. if (pos->lnum > buf->b_ml.ml_line_count) { pos->lnum = buf->b_ml.ml_line_count; - pos->col = (int)strlen(ml_get_buf(buf, pos->lnum)); + pos->col = ml_get_buf_len(buf, pos->lnum); if (pos->col > 0) { pos->col--; } @@ -1554,7 +1554,7 @@ int searchc(cmdarg_T *cap, bool t_cmd) char *p = get_cursor_line_ptr(); int col = curwin->w_cursor.col; - int len = (int)strlen(p); + int len = get_cursor_line_len(); while (count--) { while (true) { @@ -1958,7 +1958,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } linep = ml_get(pos.lnum); - pos.col = (colnr_T)strlen(linep); // pos.col on trailing NUL + pos.col = ml_get_len(pos.lnum); // pos.col on trailing NUL do_quotes = -1; line_breakcheck(); @@ -2105,7 +2105,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } if (pos.lnum > 1) { ptr = ml_get(pos.lnum - 1); - if (*ptr && *(ptr + strlen(ptr) - 1) == '\\') { + if (*ptr && *(ptr + ml_get_len(pos.lnum - 1) - 1) == '\\') { do_quotes = 1; if (start_in_quotes == kNone) { inquote = at_start; @@ -2472,7 +2472,7 @@ int current_search(int count, bool forward) } else { // try again from end of buffer // searching backwards, so set pos to last line and col pos.lnum = curwin->w_buffer->b_ml.ml_line_count; - pos.col = (colnr_T)strlen(ml_get(curwin->w_buffer->b_ml.ml_line_count)); + pos.col = ml_get_len(curwin->w_buffer->b_ml.ml_line_count); } } } diff --git a/src/nvim/spell.c b/src/nvim/spell.c index c2091c6bae..04c4f47a60 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1342,7 +1342,7 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att while (!got_int) { char *line = ml_get_buf(wp->w_buffer, lnum); - len = strlen(line); + len = (size_t)ml_get_buf_len(wp->w_buffer, lnum); if (buflen < len + MAXWLEN + 2) { xfree(buf); buflen = len + MAXWLEN + 2; @@ -2682,7 +2682,7 @@ void ex_spellrepall(exarg_T *eap) char *line = get_cursor_line_ptr(); if (addlen <= 0 || strncmp(line + curwin->w_cursor.col, repl_to, repl_to_len) != 0) { - char *p = xmalloc(strlen(line) + (size_t)addlen + 1); + char *p = xmalloc((size_t)get_cursor_line_len() + (size_t)addlen + 1); memmove(p, line, (size_t)curwin->w_cursor.col); STRCPY(p + curwin->w_cursor.col, repl_to); STRCAT(p, line + curwin->w_cursor.col + repl_from_len); diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 1c632d2700..45e1b37818 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -5114,13 +5114,12 @@ static void sug_write(spellinfo_T *spin, char *fname) for (linenr_T lnum = 1; lnum <= wcount; lnum++) { // : ... NUL char *line = ml_get_buf(spin->si_spellbuf, lnum); - size_t len = strlen(line) + 1; - if (fwrite(line, len, 1, fd) == 0) { + int len = ml_get_buf_len(spin->si_spellbuf, lnum) + 1; + if (fwrite(line, (size_t)len, 1, fd) == 0) { emsg(_(e_write)); goto theend; } - assert((size_t)spin->si_memtot + len <= INT_MAX); - spin->si_memtot += (int)len; + spin->si_memtot += len; } // Write another byte to check for errors. diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index 5c0e295f88..0cbd3d9795 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -480,9 +480,8 @@ void spell_suggest(int count) badlen++; end_visual_mode(); // make sure we don't include the NUL at the end of the line - char *line = get_cursor_line_ptr(); - if (badlen > (int)strlen(line) - (int)curwin->w_cursor.col) { - badlen = (int)strlen(line) - (int)curwin->w_cursor.col; + if (badlen > get_cursor_line_len() - curwin->w_cursor.col) { + badlen = get_cursor_line_len() - curwin->w_cursor.col; } // Find the start of the badly spelled word. } else if (spell_move_to(curwin, FORWARD, true, true, NULL) == 0 @@ -514,7 +513,7 @@ void spell_suggest(int count) int need_cap = check_need_cap(curwin, curwin->w_cursor.lnum, curwin->w_cursor.col); // Make a copy of current line since autocommands may free the line. - char *line = xstrdup(get_cursor_line_ptr()); + char *line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); spell_suggest_timeout = 5000; // Get the list of suggestions. Limit to 'lines' - 2 or the number in diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index b403f840ca..1d914dd105 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -1002,11 +1002,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // Get the byte value now, in case we need it below. This is more // efficient than making a copy of the line. int byteval; - const size_t len = strlen(line_ptr); - if (wp->w_cursor.col > (colnr_T)len) { + const colnr_T len = ml_get_buf_len(wp->w_buffer, lnum); + if (wp->w_cursor.col > len) { // Line may have changed since checking the cursor column, or the lnum // was adjusted above. - wp->w_cursor.col = (colnr_T)len; + wp->w_cursor.col = len; wp->w_cursor.coladd = 0; byteval = 0; } else { diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index ab8ab62b90..76824879d7 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -549,8 +549,8 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) // Skip lines that end in a backslash. for (; start_lnum > 1; start_lnum--) { - char *line = ml_get(start_lnum - 1); - if (*line == NUL || *(line + strlen(line) - 1) != '\\') { + char *l = ml_get(start_lnum - 1); + if (*l == NUL || *(l + ml_get_len(start_lnum - 1) - 1) != '\\') { break; } } @@ -2352,7 +2352,6 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ regmmatch_T regmatch; regmmatch_T best_regmatch; // startpos/endpos of best match lpos_T pos; - char *line; bool had_match = false; char buf_chartab[32]; // chartab array for syn option iskeyword @@ -2457,8 +2456,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ break; } - line = ml_get_buf(syn_buf, startpos->lnum); - int line_len = (int)strlen(line); + int line_len = ml_get_buf_len(syn_buf, startpos->lnum); // take care of an empty match or negative offset if (pos.col <= matchcol) { @@ -2635,7 +2633,7 @@ static void syn_add_start_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *s if (result->lnum > syn_buf->b_ml.ml_line_count) { // a "\n" at the end of the pattern may take us below the last line result->lnum = syn_buf->b_ml.ml_line_count; - col = (int)strlen(ml_get_buf(syn_buf, result->lnum)); + col = ml_get_buf_len(syn_buf, result->lnum); } if (off != 0) { base = ml_get_buf(syn_buf, result->lnum); diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index 41fb543994..c427206764 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -445,7 +445,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on // Check if cursor is not past the NUL off the line, cindent // may have added or removed indent. curwin->w_cursor.col += startcol; - colnr_T len = (colnr_T)strlen(get_cursor_line_ptr()); + colnr_T len = get_cursor_line_len(); if (curwin->w_cursor.col > len) { curwin->w_cursor.col = len; } @@ -506,12 +506,11 @@ static int fmt_check_par(linenr_T lnum, int *leader_len, char **leader_flags, bo static bool ends_in_white(linenr_T lnum) { char *s = ml_get(lnum); - size_t l; if (*s == NUL) { return false; } - l = strlen(s) - 1; + colnr_T l = ml_get_len(lnum) - 1; return ascii_iswhite((uint8_t)s[l]); } @@ -544,7 +543,7 @@ static bool same_leader(linenr_T lnum, int leader1_len, char *leader1_flags, int return false; } if (*p == COM_START) { - int line_len = (int)strlen(ml_get(lnum)); + int line_len = ml_get_len(lnum); if (line_len <= leader1_len) { return false; } @@ -647,7 +646,7 @@ void auto_format(bool trailblank, bool prev_line) // in 'formatoptions' and there is a single character before the cursor. // Otherwise the line would be broken and when typing another non-white // next they are not joined back together. - int wasatend = (pos.col == (colnr_T)strlen(old)); + bool wasatend = (pos.col == get_cursor_line_len()); if (*old != NUL && !trailblank && wasatend) { dec_cursor(); int cc = gchar_cursor(); @@ -701,7 +700,7 @@ void auto_format(bool trailblank, bool prev_line) // formatted. if (!wasatend && has_format_option(FO_WHITE_PAR)) { char *linep = get_cursor_line_ptr(); - colnr_T len = (colnr_T)strlen(linep); + colnr_T len = get_cursor_line_len(); if (curwin->w_cursor.col == len) { char *plinep = xstrnsave(linep, (size_t)len + 2); plinep[len] = ' '; @@ -1119,7 +1118,7 @@ void format_lines(linenr_T line_count, bool avoid_fex) } first_par_line = false; // If the line is getting long, format it next time - if (strlen(get_cursor_line_ptr()) > (size_t)max_len) { + if (get_cursor_line_len() > max_len) { force_format = true; } else { force_format = false; diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c index 8ac63aad16..3c81a840ea 100644 --- a/src/nvim/textobject.c +++ b/src/nvim/textobject.c @@ -218,7 +218,7 @@ bool findpar(bool *pincl, int dir, int count, int what, bool both) // Put the cursor on the last character in the last line and make the // motion inclusive. - if ((curwin->w_cursor.col = (colnr_T)strlen(line)) != 0) { + if ((curwin->w_cursor.col = ml_get_len(curr)) != 0) { curwin->w_cursor.col--; curwin->w_cursor.col -= utf_head_off(line, line + curwin->w_cursor.col); *pincl = true; -- cgit From 61b48e91b941258e6945e3eafadc777dccef5b75 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 14 Mar 2024 12:41:25 +0800 Subject: vim-patch:9.1.0177: Coverity reports dead code Problem: Coverity reports dead code. Solution: Remove the dead code. Also fix a mistake in ml_get_pos_len() and update some comments (zeertzjq). closes: vim/vim#14189 https://github.com/vim/vim/commit/8c55d60658b7ee3458dca57fc5eec90ca9bb9bf3 --- src/nvim/fold.c | 4 ++-- src/nvim/memline.c | 2 +- src/nvim/ops.c | 10 ++++------ src/nvim/quickfix.c | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/fold.c b/src/nvim/fold.c index e70a05ed9a..be3295c44c 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -518,7 +518,7 @@ static bool checkCloseRec(garray_T *gap, linenr_T lnum, int level) return retval; } -// foldCreateAllowed() {{{2 +// foldManualAllowed() {{{2 /// @return true if it's allowed to manually create or delete a fold or, /// give an error message and return false if not. int foldManualAllowed(bool create) @@ -1025,7 +1025,7 @@ void foldAdjustVisual(void) mb_adjust_cursor(); } -// cursor_foldstart() {{{2 +// foldAdjustCursor() {{{2 /// Move the cursor to the first line of a closed fold. void foldAdjustCursor(win_T *wp) { diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 9fa6261987..70304f6816 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1843,7 +1843,7 @@ colnr_T ml_get_len(linenr_T lnum) /// @return length (excluding the NUL) of the text after position "pos". colnr_T ml_get_pos_len(pos_T *pos) { - return ml_get_buf_len(curbuf, curwin->w_cursor.lnum) - pos->col; + return ml_get_buf_len(curbuf, pos->lnum) - pos->col; } /// @return length (excluding the NUL) of the given line in the given buffer. diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 81b10f30a9..2decb11d25 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1616,7 +1616,7 @@ int op_delete(oparg_T *oap) beginline(0); // cursor in column 0 } truncate_line(false); // delete the rest of the line, - // leave cursor past last char in line + // leaving cursor past last char in line if (oap->line_count > 1) { u_clearline(curbuf); // "U" command not possible after "2cc" } @@ -2232,7 +2232,6 @@ void op_insert(oparg_T *oap, int count1) ind_pre_col = (colnr_T)getwhitecols_curline(); ind_pre_vcol = get_indent(); pre_textlen = ml_get_len(oap->start.lnum) - bd.textcol; - if (oap->op_type == OP_APPEND) { pre_textlen -= bd.textlen; } @@ -4452,9 +4451,10 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) curwin->w_cursor = *pos; char *ptr = ml_get(pos->lnum); + int linelen = ml_get_len(pos->lnum); int col = pos->col; - if (*ptr == NUL || col + !!save_coladd >= (int)strlen(ptr)) { + if (col + !!save_coladd >= linelen) { goto theend; } @@ -4593,9 +4593,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // get the number value (unsigned) if (visual && VIsual_mode != 'V') { - maxlen = (curbuf->b_visual.vi_curswant == MAXCOL - ? (int)strlen(ptr) - col - : length); + maxlen = curbuf->b_visual.vi_curswant == MAXCOL ? linelen - col : length; } bool overflow = false; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index a2029a6ae5..0f639bf86a 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -5362,7 +5362,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp } } else { char *const str = ml_get_buf(buf, lnum); - const int line_len = ml_get_buf_len(buf, lnum); + const colnr_T linelen = ml_get_buf_len(buf, lnum); int score; uint32_t matches[MAX_FUZZY_MATCHES]; const size_t sz = sizeof(matches) / sizeof(matches[0]); @@ -5401,7 +5401,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp break; } col = (colnr_T)matches[pat_len - 1] + col + 1; - if (col > line_len) { + if (col > linelen) { break; } } -- cgit From fc2a56fe61a95b4124045039b39e20419920d2e2 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 14 Mar 2024 10:55:40 +0100 Subject: fix(api): fix set_lines viewport adjustment, but this time good fixes #27720 --- src/nvim/mark.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 1273093d8b..6ce42bb7fe 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1243,11 +1243,11 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount if (win != curwin || by_api) { if (win->w_topline >= line1 && win->w_topline <= line2) { if (amount == MAXLNUM) { // topline is deleted - if (line1 <= 1) { - win->w_topline = 1; + if (by_api && amount_after > line1 - line2 - 1) { + // api: if the deleted region was replaced with new contents, topline will + // get adjusted later as an effect of the adjusted cursor in fix_cursor() } else { - // api: if the deleted region was replaced with new contents, display that - win->w_topline = (by_api && amount_after > line1 - line2 - 1) ? line1 : line1 - 1; + win->w_topline = MAX(line1 - 1, 1); } } else if (win->w_topline > line1) { // keep topline on the same line, unless inserting just -- cgit From 120c4ec855bc654ae067fafdb63bb16460d97c88 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 28 Feb 2024 18:47:47 +0100 Subject: fix(terminal): disable reflow again reverts https://github.com/neovim/neovim/commit/c855eee919f2d4edc9b9fa91b277454290fbabfe This setting introduces constant CI failures on macos (see https://github.com/neovim/neovim/issues/23762). --- src/nvim/memline.c | 4 ++++ src/nvim/options.lua | 3 --- src/nvim/terminal.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 70304f6816..5acf4f0c37 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -30,6 +30,10 @@ // changed (lines appended/deleted/changed) or when it is flushed it gets a // positive number. Use mf_trans_del() to get the new number, before calling // mf_get(). +// +// "Mom, can we get ropes?" +// "We have ropes at home." +// Ropes at home: #include #include diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 411acbcc82..ca8e1eaec5 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -6573,9 +6573,6 @@ return { top are deleted if new lines exceed this limit. Minimum is 1, maximum is 100000. Only in |terminal| buffers. - - Note: Lines that are not visible and kept in scrollback are not - reflown when the terminal buffer is resized horizontally. ]=], full_name = 'scrollback', redraw = { 'current_buffer' }, diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 5a343b4972..edde7ff57a 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -307,7 +307,8 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts) // Set up screen term->vts = vterm_obtain_screen(term->vt); vterm_screen_enable_altscreen(term->vts, true); - vterm_screen_enable_reflow(term->vts, true); + // TODO(clason): reenable when https://github.com/neovim/neovim/issues/23762 is fixed + // vterm_screen_enable_reflow(term->vts, true); // delete empty lines at the end of the buffer vterm_screen_set_callbacks(term->vts, &vterm_screen_callbacks, term); vterm_screen_set_unrecognised_fallbacks(term->vts, &vterm_fallbacks, term); -- cgit From a6b6d036b19a548e3f2a199c6927ac7495c02ea1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 14 Mar 2024 19:33:14 +0800 Subject: refactor(drawline): rename vcol_off to vcol_off_co (#27857) It is clearing that it's for conceal and matches the change from Vim patch 9.0.1325. Also correct some comments related to fix_for_boguscols(). --- src/nvim/drawline.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 4eaea4c6be..851ed55f6e 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -73,7 +73,7 @@ typedef struct { int col; ///< visual column on screen, after wrapping int boguscols; ///< nonexistent columns added to "col" to force wrapping int old_boguscols; ///< bogus boguscols - int vcol_off; ///< offset for concealed characters + int vcol_off_co; ///< offset for concealed characters int off; ///< offset relative start of line @@ -865,9 +865,9 @@ static void win_line_start(win_T *wp, winlinevars_T *wlv) static void fix_for_boguscols(winlinevars_T *wlv) { - wlv->n_extra += wlv->vcol_off; - wlv->vcol -= wlv->vcol_off; - wlv->vcol_off = 0; + wlv->n_extra += wlv->vcol_off_co; + wlv->vcol -= wlv->vcol_off_co; + wlv->vcol_off_co = 0; wlv->col -= wlv->boguscols; wlv->old_boguscols = wlv->boguscols; wlv->boguscols = 0; @@ -987,7 +987,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s int conceal_attr = win_hl_attr(wp, HLF_CONCEAL); bool is_concealing = false; bool did_wcol = false; -#define vcol_hlc(wlv) ((wlv).vcol - (wlv).vcol_off) +#define vcol_hlc(wlv) ((wlv).vcol - (wlv).vcol_off_co) assert(startrow < endrow); @@ -2216,9 +2216,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } else { int saved_nextra = wlv.n_extra; - if (wlv.vcol_off > 0) { + if (wlv.vcol_off_co > 0) { // there are characters to conceal - tab_len += wlv.vcol_off; + tab_len += wlv.vcol_off_co; } // boguscols before fix_for_boguscols() from above. if (wp->w_p_lcs_chars.tab1 && wlv.old_boguscols > 0 @@ -2260,27 +2260,27 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } // n_extra will be increased by fix_for_boguscols() - // macro below, so need to adjust for that here - if (wlv.vcol_off > 0) { - wlv.n_extra -= wlv.vcol_off; + // below, so need to adjust for that here + if (wlv.vcol_off_co > 0) { + wlv.n_extra -= wlv.vcol_off_co; } } } { - int vc_saved = wlv.vcol_off; + int vc_saved = wlv.vcol_off_co; // Tab alignment should be identical regardless of // 'conceallevel' value. So tab compensates of all // previous concealed characters, and thus resets - // vcol_off and boguscols accumulated so far in the + // vcol_off_co and boguscols accumulated so far in the // line. Note that the tab can be longer than // 'tabstop' when there are concealed characters. fix_for_boguscols(&wlv); // Make sure, the highlighting for the tab char will be // correctly set further below (effectively reverts the - // FIX_FOR_BOGSUCOLS macro). + // fix_for_boguscols() call). if (wlv.n_extra == tab_len + vc_saved && wp->w_p_list && wp->w_p_lcs_chars.tab1) { tab_len += vc_saved; @@ -2408,7 +2408,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s prev_syntax_id = syntax_seqnr; if (wlv.n_extra > 0) { - wlv.vcol_off += wlv.n_extra; + wlv.vcol_off_co += wlv.n_extra; } wlv.vcol += wlv.n_extra; if (is_wrapped && wlv.n_extra > 0) { @@ -2739,9 +2739,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.col++; } else if (wp->w_p_cole > 0 && is_concealing) { wlv.skip_cells--; - wlv.vcol_off++; + wlv.vcol_off_co++; if (wlv.n_extra > 0) { - wlv.vcol_off += wlv.n_extra; + wlv.vcol_off_co += wlv.n_extra; } if (is_wrapped) { // Special voodoo required if 'wrap' is on. @@ -2872,7 +2872,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } wlv.boguscols = 0; - wlv.vcol_off = 0; + wlv.vcol_off_co = 0; wlv.row++; // When not wrapping and finished diff lines, break here. -- cgit From 0570a19c8a84debcdf2bc73f4c5f2d7d9de3ead2 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 14 Mar 2024 10:03:59 +0100 Subject: fix(intro): make intro explicitly stateful Instead of randomly disappearing because some random event might have caused mid_start or bot_scroll_start to randomly take a low value, treat intro message as a _first class stateful_ thing. This means that intro message will kept being _redrawn_ as long as we are in the state it should be shown. This also includes screen resizes. you will not lose the intro message because there was a delay in detecting terminal features. --- src/nvim/drawscreen.c | 14 ++++++++++---- src/nvim/version.c | 14 ++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index f2ad4ca77e..1fb42af786 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -421,7 +421,14 @@ bool redrawing(void) /// and redraw_all_later() to mark parts of the screen as needing a redraw. int update_screen(void) { - static bool did_intro = false; + static bool still_may_intro = true; + if (still_may_intro) { + if (!may_show_intro()) { + must_redraw = UPD_NOT_VALID; + still_may_intro = false; + } + } + bool is_stl_global = global_stl_height() > 0; // Don't do anything if the screen structures are (not yet) valid. @@ -673,10 +680,9 @@ int update_screen(void) } // May put up an introductory message when not editing a file - if (!did_intro) { - maybe_intro_message(); + if (still_may_intro) { + intro_message(false); } - did_intro = true; decor_providers_invoke_end(); diff --git a/src/nvim/version.c b/src/nvim/version.c index 038c9701bf..ff6f7835b2 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -2710,15 +2710,13 @@ void list_version(void) : "\nRun \":verbose version\" for more info")); } -/// Show the intro message when not editing a file. -void maybe_intro_message(void) +/// Whether it still is not too late to show an intro message +bool may_show_intro(void) { - if (buf_is_empty(curbuf) - && (curbuf->b_fname == NULL) - && (firstwin->w_next == NULL) - && (vim_strchr(p_shm, SHM_INTRO) == NULL)) { - intro_message(false); - } + return (buf_is_empty(curbuf) + && (curbuf->b_fname == NULL) + && (firstwin->w_next == NULL) + && (vim_strchr(p_shm, SHM_INTRO) == NULL)); } /// Give an introductory message about Vim. -- cgit From ca7dd33fa783181d62b0573082d2e691fcfc29d2 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 15 Mar 2024 05:54:22 +0800 Subject: fix(highlight): don't show CursorColumn on current line (#27848) Problem: CursorColumn highlight behavior is inconsistent with 'virtualedit' set: - If cursor is on the text, CursorColumn is not shown. - If cursor is after end of line, CursorColumn is shown. Solution: Don't shown CursorColumn on current line if cursor is after end of line. Vim doesn't have this problem because in most cases it uses the code path for drawing buffer text when CursorColumn highlight is needed. --- src/nvim/drawline.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 851ed55f6e..2f541a8a21 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2594,10 +2594,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s int col_attr = base_attr; - if (wp->w_p_cuc && vcol_hlc(wlv) == wp->w_virtcol) { - col_attr = cuc_attr; + if (wp->w_p_cuc && vcol_hlc(wlv) == wp->w_virtcol + && lnum != wp->w_cursor.lnum) { + col_attr = hl_combine_attr(col_attr, cuc_attr); } else if (wlv.color_cols && vcol_hlc(wlv) == *wlv.color_cols) { - col_attr = hl_combine_attr(wlv.line_attr_lowprio, mc_attr); + col_attr = hl_combine_attr(col_attr, mc_attr); } col_attr = hl_combine_attr(col_attr, wlv.line_attr); @@ -2798,7 +2799,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.char_attr = vcol_save_attr; } - // restore attributes after "predeces" in 'listchars' + // restore attributes after "precedes" in 'listchars' if (n_attr3 > 0 && --n_attr3 == 0) { wlv.char_attr = saved_attr3; } -- cgit From 60491466f951f93d8d9010645e1dac367f3ea979 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 15 Mar 2024 06:56:45 +0800 Subject: vim-patch:9.1.0180: Cursor pos wrong when double-width chars are concealed (#27862) Problem: Cursor pos wrong when double-width chars are concealed. Solution: Advance one more virtual column for a double-width char. Run some tests with both 'wrap' and 'nowrap' (zeertzjq). closes: vim/vim#14197 https://github.com/vim/vim/commit/010e1539d67442cc69a97bef6453efaf849d0db3 --- src/nvim/drawline.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 2f541a8a21..dfe3dbca50 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2403,6 +2403,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } else { mb_schar = schar_from_ascii(' '); } + + if (utf_char2cells(mb_c) > 1) { + // When the first char to be concealed is double-width, + // need to advance one more virtual column. + wlv.n_extra++; + } + mb_c = schar_get_first_codepoint(mb_schar); prev_syntax_id = syntax_seqnr; @@ -2739,11 +2746,21 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.off++; wlv.col++; } else if (wp->w_p_cole > 0 && is_concealing) { + bool concealed_wide = utf_char2cells(mb_c) > 1; + wlv.skip_cells--; wlv.vcol_off_co++; + if (concealed_wide) { + // When a double-width char is concealed, + // need to advance one more virtual column. + wlv.vcol++; + wlv.vcol_off_co++; + } + if (wlv.n_extra > 0) { wlv.vcol_off_co += wlv.n_extra; } + if (is_wrapped) { // Special voodoo required if 'wrap' is on. // @@ -2764,7 +2781,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.n_attr = 0; } - if (utf_char2cells(mb_c) > 1) { + if (concealed_wide) { // Need to fill two screen columns. wlv.boguscols++; wlv.col++; -- cgit From d326e04860427b0a6a0b66da86fae8e5d23c8a7c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 15 Mar 2024 08:05:59 +0800 Subject: vim-patch:9.1.0181: no overflow check for string formatting (#27863) Problem: no overflow check for string formatting Solution: Check message formatting function for overflow. (Chris van Willegen) closes: vim/vim#13799 https://github.com/vim/vim/commit/c35fc03dbd47582b256776fb11f11d8ceb24f8f0 Co-authored-by: Christ van Willegen --- src/nvim/eval.lua | 3 ++ src/nvim/strings.c | 131 +++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 104 insertions(+), 30 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 810cd2286b..7df4ab71ef 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -7836,6 +7836,9 @@ M.funcs = { echo printf("%1$*2$.*3$f", 1.4142135, 6, 2) < 1.41 + You will get an overflow error |E1510|, when the field-width + or precision will result in a string longer than 6400 chars. + *E1500* You cannot mix positional and non-positional arguments: >vim echo printf("%s%1$s", "One", "Two") diff --git a/src/nvim/strings.c b/src/nvim/strings.c index f9b945f1da..a04aaa8f60 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -986,6 +986,40 @@ static int adjust_types(const char ***ap_types, int arg, int *num_posarg, const return OK; } +static void format_overflow_error(const char *pstart) +{ + const char *p = pstart; + + while (ascii_isdigit((int)(*p))) { + p++; + } + + size_t arglen = (size_t)(p - pstart); + char *argcopy = xstrnsave(pstart, arglen); + semsg(_(e_val_too_large), argcopy); + xfree(argcopy); +} + +enum { MAX_ALLOWED_STRING_WIDTH = 6400, }; + +static int get_unsigned_int(const char *pstart, const char **p, unsigned *uj) +{ + *uj = (unsigned)(**p - '0'); + (*p)++; + + while (ascii_isdigit((int)(**p)) && *uj < MAX_ALLOWED_STRING_WIDTH) { + *uj = 10 * *uj + (unsigned)(**p - '0'); + (*p)++; + } + + if (*uj > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(pstart); + return FAIL; + } + + return OK; +} + static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *fmt, typval_T *tvs) FUNC_ATTR_NONNULL_ARG(1, 2) { @@ -1019,6 +1053,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * // variable for positional arg int pos_arg = -1; + const char *pstart = p + 1; p++; // skip '%' @@ -1038,11 +1073,12 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * } // Positional argument - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(pstart, &p, &uj) == FAIL) { + goto error; } + pos_arg = (int)uj; any_pos = 1; @@ -1080,10 +1116,10 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * if (ascii_isdigit((int)(*p))) { // Positional argument field width - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) { + goto error; } if (*p != '$') { @@ -1105,10 +1141,11 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * } else if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we treat // argument like common implementations do - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } if (*p == '$') { @@ -1126,10 +1163,10 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * if (ascii_isdigit((int)(*p))) { // Parse precision - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) { + goto error; } if (*p == '$') { @@ -1152,10 +1189,11 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * } else if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we // treat argument like common implementations do - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } if (*p == '$') { @@ -1447,11 +1485,13 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st if (*ptype == '$') { // Positional argument - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } + pos_arg = (int)uj; p++; @@ -1482,15 +1522,18 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st // parse field width if (*p == '*') { + const char *digstart = p + 1; + p++; if (ascii_isdigit((int)(*p))) { // Positional argument field width - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } + arg_idx = (int)uj; p++; @@ -1502,6 +1545,11 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st &arg_cur, fmt), va_arg(ap, int))); + if (j > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(digstart); + goto error; + } + if (j >= 0) { min_field_width = (size_t)j; } else { @@ -1511,11 +1559,18 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st } else if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we treat // argument like common implementations do - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; + } + + if (uj > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(digstart); + goto error; } + min_field_width = uj; } @@ -1527,22 +1582,32 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we // treat argument like common implementations do - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } + + if (uj > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(digstart); + goto error; + } + precision = uj; } else if (*p == '*') { + const char *digstart = p; + p++; if (ascii_isdigit((int)(*p))) { // positional argument - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } + arg_idx = (int)uj; p++; @@ -1554,6 +1619,11 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st &arg_cur, fmt), va_arg(ap, int))); + if (j > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(digstart); + goto error; + } + if (j >= 0) { precision = (size_t)j; } else { @@ -2160,6 +2230,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st emsg(_("E767: Too many arguments to printf()")); } +error: xfree(ap_types); va_end(ap); -- cgit From 062c0245e3455f0a483729479bda2fc242b3dec5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 15 Mar 2024 14:45:58 +0800 Subject: refactor: remove unused "coloff" argument of win_put_linebuf() (#27866) It isn't really used, and is always passed 0. Also rename "start_col" to "startcol" for consistency with "endcol". --- src/nvim/drawline.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index dfe3dbca50..90bf6eda51 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -1549,7 +1549,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // When only updating the columns and that's done, stop here. if (col_rows > 0) { - win_put_linebuf(wp, wlv.row, 0, wlv.off, wlv.off, bg_attr, false); + win_put_linebuf(wp, wlv.row, wlv.off, wlv.off, bg_attr, false); // Need to update more screen lines if: // - 'statuscolumn' needs to be drawn, or // - LineNrAbove or LineNrBelow is used, or @@ -1605,7 +1605,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && lnum == wp->w_cursor.lnum && wlv.vcol >= wp->w_virtcol) { draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row); // don't clear anything after wlv.col - win_put_linebuf(wp, wlv.row, 0, wlv.col, wlv.col, bg_attr, false); + win_put_linebuf(wp, wlv.row, wlv.col, wlv.col, bg_attr, false); // Pretend we have finished updating the window. Except when // 'cursorcolumn' is set. if (wp->w_p_cuc) { @@ -2638,7 +2638,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine, grid->cols, 0); } draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row); - win_put_linebuf(wp, wlv.row, 0, wlv.col, grid->cols, bg_attr, false); + win_put_linebuf(wp, wlv.row, wlv.col, grid->cols, bg_attr, false); wlv.row++; // Update w_cline_height and w_cline_folded if the cursor line was @@ -2878,7 +2878,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s draw_virt_text(wp, buf, win_col_offset, &draw_col, wlv.row); } - win_put_linebuf(wp, wlv.row, 0, draw_col, grid->cols, bg_attr, wrap); + win_put_linebuf(wp, wlv.row, draw_col, grid->cols, bg_attr, wrap); if (wrap) { ScreenGrid *current_grid = grid; int current_row = wlv.row; @@ -2938,15 +2938,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s return wlv.row; } -static void win_put_linebuf(win_T *wp, int row, int coloff, int endcol, int clear_width, - int bg_attr, bool wrap) +static void win_put_linebuf(win_T *wp, int row, int endcol, int clear_width, int bg_attr, bool wrap) { ScreenGrid *grid = &wp->w_grid; - int start_col = 0; + int startcol = 0; if (wp->w_p_rl) { - linebuf_mirror(&start_col, &endcol, &clear_width, grid->cols); + linebuf_mirror(&startcol, &endcol, &clear_width, grid->cols); } // Take care of putting "<<<" on the first line for 'smoothscroll'. @@ -2975,6 +2974,7 @@ static void win_put_linebuf(win_T *wp, int row, int coloff, int endcol, int clea } } + int coloff = 0; grid_adjust(&grid, &row, &coloff); - grid_put_linebuf(grid, row, coloff, start_col, endcol, clear_width, wp->w_p_rl, bg_attr, wrap); + grid_put_linebuf(grid, row, coloff, startcol, endcol, clear_width, wp->w_p_rl, bg_attr, wrap); } -- cgit From c971f538ab87b537ae4c97bd44167661c5691a2d Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Thu, 14 Mar 2024 23:55:32 +0100 Subject: fix(api): update grid cursor in nvim_win_set_cursor() Problem: Cursor position set by nvim_win_set_cursor() is not reflected on the screen when followed by a blocking call like getchar(). Solution: Immediately update the cursor position on the grid. --- src/nvim/api/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 026d09d9a9..30f77c7248 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -148,7 +148,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) switchwin_T switchwin; switch_win(&switchwin, win, NULL, true); update_topline(curwin); - validate_cursor(curwin); + setcursor_mayforce(true); restore_win(&switchwin, true); redraw_later(win, UPD_VALID); -- cgit From d41b8d47587bd4c300420fa76f517298e97af513 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Fri, 15 Mar 2024 00:39:44 +0100 Subject: fix(ui): ext_cmdline should not move cursor to curwin Problem: The ext_cmdline cursor position on the screen seems to rely on an implicit assumption that the event listener implements a cmdline window that is made the current window which is problematic (e.g. breaks 'incsearch' in the actual current window). Solution: Remove this assumption and allow nvim_win_set_cursor() to move the cursor on the screen to a non-current window (previous commit). --- src/nvim/ex_getln.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 303337ae98..d482f9851e 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -767,7 +767,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear } setmouse(); - ui_cursor_shape(); // may show different cursor shape + setcursor(); TryState tstate; Error err = ERROR_INIT; @@ -927,7 +927,6 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear } may_trigger_modechanged(); setmouse(); - ui_cursor_shape(); // may show different cursor shape sb_text_end_cmdline(); theend: @@ -3859,7 +3858,6 @@ void cursorcmd(void) if (ccline.redraw_state < kCmdRedrawPos) { ccline.redraw_state = kCmdRedrawPos; } - setcursor(); return; } @@ -4553,6 +4551,7 @@ static int open_cmdwin(void) State = save_State; may_trigger_modechanged(); setmouse(); + setcursor(); return cmdwin_result; } -- cgit From a8522f02e9a295055b03fe5066a77d711182c111 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 15 Mar 2024 09:23:18 +0100 Subject: fix(ui): startup intro message should be visible with ext_multigrid As this message is literally drawn on top of the EOB area of the first window, the simple solution is to just draw the message on top of the grid of the first window. We still want #24764 (msg_intro event) but now only for ext_messages. --- src/nvim/version.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/version.c b/src/nvim/version.c index ff6f7835b2..27c3826cd2 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -32,6 +32,7 @@ #include "nvim/option_vars.h" #include "nvim/os/os.h" #include "nvim/strings.h" +#include "nvim/ui.h" #include "nvim/version.h" // for ":version", ":intro", and "nvim --version" @@ -2724,7 +2725,7 @@ bool may_show_intro(void) /// Or with the ":intro" command (for Sven :-). /// /// @param colon true for ":intro" -void intro_message(int colon) +void intro_message(bool colon) { static char *(lines[]) = { N_(NVIM_VERSION_LONG), @@ -2801,7 +2802,7 @@ void intro_message(int colon) } if (*mesg != NUL) { - do_intro_line(row, mesg, 0); + do_intro_line(row, mesg, colon); } row++; @@ -2812,7 +2813,7 @@ void intro_message(int colon) } } -static void do_intro_line(int row, char *mesg, int attr) +static void do_intro_line(int row, char *mesg, bool colon) { int l; @@ -2825,7 +2826,12 @@ static void do_intro_line(int row, char *mesg, int attr) col = 0; } - grid_line_start(&default_grid, row); + ScreenGrid *grid = &default_grid; + if (!colon && ui_has(kUIMultigrid)) { + grid = &firstwin->w_grid; + } + + grid_line_start(grid, row); // Split up in parts to highlight <> items differently. for (char *p = mesg; *p != NUL; p += l) { for (l = 0; @@ -2834,7 +2840,7 @@ static void do_intro_line(int row, char *mesg, int attr) l += utfc_ptr2len(p + l) - 1; } assert(row <= INT_MAX && col <= INT_MAX); - col += grid_line_puts(col, p, l, *p == '<' ? HL_ATTR(HLF_8) : attr); + col += grid_line_puts(col, p, l, *p == '<' ? HL_ATTR(HLF_8) : 0); } grid_line_flush(); } -- cgit From e0707d3529592504fbafaca0d8f052247af789ae Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 15 Mar 2024 11:31:41 +0100 Subject: fix(ui): fix edge case around flushing ui_flush_buf() doesn't know about `lenpos` so `remote_ui_raw_line` needs to always handle it before flushing --- src/nvim/api/ui.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 692e3f95fc..35348f344b 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -533,7 +533,8 @@ static void ui_alloc_buf(RemoteUI *ui) static void prepare_call(RemoteUI *ui, const char *name) { - if (ui->packer.startptr && BUF_POS(ui) > UI_BUF_SIZE - EVENT_BUF_SIZE) { + if (ui->packer.startptr + && (BUF_POS(ui) > UI_BUF_SIZE - EVENT_BUF_SIZE || ui->ncells_pending >= 500)) { ui_flush_buf(ui); } @@ -781,11 +782,14 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco for (size_t i = 0; i < ncells; i++) { repeat++; if (i == ncells - 1 || attrs[i] != attrs[i + 1] || chunk[i] != chunk[i + 1]) { - if (UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1) { + if (UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1 + || ui->ncells_pending >= 500) { // close to overflowing the redraw buffer. finish this event, // flush, and start a new "grid_line" event at the current position. // For simplicity leave place for the final "clear" element // as well, hence the factor of 2 in the check. + // Also if there is a lot of packed cells, pass them of to the UI to + // let it start processing them mpack_w2(&lenpos, nelem); // We only ever set the wrap field on the final "grid_line" event for the line. @@ -831,11 +835,6 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco } mpack_w2(&lenpos, nelem); mpack_bool(buf, flags & kLineFlagWrap); - - if (ui->ncells_pending > 500) { - // pass off cells to UI to let it start processing them - ui_flush_buf(ui); - } } else { for (int i = 0; i < endcol - startcol; i++) { remote_ui_cursor_goto(ui, row, startcol + i); -- cgit From 4447cefa4815bd55f1511d3a655c21ac5e1c090f Mon Sep 17 00:00:00 2001 From: ite-usagi <77563904+ite-usagi@users.noreply.github.com> Date: Sat, 16 Mar 2024 15:50:52 +0900 Subject: fix(l10n): update Japanese translations (#27856) --- src/nvim/po/ja.po | 9809 ++++++++++++++++++++++++++++------------------------- 1 file changed, 5274 insertions(+), 4535 deletions(-) (limited to 'src/nvim') diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po index bdf67933f3..315c860307 100644 --- a/src/nvim/po/ja.po +++ b/src/nvim/po/ja.po @@ -1,9 +1,9 @@ -# Japanese translation for Vim +# Japanese translation for Neovim # # Do ":help uganda" in Vim to read copying and usage conditions. # Do ":help credits" in Vim to see a list of people who contributed. # -# Copyright (C) 2001-2018 MURAOKA Taro , +# Copyright (C) 2001-2023 MURAOKA Taro , # vim-jp # # THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. @@ -12,11 +12,11 @@ # msgid "" msgstr "" -"Project-Id-Version: Vim 8.1\n" +"Project-Id-Version: Neovim 0.10\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-07-18 00:43+0900\n" -"PO-Revision-Date: 2017-05-18 00:45+0900\n" -"Last-Translator: MURAOKA Taro \n" +"POT-Creation-Date: 2024-03-14 19:01+0900\n" +"PO-Revision-Date: 2024-03-14 19:46+0900\n" +"Last-Translator: ite-usagi \n" "Language-Team: Japanese \n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -24,1568 +24,1512 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -msgid "E831: bf_key_init() called with empty password" -msgstr "E831: bf_key_init() が空パスワードで呼び出されました" +msgid "(local to window)" +msgstr "(ウィンドウについてローカル)" -msgid "E820: sizeof(uint32_t) != 4" -msgstr "E820: sizeof(uint32_t) != 4" +msgid "(local to buffer)" +msgstr "(バッファについてローカル)" -msgid "E817: Blowfish big/little endian use wrong" -msgstr "E817: Blowfish暗号のビッグ/リトルエンディアンが間違っています" +msgid "(global or local to buffer)" +msgstr "(グローバル/バッファについてローカル)" -msgid "E818: sha256 test failed" -msgstr "E818: sha256のテストに失敗しました" +msgid "" +"\" Each \"set\" line shows the current value of an option (on the left)." +msgstr "\" それぞれの \"set\" 行はオプションの現在の値を(左側に)示しています。" -msgid "E819: Blowfish test failed" -msgstr "E819: Blowfish暗号のテストに失敗しました" +msgid "\" Hit on a \"set\" line to execute it." +msgstr "\" \"set\" 行で を打つとそれが実行されます。" -msgid "[Location List]" -msgstr "[ロケーションリスト]" +msgid "\" A boolean option will be toggled." +msgstr "\" 切替オプションは切り替えられます。" -msgid "[Quickfix List]" -msgstr "[Quickfixリスト]" +msgid "" +"\" For other options you can edit the value before hitting " +"." +msgstr "" +"\" その他のオプションは を打つ前に値を編集することができま" +"す。" -msgid "E855: Autocommands caused command to abort" -msgstr "E855: autocommandがコマンドの停止を引き起こしました" +msgid "\" Hit on a help line to open a help window on this option." +msgstr "" +"\" ヘルプ行で を打つと、このオプションのへルプウィンドウが開きます。" -msgid "E82: Cannot allocate any buffer, exiting..." -msgstr "E82: バッファを1つも作成できないので、終了します..." +msgid "\" Hit on an index line to jump there." +msgstr "\" インデックス行で を打つと、そこにジャンプします。" -msgid "E83: Cannot allocate buffer, using other one..." -msgstr "E83: バッファを作成できないので、他のを使用します..." +msgid "\" Hit on a \"set\" line to refresh it." +msgstr "\" \"set\" 行で を打つと、最新の値が読込まれます。" -msgid "E931: Buffer cannot be registered" -msgstr "E931: バッファを登録できません" +msgid "important" +msgstr "重要" -#, c-format -msgid "E937: Attempt to delete a buffer that is in use: %s" -msgstr "E937: 使用中のバッファを削除しようと試みました: %s" +msgid "behave very Vi compatible (not advisable)" +msgstr "Vi との互換性を非常に高くする (望ましくない)" -msgid "E515: No buffers were unloaded" -msgstr "E515: 解放されたバッファはありません" +msgid "list of flags to specify Vi compatibility" +msgstr "Vi との互換性を指定するフラグのリスト" -msgid "E516: No buffers were deleted" -msgstr "E516: 削除されたバッファはありません" +msgid "paste mode, insert typed text literally" +msgstr "paste モード、タイプされたテキストをそのまま挿入する" -msgid "E517: No buffers were wiped out" -msgstr "E517: 破棄されたバッファはありません" +msgid "list of directories used for runtime files and plugins" +msgstr "ランタイムファイルとプラグインに使われるディレクトリのリスト" -msgid "1 buffer unloaded" -msgstr "1 個のバッファが解放されました" +msgid "list of directories used for plugin packages" +msgstr "プラグインパッケージに使われるディレクトリのリスト" -#, c-format -msgid "%d buffers unloaded" -msgstr "%d 個のバッファが解放されました" +msgid "name of the main help file" +msgstr "メインのヘルプファイルの名前" -msgid "1 buffer deleted" -msgstr "1 個のバッファが削除されました" +msgid "moving around, searching and patterns" +msgstr "移動、検索とパターン" -#, c-format -msgid "%d buffers deleted" -msgstr "%d 個のバッファが削除されました" +msgid "list of flags specifying which commands wrap to another line" +msgstr "どのコマンドが行をまたぐかを指定するフラグのリスト" -msgid "1 buffer wiped out" -msgstr "1 個のバッファが破棄されました" +msgid "" +"many jump commands move the cursor to the first non-blank\n" +"character of a line" +msgstr "多くのジャンプ命令で、カーソルが行内の最初の非空白文字に移動する" -#, c-format -msgid "%d buffers wiped out" -msgstr "%d 個のバッファが破棄されました" +msgid "nroff macro names that separate paragraphs" +msgstr "段落を分けるための nroff マクロの名前" -msgid "E90: Cannot unload last buffer" -msgstr "E90: 最後のバッファは解放できません" +msgid "nroff macro names that separate sections" +msgstr "章を分けるための nroff マクロの名前" -msgid "E84: No modified buffer found" -msgstr "E84: 変更されたバッファはありません" +msgid "list of directory names used for file searching" +msgstr "ファイルの検索に用いられるディレクトリ名のリスト" -msgid "E85: There is no listed buffer" -msgstr "E85: リスト表示されるバッファはありません" +msgid ":cd without argument goes to the home directory" +msgstr "引数無しの :cd でホームディレクトリに移動する" -msgid "E87: Cannot go beyond last buffer" -msgstr "E87: 最後のバッファを越えて移動はできません" +msgid "list of directory names used for :cd" +msgstr ":cd に用いられるディレクトリ名のリスト" -msgid "E88: Cannot go before first buffer" -msgstr "E88: 最初のバッファより前へは移動できません" +msgid "change to directory of file in buffer" +msgstr "バッファ内のファイルのディレクトリに変更する" -#, c-format -msgid "E89: No write since last change for buffer %ld (add ! to override)" -msgstr "E89: バッファ %ld の変更は保存されていません (! で変更を破棄)" +msgid "search commands wrap around the end of the buffer" +msgstr "検索コマンドがバッファの末尾/先頭をまたぐ" -msgid "E948: Job still running (add ! to end the job)" -msgstr "E948: ジョブはまだ実行中です (! を追加でジョブを終了)" +msgid "show match for partly typed search command" +msgstr "部分的に入力された検索コマンドのマッチを表示する" -msgid "E37: No write since last change (add ! to override)" -msgstr "E37: 最後の変更が保存されていません (! を追加で変更を破棄)" +msgid "change the way backslashes are used in search patterns" +msgstr "検索パターン内のバックスラッシュの扱いを変更する" -msgid "E948: Job still running" -msgstr "E948: ジョブはまだ実行中です" +msgid "select the default regexp engine used" +msgstr "既定で使われる正規表現エンジンを選択する" -msgid "E37: No write since last change" -msgstr "E37: 最後の変更が保存されていません" +msgid "ignore case when using a search pattern" +msgstr "検索パターンにおいて大文字と小文字を区別しない" -msgid "W14: Warning: List of file names overflow" -msgstr "W14: 警告: ファイル名のリストが長過ぎます" +msgid "override 'ignorecase' when pattern has upper case characters" +msgstr "検索パターンが大文字を含んでいたら 'ignorecase' を上書きする" -#, c-format -msgid "E92: Buffer %ld not found" -msgstr "E92: バッファ %ld が見つかりません" +msgid "what method to use for changing case of letters" +msgstr "大文字・小文字を変更する際にどの方法を使うか" -#, c-format -msgid "E93: More than one match for %s" -msgstr "E93: %s に複数の該当がありました" +msgid "maximum amount of memory in Kbyte used for pattern matching" +msgstr "パターンマッチングに使う最大メモリ量 (Kbyte)" -#, c-format -msgid "E94: No matching buffer for %s" -msgstr "E94: %s に該当するバッファはありませんでした" +msgid "pattern for a macro definition line" +msgstr "マクロ定義行のためのパターン" -#, c-format -msgid "line %ld" -msgstr "行 %ld" +msgid "pattern for an include-file line" +msgstr "include 行のためのパターン" -msgid "E95: Buffer with this name already exists" -msgstr "E95: この名前のバッファは既にあります" +msgid "expression used to transform an include line to a file name" +msgstr "include 行をファイル名に変換するために使われる式" -msgid " [Modified]" -msgstr " [変更あり]" +msgid "tags" +msgstr "タグ" -msgid "[Not edited]" -msgstr "[未編集]" +msgid "use binary searching in tags files" +msgstr "tags ファイル内で二分探索を使う" -msgid "[New file]" -msgstr "[新ファイル]" +msgid "number of significant characters in a tag name or zero" +msgstr "タグ名で有効になる文字数、あるいはゼロ" -msgid "[Read errors]" -msgstr "[読込エラー]" +msgid "list of file names to search for tags" +msgstr "tags を検索するファイル名のリスト" -msgid "[RO]" -msgstr "[読専]" +msgid "" +"how to handle case when searching in tags files:\n" +"\"followic\" to follow 'ignorecase', \"ignore\" or \"match\"" +msgstr "" +"タグファイル内を検索するときに大文字小文字をどう扱うか:\n" +"'ignorecase' に従うなら \"followic\"、あるいは \"ignore\" か \"match\"" -msgid "[readonly]" -msgstr "[読込専用]" +msgid "file names in a tags file are relative to the tags file" +msgstr "tags ファイル内のファイル名は tags ファイルからの相対パス" -#, c-format -msgid "1 line --%d%%--" -msgstr "1 行 --%d%%--" +msgid "a :tag command will use the tagstack" +msgstr ":tag コマンドはタグスタックを使う" -#, c-format -msgid "%ld lines --%d%%--" -msgstr "%ld 行 --%d%%--" +msgid "when completing tags in Insert mode show more info" +msgstr "挿入モードでタグを補完するときにより多くの情報を表示する" -#, c-format -msgid "line %ld of %ld --%d%%-- col " -msgstr "行 %ld (全体 %ld) --%d%%-- col " +msgid "a function to be used to perform tag searches" +msgstr "タグの検索を実行する際に使われる関数" -msgid "[No Name]" -msgstr "[無名]" +msgid "displaying text" +msgstr "テキストの表示" -msgid "help" -msgstr "ヘルプ" +msgid "number of lines to scroll for CTRL-U and CTRL-D" +msgstr "CTRL-U と CTRL-D でスクロールする行数" -msgid "[Help]" -msgstr "[ヘルプ]" +msgid "scroll by screen line" +msgstr "スクリーン行でスクロールする" -msgid "[Preview]" -msgstr "[プレビュー]" +msgid "number of screen lines to show around the cursor" +msgstr "カーソルの上下に表示されるスクリーン行数" -msgid "All" -msgstr "全て" +msgid "long lines wrap" +msgstr "長い行を折り返して表示する" -msgid "Bot" -msgstr "末尾" +msgid "wrap long lines at a character in 'breakat'" +msgstr "'breakat' の文字で長い行を折り返す" -msgid "Top" -msgstr "先頭" +msgid "preserve indentation in wrapped text" +msgstr "折り返されたテキストでインデントを保持する" -msgid "" -"\n" -"# Buffer list:\n" -msgstr "" -"\n" -"# バッファリスト:\n" +msgid "adjust breakindent behaviour" +msgstr "breakindent の挙動を調整する" -msgid "E382: Cannot write, 'buftype' option is set" -msgstr "E382: 'buftype' オプションが設定されているので書込めません" +msgid "which characters might cause a line break" +msgstr "どの文字のところで行が折り返されるか" -msgid "[Prompt]" -msgstr "[プロンプト]" +msgid "string to put before wrapped screen lines" +msgstr "折り返されたスクリーン行の前に表示される文字列" -msgid "[Scratch]" -msgstr "[下書き]" +msgid "minimal number of columns to scroll horizontally" +msgstr "水平スクロールの最小桁数" + +msgid "minimal number of columns to keep left and right of the cursor" +msgstr "カーソルの左右に表示する最小桁数" msgid "" -"\n" -"--- Signs ---" +"include \"lastline\" to show the last line even if it doesn't fit\n" +"include \"uhex\" to show unprintable characters as a hex number" msgstr "" -"\n" -"--- サイン ---" +"最後の行が収まらない場合でも表示するには \"lastline\" を含めること\n" +"表示できない文字を 16 進数で表示するには \"uhex\" を含めること" -#, c-format -msgid "Signs for %s:" -msgstr "%s のサイン:" +msgid "characters to use for the status line, folds and filler lines" +msgstr "ステータス行、折畳み、フィラー行に使われる文字" -#, c-format -msgid " line=%ld id=%d name=%s" -msgstr " 行=%ld 識別子=%d 名前=%s" +msgid "number of lines used for the command-line" +msgstr "コマンドラインに使われる行数" -msgid "E902: Cannot connect to port" -msgstr "E902: ポートに接続できません" +msgid "width of the display" +msgstr "画面の幅" -msgid "E901: gethostbyname() in channel_open()" -msgstr "E901: channel_open() 内の gethostbyname() が失敗しました" +msgid "number of lines in the display" +msgstr "画面の行数" -msgid "E898: socket() in channel_open()" -msgstr "E898: channel_open() 内の socket() が失敗しました" +msgid "number of lines to scroll for CTRL-F and CTRL-B" +msgstr "CTRL-F と CTRL-B でスクロールする行数" -msgid "E903: received command with non-string argument" -msgstr "E903: 非文字列の引数のコマンドを受信しました" +msgid "don't redraw while executing macros" +msgstr "マクロを実行中に再描画しない" -msgid "E904: last argument for expr/call must be a number" -msgstr "E904: expr/call の最後の引数は数字でなければなりません" +msgid "timeout for 'hlsearch' and :match highlighting in msec" +msgstr "'hlsearch' と :match のハイライト処理のタイムアウト (ミリ秒)" -msgid "E904: third argument for call must be a list" -msgstr "E904: call の3番目の引数はリスト型でなければなりません" +msgid "" +"delay in msec for each char written to the display\n" +"(for debugging)" +msgstr "" +"それぞれの文字が画面に描かれるまでの遅延時間 (ミリ秒)\n" +"(デバッグ用)" -#, c-format -msgid "E905: received unknown command: %s" -msgstr "E905: 未知のコマンドを受信しました: %s" +msgid "show as ^I and end-of-line as $" +msgstr " を ^I として表示し、改行を $ として表示する" -msgid "E906: not an open channel" -msgstr "E906: 開いていないチャネルです" +msgid "list of strings used for list mode" +msgstr "リストモードで使われる文字列のリスト" -#, c-format -msgid "E630: %s(): write while not connected" -msgstr "E630: %s(): 非接続状態で書き込みました" +msgid "show the line number for each line" +msgstr "それぞれの行に行番号を表示する" -#, c-format -msgid "E631: %s(): write failed" -msgstr "E631: %s(): 書き込みに失敗しました" +msgid "show the relative line number for each line" +msgstr "それぞれの行に相対行番号を表示する" -#, c-format -msgid "E917: Cannot use a callback with %s()" -msgstr "E917: %s() にコールバックは使えません" +msgid "number of columns to use for the line number" +msgstr "行番号に使われる桁数" -msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel" -msgstr "" -"E912: raw や nl モードのチャネルに ch_evalexpr()/ch_sendexpr() は使えません" +msgid "controls whether concealable text is hidden" +msgstr "conceal 可能なテキストを隠すかどうかを制御する" -msgid "E920: _io file requires _name to be set" -msgstr "E920: _io ファイルは _name の設定が必要です" +msgid "modes in which text in the cursor line can be concealed" +msgstr "カーソル行のテキストを conceal 表示するモード" -msgid "E915: in_io buffer requires in_buf or in_name to be set" -msgstr "E915: in_io バッファは in_buf か in_name の設定が必要です" +msgid "syntax, highlighting and spelling" +msgstr "構文ハイライトとスペルチェック" -#, c-format -msgid "E918: buffer must be loaded: %s" -msgstr "E918: バッファがロードされてなければなりません: %s" +msgid "\"dark\" or \"light\"; the background color brightness" +msgstr "\"dark\" か \"light\"; 背景色の明るさ" -msgid "E821: File is encrypted with unknown method" -msgstr "E821: ファイルが未知の方法で暗号化されています" +msgid "type of file; triggers the FileType event when set" +msgstr "ファイルのタイプ; セットされると FileType イベントが発生する" -msgid "Warning: Using a weak encryption method; see :help 'cm'" -msgstr "警告: 弱い暗号方法を使っています; :help 'cm' を参照してください" +msgid "name of syntax highlighting used" +msgstr "使用される構文ハイライトの名前" -msgid "Enter encryption key: " -msgstr "暗号化用のキーを入力してください: " +msgid "maximum column to look for syntax items" +msgstr "構文アイテムを検索する最大桁数" -msgid "Enter same key again: " -msgstr "もう一度同じキーを入力してください: " +msgid "which highlighting to use for various occasions" +msgstr "様々な対象に対してどのハイライト表示を使うか" -msgid "Keys don't match!" -msgstr "キーが一致しません" +msgid "highlight all matches for the last used search pattern" +msgstr "最後の検索パターンに対する全てのマッチをハイライト表示する" -msgid "[crypted]" -msgstr "[暗号化]" +msgid "use GUI colors for the terminal" +msgstr "端末で GUI カラーを使う" -#, c-format -msgid "E720: Missing colon in Dictionary: %s" -msgstr "E720: 辞書型にコロンがありません: %s" +msgid "highlight the screen column of the cursor" +msgstr "カーソルのある画面上の桁をハイライト表示する" -#, c-format -msgid "E721: Duplicate key in Dictionary: \"%s\"" -msgstr "E721: 辞書型に重複キーがあります: \"%s\"" +msgid "highlight the screen line of the cursor" +msgstr "カーソルのある画面上の行をハイライト表示する" -#, c-format -msgid "E722: Missing comma in Dictionary: %s" -msgstr "E722: 辞書型にカンマがありません: %s" +msgid "specifies which area 'cursorline' highlights" +msgstr "'cursorline' がどの領域をハイライト表示するか指定する" -#, c-format -msgid "E723: Missing end of Dictionary '}': %s" -msgstr "E723: 辞書型の最後に '}' がありません: %s" +msgid "columns to highlight" +msgstr "ハイライト表示する桁" -msgid "extend() argument" -msgstr "extend() の引数" +msgid "highlight spelling mistakes" +msgstr "スペルミスをハイライト表示する" -#, c-format -msgid "E737: Key already exists: %s" -msgstr "E737: キーは既に存在します: %s" +msgid "list of accepted languages" +msgstr "受け付ける言語のリスト" -#, c-format -msgid "E96: Cannot diff more than %ld buffers" -msgstr "E96: %ld 以上のバッファはdiffできません" +msgid "file that \"zg\" adds good words to" +msgstr "\"zg\" で正しい単語を追加するファイル" -msgid "E810: Cannot read or write temp files" -msgstr "E810: 一時ファイルの読込もしくは書込ができません" +msgid "pattern to locate the end of a sentence" +msgstr "文の末尾を見つけるのに使うパターン" -msgid "E97: Cannot create diffs" -msgstr "E97: 差分を作成できません" +msgid "flags to change how spell checking works" +msgstr "どのようにスペルチェックが動作するかを変更するフラグ" -msgid "Patch file" -msgstr "パッチファイル" +msgid "methods used to suggest corrections" +msgstr "修正を提案する際に使われる方法" -msgid "E816: Cannot read patch output" -msgstr "E816: patchの出力を読込めません" +msgid "amount of memory used by :mkspell before compressing" +msgstr "圧縮の前に :mkspell で使われるメモリ量" -msgid "E98: Cannot read diff output" -msgstr "E98: diffの出力を読込めません" +msgid "multiple windows" +msgstr "複数ウィンドウ" -msgid "E99: Current buffer is not in diff mode" -msgstr "E99: 現在のバッファは差分モードではありません" +msgid "0, 1, 2 or 3; when to use a status line for the last window" +msgstr "0, 1, 2 または 3; 最後のウィンドウのステータス行がいつ使われるか" -msgid "E793: No other buffer in diff mode is modifiable" -msgstr "E793: 差分モードである他のバッファは変更できません" +msgid "custom format for the status column" +msgstr "ステータス列に使われる書式" -msgid "E100: No other buffer in diff mode" -msgstr "E100: 差分モードである他のバッファはありません" +msgid "alternate format to be used for a status line" +msgstr "ステータス行に使われる書式" -msgid "E101: More than two buffers in diff mode, don't know which one to use" -msgstr "" -"E101: 差分モードのバッファが2個以上あるので、どれを使うか特定できません" +msgid "make all windows the same size when adding/removing windows" +msgstr "ウィンドウを追加/削除するときに全ウィンドウのサイズを等しくする" -#, c-format -msgid "E102: Can't find buffer \"%s\"" -msgstr "E102: バッファ \"%s\" が見つかりません" +msgid "in which direction 'equalalways' works: \"ver\", \"hor\" or \"both\"" +msgstr "どの方向に 'equalalways' が働くか: \"ver\", \"hor\" または \"both\"" -#, c-format -msgid "E103: Buffer \"%s\" is not in diff mode" -msgstr "E103: バッファ \"%s\" は差分モードではありません" +msgid "minimal number of lines used for the current window" +msgstr "現在のウィンドウに使われる最小行数" -msgid "E787: Buffer changed unexpectedly" -msgstr "E787: 予期せずバッファが変更変更されました" +msgid "minimal number of lines used for any window" +msgstr "任意のウィンドウに使われる最小行数" -msgid "E104: Escape not allowed in digraph" -msgstr "E104: 合字にEscapeは使用できません" +msgid "keep window focused on a single buffer" +msgstr "ウィンドウを単一のバッファにフォーカスする" -msgid "E544: Keymap file not found" -msgstr "E544: キーマップファイルが見つかりません" +msgid "keep the height of the window" +msgstr "ウィンドウの高さを保つ" -msgid "E105: Using :loadkeymap not in a sourced file" -msgstr "E105: :source で取込むファイル以外では :loadkeymap を使えません" +msgid "keep the width of the window" +msgstr "ウィンドウの幅を保つ" -msgid "E791: Empty keymap entry" -msgstr "E791: 空のキーマップエントリ" +msgid "minimal number of columns used for the current window" +msgstr "現在のウィンドウに使われる最小桁数" -msgid " Keyword completion (^N^P)" -msgstr " キーワード補完 (^N^P)" +msgid "minimal number of columns used for any window" +msgstr "任意のウィンドウに使われる最小桁数" -msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)" -msgstr " ^X モード (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)" +msgid "initial height of the help window" +msgstr "ヘルプウィンドウの開始時の高さ" -msgid " Whole line completion (^L^N^P)" -msgstr " 行(全体)補完 (^L^N^P)" +msgid "default height for the preview window" +msgstr "プレビューウィンドウの既定の高さ" -msgid " File name completion (^F^N^P)" -msgstr " ファイル名補完 (^F^N^P)" +msgid "identifies the preview window" +msgstr "プレビューウィンドウを識別する" -msgid " Tag completion (^]^N^P)" -msgstr " タグ補完 (^]^N^P)" +msgid "don't unload a buffer when no longer shown in a window" +msgstr "バッファがウィンドウに表示されていないときにアンロードしない" -msgid " Path pattern completion (^N^P)" -msgstr " パスパターン補完 (^N^P)" +msgid "" +"\"useopen\" and/or \"split\"; which window to use when jumping\n" +"to a buffer" +msgstr "" +"\"useopen\" かつ/または \"split\"; バッファにジャンプするときに\n" +"どのウィンドウを使うか" -msgid " Definition completion (^D^N^P)" -msgstr " 定義補完 (^D^N^P)" +msgid "a new window is put below the current one" +msgstr "新しいウィンドウは現在のものの下に置かれる" -msgid " Dictionary completion (^K^N^P)" -msgstr " 辞書補完 (^K^N^P)" +msgid "determines scroll behavior for split windows" +msgstr "ウィンドウ分割のスクロール動作を決める" -msgid " Thesaurus completion (^T^N^P)" -msgstr " シソーラス補完 (^T^N^P)" +msgid "a new window is put right of the current one" +msgstr "新しいウィンドウは現在のものの右に置かれる" -msgid " Command-line completion (^V^N^P)" -msgstr " コマンドライン補完 (^V^N^P)" +msgid "this window scrolls together with other bound windows" +msgstr "このウィンドウは他の同調ウィンドウと一緒にスクロールする" -msgid " User defined completion (^U^N^P)" -msgstr " ユーザー定義補完 (^U^N^P)" +msgid "\"ver\", \"hor\" and/or \"jump\"; list of options for 'scrollbind'" +msgstr "" +"\"ver\", \"hor\" かつ/または \"jump\"; 'scrollbind' のオプションの\n" +"リスト" -msgid " Omni completion (^O^N^P)" -msgstr " オムニ補完 (^O^N^P)" +msgid "this window's cursor moves together with other bound windows" +msgstr "このウィンドウのカーソルは他の同調ウィンドウと一緒に動く" -msgid " Spelling suggestion (s^N^P)" -msgstr " 綴り修正候補 (s^N^P)" +msgid "size of a terminal window" +msgstr "端末ウィンドウのサイズ" -msgid " Keyword Local completion (^N^P)" -msgstr " 局所キーワード補完 (^N^P)" +msgid "key that precedes Vim commands in a terminal window" +msgstr "端末ウィンドウで Vim のコマンドの前に入力するキー" -msgid "Hit end of paragraph" -msgstr "段落の最後にヒット" +msgid "multiple tab pages" +msgstr "複数タブページ" -msgid "E839: Completion function changed window" -msgstr "E839: 補間関数がウィンドウを変更しました" +msgid "0, 1 or 2; when to use a tab pages line" +msgstr "0, 1 または 2; タブページ行をいつ使うか" -msgid "E840: Completion function deleted text" -msgstr "E840: 補完関数がテキストを削除しました" +msgid "maximum number of tab pages to open for -p and \"tab all\"" +msgstr "-p と \"tab all\" で開かれるタブページの最大数" -msgid "'dictionary' option is empty" -msgstr "'dictionary' オプションが空です" +msgid "custom tab pages line" +msgstr "カスタムのタブページ行" -msgid "'thesaurus' option is empty" -msgstr "'thesaurus' オプションが空です" +msgid "custom tab page label for the GUI" +msgstr "カスタムの GUI のタブページラベル" -#, c-format -msgid "Scanning dictionary: %s" -msgstr "辞書をスキャン中: %s" +msgid "custom tab page tooltip for the GUI" +msgstr "カスタムの GUI のタブページツールチップ" -msgid " (insert) Scroll (^E/^Y)" -msgstr " (挿入) スクロール(^E/^Y)" +msgid "terminal" +msgstr "端末" -msgid " (replace) Scroll (^E/^Y)" -msgstr " (置換) スクロール (^E/^Y)" +msgid "minimal number of lines to scroll at a time" +msgstr "一度にスクロールする最小行数" -#, c-format -msgid "Scanning: %s" -msgstr "スキャン中: %s" +msgid "specifies what the cursor looks like in different modes" +msgstr "それぞれのモード内でのカーソルの外観を指定" -msgid "Scanning tags." -msgstr "タグをスキャン中." +msgid "show info in the window title" +msgstr "ウィンドウタイトルに情報を表示" -msgid "match in file" -msgstr "ファイル内のマッチ" +msgid "percentage of 'columns' used for the window title" +msgstr "ウィンドウタイトルに使われる 'columns' の割合 (パーセント単位)" -msgid " Adding" -msgstr " 追加中" +msgid "when not empty, string to be used for the window title" +msgstr "空でないとき、ウィンドウタイトルに使われる文字列" -msgid "-- Searching..." -msgstr "-- 検索中..." +msgid "string to restore the title to when exiting Vim" +msgstr "Vim の終了時にタイトルに復元する文字列" -msgid "Back at original" -msgstr "始めに戻る" +msgid "set the text of the icon for this window" +msgstr "このウィンドウのアイコンのテキストを設定" -msgid "Word from other line" -msgstr "他の行の単語" +msgid "when not empty, text for the icon of this window" +msgstr "空でないとき、このウィンドウのアイコンに使われるテキスト" -msgid "The only match" -msgstr "唯一の該当" +msgid "using the mouse" +msgstr "マウスの使用" -#, c-format -msgid "match %d of %d" -msgstr "%d 番目の該当 (全該当 %d 個中)" +msgid "list of flags for using the mouse" +msgstr "マウスを使うためのフラグのリスト" -#, c-format -msgid "match %d" -msgstr "%d 番目の該当" +msgid "the window with the mouse pointer becomes the current one" +msgstr "マウスポインタのあるウィンドウがアクティブになる" -msgid "E18: Unexpected characters in :let" -msgstr "E18: 予期せぬ文字が :let にありました" +msgid "hide the mouse pointer while typing" +msgstr "文字の入力中にマウスポインタを隠す" -msgid "E111: Missing ']'" -msgstr "E111: ']' が見つかりません" +msgid "" +"\"extend\", \"popup\" or \"popup_setpos\"; what the right\n" +"mouse button is used for" +msgstr "" +"\"extend\", \"popup\" あるいは \"popup_setpos\"; マウスの右ボタンを\n" +"何に使うか" -msgid "E719: Cannot use [:] with a Dictionary" -msgstr "E719: [:] を辞書型と組み合わせては使えません" +msgid "maximum time in msec to recognize a double-click" +msgstr "ダブルクリックとして認識する最大時間 (ミリ秒)" -msgid "E806: using Float as a String" -msgstr "E806: 浮動小数点数を文字列として扱っています" +msgid "what the mouse pointer looks like in different modes" +msgstr "それぞれのモード内でのマウスポインタの外観を指定" -msgid "E687: Less targets than List items" -msgstr "E687: ターゲットがリスト型内の要素よりも少ないです" +msgid "GUI" +msgstr "GUI" -msgid "E688: More targets than List items" -msgstr "E688: ターゲットがリスト型内の要素よりも多いです" +msgid "list of font names to be used in the GUI" +msgstr "GUI で使われるフォント名のリスト" -msgid "Double ; in list of variables" -msgstr "リスト型の値に2つ以上の ; が検出されました" +msgid "pair of fonts to be used, for multibyte editing" +msgstr "マルチバイトの編集で使われるフォントのペア" -#, c-format -msgid "E738: Can't list variables for %s" -msgstr "E738: %s の値を一覧表示できません" +msgid "list of font names to be used for double-wide characters" +msgstr "全角文字に使われるフォント名のリスト" -msgid "E689: Can only index a List or Dictionary" -msgstr "E689: リスト型と辞書型以外はインデックス指定できません" +msgid "list of flags that specify how the GUI works" +msgstr "GUI がどう動くかを指定するフラグのリスト" -msgid "E708: [:] must come last" -msgstr "E708: [:] は最後でなければいけません" +msgid "\"icons\", \"text\" and/or \"tooltips\"; how to show the toolbar" +msgstr "" +"\"icons\", \"text\" かつ/あるいは \"tooltips\"; どのように\n" +"ツールバーを表示するか" -msgid "E709: [:] requires a List value" -msgstr "E709: [:] にはリスト型の値が必要です" +msgid "size of toolbar icons" +msgstr "ツールバーアイコンのサイズ" -msgid "E710: List value has more items than target" -msgstr "E710: リスト型変数にターゲットよりも多い要素があります" +msgid "" +"\"last\", \"buffer\" or \"current\": which directory used for the file " +"browser" +msgstr "" +"\"last\", \"buffer\" あるいは \"current\": ファイルブラウザでどの\n" +"ディレクトリを使うか" -msgid "E711: List value has not enough items" -msgstr "E711: リスト型変数に十分な数の要素がありません" +msgid "language to be used for the menus" +msgstr "メニューで使われる言語" -msgid "E690: Missing \"in\" after :for" -msgstr "E690: :for の後に \"in\" がありません" +msgid "maximum number of items in one menu" +msgstr "1 個のメニューの最大項目数" -#, c-format -msgid "E108: No such variable: \"%s\"" -msgstr "E108: その変数はありません: \"%s\"" +msgid "\"no\", \"yes\" or \"menu\"; how to use the ALT key" +msgstr "\"no\", \"yes\" または \"menu\"; ALT キーをどう使うか" -#, c-format -msgid "E940: Cannot lock or unlock variable %s" -msgstr "E940: 変数 %s はロックまたはアンロックできません" +msgid "number of pixel lines to use between characters" +msgstr "行間の幅のピクセル数" -msgid "E743: variable nested too deep for (un)lock" -msgstr "E743: (アン)ロックするには変数の入れ子が深過ぎます" +msgid "delay in milliseconds before a balloon may pop up" +msgstr "バルーン表示が出るまでの時間 (ミリ秒)" -msgid "E109: Missing ':' after '?'" -msgstr "E109: '?' の後に ':' がありません" +msgid "use balloon evaluation in the GUI" +msgstr "GUI でバルーン評価を使う" -msgid "E804: Cannot use '%' with Float" -msgstr "E804: '%' を浮動小数点数と組み合わせては使えません" +msgid "use balloon evaluation in the terminal" +msgstr "端末でバルーン評価を使う" -msgid "E110: Missing ')'" -msgstr "E110: ')' が見つかりません" +msgid "expression to show in balloon eval" +msgstr "バルーン評価に表示する式" -msgid "E260: Missing name after ->" -msgstr "E260: -> の後に名前がありません" +msgid "messages and info" +msgstr "メッセージと情報" -msgid "E695: Cannot index a Funcref" -msgstr "E695: 関数参照型はインデックスできません" +msgid "add 's' flag in 'shortmess' (don't show search message)" +msgstr "'s' フラグを 'shortmess' に追加 (検索メッセージを表示しない)" -msgid "E909: Cannot index a special variable" -msgstr "E909: 特殊変数はインデックスできません" +msgid "list of flags to make messages shorter" +msgstr "メッセージを短くするためのフラグのリスト" -#, c-format -msgid "E112: Option name missing: %s" -msgstr "E112: オプション名がありません: %s" +msgid "show (partial) command keys in location given by 'showcmdloc'" +msgstr "コマンド (の一部) を 'showcmdloc' で指定された場所に表示" -#, c-format -msgid "E113: Unknown option: %s" -msgstr "E113: 未知のオプションです: %s" +msgid "location where to show the (partial) command keys for 'showcmd'" +msgstr "'showcmd' でコマンド (の一部) を表示する場所" -#, c-format -msgid "E114: Missing quote: %s" -msgstr "E114: 引用符 (\") がありません: %s" +msgid "display the current mode in the status line" +msgstr "現在のモードをステータス行に表示" -#, c-format -msgid "E115: Missing quote: %s" -msgstr "E115: 引用符 (') がありません: %s" +msgid "show cursor position below each window" +msgstr "カーソル位置をそれぞれのウィンドウの下に表示" -msgid "Not enough memory to set references, garbage collection aborted!" -msgstr "" -"ガーベッジコレクションを中止しました! 参照を作成するのにメモリが不足しました" +msgid "alternate format to be used for the ruler" +msgstr "ルーラーに使われる代替書式" -msgid "E724: variable nested too deep for displaying" -msgstr "E724: 表示するには変数の入れ子が深過ぎます" +msgid "threshold for reporting number of changed lines" +msgstr "変更された行の数の報告が出る閾値" -msgid "E805: Using a Float as a Number" -msgstr "E805: 浮動小数点数を数値として扱っています" +msgid "the higher the more messages are given" +msgstr "値が大きいほど詳細なメッセージが表示される" -msgid "E703: Using a Funcref as a Number" -msgstr "E703: 関数参照型を数値として扱っています" +msgid "file to write messages in" +msgstr "メッセージを書込むファイル" -msgid "E745: Using a List as a Number" -msgstr "E745: リスト型を数値として扱っています" +msgid "pause listings when the screen is full" +msgstr "画面が一杯になったとき一覧表示を一時停止" -msgid "E728: Using a Dictionary as a Number" -msgstr "E728: 辞書型を数値として扱っています" +msgid "start a dialog when a command fails" +msgstr "コマンドが失敗したときにダイアログを開く" -msgid "E910: Using a Job as a Number" -msgstr "E910: ジョブを数値として扱っています" +msgid "ring the bell for error messages" +msgstr "エラーメッセージでベルを鳴らす" -msgid "E913: Using a Channel as a Number" -msgstr "E913: チャネルを数値として扱っています" +msgid "use a visual bell instead of beeping" +msgstr "ビープ音の代わりにビジュアルベルを使う" -msgid "E891: Using a Funcref as a Float" -msgstr "E891: 関数参照型を浮動小数点数として扱っています" +msgid "do not ring the bell for these reasons" +msgstr "これらの理由にはベルを鳴らさない" -msgid "E892: Using a String as a Float" -msgstr "E892: 文字列を浮動小数点数として扱っています" +msgid "list of preferred languages for finding help" +msgstr "ヘルプを見つける際の望ましい言語のリスト" -msgid "E893: Using a List as a Float" -msgstr "E893: リスト型を浮動小数点数として扱っています" +msgid "selecting text" +msgstr "テキスト選択" -msgid "E894: Using a Dictionary as a Float" -msgstr "E894: 辞書型を浮動小数点数として扱っています" +msgid "\"old\", \"inclusive\" or \"exclusive\"; how selecting text behaves" +msgstr "" +"\"old\", \"inclusive\" または \"exclusive\"; テキスト選択がどう振舞うか" -msgid "E907: Using a special value as a Float" -msgstr "E907: 特殊値を浮動小数点数として扱っています" +msgid "" +"\"mouse\", \"key\" and/or \"cmd\"; when to start Select mode\n" +"instead of Visual mode" +msgstr "" +"\"mouse\", \"key\" かつ/または \"cmd\"; いつビジュアルモードでは\n" +"なく選択モードを開始するか" -msgid "E911: Using a Job as a Float" -msgstr "E911: ジョブを浮動小数点数として扱っています" +msgid "" +"\"unnamed\" to use the * register like unnamed register\n" +"\"autoselect\" to always put selected text on the clipboard" +msgstr "" +"\"unnamed\"; * レジスタを無名レジスタと同じように使う\n" +"\"autoselect\"; 常に選択されたテキストをクリップボードにコピー" -msgid "E914: Using a Channel as a Float" -msgstr "E914: チャネルを浮動小数点数として扱っています" +msgid "\"startsel\" and/or \"stopsel\"; what special keys can do" +msgstr "\"startsel\" かつ/または \"stopsel\"; 特別なキーが何をするか" -msgid "E729: using Funcref as a String" -msgstr "E729: 関数参照型を文字列として扱っています" +msgid "editing text" +msgstr "テキスト編集" -msgid "E730: using List as a String" -msgstr "E730: リスト型を文字列として扱っています" +msgid "maximum number of changes that can be undone" +msgstr "アンドゥ可能な変更の最大値" -msgid "E731: using Dictionary as a String" -msgstr "E731: 辞書型を文字列として扱っています" +msgid "automatically save and restore undo history" +msgstr "アンドゥ履歴を自動で保存・復元" -msgid "E908: using an invalid value as a String" -msgstr "E908: 無効な値を文字列として扱っています" +msgid "list of directories for undo files" +msgstr "アンドゥファイル用のディレクトリのリスト" -#, c-format -msgid "E795: Cannot delete variable %s" -msgstr "E795: 変数 %s を削除できません" +msgid "maximum number lines to save for undo on a buffer reload" +msgstr "バッファのリロード時にアンドゥのために保存する最大行数" -#, c-format -msgid "E704: Funcref variable name must start with a capital: %s" -msgstr "E704: 関数参照型変数名は大文字で始まらなければなりません: %s" +msgid "changes have been made and not written to a file" +msgstr "変更が行われたがファイルに書込まれていない" -#, c-format -msgid "E705: Variable name conflicts with existing function: %s" -msgstr "E705: 変数名が既存の関数名と衝突します: %s" +msgid "buffer is not to be written" +msgstr "バッファは書込まれない" -#, c-format -msgid "E741: Value is locked: %s" -msgstr "E741: 値がロックされています: %s" +msgid "changes to the text are possible" +msgstr "テキストの変更が可能" -msgid "Unknown" -msgstr "不明" +msgid "line length above which to break a line" +msgstr "これより長い行は改行される" -#, c-format -msgid "E742: Cannot change value of %s" -msgstr "E742: %s の値を変更できません" +msgid "margin from the right in which to break a line" +msgstr "改行する際の右からのマージン" -msgid "E698: variable nested too deep for making a copy" -msgstr "E698: コピーを取るには変数の入れ子が深過ぎます" +msgid "specifies what , CTRL-W, etc. can do in Insert mode" +msgstr "挿入モードで , CTRL-W 等が何をできるかを指定" -msgid "" -"\n" -"# global variables:\n" -msgstr "" -"\n" -"# グローバル変数:\n" +msgid "definition of what comment lines look like" +msgstr "コメント行がどうなっているかの定義" -msgid "" -"\n" -"\tLast set from " -msgstr "" -"\n" -"\t最後にセットしたスクリプト: " +msgid "list of flags that tell how automatic formatting works" +msgstr "自動整形がどのように動作するかを決めるフラグのリスト" -msgid "E691: Can only compare List with List" -msgstr "E691: リスト型はリスト型としか比較できません" +msgid "pattern to recognize a numbered list" +msgstr "数字付きの箇条書きを認識するパターン" -msgid "E692: Invalid operation for List" -msgstr "E692: リスト型には無効な操作です" +msgid "expression used for \"gq\" to format lines" +msgstr "\"gq\" で行を整形するときに使われる式" -msgid "E735: Can only compare Dictionary with Dictionary" -msgstr "E735: 辞書型は辞書型としか比較できません" +msgid "specifies how Insert mode completion works for CTRL-N and CTRL-P" +msgstr "挿入モード補完が CTRL-N と CTRL-P でどう動作するかを指定" -msgid "E736: Invalid operation for Dictionary" -msgstr "E736: 辞書型には無効な操作です" +msgid "whether to use a popup menu for Insert mode completion" +msgstr "挿入モード補完でポップアップメニューを使うかどうか" -msgid "E694: Invalid operation for Funcrefs" -msgstr "E694: 関数参照型には無効な操作です" +msgid "maximum height of the popup menu" +msgstr "ポップアップメニューの最大高" -#, c-format -msgid "E686: Argument of %s must be a List" -msgstr "E686: %s の引数はリスト型でなければなりません" +msgid "minimum width of the popup menu" +msgstr "ポップアップメニューの最大幅" -msgid "E808: Number or Float required" -msgstr "E808: 数値か浮動小数点数が必要です" +msgid "user defined function for Insert mode completion" +msgstr "挿入モード補完用のユーザー定義関数" -msgid "E785: complete() can only be used in Insert mode" -msgstr "E785: complete() は挿入モードでしか利用できません" +msgid "function for filetype-specific Insert mode completion" +msgstr "ファイルタイプ固有の挿入モード補完用関数" -msgid "&Ok" -msgstr "&Ok" +msgid "list of dictionary files for keyword completion" +msgstr "キーワード補完用の辞書ファイルのリスト" -#, c-format -msgid "E700: Unknown function: %s" -msgstr "E700: 未知の関数です: %s" +msgid "list of thesaurus files for keyword completion" +msgstr "キーワード補完用の同義語ファイルのリスト" -msgid "E922: expected a dict" -msgstr "E922: 辞書が期待されています" +msgid "function used for thesaurus completion" +msgstr "同義語補完で使われる関数" -msgid "E923: Second argument of function() must be a list or a dict" -msgstr "E923: function() の第 2 引数はリスト型または辞書型でなければなりません" +msgid "adjust case of a keyword completion match" +msgstr "キーワード補完のマッチで大文字小文字を調整" -msgid "" -"&OK\n" -"&Cancel" -msgstr "" -"決定(&O)\n" -"キャンセル(&C)" +msgid "enable entering digraphs with c1 c2" +msgstr "c1 c2 でダイグラフを入力可能にする" -msgid "called inputrestore() more often than inputsave()" -msgstr "inputrestore() が inputsave() よりも多く呼ばれました" +msgid "the \"~\" command behaves like an operator" +msgstr "\"~\" コマンドがオペレータのようにふるまう" -msgid "E786: Range not allowed" -msgstr "E786: 範囲指定は許可されていません" +msgid "function called for the \"g@\" operator" +msgstr "\"g@\" オペレータで呼ばれる関数" -msgid "E701: Invalid type for len()" -msgstr "E701: len() には無効な型です" +msgid "when inserting a bracket, briefly jump to its match" +msgstr "括弧を入力したときに、対応する括弧にわずかの間ジャンプ" -#, c-format -msgid "E798: ID is reserved for \":match\": %ld" -msgstr "E798: ID は \":match\" のために予約されています: %ld" +msgid "tenth of a second to show a match for 'showmatch'" +msgstr "'showmatch' で対応を表示する時間 (0.1秒単位)" -msgid "E726: Stride is zero" -msgstr "E726: ストライド(前進量)が 0 です" +msgid "list of pairs that match for the \"%\" command" +msgstr "\"%\" コマンドでマッチするペアのリスト" -msgid "E727: Start past end" -msgstr "E727: 開始位置が終了位置を越えました" +msgid "use two spaces after '.' when joining a line" +msgstr "行を連結するときに '.' の後に空白を 2 個入れる" -msgid "" -msgstr "<空>" +msgid "" +"\"alpha\", \"octal\", \"hex\", \"bin\" and/or \"unsigned\"; number formats\n" +"recognized for CTRL-A and CTRL-X commands" +msgstr "" +"\"alpha\", \"octal\", \"hex\", \"bin\" かつ/または \"unsigned\";\n" +"CTRL-A と CTRL-X コマンドで認識する数字の書式" -msgid "E240: No connection to the X server" -msgstr "E240: X サーバーへの接続がありません" +msgid "tabs and indenting" +msgstr "タブとインデント" -#, c-format -msgid "E241: Unable to send to %s" -msgstr "E241: %s へ送ることができません" +msgid "number of spaces a in the text stands for" +msgstr "1 つの に対応する空白の数" -msgid "E277: Unable to read a server reply" -msgstr "E277: サーバーの応答がありません" +msgid "number of spaces used for each step of (auto)indent" +msgstr "(自動)インデントの各段階に使われる空白の数" -msgid "E941: already started a server" -msgstr "E941: サーバーはすでに開始しています" +msgid "list of number of spaces a tab counts for" +msgstr "1 つのタブが相当する空白の数のリスト" -msgid "E942: +clientserver feature not available" -msgstr "E942: +clientserver 機能が無効になっています" +msgid "list of number of spaces a soft tabsstop counts for" +msgstr "1 つのソフトタブストップに相当する空白の数のリスト" -# Added at 10-Mar-2004. -msgid "E655: Too many symbolic links (cycle?)" -msgstr "E655: シンボリックリンクが多過ぎます (循環している可能性があります)" +msgid "a in an indent inserts 'shiftwidth' spaces" +msgstr "インデント内での は 'shiftwidth' 個の空白を挿入" -msgid "E258: Unable to send to client" -msgstr "E258: クライアントへ送ることができません" +msgid "if non-zero, number of spaces to insert for a " +msgstr "0 でないとき、1 つの で挿入される空白の数" -msgid "(Invalid)" -msgstr "(無効)" +msgid "round to 'shiftwidth' for \"<<\" and \">>\"" +msgstr "\"<<\" と \">>\" で 'shiftwidth' に丸める" -#, c-format -msgid "E935: invalid submatch number: %d" -msgstr "E935: 無効なサブマッチ番号: %d" +msgid "expand to spaces in Insert mode" +msgstr "挿入モードで を空白に展開" -msgid "E921: Invalid callback argument" -msgstr "E921: 無効なコールバック引数です" +msgid "automatically set the indent of a new line" +msgstr "新しい行のインデントを自動的に設定" -#, c-format -msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s" -msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o, ダイグラフ %s" +msgid "do clever autoindenting" +msgstr "賢い自動インデントを行う" -#, c-format -msgid "<%s>%s%s %d, Hex %02x, Octal %03o" -msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o" +msgid "enable specific indenting for C code" +msgstr "C コードに特有のインデントを有効にする" -#, c-format -msgid "> %d, Hex %04x, Oct %o, Digr %s" -msgstr "> %d, 16進数 %04x, 8進数 %o, ダイグラフ %s" +msgid "options for C-indenting" +msgstr "C インデント処理用のオプション" -#, c-format -msgid "> %d, Hex %08x, Oct %o, Digr %s" -msgstr "> %d, 16進数 %08x, 8進数 %o, ダイグラフ %s" +msgid "keys that trigger C-indenting in Insert mode" +msgstr "挿入モードで C インデント処理を引き起こすキー" -#, c-format -msgid "> %d, Hex %04x, Octal %o" -msgstr "> %d, 16進数 %04x, 8進数 %o" +msgid "list of words that cause more C-indent" +msgstr "さらなる C インデントを発生させる単語のリスト" -#, c-format -msgid "> %d, Hex %08x, Octal %o" -msgstr "> %d, 16進数 %08x, 8進数 %o" +msgid "list of scope declaration names used by cino-g" +msgstr "cino-g に用いられるスコープ宣言名のリスト" -msgid "E134: Move lines into themselves" -msgstr "E134: 行をそれ自身には移動できません" +msgid "expression used to obtain the indent of a line" +msgstr "行のインデントを得るために使われる式" -msgid "1 line moved" -msgstr "1 行が移動されました" +msgid "keys that trigger indenting with 'indentexpr' in Insert mode" +msgstr "挿入モードで 'indentexpr' によるインデントを引き起こすキー" -#, c-format -msgid "%ld lines moved" -msgstr "%ld 行が移動されました" +msgid "copy whitespace for indenting from previous line" +msgstr "前の行からインデントの空白をコピー" -#, c-format -msgid "%ld lines filtered" -msgstr "%ld 行がフィルタ処理されました" +msgid "preserve kind of whitespace when changing indent" +msgstr "インデントを変更するときに空白の種類を保持" -msgid "E135: *Filter* Autocommands must not change current buffer" -msgstr "E135: *フィルタ* autocommandは現在のバッファを変更してはいけません" +msgid "enable lisp mode" +msgstr "lisp モードを有効化" -msgid "[No write since last change]\n" -msgstr "[最後の変更が保存されていません]\n" +msgid "words that change how lisp indenting works" +msgstr "lisp インデント処理の動作を変更する単語のリスト" -msgid "Save As" -msgstr "別名で保存" +msgid "options for Lisp indenting" +msgstr "list インデント処理用のオプション" -msgid "Write partial file?" -msgstr "ファイルを部分的に保存しますか?" +msgid "folding" +msgstr "折畳み" -msgid "E140: Use ! to write partial buffer" -msgstr "E140: バッファを部分的に保存するには ! を使ってください" +msgid "unset to display all folds open" +msgstr "全ての折畳みを開いて表示するにはオフにする" -#, c-format -msgid "Overwrite existing file \"%s\"?" -msgstr "既存のファイル \"%s\" を上書きしますか?" +msgid "folds with a level higher than this number will be closed" +msgstr "この数値よりもレベルの高い折畳みは閉じられる" -#, c-format -msgid "Swap file \"%s\" exists, overwrite anyway?" -msgstr "スワップファイル \"%s\" が存在します。上書きを強制しますか?" +msgid "value for 'foldlevel' when starting to edit a file" +msgstr "ファイルを編集開始する際の 'foldlevel' の値" -#, c-format -msgid "E768: Swap file exists: %s (:silent! overrides)" -msgstr "E768: スワップファイルが存在します: %s (:silent! を追加で上書)" +msgid "width of the column used to indicate folds" +msgstr "折畳みを表示するのに使われる列幅" -#, c-format -msgid "E141: No file name for buffer %ld" -msgstr "E141: バッファ %ld には名前がありません" +msgid "expression used to display the text of a closed fold" +msgstr "閉じられた折畳みのテキストを表示するのに使われる式" -msgid "E142: File not written: Writing is disabled by 'write' option" -msgstr "E142: ファイルは保存されませんでした: 'write' オプションにより無効です" +msgid "set to \"all\" to close a fold when the cursor leaves it" +msgstr "カーソルが折畳みを離れたときに閉じるには \"all\" に設定" -#, c-format -msgid "" -"'readonly' option is set for \"%s\".\n" -"Do you wish to write anyway?" -msgstr "" -"\"%s\" には 'readonly' オプションが設定されています.\n" -"上書き強制をしますか?" +msgid "specifies for which commands a fold will be opened" +msgstr "どのコマンドが折畳みを開くかを指定" + +msgid "minimum number of screen lines for a fold to be closed" +msgstr "折畳みが閉じられる画面上の最小行数" + +msgid "template for comments; used to put the marker in" +msgstr "コメント用のテンプレート; マーカーを中に置くために使われる" -#, c-format msgid "" -"File permissions of \"%s\" are read-only.\n" -"It may still be possible to write it.\n" -"Do you wish to try?" +"folding type: \"manual\", \"indent\", \"expr\", \"marker\",\n" +"\"syntax\" or \"diff\"" msgstr "" -"ファイル \"%s\" のパーミッションが読込専用です.\n" -"それでも恐らく書き込むことは可能です.\n" -"継続しますか?" +"折畳みの種類: \"manual\", \"indent\", \"expr\", \"marker\",\n" +"\"syntax\" または \"diff\"" -#, c-format -msgid "E505: \"%s\" is read-only (add ! to override)" -msgstr "E505: \"%s\" は読込専用です (強制書込には ! を追加)" +msgid "expression used when 'foldmethod' is \"expr\"" +msgstr "'foldmethod' が \"expr\" の際に使われる式" -msgid "Edit File" -msgstr "ファイルを編集" +msgid "used to ignore lines when 'foldmethod' is \"indent\"" +msgstr "'foldmethod' が \"indent\" の際に行を無視するために使われる" -#, c-format -msgid "E143: Autocommands unexpectedly deleted new buffer %s" -msgstr "E143: autocommandが予期せず新しいバッファ %s を削除しました" +msgid "markers used when 'foldmethod' is \"marker\"" +msgstr "'foldmethod' が \"marker\" の際に使われるマーカー" -msgid "E144: non-numeric argument to :z" -msgstr "E144: 数ではない引数が :z に渡されました" +msgid "maximum fold depth for when 'foldmethod' is \"indent\" or \"syntax\"" +msgstr "" +"'foldmethod' が \"indent\" または \"syntax\" の際の折畳みの\n" +"最大の深さ" -msgid "E146: Regular expressions can't be delimited by letters" -msgstr "E146: 正規表現は文字で区切ることができません" +msgid "diff mode" +msgstr "差分モード" -#, c-format -msgid "replace with %s (y/n/a/q/l/^E/^Y)?" -msgstr "%s に置換しますか? (y/n/a/q/l/^E/^Y)" +msgid "use diff mode for the current window" +msgstr "現在のウィンドウで差分モードを使う" -msgid "(Interrupted) " -msgstr "(割込まれました) " +msgid "options for using diff mode" +msgstr "差分モードを使うためのオプション" -msgid "1 match" -msgstr "1 箇所該当しました" +msgid "expression used to obtain a diff file" +msgstr "差分ファイルを取得するために使われる式" -msgid "1 substitution" -msgstr "1 箇所置換しました" +msgid "expression used to patch a file" +msgstr "ファイルにパッチを当てるために使われる式" -#, c-format -msgid "%ld matches" -msgstr "%ld 箇所該当しました" +msgid "mapping" +msgstr "マッピング" -#, c-format -msgid "%ld substitutions" -msgstr "%ld 箇所置換しました" +msgid "maximum depth of mapping" +msgstr "マッピングの最大の深さ" -msgid " on 1 line" -msgstr " (計 1 行内)" +msgid "allow timing out halfway into a mapping" +msgstr "マッピングの途中でのタイムアウトを許可" -#, c-format -msgid " on %ld lines" -msgstr " (計 %ld 行内)" +msgid "allow timing out halfway into a key code" +msgstr "キーコードの途中でのタイムアウトを許可" -msgid "E147: Cannot do :global recursive with a range" -msgstr "E147: :global を範囲付きで再帰的には使えません" +msgid "time in msec for 'timeout'" +msgstr "'timeout' の時間 (ミリ秒)" -msgid "E148: Regular expression missing from global" -msgstr "E148: globalコマンドに正規表現が指定されていません" +msgid "time in msec for 'ttimeout'" +msgstr "'ttimeout' の時間 (ミリ秒)" -#, c-format -msgid "Pattern found in every line: %s" -msgstr "パターンが全ての行で見つかりました: %s" +msgid "reading and writing files" +msgstr "ファイルの読み書き" -#, c-format -msgid "Pattern not found: %s" -msgstr "パターンは見つかりませんでした: %s" +msgid "enable using settings from modelines when reading a file" +msgstr "ファイル読込み時にモードラインからの設定の使用を有効にする" -msgid "E478: Don't panic!" -msgstr "E478: 慌てないでください" +msgid "allow setting expression options from a modeline" +msgstr "モードラインから式であるオプションを設定することを許可する" -#, c-format -msgid "E661: Sorry, no '%s' help for %s" -msgstr "E661: 残念ですが '%s' のヘルプが %s にはありません" +msgid "number of lines to check for modelines" +msgstr "モードライン用にチェックする行数" -#, c-format -msgid "E149: Sorry, no help for %s" -msgstr "E149: 残念ですが %s にはヘルプがありません" +msgid "binary file editing" +msgstr "バイナリファイルの編集" -#, c-format -msgid "Sorry, help file \"%s\" not found" -msgstr "残念ですがヘルプファイル \"%s\" が見つかりません" +msgid "last line in the file has an end-of-line" +msgstr "ファイルの最終行に改行がある" -#, c-format -msgid "E151: No match: %s" -msgstr "E151: マッチはありません: %s" +msgid "last line in the file followed by CTRL-Z" +msgstr "ファイルの最終行が CTRL-Z で終わる" -#, c-format -msgid "E152: Cannot open %s for writing" -msgstr "E152: 書込み用に %s を開けません" +msgid "fixes missing end-of-line at end of text file" +msgstr "テキストファイルの末尾に改行がない場合に修正する" -#, c-format -msgid "E153: Unable to open %s for reading" -msgstr "E153: 読込用に %s を開けません" +msgid "prepend a Byte Order Mark to the file" +msgstr "バイト順マーク (BOM) をファイル先頭につける" -# Added at 29-Apr-2004. -#, c-format -msgid "E670: Mix of help file encodings within a language: %s" -msgstr "E670: 1つの言語のヘルプファイルに複数のエンコードが混在しています: %s" +msgid "end-of-line format: \"dos\", \"unix\" or \"mac\"" +msgstr "改行の形式: \"dos\", \"unix\" または \"mac\"" -#, c-format -msgid "E154: Duplicate tag \"%s\" in file %s/%s" -msgstr "E154: タグ \"%s\" がファイル %s/%s に重複しています" +msgid "list of file formats to look for when editing a file" +msgstr "ファイル編集時に調べる改行形式のリスト" -#, c-format -msgid "E150: Not a directory: %s" -msgstr "E150: ディレクトリではありません: %s" +msgid "writing files is allowed" +msgstr "ファイルの書込みが許可されている" -#, c-format -msgid "E160: Unknown sign command: %s" -msgstr "E160: 未知のsignコマンドです: %s" +msgid "write a backup file before overwriting a file" +msgstr "ファイルを上書きする前にバックアップに書込む" -msgid "E156: Missing sign name" -msgstr "E156: sign名がありません" +msgid "keep a backup after overwriting a file" +msgstr "ファイルの上書き後にバックアップを保持" -msgid "E612: Too many signs defined" -msgstr "E612: signの定義が多数見つかりました" +msgid "patterns that specify for which files a backup is not made" +msgstr "どのファイルでバックアックが作られないかを指定するパターン" -#, c-format -msgid "E239: Invalid sign text: %s" -msgstr "E239: 無効なsignのテキストです: %s" +msgid "whether to make the backup as a copy or rename the existing file" +msgstr "バックアップを既存のファイルのコピーとするかリネームするか" -#, c-format -msgid "E155: Unknown sign: %s" -msgstr "E155: 未知のsignです: %s" +msgid "list of directories to put backup files in" +msgstr "バックアップファイルを置くディレクトリのリスト" -msgid "E159: Missing sign number" -msgstr "E159: signの番号がありません" +msgid "file name extension for the backup file" +msgstr "バックアップファイルの拡張子" -#, c-format -msgid "E158: Invalid buffer name: %s" -msgstr "E158: 無効なバッファ名です: %s" +msgid "automatically write a file when leaving a modified buffer" +msgstr "変更されたバッファを離れる際に自動的にファイルに書込む" -msgid "E934: Cannot jump to a buffer that does not have a name" -msgstr "E934: 名前の無いバッファへはジャンプできません" +msgid "as 'autowrite', but works with more commands" +msgstr "'autowrite' と同様だが、より多くのコマンドで動作する" -#, c-format -msgid "E157: Invalid sign ID: %ld" -msgstr "E157: 無効なsign識別子です: %ld" +msgid "always write without asking for confirmation" +msgstr "常に確認無しに書込む" -#, c-format -msgid "E885: Not possible to change sign %s" -msgstr "E885: 変更できない sign です: %s" +msgid "automatically read a file when it was modified outside of Vim" +msgstr "Vim の外でファイルが変更された際に自動的に読込む" -# Added at 27-Jan-2004. -msgid " (NOT FOUND)" -msgstr " (見つかりません)" +msgid "keep oldest version of a file; specifies file name extension" +msgstr "ファイルの最古のバージョンを保持; ファイルの拡張子を指定" -msgid " (not supported)" -msgstr " (非サポート)" +msgid "forcibly sync the file to disk after writing it" +msgstr "ファイルを書込んだ後に強制的にディスクに同期させる" -msgid "[Deleted]" -msgstr "[削除済]" +msgid "the swap file" +msgstr "スワップファイル" -msgid "No old files" -msgstr "古いファイルはありません" +msgid "list of directories for the swap file" +msgstr "スワップファイル用のディレクトリのリスト" -msgid "Entering Debug mode. Type \"cont\" to continue." -msgstr "デバッグモードに入ります. 続けるには \"cont\" と入力してください." +msgid "use a swap file for this buffer" +msgstr "このバッファでスワップファイルを使う" -#, c-format -msgid "Oldval = \"%s\"" -msgstr "古い値 = \"%s\"" +msgid "number of characters typed to cause a swap file update" +msgstr "何文字入力したらスワップファイルを更新するか" -#, c-format -msgid "Newval = \"%s\"" -msgstr "新しい値 = \"%s\"" +msgid "time in msec after which the swap file will be updated" +msgstr "スワップファイルを更新するまでの時間 (ミリ秒)" -#, c-format -msgid "line %ld: %s" -msgstr "行 %ld: %s" +msgid "command line editing" +msgstr "コマンドライン編集" -#, c-format -msgid "cmd: %s" -msgstr "コマンド: %s" +msgid "how many command lines are remembered" +msgstr "コマンドラインを何個まで記憶するか" -msgid "frame is zero" -msgstr "フレームが 0 です" +msgid "key that triggers command-line expansion" +msgstr "コマンドライン展開を引き起こすキー" -#, c-format -msgid "frame at highest level: %d" -msgstr "最高レベルのフレーム: %d" +msgid "like 'wildchar' but can also be used in a mapping" +msgstr "'wildchar' と同様だがマッピング内でも使用できる" -#, c-format -msgid "Breakpoint in \"%s%s\" line %ld" -msgstr "ブレークポイント \"%s%s\" 行 %ld" +msgid "specifies how command line completion works" +msgstr "どのようにコマンドライン補完が動作するかを指定" -#, c-format -msgid "E161: Breakpoint not found: %s" -msgstr "E161: ブレークポイントが見つかりません: %s" +msgid "empty or \"tagfile\" to list file name of matching tags" +msgstr "空、またはマッチしたファイル名を一覧表示するなら \"tagfile\"" -msgid "No breakpoints defined" -msgstr "ブレークポイントが定義されていません" +msgid "list of file name extensions that have a lower priority" +msgstr "低い優先度を持つ拡張子のリスト" -#, c-format -msgid "%3d %s %s line %ld" -msgstr "%3d %s %s 行 %ld" +msgid "list of file name extensions added when searching for a file" +msgstr "ファイル検索時に追加される拡張子のリスト" -#, c-format -msgid "%3d expr %s" -msgstr "%3d expr %s" +msgid "list of patterns to ignore files for file name completion" +msgstr "ファイル名補完の際に無視するファイルパターンのリスト" -msgid "E750: First use \":profile start {fname}\"" -msgstr "E750: 初めに \":profile start {fname}\" を実行してください" +msgid "ignore case when using file names" +msgstr "ファイル名を使う際に大文字小文字の違いを無視" -#, c-format -msgid "Save changes to \"%s\"?" -msgstr "変更を \"%s\" に保存しますか?" +msgid "ignore case when completing file names" +msgstr "ファイル名補完の際に大文字小文字の違いを無視" -#, c-format -msgid "E947: Job still running in buffer \"%s\"" -msgstr "E947: ジョブはバッファ \"%s\" でまだ実行中です" +msgid "command-line completion shows a list of matches" +msgstr "コマンドライン補完はマッチの一覧を表示する" -#, c-format -msgid "E162: No write since last change for buffer \"%s\"" -msgstr "E162: バッファ \"%s\" の変更は保存されていません" +msgid "key used to open the command-line window" +msgstr "コマンドラインウィンドウを開くためのキー" -msgid "Warning: Entered other buffer unexpectedly (check autocommands)" -msgstr "警告: 予期せず他バッファへ移動しました (autocommands を調べてください)" +msgid "height of the command-line window" +msgstr "コマンドラインウィンドウの高さ" -msgid "E163: There is only one file to edit" -msgstr "E163: 編集するファイルは1つしかありません" +msgid "executing external commands" +msgstr "外部コマンドの実行" -msgid "E164: Cannot go before first file" -msgstr "E164: 最初のファイルより前には行けません" +msgid "name of the shell program used for external commands" +msgstr "外部コマンドに使われるシェルプログラムの名前" -msgid "E165: Cannot go beyond last file" -msgstr "E165: 最後のファイルを越えて後には行けません" +msgid "character(s) to enclose a shell command in" +msgstr "シェルコマンドを囲む引用符" -#, c-format -msgid "E666: compiler not supported: %s" -msgstr "E666: そのコンパイラには対応していません: %s" +msgid "like 'shellquote' but include the redirection" +msgstr "'shellquote' と同様だがリダイレクトを含む" -#, c-format -msgid "W20: Required python version 2.x not supported, ignoring file: %s" -msgstr "W20: 要求されたpython 2.xは対応していません、ファイルを無視します: %s" +msgid "characters to escape when 'shellxquote' is (" +msgstr "'shellxquote' が ( の時にエスケープされる文字" -#, c-format -msgid "W21: Required python version 3.x not supported, ignoring file: %s" -msgstr "W21: 要求されたpython 3.xは対応していません、ファイルを無視します: %s" +msgid "argument for 'shell' to execute a command" +msgstr "コマンドを実行する際の 'shell' の引数" -#, c-format -msgid "Current %slanguage: \"%s\"" -msgstr "現在の %s言語: \"%s\"" +msgid "used to redirect command output to a file" +msgstr "コマンドの出力をファイルにリダイレクトする際に使われる" -#, c-format -msgid "E197: Cannot set language to \"%s\"" -msgstr "E197: 言語を \"%s\" に設定できません" +msgid "use a temp file for shell commands instead of using a pipe" +msgstr "シェルコマンドにパイプを使わずに一時ファイルを使う" -msgid "Entering Ex mode. Type \"visual\" to go to Normal mode." -msgstr "" -"Exモードに入ります. ノーマルモードに戻るには\"visual\"と入力してください." +msgid "program used for \"=\" command" +msgstr "\"=\" コマンドに使われるプログラム" -msgid "E501: At end-of-file" -msgstr "E501: ファイルの終了位置" +msgid "program used to format lines with \"gq\" command" +msgstr "\"gq\" コマンドで行を整形する際に使われるプログラム" -msgid "E169: Command too recursive" -msgstr "E169: コマンドが再帰的過ぎます" +msgid "program used for the \"K\" command" +msgstr "\"K\" コマンドに使われるプログラム" -#, c-format -msgid "E605: Exception not caught: %s" -msgstr "E605: 例外が捕捉されませんでした: %s" +msgid "warn when using a shell command and a buffer has changes" +msgstr "バッファに変更がありシェルコマンドが実行された際に警告する" -msgid "End of sourced file" -msgstr "取込ファイルの最後です" +msgid "running make and jumping to errors (quickfix)" +msgstr "make の実行とエラーへのジャンプ (quickfix)" -msgid "End of function" -msgstr "関数の最後です" +msgid "name of the file that contains error messages" +msgstr "エラーメッセージが入っているファイルの名前" -msgid "E464: Ambiguous use of user-defined command" -msgstr "E464: ユーザー定義コマンドのあいまいな使用です" +msgid "list of formats for error messages" +msgstr "エラーメッセージの書式のリスト" -msgid "E492: Not an editor command" -msgstr "E492: エディタのコマンドではありません" +msgid "program used for the \":make\" command" +msgstr "\":make\" コマンドに使われるプログラム" -msgid "E493: Backwards range given" -msgstr "E493: 逆さまの範囲が指定されました" +msgid "string used to put the output of \":make\" in the error file" +msgstr "\":make\" の出力をエラーファイルに書込むために使われる文字列" -msgid "Backwards range given, OK to swap" -msgstr "逆さまの範囲が指定されました、入替えますか?" +msgid "name of the errorfile for the 'makeprg' command" +msgstr "'makeprg' コマンド用のエラーファイルの名前" -msgid "E494: Use w or w>>" -msgstr "E494: w もしくは w>> を使用してください" +msgid "program used for the \":grep\" command" +msgstr "\":grep\" コマンドに使われるプログラム" -msgid "E943: Command table needs to be updated, run 'make cmdidxs'" -msgstr "" -"E943: コマンドテーブルを更新する必要があります、'make cmdidxs' を実行してくだ" -"さい" +msgid "list of formats for output of 'grepprg'" +msgstr "'grepprg' の出力用の書式のリスト" -msgid "E319: Sorry, the command is not available in this version" -msgstr "E319: このバージョンではこのコマンドは利用できません、ごめんなさい" +msgid "encoding of the \":make\" and \":grep\" output" +msgstr "\":make\" と \":grep\" の出力のエンコーディング" -msgid "1 more file to edit. Quit anyway?" -msgstr "編集すべきファイルが 1 個ありますが、終了しますか?" +msgid "system specific" +msgstr "システム固有" -#, c-format -msgid "%d more files to edit. Quit anyway?" -msgstr "編集すべきファイルがあと %d 個ありますが、終了しますか?" +msgid "use forward slashes in file names; for Unix-like shells" +msgstr "ファイル名でスラッシュを使う; Unix ライクなシェル用" -msgid "E173: 1 more file to edit" -msgstr "E173: 編集すべきファイルが 1 個あります" +msgid "specifies slash/backslash used for completion" +msgstr "補完に salsh/backslash のどちらを使うか指定" -#, c-format -msgid "E173: %ld more files to edit" -msgstr "E173: 編集すべきファイルがあと %ld 個あります" +msgid "language specific" +msgstr "言語固有" -msgid "E174: Command already exists: add ! to replace it" -msgstr "E174: コマンドが既にあります: 再定義するには ! を追加してください" +msgid "specifies the characters in a file name" +msgstr "ファイル名に使われる文字を指定" -msgid "" -"\n" -" Name Args Address Complete Definition" -msgstr "" -"\n" -" 名前 引数 アドレス 補完 定義" +msgid "specifies the characters in an identifier" +msgstr "識別子に使われる文字を指定" -msgid "No user-defined commands found" -msgstr "ユーザー定義コマンドが見つかりませんでした" +msgid "specifies the characters in a keyword" +msgstr "キーワードに使われる文字を指定" -msgid "E175: No attribute specified" -msgstr "E175: 属性は定義されていません" +msgid "specifies printable characters" +msgstr "表示可能な文字を指定" -msgid "E176: Invalid number of arguments" -msgstr "E176: 引数の数が無効です" +msgid "specifies escape characters in a string" +msgstr "文字列内のエスケープ文字を指定" -msgid "E177: Count cannot be specified twice" -msgstr "E177: カウントを2重指定することはできません" +msgid "display the buffer right-to-left" +msgstr "バッファを右から左に表示" -msgid "E178: Invalid default value for count" -msgstr "E178: カウントの省略値が無効です" +msgid "when to edit the command-line right-to-left" +msgstr "いつコマンドラインを右から左に編集するか" -msgid "E179: argument required for -complete" -msgstr "E179: -complete には引数が必要です" +msgid "insert characters backwards" +msgstr "文字を逆方向に挿入" -msgid "E179: argument required for -addr" -msgstr "E179: -addr には引数が必要です" +msgid "allow CTRL-_ in Insert and Command-line mode to toggle 'revins'" +msgstr "挿入・コマンドラインモードで CTRL-_ で 'revins' の切り替えを許可" -#, c-format -msgid "E181: Invalid attribute: %s" -msgstr "E181: 無効な属性です: %s" +msgid "the ASCII code for the first letter of the Hebrew alphabet" +msgstr "ヘブライ語アルファベットの最初の文字を表す ASCII コード" -msgid "E182: Invalid command name" -msgstr "E182: 無効なコマンド名です" +msgid "use Hebrew keyboard mapping" +msgstr "ヘブライキーボードのマッピングを使用" -msgid "E183: User defined commands must start with an uppercase letter" -msgstr "E183: ユーザー定義コマンドは英大文字で始まらなければなりません" +msgid "use phonetic Hebrew keyboard mapping" +msgstr "音声ヘブライキーボードのマッピングを使用" -msgid "E841: Reserved name, cannot be used for user defined command" -msgstr "E841: 予約名なので、ユーザー定義コマンドに利用できません" +msgid "prepare for editing Arabic text" +msgstr "アラビア語のテキストを編集する準備" -#, c-format -msgid "E184: No such user-defined command: %s" -msgstr "E184: そのユーザー定義コマンドはありません: %s" +msgid "perform shaping of Arabic characters" +msgstr "アラビア文字の字形処理を行う" -#, c-format -msgid "E180: Invalid address type value: %s" -msgstr "E180: 無効なアドレスタイプ値です: %s" +msgid "terminal will perform bidi handling" +msgstr "端末が双方向 (bidi) の処理を行う" -#, c-format -msgid "E180: Invalid complete value: %s" -msgstr "E180: 無効な補完指定です: %s" +msgid "name of a keyboard mapping" +msgstr "キーボードマッピングの名前" -msgid "E468: Completion argument only allowed for custom completion" -msgstr "E468: 補完引数はカスタム補完でしか使用できません" +msgid "list of characters that are translated in Normal mode" +msgstr "ノーマルモードで変換される文字のリスト" -msgid "E467: Custom completion requires a function argument" -msgstr "E467: カスタム補完には引数として関数が必要です" +msgid "apply 'langmap' to mapped characters" +msgstr "'langmap' をマップされた文字に適用" -msgid "unknown" -msgstr "不明" +msgid "when set never use IM; overrules following IM options" +msgstr "オンのとき IM を全く使わない; 以下の IM 関連オプションに優先する" -#, c-format -msgid "E185: Cannot find color scheme '%s'" -msgstr "E185: カラースキーム '%s' が見つかりません" +msgid "in Insert mode: 1: use :lmap; 2: use IM; 0: neither" +msgstr "挿入モード時: 1: :lmap を使用; 2: IM を使用; 0: どちらも不使用" -msgid "Greetings, Vim user!" -msgstr "Vim 使いさん、やあ!" +msgid "entering a search pattern: 1: use :lmap; 2: use IM; 0: neither" +msgstr "" +"検索パターン入力時: 1: :lmap を使用; 2: IM を使用;\n" +"0: どちらも不使用" -msgid "E784: Cannot close last tab page" -msgstr "E784: 最後のタブページを閉じることはできません" +msgid "when set always use IM when starting to edit a command line" +msgstr "オンのときはコマンドライン編集開始時に常に IM を使用" -msgid "Already only one tab page" -msgstr "既にタブページは1つしかありません" +msgid "function to obtain IME status" +msgstr "IME の状態を取得するための関数" -msgid "Edit File in new tab page" -msgstr "新しいタブページでファイルを編集します" +msgid "function to enable/disable IME" +msgstr "IME を有効化/無効化するための関数" -msgid "Edit File in new window" -msgstr "新しいウィンドウでファイルを編集します" +msgid "multi-byte characters" +msgstr "マルチバイト文字" -#, c-format -msgid "Tab page %d" -msgstr "タブページ %d" +msgid "character encoding used in Nvim: \"utf-8\"" +msgstr "Nvim で使われる文字エンコーディング: \"uft-8\"" -msgid "No swap file" -msgstr "スワップファイルがありません" +msgid "character encoding for the current file" +msgstr "現在のファイルの文字エンコーディング" -msgid "Append File" -msgstr "追加ファイル" +msgid "automatically detected character encodings" +msgstr "文字エンコーディングを自動検出" -msgid "E747: Cannot change directory, buffer is modified (add ! to override)" -msgstr "" -"E747: バッファが修正されているので、ディレクトリを変更できません (! を追加で" -"上書)" +msgid "expression used for character encoding conversion" +msgstr "文字エンコーディング変換に使われる式" -msgid "E186: No previous directory" -msgstr "E186: 前のディレクトリはありません" +msgid "delete combining (composing) characters on their own" +msgstr "結合文字そのものを削除" -msgid "E187: Unknown" -msgstr "E187: 未知" +msgid "maximum number of combining (composing) characters displayed" +msgstr "表示の際の結合文字の最大数" -msgid "E465: :winsize requires two number arguments" -msgstr "E465: :winsize には2つの数値の引数が必要です" +msgid "key that activates the X input method" +msgstr "X インプットメソッドを起動するためのキー" -#, c-format -msgid "Window position: X %d, Y %d" -msgstr "ウィンドウ位置: X %d, Y %d" +msgid "width of ambiguous width characters" +msgstr "あいまい幅文字の幅" + +msgid "emoji characters are full width" +msgstr "絵文字の幅は全角" + +msgid "various" +msgstr "その他" -msgid "E188: Obtaining window position not implemented for this platform" +msgid "" +"when to use virtual editing: \"block\", \"insert\", \"all\"\n" +"and/or \"onemore\"" msgstr "" -"E188: このプラットホームにはウィンドウ位置の取得機能は実装されていません" +"いつ仮想編集を使うか: \"block\", \"insert\", \"all\"\n" +"かつ/または \"onemore\"" -msgid "E466: :winpos requires two number arguments" -msgstr "E466: :winpos には2つの数値の引数が必要です" +msgid "list of autocommand events which are to be ignored" +msgstr "自動コマンドイベントで無視するもののリスト" -msgid "E930: Cannot use :redir inside execute()" -msgstr "E930: execute() の中では :redir は使えません" +msgid "load plugin scripts when starting up" +msgstr "起動時にプラグインスクリプトを読込む" -msgid "Save Redirection" -msgstr "リダイレクトを保存します" +msgid "enable reading .vimrc/.exrc/.gvimrc in the current directory" +msgstr "" +"カレントディレクトリにある .vimrc/.exrc/.gvimrc の読込みを\n" +"有効化" -#, c-format -msgid "E739: Cannot create directory: %s" -msgstr "E739: ディレクトリを作成できません: %s" +msgid "safer working with script files in the current directory" +msgstr "カレントディレクトリのスクリプトファイルを安全に扱う" -#, c-format -msgid "E189: \"%s\" exists (add ! to override)" -msgstr "E189: \"%s\" が存在します (上書するには ! を追加してください)" +msgid "use the 'g' flag for \":substitute\"" +msgstr "\":substitute\" に 'g' フラグを使う" -#, c-format -msgid "E190: Cannot open \"%s\" for writing" -msgstr "E190: \"%s\" を書込み用として開けません" +msgid "allow reading/writing devices" +msgstr "デバイスからの読み書きを許可する" -msgid "E191: Argument must be a letter or forward/backward quote" -msgstr "E191: 引数は1文字の英字か引用符 (' か `) でなければいけません" +msgid "maximum depth of function calls" +msgstr "関数呼出しの最大の深さ" -msgid "E192: Recursive use of :normal too deep" -msgstr "E192: :normal の再帰利用が深くなり過ぎました" +msgid "list of words that specifies what to put in a session file" +msgstr "セッションファイルに何を保存するかを指定する単語のリスト" -msgid "E809: #< is not available without the +eval feature" -msgstr "E809: #< は +eval 機能が無いと利用できません" +msgid "list of words that specifies what to save for :mkview" +msgstr ":mkview で何を保存するかを指定する単語のリスト" -msgid "E194: No alternate file name to substitute for '#'" -msgstr "E194: '#'を置き換える副ファイルの名前がありません" +msgid "directory where to store files with :mkview" +msgstr ":mkview でファイルを保存するディレクトリ" -msgid "E495: no autocommand file name to substitute for \"\"" -msgstr "E495: \"\"を置き換えるautocommandのファイル名がありません" +msgid "list that specifies what to write in the ShaDa file" +msgstr "ShaDa ファイルに何を書くかを指定するリスト" -msgid "E496: no autocommand buffer number to substitute for \"\"" -msgstr "E496: \"\"を置き換えるautocommandバッファ番号がありません" +msgid "what happens with a buffer when it's no longer in a window" +msgstr "バッファがウィンドウに表示されなくなった時の挙動" -msgid "E497: no autocommand match name to substitute for \"\"" -msgstr "E497: \"\"を置き換えるautocommandの該当名がありません" +msgid "empty, \"nofile\", \"nowrite\", \"quickfix\", etc.: type of buffer" +msgstr "空, \"nofile\", \"nowrite\", \"quickfix\" など: バッファの種別" -msgid "E498: no :source file name to substitute for \"\"" -msgstr "E498: \"\"を置き換える :source 対象ファイル名がありません" +msgid "whether the buffer shows up in the buffer list" +msgstr "バッファをバッファ一覧に表示するかどうか" -msgid "E842: no line number to use for \"\"" -msgstr "E842: \"\"を置き換える行番号がありません" +msgid "set to \"msg\" to see all error messages" +msgstr "全てのエラーメッセージを見るには \"msg\" に設定" -#, no-c-format -msgid "E499: Empty file name for '%' or '#', only works with \":p:h\"" -msgstr "" -"E499: '%' や '#' が無名ファイルなので \":p:h\" を伴わない使い方はできません" +msgid "whether to show the signcolumn" +msgstr "目印桁を表示するかどうか" -msgid "E500: Evaluates to an empty string" -msgstr "E500: 空文字列として評価されました" +msgid "name of the MzScheme dynamic library" +msgstr "MzScheme 動的ライブラリの名前" -msgid "Untitled" -msgstr "無題" +msgid "name of the MzScheme GC dynamic library" +msgstr "MzScheme GC 動的ライブラリの名前" -msgid "E196: No digraphs in this version" -msgstr "E196: このバージョンに合字はありません" +msgid "whether to use Python 2 or 3" +msgstr "Python 2 と 3 のどちらを使うか" -msgid "E608: Cannot :throw exceptions with 'Vim' prefix" -msgstr "E608: 'Vim' で始まる例外は :throw できません" +msgid "E249: Window layout changed unexpectedly" +msgstr "E249: 予期せずウィンドウの配置が変わりました" -#, c-format -msgid "Exception thrown: %s" -msgstr "例外が発生しました: %s" +msgid "E1156: Cannot change the argument list recursively" +msgstr "E1156: 引数リストを再帰的に変更することはできません" -#, c-format -msgid "Exception finished: %s" -msgstr "例外が収束しました: %s" +msgid "E163: There is only one file to edit" +msgstr "E163: 編集するファイルは1つしかありません" -#, c-format -msgid "Exception discarded: %s" -msgstr "例外が破棄されました: %s" +msgid "E164: Cannot go before first file" +msgstr "E164: 最初のファイルより前には行けません" -#, c-format -msgid "%s, line %ld" -msgstr "%s, 行 %ld" +msgid "E165: Cannot go beyond last file" +msgstr "E165: 最後のファイルを越えて後には行けません" -#, c-format -msgid "Exception caught: %s" -msgstr "例外が捕捉されました: %s" +msgid "E610: No argument to delete" +msgstr "E610: 削除する引数がありません" -#, c-format -msgid "%s made pending" -msgstr "%s により未決定状態が生じました" +msgid "E218: Autocommand nesting too deep" +msgstr "E218: 自動コマンドの入れ子が深過ぎます" + +msgid "--Deleted--" +msgstr "--削除済--" #, c-format -msgid "%s resumed" -msgstr "%s が再開しました" +msgid "auto-removing autocommand: %s " +msgstr "自動コマンド: %s <バッファ=%d> が自動的に削除されます" #, c-format -msgid "%s discarded" -msgstr "%s が破棄されました" +msgid "E367: No such group: \"%s\"" +msgstr "E367: そのグループはありません: \"%s\"" -msgid "Exception" -msgstr "例外" +msgid "E936: Cannot delete the current group" +msgstr "E936: 現在のグループは削除できません" -msgid "Error and interrupt" -msgstr "エラーと割込み" +msgid "W19: Deleting augroup that is still in use" +msgstr "W19: 使用中の augroup を消そうとしています" -msgid "Error" -msgstr "エラー" +msgid "" +"\n" +"--- Autocommands ---" +msgstr "" +"\n" +"--- 自動コマンド ---" -msgid "Interrupt" -msgstr "割込み" +#, c-format +msgid "E680: : invalid buffer number " +msgstr "E680: <バッファ=%d>: 無効なバッファ番号です" -msgid "E579: :if nesting too deep" -msgstr "E579: :if の入れ子が深過ぎます" +msgid "E217: Can't execute autocommands for ALL events" +msgstr "E217: 全てのイベントに対しての自動コマンドは実行できません" -msgid "E580: :endif without :if" -msgstr "E580: :if のない :endif があります" +#, c-format +msgid "No matching autocommands: %s" +msgstr "該当する自動コマンドは存在しません: %s" -msgid "E581: :else without :if" -msgstr "E581: :if のない :else があります" +#, fuzzy, c-format +#~ msgid "%s Autocommands for \"%s\"" +#~ msgstr "%s Autocommands for \"%s\"" -msgid "E582: :elseif without :if" -msgstr "E582: :if のない :elseif があります" +#, c-format +msgid "Executing %s" +msgstr "%s を実行しています" -msgid "E583: multiple :else" -msgstr "E583: 複数の :else があります" +#, c-format +msgid "autocommand %s" +msgstr "自動コマンド %s" -msgid "E584: :elseif after :else" -msgstr "E584: :else の後に :elseif があります" +#, c-format +msgid "E215: Illegal character after *: %s" +msgstr "E215: * の後に不正な文字がありました: %s" -msgid "E585: :while/:for nesting too deep" -msgstr "E585: :while や :for の入れ子が深過ぎます" +#, c-format +msgid "E216: No such event: %s" +msgstr "E216: そのようなイベントはありません: %s" -msgid "E586: :continue without :while or :for" -msgstr "E586: :while や :for のない :continue があります" +#, c-format +msgid "E216: No such group or event: %s" +msgstr "E216: そのようなグループもしくはイベントはありません: %s" -msgid "E587: :break without :while or :for" -msgstr "E587: :while や :for のない :break があります" +#, c-format +msgid "E937: Attempt to delete a buffer that is in use: %s" +msgstr "E937: 使用中のバッファを削除しようと試みました: %s" -msgid "E732: Using :endfor with :while" -msgstr "E732: :endfor を :while と組み合わせています" +msgid "E82: Cannot allocate any buffer, exiting..." +msgstr "E82: バッファを1つも作成できないので、終了します..." -msgid "E733: Using :endwhile with :for" -msgstr "E733: :endwhile を :for と組み合わせています" +msgid "E83: Cannot allocate buffer, using other one..." +msgstr "E83: バッファを作成できないので、他のを使用します..." -msgid "E601: :try nesting too deep" -msgstr "E601: :try の入れ子が深過ぎます" +msgid "E515: No buffers were unloaded" +msgstr "E515: 解放されたバッファはありません" -msgid "E603: :catch without :try" -msgstr "E603: :try のない :catch があります" +msgid "E516: No buffers were deleted" +msgstr "E516: 削除されたバッファはありません" -msgid "E604: :catch after :finally" -msgstr "E604: :finally の後に :catch があります" +msgid "E517: No buffers were wiped out" +msgstr "E517: 破棄されたバッファはありません" -msgid "E606: :finally without :try" -msgstr "E606: :try のない :finally があります" +#, c-format +msgid "%d buffer unloaded" +msgid_plural "%d buffers unloaded" +msgstr[0] "%d 個のバッファが解放されました" -msgid "E607: multiple :finally" -msgstr "E607: 複数の :finally があります" +#, c-format +msgid "%d buffer deleted" +msgid_plural "%d buffers deleted" +msgstr[0] "%d 個のバッファが削除されました" -msgid "E602: :endtry without :try" -msgstr "E602: :try のない :endtry です" +#, c-format +msgid "%d buffer wiped out" +msgid_plural "%d buffers wiped out" +msgstr[0] "%d 個のバッファが破棄されました" -msgid "E193: :endfunction not inside a function" -msgstr "E193: 関数の外に :endfunction がありました" +msgid "E90: Cannot unload last buffer" +msgstr "E90: 最後のバッファは解放できません" -msgid "E788: Not allowed to edit another buffer now" -msgstr "E788: 現在は他のバッファを編集することは許されません" +msgid "E84: No modified buffer found" +msgstr "E84: 変更されたバッファはありません" -msgid "E811: Not allowed to change buffer information now" -msgstr "E811: 現在はバッファ情報を変更することは許されません" +msgid "E85: There is no listed buffer" +msgstr "E85: リスト表示されるバッファはありません" + +msgid "E87: Cannot go beyond last buffer" +msgstr "E87: 最後のバッファを越えて移動はできません" + +msgid "E88: Cannot go before first buffer" +msgstr "E88: 最初のバッファより前へは移動できません" #, c-format msgid "" -"\n" -"# %s History (newest to oldest):\n" -msgstr "" -"\n" -"# %s 項目の履歴 (新しいものから古いものへ):\n" +"E89: No write since last change for buffer % (add ! to override)" +msgstr "E89: バッファ % の変更は保存されていません (! で変更を破棄)" -msgid "Command Line" -msgstr "コマンドライン" +#, c-format +msgid "E89: %s will be killed (add ! to override)" +msgstr "E89: \"%s\" が存在します (上書するには ! を追加してください)" -msgid "Search String" -msgstr "検索文字列" +msgid "E948: Job still running (add ! to end the job)" +msgstr "E948: ジョブはまだ実行中です (! を追加でジョブを終了)" -msgid "Expression" -msgstr "式" +msgid "E37: No write since last change (add ! to override)" +msgstr "E37: 最後の変更が保存されていません (! を追加で変更を破棄)" -msgid "Input Line" -msgstr "入力行" +msgid "E948: Job still running" +msgstr "E948: ジョブはまだ実行中です" -msgid "Debug Line" -msgstr "デバッグ行" +msgid "E37: No write since last change" +msgstr "E37: 最後の変更が保存されていません" -msgid "E198: cmd_pchar beyond the command length" -msgstr "E198: cmd_pchar がコマンド長を超えました" +msgid "W14: Warning: List of file names overflow" +msgstr "W14: 警告: ファイル名のリストが長過ぎます" -msgid "E199: Active window or buffer deleted" -msgstr "E199: アクティブなウィンドウかバッファが削除されました" +#, c-format +msgid "E92: Buffer % not found" +msgstr "E92: バッファ % が見つかりません" -msgid "E812: Autocommands changed buffer or buffer name" -msgstr "E812: autocommandがバッファかバッファ名を変更しました" +#, c-format +msgid "E93: More than one match for %s" +msgstr "E93: %s に複数の該当がありました" -msgid "Illegal file name" -msgstr "不正なファイル名" +#, c-format +msgid "E94: No matching buffer for %s" +msgstr "E94: %s に該当するバッファはありませんでした" -msgid "is a directory" -msgstr "はディレクトリです" +#, c-format +msgid "line %" +msgstr "行 %" -msgid "is not a file" -msgstr "はファイルではありません" +msgid "E95: Buffer with this name already exists" +msgstr "E95: この名前のバッファは既にあります" -msgid "is a device (disabled with 'opendevice' option)" -msgstr "はデバイスです ('opendevice' オプションで回避できます)" +msgid " [Modified]" +msgstr " [変更あり]" -msgid "[New File]" -msgstr "[新ファイル]" +msgid "[Not edited]" +msgstr "[未編集]" -msgid "[New DIRECTORY]" -msgstr "[新規ディレクトリ]" +msgid "[New]" +msgstr "[新]" -msgid "[File too big]" -msgstr "[ファイル過大]" +msgid "[Read errors]" +msgstr "[読込エラー]" -msgid "[Permission Denied]" -msgstr "[権限がありません]" +msgid "[RO]" +msgstr "[読専]" -msgid "E200: *ReadPre autocommands made the file unreadable" -msgstr "E200: *ReadPre autocommand がファイルを読込不可にしました" +msgid "[readonly]" +msgstr "[読込専用]" -msgid "E201: *ReadPre autocommands must not change current buffer" -msgstr "E201: *ReadPre autocommand は現在のバッファを変えられません" +#, c-format +msgid "% line --%d%%--" +msgid_plural "% lines --%d%%--" +msgstr[0] "% 行 --%d%%--" -msgid "Vim: Reading from stdin...\n" -msgstr "Vim: 標準入力から読込中...\n" +#, c-format +msgid "line % of % --%d%%-- col " +msgstr "行 % (全体 %) --%d%%-- col " -msgid "Reading from stdin..." -msgstr "標準入力から読込み中..." +msgid "[No Name]" +msgstr "[無名]" -msgid "E202: Conversion made file unreadable!" -msgstr "E202: 変換がファイルを読込不可にしました" +msgid "help" +msgstr "ヘルプ" -msgid "[fifo/socket]" -msgstr "[FIFO/ソケット]" +msgid "All" +msgstr "全て" -msgid "[fifo]" -msgstr "[FIFO]" +msgid "Bot" +msgstr "末尾" -msgid "[socket]" -msgstr "[ソケット]" +msgid "Top" +msgstr "先頭" -msgid "[character special]" -msgstr "[キャラクタ・デバイス]" +#, c-format +msgid "%d%%" +msgstr "%d%%" -msgid "[CR missing]" -msgstr "[CR無]" +#, c-format +msgid " (%d of %d)" +msgstr " (%d of %d)" -msgid "[long lines split]" -msgstr "[長行分割]" +#, c-format +msgid " ((%d) of %d)" +msgstr " ((%d) of %d)" -msgid "[NOT converted]" -msgstr "[未変換]" +msgid "E382: Cannot write, 'buftype' option is set" +msgstr "E382: 'buftype' オプションが設定されているので書込めません" -msgid "[converted]" -msgstr "[変換済]" +msgid "[Command Line]" +msgstr "[コマンドライン]" -#, c-format -msgid "[CONVERSION ERROR in line %ld]" -msgstr "[%ld 行目で変換エラー]" +msgid "[Prompt]" +msgstr "[プロンプト]" -#, c-format -msgid "[ILLEGAL BYTE in line %ld]" -msgstr "[%ld 行目の不正なバイト]" +msgid "[Scratch]" +msgstr "[下書き]" -msgid "[READ ERRORS]" -msgstr "[読込エラー]" +msgid "[Location List]" +msgstr "[ロケーションリスト]" -msgid "Can't find temp file for conversion" -msgstr "変換に必要な一時ファイルが見つかりません" +msgid "[Quickfix List]" +msgstr "[Quickfixリスト]" -msgid "Conversion with 'charconvert' failed" -msgstr "'charconvert' による変換が失敗しました" +msgid "E206: Patchmode: can't touch empty original file" +msgstr "E206: Patchmode: 空の原本ファイルをtouchできません" -msgid "can't read output of 'charconvert'" -msgstr "'charconvert' の出力を読込めませんでした" +msgid "E513: Write error, conversion failed (make 'fenc' empty to override)" +msgstr "E513: 書込みエラー、変換失敗 (上書するには 'fenc' を空にしてください)" + +#~ msgid "E513: Write error, conversion failed in line %" +#~ msgstr "" -msgid "E676: No matching autocommands for acwrite buffer" -msgstr "E676: acwriteバッファの該当するautocommandは存在しません" +msgid "E514: Write error (file system full?)" +msgstr "E514: 書込みエラー (ファイルシステムが満杯?)" + +#, c-format +msgid "E676: No matching autocommands for buftype=%s buffer" +msgstr "E676: buftype=%s バッファの該当する自動コマンドは存在しません" + +msgid "WARNING: The file has been changed since reading it!!!" +msgstr "警告: 読込んだ後にファイルに変更がありました!!!" + +msgid "Do you really want to write to it" +msgstr "本当に上書きしますか" msgid "E203: Autocommands deleted or unloaded buffer to be written" -msgstr "E203: 保存するバッファをautocommandが削除か解放しました" +msgstr "E203: 保存するバッファを自動コマンドが削除もしくは解放しました" msgid "E204: Autocommand changed number of lines in unexpected way" -msgstr "E204: autocommandが予期せぬ方法で行数を変更しました" - -# Added at 19-Jan-2004. -msgid "NetBeans disallows writes of unmodified buffers" -msgstr "NetBeansは未変更のバッファを上書することは許可していません" +msgstr "E204: 自動コマンドが予期せぬ方法で行数を変更しました" -msgid "Partial writes disallowed for NetBeans buffers" -msgstr "NetBeansバッファの一部を書き出すことはできません" +msgid "is a directory" +msgstr "はディレクトリです" msgid "is not a file or writable device" msgstr "はファイルでも書込み可能デバイスでもありません" -msgid "writing to device disabled with 'opendevice' option" -msgstr "'opendevice' オプションによりデバイスへの書き込みはできません" - msgid "is read-only (add ! to override)" msgstr "は読込専用です (強制書込には ! を追加)" -msgid "E506: Can't write to backup file (add ! to override)" -msgstr "E506: バックアップファイルを保存できません (! を追加で強制保存)" - -msgid "E507: Close error for backup file (add ! to override)" +#, c-format +msgid "E303: Unable to create directory \"%s\" for backup file: %s" msgstr "" -"E507: バックアップファイルを閉じる際にエラーが発生しました (! を追加で強制)" - -msgid "E508: Can't read file for backup (add ! to override)" -msgstr "E508: バックアップ用ファイルを読込めません (! を追加で強制読込)" +"E303: バックアップファイル用のディレクトリ \"%s\" を作成できませんでした: %s" msgid "E509: Cannot create backup file (add ! to override)" -msgstr "E509: バックアップファイルを作れません (! を追加で強制作成)" +msgstr "E509: バックアップファイルを作れません (! を追加で強制書込)" msgid "E510: Can't make backup file (add ! to override)" -msgstr "E510: バックアップファイルを作れません (! を追加で強制作成)" +msgstr "E510: バックアップに失敗しました (! を追加で強制書込)" msgid "E214: Can't find temp file for writing" msgstr "E214: 保存用一時ファイルが見つかりません" @@ -1596,41 +1540,33 @@ msgstr "E213: 変換できません (! を追加で変換せずに保存)" msgid "E166: Can't open linked file for writing" msgstr "E166: リンクされたファイルに書込めません" -msgid "E212: Can't open file for writing" -msgstr "E212: 書込み用にファイルを開けません" - -msgid "E949: File changed while writing" -msgstr "E949: 書込み中にファイルが変更されました" - -msgid "E512: Close failed" -msgstr "E512: 閉じることに失敗" - -msgid "E513: write error, conversion failed (make 'fenc' empty to override)" -msgstr "E513: 書込みエラー、変換失敗 (上書するには 'fenc' を空にしてください)" - #, c-format -msgid "" -"E513: write error, conversion failed in line %ld (make 'fenc' empty to " -"override)" -msgstr "" -"E513: 書込みエラー、変換失敗、行数 %ld (上書するには 'fenc' を空にしてくださ" -"い)" +msgid "E212: Can't open file for writing: %s" +msgstr "E212: 書込み用にファイルを開けません: %s" -msgid "E514: write error (file system full?)" -msgstr "E514: 書込みエラー (ファイルシステムが満杯?)" +#, c-format +msgid "E512: Close failed: %s" +msgstr "E512: 閉じることに失敗: %s" msgid " CONVERSION ERROR" msgstr " 変換エラー" #, c-format -msgid " in line %ld;" -msgstr " 行 %ld;" +msgid " in line %;" +msgstr " 行 %;" + +msgid "[NOT converted]" +msgstr "[未変換]" + +msgid "[converted]" +msgstr "[変換済]" msgid "[Device]" msgstr "[デバイス]" -msgid "[New]" -msgstr "[新]" +#, fuzzy +#~ msgid "[noeol]" +#~ msgstr "[noeol]" msgid " [a]" msgstr " [a]" @@ -1644,6 +1580,12 @@ msgstr " [w]" msgid " written" msgstr " 書込み" +msgid "E205: Patchmode: can't save original file" +msgstr "E205: patchmode: 原本ファイルを保存できません" + +msgid "E207: Can't delete backup file" +msgstr "E207: バックアップファイルを消せません" + msgid "" "\n" "WARNING: Original file may be lost or damaged\n" @@ -1654,5027 +1596,5824 @@ msgstr "" msgid "don't quit the editor until the file is successfully written!" msgstr "ファイルの保存に成功するまでエディタを終了しないでください!" -msgid "[dos]" -msgstr "[dos]" +msgid "W10: Warning: Changing a readonly file" +msgstr "W10: 警告: 読込専用ファイルを変更します" -msgid "[dos format]" -msgstr "[dosフォーマット]" +msgid "can only be opened in headless mode" +msgstr "ヘッドレスモードでのみ開くことができます" -msgid "[mac]" -msgstr "[mac]" +msgid "channel was already open" +msgstr "チャネルは既に開かれています" -msgid "[mac format]" -msgstr "[macフォーマット]" +msgid "Can't send data to closed stream" +msgstr "閉じているストリームにデータを送ることはできません" -msgid "[unix]" -msgstr "[unix]" +msgid "Can't send raw data to rpc channel" +msgstr "rpcチャネルに生データをに送ることはできません" -msgid "[unix format]" -msgstr "[unixフォーマット]" +msgid "tagname" +msgstr "タグ名" -msgid "1 line, " -msgstr "1 行, " +msgid " kind file\n" +msgstr " ファイル種類\n" -#, c-format -msgid "%ld lines, " -msgstr "%ld 行, " +msgid "'history' option is zero" +msgstr "オプション 'history' がゼロです" -msgid "1 character" -msgstr "1 文字" +msgid "E548: Digit expected" +msgstr "E548: 数値が必要です" -#, c-format -msgid "%lld characters" -msgstr "%lld 文字" +msgid "E545: Missing colon" +msgstr "E545: コロンがありません" -msgid "[noeol]" -msgstr "[noeol]" +msgid "E546: Illegal mode" +msgstr "E546: 不正なモードです" -msgid "[Incomplete last line]" -msgstr "[最終行が不完全]" +msgid "E549: Illegal percentage" +msgstr "E549: 不正なパーセンテージです" -#, c-format -msgid "E208: Error writing to \"%s\"" -msgstr "E208: \"%s\" を書込み中のエラーです" +msgid "Entering Debug mode. Type \"cont\" to continue." +msgstr "デバッグモードに入ります。続けるには \"cont\" と入力してください。" #, c-format -msgid "E209: Error closing \"%s\"" -msgstr "E209: \"%s\" を閉じる時にエラーです" +msgid "Oldval = \"%s\"" +msgstr "古い値 = \"%s\"" #, c-format -msgid "E210: Error reading \"%s\"" -msgstr "E210: \"%s\" を読込中のエラーです" - -msgid "E246: FileChangedShell autocommand deleted buffer" -msgstr "E246: autocommand の FileChangedShell がバッファを削除しました" +msgid "Newval = \"%s\"" +msgstr "新しい値 = \"%s\"" #, c-format -msgid "E211: File \"%s\" no longer available" -msgstr "E211: ファイル \"%s\" は既に存在しません" +msgid "line %: %s" +msgstr "行 %: %s" #, c-format -msgid "" -"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as " -"well" -msgstr "W12: 警告: ファイル \"%s\" が変更されVimのバッファも変更されました" +msgid "cmd: %s" +msgstr "コマンド: %s" -msgid "See \":help W12\" for more info." -msgstr "詳細は \":help W12\" を参照してください" +msgid "frame is zero" +msgstr "フレームが 0 です" #, c-format -msgid "W11: Warning: File \"%s\" has changed since editing started" -msgstr "W11: 警告: ファイル \"%s\" は編集開始後に変更されました" +msgid "frame at highest level: %d" +msgstr "最高レベルのフレーム: %d" -msgid "See \":help W11\" for more info." -msgstr "詳細は \":help W11\" を参照してください" +#, c-format +msgid "Breakpoint in \"%s%s\" line %" +msgstr "ブレークポイント \"%s%s\" 行 %" #, c-format -msgid "W16: Warning: Mode of file \"%s\" has changed since editing started" -msgstr "W16: 警告: ファイル \"%s\" のモードが編集開始後に変更されました" +msgid "E161: Breakpoint not found: %s" +msgstr "E161: ブレークポイントが見つかりません: %s" -msgid "See \":help W16\" for more info." -msgstr "詳細は \":help W16\" を参照してください" +msgid "No breakpoints defined" +msgstr "ブレークポイントが定義されていません" #, c-format -msgid "W13: Warning: File \"%s\" has been created after editing started" -msgstr "W13: 警告: ファイル \"%s\" は編集開始後に作成されました" +msgid "%3d %s %s line %" +msgstr "%3d %s %s 行 %" -msgid "Warning" -msgstr "警告" - -msgid "" -"&OK\n" -"&Load File" -msgstr "" -"&OK\n" -"ファイル読込(&L)" +#, c-format +msgid "%3d expr %s" +msgstr "%3d expr %s" #, c-format -msgid "E462: Could not prepare for reloading \"%s\"" -msgstr "E462: \"%s\" をリロードする準備ができませんでした" +msgid "E96: Cannot diff more than % buffers" +msgstr "E96: % 以上のバッファはdiffできません" #, c-format -msgid "E321: Could not reload \"%s\"" -msgstr "E321: \"%s\" はリロードできませんでした" +msgid "Not enough memory to use internal diff for buffer \"%s\"" +msgstr "バッファ \"%s\" 用に内部diffを使うためのメモリが不足しています" -msgid "--Deleted--" -msgstr "--削除済--" +msgid "E810: Cannot read or write temp files" +msgstr "E810: 一時ファイルの読込みもしくは書込みができません" -#, c-format -msgid "auto-removing autocommand: %s " -msgstr "autocommand: %s <バッファ=%d> が自動的に削除されます" +msgid "E97: Cannot create diffs" +msgstr "E97: 差分を作成できません" -#, c-format -msgid "E367: No such group: \"%s\"" -msgstr "E367: そのグループはありません: \"%s\"" +msgid "E960: Problem creating the internal diff" +msgstr "E960: 内部diff作成時に問題が発生しました" -msgid "E936: Cannot delete the current group" -msgstr "E936: 現在のグループは削除できません" +msgid "E816: Cannot read patch output" +msgstr "E816: patchの出力を読込めません" -msgid "W19: Deleting augroup that is still in use" -msgstr "W19: 使用中の augroup を消そうとしています" +msgid "E98: Cannot read diff output" +msgstr "E98: diffの出力を読込めません" -#, c-format -msgid "E215: Illegal character after *: %s" -msgstr "E215: * の後に不正な文字がありました: %s" +msgid "E99: Current buffer is not in diff mode" +msgstr "E99: 現在のバッファは差分モードではありません" -#, c-format -msgid "E216: No such event: %s" -msgstr "E216: そのようなイベントはありません: %s" +msgid "E793: No other buffer in diff mode is modifiable" +msgstr "E793: 差分モードである他のバッファは変更できません" -#, c-format -msgid "E216: No such group or event: %s" -msgstr "E216: そのようなグループもしくはイベントはありません: %s" +msgid "E100: No other buffer in diff mode" +msgstr "E100: 差分モードである他のバッファはありません" -msgid "" -"\n" -"--- Autocommands ---" +msgid "E101: More than two buffers in diff mode, don't know which one to use" msgstr "" -"\n" -"--- Autocommands ---" +"E101: 差分モードのバッファが2個以上あるので、どれを使うか特定できません" #, c-format -msgid "E680: : invalid buffer number " -msgstr "E680: <バッファ=%d>: 無効なバッファ番号です " - -msgid "E217: Can't execute autocommands for ALL events" -msgstr "E217: 全てのイベントに対してのautocommandは実行できません" +msgid "E102: Can't find buffer \"%s\"" +msgstr "E102: バッファ \"%s\" が見つかりません" -msgid "No matching autocommands" -msgstr "該当するautocommandは存在しません" +#, c-format +msgid "E103: Buffer \"%s\" is not in diff mode" +msgstr "E103: バッファ \"%s\" は差分モードではありません" -msgid "E218: autocommand nesting too deep" -msgstr "E218: autocommandの入れ子が深過ぎます" +msgid "E787: Buffer changed unexpectedly" +msgstr "E787: 予期せずバッファが変更されました" #, c-format -msgid "%s Autocommands for \"%s\"" -msgstr "%s Autocommands for \"%s\"" +msgid "E1214: Digraph must be just two characters: %s" +msgstr "E1214: ダイグラフはちょうど2文字でなければなりません: %s" #, c-format -msgid "Executing %s" -msgstr "%s を実行しています" +msgid "E1215: Digraph must be one character: %s" +msgstr "E1215: ダイグラフは1文字でなければなりません: %s" -#, c-format -msgid "autocommand %s" -msgstr "autocommand %s" +msgid "" +"E1216: digraph_setlist() argument must be a list of lists with two items" +msgstr "" +"E1216: digraph_setlist() の引数は2要素のリストのリストでなければなりません" -msgid "E219: Missing {." -msgstr "E219: { がありません." +msgid "E104: Escape not allowed in digraph" +msgstr "E104: 合字にEscapeは使用できません" -msgid "E220: Missing }." -msgstr "E220: } がありません." +msgid "Custom" +msgstr "カスタム" -msgid "E490: No fold found" -msgstr "E490: 折畳みがありません" +msgid "Latin supplement" +msgstr "ラテン補助" -msgid "E350: Cannot create fold with current 'foldmethod'" -msgstr "E350: 現在の 'foldmethod' では折畳みを作成できません" +msgid "Greek and Coptic" +msgstr "ギリシャとコプト" -msgid "E351: Cannot delete fold with current 'foldmethod'" -msgstr "E351: 現在の 'foldmethod' では折畳みを削除できません" +msgid "Cyrillic" +msgstr "キリル" -#, c-format -msgid "+--%3ld line folded " -msgid_plural "+--%3ld lines folded " -msgstr[0] "+--%3ld 行が折畳まれました" +msgid "Hebrew" +msgstr "ヘブライ" -#, c-format -msgid "+-%s%3ld line: " -msgid_plural "+-%s%3ld lines: " -msgstr[0] "+-%s%3ld 行: " +msgid "Arabic" +msgstr "アラビア" -msgid "E222: Add to read buffer" -msgstr "E222: 読込バッファへ追加" +msgid "Latin extended" +msgstr "ラテン拡張" -msgid "E223: recursive mapping" -msgstr "E223: 再帰的マッピング" +msgid "Greek extended" +msgstr "ギリシャ拡張" -msgid "E851: Failed to create a new process for the GUI" -msgstr "E851: GUI用のプロセスの起動に失敗しました" +msgid "Punctuation" +msgstr "句読点" -msgid "E852: The child process failed to start the GUI" -msgstr "E852: 子プロセスがGUIの起動に失敗しました" +msgid "Super- and subscripts" +msgstr "上付き・下付き" -msgid "E229: Cannot start the GUI" -msgstr "E229: GUIを開始できません" +msgid "Currency" +msgstr "通貨記号" -#, c-format -msgid "E230: Cannot read from \"%s\"" -msgstr "E230: \"%s\"から読込むことができません" +msgid "Other" +msgstr "その他" -msgid "E665: Cannot start GUI, no valid font found" -msgstr "E665: 有効なフォントが見つからないので、GUIを開始できません" +msgid "Roman numbers" +msgstr "ローマ数字" -msgid "E231: 'guifontwide' invalid" -msgstr "E231: 'guifontwide' が無効です" +msgid "Arrows" +msgstr "矢印" -msgid "E599: Value of 'imactivatekey' is invalid" -msgstr "E599: 'imactivatekey' に設定された値が無効です" +msgid "Mathematical operators" +msgstr "数学記号" -#, c-format -msgid "E254: Cannot allocate color %s" -msgstr "E254: %s の色を割り当てられません" +msgid "Technical" +msgstr "技術用記号" -msgid "No match at cursor, finding next" -msgstr "カーソルの位置にマッチはありません、次を検索しています" +msgid "Box drawing" +msgstr "罫線素片" -msgid " " -msgstr "<開けません> " +msgid "Block elements" +msgstr "ブロック要素" -#, c-format -msgid "E616: vim_SelFile: can't get font %s" -msgstr "E616: vim_SelFile: フォント %s を取得できません" +msgid "Geometric shapes" +msgstr "幾何学模様" + +msgid "Symbols" +msgstr "記号" + +msgid "Dingbats" +msgstr "装飾記号" -msgid "E614: vim_SelFile: can't return to current directory" -msgstr "E614: vim_SelFile: 現在のディレクトリに戻れません" +msgid "CJK symbols and punctuation" +msgstr "CJK記号及び句読点" -msgid "Pathname:" -msgstr "パス名:" +msgid "Hiragana" +msgstr "平仮名" -msgid "E615: vim_SelFile: can't get current directory" -msgstr "E615: vim_SelFile: 現在のディレクトリを取得できません" +msgid "Katakana" +msgstr "片仮名" -msgid "OK" -msgstr "OK" +msgid "Bopomofo" +msgstr "注音字母" -msgid "Cancel" -msgstr "キャンセル" +msgid "E544: Keymap file not found" +msgstr "E544: キーマップファイルが見つかりません" -msgid "Scrollbar Widget: Could not get geometry of thumb pixmap." -msgstr "スクロールバー: 画像を取得できませんでした。" +msgid "E105: Using :loadkeymap not in a sourced file" +msgstr "E105: :source で取込むファイル以外では :loadkeymap を使えません" -msgid "Vim dialog" -msgstr "Vim ダイアログ" +msgid "E791: Empty keymap entry" +msgstr "E791: 空のキーマップエントリ" -msgid "E232: Cannot create BalloonEval with both message and callback" -msgstr "E232: メッセージとコールバックのある BalloonEval を作成できません" +msgid " TERMINAL" +msgstr "端末" -msgid "_Cancel" -msgstr "キャンセル(_C)" +msgid " VREPLACE" +msgstr " 仮想置換" -msgid "_Save" -msgstr "保存(_S)" +msgid " REPLACE" +msgstr " 置換" -msgid "_Open" -msgstr "開く(_O)" +msgid " REVERSE" +msgstr " 反転" -msgid "_OK" -msgstr "_OK" +msgid " INSERT" +msgstr " 挿入" -msgid "" -"&Yes\n" -"&No\n" -"&Cancel" -msgstr "" -"はい(&Y)\n" -"いいえ(&N)\n" -"キャンセル(&C)" +msgid " (terminal)" +msgstr "(端末)" -msgid "Yes" -msgstr "はい" +msgid " (insert)" +msgstr " (挿入)" -msgid "No" -msgstr "いいえ" +msgid " (replace)" +msgstr " (置換)" -msgid "Input _Methods" -msgstr "インプットメソッド" +msgid " (vreplace)" +msgstr " (仮想置換)" -msgid "VIM - Search and Replace..." -msgstr "VIM - 検索と置換..." +msgid " Arabic" +msgstr " アラビア" -msgid "VIM - Search..." -msgstr "VIM - 検索..." +msgid " (paste)" +msgstr " (貼り付け)" -msgid "Find what:" -msgstr "検索文字列:" +msgid " VISUAL" +msgstr " ビジュアル" -msgid "Replace with:" -msgstr "置換文字列:" +msgid " VISUAL LINE" +msgstr " ビジュアル 行" -msgid "Match whole word only" -msgstr "正確に該当するものだけ" +msgid " VISUAL BLOCK" +msgstr " ビジュアル 矩形" -msgid "Match case" -msgstr "大文字/小文字を区別する" +msgid " SELECT" +msgstr " セレクト" -msgid "Direction" -msgstr "方向" +msgid " SELECT LINE" +msgstr " 行指向選択" -msgid "Up" -msgstr "上" +msgid " SELECT BLOCK" +msgstr " 矩形選択" -msgid "Down" -msgstr "下" +msgid "recording" +msgstr "記録中" -msgid "Find Next" -msgstr "次を検索" +msgid "E111: Missing ']'" +msgstr "E111: ']' が見つかりません" -msgid "Replace" -msgstr "置換" +#, c-format +msgid "E697: Missing end of List ']': %s" +msgstr "E697: リスト型の最後に ']' がありません: %s" -msgid "Replace All" -msgstr "全て置換" +msgid "E719: Cannot slice a Dictionary" +msgstr "E719: 辞書型はスライスできません" -msgid "_Close" -msgstr "閉じる(_C)" +msgid "E909: Cannot index a special variable" +msgstr "E909: 特殊変数はインデックスできません" -msgid "Vim: Received \"die\" request from session manager\n" -msgstr "Vim: セッションマネージャから \"die\" 要求を受け取りました\n" +msgid "E274: No white space allowed before parenthesis" +msgstr "E274: 丸括弧の前にスペースは許されません" -msgid "Close tab" -msgstr "タブページを閉じる" +#, c-format +msgid "E80: Error while writing: %s" +msgstr "E80: 書込み中のエラー: %s" -msgid "New tab" -msgstr "新規タブページ" +msgid "E695: Cannot index a Funcref" +msgstr "E695: 関数参照型はインデックスできません" -msgid "Open Tab..." -msgstr "タブページを開く..." +msgid "E698: Variable nested too deep for making a copy" +msgstr "E698: コピーを取るには変数の入れ子が深過ぎます" -msgid "Vim: Main window unexpectedly destroyed\n" -msgstr "Vim: メインウィンドウが不意に破壊されました\n" +msgid "E1098: String, List or Blob required" +msgstr "E1098: 文字列型、リスト型またはBlob型が必要です" -msgid "&Filter" -msgstr "フィルタ(&F)" +#, c-format +msgid "E1169: Expression too recursive: %s" +msgstr "E1169: 式の再帰が深すぎます: %s" -msgid "&Cancel" -msgstr "キャンセル(&C)" +#, c-format +msgid "E1203: Dot can only be used on a dictionary: %s" +msgstr "E1203: ドットは辞書型でのみ使用できます: %s" -msgid "Directories" -msgstr "ディレクトリ" +msgid "E1192: Empty function name" +msgstr "E1192: 関数名が空です" -msgid "Filter" -msgstr "フィルタ" +#, c-format +msgid "E1250: Argument of %s must be a List, String, Dictionary or Blob" +msgstr "E1250: %s の引数はリスト、文字列、辞書またはBlobでなければなりません" -msgid "&Help" -msgstr "ヘルプ(&H)" +msgid "" +"E5700: Expression from 'spellsuggest' must yield lists with exactly two " +"values" +msgstr "" +"E5700: 'spellsuggest'からの式は正確に2つの値を持つリストを返す必要があります" -msgid "Files" -msgstr "ファイル" +#, c-format +msgid "E121: Undefined variable: %.*s" +msgstr "E121: 未定義の変数です: %.*s" -msgid "&OK" -msgstr "&OK" +msgid "E689: Can only index a List, Dictionary or Blob" +msgstr "E689: リスト型、辞書型またはBlob型のみインデックスできます" -msgid "Selection" -msgstr "選択" +msgid "E708: [:] must come last" +msgstr "E708: [:] は最後でなければいけません" -msgid "Find &Next" -msgstr "次を検索(&N)" +msgid "E713: Cannot use empty key after ." +msgstr "E713: . の後に空のキーを使うことはできません" -msgid "&Replace" -msgstr "置換(&R)" +msgid "E709: [:] requires a List or Blob value" +msgstr "E709: [:] にはリスト型かBlob型の値が必要です" -msgid "Replace &All" -msgstr "全て置換(&A)" +msgid "E996: Cannot lock a range" +msgstr "E996: 範囲はロックできません" -msgid "&Undo" -msgstr "アンドゥ(&U)" +msgid "E996: Cannot lock a list or dict" +msgstr "E996: リストあるいは辞書はロックできません" -msgid "Open tab..." -msgstr "タブページを開く" +msgid "E690: Missing \"in\" after :for" +msgstr "E690: :for の後に \"in\" がありません" -msgid "Find string (use '\\\\' to find a '\\')" -msgstr "検索文字列 ('\\' を検索するには '\\\\')" +msgid "E109: Missing ':' after '?'" +msgstr "E109: '?' の後に ':' がありません" -msgid "Find & Replace (use '\\\\' to find a '\\')" -msgstr "検索・置換 ('\\' を検索するには '\\\\')" +msgid "E804: Cannot use '%' with Float" +msgstr "E804: '%' を浮動小数点数と組み合わせては使えません" -msgid "Not Used" -msgstr "使われません" +msgid "E110: Missing ')'" +msgstr "E110: ')' が見つかりません" -msgid "Directory\t*.nothing\n" -msgstr "ディレクトリ\t*.nothing\n" +msgid "E260: Missing name after ->" +msgstr "E260: -> の後に名前がありません" #, c-format -msgid "E671: Cannot find window title \"%s\"" -msgstr "E671: タイトルが \"%s\" のウィンドウは見つかりません" +msgid "E112: Option name missing: %s" +msgstr "E112: オプション名がありません: %s" #, c-format -msgid "E243: Argument not supported: \"-%s\"; Use the OLE version." -msgstr "E243: 引数はサポートされません: \"-%s\"; OLE版を使用してください." - -msgid "E672: Unable to open window inside MDI application" -msgstr "E672: MDIアプリの中ではウィンドウを開けません" +msgid "E113: Unknown option: %s" +msgstr "E113: 未知のオプションです: %s" -msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect" -msgstr "Vim E458: 色指定が正しくないのでエントリを割り当てられません" +msgid "E973: Blob literal should have an even number of hex characters" +msgstr "E973: Blobリテラルは偶数個の16進数文字でなければなりません" #, c-format -msgid "E250: Fonts for the following charsets are missing in fontset %s:" -msgstr "E250: 以下の文字セットのフォントがありません %s:" +msgid "E114: Missing quote: %s" +msgstr "E114: クォートがありません: %s" #, c-format -msgid "E252: Fontset name: %s" -msgstr "E252: フォントセット名: %s" +msgid "E115: Missing quote: %s" +msgstr "E115: クォートがありません: %s" #, c-format -msgid "Font '%s' is not fixed-width" -msgstr "フォント '%s' は固定幅ではありません" +msgid "E696: Missing comma in List: %s" +msgstr "E696: リスト型にコンマがありません: %s" -#, c-format -msgid "E253: Fontset name: %s" -msgstr "E253: フォントセット名: %s" +msgid "Not enough memory to set references, garbage collection aborted!" +msgstr "" +"ガーベッジコレクションを中止しました! 参照を作成するのにメモリが不足しました" #, c-format -msgid "Font0: %s" -msgstr "フォント0: %s" +msgid "E720: Missing colon in Dictionary: %s" +msgstr "E720: 辞書型にコロンがありません: %s" #, c-format -msgid "Font1: %s" -msgstr "フォント1: %s" +msgid "E721: Duplicate key in Dictionary: \"%s\"" +msgstr "E721: 辞書型に重複キーがあります: \"%s\"" #, c-format -msgid "Font%ld width is not twice that of font0" -msgstr "フォント%ld の幅がフォント0の2倍ではありません" +msgid "E722: Missing comma in Dictionary: %s" +msgstr "E722: 辞書型にコンマがありません: %s" #, c-format -msgid "Font0 width: %ld" -msgstr "フォント0の幅: %ld" +msgid "E723: Missing end of Dictionary '}': %s" +msgstr "E723: 辞書型の最後に '}' がありません: %s" + +msgid "map() argument" +msgstr "map() の引数" + +msgid "mapnew() argument" +msgstr "mapnew() の引数" + +msgid "filter() argument" +msgstr "filter() の引数" + +msgid "foreach() argument" +msgstr "foreach() の引数" #, c-format -msgid "Font1 width: %ld" -msgstr "フォント1の幅: %ld" +msgid "E700: Unknown function: %s" +msgstr "E700: 未知の関数です: %s" -msgid "Invalid font specification" -msgstr "無効なフォント指定です" +msgid "E923: Second argument of function() must be a list or a dict" +msgstr "E923: function() の第 2 引数はリスト型または辞書型でなければなりません" -msgid "&Dismiss" -msgstr "却下する(&D)" +msgid "E5050: {opts} must be the only argument" +msgstr "E5050: {opts} は唯一の引数でなければなりません" -msgid "no specific match" -msgstr "マッチするものがありません" +#, c-format +msgid "Executing command: \"%s\"" +msgstr "コマンドを実行中: %s" -msgid "Vim - Font Selector" -msgstr "Vim - フォント選択" +msgid "E921: Invalid callback argument" +msgstr "E921: 無効なコールバック引数です" -msgid "Name:" -msgstr "名前:" +msgid "" +"\n" +"\tLast set from " +msgstr "" +"\n" +"\t最後にセットしたスクリプト: " -msgid "Show size in Points" -msgstr "サイズをポイントで表示する" +msgid "E977: Can only compare Blob with Blob" +msgstr "E977: Blob型はBlob型としか比較できません" -msgid "Encoding:" -msgstr "エンコード:" +msgid "E691: Can only compare List with List" +msgstr "E691: リスト型はリスト型としか比較できません" -msgid "Font:" -msgstr "フォント:" +msgid "E692: Invalid operation for List" +msgstr "E692: リスト型には無効な操作です" -msgid "Style:" -msgstr "スタイル:" +msgid "E735: Can only compare Dictionary with Dictionary" +msgstr "E735: 辞書型は辞書型としか比較できません" -msgid "Size:" -msgstr "サイズ:" +msgid "E736: Invalid operation for Dictionary" +msgstr "E736: 辞書型には無効な操作です" -msgid "E256: Hangul automata ERROR" -msgstr "E256: ハングルオートマトンエラー" +msgid "E694: Invalid operation for Funcrefs" +msgstr "E694: 関数参照型には無効な操作です" #, c-format -msgid "E799: Invalid ID: %d (must be greater than or equal to 1)" -msgstr "E799: 無効な ID: %d (1 以上でなければなりません)" +msgid "E474: Expected comma before list item: %s" +msgstr "E474: リストの要素の前にコンマが必要です: %s" #, c-format -msgid "E801: ID already taken: %d" -msgstr "E801: ID はすでに利用中です: %d" +msgid "E474: Expected colon before dictionary value: %s" +msgstr "E474: 辞書型の値の前にコロンが必要です: %s" #, c-format -msgid "E802: Invalid ID: %d (must be greater than or equal to 1)" -msgstr "E802: 無効な ID: %d (1 以上でなければなりません)" +msgid "E474: Expected string key: %s" +msgstr "E474: 文字列のキーが必要です: %s" #, c-format -msgid "E803: ID not found: %d" -msgstr "E803: ID はありません: %d" +msgid "E474: Expected comma before dictionary key: %s" +msgstr "E474: 辞書型のキー前ににコンマが必要です: %s" #, c-format -msgid "E798: ID is reserved for \":match\": %d" -msgstr "E798: ID は \":match\" のために予約されています: %d" +msgid "E474: Unfinished escape sequence: %.*s" +msgstr "E474: 不完全なエスケープシーケンス: %.*s" -msgid "Add a new database" -msgstr "新データベースを追加" +#, c-format +msgid "E474: Unfinished unicode escape sequence: %.*s" +msgstr "E474: 不完全な Unicode エスケープシーケンス: %.*s" -msgid "Query for a pattern" -msgstr "パターンのクエリーを追加" +#, c-format +msgid "E474: Expected four hex digits after \\u: %.*s" +msgstr "E474: \\uの後に4桁の16進数が必要です: %.*s" -msgid "Show this message" -msgstr "このメッセージを表示する" +#, c-format +msgid "E474: Unknown escape sequence: %.*s" +msgstr "E474: 未知のエスケープシーケンス: %.*s" -msgid "Kill a connection" -msgstr "接続を終了する" +#, c-format +msgid "E474: ASCII control characters cannot be present inside string: %.*s" +msgstr "E474: ASCII 制御文字は文字列内に存在できません: %.*s" -msgid "Reinit all connections" -msgstr "全ての接続を再初期化する" +#, c-format +msgid "E474: Only UTF-8 strings allowed: %.*s" +msgstr "E474: UTF-8 文字列のみが使用可能です: %.*s" -msgid "Show connections" -msgstr "接続を表示する" +#, c-format +msgid "" +"E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: " +"%.*s" +msgstr "" +"E474: U+10FFFF までの UTF-8 コードポイントのみがエスケープなしで表示できま" +"す: %.*s" #, c-format -msgid "E560: Usage: cs[cope] %s" -msgstr "E560: 使用方法: cs[cope] %s" +msgid "E474: Expected string end: %.*s" +msgstr "E474: \" が必要です: %.*s" -msgid "This cscope command does not support splitting the window.\n" -msgstr "このcscopeコマンドは分割ウィンドウではサポートされません.\n" +#, c-format +msgid "E474: Leading zeroes are not allowed: %.*s" +msgstr "E474: 先頭にゼロは使用できません: %.*s" -msgid "E562: Usage: cstag " -msgstr "E562: 使用法: cstag " +#, c-format +msgid "E474: Missing number after minus sign: %.*s" +msgstr "E474: マイナス記号の後に数字がありません: %.*s" -msgid "E257: cstag: tag not found" -msgstr "E257: cstag: タグが見つかりません" +#, c-format +msgid "E474: Missing number after decimal dot: %.*s" +msgstr "E474: 小数点の後に数字がありません: %.*s" #, c-format -msgid "E563: stat(%s) error: %d" -msgstr "E563: stat(%s) エラー: %d" +msgid "E474: Missing exponent: %.*s" +msgstr "E474: 指数がありません: %.*s" -msgid "E563: stat error" -msgstr "E563: stat エラー" +#, fuzzy, c-format +msgid "" +"E685: internal error: while converting number \"%.*s\" to float string2float " +"consumed %zu bytes in place of %zu" +msgstr "" +"E685: 内部エラー: 数値\"%.*s\" をfloat型に変換中 string2float は %zu を %zu " +"バイトの代わりに消費しました" -#, c-format -msgid "E564: %s is not a directory or a valid cscope database" -msgstr "E564: %s はディレクトリ及び有効なcscopeのデータベースではありません" +#, fuzzy, c-format +msgid "" +"E685: internal error: while converting number \"%.*s\" to integer vim_str2nr " +"consumed %i bytes in place of %zu" +msgstr "" +"E685: 内部エラー: 数値\"%.*s\" をint型に変換中 vim_str2nr は %zu の代わりに " +"%i バイトを消費しました" + +msgid "E474: Attempt to decode a blank string" +msgstr "E474: 空の文字列のデコードを試みました" #, c-format -msgid "Added cscope database %s" -msgstr "cscopeデータベース %s を追加" +msgid "E474: No container to close: %.*s" +msgstr "E474: 閉じるコンテナがありません: %.*s" #, c-format -msgid "E262: error reading cscope connection %ld" -msgstr "E262: cscopeの接続 %ld を読込み中のエラーです" +msgid "E474: Closing list with curly bracket: %.*s" +msgstr "E474: リスト型を波括弧で閉じています: %.*s" -msgid "E561: unknown cscope search type" -msgstr "E561: 未知のcscope検索型です" +#, c-format +msgid "E474: Closing dictionary with square bracket: %.*s" +msgstr "E474: 辞書型を角括弧で閉じています: %.*s" -msgid "E566: Could not create cscope pipes" -msgstr "E566: cscopeパイプを作成できませんでした" +#, c-format +msgid "E474: Trailing comma: %.*s" +msgstr "E474: 余分なコンマが後ろにあります: %.*s" -msgid "E622: Could not fork for cscope" -msgstr "E622: cscopeの起動準備(fork)に失敗しました" +#, c-format +msgid "E474: Expected value after colon: %.*s" +msgstr "E474: コロンの後に値が必要です: %.*s" -msgid "cs_create_connection setpgid failed" -msgstr "cs_create_connection への setpgid に失敗しました" +#, c-format +msgid "E474: Expected value: %.*s" +msgstr "E474: 値が必要です: %.*s" -msgid "cs_create_connection exec failed" -msgstr "cs_create_connection の実行に失敗しました" +#, c-format +msgid "E474: Comma not inside container: %.*s" +msgstr "E474: コンマがコンテナ内にありません: %.*s" -msgid "cs_create_connection: fdopen for to_fp failed" -msgstr "cs_create_connection: to_fp の fdopen に失敗しました" +#, c-format +msgid "E474: Duplicate comma: %.*s" +msgstr "E474: コンマが重複しています: %.*s" -msgid "cs_create_connection: fdopen for fr_fp failed" -msgstr "cs_create_connection: fr_fp の fdopen に失敗しました" +#, c-format +msgid "E474: Comma after colon: %.*s" +msgstr "E474: コロンの後にコンマがあります: %.*s" -msgid "E623: Could not spawn cscope process" -msgstr "E623: cscopeプロセスを起動できませんでした" +#, c-format +msgid "E474: Using comma in place of colon: %.*s" +msgstr "E474: コロンではなくコンマを使用しています: %.*s" -msgid "E567: no cscope connections" -msgstr "E567: cscope接続に失敗しました" +#, c-format +msgid "E474: Leading comma: %.*s" +msgstr "E474: 余分なコンマが前にあります: %.*s" #, c-format -msgid "E469: invalid cscopequickfix flag %c for %c" -msgstr "E469: 無効な cscopequickfix フラグ %c の %c です" +msgid "E474: Colon not inside container: %.*s" +msgstr "E474: コロンがコンテナ内にありません: %.*s" #, c-format -msgid "E259: no matches found for cscope query %s of %s" -msgstr "E259: cscopeクエリー %s of %s に該当がありませんでした" +msgid "E474: Using colon not in dictionary: %.*s" +msgstr "E474: 辞書にないコロンを使用しています: %.*s" -msgid "cscope commands:\n" -msgstr "cscopeコマンド:\n" +#, c-format +msgid "E474: Unexpected colon: %.*s" +msgstr "E474: 予期しないコロンです: %.*s" #, c-format -msgid "%-5s: %s%*s (Usage: %s)" -msgstr "%-5s: %s%*s (使用法: %s)" +msgid "E474: Colon after comma: %.*s" +msgstr "E474: コンマの後にコロンがあります: %.*s" -msgid "" -"\n" -" a: Find assignments to this symbol\n" -" c: Find functions calling this function\n" -" d: Find functions called by this function\n" -" e: Find this egrep pattern\n" -" f: Find this file\n" -" g: Find this definition\n" -" i: Find files #including this file\n" -" s: Find this C symbol\n" -" t: Find this text string\n" -msgstr "" -"\n" -" a: このシンボルに対する代入を探す\n" -" c: この関数を呼んでいる関数を探す\n" -" d: この関数から呼んでいる関数を探す\n" -" e: このegrepパターンを探す\n" -" f: このファイルを探す\n" -" g: この定義を探す\n" -" i: このファイルを#includeしているファイルを探す\n" -" s: このCシンボルを探す\n" -" t: このテキスト文字列を探す\n" +#, c-format +msgid "E474: Duplicate colon: %.*s" +msgstr "E474: コロンが重複しています: %.*s" #, c-format -msgid "E625: cannot open cscope database: %s" -msgstr "E625: cscopeデータベース: %s を開くことができません" +msgid "E474: Expected null: %.*s" +msgstr "E474: null が必要です: %.*s" -msgid "E626: cannot get cscope database information" -msgstr "E626: cscopeデータベースの情報を取得できません" +#, c-format +msgid "E474: Expected true: %.*s" +msgstr "E474: true が必要です: %.*s" -msgid "E568: duplicate cscope database not added" -msgstr "E568: 重複するcscopeデータベースは追加されませんでした" +#, c-format +msgid "E474: Expected false: %.*s" +msgstr "E474: false が必要です: %.*s" #, c-format -msgid "E261: cscope connection %s not found" -msgstr "E261: cscope接続 %s が見つかりませんでした" +msgid "E474: Unidentified byte: %.*s" +msgstr "E474: 未定義のバイトです: %.*s" #, c-format -msgid "cscope connection %s closed" -msgstr "cscope接続 %s が閉じられました" +msgid "E474: Trailing characters: %.*s" +msgstr "E474: 余分な文字が後ろにあります: %.*s" -msgid "E570: fatal error in cs_manage_matches" -msgstr "E570: cs_manage_matches で致命的なエラーです" +#, c-format +msgid "E474: Unexpected end of input: %.*s" +msgstr "E474: 予期しない入力の終了: %.*s" #, c-format -msgid "Cscope tag: %s" -msgstr "Cscope タグ: %s" +msgid "key %s" +msgstr "キー %s" -msgid "" -"\n" -" # line" -msgstr "" -"\n" -" # 行番号" +#, fuzzy, c-format +#~ msgid "key %s at index %i from special map" +#~ msgstr "カスタムマップからのインデックス %i のキー %s" + +#, c-format +msgid "index %i" +msgstr "インデックス %i" -msgid "filename / context / line\n" -msgstr "ファイル名 / 文脈 / 行\n" +msgid "partial" +msgstr "部分的" #, c-format -msgid "E609: Cscope error: %s" -msgstr "E609: cscopeエラー: %s" +msgid "argument %i" +msgstr "引数 %i" -msgid "All cscope databases reset" -msgstr "全てのcscopeデータベースをリセットします" +#, fuzzy +#~ msgid "partial self dictionary" +#~ msgstr "部分的なセルフ辞書" -msgid "no cscope connections\n" -msgstr "cscope接続がありません\n" +#, fuzzy +#~ msgid "itself" +#~ msgstr "自身" -msgid " # pid database name prepend path\n" -msgstr " # pid データベース名 prepend パス\n" +msgid "E724: unable to correctly dump variable with self-referencing container" +msgstr "E724: 自らを参照するコンテナの変数を正しくダンプできませんでした" -msgid "Lua library cannot be loaded." -msgstr "Luaライブラリをロードできません。" +msgid "E474: Unable to represent NaN value in JSON" +msgstr "E474: JSON は NaN に対応していません" -msgid "cannot save undo information" -msgstr "アンドゥ情報が保存できません" +msgid "E474: Unable to represent infinity in JSON" +msgstr "E474: JSON は無限大に対応していません" +#, c-format msgid "" -"E815: Sorry, this command is disabled, the MzScheme libraries could not be " -"loaded." -msgstr "E815: このコマンドは無効です。MzScheme ライブラリをロードできません。" +"E474: String \"%.*s\" contains byte that does not start any UTF-8 character" +msgstr "" +"E474: 文字列 \"%.*s\" には UTF-8 文字で始まらないバイトが含まれています" +#, c-format msgid "" -"E895: Sorry, this command is disabled, the MzScheme's racket/base module " -"could not be loaded." +"E474: UTF-8 string contains code point which belongs to a surrogate pair: " +"%.*s" msgstr "" -"E895: このコマンドは無効です、ごめんなさい。MzScheme の racket/base モジュー" -"ルがロードできませんでした。" +"E474: UTF-8 文字列にサロゲートペアに属するコードポイントが含まれています: " +"%.*s" -msgid "invalid expression" -msgstr "無効な式です" +msgid "E474: Unable to convert EXT string to JSON" +msgstr "E474: EXT 文字列を JSON に変換できません" -msgid "expressions disabled at compile time" -msgstr "式はコンパイル時に無効にされています" +#, c-format +msgid "E474: Error while dumping %s, %s: attempt to dump function reference" +msgstr "" +"E474: %s のダンプ中にエラーが発生しました, %s: 関数参照をダンプしようとしまし" +"た" -msgid "hidden option" -msgstr "隠しオプション" +msgid "E474: Invalid key in special dictionary" +msgstr "E474: ユーザー辞書のキーが無効です" -msgid "unknown option" -msgstr "未知のオプションです" +msgid "encode_tv2string() argument" +msgstr "encode_tv2string() の引数" -msgid "window index is out of range" -msgstr "範囲外のウィンドウ番号です" +msgid ":echo argument" +msgstr ":echo の引数" -msgid "couldn't open buffer" -msgstr "バッファを開けません" +msgid "encode_tv2json() argument" +msgstr "encode_tv2json() の引数" -msgid "cannot delete line" -msgstr "行を消せません" +#, c-format +msgid "E5004: Error while dumping %s, %s: attempt to dump function reference" +msgstr "" +"E5004: %s のダンプ中にエラーが発生しました, %s: 関数参照をダンプしようとしま" +"した" -msgid "cannot replace line" -msgstr "行を置換できません" +#, c-format +msgid "E5005: Unable to dump %s: container references itself in %s" +msgstr "E5005: %s をダンプできません: コンテナは %s で自身を参照しています" -msgid "cannot insert line" -msgstr "行を挿入できません" +#, c-format +msgid "E684: List index out of range: %" +msgstr "E684: リストのインデックスが範囲外です: %" -msgid "string cannot contain newlines" -msgstr "文字列には改行文字を含められません" +#, c-format +msgid "E899: Argument of %s must be a List or Blob" +msgstr "E899: %s の引数はリスト型またはBlob型でなければなりません" -msgid "error converting Scheme values to Vim" -msgstr "Scheme値のVimへの変換エラー" +msgid "E957: Invalid window number" +msgstr "E957: 無効なウィンドウ番号です" -msgid "Vim error: ~a" -msgstr "Vim エラー: ~a" +#, c-format +msgid "E706: Argument of %s must be a List, String or Dictionary" +msgstr "E706: %s の引数はリスト型、文字列または辞書型でなければなりません" -msgid "Vim error" -msgstr "Vim エラー" +#, c-format +msgid "E935: Invalid submatch number: %d" +msgstr "E935: 無効なサブマッチ番号です: %d" -msgid "buffer is invalid" -msgstr "バッファは無効です" +#, c-format +msgid "E998: Reduce of an empty %s with no initial value" +msgstr "E998: reduce が初期値無しで空の %s で呼ばれました" -msgid "window is invalid" -msgstr "ウィンドウは無効です" +msgid "E1132: Missing function argument" +msgstr "E1132: 引数に関数がありません" -msgid "linenr out of range" -msgstr "範囲外の行番号です" +msgid "add() argument" +msgstr "add() の引数" -msgid "not allowed in the Vim sandbox" -msgstr "サンドボックスでは許されません" +#, c-format +msgid "E158: Invalid buffer name: %s" +msgstr "E158: 無効なバッファ名です: %s" #, c-format -msgid "E370: Could not load library %s" -msgstr "E370: ライブラリ %s をロードできませんでした" +msgid "Invalid channel stream \"%s\"" +msgstr "無効なチャネル ストリーム \"%s\"" -msgid "Sorry, this command is disabled: the Perl library could not be loaded." -msgstr "" -"このコマンドは無効です、ごめんなさい: Perlライブラリをロードできませんでした." - -msgid "E299: Perl evaluation forbidden in sandbox without the Safe module" -msgstr "" -"E299: サンドボックスでは Safe モジュールを使用しないPerlスクリプトは禁じられ" -"ています" +msgid "&Ok" +msgstr "&Ok" -msgid "E836: This Vim cannot execute :python after using :py3" -msgstr "E836: このVimでは :py3 を使った後に :python を使えません" +msgid "Context stack is empty" +msgstr "コンテキストスタックは空です" -msgid "" -"E263: Sorry, this command is disabled, the Python library could not be " -"loaded." -msgstr "" -"E263: このコマンドは無効です、ごめんなさい: Pythonライブラリをロードできませ" -"んでした。" +msgid "dictwatcheradd() argument" +msgstr "dictwatcheradd() の引数" -msgid "" -"E887: Sorry, this command is disabled, the Python's site module could not be " -"loaded." -msgstr "" -"E887: このコマンドは無効です、ごめんなさい。Python の site モジュールをロード" -"できませんでした。" +msgid "E900: maxdepth must be non-negative number" +msgstr "E900: maxdepth は非負数でなければなりません" -# Added at 07-Feb-2004. -msgid "E659: Cannot invoke Python recursively" -msgstr "E659: Python を再帰的に実行することはできません" +msgid "flatten() argument" +msgstr "flatten() の引数" -msgid "E837: This Vim cannot execute :py3 after using :python" -msgstr "E837: このVimでは :python を使った後に :py3 を使えません" +msgid "extend() argument" +msgstr "extend() の引数" -msgid "E265: $_ must be an instance of String" -msgstr "E265: $_ は文字列のインスタンスでなければなりません" +msgid "extendnew() argument" +msgstr "extendnew() の引数" -msgid "" -"E266: Sorry, this command is disabled, the Ruby library could not be loaded." -msgstr "" -"E266: このコマンドは無効です、ごめんなさい: Rubyライブラリをロードできません" -"でした。" +msgid "E5000: Cannot find tab number." +msgstr "E5000: タブ番号が見つかりません" -msgid "E267: unexpected return" -msgstr "E267: 予期せぬ return です" +#, fuzzy +#~ msgid "E5001: Higher scope cannot be -1 if lower scope is >= 0." +#~ msgstr "E5001: 低いスコープが 0 以上の場合高いスコープは -1 を指定できません" -msgid "E268: unexpected next" -msgstr "E268: 予期せぬ next です" +msgid "E5002: Cannot find window number." +msgstr "E5002: ウィンドウ番号が見つかりません" -msgid "E269: unexpected break" -msgstr "E269: 予期せぬ break です" +msgid "called inputrestore() more often than inputsave()" +msgstr "inputrestore() が inputsave() よりも多く呼ばれました" -msgid "E270: unexpected redo" -msgstr "E270: 予期せぬ redo です" +msgid "insert() argument" +msgstr "insert() の引数" -msgid "E271: retry outside of rescue clause" -msgstr "E271: rescue の外の retry です" +msgid "E786: Range not allowed" +msgstr "E786: 範囲指定は許可されていません" -msgid "E272: unhandled exception" -msgstr "E272: 取り扱われなかった例外があります" +msgid "E474: Failed to convert list to string" +msgstr "E474: リスト型の文字列への変換に失敗しました" #, c-format -msgid "E273: unknown longjmp status %d" -msgstr "E273: 未知のlongjmp状態: %d" +msgid "E474: Failed to parse %.*s" +msgstr "E474: 構文解析に失敗しました: %.*s" -msgid "invalid buffer number" -msgstr "無効なバッファ番号です" +msgid "E701: Invalid type for len()" +msgstr "E701: len() には無効な型です" -msgid "not implemented yet" -msgstr "まだ実装されていません" +#, fuzzy, c-format +#~ msgid "msgpackdump() argument, index %i" +#~ msgstr "msgpackdump() の引数, インデックス %i" -msgid "cannot set line(s)" -msgstr "行を設定できません" +msgid "E5070: Character number must not be less than zero" +msgstr "E5070: 文字番号は 0 未満でなければなりません" -msgid "invalid mark name" -msgstr "無効なマーク名です" +#, c-format +msgid "E5071: Character number must not be greater than INT_MAX (%i)" +msgstr "E5071: 文字番号は INT_MAX (%i) より大きくてはなりません" -msgid "mark not set" -msgstr "マークは設定されていません" +msgid "E726: Stride is zero" +msgstr "E726: ストライド(前進量)が 0 です" -#, c-format -msgid "row %d column %d" -msgstr "行 %d 列 %d" +msgid "E727: Start past end" +msgstr "E727: 開始位置が終了位置を越えました" -msgid "cannot insert/append line" -msgstr "行の挿入/追加をできません" +msgid "" +msgstr "<空>" -msgid "line number out of range" -msgstr "範囲外の行番号です" +msgid "remove() argument" +msgstr "remove() の引数" -msgid "unknown flag: " -msgstr "未知のフラグ: " +msgid "E655: Too many symbolic links (cycle?)" +msgstr "E655: シンボリックリンクが多過ぎます (循環している可能性があります)" -msgid "unknown vimOption" -msgstr "未知の vimOption です" +msgid "reverse() argument" +msgstr "reverse() の引数" -msgid "keyboard interrupt" -msgstr "キーボード割込み" +#, fuzzy, c-format +#~ msgid "E5010: List item %d of the second argument is not a string" +#~ msgstr "E5010: リスト項目 %d の二つ目の引数は文字列ではありません" -msgid "cannot create buffer/window command: object is being deleted" -msgstr "" -"バッファ/ウィンドウ作成コマンドを作成できません: オブジェクトが消去されていま" -"した" +#, c-format +msgid "E962: Invalid action: '%s'" +msgstr "E962: 無効な操作です: '%s'" -msgid "" -"cannot register callback command: buffer/window is already being deleted" -msgstr "" -"コールバックコマンドを登録できません: バッファ/ウィンドウが既に消去されました" +#, c-format +msgid "connection failed: %s" +msgstr "接続に失敗しました: %s" -msgid "" -"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim." -"org" -msgstr "" -"E280: TCL 致命的エラー: reflist 汚染!? vim-dev@vim.org に報告してください" +#, c-format +msgid "E6100: \"%s\" is not a valid stdpath" +msgstr "E6100: \"%s\" は有効な stdpath ではありません" -msgid "cannot register callback command: buffer/window reference not found" -msgstr "" -"コールバックコマンドを登録できません: バッファ/ウィンドウの参照が見つかりませ" -"ん" +msgid "(Invalid)" +msgstr "(無効)" -msgid "" -"E571: Sorry, this command is disabled: the Tcl library could not be loaded." -msgstr "" -"E571: このコマンドは無効です、ごめんなさい: Tclライブラリをロードできませんで" -"した。" +msgid "Can only call this function in an unmodified buffer" +msgstr "この関数は未変更のバッファ内でのみ呼び出すことができます" -#, c-format -msgid "E572: exit code %d" -msgstr "E572: 終了コード %d" +msgid "writefile() first argument must be a List or a Blob" +msgstr "writefile() の第1引数はリスト型またはBlob型でなければなりません" -msgid "cannot get line" -msgstr "行を取得できません" +#, c-format +msgid "E5060: Unknown flag: %s" +msgstr "E5060: 未知のフラグ: %s" -msgid "Unable to register a command server name" -msgstr "命令サーバーの名前を登録できません" +msgid "E482: Can't open file with an empty name" +msgstr "E482: 空の名前のファイルは開けません" -msgid "E248: Failed to send command to the destination program" -msgstr "E248: 目的のプログラムへのコマンド送信に失敗しました" +#, c-format +msgid "E482: Can't open file %s for writing: %s" +msgstr "E482: %s を書込み用として開けません: %s" #, c-format -msgid "E573: Invalid server id used: %s" -msgstr "E573: 無効なサーバーIDが使われました: %s" +msgid "E80: Error when closing file %s: %s" +msgstr "E80: %s を閉じる時にエラーです: %s" + +msgid "E743: Variable nested too deep for (un)lock" +msgstr "E743: (アン)ロックするには変数の入れ子が深過ぎます" -msgid "E251: VIM instance registry property is badly formed. Deleted!" -msgstr "E251: VIM 実体の登録プロパティが不正です. 消去しました!" +msgid "E908: Using an invalid value as a String" +msgstr "E908: 無効な値を文字列として扱っています" #, c-format -msgid "E938: Duplicate key in JSON: \"%s\"" -msgstr "E938: JSONに重複キーがあります: \"%s\"" +msgid "E1174: String required for argument %d" +msgstr "E1174: 引数 %d には文字列が必要です" #, c-format -msgid "E899: Argument of %s must be a List or Blob" -msgstr "E899: %s の引数はリスト型またはBlob型でなければなりません" +msgid "E1175: Non-empty string required for argument %d" +msgstr "E1175: 引数 %d には空ではない文字列が必要です" #, c-format -msgid "E696: Missing comma in List: %s" -msgstr "E696: リスト型にカンマがありません: %s" +msgid "E1206: Dictionary required for argument %d" +msgstr "E1206: 引数 %d には辞書型が必要です" #, c-format -msgid "E697: Missing end of List ']': %s" -msgstr "E697: リスト型の最後に ']' がありません: %s" +msgid "E1210: Number required for argument %d" +msgstr "E1210: 引数 %d には数値が必要です" -msgid "Unknown option argument" -msgstr "未知のオプション引数です" +#, c-format +msgid "E1211: List required for argument %d" +msgstr "E1211: 引数 %d にはリスト型が必要です" -msgid "Too many edit arguments" -msgstr "編集引数が多過ぎます" +#, c-format +msgid "E1212: Bool required for argument %d" +msgstr "E1212: 引数 %d にはBool型が必要です" -msgid "Argument missing after" -msgstr "引数がありません" +#, c-format +msgid "E1219: Float or Number required for argument %d" +msgstr "E1219: 引数 %d には浮動小数点数または数値が必要です" -msgid "Garbage after option argument" -msgstr "オプション引数の後にゴミがあります" +#, c-format +msgid "E1220: String or Number required for argument %d" +msgstr "E1220: 引数 %d には文字列または数値が必要です" -msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments" -msgstr "\"+command\", \"-c command\", \"--cmd command\" の引数が多過ぎます" +#, c-format +msgid "E1222: String or List required for argument %d" +msgstr "E1222: 引数 %d には文字列またはリスト型が必要です" -msgid "Invalid argument for" -msgstr "無効な引数です: " +#, c-format +msgid "E1226: List or Blob required for argument %d" +msgstr "E1226: 引数 %d にはリスト型またはBlob型が必要です" #, c-format -msgid "%d files to edit\n" -msgstr "%d 個のファイルが編集を控えています\n" +msgid "E1238: Blob required for argument %d" +msgstr "E1238: 引数 %d にはBlob型が必要です" -msgid "netbeans is not supported with this GUI\n" -msgstr "netbeans はこのGUIでは利用できません\n" +#, c-format +msgid "E1239: Invalid value for blob: %d" +msgstr "E1239: blobとして無効な値です: %d" -msgid "'-nb' cannot be used: not enabled at compile time\n" -msgstr "'-nb' 使用不可能です: コンパイル時に無効にされています\n" +#, c-format +msgid "E1252: String, List or Blob required for argument %d" +msgstr "E1252: 引数 %d には文字列、リスト型またはBlob型が必要です" -msgid "This Vim was not compiled with the diff feature." -msgstr "このVimにはdiff機能がありません(コンパイル時設定)。" +#, c-format +msgid "E1256: String or function required for argument %d" +msgstr "E1256: 引数 %d には文字列または関数が必要です" -msgid "Attempt to open script file again: \"" -msgstr "スクリプトファイルを再び開こうとしました: \"" +#, c-format +msgid "E1297: Non-NULL Dictionary required for argument %d" +msgstr "E1297: 引数 %d には非NULLの辞書が必要です" -msgid "Cannot open for reading: \"" -msgstr "読込用として開けません" +msgid "E710: List value has more items than target" +msgstr "E710: リスト型変数にターゲットよりも多い要素があります" -msgid "Cannot open for script output: \"" -msgstr "スクリプト出力用を開けません" +msgid "E711: List value has not enough items" +msgstr "E711: リスト型変数に十分な数の要素がありません" -msgid "Vim: Error: Failure to start gvim from NetBeans\n" -msgstr "Vim: エラー: NetBeansからgvimをスタートできません\n" +msgid "E702: Sort compare function failed" +msgstr "E702: ソートの比較関数が失敗しました" -msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n" -msgstr "Vim: エラー: このバージョンのVimはCygwin端末では動作しません\n" +msgid "E882: Uniq compare function failed" +msgstr "E882: Uniq の比較関数が失敗しました" -msgid "Vim: Warning: Output is not to a terminal\n" -msgstr "Vim: 警告: 端末への出力ではありません\n" +msgid "sort() argument" +msgstr "sort() の引数" -msgid "Vim: Warning: Input is not from a terminal\n" -msgstr "Vim: 警告: 端末からの入力ではありません\n" +msgid "uniq() argument" +msgstr "uniq() の引数" -msgid "pre-vimrc command line" -msgstr "vimrc前のコマンドライン" +msgid "E6000: Argument is not a function or function name" +msgstr "E6000: 引数は関数または関数名ではありません" #, c-format -msgid "E282: Cannot read from \"%s\"" -msgstr "E282: \"%s\"から読込むことができません" - -msgid "" -"\n" -"More info with: \"vim -h\"\n" -msgstr "" -"\n" -"より詳細な情報は: \"vim -h\"\n" +msgid "E737: Key already exists: %s" +msgstr "E737: キーは既に存在します: %s" -msgid "[file ..] edit specified file(s)" -msgstr "[ファイル..] あるファイルを編集する" +msgid "E972: Blob value does not have the right number of bytes" +msgstr "E972: Blob値のバイト数が正しくありません" -msgid "- read text from stdin" -msgstr "- 標準入力からテキストを読込む" +#, c-format +msgid "E741: Value is locked: %.*s" +msgstr "E741: 値がロックされています: %.*s" -msgid "-t tag edit file where tag is defined" -msgstr "-t タグ タグが定義されたところから編集する" +#, c-format +msgid "E742: Cannot change value of %.*s" +msgstr "E742: %.*s の値を変更できません" -msgid "-q [errorfile] edit file with first error" -msgstr "-q [errorfile] 最初のエラーで編集する" +msgid "Unknown" +msgstr "不明" -msgid "" -"\n" -"\n" -"Usage:" -msgstr "" -"\n" -"\n" -"使用法:" +msgid "E805: Expected a Number or a String, Float found" +msgstr "E805: 数値か文字列が必要ですが、浮動小数点数が見つかりました" -msgid " vim [arguments] " -msgstr " vim [引数] " +msgid "E703: Expected a Number or a String, Funcref found" +msgstr "E703: 数値か文字列が必要ですが、関数参照型が見つかりました" -msgid "" -"\n" -" or:" -msgstr "" -"\n" -" もしくは:" +msgid "E745: Expected a Number or a String, List found" +msgstr "E745: 数値か文字列が必要ですが、リスト型が見つかりました" -msgid "" -"\n" -"Where case is ignored prepend / to make flag upper case" -msgstr "" -"\n" -"大小文字が無視される場合は大文字にするために / を前置してください" +msgid "E728: Expected a Number or a String, Dictionary found" +msgstr "E728: 数値か文字列が必要ですが、辞書型が見つかりました" -msgid "" -"\n" -"\n" -"Arguments:\n" -msgstr "" -"\n" -"\n" -"引数:\n" +msgid "E974: Expected a Number or a String, Blob found" +msgstr "E974: 数値か文字列が必要ですが、Blob型が見つかりました" -msgid "--\t\t\tOnly file names after this" -msgstr "--\t\t\tこのあとにはファイル名だけ" +msgid "E5299: Expected a Number or a String, Boolean found" +msgstr "E5299: 数値か文字列が必要ですが、論理型が見つかりました" -msgid "--literal\t\tDon't expand wildcards" -msgstr "--literal\t\tワイルドカードを展開しない" +msgid "E5300: Expected a Number or a String" +msgstr "E5300: 数値か文字列が必要です" -msgid "-register\t\tRegister this gvim for OLE" -msgstr "-register\t\tこのgvimをOLEとして登録する" +msgid "E745: Using a List as a Number" +msgstr "E745: リスト型を数値として扱っています" -msgid "-unregister\t\tUnregister gvim for OLE" -msgstr "-unregister\t\tgvimのOLE登録を解除する" +msgid "E728: Using a Dictionary as a Number" +msgstr "E728: 辞書型を数値として扱っています" -msgid "-g\t\t\tRun using GUI (like \"gvim\")" -msgstr "-g\t\t\tGUIで起動する (\"gvim\" と同じ)" +msgid "E805: Using a Float as a Number" +msgstr "E805: 浮動小数点数を数値として扱っています" -msgid "-f or --nofork\tForeground: Don't fork when starting GUI" -msgstr "-f or --nofork\tフォアグラウンド: GUIを始めるときにforkしない" +msgid "E974: Using a Blob as a Number" +msgstr "E974: Blob型を数値として扱っています" -msgid "-v\t\t\tVi mode (like \"vi\")" -msgstr "-v\t\t\tViモード (\"vi\" と同じ)" +msgid "E685: using an invalid value as a Number" +msgstr "E685: 無効な値を数字として扱っています" -msgid "-e\t\t\tEx mode (like \"ex\")" -msgstr "-e\t\t\tExモード (\"ex\" と同じ)" +msgid "E730: Using a List as a String" +msgstr "E730: リスト型を文字列として扱っています" -msgid "-E\t\t\tImproved Ex mode" -msgstr "-E\t\t\t改良Exモード" +msgid "E731: Using a Dictionary as a String" +msgstr "E731: 辞書型を文字列として扱っています" -msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")" -msgstr "-s\t\t\tサイレント(バッチ)モード (\"ex\" 専用)" +msgid "E976: Using a Blob as a String" +msgstr "E976: Blob型を文字列として扱っています" -msgid "-d\t\t\tDiff mode (like \"vimdiff\")" -msgstr "-d\t\t\t差分モード (\"vidiff\" と同じ)" +msgid "E891: Using a Funcref as a Float" +msgstr "E891: 関数参照型を浮動小数点数として扱っています" -msgid "-y\t\t\tEasy mode (like \"evim\", modeless)" -msgstr "-y\t\t\tイージーモード (\"evim\" と同じ、モード無)" +msgid "E892: Using a String as a Float" +msgstr "E892: 文字列を浮動小数点数として扱っています" -msgid "-R\t\t\tReadonly mode (like \"view\")" -msgstr "-R\t\t\t読込専用モード (\"view\" と同じ)" +msgid "E893: Using a List as a Float" +msgstr "E893: リスト型を浮動小数点数として扱っています" -msgid "-m\t\t\tModifications (writing files) not allowed" -msgstr "-m\t\t\t変更 (ファイル保存時) をできないようにする" +msgid "E894: Using a Dictionary as a Float" +msgstr "E894: 辞書型を浮動小数点数として扱っています" -msgid "-M\t\t\tModifications in text not allowed" -msgstr "-M\t\t\tテキストの編集を行なえないようにする" +msgid "E362: Using a boolean value as a Float" +msgstr "E362: ブール値を浮動小数点数として扱っています" -msgid "-b\t\t\tBinary mode" -msgstr "-b\t\t\tバイナリモード" +msgid "E907: Using a special value as a Float" +msgstr "E907: 特殊値を浮動小数点数として扱っています" -msgid "-l\t\t\tLisp mode" -msgstr "-l\t\t\tLispモード" +msgid "E975: Using a Blob as a Float" +msgstr "E975: Blob型を浮動小数点数として扱っています" -msgid "-C\t\t\tCompatible with Vi: 'compatible'" -msgstr "-C\t\t\tVi互換モード: 'compatible'" +msgid "E808: Number or Float required" +msgstr "E808: 数値か浮動小数点数が必要です" -msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'" -msgstr "-N\t\t\tVi非互換モード: 'nocompatible" +#, c-format +msgid "E117: Unknown function: %s" +msgstr "E117: 未知の関数です: %s" -msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]" -msgstr "-V[N][fname]\t\tログ出力設定 [レベル N] [ログファイル名 fname]" +#, c-format +msgid "E122: Function %s already exists, add ! to replace it" +msgstr "E122: 関数 %s は定義済です、再定義するには ! を追加してください" -msgid "-D\t\t\tDebugging mode" -msgstr "-D\t\t\tデバッグモード" +msgid "E717: Dictionary entry already exists" +msgstr "E717: 辞書型内にエントリが既に存在します" -msgid "-n\t\t\tNo swap file, use memory only" -msgstr "-n\t\t\tスワップファイルを使用せずメモリだけ" +msgid "E718: Funcref required" +msgstr "E718: 関数参照型が要求されます" -msgid "-r\t\t\tList swap files and exit" -msgstr "-r\t\t\tスワップファイルを列挙し終了" +#, c-format +msgid "E130: Unknown function: %s" +msgstr "E130: 未知の関数です: %s" -msgid "-r (with file name)\tRecover crashed session" -msgstr "-r (ファイル名)\tクラッシュしたセッションを復帰" +msgid "E454: Function list was modified" +msgstr "E454: 関数リストが変更されました" -msgid "-L\t\t\tSame as -r" -msgstr "-L\t\t\t-rと同じ" +msgid "E1058: Function nesting too deep" +msgstr "E1058: 関数の入れ子が深過ぎます" -msgid "-f\t\t\tDon't use newcli to open window" -msgstr "-f\t\t\tウィンドウを開くのに newcli を使用しない" +#, c-format +msgid "E1068: No white space allowed before '%s': %s" +msgstr "E1068: '%s' の前にスペースは許されません: %s" -msgid "-dev \t\tUse for I/O" -msgstr "-dev \t\tI/Oに を使用する" +#, c-format +msgid "E1145: Missing heredoc end marker: %s" +msgstr "E1145: heredocの終端マーカーがありません '%s'" -msgid "-A\t\t\tStart in Arabic mode" -msgstr "-A\t\t\tアラビア語モードで起動する" +msgid "E1300: Cannot use a partial with dictionary for :defer" +msgstr "E1300: :defer で辞書付き部分適用は使用できません" -msgid "-H\t\t\tStart in Hebrew mode" -msgstr "-H\t\t\tヘブライ語モードで起動する" +#, c-format +msgid "E125: Illegal argument: %s" +msgstr "E125: 不正な引数です: %s" -msgid "-F\t\t\tStart in Farsi mode" -msgstr "-F\t\t\tペルシア語モードで起動する" +#, c-format +msgid "E853: Duplicate argument name: %s" +msgstr "E853: 引数名が重複しています: %s" -msgid "-T \tSet terminal type to " -msgstr "-T \t端末を に設定する" +msgid "E989: Non-default argument follows default argument" +msgstr "E989: 非デフォルト引数がデフォルト引数の後にあります" -msgid "--not-a-term\t\tSkip warning for input/output not being a terminal" -msgstr "--not-a-term\t\t入出力が端末でないとの警告をスキップする" +#, c-format +msgid "E451: Expected }: %s" +msgstr "E451: } が必要です: %s" -msgid "--ttyfail\t\tExit if input or output is not a terminal" -msgstr "--ttyfail\t\t入出力が端末でなければ終了する" +#, c-format +msgid "E740: Too many arguments for function %s" +msgstr "E740: 関数の引数が多過ぎます: %s" -msgid "-u \t\tUse instead of any .vimrc" -msgstr "-u \t\t.vimrcの代わりに を使う" +#, c-format +msgid "E116: Invalid arguments for function %s" +msgstr "E116: 関数の無効な引数です: %s" -msgid "-U \t\tUse instead of any .gvimrc" -msgstr "-U \t\t.gvimrcの代わりに を使う" +msgid "E132: Function call depth is higher than 'maxfuncdepth'" +msgstr "E132: 関数呼出しの入れ子数が 'maxfuncdepth' を超えました" -msgid "--noplugin\t\tDon't load plugin scripts" -msgstr "--noplugin\t\tプラグインスクリプトをロードしない" +#, c-format +msgid "calling %s" +msgstr "%s を実行中です" -msgid "-p[N]\t\tOpen N tab pages (default: one for each file)" -msgstr "-p[N]\t\tN 個タブページを開く(省略値: ファイルにつき1個)" +#, c-format +msgid "%s aborted" +msgstr "%s が中断されました" -msgid "-o[N]\t\tOpen N windows (default: one for each file)" -msgstr "-o[N]\t\tN 個ウィンドウを開く(省略値: ファイルにつき1個)" +#, c-format +msgid "%s returning #%" +msgstr "%s が #% を返しました" -msgid "-O[N]\t\tLike -o but split vertically" -msgstr "-O[N]\t\t-oと同じだが垂直分割" +#, c-format +msgid "%s returning %s" +msgstr "%s が %s を返しました" -msgid "+\t\t\tStart at end of file" -msgstr "+\t\t\tファイルの最後からはじめる" +#, c-format +msgid "continuing in %s" +msgstr "%s の実行を継続中です" -msgid "+\t\tStart at line " -msgstr "+\t\t 行からはじめる" +msgid "E699: Too many arguments" +msgstr "E699: 引数が多過ぎます" -msgid "--cmd \tExecute before loading any vimrc file" -msgstr "--cmd \tvimrcをロードする前に を実行する" +#, c-format +msgid "E276: Cannot use function as a method: %s" +msgstr "E276: 関数をメソッドとして使用できません: %s" -msgid "-c \t\tExecute after loading the first file" -msgstr "-c \t\t最初のファイルをロード後 を実行する" +#, c-format +msgid "E933: Function was deleted: %s" +msgstr "E933: 関数は削除されました: %s" -msgid "-S \t\tSource file after loading the first file" -msgstr "-S \t\t最初のファイルをロード後ファイル を取込む" +#, c-format +msgid "E120: Using not in a script context: %s" +msgstr "E120: スクリプト以外でが使われました: %s" -msgid "-s \tRead Normal mode commands from file " -msgstr "-s \tファイル からノーマルコマンドを読込む" +#, c-format +msgid "E725: Calling dict function without Dictionary: %s" +msgstr "E725: 辞書用関数が呼ばれましたが辞書がありません: %s" -msgid "-w \tAppend all typed commands to file " -msgstr "-w \t入力した全コマンドをファイル に追加する" +msgid "E129: Function name required" +msgstr "E129: 関数名が要求されます" -msgid "-W \tWrite all typed commands to file " -msgstr "-W \t入力した全コマンドをファイル に保存する" +#, c-format +msgid "E128: Function name must start with a capital or \"s:\": %s" +msgstr "E128: 関数名は大文字か \"s:\" で始まらなければなりません: %s" -msgid "-x\t\t\tEdit encrypted files" -msgstr "-x\t\t\t暗号化されたファイルを編集する" +#, c-format +msgid "E884: Function name cannot contain a colon: %s" +msgstr "E884: 関数名にはコロンは含められません: %s" -msgid "-display \tConnect Vim to this particular X-server" -msgstr "-display \tvimを指定した X サーバーに接続する" +#, c-format +msgid "E123: Undefined function: %s" +msgstr "E123: 未定義の関数です: %s" -msgid "-X\t\t\tDo not connect to X server" -msgstr "-X\t\t\tXサーバーに接続しない" +#, c-format +msgid "E124: Missing '(': %s" +msgstr "E124: '(' がありません: %s" -msgid "--remote \tEdit in a Vim server if possible" -msgstr "--remote \t可能ならばVimサーバーで を編集する" +msgid "E862: Cannot use g: here" +msgstr "E862: ここでは g: は使えません" -msgid "--remote-silent Same, don't complain if there is no server" -msgstr "--remote-silent 同上、サーバーが無くても警告文を出力しない" +#, c-format +msgid "E932: Closure function should not be at top level: %s" +msgstr "E932: クロージャー関数はトップレベルに記述できません: %s" -msgid "" -"--remote-wait As --remote but wait for files to have been edited" -msgstr "--remote-wait \t--remote後 ファイルの編集が終わるのを待つ" +msgid "E126: Missing :endfunction" +msgstr "E126: :endfunction がありません" -msgid "" -"--remote-wait-silent Same, don't complain if there is no server" -msgstr "" -"--remote-wait-silent 同上、サーバーが無くても警告文を出力しない" +#, c-format +msgid "W22: Text found after :endfunction: %s" +msgstr "W22: :endfunction の後に文字があります: %s" -msgid "" -"--remote-tab[-wait][-silent] As --remote but use tab page per file" -msgstr "" -"--remote-tab[-wait][-silent] --remoteでファイル1つにつき1つのタブ" -"ページを開く" +#, c-format +msgid "E707: Function name conflicts with variable: %s" +msgstr "E707: 関数名が変数名と衝突します: %s" -msgid "--remote-send \tSend to a Vim server and exit" -msgstr "--remote-send \tVimサーバーに を送信して終了する" +#, c-format +msgid "E127: Cannot redefine function %s: It is in use" +msgstr "E127: 関数 %s を再定義できません: 使用中です" -msgid "--remote-expr \tEvaluate in a Vim server and print result" -msgstr "--remote-expr \tサーバーで を実行して結果を表示する" +#, c-format +msgid "E746: Function name does not match script file name: %s" +msgstr "E746: 関数名がスクリプトのファイル名と一致しません: %s" -msgid "--serverlist\t\tList available Vim server names and exit" -msgstr "--serverlist\t\tVimサーバー名の一覧を表示して終了する" +#, c-format +msgid "E131: Cannot delete function %s: It is in use" +msgstr "E131: 関数 %s を削除できません: 使用中です" -msgid "--servername \tSend to/become the Vim server " -msgstr "--servername \tVimサーバー に送信/名前設定する" +#, c-format +msgid "Cannot delete function %s: It is being used internally" +msgstr "関数 %s を削除できません: 使用中です" -msgid "--startuptime \tWrite startup timing messages to " -msgstr "--startuptime \t起動にかかった時間の詳細を へ出力する" +msgid "E133: :return not inside a function" +msgstr "E133: 関数外に :return がありました" -msgid "-i \t\tUse instead of .viminfo" -msgstr "-i \t\t.viminfoの代わりに を使う" +msgid "E18: Unexpected characters in :let" +msgstr "E18: 予期せぬ文字が :let にありました" -msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo" -msgstr "--clean\t\t'nocompatible'、Vimの既定、プラグインなし、viminfoなし" +#, c-format +msgid "E940: Cannot lock or unlock variable %s" +msgstr "E940: 変数 %s はロックまたはアンロックできません" -msgid "-h or --help\tPrint Help (this message) and exit" -msgstr "-h or --help\tヘルプ(このメッセージ)を表示し終了する" +#, c-format +msgid "E963: Setting v:%s to value with wrong type" +msgstr "E963: v:%s を間違った型の値で設定しています" -msgid "--version\t\tPrint version information and exit" -msgstr "--version\t\tバージョン情報を表示し終了する" +msgid "E991: Cannot use =<< here" +msgstr "E991: ここでは =<< は使えません" -msgid "" -"\n" -"Arguments recognised by gvim (Motif version):\n" -msgstr "" -"\n" -"gvimによって解釈される引数(Motifバージョン):\n" +msgid "E221: Marker cannot start with lower case letter" +msgstr "E221: マーカーは英小文字で始まってはいけません" -msgid "" -"\n" -"Arguments recognised by gvim (neXtaw version):\n" -msgstr "" -"\n" -"gvimによって解釈される引数(neXtawバージョン):\n" +msgid "E172: Missing marker" +msgstr "E172: マーカーがありません" -msgid "" -"\n" -"Arguments recognised by gvim (Athena version):\n" -msgstr "" -"\n" -"gvimによって解釈される引数(Athenaバージョン):\n" +#, c-format +msgid "E990: Missing end marker '%s'" +msgstr "E990: 終端マーカーがありません '%s'" -msgid "-display \tRun Vim on " -msgstr "-display \t でvimを実行する" +msgid "E687: Less targets than List items" +msgstr "E687: ターゲットがリスト型内の要素よりも少ないです" -msgid "-iconic\t\tStart Vim iconified" -msgstr "-iconic\t\t最小化した状態でvimを起動する" +msgid "E688: More targets than List items" +msgstr "E688: ターゲットがリスト型内の要素よりも多いです" -msgid "-background \tUse for the background (also: -bg)" -msgstr "-background \t背景色に を使う(同義: -bg)" +msgid "E452: Double ; in list of variables" +msgstr "E452: リスト型の値に2つ以上の ; が検出されました" -msgid "-foreground \tUse for normal text (also: -fg)" -msgstr "-foreground \t前景色に を使う(同義: -fg)" - -msgid "-font \t\tUse for normal text (also: -fn)" -msgstr "-font \t\tテキスト表示に を使う(同義: -fn)" +#, c-format +msgid "E738: Can't list variables for %s" +msgstr "E738: %s の値を一覧表示できません" -msgid "-boldfont \tUse for bold text" -msgstr "-boldfont \t太字に を使う" +msgid "E996: Cannot lock an environment variable" +msgstr "E996: 環境変数はロックできません" -msgid "-italicfont \tUse for italic text" -msgstr "-italicfont \t斜体字に を使う" +msgid "E996: Cannot lock an option" +msgstr "E996: オプションはロックできません" -msgid "-geometry \tUse for initial geometry (also: -geom)" -msgstr "-geometry \t初期配置に を使う(同義: -geom)" +msgid "E996: Cannot lock a register" +msgstr "E996: レジスタはロックできません" -msgid "-borderwidth \tUse a border width of (also: -bw)" -msgstr "-borderwidth \t境界の幅を にする(同義: -bw)" +#, c-format +msgid "E108: No such variable: \"%s\"" +msgstr "E108: その変数はありません: \"%s\"" -msgid "-scrollbarwidth Use a scrollbar width of (also: -sw)" -msgstr "" -"-scrollbarwidth スクロールバーの幅を にする(同義: -sw)" +#, c-format +msgid "E794: Cannot set variable in the sandbox: \"%.*s\"" +msgstr "E794: サンドボックスでは変数 \"%.*s\" に値を設定できません" -msgid "-menuheight \tUse a menu bar height of (also: -mh)" -msgstr "-menuheight \tメニューバーの高さを にする(同義: -mh)" +#, c-format +msgid "E1122: Variable is locked: %*s" +msgstr "E1122: 変数がロックされています: %*s" -msgid "-reverse\t\tUse reverse video (also: -rv)" -msgstr "-reverse\t\t反転映像を使用する(同義: -rv)" +#, c-format +msgid "E795: Cannot delete variable %.*s" +msgstr "E795: 変数 %.*s を削除できません" -msgid "+reverse\t\tDon't use reverse video (also: +rv)" -msgstr "+reverse\t\t反転映像を使用しない(同義: +rv)" +#, c-format +msgid "E704: Funcref variable name must start with a capital: %s" +msgstr "E704: 関数参照型変数名は大文字で始まらなければなりません: %s" -msgid "-xrm \tSet the specified resource" -msgstr "-xrm \t特定のリソースを使用する" +#, c-format +msgid "E705: Variable name conflicts with existing function: %s" +msgstr "E705: 変数名が既存の関数名と衝突します: %s" -msgid "" -"\n" -"Arguments recognised by gvim (GTK+ version):\n" -msgstr "" -"\n" -"gvimによって解釈される引数(GTK+バージョン):\n" +#, c-format +msgid "E521: Number required: &%s = '%s'" +msgstr "E521: 数字が必要です: &%s = '%s'" -msgid "-display \tRun Vim on (also: --display)" -msgstr "-display \t でVimを実行する(同義: --display)" +msgid "E1308: Cannot resize a window in another tab page" +msgstr "E1308: 別のタブページのウィンドウをリサイズできません" -msgid "--role \tSet a unique role to identify the main window" -msgstr "--role \tメインウィンドウを識別する一意な役割(role)を設定する" +msgid "tcp address must be host:port" +msgstr "TCP アドレスは ホスト名:ポート番号 でなければなりません" -msgid "--socketid \tOpen Vim inside another GTK widget" -msgstr "--socketid \t異なるGTK widgetでVimを開く" +msgid "failed to lookup host or port" +msgstr "ホストまたはポートの検索に失敗しました" -msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout" -msgstr "--echo-wid\t\tウィンドウIDを標準出力に出力する" +msgid "connection refused" +msgstr "接続が拒否されました" -msgid "-P \tOpen Vim inside parent application" -msgstr "-P <親のタイトル>\tVimを親アプリケーションの中で起動する" +msgid "E144: Non-numeric argument to :z" +msgstr "E144: 数ではない引数が :z に渡されました" -msgid "--windowid \tOpen Vim inside another win32 widget" -msgstr "--windowid \t異なるWin32 widgetの内部にVimを開く" +#, c-format +msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s" +msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o, ダイグラフ %s" -msgid "No display" -msgstr "ディスプレイが見つかりません" +#, c-format +msgid "<%s>%s%s %d, Hex %02x, Octal %03o" +msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o" -msgid ": Send failed.\n" -msgstr ": 送信に失敗しました.\n" +#, c-format +msgid "> %d, Hex %04x, Oct %o, Digr %s" +msgstr "> %d, 16進数 %04x, 8進数 %o, ダイグラフ %s" -msgid ": Send failed. Trying to execute locally\n" -msgstr ": 送信に失敗しました。ローカルでの実行を試みています\n" +#, c-format +msgid "> %d, Hex %08x, Oct %o, Digr %s" +msgstr "> %d, 16進数 %08x, 8進数 %o, ダイグラフ %s" #, c-format -msgid "%d of %d edited" -msgstr "%d 個 (%d 個中) のファイルを編集しました" +msgid "> %d, Hex %04x, Octal %o" +msgstr "> %d, 16進数 %04x, 8進数 %o" -msgid "No display: Send expression failed.\n" -msgstr "ディスプレイがありません: 式の送信に失敗しました.\n" +#, c-format +msgid "> %d, Hex %08x, Octal %o" +msgstr "> %d, 16進数 %08x, 8進数 %o" -msgid ": Send expression failed.\n" -msgstr ": 式の送信に失敗しました.\n" +msgid "E134: Cannot move a range of lines into itself" +msgstr "E134: 行の範囲をそれ自身には移動できません" #, c-format -msgid "E224: global abbreviation already exists for %s" -msgstr "E224: %s というグローバル短縮入力は既に存在します" +msgid "% line moved" +msgid_plural "% lines moved" +msgstr[0] "% 行が移動されました" #, c-format -msgid "E225: global mapping already exists for %s" -msgstr "E225: %s というグローバルマッピングは既に存在します" +msgid "E482: Can't create file %s" +msgstr "E482: ファイル %s を作成できません" #, c-format -msgid "E226: abbreviation already exists for %s" -msgstr "E226: %s という短縮入力は既に存在します" +msgid "% lines filtered" +msgstr "% 行がフィルタ処理されました" -#, c-format -msgid "E227: mapping already exists for %s" -msgstr "E227: %s というマッピングは既に存在します" +msgid "E135: *Filter* Autocommands must not change current buffer" +msgstr "E135: *Filter* 自動コマンドは現在のバッファを変更してはいけません" -msgid "No abbreviation found" -msgstr "短縮入力は見つかりませんでした" +msgid "[No write since last change]\n" +msgstr "[最後の変更が保存されていません]\n" -msgid "No mapping found" -msgstr "マッピングは見つかりませんでした" +#, c-format +msgid "E503: \"%s\" is not a file or writable device" +msgstr "E503: \"%s\" はファイルでも書込み可能デバイスでもありません" -msgid "E228: makemap: Illegal mode" -msgstr "E228: makemap: 不正なモード" +msgid "Write partial file?" +msgstr "ファイルを部分的に保存しますか?" + +msgid "E140: Use ! to write partial buffer" +msgstr "E140: バッファを部分的に保存するには ! を使ってください" #, c-format -msgid "E357: 'langmap': Matching character missing for %s" -msgstr "E357: 'langmap': %s に対応する文字がありません" +msgid "Overwrite existing file \"%s\"?" +msgstr "既存のファイル \"%s\" を上書きしますか?" #, c-format -msgid "E358: 'langmap': Extra characters after semicolon: %s" -msgstr "E358: 'langmap': セミコロンの後に余分な文字があります: %s" +msgid "Swap file \"%s\" exists, overwrite anyway?" +msgstr "スワップファイル \"%s\" が存在します。上書きを強制しますか?" -msgid "No marks set" -msgstr "マークが設定されていません" +#, c-format +msgid "E768: Swap file exists: %s (:silent! overrides)" +msgstr "E768: スワップファイルが存在します: %s (:silent! を追加で上書)" #, c-format -msgid "E283: No marks matching \"%s\"" -msgstr "E283: \"%s\" に該当するマークがありません" +msgid "E141: No file name for buffer %" +msgstr "E141: バッファ % には名前がありません" -msgid "" -"\n" -"mark line col file/text" -msgstr "" -"\n" -"mark 行 列 ファイル/テキスト" +msgid "E142: File not written: Writing is disabled by 'write' option" +msgstr "E142: ファイルは保存されませんでした: 'write' オプションにより無効です" +#, c-format msgid "" -"\n" -" jump line col file/text" +"'readonly' option is set for \"%s\".\n" +"Do you wish to write anyway?" msgstr "" -"\n" -" jump 行 列 ファイル/テキスト" +"\"%s\" には 'readonly' オプションが設定されています.\n" +"上書き強制をしますか?" +#, c-format msgid "" -"\n" -"change line col text" +"File permissions of \"%s\" are read-only.\n" +"It may still be possible to write it.\n" +"Do you wish to try?" msgstr "" -"\n" -"変更 行 列 テキスト" +"ファイル \"%s\" のパーミッションが読込専用です.\n" +"それでも恐らく書込むことは可能です.\n" +"継続しますか?" -msgid "" -"\n" -"# File marks:\n" -msgstr "" -"\n" -"# ファイルマーク:\n" +#, c-format +msgid "E505: \"%s\" is read-only (add ! to override)" +msgstr "E505: \"%s\" は読込専用です (強制書込には ! を追加)" -msgid "" -"\n" -"# Jumplist (newest first):\n" -msgstr "" -"\n" -"# ジャンプリスト (新しいものが先):\n" +#, c-format +msgid "E143: Autocommands unexpectedly deleted new buffer %s" +msgstr "E143: 自動コマンドが予期せず新しいバッファ %s を削除しました" -msgid "" -"\n" -"# History of marks within files (newest to oldest):\n" -msgstr "" -"\n" -"# ファイル内マークの履歴 (新しいものから古いもの):\n" +msgid "E146: Regular expressions can't be delimited by letters" +msgstr "E146: 正規表現は文字で区切ることができません" + +#, c-format +msgid "replace with %s (y/n/a/q/l/^E/^Y)?" +msgstr "%s に置換しますか? (y/n/a/q/l/^E/^Y)" -msgid "Missing '>'" -msgstr "'>' が見つかりません" +msgid "(Interrupted) " +msgstr "(割込まれました) " -msgid "E543: Not a valid codepage" -msgstr "E543: 無効なコードページです" +#, c-format +msgid "% match on % line" +msgid_plural "% matches on % line" +msgstr[0] "% 箇所該当しました (計 % 行内)" -msgid "E284: Cannot set IC values" -msgstr "E284: ICの値を設定できません" +#, c-format +msgid "% substitution on % line" +msgid_plural "% substitutions on % line" +msgstr[0] "% 箇所置換しました (計 % 行内)" -msgid "E285: Failed to create input context" -msgstr "E285: インプットコンテキストの作成に失敗しました" +#, c-format +msgid "% match on % lines" +msgid_plural "% matches on % lines" +msgstr[0] "% 箇所該当しました (計 % 行内)" -msgid "E286: Failed to open input method" -msgstr "E286: インプットメソッドのオープンに失敗しました" +#, c-format +msgid "% substitution on % lines" +msgid_plural "% substitutions on % lines" +msgstr[0] "% 箇所置換しました (計 % 行内)" -msgid "E287: Warning: Could not set destroy callback to IM" -msgstr "E287: 警告: IMの破壊コールバックを設定できませんでした" +msgid "E147: Cannot do :global recursive with a range" +msgstr "E147: :global を範囲付きで再帰的には使えません" -msgid "E288: input method doesn't support any style" -msgstr "E288: インプットメソッドはどんなスタイルもサポートしません" +msgid "E148: Regular expression missing from global" +msgstr "E148: :global に正規表現が指定されていません" -msgid "E289: input method doesn't support my preedit type" -msgstr "E289: インプットメソッドは my preedit type をサポートしません" +#, c-format +msgid "Pattern found in every line: %s" +msgstr "パターンが全ての行で見つかりました: %s" -msgid "E293: block was not locked" -msgstr "E293: ブロックがロックされていません" +#, c-format +msgid "Pattern not found: %s" +msgstr "パターンは見つかりませんでした: %s" -msgid "E294: Seek error in swap file read" -msgstr "E294: スワップファイル読込時にシークエラーです" +msgid "No old files" +msgstr "古いファイルはありません" -msgid "E295: Read error in swap file" -msgstr "E295: スワップファイルの読込みエラーです" +#, c-format +msgid "E666: Compiler not supported: %s" +msgstr "E666: そのコンパイラには対応していません: %s" -msgid "E296: Seek error in swap file write" -msgstr "E296: スワップファイル書込み時にシークエラーです" +#, c-format +msgid "Save changes to \"%s\"?" +msgstr "変更を \"%s\" に保存しますか?" -msgid "E297: Write error in swap file" -msgstr "E297: スワップファイルの書込みエラーです" +#, c-format +msgid "Close \"%s\"?" +msgstr "\"%s\"を閉じますか?" -msgid "E300: Swap file already exists (symlink attack?)" -msgstr "E300: スワップファイルが既に存在します (symlinkによる攻撃?)" +#, c-format +msgid "E947: Job still running in buffer \"%s\"" +msgstr "E947: ジョブはバッファ \"%s\" でまだ実行中です" -msgid "E298: Didn't get block nr 0?" -msgstr "E298: ブロック 0 を取得できません?" +#, c-format +msgid "E162: No write since last change for buffer \"%s\"" +msgstr "E162: バッファ \"%s\" の変更は保存されていません" -msgid "E298: Didn't get block nr 1?" -msgstr "E298: ブロック 1 を取得できません?" +msgid "Warning: Entered other buffer unexpectedly (check autocommands)" +msgstr "警告: 予期せず他バッファへ移動しました (自動コマンドを調べてください)" -msgid "E298: Didn't get block nr 2?" -msgstr "E298: ブロック 2 を取得できません?" +msgid "E464: Ambiguous use of user-defined command" +msgstr "E464: ユーザー定義コマンドのあいまいな使用です" -msgid "E843: Error while updating swap file crypt" -msgstr "E843: スワップファイルの暗号を更新中にエラーが発生しました" +msgid "E489: No call stack to substitute for \"\"" +msgstr "E489: \"\" を置き換えるコールスタックがありません" -msgid "E301: Oops, lost the swap file!!!" -msgstr "E301: おっと、スワップファイルが失われました!!!" +msgid "E492: Not an editor command" +msgstr "E492: エディタのコマンドではありません" -msgid "E302: Could not rename swap file" -msgstr "E302: スワップファイルの名前を変えられません" +msgid "E495: No autocommand file name to substitute for \"\"" +msgstr "E495: \"\" を置き換える自動コマンドのファイル名がありません" -#, c-format -msgid "E303: Unable to open swap file for \"%s\", recovery impossible" -msgstr "E303: \"%s\" のスワップファイルを開けないのでリカバリは不可能です" +msgid "E496: No autocommand buffer number to substitute for \"\"" +msgstr "E496: \"\" を置き換える自動コマンドバッファ番号がありません" -msgid "E304: ml_upd_block0(): Didn't get block 0??" -msgstr "E304: ml_upd_block0(): ブロック 0 を取得できませんでした??" +msgid "E497: No autocommand match name to substitute for \"\"" +msgstr "E497: \"\" を置き換える自動コマンドの該当名がありません" -#, c-format -msgid "E305: No swap file found for %s" -msgstr "E305: %s にはスワップファイルが見つかりません" +msgid "E498: No :source file name to substitute for \"\"" +msgstr "E498: \"\" を置き換える :source 対象ファイル名がありません" -msgid "Enter number of swap file to use (0 to quit): " -msgstr "使用するスワップファイルの番号を入力してください(0 で終了): " +msgid "E842: No line number to use for \"\"" +msgstr "E842: \"\" を置き換える行番号がありません" -#, c-format -msgid "E306: Cannot open %s" -msgstr "E306: %s を開けません" +msgid "E961: No line number to use for \"\"" +msgstr "E961: \"\" を置き換える行番号がありません" -msgid "Unable to read block 0 from " -msgstr "ブロック 0 を読込めません " +msgid "E1274: No script file name to substitute for \"