diff options
author | James McCoy <jamessan@jamessan.com> | 2017-12-31 16:07:53 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-31 16:07:53 -0500 |
commit | 907b2f18f7c35eb289357aa08e00178562b65a42 (patch) | |
tree | e631ed9b5f004a4d3038b73e4c7b73208dae6fe1 | |
parent | 9ad557fb2d4a1ef3101c7894a1038aa2eb932a48 (diff) | |
parent | 9fe6c12e8159b656e53b6d79226aa5a1c39fdc27 (diff) | |
download | rneovim-907b2f18f7c35eb289357aa08e00178562b65a42.tar.gz rneovim-907b2f18f7c35eb289357aa08e00178562b65a42.tar.bz2 rneovim-907b2f18f7c35eb289357aa08e00178562b65a42.zip |
Merge pull request #7795 from jamessan/vim-8.0.0591
[RFC] vim-patch:8.0.0591,8.0.0634,8.0.0641,8.0.0657
-rw-r--r-- | runtime/doc/deprecated.txt | 8 | ||||
-rw-r--r-- | runtime/doc/eval.txt | 42 | ||||
-rw-r--r-- | runtime/doc/options.txt | 4 | ||||
-rw-r--r-- | runtime/doc/quickfix.txt | 6 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 128 | ||||
-rw-r--r-- | src/nvim/testdir/test_quickfix.vim | 111 |
6 files changed, 251 insertions, 48 deletions
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 72dfe1230e..b3073ffe58 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -37,8 +37,8 @@ Functions ~ *file_readable()* Obsolete name for |filereadable()|. *highlight_exists()* Obsolete name for |hlexists()|. *highlightID()* Obsolete name for |hlID()|. -*jobclose()* Obsolete name for |chanclose()| -*jobsend()* Obsolete name for |chansend()| +*jobclose()* Obsolete name for |chanclose()| +*jobsend()* Obsolete name for |chansend()| *last_buffer_nr()* Obsolete name for bufnr("$"). Modifiers ~ @@ -48,8 +48,10 @@ Modifiers ~ *:map-special* <> notation is always enabled. |cpo-<| Options ~ +'gd' +'gdefault' Enables the |:substitute| flag 'g' by default. *'fe'* 'fenc'+'enc' before Vim 6.0; no longer used. -*'highlight'* *'hl'* Names of builtin |highlight-groups| cannot be changed. +*'highlight'* *'hl'* Names of builtin |highlight-groups| cannot be changed. *'langnoremap'* Deprecated alias to 'nolangremap'. *'vi'* *'viminfo'* Deprecated alias to 'shada' option. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index a9474b58a3..ae62498d35 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -4327,17 +4327,25 @@ getqflist([{what}]) *getqflist()* If the optional {what} dictionary argument is supplied, then returns only the items listed in {what} as a dictionary. The following string items are supported in {what}: + context get the context stored with |setqflist()| + items quickfix list entries nr get information for this quickfix list; zero - means the current quickfix list + means the current quickfix list and '$' means + the last quickfix list title get the list title winid get the |window-ID| (if opened) all all of the above quickfix properties Non-string items in {what} are ignored. If "nr" is not present then the current quickfix list is used. + To get the number of lists in the quickfix stack, set 'nr' to + '$' in {what}. The 'nr' value in the returned dictionary + contains the quickfix stack size. In case of error processing {what}, an empty dictionary is returned. The returned dictionary contains the following entries: + context context information stored with |setqflist()| + items quickfix list entries nr quickfix list number title quickfix list title text winid quickfix |window-ID| (if opened) @@ -6885,7 +6893,12 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()* only the items listed in {what} are set. The first {list} argument is ignored. The following items can be specified in {what}: - nr list number in the quickfix stack + context any Vim type can be stored as a context + items list of quickfix entries. Same as the {list} + argument. + nr list number in the quickfix stack; zero + means the current quickfix list and '$' means + the last quickfix list title quickfix list title text Unsupported keys in {what} are ignored. If the "nr" item is not present, then the current quickfix list @@ -6990,18 +7003,22 @@ shellescape({string} [, {special}]) *shellescape()* quotes within {string}. Otherwise, it will enclose {string} in single quotes and replace all "'" with "'\''". + When the {special} argument is present and it's a non-zero Number or a non-empty String (|non-zero-arg|), then special items such as "!", "%", "#" and "<cword>" will be preceded by a backslash. This backslash will be removed again by the |:!| command. + The "!" character will be escaped (again with a |non-zero-arg| {special}) when 'shell' contains "csh" in the tail. That is because for csh and tcsh "!" is used for history replacement even when inside single quotes. - The <NL> character is also escaped. With a |non-zero-arg| - {special} and 'shell' containing "csh" in the tail it's + + With a |non-zero-arg| {special} the <NL> character is also + escaped. When 'shell' containing "csh" in the tail it's escaped a second time. + Example of use with a |:!| command: > :exe '!dir ' . shellescape(expand('<cfile>'), 1) < This results in a directory listing for the file under the @@ -10508,18 +10525,19 @@ missing: > To execute a command only when the |+eval| feature is disabled requires a trick, as this example shows: > - if 1 - nnoremap : :" - endif - normal :set history=111<CR> - if 1 - nunmap : - endif + + silent! while 0 + set history=111 + silent! endwhile + +When the |+eval| feature is available the command is skipped because of the +"while 0". Without the |+eval| feature the "while 0" is an error, which is +silently ignored, and the command is executed. The "<CR>" here is a real CR character, type CTRL-V Enter to get it. When the |+eval| feature is available the ":" is remapped to add a double -quote, which has the effect of commenting-out the command. without the +quote, which has the effect of commenting-out the command. Without the |+eval| feature the nnoremap command is skipped and the command is executed. ============================================================================== diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index f70ec32bd8..067aad1f93 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -2712,6 +2712,10 @@ A jump table for the options with a short description can be found at |Q_op|. :s///g subst. one subst. all :s///gg subst. all subst. one + DEPRECATED: Setting this option may break plugins that are not aware + of this option. Also, many users get confused that adding the /g flag + has the opposite effect of that it normally does. + *'grepformat'* *'gfm'* 'grepformat' 'gfm' string (default "%f:%l:%m,%f:%l%m,%f %l%m") global diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index 74f82b2c65..f280286290 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -470,7 +470,11 @@ keep its height, ignoring 'winheight' and 'equalalways'. You can change the height manually (e.g., by dragging the status line above it with the mouse). In the quickfix window, each line is one error. The line number is equal to -the error number. You can use ":.cc" to jump to the error under the cursor. +the error number. The current entry is highlighted with the QuickFixLine +highlighting. You can change it to your liking, e.g.: > + :hi QuickFixLine ctermbg=Yellow guibg=Yellow + +You can use ":.cc" to jump to the error under the cursor. Hitting the <Enter> key or double-clicking the mouse on a line has the same effect. The file containing the error is opened in the window above the quickfix window. If there already is a window for that file, it is used diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 120a449690..224e43008d 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -76,18 +76,25 @@ struct qfline_S { */ #define LISTCOUNT 10 +/// Quickfix/Location list definition +/// +/// Usually the list contains one or more entries. But an empty list can be +/// created using setqflist()/setloclist() with a title and/or user context +/// information and entries can be added later using setqflist()/setloclist(). typedef struct qf_list_S { - qfline_T *qf_start; // pointer to the first error - qfline_T *qf_last; // pointer to the last error - qfline_T *qf_ptr; // pointer to the current error - int qf_count; // number of errors (0 means no error list) - int qf_index; // current index in the error list - int qf_nonevalid; // TRUE if not a single valid entry found - char_u *qf_title; // title derived from the command that created - // the error list - typval_T *qf_ctx; // context set by setqflist/setloclist + qfline_T *qf_start; ///< pointer to the first error + qfline_T *qf_last; ///< pointer to the last error + qfline_T *qf_ptr; ///< pointer to the current error + int qf_count; ///< number of errors (0 means empty list) + int qf_index; ///< current index in the error list + int qf_nonevalid; ///< TRUE if not a single valid entry found + char_u *qf_title; ///< title derived from the command that created + ///< the error list or set by setqflist + typval_T *qf_ctx; ///< context set by setqflist/setloclist } qf_list_T; +/// Quickfix/Location list stack definition +/// Contains a list of quickfix/location lists (qf_list_T) struct qf_info_S { /* * Count of references to this list. Used only for location lists. @@ -1185,6 +1192,9 @@ qf_init_end: static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title) { + xfree(qi->qf_lists[qf_idx].qf_title); + qi->qf_lists[qf_idx].qf_title = NULL; + if (title != NULL) { size_t len = STRLEN(title) + 1; char_u *p = xmallocz(len); @@ -2396,8 +2406,9 @@ void qf_history(exarg_T *eap) } } -/// Free all the entries in the error list "idx". -static void qf_free(qf_info_T *qi, int idx) +/// Free all the entries in the error list "idx". Note that other information +/// associated with the list like context and title are not freed. +static void qf_free_items(qf_info_T *qi, int idx) { qfline_T *qfp; qfline_T *qfpnext; @@ -2421,12 +2432,9 @@ static void qf_free(qf_info_T *qi, int idx) qi->qf_lists[idx].qf_start = qfpnext; qi->qf_lists[idx].qf_count--; } - xfree(qi->qf_lists[idx].qf_title); + qi->qf_lists[idx].qf_start = NULL; qi->qf_lists[idx].qf_ptr = NULL; - qi->qf_lists[idx].qf_title = NULL; - tv_free(qi->qf_lists[idx].qf_ctx); - qi->qf_lists[idx].qf_ctx = NULL; qi->qf_lists[idx].qf_index = 0; qi->qf_lists[idx].qf_start = NULL; qi->qf_lists[idx].qf_last = NULL; @@ -2442,6 +2450,18 @@ static void qf_free(qf_info_T *qi, int idx) qi->qf_multiscan = false; } +/// Free error list "idx". Frees all the entries in the quickfix list, +/// associated context information and the title. +static void qf_free(qf_info_T *qi, int idx) +{ + qf_free_items(qi, idx); + + xfree(qi->qf_lists[idx].qf_title); + qi->qf_lists[idx].qf_title = NULL; + tv_free(qi->qf_lists[idx].qf_ctx); + qi->qf_lists[idx].qf_ctx = NULL; +} + /* * qf_mark_adjust: adjust marks */ @@ -4088,16 +4108,22 @@ enum { int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) { qf_info_T *qi = &ql_info; + dictitem_T *di; if (wp != NULL) { qi = GET_LOC_LIST(wp); if (qi == NULL) { + // If querying for the size of the location list, return 0 + if (((di = tv_dict_find(what, S_LEN("nr"))) != NULL) + && (di->di_tv.v_type == VAR_STRING) + && strequal((const char *)di->di_tv.vval.v_string, "$")) { + return tv_dict_add_nr(retdict, S_LEN("nr"), 0); + } return FAIL; } } int status = OK; - dictitem_T *di; int flags = QF_GETLIST_NONE; int qf_idx = qi->qf_curlist; // default is the current list @@ -4110,6 +4136,17 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { return FAIL; } + } else if (qi->qf_listcount == 0) { // stack is empty + return FAIL; + } + flags |= QF_GETLIST_NR; + } else if (di->di_tv.v_type == VAR_STRING + && strequal((const char *)di->di_tv.vval.v_string, "$")) { + // Get the last quickfix list number + if (qi->qf_listcount > 0) { + qf_idx = qi->qf_listcount - 1; + } else { + qf_idx = -1; // Quickfix stack is empty } flags |= QF_GETLIST_NR; } else { @@ -4117,20 +4154,26 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) } } - if (tv_dict_find(what, S_LEN("all")) != NULL) { - flags |= QF_GETLIST_ALL; - } + if (qf_idx != -1) { + if (tv_dict_find(what, S_LEN("all")) != NULL) { + flags |= QF_GETLIST_ALL; + } - if (tv_dict_find(what, S_LEN("title")) != NULL) { - flags |= QF_GETLIST_TITLE; - } + if (tv_dict_find(what, S_LEN("title")) != NULL) { + flags |= QF_GETLIST_TITLE; + } - if (tv_dict_find(what, S_LEN("winid")) != NULL) { - flags |= QF_GETLIST_WINID; - } + if (tv_dict_find(what, S_LEN("winid")) != NULL) { + flags |= QF_GETLIST_WINID; + } - if (tv_dict_find(what, S_LEN("context")) != NULL) { - flags |= QF_GETLIST_CONTEXT; + if (tv_dict_find(what, S_LEN("context")) != NULL) { + flags |= QF_GETLIST_CONTEXT; + } + + if (tv_dict_find(what, S_LEN("items")) != NULL) { + flags |= QF_GETLIST_ITEMS; + } } if (flags & QF_GETLIST_TITLE) { @@ -4149,6 +4192,11 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) status = tv_dict_add_nr(retdict, S_LEN("winid"), win->handle); } } + if ((status == OK) && (flags & QF_GETLIST_ITEMS)) { + list_T *l = tv_list_alloc(); + (void)get_errorlist(wp, qf_idx, l); + tv_dict_add_list(retdict, S_LEN("items"), l); + } if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) { if (qi->qf_lists[qf_idx].qf_ctx != NULL) { @@ -4185,7 +4233,7 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, // Adding to existing list, use last entry. old_last = qi->qf_lists[qf_idx].qf_last; } else if (action == 'r') { - qf_free(qi, qf_idx); + qf_free_items(qi, qf_idx); qf_store_title(qi, qf_idx, title); } @@ -4293,13 +4341,24 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action) if (di->di_tv.vval.v_number != 0) { qf_idx = (int)di->di_tv.vval.v_number - 1; } - if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { + + if ((action == ' ' || action == 'a') && qf_idx == qi->qf_listcount) { + // When creating a new list, accept qf_idx pointing to the next + // non-available list + newlist = true; + } else if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { return FAIL; + } else { + newlist = false; // use the specified list } + } else if (di->di_tv.v_type == VAR_STRING + && strequal((const char *)di->di_tv.vval.v_string, "$") + && qi->qf_listcount > 0) { + qf_idx = qi->qf_listcount - 1; + newlist = false; } else { return FAIL; } - newlist = false; // use the specified list } if (newlist) { @@ -4318,6 +4377,15 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action) retval = OK; } } + if ((di = tv_dict_find(what, S_LEN("items"))) != NULL) { + if (di->di_tv.v_type == VAR_LIST) { + char_u *title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title); + + retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list, + title_save, action == ' ' ? 'a' : action); + xfree(title_save); + } + } if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) { tv_free(qi->qf_lists[qf_idx].qf_ctx); diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 30023dddc9..95a7d29089 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -1632,12 +1632,12 @@ func XbottomTests(cchar) call assert_fails('lbottom', 'E776:') endif - call g:Xsetlist([{'filename': 'foo', 'lnum': 42}]) + call g:Xsetlist([{'filename': 'foo', 'lnum': 42}]) Xopen let wid = win_getid() call assert_equal(1, line('.')) wincmd w - call g:Xsetlist([{'filename': 'var', 'lnum': 24}], 'a') + call g:Xsetlist([{'filename': 'var', 'lnum': 24}], 'a') Xbottom call win_gotoid(wid) call assert_equal(2, line('.')) @@ -1817,6 +1817,73 @@ func Xproperty_tests(cchar) call test_garbagecollect_now() let m = g:Xgetlist({'context' : 1}) call assert_equal(["red", "blue", "green"], m.context) + + " Test for setting/getting items + Xexpr "" + let qfprev = g:Xgetlist({'nr':0}) + call g:Xsetlist([], ' ', {'title':'Green', + \ 'items' : [{'filename':'F1', 'lnum':10}]}) + let qfcur = g:Xgetlist({'nr':0}) + call assert_true(qfcur.nr == qfprev.nr + 1) + let l = g:Xgetlist({'items':1}) + call assert_equal('F1', bufname(l.items[0].bufnr)) + call assert_equal(10, l.items[0].lnum) + call g:Xsetlist([], 'a', {'items' : [{'filename':'F2', 'lnum':20}, + \ {'filename':'F2', 'lnum':30}]}) + let l = g:Xgetlist({'items':1}) + call assert_equal('F2', bufname(l.items[2].bufnr)) + call assert_equal(30, l.items[2].lnum) + call g:Xsetlist([], 'r', {'items' : [{'filename':'F3', 'lnum':40}]}) + let l = g:Xgetlist({'items':1}) + call assert_equal('F3', bufname(l.items[0].bufnr)) + call assert_equal(40, l.items[0].lnum) + call g:Xsetlist([], 'r', {'items' : []}) + let l = g:Xgetlist({'items':1}) + call assert_equal(0, len(l.items)) + + " Save and restore the quickfix stack + call g:Xsetlist([], 'f') + call assert_equal(0, g:Xgetlist({'nr':'$'}).nr) + Xexpr "File1:10:Line1" + Xexpr "File2:20:Line2" + Xexpr "File3:30:Line3" + let last_qf = g:Xgetlist({'nr':'$'}).nr + call assert_equal(3, last_qf) + let qstack = [] + for i in range(1, last_qf) + let qstack = add(qstack, g:Xgetlist({'nr':i, 'all':1})) + endfor + call g:Xsetlist([], 'f') + for i in range(len(qstack)) + call g:Xsetlist([], ' ', qstack[i]) + endfor + call assert_equal(3, g:Xgetlist({'nr':'$'}).nr) + call assert_equal(10, g:Xgetlist({'nr':1, 'items':1}).items[0].lnum) + call assert_equal(20, g:Xgetlist({'nr':2, 'items':1}).items[0].lnum) + call assert_equal(30, g:Xgetlist({'nr':3, 'items':1}).items[0].lnum) + call g:Xsetlist([], 'f') + + " Swap two quickfix lists + Xexpr "File1:10:Line10" + Xexpr "File2:20:Line20" + Xexpr "File3:30:Line30" + call g:Xsetlist([], 'r', {'nr':1,'title':'Colors','context':['Colors']}) + call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']}) + let l1=g:Xgetlist({'nr':1,'all':1}) + let l2=g:Xgetlist({'nr':2,'all':1}) + let l1.nr=2 + let l2.nr=1 + call g:Xsetlist([], 'r', l1) + call g:Xsetlist([], 'r', l2) + let newl1=g:Xgetlist({'nr':1,'all':1}) + let newl2=g:Xgetlist({'nr':2,'all':1}) + call assert_equal(':Fruits', newl1.title) + call assert_equal(['Fruits'], newl1.context) + call assert_equal('Line20', newl1.items[0].text) + call assert_equal(':Colors', newl2.title) + call assert_equal(['Colors'], newl2.context) + call assert_equal('Line10', newl2.items[0].text) + call g:Xsetlist([], 'f') endfunc func Test_qf_property() @@ -2102,3 +2169,43 @@ func Test_bufoverflow() set efm&vim endfunc +func Test_cclose_from_copen() + augroup QF_Test + au! + au FileType qf :cclose + augroup END + copen + augroup QF_Test + au! + augroup END + augroup! QF_Test +endfunc + +" Tests for getting the quickfix stack size +func XsizeTests(cchar) + call s:setup_commands(a:cchar) + + call g:Xsetlist([], 'f') + call assert_equal(0, g:Xgetlist({'nr':'$'}).nr) + call assert_equal(1, len(g:Xgetlist({'nr':'$', 'all':1}))) + call assert_equal(0, len(g:Xgetlist({'nr':0}))) + + Xexpr "File1:10:Line1" + Xexpr "File2:20:Line2" + Xexpr "File3:30:Line3" + Xolder | Xolder + call assert_equal(3, g:Xgetlist({'nr':'$'}).nr) + call g:Xsetlist([], 'f') + + Xexpr "File1:10:Line1" + Xexpr "File2:20:Line2" + Xexpr "File3:30:Line3" + Xolder | Xolder + call g:Xsetlist([], 'a', {'nr':'$', 'title':'Compiler'}) + call assert_equal('Compiler', g:Xgetlist({'nr':3, 'all':1}).title) +endfunc + +func Test_Qf_Size() + call XsizeTests('c') + call XsizeTests('l') +endfunc |