diff options
-rw-r--r-- | runtime/doc/eval.txt | 47 | ||||
-rw-r--r-- | runtime/macros/justify.vim | 319 | ||||
-rw-r--r-- | runtime/pack/dist/opt/justify/plugin/justify.vim | 316 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 5 | ||||
-rw-r--r-- | src/nvim/eval.c | 32 | ||||
-rw-r--r-- | src/nvim/testdir/Makefile | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_window_id.vim | 71 | ||||
-rw-r--r-- | src/nvim/version.c | 4 | ||||
-rw-r--r-- | src/nvim/window.c | 93 |
9 files changed, 562 insertions, 326 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index de1ced160c..3fa5474a7e 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -754,13 +754,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 @@ -2138,6 +2148,10 @@ 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_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 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} @@ -7192,6 +7206,29 @@ wildmenumode() *wildmenumode()* (Note, this needs the 'wildcharm' option set appropriately). +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/runtime/macros/justify.vim b/runtime/macros/justify.vim index 4ef3bf95fa..011a911401 100644 --- a/runtime/macros/justify.vim +++ b/runtime/macros/justify.vim @@ -1,316 +1,3 @@ -" Function to left and right align text. -" -" Written by: Preben "Peppe" Guldberg <c928400@student.dtu.dk> -" Created: 980806 14:13 (or around that time anyway) -" Revised: 001103 00:36 (See "Revisions" below) - - -" function Justify( [ textwidth [, maxspaces [, indent] ] ] ) -" -" Justify() will left and right align a line by filling in an -" appropriate amount of spaces. Extra spaces are added to existing -" spaces starting from the right side of the line. As an example, the -" following documentation has been justified. -" -" The function takes the following arguments: - -" textwidth argument -" ------------------ -" If not specified, the value of the 'textwidth' option is used. If -" 'textwidth' is zero a value of 80 is used. -" -" Additionally the arguments 'tw' and '' are accepted. The value of -" 'textwidth' will be used. These are handy, if you just want to specify -" the maxspaces argument. - -" maxspaces argument -" ------------------ -" If specified, alignment will only be done, if the longest space run -" after alignment is no longer than maxspaces. -" -" An argument of '' is accepted, should the user like to specify all -" arguments. -" -" To aid user defined commands, negative values are accepted aswell. -" Using a negative value specifies the default behaviour: any length of -" space runs will be used to justify the text. - -" indent argument -" --------------- -" This argument specifies how a line should be indented. The default is -" to keep the current indentation. -" -" Negative values: Keep current amount of leading whitespace. -" Positive values: Indent all lines with leading whitespace using this -" amount of whitespace. -" -" Note that the value 0, needs to be quoted as a string. This value -" leads to a left flushed text. -" -" Additionally units of 'shiftwidth'/'sw' and 'tabstop'/'ts' may be -" added. In this case, if the value of indent is positive, the amount of -" whitespace to be added will be multiplied by the value of the -" 'shiftwidth' and 'tabstop' settings. If these units are used, the -" argument must be given as a string, eg. Justify('','','2sw'). -" -" If the values of 'sw' or 'tw' are negative, they are treated as if -" they were 0, which means that the text is flushed left. There is no -" check if a negative number prefix is used to change the sign of a -" negative 'sw' or 'ts' value. -" -" As with the other arguments, '' may be used to get the default -" behaviour. - - -" Notes: -" -" If the line, adjusted for space runs and leading/trailing whitespace, -" is wider than the used textwidth, the line will be left untouched (no -" whitespace removed). This should be equivalent to the behaviour of -" :left, :right and :center. -" -" If the resulting line is shorter than the used textwidth it is left -" untouched. -" -" All space runs in the line are truncated before the alignment is -" carried out. -" -" If you have set 'noexpandtab', :retab! is used to replace space runs -" with whitespace using the value of 'tabstop'. This should be -" conformant with :left, :right and :center. -" -" If joinspaces is set, an extra space is added after '.', '?' and '!'. -" If 'cpooptions' include 'j', extra space is only added after '.'. -" (This may on occasion conflict with maxspaces.) - - -" Related mappings: -" -" Mappings that will align text using the current text width, using at -" most four spaces in a space run and keeping current indentation. -nmap _j :%call Justify('tw',4)<CR> -vmap _j :call Justify('tw',4)<CR> -" -" Mappings that will remove space runs and format lines (might be useful -" prior to aligning the text). -nmap ,gq :%s/\s\+/ /g<CR>gq1G -vmap ,gq :s/\s\+/ /g<CR>gvgq - - -" User defined command: -" -" The following is an ex command that works as a shortcut to the Justify -" function. Arguments to Justify() can be added after the command. -com! -range -nargs=* Justify <line1>,<line2>call Justify(<f-args>) -" -" The following commands are all equivalent: -" -" 1. Simplest use of Justify(): -" :call Justify() -" :Justify -" -" 2. The _j mapping above via the ex command: -" :%Justify tw 4 -" -" 3. Justify visualised text at 72nd column while indenting all -" previously indented text two shiftwidths -" :'<,'>call Justify(72,'','2sw') -" :'<,'>Justify 72 -1 2sw -" -" This documentation has been justified using the following command: -":se et|kz|1;/^" function Justify(/+,'z-g/^" /s/^" //|call Justify(70,3)|s/^/" / - -" Revisions: -" 001103: If 'joinspaces' was set, calculations could be wrong. -" Tabs at start of line could also lead to errors. -" Use setline() instead of "exec 's/foo/bar/' - safer. -" Cleaned up the code a bit. -" -" Todo: Convert maps to the new script specific form - -" Error function -function! Justify_error(message) - echohl Error - echo "Justify([tw, [maxspaces [, indent]]]): " . a:message - echohl None -endfunction - - -" Now for the real thing -function! Justify(...) range - - if a:0 > 3 - call Justify_error("Too many arguments (max 3)") - return 1 - endif - - " Set textwidth (accept 'tw' and '' as arguments) - if a:0 >= 1 - if a:1 =~ '^\(tw\)\=$' - let tw = &tw - elseif a:1 =~ '^\d\+$' - let tw = a:1 - else - call Justify_error("tw must be a number (>0), '' or 'tw'") - return 2 - endif - else - let tw = &tw - endif - if tw == 0 - let tw = 80 - endif - - " Set maximum number of spaces between WORDs - if a:0 >= 2 - if a:2 == '' - let maxspaces = tw - elseif a:2 =~ '^-\d\+$' - let maxspaces = tw - elseif a:2 =~ '^\d\+$' - let maxspaces = a:2 - else - call Justify_error("maxspaces must be a number or ''") - return 3 - endif - else - let maxspaces = tw - endif - if maxspaces <= 1 - call Justify_error("maxspaces should be larger than 1") - return 4 - endif - - " Set the indentation style (accept sw and ts units) - let indent_fix = '' - if a:0 >= 3 - if (a:3 == '') || a:3 =~ '^-[1-9]\d*\(shiftwidth\|sw\|tabstop\|ts\)\=$' - let indent = -1 - elseif a:3 =~ '^-\=0\(shiftwidth\|sw\|tabstop\|ts\)\=$' - let indent = 0 - elseif a:3 =~ '^\d\+\(shiftwidth\|sw\|tabstop\|ts\)\=$' - let indent = substitute(a:3, '\D', '', 'g') - elseif a:3 =~ '^\(shiftwidth\|sw\|tabstop\|ts\)$' - let indent = 1 - else - call Justify_error("indent: a number with 'sw'/'ts' unit") - return 5 - endif - if indent >= 0 - while indent > 0 - let indent_fix = indent_fix . ' ' - let indent = indent - 1 - endwhile - let indent_sw = 0 - if a:3 =~ '\(shiftwidth\|sw\)' - let indent_sw = &sw - elseif a:3 =~ '\(tabstop\|ts\)' - let indent_sw = &ts - endif - let indent_fix2 = '' - while indent_sw > 0 - let indent_fix2 = indent_fix2 . indent_fix - let indent_sw = indent_sw - 1 - endwhile - let indent_fix = indent_fix2 - endif - else - let indent = -1 - endif - - " Avoid substitution reports - let save_report = &report - set report=1000000 - - " Check 'joinspaces' and 'cpo' - if &js == 1 - if &cpo =~ 'j' - let join_str = '\(\. \)' - else - let join_str = '\([.!?!] \)' - endif - endif - - let cur = a:firstline - while cur <= a:lastline - - let str_orig = getline(cur) - let save_et = &et - set et - exec cur . "retab" - let &et = save_et - let str = getline(cur) - - let indent_str = indent_fix - let indent_n = strlen(indent_str) - " Shall we remember the current indentation - if indent < 0 - let indent_orig = matchstr(str_orig, '^\s*') - if strlen(indent_orig) > 0 - let indent_str = indent_orig - let indent_n = strlen(matchstr(str, '^\s*')) - endif - endif - - " Trim trailing, leading and running whitespace - let str = substitute(str, '\s\+$', '', '') - let str = substitute(str, '^\s\+', '', '') - let str = substitute(str, '\s\+', ' ', 'g') - let str_n = strdisplaywidth(str) - - " Possible addition of space after punctuation - if exists("join_str") - let str = substitute(str, join_str, '\1 ', 'g') - endif - let join_n = strdisplaywidth(str) - str_n - - " Can extraspaces be added? - " Note that str_n may be less than strlen(str) [joinspaces above] - if strdisplaywidth(str) <= tw - indent_n && str_n > 0 - " How many spaces should be added - let s_add = tw - str_n - indent_n - join_n - let s_nr = strlen(substitute(str, '\S', '', 'g') ) - join_n - let s_dup = s_add / s_nr - let s_mod = s_add % s_nr - - " Test if the changed line fits with tw - if 0 <= (str_n + (maxspaces - 1)*s_nr + indent_n) - tw - - " Duplicate spaces - while s_dup > 0 - let str = substitute(str, '\( \+\)', ' \1', 'g') - let s_dup = s_dup - 1 - endwhile - - " Add extra spaces from the end - while s_mod > 0 - let str = substitute(str, '\(\(\s\+\S\+\)\{' . s_mod . '}\)$', ' \1', '') - let s_mod = s_mod - 1 - endwhile - - " Indent the line - if indent_n > 0 - let str = substitute(str, '^', indent_str, '' ) - endif - - " Replace the line - call setline(cur, str) - - " Convert to whitespace - if &et == 0 - exec cur . 'retab!' - endif - - endif " Change of line - endif " Possible change - - let cur = cur + 1 - endwhile - - norm ^ - - let &report = save_report - -endfunction - -" EOF vim: tw=78 ts=8 sw=4 sts=4 noet ai +" Load the justify package. +" For those users who were loading the justify plugin from here. +packadd justify diff --git a/runtime/pack/dist/opt/justify/plugin/justify.vim b/runtime/pack/dist/opt/justify/plugin/justify.vim new file mode 100644 index 0000000000..4ef3bf95fa --- /dev/null +++ b/runtime/pack/dist/opt/justify/plugin/justify.vim @@ -0,0 +1,316 @@ +" Function to left and right align text. +" +" Written by: Preben "Peppe" Guldberg <c928400@student.dtu.dk> +" Created: 980806 14:13 (or around that time anyway) +" Revised: 001103 00:36 (See "Revisions" below) + + +" function Justify( [ textwidth [, maxspaces [, indent] ] ] ) +" +" Justify() will left and right align a line by filling in an +" appropriate amount of spaces. Extra spaces are added to existing +" spaces starting from the right side of the line. As an example, the +" following documentation has been justified. +" +" The function takes the following arguments: + +" textwidth argument +" ------------------ +" If not specified, the value of the 'textwidth' option is used. If +" 'textwidth' is zero a value of 80 is used. +" +" Additionally the arguments 'tw' and '' are accepted. The value of +" 'textwidth' will be used. These are handy, if you just want to specify +" the maxspaces argument. + +" maxspaces argument +" ------------------ +" If specified, alignment will only be done, if the longest space run +" after alignment is no longer than maxspaces. +" +" An argument of '' is accepted, should the user like to specify all +" arguments. +" +" To aid user defined commands, negative values are accepted aswell. +" Using a negative value specifies the default behaviour: any length of +" space runs will be used to justify the text. + +" indent argument +" --------------- +" This argument specifies how a line should be indented. The default is +" to keep the current indentation. +" +" Negative values: Keep current amount of leading whitespace. +" Positive values: Indent all lines with leading whitespace using this +" amount of whitespace. +" +" Note that the value 0, needs to be quoted as a string. This value +" leads to a left flushed text. +" +" Additionally units of 'shiftwidth'/'sw' and 'tabstop'/'ts' may be +" added. In this case, if the value of indent is positive, the amount of +" whitespace to be added will be multiplied by the value of the +" 'shiftwidth' and 'tabstop' settings. If these units are used, the +" argument must be given as a string, eg. Justify('','','2sw'). +" +" If the values of 'sw' or 'tw' are negative, they are treated as if +" they were 0, which means that the text is flushed left. There is no +" check if a negative number prefix is used to change the sign of a +" negative 'sw' or 'ts' value. +" +" As with the other arguments, '' may be used to get the default +" behaviour. + + +" Notes: +" +" If the line, adjusted for space runs and leading/trailing whitespace, +" is wider than the used textwidth, the line will be left untouched (no +" whitespace removed). This should be equivalent to the behaviour of +" :left, :right and :center. +" +" If the resulting line is shorter than the used textwidth it is left +" untouched. +" +" All space runs in the line are truncated before the alignment is +" carried out. +" +" If you have set 'noexpandtab', :retab! is used to replace space runs +" with whitespace using the value of 'tabstop'. This should be +" conformant with :left, :right and :center. +" +" If joinspaces is set, an extra space is added after '.', '?' and '!'. +" If 'cpooptions' include 'j', extra space is only added after '.'. +" (This may on occasion conflict with maxspaces.) + + +" Related mappings: +" +" Mappings that will align text using the current text width, using at +" most four spaces in a space run and keeping current indentation. +nmap _j :%call Justify('tw',4)<CR> +vmap _j :call Justify('tw',4)<CR> +" +" Mappings that will remove space runs and format lines (might be useful +" prior to aligning the text). +nmap ,gq :%s/\s\+/ /g<CR>gq1G +vmap ,gq :s/\s\+/ /g<CR>gvgq + + +" User defined command: +" +" The following is an ex command that works as a shortcut to the Justify +" function. Arguments to Justify() can be added after the command. +com! -range -nargs=* Justify <line1>,<line2>call Justify(<f-args>) +" +" The following commands are all equivalent: +" +" 1. Simplest use of Justify(): +" :call Justify() +" :Justify +" +" 2. The _j mapping above via the ex command: +" :%Justify tw 4 +" +" 3. Justify visualised text at 72nd column while indenting all +" previously indented text two shiftwidths +" :'<,'>call Justify(72,'','2sw') +" :'<,'>Justify 72 -1 2sw +" +" This documentation has been justified using the following command: +":se et|kz|1;/^" function Justify(/+,'z-g/^" /s/^" //|call Justify(70,3)|s/^/" / + +" Revisions: +" 001103: If 'joinspaces' was set, calculations could be wrong. +" Tabs at start of line could also lead to errors. +" Use setline() instead of "exec 's/foo/bar/' - safer. +" Cleaned up the code a bit. +" +" Todo: Convert maps to the new script specific form + +" Error function +function! Justify_error(message) + echohl Error + echo "Justify([tw, [maxspaces [, indent]]]): " . a:message + echohl None +endfunction + + +" Now for the real thing +function! Justify(...) range + + if a:0 > 3 + call Justify_error("Too many arguments (max 3)") + return 1 + endif + + " Set textwidth (accept 'tw' and '' as arguments) + if a:0 >= 1 + if a:1 =~ '^\(tw\)\=$' + let tw = &tw + elseif a:1 =~ '^\d\+$' + let tw = a:1 + else + call Justify_error("tw must be a number (>0), '' or 'tw'") + return 2 + endif + else + let tw = &tw + endif + if tw == 0 + let tw = 80 + endif + + " Set maximum number of spaces between WORDs + if a:0 >= 2 + if a:2 == '' + let maxspaces = tw + elseif a:2 =~ '^-\d\+$' + let maxspaces = tw + elseif a:2 =~ '^\d\+$' + let maxspaces = a:2 + else + call Justify_error("maxspaces must be a number or ''") + return 3 + endif + else + let maxspaces = tw + endif + if maxspaces <= 1 + call Justify_error("maxspaces should be larger than 1") + return 4 + endif + + " Set the indentation style (accept sw and ts units) + let indent_fix = '' + if a:0 >= 3 + if (a:3 == '') || a:3 =~ '^-[1-9]\d*\(shiftwidth\|sw\|tabstop\|ts\)\=$' + let indent = -1 + elseif a:3 =~ '^-\=0\(shiftwidth\|sw\|tabstop\|ts\)\=$' + let indent = 0 + elseif a:3 =~ '^\d\+\(shiftwidth\|sw\|tabstop\|ts\)\=$' + let indent = substitute(a:3, '\D', '', 'g') + elseif a:3 =~ '^\(shiftwidth\|sw\|tabstop\|ts\)$' + let indent = 1 + else + call Justify_error("indent: a number with 'sw'/'ts' unit") + return 5 + endif + if indent >= 0 + while indent > 0 + let indent_fix = indent_fix . ' ' + let indent = indent - 1 + endwhile + let indent_sw = 0 + if a:3 =~ '\(shiftwidth\|sw\)' + let indent_sw = &sw + elseif a:3 =~ '\(tabstop\|ts\)' + let indent_sw = &ts + endif + let indent_fix2 = '' + while indent_sw > 0 + let indent_fix2 = indent_fix2 . indent_fix + let indent_sw = indent_sw - 1 + endwhile + let indent_fix = indent_fix2 + endif + else + let indent = -1 + endif + + " Avoid substitution reports + let save_report = &report + set report=1000000 + + " Check 'joinspaces' and 'cpo' + if &js == 1 + if &cpo =~ 'j' + let join_str = '\(\. \)' + else + let join_str = '\([.!?!] \)' + endif + endif + + let cur = a:firstline + while cur <= a:lastline + + let str_orig = getline(cur) + let save_et = &et + set et + exec cur . "retab" + let &et = save_et + let str = getline(cur) + + let indent_str = indent_fix + let indent_n = strlen(indent_str) + " Shall we remember the current indentation + if indent < 0 + let indent_orig = matchstr(str_orig, '^\s*') + if strlen(indent_orig) > 0 + let indent_str = indent_orig + let indent_n = strlen(matchstr(str, '^\s*')) + endif + endif + + " Trim trailing, leading and running whitespace + let str = substitute(str, '\s\+$', '', '') + let str = substitute(str, '^\s\+', '', '') + let str = substitute(str, '\s\+', ' ', 'g') + let str_n = strdisplaywidth(str) + + " Possible addition of space after punctuation + if exists("join_str") + let str = substitute(str, join_str, '\1 ', 'g') + endif + let join_n = strdisplaywidth(str) - str_n + + " Can extraspaces be added? + " Note that str_n may be less than strlen(str) [joinspaces above] + if strdisplaywidth(str) <= tw - indent_n && str_n > 0 + " How many spaces should be added + let s_add = tw - str_n - indent_n - join_n + let s_nr = strlen(substitute(str, '\S', '', 'g') ) - join_n + let s_dup = s_add / s_nr + let s_mod = s_add % s_nr + + " Test if the changed line fits with tw + if 0 <= (str_n + (maxspaces - 1)*s_nr + indent_n) - tw + + " Duplicate spaces + while s_dup > 0 + let str = substitute(str, '\( \+\)', ' \1', 'g') + let s_dup = s_dup - 1 + endwhile + + " Add extra spaces from the end + while s_mod > 0 + let str = substitute(str, '\(\(\s\+\S\+\)\{' . s_mod . '}\)$', ' \1', '') + let s_mod = s_mod - 1 + endwhile + + " Indent the line + if indent_n > 0 + let str = substitute(str, '^', indent_str, '' ) + endif + + " Replace the line + call setline(cur, str) + + " Convert to whitespace + if &et == 0 + exec cur . 'retab!' + endif + + endif " Change of line + endif " Possible change + + let cur = cur + 1 + endwhile + + norm ^ + + let &report = save_report + +endfunction + +" EOF vim: tw=78 ts=8 sw=4 sts=4 noet ai diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index b515c4e1e4..46687f344c 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -937,8 +937,9 @@ struct matchitem { */ struct window_S { uint64_t handle; - buf_T *w_buffer; /* buffer we are a window into (used - often, keep it the first item!) */ + int w_id; ///< unique window ID + buf_T *w_buffer; ///< buffer we are a window into (used + ///< often, keep it the first item!) synblock_T *w_s; /* for :ownsyntax */ diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a5333d74be..7839a7f645 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6987,6 +6987,10 @@ static struct fst { { "virtcol", 1, 1, f_virtcol }, { "visualmode", 0, 1, f_visualmode }, { "wildmenumode", 0, 0, f_wildmenumode }, + { "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 }, @@ -17150,6 +17154,32 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = 1; } +/// "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); +} + /* * "winbufnr(nr)" function */ @@ -18437,7 +18467,7 @@ static void init_tv(typval_T *varp) * caller of incompatible types: it sets *denote to TRUE if "denote" * is not NULL or returns -1 otherwise. */ -static long get_tv_number(typval_T *varp) +long get_tv_number(typval_T *varp) { int error = FALSE; diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 9a0bba83fe..4979aae57a 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -39,6 +39,7 @@ NEW_TESTS = \ test_timers.res \ test_viml.res \ test_visual.res \ + test_window_id.res \ test_alot.res SCRIPTS_GUI := test16.out diff --git a/src/nvim/testdir/test_window_id.vim b/src/nvim/testdir/test_window_id.vim new file mode 100644 index 0000000000..b9e9f45c49 --- /dev/null +++ b/src/nvim/testdir/test_window_id.vim @@ -0,0 +1,71 @@ +" Test using the window ID. + +func Test_win_getid() + edit one + let id1 = win_getid() + split two + let id2 = win_getid() + split three + let id3 = win_getid() + tabnew + edit four + let id4 = win_getid() + split five + let id5 = win_getid() + 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)) + + only! +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 0adaa9cd12..aa337f9fae 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -604,7 +604,7 @@ static int included_patches[] = { 1676, 1675, // 1674 NA - // 1673, + 1673, // 1672 NA // 1671, // 1670, @@ -720,7 +720,7 @@ static int included_patches[] = { // 1560 NA // 1559, // 1558, - // 1557, + 1557, // 1556 NA // 1555 NA 1554, diff --git a/src/nvim/window.c b/src/nvim/window.c index e267d493bf..350b54d595 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3683,6 +3683,8 @@ win_T *buf_jump_open_tab(buf_T *buf) return NULL; } +static int last_win_id = 0; + /* * Allocate a window structure and link it in the window list when "hidden" is * FALSE. @@ -3695,6 +3697,7 @@ static win_T *win_alloc(win_T *after, int hidden) win_T *new_wp = xcalloc(1, sizeof(win_T)); handle_register_window(new_wp); win_alloc_lines(new_wp); + new_wp->w_id = ++last_win_id; /* init w: variables */ new_wp->w_vars = dict_alloc(); @@ -5674,3 +5677,93 @@ static bool frame_check_width(frame_T *topfrp, int width) } return true; } + +int win_getid(typval_T *argvars) +{ + if (argvars[0].v_type == VAR_UNKNOWN) { + return curwin->w_id; + } + int winnr = get_tv_number(&argvars[0]); + win_T *wp; + 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; +} |