mirror of
https://github.com/vim/vim
synced 2025-07-21 05:43:00 +00:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
f2460a3aec | |||
348808f7c0 | |||
c2a4b35b86 | |||
04d0522046 | |||
777770fbb0 | |||
158906cffc | |||
5cab73f8cc | |||
170fcfcf25 | |||
6e587dcbf3 | |||
1af5ce01c3 | |||
4af11174f7 | |||
0de50864a7 | |||
adbc11c2ee | |||
ff80cb6807 | |||
a78e9c61a0 | |||
2e6638d5f0 | |||
7077892a79 | |||
07ada5ff2f | |||
94255df057 | |||
eed3571fe0 | |||
560979ed4f | |||
80147dda4f | |||
d816cd94d8 |
@ -1,4 +1,4 @@
|
||||
*autocmd.txt* For Vim version 8.2. Last change: 2020 Jan 17
|
||||
*autocmd.txt* For Vim version 8.2. Last change: 2020 Jan 26
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
|
@ -933,8 +933,7 @@ These modifiers can be given, in this order:
|
||||
directory.
|
||||
:. Reduce file name to be relative to current directory, if
|
||||
possible. File name is unmodified if it is not below the
|
||||
current directory, but on MS-Windows the drive is removed if
|
||||
it is the current drive.
|
||||
current directory.
|
||||
For maximum shortness, use ":~:.".
|
||||
:h Head of the file name (the last component and any separators
|
||||
removed). Cannot be used with :e, :r or :t.
|
||||
|
@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 8.2. Last change: 2020 Jan 19
|
||||
*eval.txt* For Vim version 8.2. Last change: 2020 Feb 03
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -1808,7 +1808,9 @@ v:errors Errors found by assert functions, such as |assert_true()|.
|
||||
|
||||
*v:event* *event-variable*
|
||||
v:event Dictionary containing information about the current
|
||||
|autocommand|. The dictionary is emptied when the |autocommand|
|
||||
|autocommand|. See the specific event for what it puts in
|
||||
this dictionary.
|
||||
The dictionary is emptied when the |autocommand|
|
||||
finishes, please refer to |dict-identity| for how to get an
|
||||
independent copy of it.
|
||||
|
||||
@ -2846,6 +2848,7 @@ term_wait({buf} [, {time}]) Number wait for screen to be updated
|
||||
test_alloc_fail({id}, {countdown}, {repeat})
|
||||
none make memory allocation fail
|
||||
test_autochdir() none enable 'autochdir' during startup
|
||||
test_clear_search_pat() none clears the last used search pattern
|
||||
test_feedinput({string}) none add key sequence to input buffer
|
||||
test_garbagecollect_now() none free memory right now for testing
|
||||
test_garbagecollect_soon() none free memory soon for testing
|
||||
@ -3455,6 +3458,7 @@ chdir({dir}) *chdir()*
|
||||
directory (|:tcd|) then changes the tabpage local
|
||||
directory.
|
||||
- Otherwise, changes the global directory.
|
||||
{dir} must be a String.
|
||||
If successful, returns the previous working directory. Pass
|
||||
this to another chdir() to restore the directory.
|
||||
On failure, returns an empty string.
|
||||
@ -5664,7 +5668,7 @@ getwininfo([{winid}]) *getwininfo()*
|
||||
GetWinnr()->getwininfo()
|
||||
|
||||
getwinpos([{timeout}]) *getwinpos()*
|
||||
The result is a list with two numbers, the result of
|
||||
The result is a List with two numbers, the result of
|
||||
|getwinposx()| and |getwinposy()| combined:
|
||||
[x-pos, y-pos]
|
||||
{timeout} can be used to specify how long to wait in msec for
|
||||
@ -10461,6 +10465,7 @@ winline() The result is a Number, which is the screen line of the cursor
|
||||
*winnr()*
|
||||
winnr([{arg}]) The result is a Number, which is the number of the current
|
||||
window. The top window has number 1.
|
||||
Returns zero for a popup window.
|
||||
|
||||
The optional argument {arg} supports the following values:
|
||||
$ the number of the last window (the window
|
||||
|
@ -1,4 +1,4 @@
|
||||
*insert.txt* For Vim version 8.2. Last change: 2020 Jan 04
|
||||
*insert.txt* For Vim version 8.2. Last change: 2020 Jan 26
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -1079,7 +1079,8 @@ If you want to suppress the warning message for an empty result, return
|
||||
|
||||
Other items are ignored.
|
||||
|
||||
For acting upon end of completion, see the |CompleteDone| autocommand event.
|
||||
For acting upon end of completion, see the |CompleteDonePre| and
|
||||
|CompleteDone| autocommand event.
|
||||
|
||||
For example, the function can contain this: >
|
||||
let matches = ... list of words ...
|
||||
|
@ -1,4 +1,4 @@
|
||||
*popup.txt* For Vim version 8.2. Last change: 2019 Nov 30
|
||||
*popup.txt* For Vim version 8.2. Last change: 2020 Feb 03
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -11,6 +11,7 @@ Displaying text in a floating window. *popup* *popup-window* *popupwin*
|
||||
Window position and size |popup-position|
|
||||
Closing the popup window |popup-close|
|
||||
Popup buffer and window |popup-buffer|
|
||||
Terminal in popup window |popup-terminal|
|
||||
2. Functions |popup-functions|
|
||||
Details |popup-function-details|
|
||||
3. Usage |popup-usage|
|
||||
@ -140,6 +141,22 @@ And options can be set on the buffer with `setbufvar()`, e.g.: >
|
||||
You can also use `win_execute()` with a ":setlocal" command.
|
||||
|
||||
|
||||
TERMINAL IN POPUP WINDOW *popup-terminal*
|
||||
|
||||
A special case is running a terminal in a popup window. Many rules are then
|
||||
different: *E863*
|
||||
- The popup window always has focus, it is not possible to switch to another
|
||||
window.
|
||||
- When the job ends, the popup window closes.
|
||||
- The default Pmenu color is only used for the border and padding. To change
|
||||
the color of the terminal itself set 'wincolor'.
|
||||
|
||||
To run a terminal in a popup window, first create the terminal hidden. Then
|
||||
pass the buffer number to popup_create(). Example: >
|
||||
let buf = term_start(['picker', 'Something'], #{hidden: 1, term_finish: 'close'})
|
||||
let winid = popup_create(buf, #{minwidth: 50, minheight: 20})
|
||||
set wincolor=Search
|
||||
|
||||
==============================================================================
|
||||
2. Functions *popup-functions*
|
||||
|
||||
|
@ -2313,6 +2313,7 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
|
||||
:debug-name repeat.txt /*:debug-name*
|
||||
:debugg repeat.txt /*:debugg*
|
||||
:debuggreedy repeat.txt /*:debuggreedy*
|
||||
:def vim9.txt /*:def*
|
||||
:del change.txt /*:del*
|
||||
:delc map.txt /*:delc*
|
||||
:delcommand map.txt /*:delcommand*
|
||||
@ -2384,6 +2385,7 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
|
||||
:emenu gui.txt /*:emenu*
|
||||
:en eval.txt /*:en*
|
||||
:end eval.txt /*:end*
|
||||
:enddef vim9.txt /*:enddef*
|
||||
:endf eval.txt /*:endf*
|
||||
:endfo eval.txt /*:endfo*
|
||||
:endfor eval.txt /*:endfor*
|
||||
@ -2404,6 +2406,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
|
||||
:execute eval.txt /*:execute*
|
||||
:exi editing.txt /*:exi*
|
||||
:exit editing.txt /*:exit*
|
||||
:exp vim9.txt /*:exp*
|
||||
:export vim9.txt /*:export*
|
||||
:exu helphelp.txt /*:exu*
|
||||
:exusage helphelp.txt /*:exusage*
|
||||
:f editing.txt /*:f*
|
||||
@ -2506,6 +2510,9 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
|
||||
:imapclear map.txt /*:imapclear*
|
||||
:ime gui.txt /*:ime*
|
||||
:imenu gui.txt /*:imenu*
|
||||
:imp vim9.txt /*:imp*
|
||||
:import vim9.txt /*:import*
|
||||
:import-cycle vim9.txt /*:import-cycle*
|
||||
:in insert.txt /*:in*
|
||||
:index index.txt /*:index*
|
||||
:ino map.txt /*:ino*
|
||||
@ -3354,6 +3361,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
|
||||
:vie editing.txt /*:vie*
|
||||
:view editing.txt /*:view*
|
||||
:vim quickfix.txt /*:vim*
|
||||
:vim9 vim9.txt /*:vim9*
|
||||
:vim9script vim9.txt /*:vim9script*
|
||||
:vimgrep quickfix.txt /*:vimgrep*
|
||||
:vimgrepa quickfix.txt /*:vimgrepa*
|
||||
:vimgrepadd quickfix.txt /*:vimgrepadd*
|
||||
@ -3834,6 +3843,7 @@ Command-line cmdline.txt /*Command-line*
|
||||
Command-line-mode cmdline.txt /*Command-line-mode*
|
||||
CompleteChanged autocmd.txt /*CompleteChanged*
|
||||
CompleteDone autocmd.txt /*CompleteDone*
|
||||
CompleteDonePre autocmd.txt /*CompleteDonePre*
|
||||
ConPTY terminal.txt /*ConPTY*
|
||||
Contents quickref.txt /*Contents*
|
||||
Cscope if_cscop.txt /*Cscope*
|
||||
@ -4661,6 +4671,7 @@ E858 eval.txt /*E858*
|
||||
E859 eval.txt /*E859*
|
||||
E86 windows.txt /*E86*
|
||||
E862 eval.txt /*E862*
|
||||
E863 popup.txt /*E863*
|
||||
E864 pattern.txt /*E864*
|
||||
E865 pattern.txt /*E865*
|
||||
E866 pattern.txt /*E866*
|
||||
@ -6276,6 +6287,7 @@ faq intro.txt /*faq*
|
||||
farsi farsi.txt /*farsi*
|
||||
farsi.txt farsi.txt /*farsi.txt*
|
||||
fasm.vim syntax.txt /*fasm.vim*
|
||||
fast-functions vim9.txt /*fast-functions*
|
||||
fcs_choice-variable eval.txt /*fcs_choice-variable*
|
||||
fcs_reason-variable eval.txt /*fcs_reason-variable*
|
||||
feature-list eval.txt /*feature-list*
|
||||
@ -8315,6 +8327,7 @@ popup-menu-added version5.txt /*popup-menu-added*
|
||||
popup-position popup.txt /*popup-position*
|
||||
popup-props popup.txt /*popup-props*
|
||||
popup-scrollbar popup.txt /*popup-scrollbar*
|
||||
popup-terminal popup.txt /*popup-terminal*
|
||||
popup-textprop-pos popup.txt /*popup-textprop-pos*
|
||||
popup-usage popup.txt /*popup-usage*
|
||||
popup-window popup.txt /*popup-window*
|
||||
@ -9544,6 +9557,7 @@ tutor usr_01.txt /*tutor*
|
||||
twice if_cscop.txt /*twice*
|
||||
two-engines pattern.txt /*two-engines*
|
||||
type() eval.txt /*type()*
|
||||
type-inference vim9.txt /*type-inference*
|
||||
type-mistakes tips.txt /*type-mistakes*
|
||||
typecorr-settings usr_41.txt /*typecorr-settings*
|
||||
typecorr.txt usr_41.txt /*typecorr.txt*
|
||||
@ -9907,6 +9921,14 @@ vim-variable eval.txt /*vim-variable*
|
||||
vim.vim syntax.txt /*vim.vim*
|
||||
vim7 version7.txt /*vim7*
|
||||
vim8 version8.txt /*vim8*
|
||||
vim9-differences vim9.txt /*vim9-differences*
|
||||
vim9-export vim9.txt /*vim9-export*
|
||||
vim9-import vim9.txt /*vim9-import*
|
||||
vim9-rationale vim9.txt /*vim9-rationale*
|
||||
vim9-script vim9.txt /*vim9-script*
|
||||
vim9-types vim9.txt /*vim9-types*
|
||||
vim9.txt vim9.txt /*vim9.txt*
|
||||
vim9script vim9.txt /*vim9script*
|
||||
vim: options.txt /*vim:*
|
||||
vim_announce intro.txt /*vim_announce*
|
||||
vim_dev intro.txt /*vim_dev*
|
||||
|
@ -1,4 +1,4 @@
|
||||
*tagsrch.txt* For Vim version 8.2. Last change: 2019 Dec 27
|
||||
*tagsrch.txt* For Vim version 8.2. Last change: 2020 Jan 30
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -903,8 +903,8 @@ The following is a hypothetical example of a function used for 'tagfunc'. It
|
||||
uses the output of |taglist()| to generate the result: a list of tags in the
|
||||
inverse order of file names.
|
||||
>
|
||||
function! TagFunc(pattern, flags, info)
|
||||
function! CompareFilenames(item1, item2)
|
||||
function TagFunc(pattern, flags, info)
|
||||
function CompareFilenames(item1, item2)
|
||||
let f1 = a:item1['filename']
|
||||
let f2 = a:item2['filename']
|
||||
return f1 >=# f2 ?
|
||||
|
@ -1,4 +1,4 @@
|
||||
*terminal.txt* For Vim version 8.2. Last change: 2020 Jan 04
|
||||
*terminal.txt* For Vim version 8.2. Last change: 2020 Jan 30
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -1025,7 +1025,7 @@ Writing a screen dump test for Vim ~
|
||||
For an example see the Test_syntax_c() function in
|
||||
src/testdir/test_syntax.vim. The main parts are:
|
||||
- Write a file you want to test with. This is useful for testing syntax
|
||||
highlighting. You can also start Vim with en empty buffer.
|
||||
highlighting. You can also start Vim with an empty buffer.
|
||||
- Run Vim in a terminal with a specific size. The default is 20 lines of 75
|
||||
characters. This makes sure the dump is always this size. The function
|
||||
RunVimInTerminal() takes care of this. Pass it the arguments for the Vim
|
||||
|
@ -52,6 +52,11 @@ test_autochdir() *test_autochdir()*
|
||||
startup has finished.
|
||||
|
||||
|
||||
test_clear_search_pat() *test_clear_search_pat()*
|
||||
Clears the last used search pattern (|/|) and the substitute
|
||||
pattern (|:s|). This is useful for testing conditions where
|
||||
these patterns are not set previously.
|
||||
|
||||
test_feedinput({string}) *test_feedinput()*
|
||||
Characters in {string} are queued for processing as if they
|
||||
were typed by the user. This uses a low level input buffer.
|
||||
|
@ -1,4 +1,4 @@
|
||||
*todo.txt* For Vim version 8.2. Last change: 2020 Jan 23
|
||||
*todo.txt* For Vim version 8.2. Last change: 2020 Feb 04
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -40,10 +40,44 @@ browser use: https://github.com/vim/vim/issues/1234
|
||||
|
||||
Include ipv6 syntax changes? (DJ Lucas, #5360)
|
||||
|
||||
Add win_type(), which "popup" and "cmdline" as values?
|
||||
|
||||
Vim9 script:
|
||||
- test s:var += 'some'
|
||||
test exported += 'some'
|
||||
- implement default values for optional arguments
|
||||
Generate instructions at start of function, skip over if argument provided?
|
||||
- Disallow unlet for local/script/imported vars
|
||||
- :func inside vim9script must still use a:arg
|
||||
- Check that import in legacy script works and puts item in s:
|
||||
- Error in any command in "vim9script" aborts sourcing.
|
||||
- Find a way to test expressions in legacy and Vim9 script without duplication
|
||||
- Test each level of expressions properly, with type checking
|
||||
- Test the
|
||||
- Test try/catch and throw better, also nested.
|
||||
Test return inside try/finally jumps to finally and then returns.
|
||||
- call autoload function.
|
||||
- Type checking arguments when calling :def function
|
||||
- can use func as reference:
|
||||
def SomeFunc() ...
|
||||
map(list, SomeFunc)
|
||||
- define function and create funcref in one step:
|
||||
let ref = def(arg: type): rettype
|
||||
Also extends lambda
|
||||
- Test: Function declared inside a :def function is local, disappears at the
|
||||
end of the function. Unless g: is used, just like with variables.
|
||||
- Can we omit \ for line continuation inside (), {}, ?
|
||||
Requires parsing while reading a function. Like fgetline in do_one_cmd()?
|
||||
- implement :type
|
||||
- implement class
|
||||
- implement interface
|
||||
- predefined class: Promise<T>
|
||||
- import statement for type declaration?
|
||||
- Make accessing varargs faster: arg[expr]
|
||||
EVAL expr
|
||||
LOADVARARG (varags idx)
|
||||
|
||||
Popup windows:
|
||||
- Make it possible to put a terminal window in a popup. Would always grab key
|
||||
input? Sort-of possible by creating a hidden terminal and opening a popup
|
||||
with that buffer: #4063.
|
||||
- Use popup (or popup menu) for command line completion
|
||||
- When using a popup for the info of a completion menu, and there is not
|
||||
enough space, let the popup overlap with the menu. (#4544)
|
||||
@ -55,6 +89,8 @@ Popup windows:
|
||||
- Figure out the size and position better if wrapping inserts indent
|
||||
|
||||
Text properties:
|
||||
- Combining text property with 'cursorline' does not always work (Billie
|
||||
Cleek, #5533)
|
||||
- Text properties spanning more than one line
|
||||
- See remarks at top of src/textprop.c
|
||||
|
||||
@ -121,9 +157,8 @@ Terminal emulator window:
|
||||
conversions.
|
||||
|
||||
Error numbers available:
|
||||
E450, E451, E452,
|
||||
E453, E454, E460, E489, E491, E565, E578, E610, E611, E653,
|
||||
E654, E856, E857, E860, E861, E863, E889, E900
|
||||
E451, E452, E453, E454, E460, E489, E491, E565, E578, E610, E611, E653,
|
||||
E654, E856, E857, E860, E861, E900
|
||||
|
||||
Patch to move duplicated code to a function. (Yegappan Lakshmanan, #5330)
|
||||
|
||||
@ -142,16 +177,20 @@ Needs better docs. Is there a better name?
|
||||
|
||||
undo result wrong: Masato Nishihata, #4798
|
||||
|
||||
When 'lazyredraw' is set sometimes the title is not updated.
|
||||
(Jason Franklin, 2020 Feb 3) Looks like a race condition.
|
||||
|
||||
Patch to add function to return the text used in the quickfix window.
|
||||
(Yegappan, #5465)
|
||||
|
||||
Patch for Template string: #4491. New pull: #4634
|
||||
Implementation is too inefficient, avoid using lambda.
|
||||
|
||||
Undo puts cursor in wrong line after "cG<Esc>" undo.
|
||||
|
||||
:unmap <c-n> gives error but does remove the mapping. (Antony Scriven, 2019
|
||||
Dec 19)
|
||||
|
||||
Sound: support on Mac? Or does libcanberra work there?
|
||||
|
||||
Patch to fix session file when using multiple tab pages. (Jason Franklin, 2019
|
||||
May 20)
|
||||
Also put :argadd commands at the start for all buffers, so that their order
|
||||
@ -194,6 +233,8 @@ Enable 'termbidi' if $VTE_VERSION >= 5703 ?
|
||||
Universal solution to detect if t_RS is working, using cursor position.
|
||||
Koichi Iwamoto, #2126
|
||||
|
||||
Sound: support on Mac? Or does libcanberra work there?
|
||||
|
||||
Python 3.8 doesn't work. (Antonios Hadjigeorgalis, #5509)
|
||||
|
||||
The :syntax cchar value can only be a single character. It would be useful to
|
||||
@ -204,6 +245,8 @@ It can replace the BeOS code, which is likely not used anymore.
|
||||
Now on github: #1856. Updated Oct 2017
|
||||
Got permission to include this under the Vim license.
|
||||
|
||||
"--cleanFOO" does not result in an error. (#5537)
|
||||
|
||||
Add "t" action to settagstack(): truncate and add new entries. (#5405)
|
||||
|
||||
Result of synID() sometimes wrong in help files. (#5252)
|
||||
@ -269,9 +312,6 @@ Patch by Alex Dobrynin, 2007 Jun 3. Also fixes other scroll wheel problems.
|
||||
Add a WindowScrolled event. Trigger around the same time as CursorMoved.
|
||||
Can be used to update highlighting. #3127 #5181
|
||||
|
||||
Patch for Template string: #4491. New pull: #4634
|
||||
Implementation is too inefficient, avoid using lambda.
|
||||
|
||||
Incorrect formatting with autoindent. (Sebastian Gniazdowski, #4909)
|
||||
|
||||
Patch to add the :bvimgrep command. (Christian Brabandt, 2014 Nov 12)
|
||||
@ -812,9 +852,6 @@ option_save({list}) *option_save()*
|
||||
directory (Paulo Marcel Coelho Arabic, 2017 Oct 30, #2266)
|
||||
Also see #1689.
|
||||
|
||||
crash when removing an element while inside map(). (Nikolai Pavlov, 2018 Feb
|
||||
17, #2652)
|
||||
|
||||
When 'virtualedit' is "all" and 'cursorcolumn' is set, the wrong column may be
|
||||
highlighted. (van-de-bugger, 2018 Jan 23, #2576)
|
||||
|
||||
|
@ -963,6 +963,7 @@ Testing: *test-functions*
|
||||
assert_report() report a test failure
|
||||
test_alloc_fail() make memory allocation fail
|
||||
test_autochdir() enable 'autochdir' during startup
|
||||
test_clear_search_pat() clears the last used search pattern
|
||||
test_override() test with Vim internal overrides
|
||||
test_garbagecollect_now() free memory right now
|
||||
test_getvalue() get value of an internal variable
|
||||
|
@ -1,4 +1,4 @@
|
||||
*version8.txt* For Vim version 8.2. Last change: 2019 Dec 29
|
||||
*version8.txt* For Vim version 8.2. Last change: 2020 Feb 04
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -306,7 +306,6 @@ New and extended functions: ~
|
||||
|systemlist()| get the result of a shell command as a list
|
||||
|test_alloc_fail()| make memory allocation fail
|
||||
|test_autochdir()| test 'autochdir' functionality
|
||||
test_disable_char_avail() test without typeahead (removed later)
|
||||
|test_garbagecollect_now()| free memory right now
|
||||
|test_null_channel()| return a null Channel
|
||||
|test_null_dict()| return a null Dict
|
||||
|
@ -1,4 +1,4 @@
|
||||
*vim9.txt* For Vim version 8.2. Last change: 2019 Dec 06
|
||||
*vim9.txt* For Vim version 8.2. Last change: 2020 Jan 30
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -113,7 +113,7 @@ used: >
|
||||
}
|
||||
echo temp " Error!
|
||||
|
||||
An existing variable cannot be assigend to with `:let`, since that implies a
|
||||
An existing variable cannot be assigned to with `:let`, since that implies a
|
||||
declaration. An exception is global variables: these can be both used with
|
||||
and without `:let`, because there is no rule about where they are declared.
|
||||
|
||||
@ -128,7 +128,7 @@ Omitting :call and :eval ~
|
||||
|
||||
Functions can be called without `:call`: >
|
||||
writefile(lines, 'file')
|
||||
Using `:call` is still posible, but this is discouraged.
|
||||
Using `:call` is still possible, but this is discouraged.
|
||||
|
||||
A method call without `eval` is possible, so long as the start is an
|
||||
identifier or can't be an Ex command. It does not work for string constants: >
|
||||
@ -146,9 +146,14 @@ No curly braces expansion ~
|
||||
|curly-braces-names| cannot be used.
|
||||
|
||||
|
||||
Comperators ~
|
||||
No :append, :change or :insert ~
|
||||
|
||||
The 'ignorecase' option is not used for comperators that use strings.
|
||||
These commands are too quickly confused with local variable names.
|
||||
|
||||
|
||||
Comparators ~
|
||||
|
||||
The 'ignorecase' option is not used for comparators that use strings.
|
||||
|
||||
|
||||
White space ~
|
||||
@ -242,6 +247,10 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
|
||||
The second and third form are optional arguments.
|
||||
When the caller omits an argument the {value} is used.
|
||||
|
||||
NOTE: It is possible to nest `:def` inside another
|
||||
`:def`, but it is not possible to nest `:def` inside
|
||||
`:function`, for backwards compatibility.
|
||||
|
||||
[!] is used as with `:function`.
|
||||
|
||||
*:enddef*
|
||||
@ -325,7 +334,7 @@ items, can then be imported in another script.
|
||||
|
||||
Namespace ~
|
||||
*:vim9script* *:vim9*
|
||||
To recognize an file that can be imported the `vim9script` statement must
|
||||
To recognize a file that can be imported the `vim9script` statement must
|
||||
appear as the first statement in the file. It tells Vim to interpret the
|
||||
script in its own namespace, instead of the global namespace. If a file
|
||||
starts with: >
|
||||
@ -371,7 +380,7 @@ The exported items can be imported individually in another Vim9 script: >
|
||||
To import multiple items at the same time: >
|
||||
import {someValue, MyClass} from "thatscript.vim"
|
||||
|
||||
In case the name is ambigiuous, another name can be specified: >
|
||||
In case the name is ambiguous, another name can be specified: >
|
||||
import MyClass as ThatClass from "myclass.vim"
|
||||
import {someValue, MyClass as ThatClass} from "myclass.vim"
|
||||
|
||||
@ -404,7 +413,7 @@ result in undefined items.
|
||||
Import in an autoload script ~
|
||||
|
||||
For optimal startup speed, loading scripts should be postponed until they are
|
||||
actually needed. A recommended mechamism:
|
||||
actually needed. A recommended mechanism:
|
||||
|
||||
1. In the plugin define user commands, functions and/or mappings that refer to
|
||||
an autoload script. >
|
||||
@ -445,7 +454,7 @@ script-local "s:" namespace will be used, even when "s:" is not specified.
|
||||
The :def command ~
|
||||
|
||||
Plugin writers have asked for a much faster Vim script. Investigation have
|
||||
shown that keeping the existing semantics of funtion calls make this close to
|
||||
shown that keeping the existing semantics of function calls make this close to
|
||||
impossible, because of the overhead involved with calling a function, setting
|
||||
up the local function scope and executing lines. There are many details that
|
||||
need to be handled, such as error messages and exceptions. The need to create
|
||||
@ -483,7 +492,7 @@ JavaScript/TypeScript syntax and semantics ~
|
||||
Script writers have complained that the Vim script syntax is unexpectedly
|
||||
different from what they are used to. To reduce this complaint popular
|
||||
languages will be used as an example. At the same time, we do not want to
|
||||
abondon the well-known parts of legacy Vim script.
|
||||
abandon the well-known parts of legacy Vim script.
|
||||
|
||||
Since Vim already uses `:let` and `:const` and optional type checking is
|
||||
desirable, the JavaScript/TypeScript syntax fits best for variable
|
||||
|
@ -1,7 +1,7 @@
|
||||
" Vim filetype plugin file
|
||||
" Language: C
|
||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
" Last Change: 2017 Sep 28
|
||||
" Last Change: 2020 Feb 01
|
||||
|
||||
" Only do this when not done yet for this buffer
|
||||
if exists("b:did_ftplugin")
|
||||
@ -15,12 +15,16 @@ let b:did_ftplugin = 1
|
||||
let s:cpo_save = &cpo
|
||||
set cpo-=C
|
||||
|
||||
let b:undo_ftplugin = "setl fo< com< ofu< | if has('vms') | setl isk< | endif"
|
||||
let b:undo_ftplugin = "setl fo< com< ofu< cms< def< inc< | if has('vms') | setl isk< | endif"
|
||||
|
||||
" Set 'formatoptions' to break comment lines but not other lines,
|
||||
" and insert the comment leader when hitting <CR> or using "o".
|
||||
setlocal fo-=t fo+=croql
|
||||
|
||||
" These options have the right value as default, but the user may have
|
||||
" overruled that.
|
||||
setlocal commentstring& define& include&
|
||||
|
||||
" Set completion with CTRL-X CTRL-O to autoloaded function.
|
||||
if exists('&ofu')
|
||||
setlocal ofu=ccomplete#Complete
|
||||
|
@ -3,7 +3,7 @@
|
||||
" Maintainer: Nick Jensen <nickspoon@gmail.com>
|
||||
" Former Maintainers: Anduin Withers <awithers@anduin.com>
|
||||
" Johannes Zellner <johannes@zellner.org>
|
||||
" Last Change: 2019-08-01
|
||||
" Last Change: 2020-01-27
|
||||
" Filenames: *.cs
|
||||
" License: Vim (see :h license)
|
||||
" Repository: https://github.com/nickspoons/vim-cs
|
||||
@ -97,6 +97,8 @@ syn match csXmlComment "///.*$" contains=csXmlCommentLeader,@csXml,@Spell keepen
|
||||
syn include @csXml syntax/xml.vim
|
||||
hi def link xmlRegion Comment
|
||||
|
||||
" Since syntax/xml.vim contains `syn spell toplevel`, we need to set it back to `default` here.
|
||||
syn spell default
|
||||
|
||||
" [1] 9.5 Pre-processing directives
|
||||
syn region csPreCondit start="^\s*#\s*\(define\|undef\|if\|elif\|else\|endif\|line\|error\|warning\)" skip="\\$" end="$" contains=csComment keepend
|
||||
|
@ -3,7 +3,7 @@
|
||||
" Maintainer: Debian Vim Maintainers
|
||||
" Former Maintainers: Gerfried Fuchs <alfie@ist.org>
|
||||
" Wichert Akkerman <wakkerma@debian.org>
|
||||
" Last Change: 2019 Oct 20
|
||||
" Last Change: 2020 Feb 02
|
||||
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debchangelog.vim
|
||||
|
||||
" Standard syntax initialization
|
||||
@ -24,7 +24,7 @@ let s:supported = [
|
||||
\ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
|
||||
\ 'sid', 'rc-buggy',
|
||||
\
|
||||
\ 'trusty', 'xenial', 'bionic', 'disco', 'eoan', 'focal', 'devel'
|
||||
\ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'devel'
|
||||
\ ]
|
||||
let s:unsupported = [
|
||||
\ 'frozen', 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato',
|
||||
@ -33,7 +33,8 @@ let s:unsupported = [
|
||||
\ 'warty', 'hoary', 'breezy', 'dapper', 'edgy', 'feisty',
|
||||
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
|
||||
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
|
||||
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic'
|
||||
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
|
||||
\ 'disco'
|
||||
\ ]
|
||||
let &cpo=s:cpo
|
||||
|
||||
@ -43,7 +44,7 @@ exe 'syn match debchangelogFirstKV contained "; \('.s:urgency.'\|'.s:binNMU.'\)"
|
||||
exe 'syn match debchangelogOtherKV contained ", \('.s:urgency.'\|'.s:binNMU.'\)"'
|
||||
exe 'syn match debchangelogTarget contained "\%( \%('.join(s:supported, '\|').'\)\>[-[:alnum:]]*\)\+"'
|
||||
exe 'syn match debchangelogUnsupportedTarget contained "\%( \%('.join(s:unsupported, '\|').'\)\>[-[:alnum:]]*\)\+"'
|
||||
syn keyword debchangelogUnreleased contained UNRELEASED
|
||||
syn match debchangelogUnreleased contained / UNRELEASED/
|
||||
syn match debchangelogVersion contained "(.\{-})"
|
||||
syn match debchangelogCloses contained "closes:\_s*\(bug\)\=#\=\_s\=\d\+\(,\_s*\(bug\)\=#\=\_s\=\d\+\)*"
|
||||
syn match debchangelogLP contained "\clp:\s\+#\d\+\(,\s*#\d\+\)*"
|
||||
|
@ -2,7 +2,7 @@
|
||||
" Language: Debian sources.list
|
||||
" Maintainer: Debian Vim Maintainers
|
||||
" Former Maintainer: Matthijs Mohlmann <matthijs@cacholong.nl>
|
||||
" Last Change: 2019 Oct 18
|
||||
" Last Change: 2020 Feb 02
|
||||
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debsources.vim
|
||||
|
||||
" Standard syntax initialization
|
||||
@ -26,7 +26,7 @@ let s:supported = [
|
||||
\ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
|
||||
\ 'sid', 'rc-buggy',
|
||||
\
|
||||
\ 'trusty', 'xenial', 'bionic', 'disco', 'eoan', 'focal', 'devel'
|
||||
\ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'devel'
|
||||
\ ]
|
||||
let s:unsupported = [
|
||||
\ 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato',
|
||||
@ -35,7 +35,8 @@ let s:unsupported = [
|
||||
\ 'warty', 'hoary', 'breezy', 'dapper', 'edgy', 'feisty',
|
||||
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
|
||||
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
|
||||
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic'
|
||||
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
|
||||
\ 'disco'
|
||||
\ ]
|
||||
let &cpo=s:cpo
|
||||
|
||||
|
@ -1,26 +1,45 @@
|
||||
" dockerfile.vim - Syntax highlighting for Dockerfiles
|
||||
" Maintainer: Honza Pokorny <https://honza.ca>
|
||||
" Version: 0.6
|
||||
" Last Change: 2019 Aug 16
|
||||
" Last Change: 2020 Jan 27
|
||||
" License: BSD
|
||||
|
||||
" https://docs.docker.com/engine/reference/builder/
|
||||
|
||||
if exists("b:current_syntax")
|
||||
finish
|
||||
endif
|
||||
|
||||
let b:current_syntax = "dockerfile"
|
||||
syntax include @JSON syntax/json.vim
|
||||
unlet b:current_syntax
|
||||
|
||||
syntax include @Shell syntax/sh.vim
|
||||
unlet b:current_syntax
|
||||
|
||||
syntax case ignore
|
||||
syntax match dockerfileLinePrefix /\v^\s*(ONBUILD\s+)?\ze\S/ contains=dockerfileKeyword nextgroup=dockerfileInstruction skipwhite
|
||||
syntax region dockerfileFrom matchgroup=dockerfileKeyword start=/\v^\s*(FROM)\ze(\s|$)/ skip=/\v\\\_./ end=/\v((^|\s)AS(\s|$)|$)/ contains=dockerfileOption
|
||||
|
||||
syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR)\s/
|
||||
syntax keyword dockerfileKeyword contained ADD ARG CMD COPY ENTRYPOINT ENV EXPOSE HEALTHCHECK LABEL MAINTAINER ONBUILD RUN SHELL STOPSIGNAL USER VOLUME WORKDIR
|
||||
syntax match dockerfileOption contained /\v(^|\s)\zs--\S+/
|
||||
|
||||
syntax match dockerfileKeyword /\v(AS)/
|
||||
syntax match dockerfileInstruction contained /\v(\S+)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileValue
|
||||
syntax match dockerfileInstruction contained /\v(ADD|COPY)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileJSON
|
||||
syntax match dockerfileInstruction contained /\v(HEALTHCHECK)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileInstruction
|
||||
syntax match dockerfileInstruction contained /\v(CMD|ENTRYPOINT|RUN)/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileShell
|
||||
syntax match dockerfileInstruction contained /\v(CMD|ENTRYPOINT|RUN)\ze\s+\[/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON
|
||||
syntax match dockerfileInstruction contained /\v(SHELL|VOLUME)/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON
|
||||
|
||||
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/
|
||||
syntax region dockerfileString contained start=/\v"/ skip=/\v\\./ end=/\v"/
|
||||
syntax region dockerfileJSON contained keepend start=/\v\[/ skip=/\v\\\_./ end=/\v$/ contains=@JSON
|
||||
syntax region dockerfileShell contained keepend start=/\v/ skip=/\v\\\_./ end=/\v$/ contains=@Shell
|
||||
syntax region dockerfileValue contained keepend start=/\v/ skip=/\v\\\_./ end=/\v$/ contains=dockerfileString
|
||||
|
||||
syntax match dockerfileComment "\v^\s*#.*$"
|
||||
syntax region dockerfileComment start=/\v^\s*#/ end=/\v$/
|
||||
set commentstring=#\ %s
|
||||
|
||||
hi def link dockerfileString String
|
||||
hi def link dockerfileKeyword Keyword
|
||||
hi def link dockerfileComment Comment
|
||||
hi def link dockerfileOption Special
|
||||
|
||||
let b:current_syntax = "dockerfile"
|
||||
|
@ -1,7 +1,7 @@
|
||||
" Vim syntax file
|
||||
" Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77)
|
||||
" Version: 101
|
||||
" Last Change: 2019 Nov. 26
|
||||
" Version: 102
|
||||
" Last Change: 2019 Dec. 14
|
||||
" Maintainer: Ajit J. Thakkar <ajit@unb.ca>; <http://www2.unb.ca/~ajit/>
|
||||
" Usage: For instructions, do :help fortran-syntax from Vim
|
||||
" Credits:
|
||||
@ -185,8 +185,8 @@ syn match fortranLabelNumber display "^ \d\s"ms=s+4,me=e-1
|
||||
if exists("fortran_more_precise")
|
||||
" Numbers as targets
|
||||
syn match fortranTarget display "\(\<if\s*(.\+)\s*\)\@<=\(\d\+\s*,\s*\)\{2}\d\+\>"
|
||||
syn match fortranTarget display "\(\<do\s\+\)\@<11=\d\+\>"
|
||||
syn match fortranTarget display "\(\<go\s*to\s*(\=\)\@<11=\(\d\+\s*,\s*\)*\d\+\>"
|
||||
syn match fortranTarget display "\(\<do\s\+\)\@11<=\d\+\>"
|
||||
syn match fortranTarget display "\(\<go\s*to\s*(\=\)\@11<=\(\d\+\s*,\s*\)*\d\+\>"
|
||||
endif
|
||||
|
||||
syn keyword fortranTypeR external
|
||||
@ -274,7 +274,7 @@ syn match fortranType "\<elemental\>"
|
||||
syn match fortranType "\<pure\>"
|
||||
syn match fortranType "\<impure\>"
|
||||
if exists("fortran_more_precise")
|
||||
syn match fortranConstructName "\(\<end\s*forall\s\+\)\@<15=\a\w*\>"
|
||||
syn match fortranConstructName "\(\<end\s*forall\s\+\)\@15<=\a\w*\>"
|
||||
endif
|
||||
|
||||
if b:fortran_dialect == "f08"
|
||||
|
2
src/auto/configure
vendored
2
src/auto/configure
vendored
@ -14762,7 +14762,7 @@ DEPEND_CFLAGS_FILTER=
|
||||
if test "$GCC" = yes; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC 3 or later" >&5
|
||||
$as_echo_n "checking for GCC 3 or later... " >&6; }
|
||||
gccmajor=`echo "$gccversion" | sed -e 's/^\([1-9]\)\..*$/\1/g'`
|
||||
gccmajor=`echo "$gccversion" | sed -e 's/^\([1-9][0-9]*\)\..*$/\1/g'`
|
||||
if test "$gccmajor" -gt "2"; then
|
||||
DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
|
@ -2195,7 +2195,7 @@ else
|
||||
fi
|
||||
|
||||
dnl On my HPUX system the X include dir is found, but the lib dir not.
|
||||
dnl This is a desparate try to fix this.
|
||||
dnl This is a desperate try to fix this.
|
||||
|
||||
if test -d "$x_includes" && test ! -d "$x_libraries"; then
|
||||
x_libraries=`echo "$x_includes" | sed s/include/lib/`
|
||||
@ -4447,7 +4447,7 @@ dnl the number before the version number.
|
||||
DEPEND_CFLAGS_FILTER=
|
||||
if test "$GCC" = yes; then
|
||||
AC_MSG_CHECKING(for GCC 3 or later)
|
||||
gccmajor=`echo "$gccversion" | sed -e 's/^\([[1-9]]\)\..*$/\1/g'`
|
||||
gccmajor=`echo "$gccversion" | sed -e 's/^\([[1-9]][[0-9]]*\)\..*$/\1/g'`
|
||||
if test "$gccmajor" -gt "2"; then
|
||||
DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'"
|
||||
AC_MSG_RESULT(yes)
|
||||
|
@ -810,6 +810,7 @@ static funcentry_T global_functions[] =
|
||||
#endif
|
||||
{"test_alloc_fail", 3, 3, FEARG_1, &t_void, f_test_alloc_fail},
|
||||
{"test_autochdir", 0, 0, 0, &t_void, f_test_autochdir},
|
||||
{"test_clear_search_pat", 0, 0, 0, &t_void, f_test_clear_search_pat},
|
||||
{"test_feedinput", 1, 1, FEARG_1, &t_void, f_test_feedinput},
|
||||
{"test_garbagecollect_now", 0, 0, 0, &t_void, f_test_garbagecollect_now},
|
||||
{"test_garbagecollect_soon", 0, 0, 0, &t_void, f_test_garbagecollect_soon},
|
||||
|
10
src/fileio.c
10
src/fileio.c
@ -4423,17 +4423,17 @@ readdir_core(
|
||||
int (*checkitem)(void *context, char_u *name))
|
||||
{
|
||||
int failed = FALSE;
|
||||
#ifdef MSWIN
|
||||
# ifdef MSWIN
|
||||
char_u *buf, *p;
|
||||
int ok;
|
||||
HANDLE hFind = INVALID_HANDLE_VALUE;
|
||||
WIN32_FIND_DATAW wfb;
|
||||
WCHAR *wn = NULL; // UTF-16 name, NULL when not used.
|
||||
#endif
|
||||
# endif
|
||||
|
||||
ga_init2(gap, (int)sizeof(char *), 20);
|
||||
|
||||
#ifdef MSWIN
|
||||
# ifdef MSWIN
|
||||
buf = alloc(MAXPATHL);
|
||||
if (buf == NULL)
|
||||
return FAIL;
|
||||
@ -4498,7 +4498,7 @@ readdir_core(
|
||||
|
||||
vim_free(buf);
|
||||
vim_free(wn);
|
||||
#else
|
||||
# else
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
char_u *p;
|
||||
@ -4547,7 +4547,7 @@ readdir_core(
|
||||
|
||||
closedir(dirp);
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
if (!failed && gap->ga_len > 0)
|
||||
sort_strings((char_u **)gap->ga_data, gap->ga_len);
|
||||
|
110
src/filepath.c
110
src/filepath.c
@ -301,6 +301,7 @@ modify_fname(
|
||||
char_u dirname[MAXPATHL];
|
||||
int c;
|
||||
int has_fullname = 0;
|
||||
int has_homerelative = 0;
|
||||
#ifdef MSWIN
|
||||
char_u *fname_start = *fnamep;
|
||||
int has_shortname = 0;
|
||||
@ -412,7 +413,7 @@ repeat:
|
||||
}
|
||||
pbuf = NULL;
|
||||
// Need full path first (use expand_env() to remove a "~/")
|
||||
if (!has_fullname)
|
||||
if (!has_fullname && !has_homerelative)
|
||||
{
|
||||
if (c == '.' && **fnamep == '~')
|
||||
p = pbuf = expand_env_save(*fnamep);
|
||||
@ -428,16 +429,37 @@ repeat:
|
||||
{
|
||||
if (c == '.')
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
mch_dirname(dirname, MAXPATHL);
|
||||
s = shorten_fname(p, dirname);
|
||||
if (s != NULL)
|
||||
if (has_homerelative)
|
||||
{
|
||||
*fnamep = s;
|
||||
if (pbuf != NULL)
|
||||
s = vim_strsave(dirname);
|
||||
if (s != NULL)
|
||||
{
|
||||
vim_free(*bufp); // free any allocated file name
|
||||
*bufp = pbuf;
|
||||
pbuf = NULL;
|
||||
home_replace(NULL, s, dirname, MAXPATHL, TRUE);
|
||||
vim_free(s);
|
||||
}
|
||||
}
|
||||
namelen = STRLEN(dirname);
|
||||
|
||||
// Do not call shorten_fname() here since it removes the prefix
|
||||
// even though the path does not have a prefix.
|
||||
if (fnamencmp(p, dirname, namelen) == 0)
|
||||
{
|
||||
p += namelen;
|
||||
if (vim_ispathsep(*p))
|
||||
{
|
||||
while (*p && vim_ispathsep(*p))
|
||||
++p;
|
||||
*fnamep = p;
|
||||
if (pbuf != NULL)
|
||||
{
|
||||
// free any allocated file name
|
||||
vim_free(*bufp);
|
||||
*bufp = pbuf;
|
||||
pbuf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -453,6 +475,7 @@ repeat:
|
||||
*fnamep = s;
|
||||
vim_free(*bufp);
|
||||
*bufp = s;
|
||||
has_homerelative = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -701,6 +724,7 @@ f_chdir(typval_T *argvars, typval_T *rettv)
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
if (argvars[0].v_type != VAR_STRING)
|
||||
// Returning an empty string means it failed.
|
||||
return;
|
||||
|
||||
// Return the current directory
|
||||
@ -1235,41 +1259,6 @@ f_isdirectory(typval_T *argvars, typval_T *rettv)
|
||||
rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate "expr" (= "context") for readdir().
|
||||
*/
|
||||
static int
|
||||
readdir_checkitem(void *context, char_u *name)
|
||||
{
|
||||
typval_T *expr = (typval_T *)context;
|
||||
typval_T save_val;
|
||||
typval_T rettv;
|
||||
typval_T argv[2];
|
||||
int retval = 0;
|
||||
int error = FALSE;
|
||||
|
||||
if (expr->v_type == VAR_UNKNOWN)
|
||||
return 1;
|
||||
|
||||
prepare_vimvar(VV_VAL, &save_val);
|
||||
set_vim_var_string(VV_VAL, name, -1);
|
||||
argv[0].v_type = VAR_STRING;
|
||||
argv[0].vval.v_string = name;
|
||||
|
||||
if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
|
||||
goto theend;
|
||||
|
||||
retval = tv_get_number_chk(&rettv, &error);
|
||||
if (error)
|
||||
retval = -1;
|
||||
clear_tv(&rettv);
|
||||
|
||||
theend:
|
||||
set_vim_var_string(VV_VAL, NULL, 0);
|
||||
restore_vimvar(VV_VAL, &save_val);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the directory in which "dir" is located, and higher levels when
|
||||
* needed.
|
||||
@ -1365,6 +1354,41 @@ f_pathshorten(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate "expr" (= "context") for readdir().
|
||||
*/
|
||||
static int
|
||||
readdir_checkitem(void *context, char_u *name)
|
||||
{
|
||||
typval_T *expr = (typval_T *)context;
|
||||
typval_T save_val;
|
||||
typval_T rettv;
|
||||
typval_T argv[2];
|
||||
int retval = 0;
|
||||
int error = FALSE;
|
||||
|
||||
if (expr->v_type == VAR_UNKNOWN)
|
||||
return 1;
|
||||
|
||||
prepare_vimvar(VV_VAL, &save_val);
|
||||
set_vim_var_string(VV_VAL, name, -1);
|
||||
argv[0].v_type = VAR_STRING;
|
||||
argv[0].vval.v_string = name;
|
||||
|
||||
if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
|
||||
goto theend;
|
||||
|
||||
retval = tv_get_number_chk(&rettv, &error);
|
||||
if (error)
|
||||
retval = -1;
|
||||
clear_tv(&rettv);
|
||||
|
||||
theend:
|
||||
set_vim_var_string(VV_VAL, NULL, 0);
|
||||
restore_vimvar(VV_VAL, &save_val);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* "readdir()" function
|
||||
*/
|
||||
|
@ -2371,6 +2371,10 @@ f_popup_close(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
void
|
||||
popup_hide(win_T *wp)
|
||||
{
|
||||
#ifdef FEAT_TERMINAL
|
||||
if (error_if_term_popup_window())
|
||||
return;
|
||||
#endif
|
||||
if ((wp->w_popup_flags & POPF_HIDDEN) == 0)
|
||||
{
|
||||
wp->w_popup_flags |= POPF_HIDDEN;
|
||||
|
@ -12,6 +12,7 @@ int vim_regcomp_had_eol(void);
|
||||
regprog_T *vim_regcomp(char_u *expr_arg, int re_flags);
|
||||
void vim_regfree(regprog_T *prog);
|
||||
void free_regexp_stuff(void);
|
||||
void free_regexp_prev_sub(void);
|
||||
int regprog_in_use(regprog_T *prog);
|
||||
int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col);
|
||||
int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col);
|
||||
|
@ -9,6 +9,7 @@ void free_search_patterns(void);
|
||||
void save_last_search_pattern(void);
|
||||
void restore_last_search_pattern(void);
|
||||
char_u *last_search_pattern(void);
|
||||
void free_last_pat(int idx);
|
||||
int ignorecase(char_u *pat);
|
||||
int ignorecase_opt(char_u *pat, int ic_in, int scs);
|
||||
int pat_has_uppercase(char_u *pat);
|
||||
|
@ -13,6 +13,7 @@ void f_assert_report(typval_T *argvars, typval_T *rettv);
|
||||
void f_assert_true(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_autochdir(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_clear_search_pat(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_feedinput(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_getvalue(typval_T *argvars, typval_T *rettv);
|
||||
void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
|
||||
|
@ -6,6 +6,7 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
|
||||
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
|
||||
void emsg_funcname(char *ermsg, char_u *name);
|
||||
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe);
|
||||
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
|
||||
ufunc_T *find_func(char_u *name, cctx_T *cctx);
|
||||
int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
|
||||
void save_funccal(funccal_entry_T *entry);
|
||||
@ -26,7 +27,6 @@ int has_varargs(ufunc_T *ufunc);
|
||||
int function_exists(char_u *name, int no_deref);
|
||||
char_u *get_expanded_name(char_u *name, int check);
|
||||
char_u *get_user_func_name(expand_T *xp, int idx);
|
||||
void clean_script_functions(int sid);
|
||||
void ex_delfunction(exarg_T *eap);
|
||||
void func_unref(char_u *name);
|
||||
void func_ptr_unref(ufunc_T *fp);
|
||||
|
@ -2663,6 +2663,15 @@ free_regexp_stuff(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Free the previously used substitute search pattern.
|
||||
*/
|
||||
void
|
||||
free_regexp_prev_sub(void)
|
||||
{
|
||||
VIM_CLEAR(reg_prev_sub);
|
||||
}
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
static void
|
||||
report_re_switch(char_u *pat)
|
||||
|
@ -380,6 +380,12 @@ last_search_pattern(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
free_last_pat(int idx)
|
||||
{
|
||||
VIM_CLEAR(spats[idx].pat);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE when case should be ignored for search pattern "pat".
|
||||
* Uses the 'ignorecase' and 'smartcase' options.
|
||||
|
@ -1515,6 +1515,8 @@ typedef struct
|
||||
type_T **uf_arg_types; // argument types (count == uf_args.ga_len)
|
||||
type_T *uf_ret_type; // return type
|
||||
garray_T uf_type_list; // types used in arg and return types
|
||||
int *uf_def_arg_idx; // instruction indexes for evaluating
|
||||
// uf_def_args; length: uf_def_args.ga_len + 1
|
||||
char_u *uf_va_name; // name from "...name" or NULL
|
||||
type_T *uf_va_type; // type from "...name: type" or NULL
|
||||
|
||||
|
@ -268,6 +268,7 @@ NEW_TESTS = \
|
||||
test_utf8 \
|
||||
test_utf8_comparisons \
|
||||
test_vartabs \
|
||||
test_vim9_disassemble \
|
||||
test_vim9_expr \
|
||||
test_vim9_script \
|
||||
test_viminfo \
|
||||
@ -470,6 +471,7 @@ NEW_TESTS_RES = \
|
||||
test_user_func.res \
|
||||
test_usercommands.res \
|
||||
test_vartabs.res \
|
||||
test_vim9_disassemble.res \
|
||||
test_vim9_expr.res \
|
||||
test_vim9_script.res \
|
||||
test_viminfo.res \
|
||||
|
15
src/testdir/dumps/Test_terminal_popup_4.dump
Normal file
15
src/testdir/dumps/Test_terminal_popup_4.dump
Normal file
@ -0,0 +1,15 @@
|
||||
|3+0&#ffffff0| @12|╔+0&#a8a8a8255|═@44|╗| +0&#ffffff0@13
|
||||
|4| @12|║+0&#a8a8a8255|s|o|m|e| |t|e|x|t| @35|║| +0&#ffffff0@13
|
||||
|5| @12|║+0&#a8a8a8255|t|o| |e+0&#ffff4012|d|i|t| +0&#a8a8a8255@37|║| +0&#ffffff0@13
|
||||
|6| @12|║+0&#a8a8a8255|i|n| |a| |p|o|p|u|p| |w|i|n|d|o|w| @27|║| +0&#ffffff0@13
|
||||
|7| @12|║+0&#a8a8a8255|~+0#4040ff13&| @43|║+0#0000000&| +0&#ffffff0@13
|
||||
|8| @12|║+0&#a8a8a8255|~+0#4040ff13&| @43|║+0#0000000&| +0&#ffffff0@13
|
||||
|9| @12|║+0&#a8a8a8255|~+0#4040ff13&| @43|║+0#0000000&| +0&#ffffff0@13
|
||||
|1|0| @11|║+0&#a8a8a8255|/|e|d|i|t| @21|2|,|4| @10|A|l@1| |║| +0&#ffffff0@13
|
||||
|1@1| @11|╚+0&#a8a8a8255|═@44|⇲| +0&#ffffff0@13
|
||||
|1|2| @72
|
||||
|1|3| @72
|
||||
|E+0#ffffff16#e000002|r@1|o|r| |d|e|t|e|c|t|e|d| |w|h|i|l|e| |p|r|o|c|e|s@1|i|n|g| |f|u|n|c|t|i|o|n| |H|i|d|e|P|o|p|u|p|:| +0#0000000#ffffff0@23
|
||||
|l+0#af5f00255&|i|n|e| @3|1|:| +0#0000000&@64
|
||||
|E+0#ffffff16#e000002|8|6|3|:| |N|o|t| |a|l@1|o|w|e|d| |f|o|r| |a| |t|e|r|m|i|n|a|l| |i|n| |a| |p|o|p|u|p| |w|i|n|d|o|w| +0#0000000#ffffff0@24
|
||||
|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@35
|
@ -3,8 +3,10 @@
|
||||
func Test_fnamemodify()
|
||||
let save_home = $HOME
|
||||
let save_shell = &shell
|
||||
let save_shellslash = &shellslash
|
||||
let $HOME = fnamemodify('.', ':p:h:h')
|
||||
set shell=sh
|
||||
set shellslash
|
||||
|
||||
call assert_equal('/', fnamemodify('.', ':p')[-1:])
|
||||
call assert_equal('r', fnamemodify('.', ':p:h')[-1:])
|
||||
@ -28,6 +30,17 @@ func Test_fnamemodify()
|
||||
call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e:e'))
|
||||
call assert_equal('tar', fnamemodify('abc.fb2.tar.gz', ':e:e:r'))
|
||||
|
||||
let cwd = getcwd()
|
||||
call mkdir($HOME . '/XXXXXXXX/a', 'p')
|
||||
call mkdir($HOME . '/XXXXXXXX/b', 'p')
|
||||
call chdir($HOME . '/XXXXXXXX/a/')
|
||||
call assert_equal('foo', fnamemodify($HOME . '/XXXXXXXX/a/foo', ':p:~:.'))
|
||||
call assert_equal('~/XXXXXXXX/b/foo', fnamemodify($HOME . '/XXXXXXXX/b/foo', ':p:~:.'))
|
||||
call mkdir($HOME . '/XXXXXXXX/a.ext', 'p')
|
||||
call assert_equal('~/XXXXXXXX/a.ext/foo', fnamemodify($HOME . '/XXXXXXXX/a.ext/foo', ':p:~:.'))
|
||||
call chdir(cwd)
|
||||
call delete($HOME . '/XXXXXXXX', 'rf')
|
||||
|
||||
call assert_equal('''abc def''', fnamemodify('abc def', ':S'))
|
||||
call assert_equal('''abc" "def''', fnamemodify('abc" "def', ':S'))
|
||||
call assert_equal('''abc"%"def''', fnamemodify('abc"%"def', ':S'))
|
||||
@ -44,6 +57,7 @@ func Test_fnamemodify()
|
||||
|
||||
let $HOME = save_home
|
||||
let &shell = save_shell
|
||||
let &shellslash = save_shellslash
|
||||
endfunc
|
||||
|
||||
func Test_fnamemodify_er()
|
||||
|
@ -1965,7 +1965,7 @@ func Test_range()
|
||||
|
||||
" settagstack()
|
||||
call settagstack(1, #{items : range(4)})
|
||||
|
||||
|
||||
" sign_define()
|
||||
call assert_fails("call sign_define(range(5))", "E715:")
|
||||
call assert_fails("call sign_placelist(range(5))", "E715:")
|
||||
@ -1997,12 +1997,17 @@ func Test_range()
|
||||
set tagfunc=TagFunc
|
||||
call assert_fails("call taglist('asdf')", 'E987:')
|
||||
set tagfunc=
|
||||
|
||||
|
||||
" term_start()
|
||||
if has('terminal') && has('termguicolors')
|
||||
call assert_fails('call term_start(range(3, 4))', 'E474:')
|
||||
let g:terminal_ansi_colors = range(16)
|
||||
call assert_fails('call term_start("ls", #{term_finish: "close"})', 'E475:')
|
||||
if has('win32')
|
||||
let cmd = "cmd /c dir"
|
||||
else
|
||||
let cmd = "ls"
|
||||
endif
|
||||
call assert_fails('call term_start("' .. cmd .. '", #{term_finish: "close"})', 'E475:')
|
||||
unlet g:terminal_ansi_colors
|
||||
endif
|
||||
|
||||
|
@ -2718,6 +2718,10 @@ func XvimgrepTests(cchar)
|
||||
call assert_equal(0, getbufinfo('Xtestfile1')[0].loaded)
|
||||
call assert_equal([], getbufinfo('Xtestfile2'))
|
||||
|
||||
" Test with the last search pattern not set
|
||||
call test_clear_search_pat()
|
||||
call assert_fails('Xvimgrep // *', 'E35:')
|
||||
|
||||
call delete('Xtestfile1')
|
||||
call delete('Xtestfile2')
|
||||
endfunc
|
||||
|
@ -1455,3 +1455,44 @@ func Test_search_special()
|
||||
set t_PE=
|
||||
exe "norm /\x80PS"
|
||||
endfunc
|
||||
|
||||
" Test for command failures when the last search pattern is not set.
|
||||
func Test_search_with_no_last_pat()
|
||||
call test_clear_search_pat()
|
||||
call assert_fails("normal i\<C-R>/\e", 'E35:')
|
||||
call assert_fails("exe '/'", 'E35:')
|
||||
call assert_fails("exe '?'", 'E35:')
|
||||
call assert_fails("/", 'E35:')
|
||||
call assert_fails("?", 'E35:')
|
||||
call assert_fails("normal n", 'E35:')
|
||||
call assert_fails("normal N", 'E35:')
|
||||
call assert_fails("normal gn", 'E35:')
|
||||
call assert_fails("normal gN", 'E35:')
|
||||
call assert_fails("normal cgn", 'E35:')
|
||||
call assert_fails("normal cgN", 'E35:')
|
||||
let p = []
|
||||
let p = @/
|
||||
call assert_equal('', p)
|
||||
call assert_fails("normal :\<C-R>/", 'E35:')
|
||||
call assert_fails("//p", 'E35:')
|
||||
call assert_fails(";//p", 'E35:')
|
||||
call assert_fails("??p", 'E35:')
|
||||
call assert_fails(";??p", 'E35:')
|
||||
call assert_fails('g//p', 'E476:')
|
||||
call assert_fails('v//p', 'E476:')
|
||||
endfunc
|
||||
|
||||
" Test for using tilde (~) atom in search. This should use the last used
|
||||
" substitute pattern
|
||||
func Test_search_tilde_pat()
|
||||
call test_clear_search_pat()
|
||||
set regexpengine=1
|
||||
call assert_fails('exe "normal /~\<CR>"', 'E33:')
|
||||
call assert_fails('exe "normal ?~\<CR>"', 'E33:')
|
||||
set regexpengine=2
|
||||
call assert_fails('exe "normal /~\<CR>"', 'E383:')
|
||||
call assert_fails('exe "normal ?~\<CR>"', 'E383:')
|
||||
set regexpengine&
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -1383,6 +1383,8 @@ func Test_sort_last_search_pat()
|
||||
call setline(1, ['3b', '1c', '2a'])
|
||||
sort //
|
||||
call assert_equal(['2a', '3b', '1c'], getline(1, '$'))
|
||||
call test_clear_search_pat()
|
||||
call assert_fails('sort //', 'E35:')
|
||||
close!
|
||||
endfunc
|
||||
|
||||
|
@ -803,4 +803,19 @@ func Test_sub_expand_text()
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for command failures when the last substitute pattern is not set.
|
||||
func Test_sub_with_no_last_pat()
|
||||
call test_clear_search_pat()
|
||||
call assert_fails('~', 'E33:')
|
||||
call assert_fails('s//abc/g', 'E476:')
|
||||
call assert_fails('s\/bar', 'E476:')
|
||||
call assert_fails('s\&bar&', 'E476:')
|
||||
|
||||
call test_clear_search_pat()
|
||||
let save_cpo = &cpo
|
||||
set cpo+=/
|
||||
call assert_fails('s/abc/%/', 'E33:')
|
||||
let &cpo = save_cpo
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -2337,12 +2337,15 @@ func Test_terminal_in_popup()
|
||||
\ 'hi PopTerm ctermbg=grey',
|
||||
\ 'func OpenTerm(setColor)',
|
||||
\ " let buf = term_start('" .. cmd .. " Xtext', #{hidden: 1, term_finish: 'close'})",
|
||||
\ ' let winid = popup_create(buf, #{minwidth: 45, minheight: 7, border: [], drag: 1, resize: 1})',
|
||||
\ ' let s:winid = popup_create(buf, #{minwidth: 45, minheight: 7, border: [], drag: 1, resize: 1})',
|
||||
\ ' if a:setColor',
|
||||
\ ' call win_execute(winid, "set wincolor=PopTerm")',
|
||||
\ ' call win_execute(s:winid, "set wincolor=PopTerm")',
|
||||
\ ' endif',
|
||||
\ 'endfunc',
|
||||
\ 'call OpenTerm(0)',
|
||||
\ 'func HidePopup()',
|
||||
\ ' call popup_hide(s:winid)',
|
||||
\ 'endfunc',
|
||||
\ ]
|
||||
call writefile(lines, 'XtermPopup')
|
||||
let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15})
|
||||
@ -2356,6 +2359,11 @@ func Test_terminal_in_popup()
|
||||
call term_sendkeys(buf, "/edit\<CR>")
|
||||
call VerifyScreenDump(buf, 'Test_terminal_popup_3', {})
|
||||
|
||||
call term_sendkeys(buf, "\<C-W>:call HidePopup()\<CR>")
|
||||
call VerifyScreenDump(buf, 'Test_terminal_popup_4', {})
|
||||
call term_sendkeys(buf, "\<CR>")
|
||||
call term_wait(buf, 50)
|
||||
|
||||
call term_sendkeys(buf, ":q\<CR>")
|
||||
call term_wait(buf, 100) " wait for terminal to vanish
|
||||
|
||||
|
533
src/testdir/test_vim9_disassemble.vim
Normal file
533
src/testdir/test_vim9_disassemble.vim
Normal file
@ -0,0 +1,533 @@
|
||||
" Test the :disassemble command, and compilation as a side effect
|
||||
|
||||
func NotCompiled()
|
||||
echo "not"
|
||||
endfunc
|
||||
|
||||
let s:scriptvar = 4
|
||||
let g:globalvar = 'g'
|
||||
|
||||
def s:ScriptFuncLoad(arg: string)
|
||||
let local = 1
|
||||
buffers
|
||||
echo arg
|
||||
echo local
|
||||
echo v:version
|
||||
echo s:scriptvar
|
||||
echo g:globalvar
|
||||
echo &tabstop
|
||||
echo $ENVVAR
|
||||
echo @z
|
||||
enddef
|
||||
|
||||
def Test_disassemble_load()
|
||||
assert_fails('disass NoFunc', 'E1061:')
|
||||
assert_fails('disass NotCompiled', 'E1062:')
|
||||
|
||||
let res = execute('disass s:ScriptFuncLoad')
|
||||
assert_match('<SNR>\d*_ScriptFuncLoad.*'
|
||||
\ .. 'buffers.*'
|
||||
\ .. ' EXEC \+buffers.*'
|
||||
\ .. ' LOAD arg\[-1\].*'
|
||||
\ .. ' LOAD $0.*'
|
||||
\ .. ' LOADV v:version.*'
|
||||
\ .. ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*'
|
||||
\ .. ' LOADG g:globalvar.*'
|
||||
\ .. ' LOADENV $ENVVAR.*'
|
||||
\ .. ' LOADREG @z.*'
|
||||
\, res)
|
||||
enddef
|
||||
|
||||
def s:ScriptFuncPush()
|
||||
let localbool = true
|
||||
let localspec = v:none
|
||||
let localblob = 0z1234
|
||||
if has('float')
|
||||
let localfloat = 1.234
|
||||
endif
|
||||
enddef
|
||||
|
||||
def Test_disassemble_push()
|
||||
let res = execute('disass s:ScriptFuncPush')
|
||||
assert_match('<SNR>\d*_ScriptFuncPush.*'
|
||||
\ .. 'localbool = true.*'
|
||||
\ .. ' PUSH v:true.*'
|
||||
\ .. 'localspec = v:none.*'
|
||||
\ .. ' PUSH v:none.*'
|
||||
\ .. 'localblob = 0z1234.*'
|
||||
\ .. ' PUSHBLOB 0z1234.*'
|
||||
\, res)
|
||||
if has('float')
|
||||
assert_match('<SNR>\d*_ScriptFuncPush.*'
|
||||
\ .. 'localfloat = 1.234.*'
|
||||
\ .. ' PUSHF 1.234.*'
|
||||
\, res)
|
||||
endif
|
||||
enddef
|
||||
|
||||
def s:ScriptFuncStore()
|
||||
let localnr = 1
|
||||
localnr = 2
|
||||
let localstr = 'abc'
|
||||
localstr = 'xyz'
|
||||
v:char = 'abc'
|
||||
s:scriptvar = 'sv'
|
||||
g:globalvar = 'gv'
|
||||
&tabstop = 8
|
||||
$ENVVAR = 'ev'
|
||||
@z = 'rv'
|
||||
enddef
|
||||
|
||||
def Test_disassemble_store()
|
||||
let res = execute('disass s:ScriptFuncStore')
|
||||
assert_match('<SNR>\d*_ScriptFuncStore.*'
|
||||
\ .. 'localnr = 2.*'
|
||||
\ .. ' STORE 2 in $0.*'
|
||||
\ .. 'localstr = ''xyz''.*'
|
||||
\ .. ' STORE $1.*'
|
||||
\ .. 'v:char = ''abc''.*'
|
||||
\ .. 'STOREV v:char.*'
|
||||
\ .. 's:scriptvar = ''sv''.*'
|
||||
\ .. ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*'
|
||||
\ .. 'g:globalvar = ''gv''.*'
|
||||
\ .. ' STOREG g:globalvar.*'
|
||||
\ .. '&tabstop = 8.*'
|
||||
\ .. ' STOREOPT &tabstop.*'
|
||||
\ .. '$ENVVAR = ''ev''.*'
|
||||
\ .. ' STOREENV $ENVVAR.*'
|
||||
\ .. '@z = ''rv''.*'
|
||||
\ .. ' STOREREG @z.*'
|
||||
\, res)
|
||||
enddef
|
||||
|
||||
def s:ScriptFuncTry()
|
||||
try
|
||||
echo 'yes'
|
||||
catch /fail/
|
||||
echo 'no'
|
||||
finally
|
||||
throw 'end'
|
||||
endtry
|
||||
enddef
|
||||
|
||||
def Test_disassemble_try()
|
||||
let res = execute('disass s:ScriptFuncTry')
|
||||
assert_match('<SNR>\d*_ScriptFuncTry.*'
|
||||
\ .. 'try.*'
|
||||
\ .. 'TRY catch -> \d\+, finally -> \d\+.*'
|
||||
\ .. 'catch /fail/.*'
|
||||
\ .. ' JUMP -> \d\+.*'
|
||||
\ .. ' PUSH v:exception.*'
|
||||
\ .. ' PUSHS "fail".*'
|
||||
\ .. ' COMPARESTRING =\~.*'
|
||||
\ .. ' JUMP_IF_FALSE -> \d\+.*'
|
||||
\ .. ' CATCH.*'
|
||||
\ .. 'finally.*'
|
||||
\ .. ' PUSHS "end".*'
|
||||
\ .. ' THROW.*'
|
||||
\ .. 'endtry.*'
|
||||
\ .. ' ENDTRY.*'
|
||||
\, res)
|
||||
enddef
|
||||
|
||||
def s:ScriptFuncNew()
|
||||
let ll = [1, "two", 333]
|
||||
let dd = #{one: 1, two: "val"}
|
||||
enddef
|
||||
|
||||
def Test_disassemble_new()
|
||||
let res = execute('disass s:ScriptFuncNew')
|
||||
assert_match('<SNR>\d*_ScriptFuncNew.*'
|
||||
\ .. 'let ll = \[1, "two", 333].*'
|
||||
\ .. 'PUSHNR 1.*'
|
||||
\ .. 'PUSHS "two".*'
|
||||
\ .. 'PUSHNR 333.*'
|
||||
\ .. 'NEWLIST size 3.*'
|
||||
\ .. 'let dd = #{one: 1, two: "val"}.*'
|
||||
\ .. 'PUSHS "one".*'
|
||||
\ .. 'PUSHNR 1.*'
|
||||
\ .. 'PUSHS "two".*'
|
||||
\ .. 'PUSHS "val".*'
|
||||
\ .. 'NEWDICT size 2.*'
|
||||
\, res)
|
||||
enddef
|
||||
|
||||
def FuncWithArg(arg)
|
||||
echo arg
|
||||
enddef
|
||||
|
||||
func UserFunc()
|
||||
echo 'nothing'
|
||||
endfunc
|
||||
|
||||
func UserFuncWithArg(arg)
|
||||
echo a:arg
|
||||
endfunc
|
||||
|
||||
def s:ScriptFuncCall(): string
|
||||
changenr()
|
||||
char2nr("abc")
|
||||
Test_disassemble_new()
|
||||
FuncWithArg(343)
|
||||
ScriptFuncNew()
|
||||
s:ScriptFuncNew()
|
||||
UserFunc()
|
||||
UserFuncWithArg("foo")
|
||||
let FuncRef = function("UserFunc")
|
||||
FuncRef()
|
||||
let FuncRefWithArg = function("UserFuncWithArg")
|
||||
FuncRefWithArg("bar")
|
||||
return "yes"
|
||||
enddef
|
||||
|
||||
def Test_disassemble_call()
|
||||
let res = execute('disass s:ScriptFuncCall')
|
||||
assert_match('<SNR>\d\+_ScriptFuncCall.*'
|
||||
\ .. 'changenr().*'
|
||||
\ .. ' BCALL changenr(argc 0).*'
|
||||
\ .. 'char2nr("abc").*'
|
||||
\ .. ' PUSHS "abc".*'
|
||||
\ .. ' BCALL char2nr(argc 1).*'
|
||||
\ .. 'Test_disassemble_new().*'
|
||||
\ .. ' DCALL Test_disassemble_new(argc 0).*'
|
||||
\ .. 'FuncWithArg(343).*'
|
||||
\ .. ' PUSHNR 343.*'
|
||||
\ .. ' DCALL FuncWithArg(argc 1).*'
|
||||
\ .. 'ScriptFuncNew().*'
|
||||
\ .. ' DCALL <SNR>\d\+_ScriptFuncNew(argc 0).*'
|
||||
\ .. 's:ScriptFuncNew().*'
|
||||
\ .. ' DCALL <SNR>\d\+_ScriptFuncNew(argc 0).*'
|
||||
\ .. 'UserFunc().*'
|
||||
\ .. ' UCALL UserFunc(argc 0).*'
|
||||
\ .. 'UserFuncWithArg("foo").*'
|
||||
\ .. ' PUSHS "foo".*'
|
||||
\ .. ' UCALL UserFuncWithArg(argc 1).*'
|
||||
\ .. 'let FuncRef = function("UserFunc").*'
|
||||
\ .. 'FuncRef().*'
|
||||
\ .. ' LOAD $\d.*'
|
||||
\ .. ' PCALL (argc 0).*'
|
||||
\ .. 'let FuncRefWithArg = function("UserFuncWithArg").*'
|
||||
\ .. 'FuncRefWithArg("bar").*'
|
||||
\ .. ' PUSHS "bar".*'
|
||||
\ .. ' LOAD $\d.*'
|
||||
\ .. ' PCALL (argc 1).*'
|
||||
\ .. 'return "yes".*'
|
||||
\ .. ' PUSHS "yes".*'
|
||||
\ .. ' RETURN.*'
|
||||
\, res)
|
||||
enddef
|
||||
|
||||
def HasEval()
|
||||
if has("eval")
|
||||
echo "yes"
|
||||
else
|
||||
echo "no"
|
||||
endif
|
||||
enddef
|
||||
|
||||
def HasNothing()
|
||||
if has("nothing")
|
||||
echo "yes"
|
||||
else
|
||||
echo "no"
|
||||
endif
|
||||
enddef
|
||||
|
||||
def HasSomething()
|
||||
if has("nothing")
|
||||
echo "nothing"
|
||||
elseif has("something")
|
||||
echo "something"
|
||||
elseif has("eval")
|
||||
echo "eval"
|
||||
elseif has("less")
|
||||
echo "less"
|
||||
endif
|
||||
enddef
|
||||
|
||||
def Test_disassemble_const_expr()
|
||||
assert_equal("\nyes", execute('call HasEval()'))
|
||||
let instr = execute('disassemble HasEval')
|
||||
assert_match('HasEval.*'
|
||||
\ .. 'if has("eval").*'
|
||||
\ .. ' PUSHS "yes".*'
|
||||
\, instr)
|
||||
assert_notmatch('JUMP', instr)
|
||||
|
||||
assert_equal("\nno", execute('call HasNothing()'))
|
||||
instr = execute('disassemble HasNothing')
|
||||
assert_match('HasNothing.*'
|
||||
\ .. 'if has("nothing").*'
|
||||
\ .. 'else.*'
|
||||
\ .. ' PUSHS "no".*'
|
||||
\, instr)
|
||||
assert_notmatch('PUSHS "yes"', instr)
|
||||
assert_notmatch('JUMP', instr)
|
||||
|
||||
assert_equal("\neval", execute('call HasSomething()'))
|
||||
instr = execute('disassemble HasSomething')
|
||||
assert_match('HasSomething.*'
|
||||
\ .. 'if has("nothing").*'
|
||||
\ .. 'elseif has("something").*'
|
||||
\ .. 'elseif has("eval").*'
|
||||
\ .. ' PUSHS "eval".*'
|
||||
\ .. 'elseif has("less").*'
|
||||
\, instr)
|
||||
assert_notmatch('PUSHS "nothing"', instr)
|
||||
assert_notmatch('PUSHS "something"', instr)
|
||||
assert_notmatch('PUSHS "less"', instr)
|
||||
assert_notmatch('JUMP', instr)
|
||||
enddef
|
||||
|
||||
def WithLambda(): string
|
||||
let F = {a -> "X" .. a .. "X"}
|
||||
return F("x")
|
||||
enddef
|
||||
|
||||
def Test_disassemble_lambda()
|
||||
assert_equal("XxX", WithLambda())
|
||||
let instr = execute('disassemble WithLambda')
|
||||
assert_match('WithLambda.*'
|
||||
\ .. 'let F = {a -> "X" .. a .. "X"}.*'
|
||||
\ .. ' FUNCREF <lambda>\d\+.*'
|
||||
\ .. 'PUSHS "x".*'
|
||||
\ .. ' LOAD $0.*'
|
||||
\ .. ' PCALL (argc 1).*'
|
||||
\ .. ' CHECKTYPE string stack\[-1].*'
|
||||
\, instr)
|
||||
enddef
|
||||
|
||||
def AndOr(arg): string
|
||||
if arg == 1 && arg != 2 || arg == 4
|
||||
return 'yes'
|
||||
endif
|
||||
return 'no'
|
||||
enddef
|
||||
|
||||
def Test_disassemble_and_or()
|
||||
assert_equal("yes", AndOr(1))
|
||||
assert_equal("no", AndOr(2))
|
||||
assert_equal("yes", AndOr(4))
|
||||
let instr = execute('disassemble AndOr')
|
||||
assert_match('AndOr.*'
|
||||
\ .. 'if arg == 1 && arg != 2 || arg == 4.*'
|
||||
\ .. '\d LOAD arg\[-1].*'
|
||||
\ .. '\d PUSHNR 1.*'
|
||||
\ .. '\d COMPAREANY ==.*'
|
||||
\ .. '\d JUMP_AND_KEEP_IF_FALSE -> \d\+.*'
|
||||
\ .. '\d LOAD arg\[-1].*'
|
||||
\ .. '\d PUSHNR 2.*'
|
||||
\ .. '\d COMPAREANY !=.*'
|
||||
\ .. '\d JUMP_AND_KEEP_IF_TRUE -> \d\+.*'
|
||||
\ .. '\d LOAD arg\[-1].*'
|
||||
\ .. '\d PUSHNR 4.*'
|
||||
\ .. '\d COMPAREANY ==.*'
|
||||
\ .. '\d JUMP_IF_FALSE -> \d\+.*'
|
||||
\, instr)
|
||||
enddef
|
||||
|
||||
def ForLoop(): list<number>
|
||||
let res: list<number>
|
||||
for i in range(3)
|
||||
res->add(i)
|
||||
endfor
|
||||
return res
|
||||
enddef
|
||||
|
||||
def Test_disassemble_for_loop()
|
||||
assert_equal([0, 1, 2], ForLoop())
|
||||
let instr = execute('disassemble ForLoop')
|
||||
assert_match('ForLoop.*'
|
||||
\ .. 'let res: list<number>.*'
|
||||
\ .. ' NEWLIST size 0.*'
|
||||
\ .. '\d STORE $0.*'
|
||||
\ .. 'for i in range(3).*'
|
||||
\ .. '\d STORE -1 in $1.*'
|
||||
\ .. '\d PUSHNR 3.*'
|
||||
\ .. '\d BCALL range(argc 1).*'
|
||||
\ .. '\d FOR $1 -> \d\+.*'
|
||||
\ .. '\d STORE $2.*'
|
||||
\ .. 'res->add(i).*'
|
||||
\ .. '\d LOAD $0.*'
|
||||
\ .. '\d LOAD $2.*'
|
||||
\ .. '\d BCALL add(argc 2).*'
|
||||
\ .. '\d DROP.*'
|
||||
\ .. 'endfor.*'
|
||||
\ .. '\d JUMP -> \d\+.*'
|
||||
\ .. '\d DROP.*'
|
||||
\, instr)
|
||||
enddef
|
||||
|
||||
let g:number = 42
|
||||
|
||||
def Computing()
|
||||
let nr = 3
|
||||
let nrres = nr + 7
|
||||
nrres = nr - 7
|
||||
nrres = nr * 7
|
||||
nrres = nr / 7
|
||||
nrres = nr % 7
|
||||
|
||||
let anyres = g:number + 7
|
||||
anyres = g:number - 7
|
||||
anyres = g:number * 7
|
||||
anyres = g:number / 7
|
||||
anyres = g:number % 7
|
||||
|
||||
if has('float')
|
||||
let fl = 3.0
|
||||
let flres = fl + 7.0
|
||||
flres = fl - 7.0
|
||||
flres = fl * 7.0
|
||||
flres = fl / 7.0
|
||||
endif
|
||||
enddef
|
||||
|
||||
def Test_disassemble_computing()
|
||||
let instr = execute('disassemble Computing')
|
||||
assert_match('Computing.*'
|
||||
\ .. 'let nr = 3.*'
|
||||
\ .. '\d STORE 3 in $0.*'
|
||||
\ .. 'let nrres = nr + 7.*'
|
||||
\ .. '\d LOAD $0.*'
|
||||
\ .. '\d PUSHNR 7.*'
|
||||
\ .. '\d OPNR +.*'
|
||||
\ .. '\d STORE $1.*'
|
||||
\ .. 'nrres = nr - 7.*'
|
||||
\ .. '\d OPNR -.*'
|
||||
\ .. 'nrres = nr \* 7.*'
|
||||
\ .. '\d OPNR \*.*'
|
||||
\ .. 'nrres = nr / 7.*'
|
||||
\ .. '\d OPNR /.*'
|
||||
\ .. 'nrres = nr % 7.*'
|
||||
\ .. '\d OPNR %.*'
|
||||
\ .. 'let anyres = g:number + 7.*'
|
||||
\ .. '\d LOADG g:number.*'
|
||||
\ .. '\d PUSHNR 7.*'
|
||||
\ .. '\d OPANY +.*'
|
||||
\ .. '\d STORE $2.*'
|
||||
\ .. 'anyres = g:number - 7.*'
|
||||
\ .. '\d OPANY -.*'
|
||||
\ .. 'anyres = g:number \* 7.*'
|
||||
\ .. '\d OPANY \*.*'
|
||||
\ .. 'anyres = g:number / 7.*'
|
||||
\ .. '\d OPANY /.*'
|
||||
\ .. 'anyres = g:number % 7.*'
|
||||
\ .. '\d OPANY %.*'
|
||||
\, instr)
|
||||
if has('float')
|
||||
assert_match('Computing.*'
|
||||
\ .. 'let fl = 3.0.*'
|
||||
\ .. '\d PUSHF 3.0.*'
|
||||
\ .. '\d STORE $3.*'
|
||||
\ .. 'let flres = fl + 7.0.*'
|
||||
\ .. '\d LOAD $3.*'
|
||||
\ .. '\d PUSHF 7.0.*'
|
||||
\ .. '\d OPFLOAT +.*'
|
||||
\ .. '\d STORE $4.*'
|
||||
\ .. 'flres = fl - 7.0.*'
|
||||
\ .. '\d OPFLOAT -.*'
|
||||
\ .. 'flres = fl \* 7.0.*'
|
||||
\ .. '\d OPFLOAT \*.*'
|
||||
\ .. 'flres = fl / 7.0.*'
|
||||
\ .. '\d OPFLOAT /.*'
|
||||
\, instr)
|
||||
endif
|
||||
enddef
|
||||
|
||||
def Test_disassemble_compare()
|
||||
" TODO: COMPAREFUNC
|
||||
let cases = [
|
||||
\ ['true == false', 'COMPAREBOOL =='],
|
||||
\ ['true != false', 'COMPAREBOOL !='],
|
||||
\ ['v:none == v:null', 'COMPARESPECIAL =='],
|
||||
\ ['v:none != v:null', 'COMPARESPECIAL !='],
|
||||
\
|
||||
\ ['111 == 222', 'COMPARENR =='],
|
||||
\ ['111 != 222', 'COMPARENR !='],
|
||||
\ ['111 > 222', 'COMPARENR >'],
|
||||
\ ['111 < 222', 'COMPARENR <'],
|
||||
\ ['111 >= 222', 'COMPARENR >='],
|
||||
\ ['111 <= 222', 'COMPARENR <='],
|
||||
\ ['111 =~ 222', 'COMPARENR =\~'],
|
||||
\ ['111 !~ 222', 'COMPARENR !\~'],
|
||||
\
|
||||
\ ['"xx" == "yy"', 'COMPARESTRING =='],
|
||||
\ ['"xx" != "yy"', 'COMPARESTRING !='],
|
||||
\ ['"xx" > "yy"', 'COMPARESTRING >'],
|
||||
\ ['"xx" < "yy"', 'COMPARESTRING <'],
|
||||
\ ['"xx" >= "yy"', 'COMPARESTRING >='],
|
||||
\ ['"xx" <= "yy"', 'COMPARESTRING <='],
|
||||
\ ['"xx" =~ "yy"', 'COMPARESTRING =\~'],
|
||||
\ ['"xx" !~ "yy"', 'COMPARESTRING !\~'],
|
||||
\ ['"xx" is "yy"', 'COMPARESTRING is'],
|
||||
\ ['"xx" isnot "yy"', 'COMPARESTRING isnot'],
|
||||
\
|
||||
\ ['0z11 == 0z22', 'COMPAREBLOB =='],
|
||||
\ ['0z11 != 0z22', 'COMPAREBLOB !='],
|
||||
\ ['0z11 is 0z22', 'COMPAREBLOB is'],
|
||||
\ ['0z11 isnot 0z22', 'COMPAREBLOB isnot'],
|
||||
\
|
||||
\ ['[1,2] == [3,4]', 'COMPARELIST =='],
|
||||
\ ['[1,2] != [3,4]', 'COMPARELIST !='],
|
||||
\ ['[1,2] is [3,4]', 'COMPARELIST is'],
|
||||
\ ['[1,2] isnot [3,4]', 'COMPARELIST isnot'],
|
||||
\
|
||||
\ ['#{a:1} == #{x:2}', 'COMPAREDICT =='],
|
||||
\ ['#{a:1} != #{x:2}', 'COMPAREDICT !='],
|
||||
\ ['#{a:1} is #{x:2}', 'COMPAREDICT is'],
|
||||
\ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'],
|
||||
\
|
||||
\ ['{->33} == {->44}', 'COMPAREPARTIAL =='],
|
||||
\ ['{->33} != {->44}', 'COMPAREPARTIAL !='],
|
||||
\ ['{->33} is {->44}', 'COMPAREPARTIAL is'],
|
||||
\ ['{->33} isnot {->44}', 'COMPAREPARTIAL isnot'],
|
||||
\
|
||||
\ ['77 == g:xx', 'COMPAREANY =='],
|
||||
\ ['77 != g:xx', 'COMPAREANY !='],
|
||||
\ ['77 > g:xx', 'COMPAREANY >'],
|
||||
\ ['77 < g:xx', 'COMPAREANY <'],
|
||||
\ ['77 >= g:xx', 'COMPAREANY >='],
|
||||
\ ['77 <= g:xx', 'COMPAREANY <='],
|
||||
\ ['77 =~ g:xx', 'COMPAREANY =\~'],
|
||||
\ ['77 !~ g:xx', 'COMPAREANY !\~'],
|
||||
\ ['77 is g:xx', 'COMPAREANY is'],
|
||||
\ ['77 isnot g:xx', 'COMPAREANY isnot'],
|
||||
\ ]
|
||||
if has('float')
|
||||
cases->extend([
|
||||
\ ['1.1 == 2.2', 'COMPAREFLOAT =='],
|
||||
\ ['1.1 != 2.2', 'COMPAREFLOAT !='],
|
||||
\ ['1.1 > 2.2', 'COMPAREFLOAT >'],
|
||||
\ ['1.1 < 2.2', 'COMPAREFLOAT <'],
|
||||
\ ['1.1 >= 2.2', 'COMPAREFLOAT >='],
|
||||
\ ['1.1 <= 2.2', 'COMPAREFLOAT <='],
|
||||
\ ['1.1 =~ 2.2', 'COMPAREFLOAT =\~'],
|
||||
\ ['1.1 !~ 2.2', 'COMPAREFLOAT !\~'],
|
||||
\ ])
|
||||
endif
|
||||
|
||||
let nr = 1
|
||||
for case in cases
|
||||
writefile(['def TestCase' .. nr .. '()',
|
||||
\ ' if ' .. case[0],
|
||||
\ ' echo 42'
|
||||
\ ' endif',
|
||||
\ 'enddef'], 'Xdisassemble')
|
||||
source Xdisassemble
|
||||
let instr = execute('disassemble TestCase' .. nr)
|
||||
assert_match('TestCase' .. nr .. '.*'
|
||||
\ .. 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*'
|
||||
\ .. '\d \(PUSH\|FUNCREF\).*'
|
||||
\ .. '\d \(PUSH\|FUNCREF\|LOADG\).*'
|
||||
\ .. '\d ' .. case[1] .. '.*'
|
||||
\ .. '\d JUMP_IF_FALSE -> \d\+.*'
|
||||
\, instr)
|
||||
|
||||
nr += 1
|
||||
endfor
|
||||
|
||||
" delete('Xdisassemble')
|
||||
enddef
|
||||
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
@ -27,6 +27,9 @@ func Test_def_basic()
|
||||
call assert_equal('yes', SomeFunc())
|
||||
endfunc
|
||||
|
||||
let s:appendToMe = 'xxx'
|
||||
let s:addToMe = 111
|
||||
|
||||
def Test_assignment()
|
||||
let bool1: bool = true
|
||||
assert_equal(v:true, bool1)
|
||||
@ -44,11 +47,16 @@ def Test_assignment()
|
||||
let dict2: dict<number> = #{one: 1, two: 2}
|
||||
|
||||
v:char = 'abc'
|
||||
call assert_equal('abc', v:char)
|
||||
assert_equal('abc', v:char)
|
||||
|
||||
$ENVVAR = 'foobar'
|
||||
call assert_equal('foobar', $ENVVAR)
|
||||
assert_equal('foobar', $ENVVAR)
|
||||
$ENVVAR = ''
|
||||
|
||||
appendToMe ..= 'yyy'
|
||||
assert_equal('xxxyyy', appendToMe)
|
||||
addToMe += 222
|
||||
assert_equal(333, addToMe)
|
||||
enddef
|
||||
|
||||
func Test_assignment_failure()
|
||||
@ -131,6 +139,39 @@ def Test_call_varargs()
|
||||
assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
|
||||
enddef
|
||||
|
||||
def MyDefaultArgs(name = 'string'): string
|
||||
return name
|
||||
enddef
|
||||
|
||||
def Test_call_default_args()
|
||||
assert_equal('string', MyDefaultArgs())
|
||||
assert_equal('one', MyDefaultArgs('one'))
|
||||
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
enddef
|
||||
|
||||
func Test_call_default_args_from_func()
|
||||
call assert_equal('string', MyDefaultArgs())
|
||||
call assert_equal('one', MyDefaultArgs('one'))
|
||||
call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
endfunc
|
||||
|
||||
" Default arg and varargs
|
||||
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
|
||||
let res = one .. ',' .. two
|
||||
for s in rest
|
||||
res ..= ',' .. s
|
||||
endfor
|
||||
return res
|
||||
enddef
|
||||
|
||||
def Test_call_def_varargs()
|
||||
call assert_fails('call MyDefVarargs()', 'E119:')
|
||||
assert_equal('one,foo', MyDefVarargs('one'))
|
||||
assert_equal('one,two', MyDefVarargs('one', 'two'))
|
||||
assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
|
||||
enddef
|
||||
|
||||
|
||||
"def Test_call_func_defined_later()
|
||||
" call assert_equal('one', DefineLater('one'))
|
||||
" call assert_fails('call NotDefined("one")', 'E99:')
|
||||
@ -140,25 +181,6 @@ func DefineLater(arg)
|
||||
return a:arg
|
||||
endfunc
|
||||
|
||||
def MyDefaultArgs(name = 'string'): string
|
||||
return name
|
||||
enddef
|
||||
|
||||
func Test_call_default_args_from_func()
|
||||
" TODO: implement using default value for optional argument
|
||||
"call assert_equal('string', MyDefaultArgs())
|
||||
call assert_fails('call MyDefaultArgs()', 'optional arguments not implemented yet')
|
||||
call assert_equal('one', MyDefaultArgs('one'))
|
||||
call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
endfunc
|
||||
|
||||
def Test_call_default_args()
|
||||
" TODO: implement using default value for optional argument
|
||||
"assert_equal('string', MyDefaultArgs())
|
||||
assert_equal('one', MyDefaultArgs('one'))
|
||||
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
enddef
|
||||
|
||||
def Test_return_type_wrong()
|
||||
CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string')
|
||||
CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number')
|
||||
@ -195,6 +217,7 @@ let s:export_script_lines =<< trim END
|
||||
|
||||
export const CONST = 1234
|
||||
export let exported = 9876
|
||||
export let exp_name = 'John'
|
||||
export def Exported(): string
|
||||
return 'Exported'
|
||||
enddef
|
||||
@ -205,7 +228,14 @@ def Test_vim9script()
|
||||
vim9script
|
||||
import {exported, Exported} from './Xexport.vim'
|
||||
g:imported = exported
|
||||
exported += 3
|
||||
g:imported_added = exported
|
||||
g:imported_func = Exported()
|
||||
|
||||
import {exp_name} from './Xexport.vim'
|
||||
g:imported_name = exp_name
|
||||
exp_name ..= ' Doe'
|
||||
g:imported_name_appended = exp_name
|
||||
END
|
||||
|
||||
writefile(import_script_lines, 'Ximport.vim')
|
||||
@ -216,13 +246,18 @@ def Test_vim9script()
|
||||
assert_equal('bobbie', g:result)
|
||||
assert_equal('bob', g:localname)
|
||||
assert_equal(9876, g:imported)
|
||||
assert_equal(9879, g:imported_added)
|
||||
assert_equal('Exported', g:imported_func)
|
||||
assert_equal('John', g:imported_name)
|
||||
assert_equal('John Doe', g:imported_name_appended)
|
||||
assert_false(exists('g:name'))
|
||||
|
||||
unlet g:result
|
||||
unlet g:localname
|
||||
unlet g:imported
|
||||
unlet g:imported_added
|
||||
unlet g:imported_func
|
||||
unlet g:imported_name g:imported_name_appended
|
||||
delete('Ximport.vim')
|
||||
delete('Xexport.vim')
|
||||
|
||||
@ -424,108 +459,22 @@ def do_something():
|
||||
EOF
|
||||
endfunc
|
||||
|
||||
def HasEval()
|
||||
if has('eval')
|
||||
echo 'yes'
|
||||
def IfElse(what: number): string
|
||||
let res = ''
|
||||
if what == 1
|
||||
res = "one"
|
||||
elseif what == 2
|
||||
res = "two"
|
||||
else
|
||||
echo 'no'
|
||||
res = "three"
|
||||
endif
|
||||
return res
|
||||
enddef
|
||||
|
||||
def HasNothing()
|
||||
if has('nothing')
|
||||
echo 'yes'
|
||||
else
|
||||
echo 'no'
|
||||
endif
|
||||
enddef
|
||||
|
||||
def Test_compile_const_expr()
|
||||
assert_equal("\nyes", execute('call HasEval()'))
|
||||
let instr = execute('disassemble HasEval')
|
||||
assert_match('PUSHS "yes"', instr)
|
||||
assert_notmatch('PUSHS "no"', instr)
|
||||
assert_notmatch('JUMP', instr)
|
||||
|
||||
assert_equal("\nno", execute('call HasNothing()'))
|
||||
instr = execute('disassemble HasNothing')
|
||||
assert_notmatch('PUSHS "yes"', instr)
|
||||
assert_match('PUSHS "no"', instr)
|
||||
assert_notmatch('JUMP', instr)
|
||||
enddef
|
||||
|
||||
func NotCompiled()
|
||||
echo "not"
|
||||
endfunc
|
||||
|
||||
let s:scriptvar = 4
|
||||
let g:globalvar = 'g'
|
||||
|
||||
def s:ScriptFuncLoad(arg: string)
|
||||
let local = 1
|
||||
buffers
|
||||
echo arg
|
||||
echo local
|
||||
echo v:version
|
||||
echo s:scriptvar
|
||||
echo g:globalvar
|
||||
echo &tabstop
|
||||
echo $ENVVAR
|
||||
echo @z
|
||||
enddef
|
||||
|
||||
def s:ScriptFuncStore()
|
||||
let localnr = 1
|
||||
localnr = 2
|
||||
let localstr = 'abc'
|
||||
localstr = 'xyz'
|
||||
v:char = 'abc'
|
||||
s:scriptvar = 'sv'
|
||||
g:globalvar = 'gv'
|
||||
&tabstop = 8
|
||||
$ENVVAR = 'ev'
|
||||
@z = 'rv'
|
||||
enddef
|
||||
|
||||
def Test_disassemble()
|
||||
assert_fails('disass NoFunc', 'E1061:')
|
||||
assert_fails('disass NotCompiled', 'E1062:')
|
||||
|
||||
let res = execute('disass s:ScriptFuncLoad')
|
||||
assert_match('<SNR>\d*_ScriptFuncLoad.*'
|
||||
\ .. 'buffers.*'
|
||||
\ .. ' EXEC \+buffers.*'
|
||||
\ .. ' LOAD arg\[-1\].*'
|
||||
\ .. ' LOAD $0.*'
|
||||
\ .. ' LOADV v:version.*'
|
||||
\ .. ' LOADS s:scriptvar from .*test_vim9_script.vim.*'
|
||||
\ .. ' LOADG g:globalvar.*'
|
||||
\ .. ' LOADENV $ENVVAR.*'
|
||||
\ .. ' LOADREG @z.*'
|
||||
\, res)
|
||||
|
||||
" TODO:
|
||||
" v:char =
|
||||
" s:scriptvar =
|
||||
res = execute('disass s:ScriptFuncStore')
|
||||
assert_match('<SNR>\d*_ScriptFuncStore.*'
|
||||
\ .. 'localnr = 2.*'
|
||||
\ .. ' STORE 2 in $0.*'
|
||||
\ .. 'localstr = ''xyz''.*'
|
||||
\ .. ' STORE $1.*'
|
||||
\ .. 'v:char = ''abc''.*'
|
||||
\ .. 'STOREV v:char.*'
|
||||
\ .. 's:scriptvar = ''sv''.*'
|
||||
\ .. ' STORES s:scriptvar in .*test_vim9_script.vim.*'
|
||||
\ .. 'g:globalvar = ''gv''.*'
|
||||
\ .. ' STOREG g:globalvar.*'
|
||||
\ .. '&tabstop = 8.*'
|
||||
\ .. ' STOREOPT &tabstop.*'
|
||||
\ .. '$ENVVAR = ''ev''.*'
|
||||
\ .. ' STOREENV $ENVVAR.*'
|
||||
\ .. '@z = ''rv''.*'
|
||||
\ .. ' STOREREG @z.*'
|
||||
\, res)
|
||||
def Test_if_elseif_else()
|
||||
assert_equal('one', IfElse(1))
|
||||
assert_equal('two', IfElse(2))
|
||||
assert_equal('three', IfElse(3))
|
||||
enddef
|
||||
|
||||
|
||||
|
@ -631,6 +631,19 @@ f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* "test_clear_search_pat()"
|
||||
* Free the last search and substitute patterns
|
||||
*/
|
||||
void
|
||||
f_test_clear_search_pat(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||
{
|
||||
free_last_pat(RE_SUBST);
|
||||
free_last_pat(RE_SEARCH);
|
||||
set_old_sub(NULL);
|
||||
free_regexp_prev_sub();
|
||||
}
|
||||
|
||||
/*
|
||||
* "test_feedinput()"
|
||||
*/
|
||||
|
@ -200,6 +200,7 @@ get_function_args(
|
||||
{
|
||||
typval_T rettv;
|
||||
|
||||
// find the end of the expression (doesn't evaluate it)
|
||||
any_default = TRUE;
|
||||
p = skipwhite(p) + 1;
|
||||
p = skipwhite(p);
|
||||
@ -572,8 +573,6 @@ get_func_tv(
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define FLEN_FIXED 40
|
||||
|
||||
/*
|
||||
* Return TRUE if "p" starts with "<SID>" or "s:".
|
||||
* Only works if eval_fname_script() returned non-zero for "p"!
|
||||
@ -590,7 +589,7 @@ eval_fname_sid(char_u *p)
|
||||
* Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory
|
||||
* (slow).
|
||||
*/
|
||||
static char_u *
|
||||
char_u *
|
||||
fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
|
||||
{
|
||||
int llen;
|
||||
|
@ -742,6 +742,50 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
229,
|
||||
/**/
|
||||
228,
|
||||
/**/
|
||||
227,
|
||||
/**/
|
||||
226,
|
||||
/**/
|
||||
225,
|
||||
/**/
|
||||
224,
|
||||
/**/
|
||||
223,
|
||||
/**/
|
||||
222,
|
||||
/**/
|
||||
221,
|
||||
/**/
|
||||
220,
|
||||
/**/
|
||||
219,
|
||||
/**/
|
||||
218,
|
||||
/**/
|
||||
217,
|
||||
/**/
|
||||
216,
|
||||
/**/
|
||||
215,
|
||||
/**/
|
||||
214,
|
||||
/**/
|
||||
213,
|
||||
/**/
|
||||
212,
|
||||
/**/
|
||||
211,
|
||||
/**/
|
||||
210,
|
||||
/**/
|
||||
209,
|
||||
/**/
|
||||
208,
|
||||
/**/
|
||||
207,
|
||||
/**/
|
||||
|
@ -2574,6 +2574,9 @@ typedef enum {
|
||||
#define FCERR_DELETED 7
|
||||
#define FCERR_NOTMETHOD 8 // function cannot be used as a method
|
||||
|
||||
// fixed buffer length for fname_trans_sid()
|
||||
#define FLEN_FIXED 40
|
||||
|
||||
// flags for find_name_end()
|
||||
#define FNE_INCL_BR 1 // include [] in name
|
||||
#define FNE_CHECK_START 2 // check name starts with valid character
|
||||
|
@ -130,7 +130,6 @@ typedef struct {
|
||||
|
||||
typedef enum {
|
||||
JUMP_ALWAYS,
|
||||
JUMP_IF_TRUE, // pop and jump if true
|
||||
JUMP_IF_FALSE, // pop and jump if false
|
||||
JUMP_AND_KEEP_IF_TRUE, // jump if top of stack is true, drop if not
|
||||
JUMP_AND_KEEP_IF_FALSE, // jump if top of stack is false, drop if not
|
||||
|
@ -956,11 +956,12 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount)
|
||||
* Return FAIL if the number of arguments is wrong.
|
||||
*/
|
||||
static int
|
||||
generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int argcount)
|
||||
generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
||||
{
|
||||
isn_T *isn;
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
int regular_args = ufunc->uf_args.ga_len;
|
||||
int argcount = pushed_argcount;
|
||||
|
||||
if (argcount > regular_args && !has_varargs(ufunc))
|
||||
{
|
||||
@ -978,9 +979,13 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int argcount)
|
||||
{
|
||||
int count = argcount - regular_args;
|
||||
|
||||
// TODO: add default values for optional arguments?
|
||||
generate_NEWLIST(cctx, count < 0 ? 0 : count);
|
||||
argcount = regular_args + 1;
|
||||
// If count is negative an empty list will be added after evaluating
|
||||
// default values for missing optional arguments.
|
||||
if (count >= 0)
|
||||
{
|
||||
generate_NEWLIST(cctx, count);
|
||||
argcount = regular_args + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((isn = generate_instr(cctx,
|
||||
@ -1681,49 +1686,60 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init)
|
||||
char_u *p;
|
||||
int argcount = argcount_init;
|
||||
char_u namebuf[100];
|
||||
char_u fname_buf[FLEN_FIXED + 1];
|
||||
char_u *tofree = NULL;
|
||||
int error = FCERR_NONE;
|
||||
ufunc_T *ufunc;
|
||||
int res = FAIL;
|
||||
|
||||
if (varlen >= sizeof(namebuf))
|
||||
{
|
||||
semsg(_("E1011: name too long: %s"), name);
|
||||
return FAIL;
|
||||
}
|
||||
vim_strncpy(namebuf, name, varlen);
|
||||
vim_strncpy(namebuf, *arg, varlen);
|
||||
name = fname_trans_sid(namebuf, fname_buf, &tofree, &error);
|
||||
|
||||
*arg = skipwhite(*arg + varlen + 1);
|
||||
if (compile_arguments(arg, cctx, &argcount) == FAIL)
|
||||
return FAIL;
|
||||
goto theend;
|
||||
|
||||
if (ASCII_ISLOWER(*name))
|
||||
if (ASCII_ISLOWER(*name) && name[1] != ':')
|
||||
{
|
||||
int idx;
|
||||
|
||||
// builtin function
|
||||
idx = find_internal_func(namebuf);
|
||||
idx = find_internal_func(name);
|
||||
if (idx >= 0)
|
||||
return generate_BCALL(cctx, idx, argcount);
|
||||
{
|
||||
res = generate_BCALL(cctx, idx, argcount);
|
||||
goto theend;
|
||||
}
|
||||
semsg(_(e_unknownfunc), namebuf);
|
||||
}
|
||||
|
||||
// User defined function or variable must start with upper case.
|
||||
if (!ASCII_ISUPPER(*name))
|
||||
{
|
||||
semsg(_("E1012: Invalid function name: %s"), namebuf);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// If we can find the function by name generate the right call.
|
||||
ufunc = find_func(namebuf, cctx);
|
||||
ufunc = find_func(name, cctx);
|
||||
if (ufunc != NULL)
|
||||
return generate_CALL(cctx, ufunc, argcount);
|
||||
{
|
||||
res = generate_CALL(cctx, ufunc, argcount);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
// If the name is a variable, load it and use PCALL.
|
||||
p = namebuf;
|
||||
if (compile_load(&p, namebuf + varlen, cctx, FALSE) == OK)
|
||||
return generate_PCALL(cctx, argcount, FALSE);
|
||||
{
|
||||
res = generate_PCALL(cctx, argcount, FALSE);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
// The function may be defined only later. Need to figure out at runtime.
|
||||
return generate_UCALL(cctx, namebuf, argcount);
|
||||
res = generate_UCALL(cctx, name, argcount);
|
||||
|
||||
theend:
|
||||
vim_free(tofree);
|
||||
return res;
|
||||
}
|
||||
|
||||
// like NAMESPACE_CHAR but with 'a' and 'l'.
|
||||
@ -2326,7 +2342,7 @@ compile_subscript(
|
||||
emsg(_(e_missbrac));
|
||||
return FAIL;
|
||||
}
|
||||
*arg = skipwhite(*arg + 1);
|
||||
*arg = *arg + 1;
|
||||
|
||||
if (generate_instr_drop(cctx, ISN_INDEX, 1) == FAIL)
|
||||
return FAIL;
|
||||
@ -3411,13 +3427,51 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
else
|
||||
{
|
||||
// variables are always initialized
|
||||
// TODO: support more types
|
||||
if (ga_grow(instr, 1) == FAIL)
|
||||
goto theend;
|
||||
if (type->tt_type == VAR_STRING)
|
||||
generate_PUSHS(cctx, vim_strsave((char_u *)""));
|
||||
else
|
||||
generate_PUSHNR(cctx, 0);
|
||||
switch (type->tt_type)
|
||||
{
|
||||
case VAR_BOOL:
|
||||
generate_PUSHBOOL(cctx, VVAL_FALSE);
|
||||
break;
|
||||
case VAR_SPECIAL:
|
||||
generate_PUSHSPEC(cctx, VVAL_NONE);
|
||||
break;
|
||||
case VAR_FLOAT:
|
||||
#ifdef FEAT_FLOAT
|
||||
generate_PUSHF(cctx, 0.0);
|
||||
#endif
|
||||
break;
|
||||
case VAR_STRING:
|
||||
generate_PUSHS(cctx, NULL);
|
||||
break;
|
||||
case VAR_BLOB:
|
||||
generate_PUSHBLOB(cctx, NULL);
|
||||
break;
|
||||
case VAR_FUNC:
|
||||
// generate_PUSHS(cctx, NULL); TODO
|
||||
break;
|
||||
case VAR_PARTIAL:
|
||||
// generate_PUSHS(cctx, NULL); TODO
|
||||
break;
|
||||
case VAR_LIST:
|
||||
generate_NEWLIST(cctx, 0);
|
||||
break;
|
||||
case VAR_DICT:
|
||||
generate_NEWDICT(cctx, 0);
|
||||
break;
|
||||
case VAR_JOB:
|
||||
// generate_PUSHS(cctx, NULL); TODO
|
||||
break;
|
||||
case VAR_CHANNEL:
|
||||
// generate_PUSHS(cctx, NULL); TODO
|
||||
break;
|
||||
case VAR_NUMBER:
|
||||
case VAR_UNKNOWN:
|
||||
case VAR_VOID:
|
||||
generate_PUSHNR(cctx, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oplen > 0 && *op != '=')
|
||||
@ -3678,6 +3732,7 @@ evaluate_const_and_or(char_u **arg, cctx_T *cctx, char *op, typval_T *tv)
|
||||
// eval the next expression
|
||||
*arg = skipwhite(p + 2);
|
||||
tv2.v_type = VAR_UNKNOWN;
|
||||
tv2.v_lock = 0;
|
||||
if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2)
|
||||
: evaluate_const_expr7(arg, cctx, &tv2)) == FAIL)
|
||||
{
|
||||
@ -3874,7 +3929,7 @@ compile_elseif(char_u *arg, cctx_T *cctx)
|
||||
}
|
||||
cctx->ctx_locals.ga_len = scope->se_local_count;
|
||||
|
||||
if (cctx->ctx_skip != TRUE)
|
||||
if (cctx->ctx_skip == MAYBE)
|
||||
{
|
||||
if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
|
||||
JUMP_ALWAYS, cctx) == FAIL)
|
||||
@ -3930,13 +3985,14 @@ compile_else(char_u *arg, cctx_T *cctx)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cctx->ctx_skip != TRUE)
|
||||
if (cctx->ctx_skip == MAYBE)
|
||||
{
|
||||
if (scope->se_u.se_if.is_if_label >= 0)
|
||||
{
|
||||
// previous "if" or "elseif" jumps here
|
||||
isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
|
||||
isn->isn_arg.jump.jump_where = instr->ga_len;
|
||||
scope->se_u.se_if.is_if_label = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4368,13 +4424,33 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
|
||||
}
|
||||
else
|
||||
{
|
||||
char_u *end;
|
||||
char_u *pat;
|
||||
char_u *tofree = NULL;
|
||||
size_t len;
|
||||
|
||||
// Push v:exception, push {expr} and MATCH
|
||||
generate_instr_type(cctx, ISN_PUSHEXC, &t_string);
|
||||
|
||||
if (compile_expr1(&p, cctx) == FAIL)
|
||||
return NULL;
|
||||
end = skip_regexp(p + 1, *p, TRUE, &tofree);
|
||||
if (*end != *p)
|
||||
{
|
||||
semsg(_("E1067: Separator mismatch: %s"), p);
|
||||
vim_free(tofree);
|
||||
return FAIL;
|
||||
}
|
||||
if (tofree == NULL)
|
||||
len = end - (p + 1);
|
||||
else
|
||||
len = end - (tofree + 1);
|
||||
pat = vim_strnsave(p + 1, len);
|
||||
vim_free(tofree);
|
||||
p += len + 2;
|
||||
if (pat == NULL)
|
||||
return FAIL;
|
||||
if (generate_PUSHS(cctx, pat) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
// TODO: check for strings?
|
||||
if (generate_COMPARE(cctx, EXPR_MATCH, FALSE) == FAIL)
|
||||
return NULL;
|
||||
|
||||
@ -4579,6 +4655,44 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
|
||||
// Most modern script version.
|
||||
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
|
||||
|
||||
if (ufunc->uf_def_args.ga_len > 0)
|
||||
{
|
||||
int count = ufunc->uf_def_args.ga_len;
|
||||
int i;
|
||||
char_u *arg;
|
||||
int off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0);
|
||||
|
||||
// Produce instructions for the default values of optional arguments.
|
||||
// Store the instruction index in uf_def_arg_idx[] so that we know
|
||||
// where to start when the function is called, depending on the number
|
||||
// of arguments.
|
||||
ufunc->uf_def_arg_idx = ALLOC_CLEAR_MULT(int, count + 1);
|
||||
if (ufunc->uf_def_arg_idx == NULL)
|
||||
goto erret;
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
ufunc->uf_def_arg_idx[i] = instr->ga_len;
|
||||
arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
|
||||
if (compile_expr1(&arg, &cctx) == FAIL
|
||||
|| generate_STORE(&cctx, ISN_STORE,
|
||||
i - count - off, NULL) == FAIL)
|
||||
goto erret;
|
||||
}
|
||||
|
||||
// If a varargs is following, push an empty list.
|
||||
if (ufunc->uf_va_name != NULL)
|
||||
{
|
||||
if (generate_NEWLIST(&cctx, 0) == FAIL
|
||||
|| generate_STORE(&cctx, ISN_STORE, -off, NULL) == FAIL)
|
||||
goto erret;
|
||||
}
|
||||
|
||||
ufunc->uf_def_arg_idx[count] = instr->ga_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop over all the lines of the function and generate instructions.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
if (line != NULL && *line == '|')
|
||||
|
@ -70,7 +70,7 @@ typedef struct {
|
||||
#define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx)
|
||||
|
||||
/*
|
||||
* Return the number of arguments, including any vararg.
|
||||
* Return the number of arguments, including optional arguments and any vararg.
|
||||
*/
|
||||
static int
|
||||
ufunc_argcount(ufunc_T *ufunc)
|
||||
@ -78,6 +78,35 @@ ufunc_argcount(ufunc_T *ufunc)
|
||||
return ufunc->uf_args.ga_len + (ufunc->uf_va_name != NULL ? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the instruction index, depending on omitted arguments, where the default
|
||||
* values are to be computed. If all optional arguments are present, start
|
||||
* with the function body.
|
||||
* The expression evaluation is at the start of the instructions:
|
||||
* 0 -> EVAL default1
|
||||
* STORE arg[-2]
|
||||
* 1 -> EVAL default2
|
||||
* STORE arg[-1]
|
||||
* 2 -> function body
|
||||
*/
|
||||
static void
|
||||
init_instr_idx(ufunc_T *ufunc, int argcount, ectx_T *ectx)
|
||||
{
|
||||
if (ufunc->uf_def_args.ga_len == 0)
|
||||
ectx->ec_iidx = 0;
|
||||
else
|
||||
{
|
||||
int defcount = ufunc->uf_args.ga_len - argcount;
|
||||
|
||||
// If there is a varargs argument defcount can be negative, no defaults
|
||||
// to evaluate then.
|
||||
if (defcount < 0)
|
||||
defcount = 0;
|
||||
ectx->ec_iidx = ufunc->uf_def_arg_idx[
|
||||
ufunc->uf_def_args.ga_len - defcount];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Call compiled function "cdf_idx" from compiled code.
|
||||
*
|
||||
@ -107,23 +136,15 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx)
|
||||
if (ga_grow(&ectx->ec_stack, optcount + 3 + dfunc->df_varcount) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
// TODO: Put omitted argument default values on the stack.
|
||||
if (optcount > 0)
|
||||
{
|
||||
emsg("optional arguments not implemented yet");
|
||||
return FAIL;
|
||||
}
|
||||
if (optcount < 0)
|
||||
{
|
||||
emsg("argument count wrong?");
|
||||
return FAIL;
|
||||
}
|
||||
// for (idx = argcount - dfunc->df_minarg;
|
||||
// idx < dfunc->df_maxarg; ++idx)
|
||||
// {
|
||||
// copy_tv(&dfunc->df_defarg[idx], STACK_TV_BOT(0));
|
||||
// ++ectx->ec_stack.ga_len;
|
||||
// }
|
||||
|
||||
// Reserve space for omitted optional arguments, filled in soon.
|
||||
// Also any empty varargs argument.
|
||||
ectx->ec_stack.ga_len += optcount;
|
||||
|
||||
// Store current execution state in stack frame for ISN_RETURN.
|
||||
// TODO: If the actual number of arguments doesn't match what the called
|
||||
@ -142,7 +163,9 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx)
|
||||
ectx->ec_dfunc_idx = cdf_idx;
|
||||
ectx->ec_instr = dfunc->df_instr;
|
||||
estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1);
|
||||
ectx->ec_iidx = 0;
|
||||
|
||||
// Decide where to start execution, handles optional arguments.
|
||||
init_instr_idx(ufunc, argcount, ectx);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@ -156,9 +179,9 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx)
|
||||
static void
|
||||
func_return(ectx_T *ectx)
|
||||
{
|
||||
int ret_idx = ectx->ec_stack.ga_len - 1;
|
||||
int idx;
|
||||
dfunc_T *dfunc;
|
||||
int top;
|
||||
|
||||
// execution context goes one level up
|
||||
estack_pop();
|
||||
@ -166,17 +189,27 @@ func_return(ectx_T *ectx)
|
||||
// Clear the local variables and temporary values, but not
|
||||
// the return value.
|
||||
for (idx = ectx->ec_frame + STACK_FRAME_SIZE;
|
||||
idx < ectx->ec_stack.ga_len - 1; ++idx)
|
||||
idx < ectx->ec_stack.ga_len - 1; ++idx)
|
||||
clear_tv(STACK_TV(idx));
|
||||
|
||||
// Clear the arguments.
|
||||
dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
|
||||
ectx->ec_stack.ga_len = ectx->ec_frame
|
||||
- ufunc_argcount(dfunc->df_ufunc) + 1;
|
||||
top = ectx->ec_frame - ufunc_argcount(dfunc->df_ufunc);
|
||||
for (idx = top; idx < ectx->ec_frame; ++idx)
|
||||
clear_tv(STACK_TV(idx));
|
||||
|
||||
// Restore the previous frame.
|
||||
ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame)->vval.v_number;
|
||||
ectx->ec_iidx = STACK_TV(ectx->ec_frame + 1)->vval.v_number;
|
||||
ectx->ec_frame = STACK_TV(ectx->ec_frame + 2)->vval.v_number;
|
||||
*STACK_TV_BOT(-1) = *STACK_TV(ret_idx);
|
||||
dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
|
||||
ectx->ec_instr = dfunc->df_instr;
|
||||
|
||||
// Reset the stack to the position before the call, move the return value
|
||||
// to the top of the stack.
|
||||
idx = ectx->ec_stack.ga_len - 1;
|
||||
ectx->ec_stack.ga_len = top + 1;
|
||||
*STACK_TV_BOT(-1) = *STACK_TV(idx);
|
||||
}
|
||||
|
||||
#undef STACK_TV
|
||||
@ -362,7 +395,7 @@ call_def_function(
|
||||
int idx;
|
||||
int ret = FAIL;
|
||||
dfunc_T *dfunc;
|
||||
int optcount = ufunc_argcount(ufunc) - argc;
|
||||
int defcount = ufunc->uf_args.ga_len - argc;
|
||||
|
||||
// Get pointer to item in the stack.
|
||||
#define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
|
||||
@ -388,17 +421,18 @@ call_def_function(
|
||||
copy_tv(&argv[idx], STACK_TV_BOT(0));
|
||||
++ectx.ec_stack.ga_len;
|
||||
}
|
||||
// Make space for omitted arguments, will store default value below.
|
||||
if (defcount > 0)
|
||||
for (idx = 0; idx < defcount; ++idx)
|
||||
{
|
||||
STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
|
||||
++ectx.ec_stack.ga_len;
|
||||
}
|
||||
|
||||
// Frame pointer points to just after arguments.
|
||||
ectx.ec_frame = ectx.ec_stack.ga_len;
|
||||
initial_frame_ptr = ectx.ec_frame;
|
||||
|
||||
// TODO: Put omitted argument default values on the stack.
|
||||
if (optcount > 0)
|
||||
{
|
||||
emsg("optional arguments not implemented yet");
|
||||
return FAIL;
|
||||
}
|
||||
// dummy frame entries
|
||||
for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
|
||||
{
|
||||
@ -413,7 +447,10 @@ call_def_function(
|
||||
ectx.ec_stack.ga_len += dfunc->df_varcount;
|
||||
|
||||
ectx.ec_instr = dfunc->df_instr;
|
||||
ectx.ec_iidx = 0;
|
||||
|
||||
// Decide where to start execution, handles optional arguments.
|
||||
init_instr_idx(ufunc, argc, &ectx);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
isn_T *iptr;
|
||||
@ -964,8 +1001,7 @@ call_def_function(
|
||||
if (when == JUMP_IF_FALSE
|
||||
|| when == JUMP_AND_KEEP_IF_FALSE)
|
||||
jump = !jump;
|
||||
if (when == JUMP_IF_FALSE || when == JUMP_IF_TRUE
|
||||
|| !jump)
|
||||
if (when == JUMP_IF_FALSE || !jump)
|
||||
{
|
||||
// drop the value from the stack
|
||||
clear_tv(tv);
|
||||
@ -1546,15 +1582,14 @@ failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DISASSEMBLE 1
|
||||
|
||||
/*
|
||||
* ":dissassemble".
|
||||
* We don't really need this at runtime, but we do have tests that require it,
|
||||
* so always include this.
|
||||
*/
|
||||
void
|
||||
ex_disassemble(exarg_T *eap)
|
||||
{
|
||||
#ifdef DISASSEMBLE
|
||||
char_u *fname;
|
||||
ufunc_T *ufunc;
|
||||
dfunc_T *dfunc;
|
||||
@ -1587,6 +1622,7 @@ ex_disassemble(exarg_T *eap)
|
||||
for (current = 0; current < dfunc->df_instr_count; ++current)
|
||||
{
|
||||
isn_T *iptr = &instr[current];
|
||||
char *line;
|
||||
|
||||
while (line_idx < iptr->isn_lnum && line_idx < ufunc->uf_lines.ga_len)
|
||||
{
|
||||
@ -1595,7 +1631,9 @@ ex_disassemble(exarg_T *eap)
|
||||
msg_puts("\n\n");
|
||||
prev_current = current;
|
||||
}
|
||||
msg(((char **)ufunc->uf_lines.ga_data)[line_idx++]);
|
||||
line = ((char **)ufunc->uf_lines.ga_data)[line_idx++];
|
||||
if (line != NULL)
|
||||
msg(line);
|
||||
}
|
||||
|
||||
switch (iptr->isn_type)
|
||||
@ -1657,7 +1695,11 @@ ex_disassemble(exarg_T *eap)
|
||||
break;
|
||||
|
||||
case ISN_STORE:
|
||||
smsg("%4d STORE $%lld", current, iptr->isn_arg.number);
|
||||
if (iptr->isn_arg.number < 0)
|
||||
smsg("%4d STORE arg[%lld]", current,
|
||||
iptr->isn_arg.number + STACK_FRAME_SIZE);
|
||||
else
|
||||
smsg("%4d STORE $%lld", current, iptr->isn_arg.number);
|
||||
break;
|
||||
case ISN_STOREV:
|
||||
smsg("%4d STOREV v:%s", current,
|
||||
@ -1726,7 +1768,7 @@ ex_disassemble(exarg_T *eap)
|
||||
char_u *tofree;
|
||||
|
||||
r = blob2string(iptr->isn_arg.blob, &tofree, numbuf);
|
||||
smsg("%4d PUSHBLOB \"%s\"", current, r);
|
||||
smsg("%4d PUSHBLOB %s", current, r);
|
||||
vim_free(tofree);
|
||||
}
|
||||
break;
|
||||
@ -1799,9 +1841,6 @@ ex_disassemble(exarg_T *eap)
|
||||
case JUMP_ALWAYS:
|
||||
when = "JUMP";
|
||||
break;
|
||||
case JUMP_IF_TRUE:
|
||||
when = "JUMP_IF_TRUE";
|
||||
break;
|
||||
case JUMP_AND_KEEP_IF_TRUE:
|
||||
when = "JUMP_AND_KEEP_IF_TRUE";
|
||||
break;
|
||||
@ -1956,7 +1995,6 @@ ex_disassemble(exarg_T *eap)
|
||||
case ISN_DROP: smsg("%4d DROP", current); break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user