diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/vim.c | 4 | ||||
-rw-r--r-- | src/nvim/buffer.c | 1 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 25 | ||||
-rw-r--r-- | src/nvim/file_search.c | 2 | ||||
-rw-r--r-- | src/nvim/func_attr.h | 5 | ||||
-rw-r--r-- | src/nvim/generators/gen_unicode_tables.lua | 2 | ||||
-rw-r--r-- | src/nvim/mbyte.c | 141 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 16 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 850 |
10 files changed, 584 insertions, 464 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index d0327b241c..f54ac5072c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -683,14 +683,14 @@ void nvim_set_current_dir(String dir, Error *err) try_start(); - if (vim_chdir((char_u *)string, kCdScopeGlobal)) { + if (vim_chdir((char_u *)string)) { if (!try_end(err)) { api_set_error(err, kErrorTypeException, "Failed to change directory"); } return; } - post_chdir(kCdScopeGlobal); + post_chdir(kCdScopeGlobal, true); try_end(err); } diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index d7a16de299..b9c4c4d544 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1620,6 +1620,7 @@ void do_autochdir(void) if (starting == 0 && curbuf->b_ffname != NULL && vim_chdirfile(curbuf->b_ffname) == OK) { + post_chdir(kCdScopeGlobal, false); shorten_fnames(true); } } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index af92a9c846..150e13efd5 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -6392,6 +6392,7 @@ void ex_substitute(exarg_T *eap) } block_autocmds(); // Disable events during command preview. + input_disable_events(); char_u *save_eap = eap->arg; garray_T save_view; @@ -6434,6 +6435,7 @@ void ex_substitute(exarg_T *eap) restore_search_patterns(); win_size_restore(&save_view); ga_clear(&save_view); + input_enable_events(); unblock_autocmds(); } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 037b5dec7f..4d958b201a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7241,7 +7241,7 @@ void free_cd_dir(void) /// Deal with the side effects of changing the current directory. /// /// @param scope Scope of the function call (global, tab or window). -void post_chdir(CdScope scope) +void post_chdir(CdScope scope, bool trigger_dirchanged) { // Always overwrite the window-local CWD. xfree(curwin->w_localdir); @@ -7281,7 +7281,10 @@ void post_chdir(CdScope scope) } shorten_fnames(true); - do_autocmd_dirchanged(cwd, scope); + + if (trigger_dirchanged) { + do_autocmd_dirchanged(cwd, scope); + } } /// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`. @@ -7340,10 +7343,10 @@ void ex_cd(exarg_T *eap) break; } - if (vim_chdir(new_dir, scope)) { + if (vim_chdir(new_dir)) { EMSG(_(e_failed)); } else { - post_chdir(scope); + post_chdir(scope, true); // Echo the new current directory if the command was typed. if (KeyTyped || p_verbose >= 5) { ex_pwd(eap); @@ -7804,11 +7807,12 @@ static void ex_redir(exarg_T *eap) redir_off = FALSE; } -/* - * ":redraw": force redraw - */ +/// ":redraw": force redraw static void ex_redraw(exarg_T *eap) { + if (State & CMDPREVIEW) { + return; // Ignore :redraw during 'inccommand' preview. #9777 + } int r = RedrawingDisabled; int p = p_lz; @@ -7837,11 +7841,12 @@ static void ex_redraw(exarg_T *eap) ui_flush(); } -/* - * ":redrawstatus": force redraw of status line(s) - */ +/// ":redrawstatus": force redraw of status line(s) static void ex_redrawstatus(exarg_T *eap) { + if (State & CMDPREVIEW) { + return; // Ignore :redrawstatus during 'inccommand' preview. #9777 + } int r = RedrawingDisabled; int p = p_lz; diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index ee775bab4a..e358f0218e 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1634,7 +1634,7 @@ int vim_chdirfile(char_u *fname) } /// Change directory to "new_dir". Search 'cdpath' for relative directory names. -int vim_chdir(char_u *new_dir, CdScope scope) +int vim_chdir(char_u *new_dir) { char_u *dir_name = find_directory_in_path(new_dir, STRLEN(new_dir), FNAME_MESS, curbuf->b_ffname); diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h index 6e5e47c060..d3b600a40c 100644 --- a/src/nvim/func_attr.h +++ b/src/nvim/func_attr.h @@ -205,10 +205,15 @@ #endif #ifdef DEFINE_FUNC_ATTRIBUTES +/// Non-deferred API function. # define FUNC_API_ASYNC +/// Internal C function not exposed in the RPC API. # define FUNC_API_NOEXPORT +/// API function not exposed in VimL/eval. # define FUNC_API_REMOTE_ONLY +/// API function introduced at the given API level. # define FUNC_API_SINCE(X) +/// API function deprecated since the given API level. # define FUNC_API_DEPRECATED_SINCE(X) # define FUNC_ATTR_MALLOC REAL_FATTR_MALLOC # define FUNC_ATTR_ALLOC_SIZE(x) REAL_FATTR_ALLOC_SIZE(x) diff --git a/src/nvim/generators/gen_unicode_tables.lua b/src/nvim/generators/gen_unicode_tables.lua index 66430ba26e..3130cecd82 100644 --- a/src/nvim/generators/gen_unicode_tables.lua +++ b/src/nvim/generators/gen_unicode_tables.lua @@ -17,7 +17,7 @@ -- which don't have ambiguous or double width, and emoji_all has all Emojis. if arg[1] == '--help' then print('Usage:') - print(' genunicodetables.lua unicode/ unicode_tables.generated.h') + print(' gen_unicode_tables.lua unicode/ unicode_tables.generated.h') os.exit(0) end diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 6c34cacb8d..8cc91146cc 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1063,75 +1063,78 @@ int utf_class_tab(const int c, const uint64_t *const chartab) unsigned int first; unsigned int last; unsigned int class; - } classes[] = - { - {0x037e, 0x037e, 1}, /* Greek question mark */ - {0x0387, 0x0387, 1}, /* Greek ano teleia */ - {0x055a, 0x055f, 1}, /* Armenian punctuation */ - {0x0589, 0x0589, 1}, /* Armenian full stop */ - {0x05be, 0x05be, 1}, - {0x05c0, 0x05c0, 1}, - {0x05c3, 0x05c3, 1}, - {0x05f3, 0x05f4, 1}, - {0x060c, 0x060c, 1}, - {0x061b, 0x061b, 1}, - {0x061f, 0x061f, 1}, - {0x066a, 0x066d, 1}, - {0x06d4, 0x06d4, 1}, - {0x0700, 0x070d, 1}, /* Syriac punctuation */ - {0x0964, 0x0965, 1}, - {0x0970, 0x0970, 1}, - {0x0df4, 0x0df4, 1}, - {0x0e4f, 0x0e4f, 1}, - {0x0e5a, 0x0e5b, 1}, - {0x0f04, 0x0f12, 1}, - {0x0f3a, 0x0f3d, 1}, - {0x0f85, 0x0f85, 1}, - {0x104a, 0x104f, 1}, /* Myanmar punctuation */ - {0x10fb, 0x10fb, 1}, /* Georgian punctuation */ - {0x1361, 0x1368, 1}, /* Ethiopic punctuation */ - {0x166d, 0x166e, 1}, /* Canadian Syl. punctuation */ - {0x1680, 0x1680, 0}, - {0x169b, 0x169c, 1}, - {0x16eb, 0x16ed, 1}, - {0x1735, 0x1736, 1}, - {0x17d4, 0x17dc, 1}, /* Khmer punctuation */ - {0x1800, 0x180a, 1}, /* Mongolian punctuation */ - {0x2000, 0x200b, 0}, /* spaces */ - {0x200c, 0x2027, 1}, /* punctuation and symbols */ - {0x2028, 0x2029, 0}, - {0x202a, 0x202e, 1}, /* punctuation and symbols */ - {0x202f, 0x202f, 0}, - {0x2030, 0x205e, 1}, /* punctuation and symbols */ - {0x205f, 0x205f, 0}, - {0x2060, 0x27ff, 1}, /* punctuation and symbols */ - {0x2070, 0x207f, 0x2070}, /* superscript */ - {0x2080, 0x2094, 0x2080}, /* subscript */ - {0x20a0, 0x27ff, 1}, /* all kinds of symbols */ - {0x2800, 0x28ff, 0x2800}, /* braille */ - {0x2900, 0x2998, 1}, /* arrows, brackets, etc. */ - {0x29d8, 0x29db, 1}, - {0x29fc, 0x29fd, 1}, - {0x2e00, 0x2e7f, 1}, /* supplemental punctuation */ - {0x3000, 0x3000, 0}, /* ideographic space */ - {0x3001, 0x3020, 1}, /* ideographic punctuation */ - {0x3030, 0x3030, 1}, - {0x303d, 0x303d, 1}, - {0x3040, 0x309f, 0x3040}, /* Hiragana */ - {0x30a0, 0x30ff, 0x30a0}, /* Katakana */ - {0x3300, 0x9fff, 0x4e00}, /* CJK Ideographs */ - {0xac00, 0xd7a3, 0xac00}, /* Hangul Syllables */ - {0xf900, 0xfaff, 0x4e00}, /* CJK Ideographs */ - {0xfd3e, 0xfd3f, 1}, - {0xfe30, 0xfe6b, 1}, /* punctuation forms */ - {0xff00, 0xff0f, 1}, /* half/fullwidth ASCII */ - {0xff1a, 0xff20, 1}, /* half/fullwidth ASCII */ - {0xff3b, 0xff40, 1}, /* half/fullwidth ASCII */ - {0xff5b, 0xff65, 1}, /* half/fullwidth ASCII */ - {0x20000, 0x2a6df, 0x4e00}, /* CJK Ideographs */ - {0x2a700, 0x2b73f, 0x4e00}, /* CJK Ideographs */ - {0x2b740, 0x2b81f, 0x4e00}, /* CJK Ideographs */ - {0x2f800, 0x2fa1f, 0x4e00}, /* CJK Ideographs */ + } classes[] = { + { 0x037e, 0x037e, 1 }, // Greek question mark + { 0x0387, 0x0387, 1 }, // Greek ano teleia + { 0x055a, 0x055f, 1 }, // Armenian punctuation + { 0x0589, 0x0589, 1 }, // Armenian full stop + { 0x05be, 0x05be, 1 }, + { 0x05c0, 0x05c0, 1 }, + { 0x05c3, 0x05c3, 1 }, + { 0x05f3, 0x05f4, 1 }, + { 0x060c, 0x060c, 1 }, + { 0x061b, 0x061b, 1 }, + { 0x061f, 0x061f, 1 }, + { 0x066a, 0x066d, 1 }, + { 0x06d4, 0x06d4, 1 }, + { 0x0700, 0x070d, 1 }, // Syriac punctuation + { 0x0964, 0x0965, 1 }, + { 0x0970, 0x0970, 1 }, + { 0x0df4, 0x0df4, 1 }, + { 0x0e4f, 0x0e4f, 1 }, + { 0x0e5a, 0x0e5b, 1 }, + { 0x0f04, 0x0f12, 1 }, + { 0x0f3a, 0x0f3d, 1 }, + { 0x0f85, 0x0f85, 1 }, + { 0x104a, 0x104f, 1 }, // Myanmar punctuation + { 0x10fb, 0x10fb, 1 }, // Georgian punctuation + { 0x1361, 0x1368, 1 }, // Ethiopic punctuation + { 0x166d, 0x166e, 1 }, // Canadian Syl. punctuation + { 0x1680, 0x1680, 0 }, + { 0x169b, 0x169c, 1 }, + { 0x16eb, 0x16ed, 1 }, + { 0x1735, 0x1736, 1 }, + { 0x17d4, 0x17dc, 1 }, // Khmer punctuation + { 0x1800, 0x180a, 1 }, // Mongolian punctuation + { 0x2000, 0x200b, 0 }, // spaces + { 0x200c, 0x2027, 1 }, // punctuation and symbols + { 0x2028, 0x2029, 0 }, + { 0x202a, 0x202e, 1 }, // punctuation and symbols + { 0x202f, 0x202f, 0 }, + { 0x2030, 0x205e, 1 }, // punctuation and symbols + { 0x205f, 0x205f, 0 }, + { 0x2060, 0x27ff, 1 }, // punctuation and symbols + { 0x2070, 0x207f, 0x2070 }, // superscript + { 0x2080, 0x2094, 0x2080 }, // subscript + { 0x20a0, 0x27ff, 1 }, // all kinds of symbols + { 0x2800, 0x28ff, 0x2800 }, // braille + { 0x2900, 0x2998, 1 }, // arrows, brackets, etc. + { 0x29d8, 0x29db, 1 }, + { 0x29fc, 0x29fd, 1 }, + { 0x2e00, 0x2e7f, 1 }, // supplemental punctuation + { 0x3000, 0x3000, 0 }, // ideographic space + { 0x3001, 0x3020, 1 }, // ideographic punctuation + { 0x3030, 0x3030, 1 }, + { 0x303d, 0x303d, 1 }, + { 0x3040, 0x309f, 0x3040 }, // Hiragana + { 0x30a0, 0x30ff, 0x30a0 }, // Katakana + { 0x3300, 0x9fff, 0x4e00 }, // CJK Ideographs + { 0xac00, 0xd7a3, 0xac00 }, // Hangul Syllables + { 0xf900, 0xfaff, 0x4e00 }, // CJK Ideographs + { 0xfd3e, 0xfd3f, 1 }, + { 0xfe30, 0xfe6b, 1 }, // punctuation forms + { 0xff00, 0xff0f, 1 }, // half/fullwidth ASCII + { 0xff1a, 0xff20, 1 }, // half/fullwidth ASCII + { 0xff3b, 0xff40, 1 }, // half/fullwidth ASCII + { 0xff5b, 0xff65, 1 }, // half/fullwidth ASCII + { 0x1d000, 0x1d24f, 1 }, // Musical notation + { 0x1d400, 0x1d7ff, 1 }, // Mathematical Alphanumeric Symbols + { 0x1f000, 0x1f2ff, 1 }, // Game pieces; enclosed characters + { 0x1f300, 0x1f9ff, 1 }, // Many symbol blocks + { 0x20000, 0x2a6df, 0x4e00 }, // CJK Ideographs + { 0x2a700, 0x2b73f, 0x4e00 }, // CJK Ideographs + { 0x2b740, 0x2b81f, 0x4e00 }, // CJK Ideographs + { 0x2f800, 0x2fa1f, 0x4e00 }, // CJK Ideographs }; int bot = 0; int top = ARRAY_SIZE(classes) - 1; diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 4cde9d22a1..3438949e2d 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -348,28 +348,28 @@ static void handle_request(Channel *channel, msgpack_object *request) if (is_get_mode && !input_blocking()) { // Defer the event to a special queue used by os/input.c. #6247 - multiqueue_put(ch_before_blocking_events, response_event, 1, evdata); + multiqueue_put(ch_before_blocking_events, request_event, 1, evdata); } else { // Invoke immediately. - response_event((void **)&evdata); + request_event((void **)&evdata); } } else { - multiqueue_put(channel->events, response_event, 1, evdata); + multiqueue_put(channel->events, request_event, 1, evdata); DLOG("RPC: scheduled %.*s", method->via.bin.size, method->via.bin.ptr); } } -/// Responds to a message, depending on the type: -/// - Request: writes the response. -/// - Notification: does nothing. -static void response_event(void **argv) +/// Handles a message, depending on the type: +/// - Request: invokes method and writes the response (or error). +/// - Notification: invokes method (emits `nvim_error_event` on error). +static void request_event(void **argv) { RequestEvent *e = argv[0]; Channel *channel = e->channel; MsgpackRpcRequestHandler handler = e->handler; Error error = ERROR_INIT; Object result = handler.fn(channel->id, e->args, &error); - if (e->type == kMessageTypeRequest) { + if (e->type == kMessageTypeRequest || ERROR_SET(&error)) { // Send the response. msgpack_packer response; msgpack_packer_init(&response, &out_buffer, msgpack_sbuffer_write); diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index ee1cf2182f..f544576860 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -1725,314 +1725,512 @@ static bool is_qf_entry_present(qf_info_T *qi, qfline_T *qf_ptr) return true; } -/* - * jump to a quickfix line - * if dir == FORWARD go "errornr" valid entries forward - * if dir == BACKWARD go "errornr" valid entries backward - * if dir == FORWARD_FILE go "errornr" valid entries files backward - * if dir == BACKWARD_FILE go "errornr" valid entries files backward - * else if "errornr" is zero, redisplay the same line - * else go to entry "errornr" - */ -void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit) +/// Get the next valid entry in the current quickfix/location list. The search +/// starts from the current entry. Returns NULL on failure. +static qfline_T *get_next_valid_entry(qf_info_T *qi, qfline_T *qf_ptr, + int *qf_index, int dir) { - qf_info_T *ll_ref; - qfline_T *qf_ptr; - qfline_T *old_qf_ptr; - int qf_index; - int old_qf_fnum; - int old_qf_index; - int prev_index; - static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); - char_u *err = e_no_more_items; - linenr_T i; - buf_T *old_curbuf; - linenr_T old_lnum; - colnr_T screen_col; - colnr_T char_col; - char_u *line; - char_u *old_swb = p_swb; - unsigned old_swb_flags = swb_flags; - int opened_window = FALSE; - win_T *win; - win_T *altwin; - int flags; - win_T *oldwin = curwin; - int print_message = TRUE; - int len; - const bool old_KeyTyped = KeyTyped; // getting file may reset it - int ok = OK; - bool usable_win; + int idx = *qf_index; + int old_qf_fnum = qf_ptr->qf_fnum; - if (qi == NULL) - qi = &ql_info; + do { + if (idx == qi->qf_lists[qi->qf_curlist].qf_count + || qf_ptr->qf_next == NULL) { + return NULL; + } + idx++; + qf_ptr = qf_ptr->qf_next; + } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid && !qf_ptr->qf_valid) + || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); - if (qi->qf_curlist >= qi->qf_listcount - || qi->qf_lists[qi->qf_curlist].qf_count == 0) { - EMSG(_(e_quickfix)); - return; - } + *qf_index = idx; + return qf_ptr; +} - qf_ptr = qi->qf_lists[qi->qf_curlist].qf_ptr; - old_qf_ptr = qf_ptr; - qf_index = qi->qf_lists[qi->qf_curlist].qf_index; - old_qf_index = qf_index; - if (dir == FORWARD || dir == FORWARD_FILE) { /* next valid entry */ - while (errornr--) { - old_qf_ptr = qf_ptr; - prev_index = qf_index; - old_qf_fnum = qf_ptr->qf_fnum; - do { - if (qf_index == qi->qf_lists[qi->qf_curlist].qf_count - || qf_ptr->qf_next == NULL) { - qf_ptr = old_qf_ptr; - qf_index = prev_index; - if (err != NULL) { - EMSG(_(err)); - goto theend; - } - errornr = 0; - break; - } - ++qf_index; - qf_ptr = qf_ptr->qf_next; - } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid - && !qf_ptr->qf_valid) - || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); - err = NULL; - } - } else if (dir == BACKWARD || dir == BACKWARD_FILE) { /* prev. valid entry */ - while (errornr--) { - old_qf_ptr = qf_ptr; - prev_index = qf_index; - old_qf_fnum = qf_ptr->qf_fnum; - do { - if (qf_index == 1 || qf_ptr->qf_prev == NULL) { - qf_ptr = old_qf_ptr; - qf_index = prev_index; - if (err != NULL) { - EMSG(_(err)); - goto theend; - } - errornr = 0; - break; - } - --qf_index; - qf_ptr = qf_ptr->qf_prev; - } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid - && !qf_ptr->qf_valid) - || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); - err = NULL; +/// Get the previous valid entry in the current quickfix/location list. The +/// search starts from the current entry. Returns NULL on failure. +static qfline_T *get_prev_valid_entry(qf_info_T *qi, qfline_T *qf_ptr, + int *qf_index, int dir) +{ + int idx = *qf_index; + int old_qf_fnum = qf_ptr->qf_fnum; + + do { + if (idx == 1 || qf_ptr->qf_prev == NULL) { + return NULL; } - } else if (errornr != 0) { /* go to specified number */ - while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL) { - --qf_index; - qf_ptr = qf_ptr->qf_prev; + idx--; + qf_ptr = qf_ptr->qf_prev; + } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid && !qf_ptr->qf_valid) + || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); + + *qf_index = idx; + return qf_ptr; +} + +/// Get the n'th (errornr) previous/next valid entry from the current entry in +/// the quickfix list. +/// dir == FORWARD or FORWARD_FILE: next valid entry +/// dir == BACKWARD or BACKWARD_FILE: previous valid entry +static qfline_T *get_nth_valid_entry(qf_info_T *qi, int errornr, + qfline_T *qf_ptr, int *qf_index, int dir) +{ + qfline_T *prev_qf_ptr; + int prev_index; + static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); + char_u *err = e_no_more_items; + + while (errornr--) { + prev_qf_ptr = qf_ptr; + prev_index = *qf_index; + + if (dir == FORWARD || dir == FORWARD_FILE) { + qf_ptr = get_next_valid_entry(qi, qf_ptr, qf_index, dir); + } else { + qf_ptr = get_prev_valid_entry(qi, qf_ptr, qf_index, dir); } - while (errornr > qf_index && qf_index < - qi->qf_lists[qi->qf_curlist].qf_count - && qf_ptr->qf_next != NULL) { - ++qf_index; - qf_ptr = qf_ptr->qf_next; + + if (qf_ptr == NULL) { + qf_ptr = prev_qf_ptr; + *qf_index = prev_index; + if (err != NULL) { + EMSG(_(err)); + return NULL; + } + break; } + + err = NULL; } - qi->qf_lists[qi->qf_curlist].qf_index = qf_index; - if (qf_win_pos_update(qi, old_qf_index)) - /* No need to print the error message if it's visible in the error - * window */ - print_message = FALSE; + return qf_ptr; +} - /* - * For ":helpgrep" find a help window or open one. - */ - if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) { - win_T *wp = NULL; +/// Get n'th (errornr) quickfix entry +static qfline_T *get_nth_entry(qf_info_T *qi, int errornr, qfline_T *qf_ptr, + int *cur_qfidx) +{ + int qf_idx = *cur_qfidx; - if (cmdmod.tab == 0) { - FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) { - if (bt_help(wp2->w_buffer)) { - wp = wp2; - break; - } + // New error number is less than the current error number + while (errornr < qf_idx && qf_idx > 1 && qf_ptr->qf_prev != NULL) { + qf_idx--; + qf_ptr = qf_ptr->qf_prev; + } + + // New error number is greater than the current error number + while (errornr > qf_idx + && qf_idx < qi->qf_lists[qi->qf_curlist].qf_count + && qf_ptr->qf_next != NULL) { + qf_idx++; + qf_ptr = qf_ptr->qf_next; + } + + *cur_qfidx = qf_idx; + return qf_ptr; +} + +/// Find a help window or open one. +static int jump_to_help_window(qf_info_T *qi, int *opened_window) +{ + win_T *wp = NULL; + + if (cmdmod.tab != 0) { + wp = NULL; + } else { + FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) { + if (bt_help(wp2->w_buffer)) { + wp = wp2; + break; } } - if (wp != NULL && wp->w_buffer->b_nwindows > 0) - win_enter(wp, true); - else { - /* - * Split off help window; put it at far top if no position - * specified, the current window is vertically split and narrow. - */ - flags = WSP_HELP; - if (cmdmod.split == 0 && curwin->w_width != Columns - && curwin->w_width < 80) - flags |= WSP_TOP; - if (qi != &ql_info) - flags |= WSP_NEWLOC; /* don't copy the location list */ - - if (win_split(0, flags) == FAIL) - goto theend; - opened_window = TRUE; /* close it when fail */ - - if (curwin->w_height < p_hh) - win_setheight((int)p_hh); - - if (qi != &ql_info) { /* not a quickfix list */ - /* The new window should use the supplied location list */ - curwin->w_llist = qi; - qi->qf_refcount++; - } + } + + if (wp != NULL && wp->w_buffer->b_nwindows > 0) { + win_enter(wp, true); + } else { + // Split off help window; put it at far top if no position + // specified, the current window is vertically split and narrow. + int flags = WSP_HELP; + if (cmdmod.split == 0 + && curwin->w_width != Columns + && curwin->w_width < 80) { + flags |= WSP_TOP; } - if (!p_im) - restart_edit = 0; /* don't want insert mode in help file */ - } + if (qi != &ql_info) { + flags |= WSP_NEWLOC; // don't copy the location list + } - /* - * If currently in the quickfix window, find another window to show the - * file in. - */ - if (bt_quickfix(curbuf) && !opened_window) { - win_T *usable_win_ptr = NULL; + if (win_split(0, flags) == FAIL) { + return FAIL; + } - /* - * If there is no file specified, we don't know where to go. - * But do advance, otherwise ":cn" gets stuck. - */ - if (qf_ptr->qf_fnum == 0) - goto theend; + *opened_window = true; - usable_win = false; + if (curwin->w_height < p_hh) { + win_setheight((int)p_hh); + } - ll_ref = curwin->w_llist_ref; - if (ll_ref != NULL) { - /* Find a window using the same location list that is not a - * quickfix window. */ - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_llist == ll_ref - && wp->w_buffer->b_p_bt[0] != 'q') { - usable_win = true; - usable_win_ptr = wp; - break; - } + if (qi != &ql_info) { // not a quickfix list + // The new window should use the supplied location list + curwin->w_llist = qi; + qi->qf_refcount++; + } + } + + if (!p_im) { + restart_edit = 0; // don't want insert mode in help file + } + + return OK; +} + +/// Find a suitable window for opening a file (qf_fnum) and jump to it. +/// If the file is already opened in a window, jump to it. +static int qf_jump_to_usable_window(int qf_fnum, int *opened_window) +{ + win_T *usable_win_ptr = NULL; + int usable_win; + int flags; + win_T *win = NULL; + win_T *altwin; + + usable_win = 0; + + qf_info_T *ll_ref = curwin->w_llist_ref; + if (ll_ref != NULL) { + // Find a window using the same location list that is not a + // quickfix window. + FOR_ALL_WINDOWS_IN_TAB(usable_win_ptr2, curtab) { + if (usable_win_ptr2->w_llist == ll_ref + && !bt_quickfix(usable_win_ptr2->w_buffer)) { + usable_win_ptr = usable_win_ptr2; + usable_win = 1; + break; } } + } - if (!usable_win) { - /* Locate a window showing a normal buffer */ - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer->b_p_bt[0] == NUL) { - usable_win = true; - break; - } + if (!usable_win) { + // Locate a window showing a normal buffer + FOR_ALL_WINDOWS_IN_TAB(win2, curtab) { + if (win2->w_buffer->b_p_bt[0] == NUL) { + win = win2; + usable_win = 1; + break; } } + } - /* - * If no usable window is found and 'switchbuf' contains "usetab" - * then search in other tabs. - */ - if (!usable_win && (swb_flags & SWB_USETAB)) { - FOR_ALL_TAB_WINDOWS(tp, wp) { - if (wp->w_buffer->b_fnum == qf_ptr->qf_fnum) { - goto_tabpage_win(tp, wp); - usable_win = true; - goto win_found; - } + // If no usable window is found and 'switchbuf' contains "usetab" + // then search in other tabs. + if (!usable_win && (swb_flags & SWB_USETAB)) { + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer->b_fnum == qf_fnum) { + goto_tabpage_win(tp, wp); + usable_win = 1; + goto win_found; } } + } win_found: - /* - * If there is only one window and it is the quickfix window, create a - * new one above the quickfix window. - */ - if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) { - flags = WSP_ABOVE; - if (ll_ref != NULL) - flags |= WSP_NEWLOC; - if (win_split(0, flags) == FAIL) - goto failed; /* not enough room for window */ - opened_window = TRUE; /* close it when fail */ - p_swb = empty_option; /* don't split again */ - swb_flags = 0; - RESET_BINDING(curwin); - if (ll_ref != NULL) { - /* The new window should use the location list from the - * location list window */ - curwin->w_llist = ll_ref; - ll_ref->qf_refcount++; - } - } else { - if (curwin->w_llist_ref != NULL) { - /* In a location window */ - win = usable_win_ptr; + // If there is only one window and it is the quickfix window, create a + // new one above the quickfix window. + if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) { + flags = WSP_ABOVE; + if (ll_ref != NULL) { + flags |= WSP_NEWLOC; + } + if (win_split(0, flags) == FAIL) { + return FAIL; // not enough room for window + } + *opened_window = true; // close it when fail + p_swb = empty_option; // don't split again + swb_flags = 0; + RESET_BINDING(curwin); + if (ll_ref != NULL) { + // The new window should use the location list from the + // location list window + curwin->w_llist = ll_ref; + ll_ref->qf_refcount++; + } + } else { + if (curwin->w_llist_ref != NULL) { + // In a location window + win = usable_win_ptr; + if (win == NULL) { + // Find the window showing the selected file + FOR_ALL_WINDOWS_IN_TAB(win2, curtab) { + if (win2->w_buffer->b_fnum == qf_fnum) { + win = win2; + break; + } + } if (win == NULL) { - /* Find the window showing the selected file */ - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer->b_fnum == qf_ptr->qf_fnum) { - win = wp; + // Find a previous usable window + win = curwin; + do { + if (win->w_buffer->b_p_bt[0] == NUL) { break; } + if (win->w_prev == NULL) { + win = lastwin; // wrap around the top + } else { + win = win->w_prev; // go to previous window + } + } while (win != curwin); + } + } + win_goto(win); + + // If the location list for the window is not set, then set it + // to the location list from the location window + if (win->w_llist == NULL) { + win->w_llist = ll_ref; + ll_ref->qf_refcount++; + } + } else { + // Try to find a window that shows the right buffer. + // Default to the window just above the quickfix buffer. + win = curwin; + altwin = NULL; + for (;;) { + if (win->w_buffer->b_fnum == qf_fnum) { + break; + } + if (win->w_prev == NULL) { + win = lastwin; // wrap around the top + } else { + win = win->w_prev; // go to previous window + } + if (IS_QF_WINDOW(win)) { + // Didn't find it, go to the window before the quickfix window. + if (altwin != NULL) { + win = altwin; + } else if (curwin->w_prev != NULL) { + win = curwin->w_prev; + } else { + win = curwin->w_next; } - if (win == NULL) { - /* Find a previous usable window */ - win = curwin; - do { - if (win->w_buffer->b_p_bt[0] == NUL) - break; - if (win->w_prev == NULL) - win = lastwin; /* wrap around the top */ - else - win = win->w_prev; /* go to previous window */ - } while (win != curwin); - } + break; } - win_goto(win); - /* If the location list for the window is not set, then set it - * to the location list from the location window */ - if (win->w_llist == NULL) { - win->w_llist = ll_ref; - ll_ref->qf_refcount++; + // Remember a usable window. + if (altwin == NULL && !win->w_p_pvw + && win->w_buffer->b_p_bt[0] == NUL) { + altwin = win; } + } + + win_goto(win); + } + } + + return OK; +} + +/// Edit the selected file or help file. +static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, + win_T *oldwin, int *opened_window, int *abort) +{ + int retval = OK; + + if (qf_ptr->qf_type == 1) { + // Open help file (do_ecmd() will set b_help flag, readfile() will + // set b_p_ro flag). + if (!can_abandon(curbuf, forceit)) { + EMSG(_(e_nowrtmsg)); + retval = false; + } else { + retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, + ECMD_HIDE + ECMD_SET_HELP, + oldwin == curwin ? curwin : NULL); + } + } else { + int old_qf_curlist = qi->qf_curlist; + + retval = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1, + GETF_SETMARK | GETF_SWITCH, forceit); + if (qi != &ql_info && !win_valid_any_tab(oldwin)) { + EMSG(_("E924: Current window was closed")); + *abort = true; + *opened_window = false; + } else if (old_qf_curlist != qi->qf_curlist + || !is_qf_entry_present(qi, qf_ptr)) { + if (qi == &ql_info) { + EMSG(_("E925: Current quickfix was changed")); } else { + EMSG(_("E926: Current location list was changed")); + } + *abort = true; + } - /* - * Try to find a window that shows the right buffer. - * Default to the window just above the quickfix buffer. - */ - win = curwin; - altwin = NULL; - for (;; ) { - if (win->w_buffer->b_fnum == qf_ptr->qf_fnum) - break; - if (win->w_prev == NULL) - win = lastwin; /* wrap around the top */ - else - win = win->w_prev; /* go to previous window */ - - if (IS_QF_WINDOW(win)) { - /* Didn't find it, go to the window before the quickfix - * window. */ - if (altwin != NULL) - win = altwin; - else if (curwin->w_prev != NULL) - win = curwin->w_prev; - else - win = curwin->w_next; + if (*abort) { + retval = false; + } + } + + return retval; +} + +/// Goto the error line in the current file using either line/column number or a +/// search pattern. +static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char_u qf_viscol, + char_u *qf_pattern) +{ + linenr_T i; + char_u *line; + colnr_T screen_col; + colnr_T char_col; + + if (qf_pattern == NULL) { + // Go to line with error, unless qf_lnum is 0. + i = qf_lnum; + if (i > 0) { + if (i > curbuf->b_ml.ml_line_count) { + i = curbuf->b_ml.ml_line_count; + } + curwin->w_cursor.lnum = i; + } + if (qf_col > 0) { + curwin->w_cursor.col = qf_col - 1; + curwin->w_cursor.coladd = 0; + if (qf_viscol == true) { + // Check each character from the beginning of the error + // line up to the error column. For each tab character + // found, reduce the error column value by the length of + // a tab character. + line = get_cursor_line_ptr(); + screen_col = 0; + for (char_col = 0; char_col < curwin->w_cursor.col; char_col++) { + if (*line == NUL) { break; } - - /* Remember a usable window. */ - if (altwin == NULL && !win->w_p_pvw - && win->w_buffer->b_p_bt[0] == NUL) - altwin = win; + if (*line++ == '\t') { + curwin->w_cursor.col -= 7 - (screen_col % 8); + screen_col += 8 - (screen_col % 8); + } else { + screen_col++; + } } - - win_goto(win); } + check_cursor(); + } else { + beginline(BL_WHITE | BL_FIX); + } + } else { + // Move the cursor to the first line in the buffer + pos_T save_cursor = curwin->w_cursor; + curwin->w_cursor.lnum = 0; + if (!do_search(NULL, '/', qf_pattern, (long)1, SEARCH_KEEP, NULL, NULL)) { + curwin->w_cursor = save_cursor; + } + } +} + +/// Display quickfix list index and size message +static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, + buf_T *old_curbuf, linenr_T old_lnum) +{ + // Update the screen before showing the message, unless the screen + // scrolled up. + if (!msg_scrolled) { + update_topline_redraw(); + } + snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index, + qi->qf_lists[qi->qf_curlist].qf_count, + qf_ptr->qf_cleared ? _(" (line deleted)") : "", + (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); + // Add the message, skipping leading whitespace and newlines. + int len = (int)STRLEN(IObuff); + qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len); + + // Output the message. Overwrite to avoid scrolling when the 'O' + // flag is present in 'shortmess'; But when not jumping, print the + // whole message. + linenr_T i = msg_scroll; + if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) { + msg_scroll = true; + } else if (!msg_scrolled && shortmess(SHM_OVERALL)) { + msg_scroll = false; + } + msg_attr_keep(IObuff, 0, true, false); + msg_scroll = (int)i; +} + +/// jump to a quickfix line +/// if dir == FORWARD go "errornr" valid entries forward +/// if dir == BACKWARD go "errornr" valid entries backward +/// if dir == FORWARD_FILE go "errornr" valid entries files backward +/// if dir == BACKWARD_FILE go "errornr" valid entries files backward +/// else if "errornr" is zero, redisplay the same line +/// else go to entry "errornr" +void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit) +{ + qfline_T *qf_ptr; + qfline_T *old_qf_ptr; + int qf_index; + int old_qf_index; + buf_T *old_curbuf; + linenr_T old_lnum; + char_u *old_swb = p_swb; + unsigned old_swb_flags = swb_flags; + int opened_window = false; + win_T *oldwin = curwin; + int print_message = true; + const bool old_KeyTyped = KeyTyped; // getting file may reset it + int retval = OK; + + if (qi == NULL) + qi = &ql_info; + + if (qi->qf_curlist >= qi->qf_listcount + || qi->qf_lists[qi->qf_curlist].qf_count == 0) { + EMSG(_(e_quickfix)); + return; + } + + qf_ptr = qi->qf_lists[qi->qf_curlist].qf_ptr; + old_qf_ptr = qf_ptr; + qf_index = qi->qf_lists[qi->qf_curlist].qf_index; + old_qf_index = qf_index; + if (dir == FORWARD || dir == FORWARD_FILE || dir == BACKWARD + || dir == BACKWARD_FILE) { // next/prev valid entry + qf_ptr = get_nth_valid_entry(qi, errornr, qf_ptr, &qf_index, dir); + if (qf_ptr == NULL) { + qf_ptr = old_qf_ptr; + qf_index = old_qf_index; + goto theend; // The horror... the horror... + } + } else if (errornr != 0) { // go to specified number + qf_ptr = get_nth_entry(qi, errornr, qf_ptr, &qf_index); + } + + qi->qf_lists[qi->qf_curlist].qf_index = qf_index; + if (qf_win_pos_update(qi, old_qf_index)) + /* No need to print the error message if it's visible in the error + * window */ + print_message = FALSE; + + // For ":helpgrep" find a help window or open one. + if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) { + if (jump_to_help_window(qi, &opened_window) == FAIL) { + goto theend; + } + } + + // If currently in the quickfix window, find another window to show the + // file in. + if (bt_quickfix(curbuf) && !opened_window) { + // If there is no file specified, we don't know where to go. + // But do advance, otherwise ":cn" gets stuck. + if (qf_ptr->qf_fnum == 0) { + goto theend; + } + if (qf_jump_to_usable_window(qf_ptr->qf_fnum, &opened_window) == FAIL) { + goto failed; } } @@ -2044,122 +2242,28 @@ win_found: old_lnum = curwin->w_cursor.lnum; if (qf_ptr->qf_fnum != 0) { - if (qf_ptr->qf_type == 1) { - /* Open help file (do_ecmd() will set b_help flag, readfile() will - * set b_p_ro flag). */ - if (!can_abandon(curbuf, forceit)) { - EMSG(_(e_nowrtmsg)); - ok = false; - } else { - ok = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, - ECMD_HIDE + ECMD_SET_HELP, - oldwin == curwin ? curwin : NULL); - } - } else { - int old_qf_curlist = qi->qf_curlist; - bool is_abort = false; - - ok = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1, - GETF_SETMARK | GETF_SWITCH, forceit); - if (qi != &ql_info && !win_valid_any_tab(oldwin)) { - EMSG(_("E924: Current window was closed")); - is_abort = true; - opened_window = false; - } else if (old_qf_curlist != qi->qf_curlist // -V560 - || !is_qf_entry_present(qi, qf_ptr)) { - if (qi == &ql_info) { - EMSG(_("E925: Current quickfix was changed")); - } else { - EMSG(_("E926: Current location list was changed")); - } - is_abort = true; - } - - if (is_abort) { - ok = false; - qi = NULL; - qf_ptr = NULL; - } + int abort = false; + retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, oldwin, &opened_window, + &abort); + if (abort) { + qi = NULL; + qf_ptr = NULL; } } - if (ok == OK) { - /* When not switched to another buffer, still need to set pc mark */ - if (curbuf == old_curbuf) + if (retval == OK) { + // When not switched to another buffer, still need to set pc mark + if (curbuf == old_curbuf) { setpcmark(); - - if (qf_ptr->qf_pattern == NULL) { - /* - * Go to line with error, unless qf_lnum is 0. - */ - i = qf_ptr->qf_lnum; - if (i > 0) { - if (i > curbuf->b_ml.ml_line_count) - i = curbuf->b_ml.ml_line_count; - curwin->w_cursor.lnum = i; - } - if (qf_ptr->qf_col > 0) { - curwin->w_cursor.col = qf_ptr->qf_col - 1; - curwin->w_cursor.coladd = 0; - if (qf_ptr->qf_viscol == true) { - // Check each character from the beginning of the error - // line up to the error column. For each tab character - // found, reduce the error column value by the length of - // a tab character. - line = get_cursor_line_ptr(); - screen_col = 0; - for (char_col = 0; char_col < curwin->w_cursor.col; ++char_col) { - if (*line == NUL) - break; - if (*line++ == '\t') { - curwin->w_cursor.col -= 7 - (screen_col % 8); - screen_col += 8 - (screen_col % 8); - } else - ++screen_col; - } - } - check_cursor(); - } else - beginline(BL_WHITE | BL_FIX); - } else { - pos_T save_cursor; - - /* Move the cursor to the first line in the buffer */ - save_cursor = curwin->w_cursor; - curwin->w_cursor.lnum = 0; - if (!do_search(NULL, '/', qf_ptr->qf_pattern, (long)1, - SEARCH_KEEP, NULL, NULL)) { - curwin->w_cursor = save_cursor; - } } + qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol, + qf_ptr->qf_pattern); + if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped) foldOpenCursor(); if (print_message) { - /* Update the screen before showing the message, unless the screen - * scrolled up. */ - if (!msg_scrolled) - update_topline_redraw(); - sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index, - qi->qf_lists[qi->qf_curlist].qf_count, - qf_ptr->qf_cleared ? _(" (line deleted)") : "", - (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); - /* Add the message, skipping leading whitespace and newlines. */ - len = (int)STRLEN(IObuff); - qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len); - - /* Output the message. Overwrite to avoid scrolling when the 'O' - * flag is present in 'shortmess'; But when not jumping, print the - * whole message. */ - i = msg_scroll; - if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) { - msg_scroll = true; - } else if (!msg_scrolled && shortmess(SHM_OVERALL)) { - msg_scroll = false; - } - msg_ext_set_kind("quickfix"); - msg_attr_keep(IObuff, 0, true, false); - msg_scroll = (int)i; + qf_jump_print_msg(qi, qf_index, qf_ptr, old_curbuf, old_lnum); } } else { if (opened_window) { |