diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 60e15a873b..1c52ff28bf 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.4. Last change: 2016 Mar 12 +*eval.txt* For Vim version 7.4. Last change: 2016 Mar 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -764,13 +764,23 @@ expressions are referring to the same |List| or |Dictionary| instance. A copy of a |List| is different from the original |List|. When using "is" without a |List| or a |Dictionary| it is equivalent to using "equal", using "isnot" equivalent to using "not equal". Except that a different type means the -values are different: "4 == '4'" is true, "4 is '4'" is false and "0 is []" is -false and not an error. "is#"/"isnot#" and "is?"/"isnot?" can be used to match -and ignore case. +values are different: > + echo 4 == '4' + 1 + echo 4 is '4' + 0 + echo 0 is [] + 0 +"is#"/"isnot#" and "is?"/"isnot?" can be used to match and ignore case. When comparing a String with a Number, the String is converted to a Number, -and the comparison is done on Numbers. This means that "0 == 'x'" is TRUE, -because 'x' converted to a Number is zero. +and the comparison is done on Numbers. This means that: > + echo 0 == 'x' + 1 +because 'x' converted to a Number is zero. However: > + echo [0] == ['x'] + 0 +Inside a List or Dictionary this conversion is not used. When comparing two Strings, this is done with strcmp() or stricmp(). This results in the mathematical difference (comparing byte values), not @@ -2139,6 +2149,11 @@ values( {dict}) List values in {dict} virtcol( {expr}) Number screen column of cursor or mark visualmode( [expr]) String last visual mode used wildmenumode() Number whether 'wildmenu' mode is active +win_findbuf( {bufnr}) List find windows containing {bufnr} +win_getid( [{win} [, {tab}]]) Number get window ID for {win} in {tab} +win_gotoid( {expr}) Number go to window with ID {expr} +win_id2tabwin( {expr}) List get tab and window nr from window ID +win_id2win( {expr}) Number get window nr from window ID winbufnr( {nr}) Number buffer number of window {nr} wincol() Number window column of the cursor winheight( {nr}) Number height of window {nr} @@ -7162,6 +7177,33 @@ wildmenumode() *wildmenumode()* (Note, this needs the 'wildcharm' option set appropriately). +win_findbuf({bufnr}) *win_findbuf()* + Returns a list with window IDs for windows that contain buffer + {bufnr}. When there is none the list is empty. + +win_getid([{win} [, {tab}]]) *win_getid()* + Get the window ID for the specified window. + When {win} is missing use the current window. + With {win} this is the window number. The top window has + number 1. + Without {tab} use the current tab, otherwise the tab with + number {tab}. The first tab has number one. + Return zero if the window cannot be found. + +win_gotoid({expr}) *win_gotoid()* + Go to window with ID {expr}. This may also change the current + tabpage. + Return 1 if successful, 0 if the window cannot be found. + +win_id2tabwin({expr} *win_id2tabwin()* + Return a list with the tab number and window number of window + with ID {expr}: [tabnr, winnr]. + Return [0, 0] if the window cannot be found. + +win_id2win({expr}) *win_id2win()* + Return the window number of window with ID {expr}. + Return 0 if the window cannot be found in the current tabpage. + *winbufnr()* winbufnr({nr}) The result is a Number, which is the number of the buffer associated with window {nr}. When {nr} is zero, the number of diff --git a/src/Makefile b/src/Makefile index ca57f6453b..d9b1a5856e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -424,7 +424,7 @@ CClink = $(CC) # NOTE: This may cause threading to be enabled, which has side effects (such # as using different libraries and debugging becomes more difficult). # NOTE: Using this together with Perl may cause a crash in initialization. -# For Python3 support make a symbolic link in /usr/local/bin: +# For Python3 support make a symbolic link in /usr/local/bin: # ln -s python3 python3.1 # If both python2.x and python3.x are enabled then the linking will be via # dlopen(), dlsym(), dlclose(), i.e. pythonX.Y.so must be available @@ -2014,30 +2014,38 @@ test1 \ # Run individual NEW style test, assuming that Vim was already compiled. test_arglist \ test_assert \ + test_assign \ test_backspace_opt \ test_cdo \ test_channel \ test_cursor_func \ test_delete \ test_expand \ + test_feedkeys \ + test_file_perm \ test_glob2regpat \ test_hardcopy \ + test_history \ test_increment \ + test_join \ test_json \ test_langmap \ test_lispwords \ test_menu \ + test_packadd \ test_perl \ test_quickfix \ test_reltime \ test_searchpos \ test_set \ test_sort \ + test_syn_attr \ test_syntax \ test_undolevels \ test_unlet \ test_viminfo \ test_viml \ + test_visual \ test_alot: cd testdir; rm -f $@.res test.log messages; $(MAKE) -f Makefile $@.res VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) @if test -f testdir/test.log; then \ @@ -2121,6 +2129,9 @@ installrtbase: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \ -$(SHELL) ./installman.sh install $(DEST_MAN) "" $(INSTALLMANARGS) @echo generating help tags # Generate the help tags with ":helptags" to handle all languages. +# Move the distributed tags file aside and restore it, to avoid it being +# different from the repository. + cd $(HELPSOURCE); mv -f tags tags.dist -@cd $(HELPSOURCE); $(MAKE) VIMEXE=$(DEST_BIN)/$(VIMTARGET) vimtags cd $(HELPSOURCE); \ files=`ls *.txt tags`; \ @@ -2130,6 +2141,7 @@ installrtbase: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \ chmod $(HELPMOD) $$files $(INSTALL_DATA) $(HELPSOURCE)/*.pl $(DEST_HELP) chmod $(SCRIPTMOD) $(DEST_HELP)/*.pl + cd $(HELPSOURCE); mv -f tags.dist tags # install the menu files $(INSTALL_DATA) $(SCRIPTSOURCE)/menu.vim $(SYS_MENU_FILE) chmod $(VIMSCRIPTMOD) $(SYS_MENU_FILE) diff --git a/src/eval.c b/src/eval.c index 80a2d052b5..e5b66f24af 100644 --- a/src/eval.c +++ b/src/eval.c @@ -434,7 +434,6 @@ static int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); static int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); static long list_find_nr(list_T *l, long idx, int *errorp); static long list_idx_of_item(list_T *l, listitem_T *item); -static int list_append_number(list_T *l, varnumber_T n); static int list_extend(list_T *l1, list_T *l2, listitem_T *bef); static int list_concat(list_T *l1, list_T *l2, typval_T *tv); static list_T *list_copy(list_T *orig, int deep, int copyID); @@ -808,6 +807,11 @@ static void f_values(typval_T *argvars, typval_T *rettv); static void f_virtcol(typval_T *argvars, typval_T *rettv); static void f_visualmode(typval_T *argvars, typval_T *rettv); static void f_wildmenumode(typval_T *argvars, typval_T *rettv); +static void f_win_findbuf(typval_T *argvars, typval_T *rettv); +static void f_win_getid(typval_T *argvars, typval_T *rettv); +static void f_win_gotoid(typval_T *argvars, typval_T *rettv); +static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv); +static void f_win_id2win(typval_T *argvars, typval_T *rettv); static void f_winbufnr(typval_T *argvars, typval_T *rettv); static void f_wincol(typval_T *argvars, typval_T *rettv); static void f_winheight(typval_T *argvars, typval_T *rettv); @@ -6469,7 +6473,7 @@ list_append_string(list_T *l, char_u *str, int len) * Append "n" to list "l". * Returns FAIL when out of memory. */ - static int + int list_append_number(list_T *l, varnumber_T n) { listitem_T *li; @@ -8385,6 +8389,11 @@ static struct fst {"virtcol", 1, 1, f_virtcol}, {"visualmode", 0, 1, f_visualmode}, {"wildmenumode", 0, 0, f_wildmenumode}, + {"win_findbuf", 1, 1, f_win_findbuf}, + {"win_getid", 0, 2, f_win_getid}, + {"win_gotoid", 1, 1, f_win_gotoid}, + {"win_id2tabwin", 1, 1, f_win_id2tabwin}, + {"win_id2win", 1, 1, f_win_id2win}, {"winbufnr", 1, 1, f_winbufnr}, {"wincol", 0, 0, f_wincol}, {"winheight", 1, 1, f_winheight}, @@ -12668,6 +12677,53 @@ f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) #endif } +/* + * "win_findbuf()" function + */ + static void +f_win_findbuf(typval_T *argvars, typval_T *rettv) +{ + if (rettv_list_alloc(rettv) != FAIL) + win_findbuf(argvars, rettv->vval.v_list); +} + +/* + * "win_getid()" function + */ + static void +f_win_getid(typval_T *argvars, typval_T *rettv) +{ + rettv->vval.v_number = win_getid(argvars); +} + +/* + * "win_gotoid()" function + */ + static void +f_win_gotoid(typval_T *argvars, typval_T *rettv) +{ + rettv->vval.v_number = win_gotoid(argvars); +} + +/* + * "win_id2tabwin()" function + */ + static void +f_win_id2tabwin(typval_T *argvars, typval_T *rettv) +{ + if (rettv_list_alloc(rettv) != FAIL) + win_id2tabwin(argvars, rettv->vval.v_list); +} + +/* + * "win_id2win()" function + */ + static void +f_win_id2win(typval_T *argvars, typval_T *rettv) +{ + rettv->vval.v_number = win_id2win(argvars); +} + /* * "getwinposy()" function */ diff --git a/src/ex_getln.c b/src/ex_getln.c index 6f7ce4e167..258d190233 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -111,7 +111,7 @@ static int ExpandFromContext(expand_T *xp, char_u *, int *, char_u ***, int); static int expand_showtail(expand_T *xp); #ifdef FEAT_CMDL_COMPL static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg); -static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirname[]); +static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, char *dirname[]); static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file); # ifdef FEAT_CMDHIST static char_u *get_history_arg(expand_T *xp, int idx); @@ -4639,22 +4639,23 @@ ExpandFromContext( if (xp->xp_context == EXPAND_COLORS) { char *directories[] = {"colors", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + return ExpandRTDir(pat, DIP_START + DIP_OPT, num_file, file, + directories); } if (xp->xp_context == EXPAND_COMPILER) { char *directories[] = {"compiler", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + return ExpandRTDir(pat, 0, num_file, file, directories); } if (xp->xp_context == EXPAND_OWNSYNTAX) { char *directories[] = {"syntax", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + return ExpandRTDir(pat, 0, num_file, file, directories); } if (xp->xp_context == EXPAND_FILETYPE) { char *directories[] = {"syntax", "indent", "ftplugin", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + return ExpandRTDir(pat, 0, num_file, file, directories); } # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) if (xp->xp_context == EXPAND_USER_LIST) @@ -5133,13 +5134,19 @@ ExpandUserList( #endif /* - * Expand color scheme, compiler or filetype names: - * 'runtimepath'/{dirnames}/{pat}.vim + * Expand color scheme, compiler or filetype names. + * Search from 'runtimepath': + * 'runtimepath'/{dirnames}/{pat}.vim + * When "flags" has DIP_START: search also from 'start' of 'packpath': + * 'packpath'/pack/ * /start/ * /{dirnames}/{pat}.vim + * When "flags" has DIP_OPT: search also from 'opt' of 'packpath': + * 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim * "dirnames" is an array with one or more directory names. */ static int ExpandRTDir( char_u *pat, + int flags, int *num_file, char_u ***file, char *dirnames[]) @@ -5169,6 +5176,36 @@ ExpandRTDir( vim_free(s); } + if (flags & DIP_START) { + for (i = 0; dirnames[i] != NULL; ++i) + { + s = alloc((unsigned)(STRLEN(dirnames[i]) + pat_len + 22)); + if (s == NULL) + { + ga_clear_strings(&ga); + return FAIL; + } + sprintf((char *)s, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat); + globpath(p_pp, s, &ga, 0); + vim_free(s); + } + } + + if (flags & DIP_OPT) { + for (i = 0; dirnames[i] != NULL; ++i) + { + s = alloc((unsigned)(STRLEN(dirnames[i]) + pat_len + 20)); + if (s == NULL) + { + ga_clear_strings(&ga); + return FAIL; + } + sprintf((char *)s, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat); + globpath(p_pp, s, &ga, 0); + vim_free(s); + } + } + for (i = 0; i < ga.ga_len; ++i) { match = ((char_u **)ga.ga_data)[i]; diff --git a/src/proto/eval.pro b/src/proto/eval.pro index f5e0d19504..7035f26e24 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -59,6 +59,7 @@ void list_append(list_T *l, listitem_T *item); int list_append_tv(list_T *l, typval_T *tv); int list_append_dict(list_T *list, dict_T *dict); int list_append_string(list_T *l, char_u *str, int len); +int list_append_number(list_T *l, varnumber_T n); int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item); void list_insert(list_T *l, listitem_T *ni, listitem_T *item); void vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2); diff --git a/src/proto/window.pro b/src/proto/window.pro index 613fe219bb..05b6b9daeb 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -83,4 +83,9 @@ void clear_matches(win_T *wp); matchitem_T *get_match(win_T *wp, int id); int get_win_number(win_T *wp, win_T *first_win); int get_tab_number(tabpage_T *tp); +int win_getid(typval_T *argvars); +int win_gotoid(typval_T *argvars); +void win_id2tabwin(typval_T *argvars, list_T *list); +int win_id2win(typval_T *argvars); +void win_findbuf(typval_T *argvars, list_T *list); /* vim: set ft=c : */ diff --git a/src/structs.h b/src/structs.h index 382c30bb86..ae33462efb 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2285,6 +2285,8 @@ struct matchitem */ struct window_S { + int w_id; /* unique window ID */ + buf_T *w_buffer; /* buffer we are a window into (used often, keep it the first item!) */ diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 5ad1718c6f..233ca12dfd 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -186,6 +186,7 @@ NEW_TESTS = test_arglist.res \ test_viminfo.res \ test_viml.res \ test_visual.res \ + test_window_id.res \ test_alot.res diff --git a/src/testdir/test_packadd.vim b/src/testdir/test_packadd.vim index 52e6a33cab..44b733ffce 100644 --- a/src/testdir/test_packadd.vim +++ b/src/testdir/test_packadd.vim @@ -135,6 +135,29 @@ func Test_colorscheme() call assert_equal(1, g:found_three) endfunc +func Test_colorscheme_completion() + let colordirrun = &packpath . '/runtime/colors' + let colordirstart = &packpath . '/pack/mine/start/foo/colors' + let colordiropt = &packpath . '/pack/mine/opt/bar/colors' + call mkdir(colordirrun, 'p') + call mkdir(colordirstart, 'p') + call mkdir(colordiropt, 'p') + call writefile(['let g:found_one = 1'], colordirrun . '/one.vim') + call writefile(['let g:found_two = 1'], colordirstart . '/two.vim') + call writefile(['let g:found_three = 1'], colordiropt . '/three.vim') + exe 'set rtp=' . &packpath . '/runtime' + + let li=[] + call feedkeys(":colorscheme " . repeat("\", 1) . "')\call add(li, '\", 't') + call feedkeys(":colorscheme " . repeat("\", 2) . "')\call add(li, '\", 't') + call feedkeys(":colorscheme " . repeat("\", 3) . "')\call add(li, '\", 't') + call feedkeys(":colorscheme " . repeat("\", 4) . "')\call add(li, '\", 'tx') + call assert_equal("colorscheme one", li[0]) + call assert_equal("colorscheme three", li[1]) + call assert_equal("colorscheme two", li[2]) + call assert_equal("colorscheme ", li[3]) +endfunc + func Test_runtime() let rundir = &packpath . '/runtime/extra' let startdir = &packpath . '/pack/mine/start/foo/extra' diff --git a/src/testdir/test_window_id.vim b/src/testdir/test_window_id.vim new file mode 100644 index 0000000000..fa3ebd757e --- /dev/null +++ b/src/testdir/test_window_id.vim @@ -0,0 +1,79 @@ +" Test using the window ID. + +func Test_win_getid() + edit one + let id1 = win_getid() + split two + let id2 = win_getid() + let bufnr2 = bufnr('%') + split three + let id3 = win_getid() + tabnew + edit four + let id4 = win_getid() + split five + let id5 = win_getid() + let bufnr5 = bufnr('%') + tabnext + + wincmd w + call assert_equal("two", expand("%")) + call assert_equal(id2, win_getid()) + let nr2 = winnr() + wincmd w + call assert_equal("one", expand("%")) + call assert_equal(id1, win_getid()) + let nr1 = winnr() + wincmd w + call assert_equal("three", expand("%")) + call assert_equal(id3, win_getid()) + let nr3 = winnr() + tabnext + call assert_equal("five", expand("%")) + call assert_equal(id5, win_getid()) + let nr5 = winnr() + wincmd w + call assert_equal("four", expand("%")) + call assert_equal(id4, win_getid()) + let nr4 = winnr() + tabnext + + exe nr1 . "wincmd w" + call assert_equal(id1, win_getid()) + exe nr2 . "wincmd w" + call assert_equal(id2, win_getid()) + exe nr3 . "wincmd w" + call assert_equal(id3, win_getid()) + tabnext + exe nr4 . "wincmd w" + call assert_equal(id4, win_getid()) + exe nr5 . "wincmd w" + call assert_equal(id5, win_getid()) + + call win_gotoid(id2) + call assert_equal("two", expand("%")) + call win_gotoid(id4) + call assert_equal("four", expand("%")) + call win_gotoid(id1) + call assert_equal("one", expand("%")) + call win_gotoid(id5) + call assert_equal("five", expand("%")) + + call assert_equal(0, win_id2win(9999)) + call assert_equal(nr5, win_id2win(id5)) + call assert_equal(0, win_id2win(id1)) + tabnext + call assert_equal(nr1, win_id2win(id1)) + + call assert_equal([0, 0], win_id2tabwin(9999)) + call assert_equal([1, nr2], win_id2tabwin(id2)) + call assert_equal([2, nr4], win_id2tabwin(id4)) + + call assert_equal([], win_findbuf(9999)) + call assert_equal([id2], win_findbuf(bufnr2)) + call win_gotoid(id5) + split + call assert_equal(sort([id5, win_getid()]), sort(win_findbuf(bufnr5))) + + only! +endfunc diff --git a/src/version.c b/src/version.c index b794a63a3f..27d10ca753 100644 --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,16 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1558, +/**/ + 1557, +/**/ + 1556, +/**/ + 1555, +/**/ + 1554, /**/ 1553, /**/ diff --git a/src/window.c b/src/window.c index 3b2846142d..d16bd37d68 100644 --- a/src/window.c +++ b/src/window.c @@ -4546,6 +4546,8 @@ buf_jump_open_tab(buf_T *buf) } #endif +static int last_win_id = 0; + /* * Allocate a window structure and link it in the window list when "hidden" is * FALSE. @@ -4568,6 +4570,8 @@ win_alloc(win_T *after UNUSED, int hidden UNUSED) return NULL; } + new_wp->w_id = ++last_win_id; + #ifdef FEAT_EVAL /* init w: variables */ new_wp->w_vars = dict_alloc(); @@ -7208,3 +7212,114 @@ frame_check_width(frame_T *topfrp, int width) } #endif +#if defined(FEAT_EVAL) || defined(PROTO) + int +win_getid(typval_T *argvars) +{ + int winnr; + win_T *wp; + + if (argvars[0].v_type == VAR_UNKNOWN) + return curwin->w_id; + winnr = get_tv_number(&argvars[0]); + if (winnr > 0) + { + if (argvars[1].v_type == VAR_UNKNOWN) + wp = firstwin; + else + { + tabpage_T *tp; + int tabnr = get_tv_number(&argvars[1]); + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + if (--tabnr == 0) + break; + if (tp == NULL) + return -1; + wp = tp->tp_firstwin; + } + for ( ; wp != NULL; wp = wp->w_next) + if (--winnr == 0) + return wp->w_id; + } + return 0; +} + + int +win_gotoid(typval_T *argvars) +{ + win_T *wp; + tabpage_T *tp; + int id = get_tv_number(&argvars[0]); + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + for (wp = tp == curtab ? firstwin : tp->tp_firstwin; + wp != NULL; wp = wp->w_next) + if (wp->w_id == id) + { + goto_tabpage_win(tp, wp); + return 1; + } + return 0; +} + + void +win_id2tabwin(typval_T *argvars, list_T *list) +{ + win_T *wp; + tabpage_T *tp; + int winnr = 1; + int tabnr = 1; + int id = get_tv_number(&argvars[0]); + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + { + for (wp = tp == curtab ? firstwin : tp->tp_firstwin; + wp != NULL; wp = wp->w_next) + { + if (wp->w_id == id) + { + list_append_number(list, tabnr); + list_append_number(list, winnr); + return; + } + ++winnr; + } + ++tabnr; + winnr = 1; + } + list_append_number(list, 0); + list_append_number(list, 0); +} + + int +win_id2win(typval_T *argvars) +{ + win_T *wp; + int nr = 1; + int id = get_tv_number(&argvars[0]); + + for (wp = firstwin; wp != NULL; wp = wp->w_next) + { + if (wp->w_id == id) + return nr; + ++nr; + } + return 0; +} + + void +win_findbuf(typval_T *argvars, list_T *list) +{ + win_T *wp; + tabpage_T *tp; + int bufnr = get_tv_number(&argvars[0]); + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + for (wp = tp == curtab ? firstwin : tp->tp_firstwin; + wp != NULL; wp = wp->w_next) + if (wp->w_buffer->b_fnum == bufnr) + list_append_number(list, wp->w_id); +} + +#endif