mirror of
https://github.com/vim/vim
synced 2025-07-17 09:41:54 +00:00
Compare commits
46 Commits
Author | SHA1 | Date | |
---|---|---|---|
373c65104e | |||
7633fe595e | |||
38041da1c2 | |||
73fef33014 | |||
8d9437968b | |||
7fe875583b | |||
f5433fbfe4 | |||
da58134eed | |||
23c5527373 | |||
e55b1c098d | |||
820ffa567c | |||
a3b7fdc1bb | |||
8c524f76eb | |||
6797966dfc | |||
0cb5bcf583 | |||
845e0ee594 | |||
a190548e91 | |||
b326edf5b3 | |||
ef6746f637 | |||
280b0dc815 | |||
1089374130 | |||
7e380030c1 | |||
20298ce679 | |||
1e0b7b11db | |||
ec9b017b87 | |||
3b74b6b4bb | |||
c785b9a7f4 | |||
128d307963 | |||
c5b1c20b6b | |||
0779fab297 | |||
c8cb883015 | |||
efd8855594 | |||
9b68c82b7c | |||
511feec6f0 | |||
865af6b990 | |||
ceb2e77510 | |||
72abcf42d4 | |||
158ea175a9 | |||
2f03e5a0a9 | |||
3d9207ad2f | |||
856c1110c1 | |||
40a019f157 | |||
e17f8817a1 | |||
9bb3eb3e02 | |||
f7d267ef20 | |||
101f4810e2 |
@ -8,6 +8,7 @@ cd src
|
||||
echo "Building MinGW 32bit console version"
|
||||
set PATH=c:\msys64\mingw32\bin;%PATH%
|
||||
mingw32-make.exe -f Make_ming.mak GUI=no OPTIMIZE=speed IME=yes ICONV=yes DEBUG=no FEATURES=%FEATURE% || exit 1
|
||||
.\vim -u NONE -c "redir @a | ver |0put a | wq" ver_ming.txt
|
||||
:: Save vim.exe before Make clean, moved back below.
|
||||
copy vim.exe testdir
|
||||
mingw32-make.exe -f Make_ming.mak clean
|
||||
@ -20,13 +21,14 @@ if "%FEATURE%" == "HUGE" (
|
||||
) ELSE (
|
||||
mingw32-make.exe -f Make_ming.mak OPTIMIZE=speed GUI=yes IME=yes ICONV=yes DEBUG=no FEATURES=%FEATURE% || exit 1
|
||||
)
|
||||
.\gvim -u NONE -c "redir @a | ver |0put a | wq" ver_ming.txt
|
||||
.\gvim -u NONE -c "redir @a | ver |0put a | wq" ver_ming_gui.txt
|
||||
|
||||
:: Filter out the progress bar from the build log
|
||||
sed -e "s/@<<$/@<< | sed -e 's#.*\\\\r.*##'/" Make_mvc.mak > Make_mvc2.mak
|
||||
|
||||
echo "Building MSVC 64bit console Version"
|
||||
nmake -f Make_mvc2.mak CPU=AMD64 OLE=no GUI=no IME=yes ICONV=yes DEBUG=no FEATURES=%FEATURE% || exit 1
|
||||
:: The executable is not used
|
||||
nmake -f Make_mvc2.mak clean
|
||||
|
||||
:: build MSVC huge version with python and channel support
|
||||
@ -43,6 +45,8 @@ if "%FEATURE%" == "HUGE" (
|
||||
move /Y testdir\vim.exe .
|
||||
echo "version output MinGW"
|
||||
type ver_ming.txt
|
||||
echo "version output MinGW GUI"
|
||||
type ver_ming_gui.txt
|
||||
echo "version output MVC"
|
||||
type ver_msvc.txt
|
||||
cd ..
|
||||
|
@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 8.2. Last change: 2020 Jun 14
|
||||
*eval.txt* For Vim version 8.2. Last change: 2020 Jun 17
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -3667,7 +3667,7 @@ complete_info([{what}])
|
||||
"function" User defined completion |i_CTRL-X_CTRL-U|
|
||||
"omni" Omni completion |i_CTRL-X_CTRL-O|
|
||||
"spell" Spelling suggestions |i_CTRL-X_s|
|
||||
"eval" |complete()| completion
|
||||
"eval" |complete()| completion
|
||||
"unknown" Other internal modes
|
||||
|
||||
If the optional {what} list argument is supplied, then only
|
||||
@ -4536,7 +4536,7 @@ flatten({list} [, {maxdepth}]) *flatten()*
|
||||
a very large number.
|
||||
The {list} is changed in place, make a copy first if you do
|
||||
not want that.
|
||||
*E900*
|
||||
*E900*
|
||||
{maxdepth} means how deep in nested lists changes are made.
|
||||
{list} is not modified when {maxdepth} is 0.
|
||||
{maxdepth} must be positive number.
|
||||
@ -5163,7 +5163,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
|
||||
highlight highlight groups
|
||||
history :history suboptions
|
||||
locale locale names (as output of locale -a)
|
||||
mapclear buffer argument
|
||||
mapclear buffer argument
|
||||
mapping mapping name
|
||||
menu menus
|
||||
messages |:messages| suboptions
|
||||
@ -5189,7 +5189,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
|
||||
If {type} is "cmdline", then the |cmdline-completion| result is
|
||||
returned. For example, to complete the possible values after
|
||||
a ":call" command: >
|
||||
echo getcompletion('call ', 'cmdline')
|
||||
echo getcompletion('call ', 'cmdline')
|
||||
<
|
||||
If there are no matches, an empty list is returned. An
|
||||
invalid value for {type} produces an error.
|
||||
@ -5770,8 +5770,8 @@ getwininfo([{winid}]) *getwininfo()*
|
||||
Returns information about windows as a List with Dictionaries.
|
||||
|
||||
If {winid} is given Information about the window with that ID
|
||||
is returned. If the window does not exist the result is an
|
||||
empty list.
|
||||
is returned, as a List with one item. If the window does not
|
||||
exist the result is an empty list.
|
||||
|
||||
Without {winid} information about all the windows in all the
|
||||
tab pages is returned.
|
||||
@ -8606,14 +8606,14 @@ searchcount([{options}]) *searchcount()*
|
||||
if result.total > result.maxcount &&
|
||||
\ result.current > result.maxcount
|
||||
return printf(' /%s [>%d/>%d]', @/,
|
||||
\ result.current, result.total)
|
||||
\ result.current, result.total)
|
||||
elseif result.total > result.maxcount
|
||||
return printf(' /%s [%d/>%d]', @/,
|
||||
\ result.current, result.total)
|
||||
\ result.current, result.total)
|
||||
endif
|
||||
endif
|
||||
return printf(' /%s [%d/%d]', @/,
|
||||
\ result.current, result.total)
|
||||
\ result.current, result.total)
|
||||
endfunction
|
||||
let &statusline .= '%{LastSearchCount()}'
|
||||
|
||||
@ -9386,7 +9386,9 @@ simplify({filename}) *simplify()*
|
||||
Unix) are not resolved. If the first path component in
|
||||
{filename} designates the current directory, this will be
|
||||
valid for the result as well. A trailing path separator is
|
||||
not removed either.
|
||||
not removed either. On Unix "//path" is unchanged, but
|
||||
"///path" is simplified to "/path" (this follows the Posix
|
||||
standard).
|
||||
Example: >
|
||||
simplify("./dir/.././/file/") == "./file/"
|
||||
< Note: The combination "dir/.." is only removed if "dir" is
|
||||
@ -9696,7 +9698,7 @@ state([{what}]) *state()*
|
||||
m halfway a mapping, :normal command, feedkeys() or
|
||||
stuffed command
|
||||
o operator pending or waiting for a command argument,
|
||||
e.g. after |f|
|
||||
e.g. after |f|
|
||||
a Insert mode autocomplete active
|
||||
x executing an autocommand
|
||||
w blocked on waiting, e.g. ch_evalexpr(), ch_read() and
|
||||
@ -10450,9 +10452,9 @@ terminalprops() *terminalprops()*
|
||||
If the |+termresponse| feature is missing then the result is
|
||||
an empty dictionary.
|
||||
|
||||
If "cursor_style" is 'y' then |t_RS| will be send to request the
|
||||
If "cursor_style" is 'y' then |t_RS| will be sent to request the
|
||||
current cursor style.
|
||||
If "cursor_blink_mode" is 'y' then |t_RC| will be send to
|
||||
If "cursor_blink_mode" is 'y' then |t_RC| will be sent to
|
||||
request the cursor blink status.
|
||||
"cursor_style" and "cursor_blink_mode" are also set if |t_u7|
|
||||
is not empty, Vim will detect the working of sending |t_RS|
|
||||
@ -10864,7 +10866,7 @@ win_getid([{win} [, {tab}]]) *win_getid()*
|
||||
|
||||
win_gettype([{nr}]) *win_gettype()*
|
||||
Return the type of the window:
|
||||
"aucmdwin" autocommand window. Temporary window
|
||||
"autocmd" autocommand window. Temporary window
|
||||
used to execute autocommands.
|
||||
"popup" popup window |popup|
|
||||
"preview" preview window |preview-window|
|
||||
@ -10916,7 +10918,7 @@ win_screenpos({nr}) *win_screenpos()*
|
||||
GetWinid()->win_screenpos()
|
||||
<
|
||||
win_splitmove({nr}, {target} [, {options}]) *win_splitmove()*
|
||||
Move the window {nr} to a new split of the window {target}.
|
||||
Move the window {nr} to a new split of the window {target}.
|
||||
This is similar to moving to {target}, creating a new window
|
||||
using |:split| but having the same contents as window {nr}, and
|
||||
then closing {nr}.
|
||||
|
@ -1,4 +1,4 @@
|
||||
*mlang.txt* For Vim version 8.2. Last change: 2019 May 05
|
||||
*mlang.txt* For Vim version 8.2. Last change: 2020 Jun 16
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
|
@ -163,6 +163,11 @@ q Stops recording. (Implementation note: The 'q' that
|
||||
result of evaluating the expression is executed as an
|
||||
Ex command.
|
||||
Mappings are not recognized in these commands.
|
||||
When the |line-continuation| character (\) is present
|
||||
at the beginning of a line in a linewise register,
|
||||
then it is combined with the previous line. This is
|
||||
useful for yanking and executing parts of a Vim
|
||||
script.
|
||||
Future: Will execute the register for each line in the
|
||||
address range.
|
||||
|
||||
|
@ -3897,6 +3897,7 @@ E105 mbyte.txt /*E105*
|
||||
E107 eval.txt /*E107*
|
||||
E108 eval.txt /*E108*
|
||||
E109 eval.txt /*E109*
|
||||
E1094 vim9.txt /*E1094*
|
||||
E11 cmdline.txt /*E11*
|
||||
E110 eval.txt /*E110*
|
||||
E111 eval.txt /*E111*
|
||||
@ -5798,6 +5799,7 @@ coding-style develop.txt /*coding-style*
|
||||
col() eval.txt /*col()*
|
||||
coldfusion.vim syntax.txt /*coldfusion.vim*
|
||||
collapse tips.txt /*collapse*
|
||||
collate-variable eval.txt /*collate-variable*
|
||||
color-xterm syntax.txt /*color-xterm*
|
||||
coloring syntax.txt /*coloring*
|
||||
colortest.vim syntax.txt /*colortest.vim*
|
||||
@ -9723,6 +9725,7 @@ v:charconvert_from eval.txt /*v:charconvert_from*
|
||||
v:charconvert_to eval.txt /*v:charconvert_to*
|
||||
v:cmdarg eval.txt /*v:cmdarg*
|
||||
v:cmdbang eval.txt /*v:cmdbang*
|
||||
v:collate eval.txt /*v:collate*
|
||||
v:completed_item eval.txt /*v:completed_item*
|
||||
v:count eval.txt /*v:count*
|
||||
v:count1 eval.txt /*v:count1*
|
||||
|
@ -1,4 +1,4 @@
|
||||
*testing.txt* For Vim version 8.2. Last change: 2020 Jun 13
|
||||
*testing.txt* For Vim version 8.2. Last change: 2020 Jun 15
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
|
@ -1,4 +1,4 @@
|
||||
*todo.txt* For Vim version 8.2. Last change: 2020 Jun 14
|
||||
*todo.txt* For Vim version 8.2. Last change: 2020 Jun 21
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -40,16 +40,16 @@ browser use: https://github.com/vim/vim/issues/1234
|
||||
|
||||
Include src/po/vim.pot ?
|
||||
|
||||
See if resizing a terminal can be fixed.
|
||||
|
||||
Vim9 script:
|
||||
Making everything work:
|
||||
- assignment to script var should check type
|
||||
- Compile: let [var, var] = expr
|
||||
share code for :let between compiled and uncompiled?
|
||||
- do not allow "let g:var = value", must drop "let"
|
||||
- Error for "g:var: string = 'value'"
|
||||
- Make func()->append('$') work - value is last argument, not first. #6305
|
||||
- possible memory leak in test_vim9_func through compile_nested_function.
|
||||
- memory leaks in test_vim9_expr
|
||||
- memory leaks in test_vim9_script
|
||||
- Test that a script-local function in Vim9 script cannot be deleted.
|
||||
- more return types depending on the first argument, like sort().
|
||||
- Check that when sourcing a Vim9 script, only the global items can be used.
|
||||
- Make "true" and "false" work in vim9script
|
||||
- Test that a function defined inside a :def function is local to that
|
||||
@ -240,10 +240,12 @@ Terminal emulator window:
|
||||
conversions.
|
||||
|
||||
Error numbers available:
|
||||
E489, E610, E611, E653, E856, E857, E861
|
||||
E489, E610, E611, E653, E856
|
||||
|
||||
Remove SPACE_IN_FILENAME ? It is only used for completion.
|
||||
|
||||
Patch to use collaction based sorting. (Christian Brabandt, #6229)
|
||||
|
||||
Can we detect true color support? https://gist.github.com/XVilka/8346728
|
||||
Try setting a color then request the current color, like using t_u7.
|
||||
|
||||
@ -272,6 +274,8 @@ The buffer list and windows are locked, no changes possible
|
||||
How about removing Atari MiNT support?
|
||||
src/Make_mint.mak, src/os_mint.h, matches with __MINT__
|
||||
|
||||
Patch to make :q work with local arglist. (Christian Brabandt, #6286)
|
||||
|
||||
Patch to fix drawing error with DirectX. (James Grant, #5688)
|
||||
Causes flicker on resizing. Workaround from Ken Takata.
|
||||
How about only setting the attribute when part of the Vim window is offscreen?
|
||||
@ -285,6 +289,8 @@ Motif: Build on Ubuntu can't enter any text in dialog text fields.
|
||||
Running test_gui and test_gui_init with Motif sometimes kills the window
|
||||
manager. Problem with Motif?
|
||||
|
||||
Patch to add :argdedupe. (Nir Lichtman, #6235)
|
||||
|
||||
:map output does not clear the reset of the command line.
|
||||
(#5623, also see #5962)
|
||||
|
||||
@ -1402,9 +1408,6 @@ the system encoding (usually utf-8).
|
||||
MS-Windows: use WS_HIDE instead of SW_SHOWMINNOACTIVE in os_win32.c?
|
||||
Otherwise task flickers in taskbar.
|
||||
|
||||
Should make ":@r" handle line continuation. (Cesar Romani, 2016 Jun 26)
|
||||
Also for ":@.".
|
||||
|
||||
Repeating 'opfunc' in a function only works once. (Tarmean, 2016 Jul 15, #925)
|
||||
|
||||
Have a way to get the call stack, in a function and from an exception.
|
||||
|
@ -211,7 +211,7 @@ will automatically delete it:
|
||||
- The flag that the file was modified is not set.
|
||||
- The process is not running.
|
||||
|
||||
You can programatically deal with this situation with the |FileChangedShell|
|
||||
You can programmatically deal with this situation with the |FileChangedShell|
|
||||
autocommand event.
|
||||
|
||||
|
||||
|
@ -112,7 +112,7 @@ Although it's shorter to do: >
|
||||
|
||||
Legacy Vim script does have type checking, but this happens at runtime, when
|
||||
the code is executed. And it's permissive, often a computation gives an
|
||||
unexpected value instead of reporting an error . Thus you can define a
|
||||
unexpected value instead of reporting an error. Thus you can define a
|
||||
function and think it's fine, but see a problem only later when it is called: >
|
||||
let s:collected = ''
|
||||
func ExtendAndReturn(add)
|
||||
@ -142,7 +142,7 @@ you did wrong: >
|
||||
|
||||
Vim9 script is strict, it uses the "+" operator only for numbers and floats.
|
||||
For string concatenation ".." must be used. This avoids mistakes and avoids
|
||||
the automatic conversion that gave a suprising result above. So you change
|
||||
the automatic conversion that gave a surprising result above. So you change
|
||||
the first line of the function to: >
|
||||
s:collected ..= add
|
||||
And now it works.
|
||||
|
@ -1,4 +1,4 @@
|
||||
*usr_toc.txt* For Vim version 8.2. Last change: 2020 Jun 11
|
||||
*usr_toc.txt* For Vim version 8.2. Last change: 2020 Jun 15
|
||||
|
||||
VIM USER MANUAL - by Bram Moolenaar
|
||||
|
||||
@ -340,6 +340,12 @@ Make Vim work as you like it.
|
||||
|45.4| Editing files with a different encoding
|
||||
|45.5| Entering language text
|
||||
|
||||
|usr_46.txt| Write plugins using Vim9 script
|
||||
|46.1| Introduction
|
||||
|46.2| Variable declarations
|
||||
|46.3| Functions and types
|
||||
|46.?| Using a Vim9 script from legacy script
|
||||
|
||||
==============================================================================
|
||||
Making Vim Run ~
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
*vim9.txt* For Vim version 8.2. Last change: 2020 Jun 14
|
||||
*vim9.txt* For Vim version 8.2. Last change: 2020 Jun 21
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -30,7 +30,7 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
|
||||
|
||||
Vim script has been growing over time, while preserving backwards
|
||||
compatibility. That means bad choices from the past often can't be changed
|
||||
and compability with Vi restricts possible solutions. Execution is quite
|
||||
and compatibility with Vi restricts possible solutions. Execution is quite
|
||||
slow, each line is parsed every time it is executed.
|
||||
|
||||
The main goal of Vim9 script is to drastically improve performance. This is
|
||||
@ -68,7 +68,7 @@ In Vim script comments normally start with double quote. That can also be the
|
||||
start of a string, thus in many places it cannot be used. In Vim9 script a
|
||||
comment can also start with #. In Vi this is a command to list text with
|
||||
numbers, but you can also use `:number` for that. >
|
||||
let count = 0 # number of occurences
|
||||
let count = 0 # number of occurrences
|
||||
|
||||
To improve readability there must be a space between the command and the #
|
||||
that starts a comment. Note that #{ is the start of a dictionary, therefore
|
||||
@ -269,6 +269,13 @@ possible AFTER the operators. For example: >
|
||||
PosFunc(arg) :
|
||||
NegFunc(arg)
|
||||
|
||||
A special case is "->" for function call chains, it can appear in the next
|
||||
line: >
|
||||
let result = GetBuilder()
|
||||
->BuilderSetWidth(333)
|
||||
->BuilderSetHeight(777)
|
||||
->BuilderBuild()
|
||||
|
||||
Note that "enddef" cannot be used at the start of a continuation line, it ends
|
||||
the current function.
|
||||
|
||||
@ -566,7 +573,7 @@ defined (otherwise script-local) items: >
|
||||
|
||||
|
||||
Import ~
|
||||
*:import* *:imp*
|
||||
*:import* *:imp* *E1094*
|
||||
The exported items can be imported individually in another Vim9 script: >
|
||||
import EXPORTED_CONST from "thatscript.vim"
|
||||
import MyClass from "myclass.vim"
|
||||
@ -692,7 +699,7 @@ A, B and C, where A calls B, B calls C, and C calls A again. It's impossible
|
||||
to reorder the functions to avoid forward references.
|
||||
|
||||
An alternative would be to first scan through the file to locate items and
|
||||
figure out their type, so that forward refeferences are found, and only then
|
||||
figure out their type, so that forward references are found, and only then
|
||||
execute the script and compile the functions. This means the script has to be
|
||||
parsed twice, which is slower, and some conditions at the script level, such
|
||||
as checking if a feature is supported, are hard to use. An attempt was made
|
||||
|
@ -1,7 +1,7 @@
|
||||
" Vim support file to detect file types
|
||||
"
|
||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
" Last Change: 2020 Jun 07
|
||||
" Last Change: 2020 Jun 15
|
||||
|
||||
" Listen very carefully, I will say this only once
|
||||
if exists("did_load_filetypes")
|
||||
@ -237,7 +237,7 @@ au BufNewFile,BufRead */etc/blkid.tab,*/etc/blkid.tab.old setf xml
|
||||
au BufNewFile,BufRead *bsd,*.bsdl setf bsdl
|
||||
|
||||
" Bazel (http://bazel.io)
|
||||
autocmd BufRead,BufNewFile *.bzl,WORKSPACE,BUILD.bazel setf bzl
|
||||
autocmd BufRead,BufNewFile *.bzl,WORKSPACE,BUILD.bazel setf bzl
|
||||
if has("fname_case")
|
||||
" There is another check for BUILD further below.
|
||||
autocmd BufRead,BufNewFile BUILD setf bzl
|
||||
@ -625,8 +625,8 @@ au BufNewFile,BufRead *.mo,*.gdmo setf gdmo
|
||||
au BufNewFile,BufRead *.ged,lltxxxxx.txt setf gedcom
|
||||
|
||||
" Git
|
||||
au BufNewFile,BufRead COMMIT_EDITMSG,MERGE_MSG,TAG_EDITMSG setf gitcommit
|
||||
au BufNewFile,BufRead *.git/config,.gitconfig,/etc/gitconfig setf gitconfig
|
||||
au BufNewFile,BufRead COMMIT_EDITMSG,MERGE_MSG,TAG_EDITMSG setf gitcommit
|
||||
au BufNewFile,BufRead *.git/config,.gitconfig,/etc/gitconfig setf gitconfig
|
||||
au BufNewFile,BufRead */.config/git/config setf gitconfig
|
||||
au BufNewFile,BufRead .gitmodules,*.git/modules/*/config setf gitconfig
|
||||
if !empty($XDG_CONFIG_HOME)
|
||||
@ -770,11 +770,11 @@ au BufNewFile,BufRead *.inf,*.INF setf inform
|
||||
au BufNewFile,BufRead */etc/initng/*/*.i,*.ii setf initng
|
||||
|
||||
" Innovation Data Processing
|
||||
au BufRead,BufNewFile upstream.dat\c,upstream.*.dat\c,*.upstream.dat\c setf upstreamdat
|
||||
au BufRead,BufNewFile fdrupstream.log,upstream.log\c,upstream.*.log\c,*.upstream.log\c,UPSTREAM-*.log\c setf upstreamlog
|
||||
au BufRead,BufNewFile upstream.dat\c,upstream.*.dat\c,*.upstream.dat\c setf upstreamdat
|
||||
au BufRead,BufNewFile fdrupstream.log,upstream.log\c,upstream.*.log\c,*.upstream.log\c,UPSTREAM-*.log\c setf upstreamlog
|
||||
au BufRead,BufNewFile upstreaminstall.log\c,upstreaminstall.*.log\c,*.upstreaminstall.log\c setf upstreaminstalllog
|
||||
au BufRead,BufNewFile usserver.log\c,usserver.*.log\c,*.usserver.log\c setf usserverlog
|
||||
au BufRead,BufNewFile usw2kagt.log\c,usw2kagt.*.log\c,*.usw2kagt.log\c setf usw2kagtlog
|
||||
au BufRead,BufNewFile usserver.log\c,usserver.*.log\c,*.usserver.log\c setf usserverlog
|
||||
au BufRead,BufNewFile usw2kagt.log\c,usw2kagt.*.log\c,*.usw2kagt.log\c setf usw2kagtlog
|
||||
|
||||
" Ipfilter
|
||||
au BufNewFile,BufRead ipf.conf,ipf6.conf,ipf.rules setf ipfilter
|
||||
@ -1073,7 +1073,7 @@ au BufNewFile,BufRead Mutt{ng,}rc setf muttrc
|
||||
au BufRead,BufNewfile *.n1ql,*.nql setf n1ql
|
||||
|
||||
" Nano
|
||||
au BufNewFile,BufRead */etc/nanorc,*.nanorc setf nanorc
|
||||
au BufNewFile,BufRead */etc/nanorc,*.nanorc setf nanorc
|
||||
|
||||
" Nastran input/DMAP
|
||||
"au BufNewFile,BufRead *.dat setf nastran
|
||||
@ -1156,7 +1156,7 @@ au BufNewFile,BufRead *.dpr setf pascal
|
||||
au BufNewFile,BufRead *.pdf setf pdf
|
||||
|
||||
" PCMK - HAE - crm configure edit
|
||||
au BufNewFile,BufRead *.pcmk setf pcmk
|
||||
au BufNewFile,BufRead *.pcmk setf pcmk
|
||||
|
||||
" Perl
|
||||
if has("fname_case")
|
||||
@ -1646,10 +1646,10 @@ au BufNewFile,BufRead *.cm setf voscm
|
||||
|
||||
" Swift
|
||||
au BufNewFile,BufRead *.swift setf swift
|
||||
au BufNewFile,BufRead *.swift.gyb setf swiftgyb
|
||||
au BufNewFile,BufRead *.swift.gyb setf swiftgyb
|
||||
|
||||
" Swift Intermediate Language
|
||||
au BufNewFile,BufRead *.sil setf sil
|
||||
au BufNewFile,BufRead *.sil setf sil
|
||||
|
||||
" Sysctl
|
||||
au BufNewFile,BufRead */etc/sysctl.conf,*/etc/sysctl.d/*.conf setf sysctl
|
||||
@ -2066,7 +2066,7 @@ au BufNewFile,BufRead *fvwm2rc*
|
||||
au BufNewFile,BufRead */tmp/lltmp* call s:StarSetf('gedcom')
|
||||
|
||||
" Git
|
||||
au BufNewFile,BufRead */.gitconfig.d/*,/etc/gitconfig.d/* call s:StarSetf('gitconfig')
|
||||
au BufNewFile,BufRead */.gitconfig.d/*,/etc/gitconfig.d/* call s:StarSetf('gitconfig')
|
||||
|
||||
" Gitolite
|
||||
au BufNewFile,BufRead */gitolite-admin/conf/* call s:StarSetf('gitolite')
|
||||
|
@ -1,7 +1,7 @@
|
||||
" Vim filetype plugin
|
||||
" Language: Vim
|
||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
" Last Change: 2020 May 17
|
||||
" Last Change: 2020 Jun 16
|
||||
|
||||
" Only do this when not done yet for this buffer
|
||||
if exists("b:did_ftplugin")
|
||||
@ -83,8 +83,7 @@ endif
|
||||
if exists("loaded_matchit")
|
||||
let b:match_ignorecase = 0
|
||||
let b:match_words =
|
||||
\ '\<fu\%[nction]\>:\<retu\%[rn]\>:\<endf\%[unction]\>,' .
|
||||
\ '\<def\>:\<retu\%[rn]\>:\<enddef\>,' .
|
||||
\ '\<\%(fu\%[nction]\|def\)\>:\<retu\%[rn]\>:\<\%(endf\%[unction]\|enddef\)\>,' .
|
||||
\ '\<\(wh\%[ile]\|for\)\>:\<brea\%[k]\>:\<con\%[tinue]\>:\<end\(w\%[hile]\|fo\%[r]\)\>,' .
|
||||
\ '\<if\>:\<el\%[seif]\>:\<en\%[dif]\>,' .
|
||||
\ '{:},' .
|
||||
|
@ -2,7 +2,7 @@
|
||||
" Header: "{{{
|
||||
" Maintainer: Bram Moolenaar
|
||||
" Original Author: Andy Wokula <anwoku@yahoo.de>
|
||||
" Last Change: 2019 Mar 20
|
||||
" Last Change: 2020 Jun 18
|
||||
" Version: 1.0
|
||||
" Description: HTML indent script with cached state for faster indenting on a
|
||||
" range of lines.
|
||||
@ -223,7 +223,7 @@ endfunc "}}}
|
||||
call s:AddITags(s:indent_tags, [
|
||||
\ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big',
|
||||
\ 'blockquote', 'body', 'button', 'caption', 'center', 'cite', 'code',
|
||||
\ 'colgroup', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font',
|
||||
\ 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'fieldset', 'font',
|
||||
\ 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html',
|
||||
\ 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li',
|
||||
\ 'map', 'menu', 'noframes', 'noscript', 'object', 'ol',
|
||||
|
@ -23,4 +23,14 @@ bar">
|
||||
text
|
||||
</div>
|
||||
|
||||
<dl>
|
||||
<dd>
|
||||
dd text
|
||||
</dd>
|
||||
<dt>
|
||||
dt text
|
||||
</dt>
|
||||
</dl>
|
||||
|
||||
|
||||
" END_INDENT
|
||||
|
@ -23,4 +23,14 @@
|
||||
text
|
||||
</div>
|
||||
|
||||
<dl>
|
||||
<dd>
|
||||
dd text
|
||||
</dd>
|
||||
<dt>
|
||||
dt text
|
||||
</dt>
|
||||
</dl>
|
||||
|
||||
|
||||
" END_INDENT
|
||||
|
@ -1,6 +1,6 @@
|
||||
" Vim plugin for showing matching parens
|
||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
" Last Change: 2019 Oct 28
|
||||
" Last Change: 2020 Jun 18
|
||||
|
||||
" Exit quickly when:
|
||||
" - this plugin was already loaded (or disabled)
|
||||
@ -21,6 +21,7 @@ endif
|
||||
augroup matchparen
|
||||
" Replace all matchparen autocommands
|
||||
autocmd! CursorMoved,CursorMovedI,WinEnter * call s:Highlight_Matching_Pair()
|
||||
autocmd! WinLeave * call s:Remove_Matches()
|
||||
if exists('##TextChanged')
|
||||
autocmd! TextChanged,TextChangedI * call s:Highlight_Matching_Pair()
|
||||
endif
|
||||
@ -38,10 +39,7 @@ set cpo-=C
|
||||
" for any matching paren.
|
||||
func s:Highlight_Matching_Pair()
|
||||
" Remove any previous match.
|
||||
if exists('w:paren_hl_on') && w:paren_hl_on
|
||||
silent! call matchdelete(3)
|
||||
let w:paren_hl_on = 0
|
||||
endif
|
||||
call s:Remove_Matches()
|
||||
|
||||
" Avoid that we remove the popup menu.
|
||||
" Return when there are no colors (looks like the cursor jumps).
|
||||
@ -195,6 +193,14 @@ func s:Highlight_Matching_Pair()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
func s:Remove_Matches()
|
||||
if exists('w:paren_hl_on') && w:paren_hl_on
|
||||
silent! call matchdelete(3)
|
||||
let w:paren_hl_on = 0
|
||||
endif
|
||||
endfunc
|
||||
|
||||
|
||||
" Define commands that will disable and enable the plugin.
|
||||
command DoMatchParen call s:DoMatchParen()
|
||||
command NoMatchParen call s:NoMatchParen()
|
||||
|
@ -1146,6 +1146,15 @@ set_one_cmd_context(
|
||||
arg = skipwhite(arg);
|
||||
}
|
||||
|
||||
// Skip over ++argopt argument
|
||||
if ((ea.argt & EX_ARGOPT) && *arg != NUL && STRNCMP(arg, "++", 2) == 0)
|
||||
{
|
||||
p = arg;
|
||||
while (*p && !vim_isspace(*p))
|
||||
MB_PTR_ADV(p);
|
||||
arg = skipwhite(p);
|
||||
}
|
||||
|
||||
// Check for '|' to separate commands and '"' to start comments.
|
||||
// Don't do this for ":read !cmd" and ":write !cmd".
|
||||
if ((ea.argt & EX_TRLBAR) && !usefilter)
|
||||
|
@ -1287,13 +1287,13 @@ win_line(
|
||||
// When still displaying '$' of change command, stop at cursor.
|
||||
// When only displaying the (relative) line number and that's done,
|
||||
// stop here.
|
||||
if ((dollar_vcol >= 0 && wp == curwin
|
||||
&& lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
|
||||
if (((dollar_vcol >= 0 && wp == curwin
|
||||
&& lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol)
|
||||
|| (number_only && draw_state > WL_NR))
|
||||
#ifdef FEAT_DIFF
|
||||
&& filler_todo <= 0
|
||||
#endif
|
||||
)
|
||||
|| (number_only && draw_state > WL_NR))
|
||||
{
|
||||
screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
|
||||
screen_line_flags);
|
||||
|
@ -253,7 +253,7 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
|
||||
return FAIL;
|
||||
|
||||
if (partial->pt_func != NULL
|
||||
&& partial->pt_func->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
&& partial->pt_func->uf_def_status != UF_NOT_COMPILED)
|
||||
{
|
||||
if (call_def_function(partial->pt_func, argc, argv,
|
||||
partial, rettv) == FAIL)
|
||||
|
107
src/evalfunc.c
107
src/evalfunc.c
@ -339,6 +339,14 @@ ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
|
||||
return &t_job;
|
||||
}
|
||||
|
||||
static type_T *
|
||||
ret_first_arg(int argcount, type_T **argtypes)
|
||||
{
|
||||
if (argcount > 0)
|
||||
return argtypes[0];
|
||||
return &t_void;
|
||||
}
|
||||
|
||||
static type_T *ret_f_function(int argcount, type_T **argtypes);
|
||||
|
||||
/*
|
||||
@ -849,7 +857,7 @@ static funcentry_T global_functions[] =
|
||||
{"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
|
||||
{"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
|
||||
{"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
|
||||
{"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
|
||||
{"sort", 1, 3, FEARG_1, ret_first_arg, f_sort},
|
||||
{"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
|
||||
{"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
|
||||
{"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
|
||||
@ -5994,11 +6002,11 @@ static int srand_seed_for_testing_is_used = FALSE;
|
||||
f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_UNKNOWN)
|
||||
srand_seed_for_testing_is_used = FALSE;
|
||||
srand_seed_for_testing_is_used = FALSE;
|
||||
else
|
||||
{
|
||||
srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
|
||||
srand_seed_for_testing_is_used = TRUE;
|
||||
srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
|
||||
srand_seed_for_testing_is_used = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6011,7 +6019,7 @@ init_srand(UINT32_T *x)
|
||||
|
||||
if (srand_seed_for_testing_is_used)
|
||||
{
|
||||
*x = srand_seed_for_testing;
|
||||
*x = srand_seed_for_testing;
|
||||
return;
|
||||
}
|
||||
#ifndef MSWIN
|
||||
@ -7260,6 +7268,37 @@ f_setpos(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a register type string to the yank type and block length
|
||||
*/
|
||||
static int
|
||||
get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
|
||||
{
|
||||
char_u *stropt = *pp;
|
||||
switch (*stropt)
|
||||
{
|
||||
case 'v': case 'c': // character-wise selection
|
||||
*yank_type = MCHAR;
|
||||
break;
|
||||
case 'V': case 'l': // line-wise selection
|
||||
*yank_type = MLINE;
|
||||
break;
|
||||
case 'b': case Ctrl_V: // block-wise selection
|
||||
*yank_type = MBLOCK;
|
||||
if (VIM_ISDIGIT(stropt[1]))
|
||||
{
|
||||
++stropt;
|
||||
*block_len = getdigits(&stropt) - 1;
|
||||
--stropt;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return FAIL;
|
||||
}
|
||||
*pp = stropt;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* "setreg()" function
|
||||
*/
|
||||
@ -7294,30 +7333,31 @@ f_setreg(typval_T *argvars, typval_T *rettv)
|
||||
if (argvars[1].v_type == VAR_DICT)
|
||||
{
|
||||
dict_T *d = argvars[1].vval.v_dict;
|
||||
dictitem_T *di = dict_find(d, (char_u *)"regcontents", -1);
|
||||
dictitem_T *di;
|
||||
|
||||
if (d == NULL || d->dv_hashtab.ht_used == 0)
|
||||
{
|
||||
// Empty dict, clear the register (like setreg(0, []))
|
||||
char_u *lstval[2] = {NULL, NULL};
|
||||
write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
di = dict_find(d, (char_u *)"regcontents", -1);
|
||||
if (di != NULL)
|
||||
regcontents = &di->di_tv;
|
||||
|
||||
stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
|
||||
if (stropt != NULL)
|
||||
switch (*stropt)
|
||||
{
|
||||
int ret = get_yank_type(&stropt, &yank_type, &block_len);
|
||||
|
||||
if (ret == FAIL || *++stropt != NUL)
|
||||
{
|
||||
case 'v': // character-wise selection
|
||||
yank_type = MCHAR;
|
||||
break;
|
||||
case 'V': // line-wise selection
|
||||
yank_type = MLINE;
|
||||
break;
|
||||
case Ctrl_V: // block-wise selection
|
||||
yank_type = MBLOCK;
|
||||
if (VIM_ISDIGIT(stropt[1]))
|
||||
{
|
||||
++stropt;
|
||||
block_len = getdigits(&stropt) - 1;
|
||||
--stropt;
|
||||
}
|
||||
break;
|
||||
semsg(_(e_invargval), "value");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (regname == '"')
|
||||
{
|
||||
@ -7336,6 +7376,12 @@ f_setreg(typval_T *argvars, typval_T *rettv)
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
if (yank_type != MAUTO)
|
||||
{
|
||||
semsg(_(e_toomanyarg), "setreg");
|
||||
return;
|
||||
}
|
||||
|
||||
stropt = tv_get_string_chk(&argvars[2]);
|
||||
if (stropt == NULL)
|
||||
return; // type error
|
||||
@ -7345,21 +7391,8 @@ f_setreg(typval_T *argvars, typval_T *rettv)
|
||||
case 'a': case 'A': // append
|
||||
append = TRUE;
|
||||
break;
|
||||
case 'v': case 'c': // character-wise selection
|
||||
yank_type = MCHAR;
|
||||
break;
|
||||
case 'V': case 'l': // line-wise selection
|
||||
yank_type = MLINE;
|
||||
break;
|
||||
case 'b': case Ctrl_V: // block-wise selection
|
||||
yank_type = MBLOCK;
|
||||
if (VIM_ISDIGIT(stropt[1]))
|
||||
{
|
||||
++stropt;
|
||||
block_len = getdigits(&stropt) - 1;
|
||||
--stropt;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
get_yank_type(&stropt, &yank_type, &block_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1204,6 +1204,13 @@ ex_let_one(
|
||||
emsg(_("E996: Cannot lock an environment variable"));
|
||||
return NULL;
|
||||
}
|
||||
if (current_sctx.sc_version == SCRIPT_VERSION_VIM9
|
||||
&& (flags & LET_NO_COMMAND) == 0)
|
||||
{
|
||||
vim9_declare_error(arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find the end of the name.
|
||||
++arg;
|
||||
name = arg;
|
||||
@ -2628,7 +2635,7 @@ find_var_ht(char_u *name, char_u **varname)
|
||||
if (*name == 'v') // v: variable
|
||||
return &vimvarht;
|
||||
if (get_current_funccal() != NULL
|
||||
&& get_current_funccal()->func->uf_dfunc_idx == UF_NOT_COMPILED)
|
||||
&& get_current_funccal()->func->uf_def_status == UF_NOT_COMPILED)
|
||||
{
|
||||
// a: and l: are only used in functions defined with ":function"
|
||||
if (*name == 'a') // a: function argument
|
||||
@ -2866,6 +2873,15 @@ set_var_const(
|
||||
}
|
||||
is_script_local = ht == get_script_local_ht();
|
||||
|
||||
if (current_sctx.sc_version == SCRIPT_VERSION_VIM9
|
||||
&& !is_script_local
|
||||
&& (flags & LET_NO_COMMAND) == 0
|
||||
&& name[1] == ':')
|
||||
{
|
||||
vim9_declare_error(name);
|
||||
return;
|
||||
}
|
||||
|
||||
di = find_var_in_ht(ht, 0, varname, TRUE);
|
||||
|
||||
// Search in parent scope which is possible to reference from lambda
|
||||
@ -2886,10 +2902,6 @@ set_var_const(
|
||||
return;
|
||||
}
|
||||
|
||||
if (var_check_ro(di->di_flags, name, FALSE)
|
||||
|| var_check_lock(di->di_tv.v_lock, name, FALSE))
|
||||
return;
|
||||
|
||||
if (is_script_local
|
||||
&& current_sctx.sc_version == SCRIPT_VERSION_VIM9)
|
||||
{
|
||||
@ -2900,8 +2912,13 @@ set_var_const(
|
||||
}
|
||||
|
||||
// check the type
|
||||
check_script_var_type(&di->di_tv, tv, name);
|
||||
if (check_script_var_type(&di->di_tv, tv, name) == FAIL)
|
||||
return;
|
||||
}
|
||||
|
||||
if (var_check_ro(di->di_flags, name, FALSE)
|
||||
|| var_check_lock(di->di_tv.v_lock, name, FALSE))
|
||||
return;
|
||||
}
|
||||
else
|
||||
// can only redefine once
|
||||
|
@ -859,7 +859,7 @@ f_win_gettype(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
}
|
||||
if (wp == aucmd_win)
|
||||
rettv->vval.v_string = vim_strsave((char_u *)"aucmdwin");
|
||||
rettv->vval.v_string = vim_strsave((char_u *)"autocmd");
|
||||
#if defined(FEAT_QUICKFIX)
|
||||
else if (wp->w_p_pvw)
|
||||
rettv->vval.v_string = vim_strsave((char_u *)"preview");
|
||||
|
@ -1895,7 +1895,7 @@ do_one_cmd(
|
||||
p = ea.cmd;
|
||||
while (ASCII_ISALNUM(*p))
|
||||
++p;
|
||||
p = vim_strnsave(ea.cmd, (int)(p - ea.cmd));
|
||||
p = vim_strnsave(ea.cmd, p - ea.cmd);
|
||||
ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, TRUE, NULL);
|
||||
vim_free(p);
|
||||
// If the autocommands did something and didn't cause an error, try
|
||||
@ -6215,6 +6215,7 @@ do_exedit(
|
||||
|| eap->cmdidx == CMD_view))
|
||||
{
|
||||
exmode_active = FALSE;
|
||||
ex_pressedreturn = FALSE;
|
||||
if (*eap->arg == NUL)
|
||||
{
|
||||
// Special case: ":global/pat/visual\NLvi-commands"
|
||||
|
@ -1788,6 +1788,8 @@ EXTERN char e_no_white_before[] INIT(= N_("E1068: No white space allowed before
|
||||
EXTERN char e_lock_unlock[] INIT(= N_("E940: Cannot lock or unlock variable %s"));
|
||||
EXTERN char e_const_req_value[] INIT(= N_("E1021: const requires a value"));
|
||||
EXTERN char e_type_req[] INIT(= N_("E1022: type or initialization required"));
|
||||
EXTERN char e_declare_var[] INIT(= N_("E1016: Cannot declare a %s variable: %s"));
|
||||
EXTERN char e_declare_env_var[] INIT(= N_("E1016: Cannot declare an environment variable: %s"));
|
||||
#endif
|
||||
#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
|
||||
EXTERN char e_alloc_color[] INIT(= N_("E254: Cannot allocate color %s"));
|
||||
|
@ -1211,15 +1211,19 @@ key_press_event(GtkWidget *widget UNUSED,
|
||||
if (len == 0) // Unrecognized key
|
||||
return TRUE;
|
||||
|
||||
// Handle modifiers.
|
||||
modifiers = modifiers_gdk2vim(state);
|
||||
|
||||
// For some keys a shift modifier is translated into another key code.
|
||||
if (len == -3)
|
||||
key = TO_SPECIAL(string[1], string[2]);
|
||||
else
|
||||
key = string[0];
|
||||
{
|
||||
string[len] = NUL;
|
||||
key = mb_ptr2char(string);
|
||||
}
|
||||
|
||||
// Handle modifiers.
|
||||
modifiers = modifiers_gdk2vim(state);
|
||||
|
||||
// Recognize special keys.
|
||||
key = simplify_key(key, &modifiers);
|
||||
if (key == CSI)
|
||||
key = K_CSI;
|
||||
@ -1235,8 +1239,11 @@ key_press_event(GtkWidget *widget UNUSED,
|
||||
// <C-H> and <C-h> mean the same thing, always use "H"
|
||||
if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
|
||||
key = TOUPPER_ASC(key);
|
||||
string[0] = key;
|
||||
len = 1;
|
||||
|
||||
// May remove the shift modifier if it's included in the key.
|
||||
modifiers = may_remove_shift_modifier(modifiers, key);
|
||||
|
||||
len = mb_char2bytes(key, string);
|
||||
}
|
||||
|
||||
if (modifiers != 0)
|
||||
|
@ -938,7 +938,10 @@ gui_x11_key_hit_cb(
|
||||
if (len == -3)
|
||||
key = TO_SPECIAL(string[1], string[2]);
|
||||
else
|
||||
key = string[0];
|
||||
{
|
||||
string[len] = NUL;
|
||||
key = mb_ptr2char(string);
|
||||
}
|
||||
key = simplify_key(key, &modifiers);
|
||||
if (key == CSI)
|
||||
key = K_CSI;
|
||||
@ -951,8 +954,7 @@ gui_x11_key_hit_cb(
|
||||
}
|
||||
else
|
||||
{
|
||||
string[0] = key;
|
||||
len = 1;
|
||||
len = mb_char2bytes(key, string);
|
||||
|
||||
// Remove the SHIFT modifier for keys where it's already included,
|
||||
// e.g., '(', '!' and '*'.
|
||||
|
@ -658,6 +658,11 @@ S_SvREFCNT_dec(pTHX_ SV *sv)
|
||||
}
|
||||
# endif
|
||||
|
||||
/* perl-5.32 needs Perl_SvREFCNT_dec */
|
||||
# if (PERL_REVISION == 5) && (PERL_VERSION >= 32)
|
||||
# define Perl_SvREFCNT_dec S_SvREFCNT_dec
|
||||
# endif
|
||||
|
||||
/* perl-5.26 also needs S_TOPMARK and S_POPMARK. */
|
||||
# if (PERL_REVISION == 5) && (PERL_VERSION >= 26)
|
||||
PERL_STATIC_INLINE I32
|
||||
@ -682,6 +687,20 @@ S_POPMARK(pTHX)
|
||||
}
|
||||
# endif
|
||||
|
||||
/* perl-5.32 needs Perl_POPMARK */
|
||||
# if (PERL_REVISION == 5) && (PERL_VERSION >= 32)
|
||||
# define Perl_POPMARK S_POPMARK
|
||||
|
||||
/* perl-5.32 needs Perl_SvTRUE */
|
||||
PERL_STATIC_INLINE bool
|
||||
Perl_SvTRUE(pTHX_ SV *sv) {
|
||||
if (!LIKELY(sv))
|
||||
return FALSE;
|
||||
SvGETMAGIC(sv);
|
||||
return SvTRUE_nomg_NN(sv);
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Make all runtime-links of perl.
|
||||
*
|
||||
|
@ -646,6 +646,12 @@ static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInf
|
||||
newinfo->doubleheight != oldinfo->doubleheight) {
|
||||
for(col = 0; col < screen->cols; col++) {
|
||||
ScreenCell *cell = getcell(screen, row, col);
|
||||
if (cell == NULL)
|
||||
{
|
||||
DEBUG_LOG2("libvterm: setlineinfo() position invalid: %d / %d",
|
||||
row, col);
|
||||
return 1;
|
||||
}
|
||||
cell->pen.dwl = newinfo->doublewidth;
|
||||
cell->pen.dhl = newinfo->doubleheight;
|
||||
}
|
||||
@ -773,6 +779,12 @@ static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer
|
||||
ScreenCell *cell = getcell(screen, row, col);
|
||||
int i;
|
||||
|
||||
if (cell == NULL)
|
||||
{
|
||||
DEBUG_LOG2("libvterm: _get_chars() position invalid: %d / %d",
|
||||
row, col);
|
||||
return 1;
|
||||
}
|
||||
if(cell->chars[0] == 0)
|
||||
// Erased cell, might need a space
|
||||
padding++;
|
||||
|
@ -17,11 +17,6 @@ static void putglyph(VTermState *state, const uint32_t chars[], int width, VTerm
|
||||
{
|
||||
VTermGlyphInfo info;
|
||||
|
||||
if (pos.row >= state->rows)
|
||||
{
|
||||
DEBUG_LOG2("libvterm: putglyph() pos.row %d out of range (rows = %d)\n", pos.row, state.rows);
|
||||
return;
|
||||
}
|
||||
info.chars = chars;
|
||||
info.width = width;
|
||||
info.protected_cell = state->protected_cell;
|
||||
@ -289,11 +284,6 @@ static int on_text(const char bytes[], size_t len, void *user)
|
||||
|
||||
VTermPos oldpos = state->pos;
|
||||
|
||||
if (state->pos.row >= state->rows)
|
||||
{
|
||||
DEBUG_LOG2("libvterm: on_text() pos.row %d out of range (rows = %d)\n", state->pos.row, state.rows);
|
||||
return 0;
|
||||
}
|
||||
// We'll have at most len codepoints, plus one from a previous incomplete
|
||||
// sequence.
|
||||
codepoints = vterm_allocator_malloc(state->vt, (len + 1) * sizeof(uint32_t));
|
||||
@ -1856,8 +1846,12 @@ static int on_resize(int rows, int cols, void *user)
|
||||
|
||||
if(state->pos.row >= rows)
|
||||
state->pos.row = rows - 1;
|
||||
if(state->pos.row < 0)
|
||||
state->pos.row = 0;
|
||||
if(state->pos.col >= cols)
|
||||
state->pos.col = cols - 1;
|
||||
if(state->pos.col < 0)
|
||||
state->pos.col = 0;
|
||||
|
||||
updatecursor(state, &oldpos, 1);
|
||||
|
||||
|
27
src/misc2.c
27
src/misc2.c
@ -2910,6 +2910,25 @@ find_special_key(
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Some keys already have Shift included, pass them as normal keys.
|
||||
* Not when Ctrl is also used, because <C-H> and <C-S-H> are different.
|
||||
* Also for <A-S-a> and <M-S-a>.
|
||||
*/
|
||||
int
|
||||
may_remove_shift_modifier(int modifiers, int key)
|
||||
{
|
||||
if ((modifiers == MOD_MASK_SHIFT
|
||||
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_ALT)
|
||||
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_META))
|
||||
&& ((key >= '@' && key <= 'Z')
|
||||
|| key == '^' || key == '_'
|
||||
|| (key >= '{' && key <= '~')))
|
||||
return modifiers & ~MOD_MASK_SHIFT;
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to include modifiers in the key.
|
||||
* Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
|
||||
@ -2929,9 +2948,11 @@ extract_modifiers(int key, int *modp, int simplify, int *did_simplify)
|
||||
if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key))
|
||||
{
|
||||
key = TOUPPER_ASC(key);
|
||||
// With <C-S-a> and <A-S-a> we keep the shift modifier.
|
||||
// With <S-a> and <S-A> we don't keep the shift modifier.
|
||||
if (simplify || modifiers == MOD_MASK_SHIFT)
|
||||
// With <C-S-a> we keep the shift modifier.
|
||||
// With <S-a>, <A-S-a> and <S-A> we don't keep the shift modifier.
|
||||
if (simplify || modifiers == MOD_MASK_SHIFT
|
||||
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_ALT)
|
||||
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_META))
|
||||
modifiers &= ~MOD_MASK_SHIFT;
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,7 @@ char_u *get_special_key_name(int c, int modifiers);
|
||||
int trans_special(char_u **srcp, char_u *dst, int flags, int *did_simplify);
|
||||
int special_to_buf(int key, int modifiers, int keycode, char_u *dst);
|
||||
int find_special_key(char_u **srcp, int *modp, int flags, int *did_simplify);
|
||||
int may_remove_shift_modifier(int modifiers, int key);
|
||||
int extract_modifiers(int key, int *modp, int simplify, int *did_simplify);
|
||||
int find_special_key_in_table(int c);
|
||||
int get_special_key_code(char_u *name);
|
||||
|
@ -10,10 +10,11 @@ int get_script_item_idx(int sid, char_u *name, int check_writable);
|
||||
imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
|
||||
char_u *to_name_const_end(char_u *arg);
|
||||
int assignment_len(char_u *p, int *heredoc);
|
||||
void vim9_declare_error(char_u *name);
|
||||
int check_vim9_unlet(char_u *name);
|
||||
int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx);
|
||||
void set_function_type(ufunc_T *ufunc);
|
||||
void delete_instr(isn_T *isn);
|
||||
void delete_def_function(ufunc_T *ufunc);
|
||||
void clear_def_function(ufunc_T *ufunc);
|
||||
void free_def_functions(void);
|
||||
/* vim: set ft=c : */
|
||||
|
@ -7,5 +7,5 @@ void ex_import(exarg_T *eap);
|
||||
int find_exported(int sid, char_u **argp, int *name_len, ufunc_T **ufunc, type_T **type);
|
||||
char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx);
|
||||
char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
|
||||
void check_script_var_type(typval_T *dest, typval_T *value, char_u *name);
|
||||
int check_script_var_type(typval_T *dest, typval_T *value, char_u *name);
|
||||
/* vim: set ft=c : */
|
||||
|
@ -473,6 +473,73 @@ set_execreg_lastc(int lastc)
|
||||
execreg_lastc = lastc;
|
||||
}
|
||||
|
||||
/*
|
||||
* When executing a register as a series of ex-commands, if the
|
||||
* line-continuation character is used for a line, then join it with one or
|
||||
* more previous lines. Note that lines are processed backwards starting from
|
||||
* the last line in the register.
|
||||
*
|
||||
* Arguments:
|
||||
* lines - list of lines in the register
|
||||
* idx - index of the line starting with \ or "\. Join this line with all the
|
||||
* immediate predecessor lines that start with a \ and the first line
|
||||
* that doesn't start with a \. Lines that start with a comment "\
|
||||
* character are ignored.
|
||||
*
|
||||
* Returns the concatenated line. The index of the line that should be
|
||||
* processed next is returned in idx.
|
||||
*/
|
||||
static char_u *
|
||||
execreg_line_continuation(char_u **lines, long *idx)
|
||||
{
|
||||
garray_T ga;
|
||||
long i = *idx;
|
||||
char_u *p;
|
||||
int cmd_start;
|
||||
int cmd_end = i;
|
||||
int j;
|
||||
char_u *str;
|
||||
|
||||
ga_init2(&ga, (int)sizeof(char_u), 400);
|
||||
|
||||
// search backwards to find the first line of this command.
|
||||
// Any line not starting with \ or "\ is the start of the
|
||||
// command.
|
||||
while (--i > 0)
|
||||
{
|
||||
p = skipwhite(lines[i]);
|
||||
if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' '))
|
||||
break;
|
||||
}
|
||||
cmd_start = i;
|
||||
|
||||
// join all the lines
|
||||
ga_concat(&ga, lines[cmd_start]);
|
||||
for (j = cmd_start + 1; j <= cmd_end; j++)
|
||||
{
|
||||
p = skipwhite(lines[j]);
|
||||
if (*p == '\\')
|
||||
{
|
||||
// Adjust the growsize to the current length to
|
||||
// speed up concatenating many lines.
|
||||
if (ga.ga_len > 400)
|
||||
{
|
||||
if (ga.ga_len > 8000)
|
||||
ga.ga_growsize = 8000;
|
||||
else
|
||||
ga.ga_growsize = ga.ga_len;
|
||||
}
|
||||
ga_concat(&ga, p + 1);
|
||||
}
|
||||
}
|
||||
ga_append(&ga, NUL);
|
||||
str = vim_strsave(ga.ga_data);
|
||||
ga_clear(&ga);
|
||||
|
||||
*idx = i;
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute a yank register: copy it into the stuff buffer.
|
||||
*
|
||||
@ -579,6 +646,8 @@ do_execreg(
|
||||
for (i = y_current->y_size; --i >= 0; )
|
||||
{
|
||||
char_u *escaped;
|
||||
char_u *str;
|
||||
int free_str = FALSE;
|
||||
|
||||
// insert NL between lines and after last line if type is MLINE
|
||||
if (y_current->y_type == MLINE || i < y_current->y_size - 1
|
||||
@ -587,7 +656,23 @@ do_execreg(
|
||||
if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
escaped = vim_strsave_escape_csi(y_current->y_array[i]);
|
||||
|
||||
// Handle line-continuation for :@<register>
|
||||
str = y_current->y_array[i];
|
||||
if (colon && i > 0)
|
||||
{
|
||||
p = skipwhite(str);
|
||||
if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))
|
||||
{
|
||||
str = execreg_line_continuation(y_current->y_array, &i);
|
||||
if (str == NULL)
|
||||
return FAIL;
|
||||
free_str = TRUE;
|
||||
}
|
||||
}
|
||||
escaped = vim_strsave_escape_csi(str);
|
||||
if (free_str)
|
||||
vim_free(str);
|
||||
if (escaped == NULL)
|
||||
return FAIL;
|
||||
retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
|
||||
|
@ -1343,7 +1343,7 @@ do_source(
|
||||
|
||||
// Allocate the local script variables to use for this script.
|
||||
new_script_vars(script_items.ga_len);
|
||||
ga_init2(&si->sn_var_vals, sizeof(typval_T), 10);
|
||||
ga_init2(&si->sn_var_vals, sizeof(svar_T), 10);
|
||||
ga_init2(&si->sn_imports, sizeof(imported_T), 10);
|
||||
ga_init2(&si->sn_type_list, sizeof(type_T), 10);
|
||||
# ifdef FEAT_PROFILE
|
||||
@ -1873,7 +1873,7 @@ ex_scriptversion(exarg_T *eap UNUSED)
|
||||
nr = getdigits(&eap->arg);
|
||||
if (nr == 0 || *eap->arg != NUL)
|
||||
emsg(_(e_invarg));
|
||||
else if (nr > 4)
|
||||
else if (nr > SCRIPT_VERSION_MAX)
|
||||
semsg(_("E999: scriptversion not supported: %d"), nr);
|
||||
else
|
||||
{
|
||||
|
@ -67,6 +67,8 @@ typedef struct terminal_S term_T;
|
||||
typedef struct VimMenu vimmenu_T;
|
||||
#endif
|
||||
|
||||
// maximum value for sc_version
|
||||
#define SCRIPT_VERSION_MAX 4
|
||||
// value for sc_version in a Vim9 script file
|
||||
#define SCRIPT_VERSION_VIM9 999999
|
||||
|
||||
@ -1531,8 +1533,11 @@ struct blobvar_S
|
||||
typedef struct funccall_S funccall_T;
|
||||
|
||||
// values used for "uf_dfunc_idx"
|
||||
# define UF_NOT_COMPILED -2
|
||||
# define UF_TO_BE_COMPILED -1
|
||||
typedef enum {
|
||||
UF_NOT_COMPILED,
|
||||
UF_TO_BE_COMPILED,
|
||||
UF_COMPILED
|
||||
} def_status_T;
|
||||
|
||||
/*
|
||||
* Structure to hold info for a user function.
|
||||
@ -1543,7 +1548,8 @@ typedef struct
|
||||
int uf_flags; // FC_ flags
|
||||
int uf_calls; // nr of active calls
|
||||
int uf_cleared; // func_clear() was already called
|
||||
int uf_dfunc_idx; // UF_NOT_COMPILED, UF_TO_BE_COMPILED or >= 0
|
||||
def_status_T uf_def_status; // UF_NOT_COMPILED, UF_TO_BE_COMPILED, etc.
|
||||
int uf_dfunc_idx; // only valid if uf_def_status is UF_COMPILED
|
||||
garray_T uf_args; // arguments, including optional arguments
|
||||
garray_T uf_def_args; // default argument expressions
|
||||
|
||||
|
10
src/term.c
10
src/term.c
@ -4769,14 +4769,8 @@ handle_key_with_modifier(
|
||||
|
||||
modifiers = decode_modifiers(arg[1]);
|
||||
|
||||
// Some keys already have Shift included, pass them as
|
||||
// normal keys. Not when Ctrl is also used, because <C-H>
|
||||
// and <C-S-H> are different.
|
||||
if (modifiers == MOD_MASK_SHIFT
|
||||
&& ((key >= '@' && key <= 'Z')
|
||||
|| key == '^' || key == '_'
|
||||
|| (key >= '{' && key <= '~')))
|
||||
modifiers = 0;
|
||||
// May remove the shift modifier if it's already included in the key.
|
||||
modifiers = may_remove_shift_modifier(modifiers, key);
|
||||
|
||||
// When used with Ctrl we always make a letter upper case,
|
||||
// so that mapping <C-H> and <C-h> are the same. Typing
|
||||
|
20
src/testdir/dumps/Test_diff_rnu_01.dump
Normal file
20
src/testdir/dumps/Test_diff_rnu_01.dump
Normal file
@ -0,0 +1,20 @@
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&|1+0#af5f00255&| @2>a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|1| |a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|2| |a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|x+2#0000000#ff404010| +0&#ffd7ff255@33||+1&#ffffff0| +0#af5f00255&@1|3| |y+2#0000000#ff404010| +0&#ffd7ff255@31
|
||||
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
|
||||
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|4| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|5| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|6| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|7| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|8| |b+0#0000000&| @31
|
||||
|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
|
||||
| +0&&@74
|
20
src/testdir/dumps/Test_diff_rnu_02.dump
Normal file
20
src/testdir/dumps/Test_diff_rnu_02.dump
Normal file
@ -0,0 +1,20 @@
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|1| |a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&|2+0#af5f00255&| @2>a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|1| |a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|x+2#0000000#ff404010| +0&#ffd7ff255@33||+1&#ffffff0| +0#af5f00255&@1|2| |y+2#0000000#ff404010| +0&#ffd7ff255@31
|
||||
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
|
||||
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|3| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|4| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|5| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|6| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|7| |b+0#0000000&| @31
|
||||
|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|2|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|2|,|1| @11|A|l@1
|
||||
| +0&&@74
|
20
src/testdir/dumps/Test_diff_rnu_03.dump
Normal file
20
src/testdir/dumps/Test_diff_rnu_03.dump
Normal file
@ -0,0 +1,20 @@
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|2| |a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|1| |a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&|3+0#af5f00255&| @2>a+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|x+2#0000000#ff404010| +0&#ffd7ff255@33||+1&#ffffff0| +0#af5f00255&@1|1| |y+2#0000000#ff404010| +0&#ffd7ff255@31
|
||||
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
|
||||
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|2| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|3| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|4| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|5| |b+0#0000000&| @31
|
||||
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|6| |b+0#0000000&| @31
|
||||
|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|
||||
|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|1| @11|A|l@1
|
||||
| +0&&@74
|
@ -216,7 +216,15 @@ func RunTheTest(test)
|
||||
|
||||
let message = 'Executed ' . a:test
|
||||
if has('reltime')
|
||||
let message ..= ' in ' .. reltimestr(reltime(func_start)) .. ' seconds'
|
||||
let message ..= repeat(' ', 50 - len(message))
|
||||
let time = reltime(func_start)
|
||||
if has('float') && reltimefloat(time) > 0.1
|
||||
let message = &t_md .. message
|
||||
endif
|
||||
let message ..= ' in ' .. reltimestr(time) .. ' seconds'
|
||||
if has('float') && reltimefloat(time) > 0.1
|
||||
let message ..= &t_me
|
||||
endif
|
||||
endif
|
||||
call add(s:messages, message)
|
||||
let s:done += 1
|
||||
@ -284,7 +292,9 @@ func FinishTesting()
|
||||
let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
|
||||
endif
|
||||
if s:done > 0 && has('reltime')
|
||||
let message = &t_md .. message .. repeat(' ', 40 - len(message))
|
||||
let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
|
||||
let message ..= &t_me
|
||||
endif
|
||||
echo message
|
||||
call add(s:messages, message)
|
||||
|
@ -28,10 +28,12 @@ endfunc
|
||||
" The second argument is the minimum time to wait in msec, 10 if omitted.
|
||||
func TermWait(buf, ...)
|
||||
let wait_time = a:0 ? a:1 : 10
|
||||
if g:run_nr == 2
|
||||
let wait_time *= 4
|
||||
elseif g:run_nr > 2
|
||||
let wait_time *= 10
|
||||
if exists('g:run_nr')
|
||||
if g:run_nr == 2
|
||||
let wait_time *= 4
|
||||
elseif g:run_nr > 2
|
||||
let wait_time *= 10
|
||||
endif
|
||||
endif
|
||||
call term_wait(a:buf, wait_time)
|
||||
|
||||
@ -107,16 +109,18 @@ func RunVimInTerminal(arguments, options)
|
||||
|
||||
call TermWait(buf)
|
||||
|
||||
" Wait for "All" or "Top" of the ruler to be shown in the last line or in
|
||||
" the status line of the last window. This can be quite slow (e.g. when
|
||||
" using valgrind).
|
||||
" If it fails then show the terminal contents for debugging.
|
||||
try
|
||||
call WaitFor({-> len(term_getline(buf, rows)) >= cols - 1 || len(term_getline(buf, rows - statusoff)) >= cols - 1})
|
||||
catch /timed out after/
|
||||
let lines = map(range(1, rows), {key, val -> term_getline(buf, val)})
|
||||
call assert_report('RunVimInTerminal() failed, screen contents: ' . join(lines, "<NL>"))
|
||||
endtry
|
||||
if get(a:options, 'wait_for_ruler', 1)
|
||||
" Wait for "All" or "Top" of the ruler to be shown in the last line or in
|
||||
" the status line of the last window. This can be quite slow (e.g. when
|
||||
" using valgrind).
|
||||
" If it fails then show the terminal contents for debugging.
|
||||
try
|
||||
call WaitFor({-> len(term_getline(buf, rows)) >= cols - 1 || len(term_getline(buf, rows - statusoff)) >= cols - 1})
|
||||
catch /timed out after/
|
||||
let lines = map(range(1, rows), {key, val -> term_getline(buf, val)})
|
||||
call assert_report('RunVimInTerminal() failed, screen contents: ' . join(lines, "<NL>"))
|
||||
endtry
|
||||
endif
|
||||
|
||||
" Starting a terminal to run Vim is always considered flaky.
|
||||
let g:test_is_flaky = 1
|
||||
|
@ -2592,7 +2592,7 @@ func Test_autocmd_window()
|
||||
augroup END
|
||||
|
||||
doautoall BufEnter
|
||||
call assert_equal([['one.txt', 'aucmdwin'], ['two.txt', '']], g:blist)
|
||||
call assert_equal([['one.txt', 'autocmd'], ['two.txt', '']], g:blist)
|
||||
|
||||
augroup aucmd_win_test
|
||||
au!
|
||||
|
@ -254,6 +254,7 @@ func Test_blob_func_remove()
|
||||
call assert_fails("call remove(b, 3, 2)", 'E979:')
|
||||
call assert_fails("call remove(1, 0)", 'E896:')
|
||||
call assert_fails("call remove(b, b)", 'E974:')
|
||||
call assert_fails("call remove(b, 1, [])", 'E745:')
|
||||
call assert_fails("call remove(test_null_blob(), 1, 2)", 'E979:')
|
||||
endfunc
|
||||
|
||||
|
@ -29,14 +29,14 @@ func SetUp()
|
||||
endif
|
||||
let s:chopt = {}
|
||||
call ch_log(g:testfunc)
|
||||
|
||||
" Most tests use job_start(), which can be flaky
|
||||
let g:test_is_flaky = 1
|
||||
endfunc
|
||||
|
||||
" Run "testfunc" after starting the server and stop the server afterwards.
|
||||
func s:run_server(testfunc, ...)
|
||||
call RunServer(s:testscript, a:testfunc, a:000)
|
||||
|
||||
" communicating with a server can be flaky
|
||||
let g:test_is_flaky = 1
|
||||
endfunc
|
||||
|
||||
" Return a list of open files.
|
||||
@ -455,7 +455,6 @@ endfunc
|
||||
func Test_connect_waittime()
|
||||
CheckFunction reltimefloat
|
||||
" this is timing sensitive
|
||||
let g:test_is_flaky = 1
|
||||
|
||||
let start = reltime()
|
||||
let handle = ch_open('localhost:9876', s:chopt)
|
||||
@ -1762,9 +1761,8 @@ func Test_write_to_deleted_buffer()
|
||||
endfunc
|
||||
|
||||
func Test_cmd_parsing()
|
||||
if !has('unix')
|
||||
return
|
||||
endif
|
||||
CheckUnix
|
||||
|
||||
call assert_false(filereadable("file with space"))
|
||||
let job = job_start('touch "file with space"')
|
||||
call WaitForAssert({-> assert_true(filereadable("file with space"))})
|
||||
@ -1963,9 +1961,7 @@ func Test_list_args()
|
||||
endfunc
|
||||
|
||||
func Test_keep_pty_open()
|
||||
if !has('unix')
|
||||
return
|
||||
endif
|
||||
CheckUnix
|
||||
|
||||
let job = job_start(s:python . ' -c "import time;time.sleep(0.2)"',
|
||||
\ {'out_io': 'null', 'err_io': 'null', 'pty': 1})
|
||||
@ -2047,9 +2043,7 @@ func Test_no_hang_windows()
|
||||
endfunc
|
||||
|
||||
func Test_job_exitval_and_termsig()
|
||||
if !has('unix')
|
||||
return
|
||||
endif
|
||||
CheckUnix
|
||||
|
||||
" Terminate job normally
|
||||
let cmd = ['echo']
|
||||
@ -2123,6 +2117,7 @@ endfunc
|
||||
|
||||
" Do this last, it stops any channel log.
|
||||
func Test_zz_nl_err_to_out_pipe()
|
||||
|
||||
eval 'Xlog'->ch_logfile()
|
||||
call ch_log('Test_zz_nl_err_to_out_pipe()')
|
||||
let job = job_start(s:python . " test_channel_pipe.py", {'err_io': 'out'})
|
||||
@ -2214,6 +2209,7 @@ endfunc
|
||||
func Test_job_trailing_space_unix()
|
||||
CheckUnix
|
||||
CheckExecutable cat
|
||||
|
||||
let job = job_start("cat ", #{in_io: 'null'})
|
||||
call WaitForAssert({-> assert_equal("dead", job_status(job))})
|
||||
call assert_equal(0, job_info(job).exitval)
|
||||
|
@ -1568,5 +1568,20 @@ func Test_zero_line_search()
|
||||
q!
|
||||
endfunc
|
||||
|
||||
func Test_read_shellcmd()
|
||||
CheckUnix
|
||||
if executable('ls')
|
||||
" There should be ls in the $PATH
|
||||
call feedkeys(":r! l\<c-a>\<c-b>\"\<cr>", 'tx')
|
||||
call assert_match('^"r! .*\<ls\>', @:)
|
||||
endif
|
||||
|
||||
if executable('rm')
|
||||
call feedkeys(":r! ++enc=utf-8 r\<c-a>\<c-b>\"\<cr>", 'tx')
|
||||
call assert_notmatch('^"r!.*\<runtest.vim\>', @:)
|
||||
call assert_match('^"r!.*\<rm\>', @:)
|
||||
endif
|
||||
endfunc
|
||||
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -246,6 +246,7 @@ func Test_cpo_H()
|
||||
endfunc
|
||||
|
||||
" TODO: Add a test for the 'i' flag in 'cpo'
|
||||
" Interrupting the reading of a file will leave it modified.
|
||||
|
||||
" Test for the 'I' flag in 'cpo' (deleting autoindent when using arrow keys)
|
||||
func Test_cpo_I()
|
||||
@ -294,9 +295,12 @@ func Test_cpo_J()
|
||||
let &cpo = save_cpo
|
||||
endfunc
|
||||
|
||||
" TODO: Add a test for the 'k' flag in 'cpo'
|
||||
" TODO: Add a test for the 'k' flag in 'cpo'.
|
||||
" Disable the recognition of raw key codes in mappings, abbreviations, and the
|
||||
" "to" part of menu commands.
|
||||
|
||||
" TODO: Add a test for the 'K' flag in 'cpo'
|
||||
" TODO: Add a test for the 'K' flag in 'cpo'.
|
||||
" Don't wait for a key code to complete when it is halfway a mapping.
|
||||
|
||||
" Test for the 'l' flag in 'cpo' (backslash in a [] range)
|
||||
func Test_cpo_l()
|
||||
@ -334,7 +338,9 @@ func Test_cpo_L()
|
||||
let &cpo = save_cpo
|
||||
endfunc
|
||||
|
||||
" TODO: Add a test for the 'm' flag in 'cpo'
|
||||
" TODO: Add a test for the 'm' flag in 'cpo'.
|
||||
" When included, a showmatch will always wait half a second. When not
|
||||
" included, a showmatch will wait half a second or until a character is typed.
|
||||
|
||||
" Test for the 'M' flag in 'cpo' (% with escape parenthesis)
|
||||
func Test_cpo_M()
|
||||
@ -498,7 +504,9 @@ func Test_cpo_R()
|
||||
let &cpo = save_cpo
|
||||
endfunc
|
||||
|
||||
" TODO: Add a test for the 's' flag in 'cpo'
|
||||
" TODO: Add a test for the 's' flag in 'cpo'.
|
||||
" Set buffer options when entering the buffer for the first time. If not
|
||||
" present the options are set when the buffer is created.
|
||||
|
||||
" Test for the 'S' flag in 'cpo' (copying buffer options)
|
||||
func Test_cpo_S()
|
||||
@ -543,8 +551,8 @@ func Test_cpo_u()
|
||||
let &cpo = save_cpo
|
||||
endfunc
|
||||
|
||||
" TODO: Add a test for the 'v' flag in 'cpo' (backspace doesn't remove
|
||||
" characters from the screen)
|
||||
" TODO: Add a test for the 'v' flag in 'cpo'.
|
||||
" Backspaced characters remain visible on the screen in Insert mode.
|
||||
|
||||
" Test for the 'w' flag in 'cpo' ('cw' on a blank character changes only one
|
||||
" character)
|
||||
|
@ -1093,4 +1093,29 @@ func Test_patchexpr()
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_diff_rnu()
|
||||
CheckScreendump
|
||||
|
||||
let content =<< trim END
|
||||
call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b'])
|
||||
vnew
|
||||
call setline(1, ['a', 'a', 'a', 'x', 'x', 'x', 'b', 'b', 'b', 'b', 'b'])
|
||||
windo diffthis
|
||||
setlocal number rnu foldcolumn=0
|
||||
END
|
||||
call writefile(content, 'Xtest_diff_rnu')
|
||||
let buf = RunVimInTerminal('-S Xtest_diff_rnu', {})
|
||||
|
||||
call VerifyScreenDump(buf, 'Test_diff_rnu_01', {})
|
||||
|
||||
call term_sendkeys(buf, "j")
|
||||
call VerifyScreenDump(buf, 'Test_diff_rnu_02', {})
|
||||
call term_sendkeys(buf, "j")
|
||||
call VerifyScreenDump(buf, 'Test_diff_rnu_03', {})
|
||||
|
||||
" clean up
|
||||
call StopVimInTerminal(buf)
|
||||
call delete('Xtest_diff_rnu')
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
source check.vim
|
||||
CheckFeature digraphs
|
||||
source term_util.vim
|
||||
|
||||
func Put_Dig(chars)
|
||||
exe "norm! o\<c-k>".a:chars
|
||||
@ -502,4 +503,20 @@ func Test_loadkeymap_error()
|
||||
call delete('Xkeymap')
|
||||
endfunc
|
||||
|
||||
" Test for the characters displayed on the screen when entering a digraph
|
||||
func Test_entering_digraph()
|
||||
CheckRunVimInTerminal
|
||||
let buf = RunVimInTerminal('', {'rows': 6})
|
||||
call term_sendkeys(buf, "i\<C-K>")
|
||||
call term_wait(buf)
|
||||
call assert_equal('?', term_getline(buf, 1))
|
||||
call term_sendkeys(buf, "1")
|
||||
call term_wait(buf)
|
||||
call assert_equal('1', term_getline(buf, 1))
|
||||
call term_sendkeys(buf, "2")
|
||||
call term_wait(buf)
|
||||
call assert_equal('½', term_getline(buf, 1))
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -401,6 +401,14 @@ func Test_edit_13()
|
||||
call assert_equal("", getline(2))
|
||||
call assert_equal(" baz", getline(3))
|
||||
set autoindent&
|
||||
|
||||
" pressing <C-U> to erase line should keep the indent with 'autoindent'
|
||||
set backspace=2 autoindent
|
||||
%d
|
||||
exe "normal i\tone\<CR>three\<C-U>two"
|
||||
call assert_equal(["\tone", "\ttwo"], getline(1, '$'))
|
||||
set backspace& autoindent&
|
||||
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
@ -1301,9 +1309,7 @@ endfunc
|
||||
|
||||
func Test_edit_rightleft()
|
||||
" Cursor in rightleft mode moves differently
|
||||
if !exists("+rightleft")
|
||||
return
|
||||
endif
|
||||
CheckFeature rightleft
|
||||
call NewWindow(10, 20)
|
||||
call setline(1, ['abc', 'def', 'ghi'])
|
||||
call cursor(1, 2)
|
||||
@ -1348,6 +1354,13 @@ func Test_edit_rightleft()
|
||||
\" ihg",
|
||||
\" ~"]
|
||||
call assert_equal(join(expect, "\n"), join(lines, "\n"))
|
||||
%d _
|
||||
call test_override('redraw_flag', 1)
|
||||
call test_override('char_avail', 1)
|
||||
call feedkeys("a\<C-V>x41", "xt")
|
||||
redraw!
|
||||
call assert_equal(repeat(' ', 19) .. 'A', Screenline(1))
|
||||
call test_override('ALL', 0)
|
||||
set norightleft
|
||||
bw!
|
||||
endfunc
|
||||
@ -1683,4 +1696,103 @@ func Test_edit_file_no_read_perm()
|
||||
call delete('Xfile')
|
||||
endfunc
|
||||
|
||||
" Pressing escape in 'insertmode' should beep
|
||||
func Test_edit_insertmode_esc_beeps()
|
||||
new
|
||||
set insertmode
|
||||
call assert_beeps("call feedkeys(\"one\<Esc>\", 'xt')")
|
||||
set insertmode&
|
||||
" unsupported CTRL-G command should beep in insert mode.
|
||||
call assert_beeps("normal i\<C-G>l")
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for 'hkmap' and 'hkmapp'
|
||||
func Test_edit_hkmap()
|
||||
CheckFeature rightleft
|
||||
if has('win32') && !has('gui')
|
||||
" Test fails on the MS-Windows terminal version
|
||||
return
|
||||
endif
|
||||
new
|
||||
|
||||
set revins hkmap
|
||||
let str = 'abcdefghijklmnopqrstuvwxyz'
|
||||
let str ..= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
let str ..= '`/'',.;'
|
||||
call feedkeys('i' .. str, 'xt')
|
||||
let expected = "óõú,.;"
|
||||
let expected ..= "ZYXWVUTSRQPONMLKJIHGFEDCBA"
|
||||
let expected ..= "æèñ'äåàãø/ôíîöêìçïéòë÷âáðù"
|
||||
call assert_equal(expected, getline(1))
|
||||
|
||||
%d
|
||||
set revins hkmap hkmapp
|
||||
let str = 'abcdefghijklmnopqrstuvwxyz'
|
||||
let str ..= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
call feedkeys('i' .. str, 'xt')
|
||||
let expected = "õYXWVUTSRQóOïíLKJIHGFEDêBA"
|
||||
let expected ..= "öòXùåèúæø'ôñðîì÷çéäâóǟãëáà"
|
||||
call assert_equal(expected, getline(1))
|
||||
|
||||
set revins& hkmap& hkmapp&
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for 'allowrevins' and using CTRL-_ in insert mode
|
||||
func Test_edit_allowrevins()
|
||||
CheckFeature rightleft
|
||||
new
|
||||
set allowrevins
|
||||
call feedkeys("iABC\<C-_>DEF\<C-_>GHI", 'xt')
|
||||
call assert_equal('ABCFEDGHI', getline(1))
|
||||
set allowrevins&
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for inserting a register in insert mode using CTRL-R
|
||||
func Test_edit_insert_reg()
|
||||
new
|
||||
let g:Line = ''
|
||||
func SaveFirstLine()
|
||||
let g:Line = Screenline(1)
|
||||
return 'r'
|
||||
endfunc
|
||||
inoremap <expr> <buffer> <F2> SaveFirstLine()
|
||||
call test_override('redraw_flag', 1)
|
||||
call test_override('char_avail', 1)
|
||||
let @r = 'sample'
|
||||
call feedkeys("a\<C-R>=SaveFirstLine()\<CR>", "xt")
|
||||
call assert_equal('"', g:Line)
|
||||
call test_override('ALL', 0)
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" When a character is inserted at the last position of the last line in a
|
||||
" window, the window contents should be scrolled one line up. If the top line
|
||||
" is part of a fold, then the entire fold should be scrolled up.
|
||||
func Test_edit_lastline_scroll()
|
||||
new
|
||||
let h = winheight(0)
|
||||
let lines = ['one', 'two', 'three']
|
||||
let lines += repeat(['vim'], h - 4)
|
||||
call setline(1, lines)
|
||||
call setline(h, repeat('x', winwidth(0) - 1))
|
||||
call feedkeys("GAx", 'xt')
|
||||
redraw!
|
||||
call assert_equal(h - 1, winline())
|
||||
call assert_equal(2, line('w0'))
|
||||
|
||||
" scroll with a fold
|
||||
1,2fold
|
||||
normal gg
|
||||
call setline(h + 1, repeat('x', winwidth(0) - 1))
|
||||
call feedkeys("GAx", 'xt')
|
||||
redraw!
|
||||
call assert_equal(h - 1, winline())
|
||||
call assert_equal(3, line('w0'))
|
||||
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -166,6 +166,17 @@ func Test_ex_mode_errors()
|
||||
endtry
|
||||
call assert_equal(1, caught_e565)
|
||||
au! InsertCharPre
|
||||
|
||||
new
|
||||
au CmdLineEnter * call ExEnterFunc()
|
||||
func ExEnterFunc()
|
||||
|
||||
endfunc
|
||||
call feedkeys("gQvi\r", 'xt')
|
||||
|
||||
au! CmdLineEnter
|
||||
delfunc ExEnterFunc
|
||||
quit
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -2014,6 +2014,25 @@ func Test_readdir_sort()
|
||||
let files = readdir(dir, '1', #{sort: 'icase'})
|
||||
call assert_equal(default->sort('i'), files, 'sort by ignoring case')
|
||||
|
||||
" 4) collation
|
||||
let collate = v:collate
|
||||
lang collate C
|
||||
let files = readdir(dir, 1, #{sort: 'collate'})
|
||||
call assert_equal(default->sort(), files, 'sort by C collation')
|
||||
exe "lang collate" collate
|
||||
|
||||
" 5) Errors
|
||||
call assert_fails('call readdir(dir, 1, 1)', 'E715')
|
||||
call assert_fails('call readdir(dir, 1, #{sorta: 1})')
|
||||
call assert_fails('call readdirex(dir, 1, #{sorta: 1})')
|
||||
|
||||
" 6) ignore other values in dict
|
||||
let files = readdir(dir, '1', #{sort: 'c'})
|
||||
call assert_equal(default, files, 'sort using default2')
|
||||
|
||||
" Cleanup
|
||||
exe "lang collate" collate
|
||||
|
||||
eval dir->delete('rf')
|
||||
endfunc
|
||||
|
||||
|
@ -7,7 +7,7 @@ let s:imstatus_active = 0
|
||||
|
||||
func IM_activatefunc(active)
|
||||
let s:imactivatefunc_called = 1
|
||||
let s:imstatus_active = a:active
|
||||
let s:imstatus_active = a:active
|
||||
endfunc
|
||||
|
||||
func IM_statusfunc()
|
||||
@ -83,4 +83,30 @@ func Test_lmap_in_insert_mode()
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for using CTRL-^ to toggle iminsert in insert mode
|
||||
func Test_iminsert_toggle()
|
||||
CheckGui
|
||||
if has('win32')
|
||||
CheckFeature multi_byte_ime
|
||||
elseif !has('gui_mac')
|
||||
CheckFeature xim
|
||||
endif
|
||||
if has('gui_running') && !has('win32')
|
||||
" this works only in Win32 GUI version (for some reason)
|
||||
return
|
||||
endif
|
||||
new
|
||||
let save_imdisable = &imdisable
|
||||
let save_iminsert = &iminsert
|
||||
set noimdisable
|
||||
set iminsert=0
|
||||
exe "normal i\<C-^>"
|
||||
call assert_equal(2, &iminsert)
|
||||
exe "normal i\<C-^>"
|
||||
call assert_equal(0, &iminsert)
|
||||
let &iminsert = save_iminsert
|
||||
let &imdisable = save_imdisable
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -79,11 +79,27 @@ func Test_paste_clipboard()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" bracketed paste in command line
|
||||
func Test_paste_cmdline()
|
||||
call feedkeys(":a\<Esc>[200~foo\<CR>bar\<Esc>[201~b\<Home>\"\<CR>", 'xt')
|
||||
call assert_equal("\"afoo\<CR>barb", getreg(':'))
|
||||
endfunc
|
||||
|
||||
" bracketed paste in Ex-mode
|
||||
func Test_paste_ex_mode()
|
||||
unlet! foo
|
||||
call feedkeys("Qlet foo=\"\<Esc>[200~foo\<CR>bar\<Esc>[201~\"\<CR>vi\<CR>", 'xt')
|
||||
call assert_equal("foo\rbar", foo)
|
||||
endfunc
|
||||
|
||||
func Test_paste_onechar()
|
||||
new
|
||||
let @f='abc'
|
||||
call feedkeys("i\<C-R>\<Esc>[200~foo\<CR>bar\<Esc>[201~", 'xt')
|
||||
call assert_equal("abc", getline(1))
|
||||
close!
|
||||
endfunc
|
||||
|
||||
func Test_paste_visual_mode()
|
||||
new
|
||||
call setline(1, 'here are some words')
|
||||
@ -134,3 +150,5 @@ func Test_xrestore()
|
||||
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -2079,9 +2079,9 @@ func Test_popup_scrollbar()
|
||||
" check size with wrapping lines
|
||||
call term_sendkeys(buf, "j")
|
||||
call VerifyScreenDump(buf, 'Test_popupwin_scroll_12', {})
|
||||
call term_sendkeys(buf, "x")
|
||||
|
||||
" clean up
|
||||
call term_sendkeys(buf, "x")
|
||||
call StopVimInTerminal(buf)
|
||||
call delete('XtestPopupScroll')
|
||||
endfunc
|
||||
@ -2454,9 +2454,11 @@ func Test_popupwin_terminal_buffer()
|
||||
call term_sendkeys(termbuf2, "exit\<CR>")
|
||||
|
||||
" Exiting shell closes popup window
|
||||
let pupwin = win_getid()
|
||||
call feedkeys("exit\<CR>", 'xt')
|
||||
" Wait for shell to exit
|
||||
sleep 100m
|
||||
call WaitForAssert({-> assert_notequal(pupwin, win_getid())})
|
||||
|
||||
call feedkeys(":quit\<CR>", 'xt')
|
||||
call assert_equal(origwin, win_getid())
|
||||
endfunc
|
||||
@ -3347,6 +3349,16 @@ func Test_popupwin_filter_input_multibyte()
|
||||
call feedkeys("\u301b", 'xt')
|
||||
call assert_equal([0xe3, 0x80, 0x9b], g:bytes)
|
||||
|
||||
if has('unix')
|
||||
" with modifyOtherKeys <M-S-a> does not include a modifier sequence
|
||||
if has('gui_running')
|
||||
call feedkeys("\x9b\xfc\x08A", 'Lx!')
|
||||
else
|
||||
call feedkeys("\<Esc>[27;4;65~", 'Lx!')
|
||||
endif
|
||||
call assert_equal([0xc3, 0x81], g:bytes)
|
||||
endif
|
||||
|
||||
call popup_clear()
|
||||
delfunc MyPopupFilter
|
||||
unlet g:bytes
|
||||
|
@ -147,6 +147,11 @@ func Test_prompt_buffer_edit()
|
||||
call assert_beeps('normal! S')
|
||||
call assert_beeps("normal! \<C-A>")
|
||||
call assert_beeps("normal! \<C-X>")
|
||||
" pressing CTRL-W in the prompt buffer should trigger the window commands
|
||||
call assert_equal(1, winnr())
|
||||
exe "normal A\<C-W>\<C-W>"
|
||||
call assert_equal(2, winnr())
|
||||
wincmd w
|
||||
close!
|
||||
call assert_equal(0, prompt_setprompt([], ''))
|
||||
endfunc
|
||||
|
@ -485,6 +485,14 @@ func Test_set_register_dict()
|
||||
call assert_equal(['six'], getreginfo('0').regcontents)
|
||||
call assert_equal(['six'], getreginfo('"').regcontents)
|
||||
|
||||
let @x = 'one'
|
||||
call setreg('x', {})
|
||||
call assert_equal(1, len(split(execute('reg x'), '\n')))
|
||||
|
||||
call assert_fails("call setreg('0', #{regtype: 'V'}, 'v')", 'E118:')
|
||||
call assert_fails("call setreg('0', #{regtype: 'X'})", 'E475:')
|
||||
call assert_fails("call setreg('0', #{regtype: 'vy'})", 'E475:')
|
||||
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
@ -557,4 +565,80 @@ func Test_v_register()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" Test for executing the contents of a register as an Ex command with line
|
||||
" continuation.
|
||||
func Test_execute_reg_as_ex_cmd()
|
||||
" Line continuation with just two lines
|
||||
let code =<< trim END
|
||||
let l = [
|
||||
\ 1]
|
||||
END
|
||||
let @r = code->join("\n")
|
||||
let l = []
|
||||
@r
|
||||
call assert_equal([1], l)
|
||||
|
||||
" Line continuation with more than two lines
|
||||
let code =<< trim END
|
||||
let l = [
|
||||
\ 1,
|
||||
\ 2,
|
||||
\ 3]
|
||||
END
|
||||
let @r = code->join("\n")
|
||||
let l = []
|
||||
@r
|
||||
call assert_equal([1, 2, 3], l)
|
||||
|
||||
" use comments interspersed with code
|
||||
let code =<< trim END
|
||||
let l = [
|
||||
"\ one
|
||||
\ 1,
|
||||
"\ two
|
||||
\ 2,
|
||||
"\ three
|
||||
\ 3]
|
||||
END
|
||||
let @r = code->join("\n")
|
||||
let l = []
|
||||
@r
|
||||
call assert_equal([1, 2, 3], l)
|
||||
|
||||
" use line continuation in the middle
|
||||
let code =<< trim END
|
||||
let a = "one"
|
||||
let l = [
|
||||
\ 1,
|
||||
\ 2]
|
||||
let b = "two"
|
||||
END
|
||||
let @r = code->join("\n")
|
||||
let l = []
|
||||
@r
|
||||
call assert_equal([1, 2], l)
|
||||
call assert_equal("one", a)
|
||||
call assert_equal("two", b)
|
||||
|
||||
" only one line with a \
|
||||
let @r = "\\let l = 1"
|
||||
call assert_fails('@r', 'E10:')
|
||||
|
||||
" only one line with a "\
|
||||
let @r = ' "\ let i = 1'
|
||||
@r
|
||||
call assert_false(exists('i'))
|
||||
|
||||
" first line also begins with a \
|
||||
let @r = "\\let l = [\n\\ 1]"
|
||||
call assert_fails('@r', 'E10:')
|
||||
|
||||
" Test with a large number of lines
|
||||
let @r = "let str = \n"
|
||||
let @r ..= repeat(" \\ 'abcdefghijklmnopqrstuvwxyz' ..\n", 312)
|
||||
let @r ..= ' \ ""'
|
||||
@r
|
||||
call assert_equal(repeat('abcdefghijklmnopqrstuvwxyz', 312), str)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -26,6 +26,18 @@ func Test_rubydo()
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_rubydo_dollar_underscore()
|
||||
new
|
||||
call setline(1, ['one', 'two', 'three', 'four'])
|
||||
2,3rubydo $_ = '[' + $_ + ']'
|
||||
call assert_equal(['one', '[two]', '[three]', 'four'], getline(1, '$'))
|
||||
bwipe!
|
||||
|
||||
call assert_fails('rubydo $_ = 0', 'E265:')
|
||||
call assert_fails('rubydo (')
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_rubyfile()
|
||||
" Check :rubyfile does not SEGV with Ruby level exception but just fails
|
||||
let tempfile = tempname() . '.rb'
|
||||
@ -395,6 +407,15 @@ func Test_ruby_p()
|
||||
call assert_equal(0, len(messages))
|
||||
endfunc
|
||||
|
||||
func Test_rubyeval_error()
|
||||
" On Linux or Windows the error matches:
|
||||
" "syntax error, unexpected end-of-input"
|
||||
" whereas on macOS in CI, the error message makes less sense:
|
||||
" "SyntaxError: array length must be 2"
|
||||
" Unclear why. The test does not check the error message.
|
||||
call assert_fails('call rubyeval("(")')
|
||||
endfunc
|
||||
|
||||
" Test for various heredoc syntax
|
||||
func Test_ruby_heredoc()
|
||||
ruby << END
|
||||
|
@ -38,6 +38,9 @@ func Test_selectmode_start()
|
||||
set selectmode=cmd
|
||||
call feedkeys('gvabc', 'xt')
|
||||
call assert_equal('abctdef', getline(1))
|
||||
" arrow keys without shift should not start selection
|
||||
call feedkeys("A\<Home>\<Right>\<Left>ro", 'xt')
|
||||
call assert_equal('roabctdef', getline(1))
|
||||
set selectmode= keymodel=
|
||||
bw!
|
||||
endfunc
|
||||
|
@ -623,4 +623,93 @@ func Test_tabpage_close_cmdwin()
|
||||
tabonly
|
||||
endfunc
|
||||
|
||||
" Pressing <C-PageUp> in insert mode should go to the previous tab page
|
||||
" and <C-PageDown> should go to the next tab page
|
||||
func Test_tabpage_Ctrl_Pageup()
|
||||
tabnew
|
||||
call feedkeys("i\<C-PageUp>", 'xt')
|
||||
call assert_equal(1, tabpagenr())
|
||||
call feedkeys("i\<C-PageDown>", 'xt')
|
||||
call assert_equal(2, tabpagenr())
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" Return the terminal key code for selecting a tab page from the tabline. This
|
||||
" sequence contains the following codes: a CSI (0x9b), KS_TABLINE (0xf0),
|
||||
" KS_FILLER (0x58) and then the tab page number.
|
||||
func TabLineSelectPageCode(tabnr)
|
||||
return "\x9b\xf0\x58" .. nr2char(a:tabnr)
|
||||
endfunc
|
||||
|
||||
" Return the terminal key code for opening a new tabpage from the tabpage
|
||||
" menu. This sequence consists of the following codes: a CSI (0x9b),
|
||||
" KS_TABMENU (0xef), KS_FILLER (0x58), the tab page number and
|
||||
" TABLINE_MENU_NEW (2).
|
||||
func TabMenuNewItemCode(tabnr)
|
||||
return "\x9b\xef\x58" .. nr2char(a:tabnr) .. nr2char(2)
|
||||
endfunc
|
||||
|
||||
" Return the terminal key code for closing a tabpage from the tabpage menu.
|
||||
" This sequence consists of the following codes: a CSI (0x9b), KS_TABMENU
|
||||
" (0xef), KS_FILLER (0x58), the tab page number and TABLINE_MENU_CLOSE (1).
|
||||
func TabMenuCloseItemCode(tabnr)
|
||||
return "\x9b\xef\x58" .. nr2char(a:tabnr) .. nr2char(1)
|
||||
endfunc
|
||||
|
||||
" Test for using the tabpage menu from the insert and normal modes
|
||||
func Test_tabline_tabmenu()
|
||||
" only works in GUI
|
||||
CheckGui
|
||||
|
||||
%bw!
|
||||
tabnew
|
||||
tabnew
|
||||
call assert_equal(3, tabpagenr())
|
||||
|
||||
" go to tab page 2 in normal mode
|
||||
call feedkeys(TabLineSelectPageCode(2), "Lx!")
|
||||
call assert_equal(2, tabpagenr())
|
||||
|
||||
" close tab page 3 in normal mode
|
||||
call feedkeys(TabMenuCloseItemCode(3), "Lx!")
|
||||
call assert_equal(2, tabpagenr('$'))
|
||||
call assert_equal(2, tabpagenr())
|
||||
|
||||
" open new tab page before tab page 1 in normal mode
|
||||
call feedkeys(TabMenuNewItemCode(1), "Lx!")
|
||||
call assert_equal(1, tabpagenr())
|
||||
call assert_equal(3, tabpagenr('$'))
|
||||
|
||||
" go to tab page 2 in operator-pending mode (should beep)
|
||||
call assert_beeps('call feedkeys("f" .. TabLineSelectPageCode(2), "Lx!")')
|
||||
|
||||
" open new tab page before tab page 1 in operator-pending mode (should beep)
|
||||
call assert_beeps('call feedkeys("f" .. TabMenuNewItemCode(1), "Lx!")')
|
||||
|
||||
" open new tab page after tab page 3 in normal mode
|
||||
call feedkeys(TabMenuNewItemCode(4), "Lx!")
|
||||
call assert_equal(4, tabpagenr())
|
||||
call assert_equal(4, tabpagenr('$'))
|
||||
|
||||
" go to tab page 2 in insert mode
|
||||
call feedkeys("i" .. TabLineSelectPageCode(2) .. "\<C-C>", "Lx!")
|
||||
call assert_equal(2, tabpagenr())
|
||||
|
||||
" close tab page 2 in insert mode
|
||||
call feedkeys("i" .. TabMenuCloseItemCode(2) .. "\<C-C>", "Lx!")
|
||||
call assert_equal(3, tabpagenr('$'))
|
||||
|
||||
" open new tab page before tab page 3 in insert mode
|
||||
call feedkeys("i" .. TabMenuNewItemCode(3) .. "\<C-C>", "Lx!")
|
||||
call assert_equal(3, tabpagenr())
|
||||
call assert_equal(4, tabpagenr('$'))
|
||||
|
||||
" open new tab page after tab page 4 in insert mode
|
||||
call feedkeys("i" .. TabMenuNewItemCode(5) .. "\<C-C>", "Lx!")
|
||||
call assert_equal(5, tabpagenr())
|
||||
call assert_equal(5, tabpagenr('$'))
|
||||
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -240,6 +240,7 @@ func Test_tag_file_encoding()
|
||||
call delete('Xtags1')
|
||||
endfunc
|
||||
|
||||
" Test for emacs-style tags file (TAGS)
|
||||
func Test_tagjump_etags()
|
||||
if !has('emacs_tags')
|
||||
return
|
||||
@ -263,8 +264,52 @@ func Test_tagjump_etags()
|
||||
ta foo
|
||||
call assert_equal('void foo() {}', getline('.'))
|
||||
|
||||
" Test for including another tags file
|
||||
call writefile([
|
||||
\ "\x0c",
|
||||
\ "Xmain.c,64",
|
||||
\ "void foo() {}\x7ffoo\x011,0",
|
||||
\ "\x0c",
|
||||
\ "Xnonexisting,include",
|
||||
\ "\x0c",
|
||||
\ "Xtags2,include"
|
||||
\ ], 'Xtags')
|
||||
call writefile([
|
||||
\ "\x0c",
|
||||
\ "Xmain.c,64",
|
||||
\ "int main(int argc, char **argv)\x7fmain\x012,14",
|
||||
\ ], 'Xtags2')
|
||||
tag main
|
||||
call assert_equal(2, line('.'))
|
||||
|
||||
" corrupted tag line
|
||||
call writefile([
|
||||
\ "\x0c",
|
||||
\ "Xmain.c,8",
|
||||
\ "int main"
|
||||
\ ], 'Xtags', 'b')
|
||||
call assert_fails('tag foo', 'E426:')
|
||||
|
||||
" invalid line number
|
||||
call writefile([
|
||||
\ "\x0c",
|
||||
\ "Xmain.c,64",
|
||||
\ "void foo() {}\x7ffoo\x0abc,0",
|
||||
\ ], 'Xtags')
|
||||
call assert_fails('tag foo', 'E426:')
|
||||
|
||||
" invalid tag name
|
||||
call writefile([
|
||||
\ "\x0c",
|
||||
\ "Xmain.c,64",
|
||||
\ ";;;;\x7f1,0",
|
||||
\ ], 'Xtags')
|
||||
call assert_fails('tag foo', 'E426:')
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xtags2')
|
||||
call delete('Xmain.c')
|
||||
set tags&
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
@ -1011,7 +1056,7 @@ func Test_tselect_listing()
|
||||
call writefile([
|
||||
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "first\tXfoo\t1" .. ';"' .. "\tv\ttyperef:typename:int\tfile:",
|
||||
\ "first\tXfoo\t2" .. ';"' .. "\tv\ttyperef:typename:char\tfile:"],
|
||||
\ "first\tXfoo\t2" .. ';"' .. "\tkind:v\ttyperef:typename:char\tfile:"],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
|
||||
@ -1268,4 +1313,81 @@ func Test_comment_search()
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for the 'taglength' option
|
||||
func Test_tag_length()
|
||||
set tags=Xtags
|
||||
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "tame\tXfile1\t1;",
|
||||
\ "tape\tXfile2\t1;"], 'Xtags')
|
||||
call writefile(['tame'], 'Xfile1')
|
||||
call writefile(['tape'], 'Xfile2')
|
||||
|
||||
" Jumping to the tag 'tape', should instead jump to 'tame'
|
||||
new
|
||||
set taglength=2
|
||||
tag tape
|
||||
call assert_equal('Xfile1', @%)
|
||||
" Tag search should jump to the right tag
|
||||
enew
|
||||
tag /^tape$
|
||||
call assert_equal('Xfile2', @%)
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfile1')
|
||||
call delete('Xfile2')
|
||||
set tags& taglength&
|
||||
endfunc
|
||||
|
||||
" Tests for errors in a tags file
|
||||
func Test_tagfile_errors()
|
||||
set tags=Xtags
|
||||
|
||||
" missing search pattern or line number for a tag
|
||||
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "foo\tXfile\t"], 'Xtags', 'b')
|
||||
call writefile(['foo'], 'Xfile')
|
||||
|
||||
enew
|
||||
tag foo
|
||||
call assert_equal('', @%)
|
||||
let caught_431 = v:false
|
||||
try
|
||||
eval taglist('.*')
|
||||
catch /:E431:/
|
||||
let caught_431 = v:true
|
||||
endtry
|
||||
call assert_equal(v:true, caught_431)
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfile')
|
||||
set tags&
|
||||
endfunc
|
||||
|
||||
" When :stag fails to open the file, should close the new window
|
||||
func Test_stag_close_window_on_error()
|
||||
new | only
|
||||
set tags=Xtags
|
||||
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "foo\tXfile\t1"], 'Xtags')
|
||||
call writefile(['foo'], 'Xfile')
|
||||
call writefile([], '.Xfile.swp')
|
||||
" Remove the catch-all that runtest.vim adds
|
||||
au! SwapExists
|
||||
augroup StagTest
|
||||
au!
|
||||
autocmd SwapExists Xfile let v:swapchoice='q'
|
||||
augroup END
|
||||
|
||||
stag foo
|
||||
call assert_equal(1, winnr('$'))
|
||||
call assert_equal('', @%)
|
||||
|
||||
augroup StagTest
|
||||
au!
|
||||
augroup END
|
||||
call delete('Xfile')
|
||||
call delete('.Xfile.swp')
|
||||
set tags&
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -1116,6 +1116,20 @@ func Test_fo_a_w()
|
||||
call feedkeys("iabc abc a abc\<Esc>k0weade", 'xt')
|
||||
call assert_equal(['abc abcde ', 'a abc'], getline(1, '$'))
|
||||
|
||||
" when a line ends with space, it is not broken up.
|
||||
%d
|
||||
call feedkeys("ione two to ", 'xt')
|
||||
call assert_equal('one two to ', getline(1))
|
||||
|
||||
" when a line ends with spaces and backspace is used in the next line, the
|
||||
" last space in the previous line should be removed.
|
||||
%d
|
||||
set backspace=indent,eol,start
|
||||
call setline(1, ['one ', 'two'])
|
||||
exe "normal 2Gi\<BS>"
|
||||
call assert_equal(['one two'], getline(1, '$'))
|
||||
set backspace&
|
||||
|
||||
" Test for 'a', 'w' and '1' options.
|
||||
setlocal textwidth=0
|
||||
setlocal fo=1aw
|
||||
|
@ -311,6 +311,17 @@ func Test_sentence_with_cursor_on_delimiter()
|
||||
normal! 17|yas
|
||||
call assert_equal("A '([sentence.])' ", @")
|
||||
|
||||
" don't get stuck on a quote at the start of a sentence
|
||||
%delete _
|
||||
call setline(1, ['A sentence.', '"A sentence"?', 'A sentence!'])
|
||||
normal gg))
|
||||
call assert_equal(3, getcurpos()[1])
|
||||
|
||||
%delete _
|
||||
call setline(1, ['A sentence.', "'A sentence'?", 'A sentence!'])
|
||||
normal gg))
|
||||
call assert_equal(3, getcurpos()[1])
|
||||
|
||||
%delete _
|
||||
endfunc
|
||||
|
||||
|
@ -185,6 +185,42 @@ def Test_disassemble_store_member()
|
||||
res)
|
||||
enddef
|
||||
|
||||
def s:ListAssign()
|
||||
let x: string
|
||||
let y: string
|
||||
let l: list<any>
|
||||
[x, y; l] = g:stringlist
|
||||
enddef
|
||||
|
||||
def Test_disassemble_list_assign()
|
||||
let res = execute('disass s:ListAssign')
|
||||
assert_match('<SNR>\d*_ListAssign\_s*' ..
|
||||
'let x: string\_s*' ..
|
||||
'\d PUSHS "\[NULL\]"\_s*' ..
|
||||
'\d STORE $0\_s*' ..
|
||||
'let y: string\_s*' ..
|
||||
'\d PUSHS "\[NULL\]"\_s*' ..
|
||||
'\d STORE $1\_s*' ..
|
||||
'let l: list<any>\_s*' ..
|
||||
'\d NEWLIST size 0\_s*' ..
|
||||
'\d STORE $2\_s*' ..
|
||||
'\[x, y; l\] = g:stringlist\_s*' ..
|
||||
'\d LOADG g:stringlist\_s*' ..
|
||||
'\d CHECKTYPE list stack\[-1\]\_s*' ..
|
||||
'\d CHECKLEN >= 2\_s*' ..
|
||||
'\d\+ ITEM 0\_s*' ..
|
||||
'\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
|
||||
'\d\+ STORE $0\_s*' ..
|
||||
'\d\+ ITEM 1\_s*' ..
|
||||
'\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
|
||||
'\d\+ STORE $1\_s*' ..
|
||||
'\d\+ SLICE 2\_s*' ..
|
||||
'\d\+ STORE $2\_s*' ..
|
||||
'\d\+ PUSHNR 0\_s*' ..
|
||||
'\d\+ RETURN',
|
||||
res)
|
||||
enddef
|
||||
|
||||
def s:ScriptFuncUnlet()
|
||||
g:somevar = "value"
|
||||
unlet g:somevar
|
||||
@ -533,6 +569,30 @@ def Test_disassemble_const_expr()
|
||||
assert_notmatch('JUMP', instr)
|
||||
enddef
|
||||
|
||||
def ReturnInIf(): string
|
||||
if g:cond
|
||||
return "yes"
|
||||
else
|
||||
return "no"
|
||||
endif
|
||||
enddef
|
||||
|
||||
def Test_disassemble_return_in_if()
|
||||
let instr = execute('disassemble ReturnInIf')
|
||||
assert_match('ReturnInIf\_s*' ..
|
||||
'if g:cond\_s*' ..
|
||||
'0 LOADG g:cond\_s*' ..
|
||||
'1 JUMP_IF_FALSE -> 4\_s*' ..
|
||||
'return "yes"\_s*' ..
|
||||
'2 PUSHS "yes"\_s*' ..
|
||||
'3 RETURN\_s*' ..
|
||||
'else\_s*' ..
|
||||
' return "no"\_s*' ..
|
||||
'4 PUSHS "no"\_s*' ..
|
||||
'5 RETURN$',
|
||||
instr)
|
||||
enddef
|
||||
|
||||
def WithFunc()
|
||||
let Funky1: func
|
||||
let Funky2: func = function("len")
|
||||
@ -1130,7 +1190,7 @@ def Test_vim9script_forward_func()
|
||||
def FuncTwo(): string
|
||||
return 'two'
|
||||
enddef
|
||||
let g:res_FuncOne: string = execute('disass FuncOne')
|
||||
g:res_FuncOne = execute('disass FuncOne')
|
||||
END
|
||||
writefile(lines, 'Xdisassemble')
|
||||
source Xdisassemble
|
||||
|
@ -524,6 +524,7 @@ def Test_expr5()
|
||||
g:anint)
|
||||
assert_equal(9, g:alsoint + 5)
|
||||
assert_equal(14, g:alsoint + g:anint)
|
||||
assert_equal([1, 2, 3, 4], [1] + g:alist)
|
||||
|
||||
assert_equal(54, 60 - 6)
|
||||
assert_equal(50, 60 -
|
||||
@ -1028,6 +1029,39 @@ def Test_expr7_trailing()
|
||||
assert_equal(123, d.key)
|
||||
enddef
|
||||
|
||||
def Test_expr7_subscript_linebreak()
|
||||
let range = range(
|
||||
3)
|
||||
let l = range->
|
||||
map('string(v:key)')
|
||||
assert_equal(['0', '1', '2'], l)
|
||||
|
||||
l = range
|
||||
->map('string(v:key)')
|
||||
assert_equal(['0', '1', '2'], l)
|
||||
|
||||
l = range # comment
|
||||
->map('string(v:key)')
|
||||
assert_equal(['0', '1', '2'], l)
|
||||
|
||||
l = range
|
||||
|
||||
->map('string(v:key)')
|
||||
assert_equal(['0', '1', '2'], l)
|
||||
|
||||
l = range
|
||||
# comment
|
||||
->map('string(v:key)')
|
||||
assert_equal(['0', '1', '2'], l)
|
||||
|
||||
assert_equal('1', l[
|
||||
1])
|
||||
|
||||
let d = #{one: 33}
|
||||
assert_equal(33, d.
|
||||
one)
|
||||
enddef
|
||||
|
||||
|
||||
func Test_expr7_trailing_fails()
|
||||
call CheckDefFailure(['let l = [2]', 'l->{l -> add(l, 8)}'], 'E107')
|
||||
@ -1043,7 +1077,7 @@ func Test_expr_fails()
|
||||
call CheckDefFailure(["CallMe2('yes' , 'no')"], 'E1068:')
|
||||
|
||||
call CheckDefFailure(["v:nosuch += 3"], 'E1001:')
|
||||
call CheckDefFailure(["let v:statusmsg = ''"], 'E1064:')
|
||||
call CheckDefFailure(["let v:statusmsg = ''"], 'E1016: Cannot declare a v: variable:')
|
||||
call CheckDefFailure(["let asdf = v:nosuch"], 'E1001:')
|
||||
|
||||
call CheckDefFailure(["echo len('asdf'"], 'E110:')
|
||||
|
@ -31,6 +31,31 @@ def Test_return_something()
|
||||
assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
|
||||
enddef
|
||||
|
||||
def Test_missing_return()
|
||||
CheckDefFailure(['def Missing(): number',
|
||||
' if g:cond',
|
||||
' echo "no return"',
|
||||
' else',
|
||||
' return 0',
|
||||
' endif'
|
||||
'enddef'], 'E1027:')
|
||||
CheckDefFailure(['def Missing(): number',
|
||||
' if g:cond',
|
||||
' return 1',
|
||||
' else',
|
||||
' echo "no return"',
|
||||
' endif'
|
||||
'enddef'], 'E1027:')
|
||||
CheckDefFailure(['def Missing(): number',
|
||||
' if g:cond',
|
||||
' return 1',
|
||||
' else',
|
||||
' return 2',
|
||||
' endif'
|
||||
' return 3'
|
||||
'enddef'], 'E1095:')
|
||||
enddef
|
||||
|
||||
let s:nothing = 0
|
||||
def ReturnNothing()
|
||||
s:nothing = 1
|
||||
@ -298,7 +323,7 @@ def Test_vim9script_call()
|
||||
str->MyFunc()
|
||||
assert_equal('barfoo', var)
|
||||
|
||||
let g:value = 'value'
|
||||
g:value = 'value'
|
||||
g:value->MyFunc()
|
||||
assert_equal('value', var)
|
||||
|
||||
@ -807,5 +832,10 @@ def Test_call_closure_not_compiled()
|
||||
assert_equal('sometext', GetResult(g:Ref))
|
||||
enddef
|
||||
|
||||
def Test_sort_return_type()
|
||||
let res: list<number>
|
||||
res = [1, 2, 3]->sort()
|
||||
enddef
|
||||
|
||||
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||
|
@ -1,6 +1,7 @@
|
||||
" Test various aspects of the Vim9 script language.
|
||||
|
||||
source check.vim
|
||||
source term_util.vim
|
||||
source view_util.vim
|
||||
source vim9.vim
|
||||
|
||||
@ -108,6 +109,41 @@ def Test_assignment()
|
||||
call CheckDefFailure(['v:errmsg += 123'], 'E1013:')
|
||||
enddef
|
||||
|
||||
def Test_vim9_single_char_vars()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
|
||||
" single character variable declarations work
|
||||
let a: string
|
||||
let b: number
|
||||
let l: list<any>
|
||||
let s: string
|
||||
let t: number
|
||||
let v: number
|
||||
let w: number
|
||||
|
||||
" script-local variables can be used without s: prefix
|
||||
a = 'script-a'
|
||||
b = 111
|
||||
l = [1, 2, 3]
|
||||
s = 'script-s'
|
||||
t = 222
|
||||
v = 333
|
||||
w = 444
|
||||
|
||||
assert_equal('script-a', a)
|
||||
assert_equal(111, b)
|
||||
assert_equal([1, 2, 3], l)
|
||||
assert_equal('script-s', s)
|
||||
assert_equal(222, t)
|
||||
assert_equal(333, v)
|
||||
assert_equal(444, w)
|
||||
END
|
||||
writefile(lines, 'Xsinglechar')
|
||||
source Xsinglechar
|
||||
delete('Xsinglechar')
|
||||
enddef
|
||||
|
||||
def Test_assignment_list()
|
||||
let list1: list<bool> = [false, true, false]
|
||||
let list2: list<number> = [1, 2, 3]
|
||||
@ -126,6 +162,7 @@ def Test_assignment_list()
|
||||
list2[-3] = 77
|
||||
assert_equal([77, 88, 99], list2)
|
||||
call CheckDefExecFailure(['let ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:')
|
||||
call CheckDefExecFailure(['let [v1, v2] = [1, 2]'], 'E1092:')
|
||||
|
||||
# type becomes list<any>
|
||||
let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
|
||||
@ -138,6 +175,9 @@ def Test_assignment_dict()
|
||||
let dict4: dict<any> = #{one: 1, two: '2'}
|
||||
let dict5: dict<blob> = #{one: 0z01, two: 0z02}
|
||||
|
||||
" overwrite
|
||||
dict3['key'] = 'another'
|
||||
|
||||
call CheckDefExecFailure(['let dd = {}', 'dd[""] = 6'], 'E713:')
|
||||
|
||||
# type becomes dict<any>
|
||||
@ -217,6 +257,13 @@ def Test_assignment_default()
|
||||
|
||||
let thechannel: channel
|
||||
assert_equal(test_null_channel(), thechannel)
|
||||
|
||||
if has('unix') && executable('cat')
|
||||
" check with non-null job and channel, types must match
|
||||
thejob = job_start("cat ", #{})
|
||||
thechannel = job_getchannel(thejob)
|
||||
job_stop(thejob, 'kill')
|
||||
endif
|
||||
endif
|
||||
|
||||
let nr = 1234 | nr = 5678
|
||||
@ -275,15 +322,15 @@ def Test_assignment_failure()
|
||||
call CheckDefFailure(['let &option'], 'E1052:')
|
||||
call CheckDefFailure(['&g:option = 5'], 'E113:')
|
||||
|
||||
call CheckDefFailure(['let $VAR = 5'], 'E1065:')
|
||||
call CheckDefFailure(['let $VAR = 5'], 'E1016: Cannot declare an environment variable:')
|
||||
|
||||
call CheckDefFailure(['let @~ = 5'], 'E354:')
|
||||
call CheckDefFailure(['let @a = 5'], 'E1066:')
|
||||
|
||||
call CheckDefFailure(['let g:var = 5'], 'E1016:')
|
||||
call CheckDefFailure(['let w:var = 5'], 'E1079:')
|
||||
call CheckDefFailure(['let b:var = 5'], 'E1078:')
|
||||
call CheckDefFailure(['let t:var = 5'], 'E1080:')
|
||||
call CheckDefFailure(['let g:var = 5'], 'E1016: Cannot declare a global variable:')
|
||||
call CheckDefFailure(['let w:var = 5'], 'E1016: Cannot declare a window variable:')
|
||||
call CheckDefFailure(['let b:var = 5'], 'E1016: Cannot declare a buffer variable:')
|
||||
call CheckDefFailure(['let t:var = 5'], 'E1016: Cannot declare a tab variable:')
|
||||
|
||||
call CheckDefFailure(['let anr = 4', 'anr ..= "text"'], 'E1019:')
|
||||
call CheckDefFailure(['let xnr += 4'], 'E1020:')
|
||||
@ -773,10 +820,37 @@ def Test_vim9script_fails()
|
||||
CheckScriptFailure(['vim9script', 'export let g:some'], 'E1044:')
|
||||
CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
|
||||
|
||||
CheckScriptFailure(['vim9script', 'let str: string', 'str = 1234'], 'E1013:')
|
||||
CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
|
||||
|
||||
assert_fails('vim9script', 'E1038')
|
||||
assert_fails('export something', 'E1043')
|
||||
enddef
|
||||
|
||||
func Test_import_fails_without_script()
|
||||
CheckRunVimInTerminal
|
||||
|
||||
" call indirectly to avoid compilation error for missing functions
|
||||
call Run_Test_import_fails_without_script()
|
||||
endfunc
|
||||
|
||||
def Run_Test_import_fails_without_script()
|
||||
let export =<< trim END
|
||||
vim9script
|
||||
export def Foo(): number
|
||||
return 0
|
||||
enddef
|
||||
END
|
||||
writefile(export, 'Xexport.vim')
|
||||
|
||||
let buf = RunVimInTerminal('-c "import Foo from ''./Xexport.vim''"', #{
|
||||
rows: 6, wait_for_ruler: 0})
|
||||
WaitForAssert({-> assert_match('^E1094:', term_getline(buf, 5))})
|
||||
|
||||
delete('Xexport.vim')
|
||||
StopVimInTerminal(buf)
|
||||
enddef
|
||||
|
||||
def Test_vim9script_reload_import()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
@ -1025,11 +1099,11 @@ def Test_if_const_expr()
|
||||
|
||||
g:glob = 2
|
||||
if false
|
||||
execute('let g:glob = 3')
|
||||
execute('g:glob = 3')
|
||||
endif
|
||||
assert_equal(2, g:glob)
|
||||
if true
|
||||
execute('let g:glob = 3')
|
||||
execute('g:glob = 3')
|
||||
endif
|
||||
assert_equal(3, g:glob)
|
||||
|
||||
@ -1137,6 +1211,26 @@ def Test_if_const_expr_fails()
|
||||
call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
|
||||
enddef
|
||||
|
||||
def RunNested(i: number): number
|
||||
let x: number = 0
|
||||
if i % 2
|
||||
if 1
|
||||
" comment
|
||||
else
|
||||
" comment
|
||||
endif
|
||||
x += 1
|
||||
else
|
||||
x += 1000
|
||||
endif
|
||||
return x
|
||||
enddef
|
||||
|
||||
def Test_nested_if()
|
||||
assert_equal(1, RunNested(1))
|
||||
assert_equal(1000, RunNested(2))
|
||||
enddef
|
||||
|
||||
def Test_execute_cmd()
|
||||
new
|
||||
setline(1, 'default')
|
||||
@ -1696,8 +1790,8 @@ def Test_vim9_comment_gui()
|
||||
enddef
|
||||
|
||||
def Test_vim9_comment_not_compiled()
|
||||
au TabEnter *.vim let g:entered = 1
|
||||
au TabEnter *.x let g:entered = 2
|
||||
au TabEnter *.vim g:entered = 1
|
||||
au TabEnter *.x g:entered = 2
|
||||
|
||||
edit test.vim
|
||||
doautocmd TabEnter #comment
|
||||
@ -1717,14 +1811,46 @@ def Test_vim9_comment_not_compiled()
|
||||
|
||||
CheckScriptSuccess([
|
||||
'vim9script',
|
||||
'let g:var = 123',
|
||||
'let w:var = 777',
|
||||
'g:var = 123',
|
||||
'b:var = 456',
|
||||
'w:var = 777',
|
||||
't:var = 888',
|
||||
'unlet g:var w:var # something',
|
||||
])
|
||||
|
||||
CheckScriptFailure([
|
||||
'vim9script',
|
||||
'let g:var = 123',
|
||||
], 'E1016: Cannot declare a global variable:')
|
||||
|
||||
CheckScriptFailure([
|
||||
'vim9script',
|
||||
'let b:var = 123',
|
||||
], 'E1016: Cannot declare a buffer variable:')
|
||||
|
||||
CheckScriptFailure([
|
||||
'vim9script',
|
||||
'let w:var = 123',
|
||||
], 'E1016: Cannot declare a window variable:')
|
||||
|
||||
CheckScriptFailure([
|
||||
'vim9script',
|
||||
'let t:var = 123',
|
||||
], 'E1016: Cannot declare a tab variable:')
|
||||
|
||||
CheckScriptFailure([
|
||||
'vim9script',
|
||||
'let v:version = 123',
|
||||
], 'E1016: Cannot declare a v: variable:')
|
||||
|
||||
CheckScriptFailure([
|
||||
'vim9script',
|
||||
'let $VARIABLE = "text"',
|
||||
], 'E1016: Cannot declare an environment variable:')
|
||||
|
||||
CheckScriptFailure([
|
||||
'vim9script',
|
||||
'g:var = 123',
|
||||
'unlet g:var# comment1',
|
||||
], 'E108:')
|
||||
|
||||
@ -1795,11 +1921,11 @@ enddef
|
||||
def Test_finish()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
let g:res = 'one'
|
||||
g:res = 'one'
|
||||
if v:false | finish | endif
|
||||
let g:res = 'two'
|
||||
g:res = 'two'
|
||||
finish
|
||||
let g:res = 'three'
|
||||
g:res = 'three'
|
||||
END
|
||||
writefile(lines, 'Xfinished')
|
||||
source Xfinished
|
||||
@ -1875,6 +2001,20 @@ def Test_let_declaration()
|
||||
unlet g:other_var
|
||||
enddef
|
||||
|
||||
def Test_let_declaration_fails()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
const var: string
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1021:')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
let 9var: string
|
||||
END
|
||||
CheckScriptFailure(lines, 'E475:')
|
||||
enddef
|
||||
|
||||
def Test_let_type_check()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
@ -1888,6 +2028,12 @@ def Test_let_type_check()
|
||||
let var:string
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1069:')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
let var: asdf
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1010:')
|
||||
enddef
|
||||
|
||||
def Test_forward_declaration()
|
||||
|
@ -87,6 +87,28 @@ func Test_global_vars()
|
||||
call assert_equal(test_null, g:MY_GLOBAL_NULL)
|
||||
call assert_equal(test_none, g:MY_GLOBAL_NONE)
|
||||
|
||||
" Test for invalid values for a blob, list, dict in a viminfo file
|
||||
call writefile([
|
||||
\ "!GLOB_BLOB_1\tBLO\t123",
|
||||
\ "!GLOB_BLOB_2\tBLO\t012",
|
||||
\ "!GLOB_BLOB_3\tBLO\t0z1x",
|
||||
\ "!GLOB_BLOB_4\tBLO\t0z12 ab",
|
||||
\ "!GLOB_LIST_1\tLIS\t1 2",
|
||||
\ "!GLOB_DICT_1\tDIC\t1 2"], 'Xviminfo')
|
||||
call assert_fails('rv! Xviminfo', 'E15:')
|
||||
call assert_equal('123', g:GLOB_BLOB_1)
|
||||
call assert_equal(1, type(g:GLOB_BLOB_1))
|
||||
call assert_equal('012', g:GLOB_BLOB_2)
|
||||
call assert_equal(1, type(g:GLOB_BLOB_2))
|
||||
call assert_equal('0z1x', g:GLOB_BLOB_3)
|
||||
call assert_equal(1, type(g:GLOB_BLOB_3))
|
||||
call assert_equal('0z12 ab', g:GLOB_BLOB_4)
|
||||
call assert_equal(1, type(g:GLOB_BLOB_4))
|
||||
call assert_equal('1 2', g:GLOB_LIST_1)
|
||||
call assert_equal(1, type(g:GLOB_LIST_1))
|
||||
call assert_equal('1 2', g:GLOB_DICT_1)
|
||||
call assert_equal(1, type(g:GLOB_DICT_1))
|
||||
|
||||
call delete('Xviminfo')
|
||||
set viminfo-=!
|
||||
endfunc
|
||||
|
@ -357,4 +357,22 @@ func Test_delete_break_tab()
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for using <BS>, <C-W> and <C-U> in virtual edit mode
|
||||
" to erase character, word and line.
|
||||
func Test_ve_backspace()
|
||||
new
|
||||
call setline(1, 'sample')
|
||||
set virtualedit=all
|
||||
set backspace=indent,eol,start
|
||||
exe "normal 15|i\<BS>\<BS>"
|
||||
call assert_equal([0, 1, 7, 5], getpos('.'))
|
||||
exe "normal 15|i\<C-W>"
|
||||
call assert_equal([0, 1, 6, 0], getpos('.'))
|
||||
exe "normal 15|i\<C-U>"
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
set backspace&
|
||||
set virtualedit&
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -208,6 +208,15 @@ func Test_virtual_replace()
|
||||
exe "normal iabcdefghijklmnopqrst\<Esc>0gRAB\tIJKLMNO\tQR"
|
||||
call assert_equal(['AB......CDEFGHI.Jkl',
|
||||
\ 'AB IJKLMNO QRst'], getline(12, 13))
|
||||
|
||||
" Test inserting Tab with 'noexpandtab' and 'softabstop' set to 4
|
||||
%d
|
||||
call setline(1, 'aaaaaaaaaaaaa')
|
||||
set softtabstop=4
|
||||
exe "normal gggR\<Tab>\<Tab>x"
|
||||
call assert_equal("\txaaaa", getline(1))
|
||||
set softtabstop&
|
||||
|
||||
enew!
|
||||
set noai bs&vim
|
||||
if exists('save_t_kD')
|
||||
|
@ -26,6 +26,7 @@ static int skip_chars(int, int);
|
||||
findsent(int dir, long count)
|
||||
{
|
||||
pos_T pos, tpos;
|
||||
pos_T prev_pos;
|
||||
int c;
|
||||
int (*func)(pos_T *);
|
||||
int startlnum;
|
||||
@ -41,6 +42,8 @@ findsent(int dir, long count)
|
||||
|
||||
while (count--)
|
||||
{
|
||||
prev_pos = pos;
|
||||
|
||||
/*
|
||||
* if on an empty line, skip up to a non-empty line
|
||||
*/
|
||||
@ -133,6 +136,18 @@ found:
|
||||
while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
|
||||
if (incl(&pos) == -1)
|
||||
break;
|
||||
|
||||
if (EQUAL_POS(prev_pos, pos))
|
||||
{
|
||||
// didn't actually move, advance one character and try again
|
||||
if ((*func)(&pos) == -1)
|
||||
{
|
||||
if (count)
|
||||
return FAIL;
|
||||
break;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
setpcmark();
|
||||
|
49
src/typval.c
49
src/typval.c
@ -1182,7 +1182,7 @@ get_number_tv(
|
||||
get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
|
||||
{
|
||||
char_u *p;
|
||||
char_u *name;
|
||||
char_u *end;
|
||||
int extra = 0;
|
||||
int len;
|
||||
|
||||
@ -1216,12 +1216,12 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
|
||||
|
||||
// Copy the string into allocated memory, handling backslashed
|
||||
// characters.
|
||||
len = (int)(p - *arg + extra);
|
||||
name = alloc(len);
|
||||
if (name == NULL)
|
||||
return FAIL;
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = name;
|
||||
len = (int)(p - *arg + extra);
|
||||
rettv->vval.v_string = alloc(len);
|
||||
if (rettv->vval.v_string == NULL)
|
||||
return FAIL;
|
||||
end = rettv->vval.v_string;
|
||||
|
||||
for (p = *arg + 1; *p != NUL && *p != '"'; )
|
||||
{
|
||||
@ -1229,12 +1229,12 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
|
||||
{
|
||||
switch (*++p)
|
||||
{
|
||||
case 'b': *name++ = BS; ++p; break;
|
||||
case 'e': *name++ = ESC; ++p; break;
|
||||
case 'f': *name++ = FF; ++p; break;
|
||||
case 'n': *name++ = NL; ++p; break;
|
||||
case 'r': *name++ = CAR; ++p; break;
|
||||
case 't': *name++ = TAB; ++p; break;
|
||||
case 'b': *end++ = BS; ++p; break;
|
||||
case 'e': *end++ = ESC; ++p; break;
|
||||
case 'f': *end++ = FF; ++p; break;
|
||||
case 'n': *end++ = NL; ++p; break;
|
||||
case 'r': *end++ = CAR; ++p; break;
|
||||
case 't': *end++ = TAB; ++p; break;
|
||||
|
||||
case 'X': // hex: "\x1", "\x12"
|
||||
case 'x':
|
||||
@ -1261,9 +1261,9 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
|
||||
// For "\u" store the number according to
|
||||
// 'encoding'.
|
||||
if (c != 'X')
|
||||
name += (*mb_char2bytes)(nr, name);
|
||||
end += (*mb_char2bytes)(nr, end);
|
||||
else
|
||||
*name++ = nr;
|
||||
*end++ = nr;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1275,14 +1275,14 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7': *name = *p++ - '0';
|
||||
case '7': *end = *p++ - '0';
|
||||
if (*p >= '0' && *p <= '7')
|
||||
{
|
||||
*name = (*name << 3) + *p++ - '0';
|
||||
*end = (*end << 3) + *p++ - '0';
|
||||
if (*p >= '0' && *p <= '7')
|
||||
*name = (*name << 3) + *p++ - '0';
|
||||
*end = (*end << 3) + *p++ - '0';
|
||||
}
|
||||
++name;
|
||||
++end;
|
||||
break;
|
||||
|
||||
// Special key, e.g.: "\<C-W>"
|
||||
@ -1292,26 +1292,25 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
|
||||
|
||||
if (p[1] != '*')
|
||||
flags |= FSK_SIMPLIFY;
|
||||
extra = trans_special(&p, name, flags, NULL);
|
||||
extra = trans_special(&p, end, flags, NULL);
|
||||
if (extra != 0)
|
||||
{
|
||||
name += extra;
|
||||
if (name >= rettv->vval.v_string + len)
|
||||
end += extra;
|
||||
if (end >= rettv->vval.v_string + len)
|
||||
iemsg("get_string_tv() used more space than allocated");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// FALLTHROUGH
|
||||
|
||||
default: MB_COPY_CHAR(p, name);
|
||||
default: MB_COPY_CHAR(p, end);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
MB_COPY_CHAR(p, name);
|
||||
|
||||
MB_COPY_CHAR(p, end);
|
||||
}
|
||||
*name = NUL;
|
||||
*end = NUL;
|
||||
if (*p != NUL) // just in case
|
||||
++p;
|
||||
*arg = p;
|
||||
|
@ -409,7 +409,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
||||
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
||||
if (fp == NULL)
|
||||
goto errret;
|
||||
fp->uf_dfunc_idx = UF_NOT_COMPILED;
|
||||
fp->uf_def_status = UF_NOT_COMPILED;
|
||||
pt = ALLOC_CLEAR_ONE(partial_T);
|
||||
if (pt == NULL)
|
||||
goto errret;
|
||||
@ -1001,7 +1001,7 @@ func_remove(ufunc_T *fp)
|
||||
{
|
||||
// When there is a def-function index do not actually remove the
|
||||
// function, so we can find the index when defining the function again.
|
||||
if (fp->uf_dfunc_idx >= 0)
|
||||
if (fp->uf_def_status == UF_COMPILED)
|
||||
fp->uf_flags |= FC_DEAD;
|
||||
else
|
||||
hash_remove(&func_hashtab, hi);
|
||||
@ -1046,7 +1046,7 @@ func_clear(ufunc_T *fp, int force)
|
||||
// clear this function
|
||||
func_clear_items(fp);
|
||||
funccal_unref(fp->uf_scoped, fp, force);
|
||||
delete_def_function(fp);
|
||||
clear_def_function(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1074,7 +1074,8 @@ func_free(ufunc_T *fp, int force)
|
||||
func_clear_free(ufunc_T *fp, int force)
|
||||
{
|
||||
func_clear(fp, force);
|
||||
func_free(fp, force);
|
||||
if (force || fp->uf_dfunc_idx == 0)
|
||||
func_free(fp, force);
|
||||
}
|
||||
|
||||
|
||||
@ -1137,7 +1138,7 @@ call_user_func(
|
||||
ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
|
||||
func_ptr_ref(fp);
|
||||
|
||||
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
if (fp->uf_def_status != UF_NOT_COMPILED)
|
||||
{
|
||||
estack_push_ufunc(fp, 1);
|
||||
save_current_sctx = current_sctx;
|
||||
@ -1662,7 +1663,7 @@ free_all_functions(void)
|
||||
// clear the def function index now
|
||||
fp = HI2UF(hi);
|
||||
fp->uf_flags &= ~FC_DEAD;
|
||||
fp->uf_dfunc_idx = UF_NOT_COMPILED;
|
||||
fp->uf_def_status = UF_NOT_COMPILED;
|
||||
|
||||
// Only free functions that are not refcounted, those are
|
||||
// supposed to be freed when no longer referenced.
|
||||
@ -2058,7 +2059,7 @@ list_func_head(ufunc_T *fp, int indent)
|
||||
msg_start();
|
||||
if (indent)
|
||||
msg_puts(" ");
|
||||
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
if (fp->uf_def_status != UF_NOT_COMPILED)
|
||||
msg_puts("def ");
|
||||
else
|
||||
msg_puts("function ");
|
||||
@ -2107,7 +2108,7 @@ list_func_head(ufunc_T *fp, int indent)
|
||||
}
|
||||
msg_putchar(')');
|
||||
|
||||
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
if (fp->uf_def_status != UF_NOT_COMPILED)
|
||||
{
|
||||
if (fp->uf_ret_type != &t_void)
|
||||
{
|
||||
@ -2624,7 +2625,7 @@ def_function(exarg_T *eap, char_u *name_arg)
|
||||
if (!got_int)
|
||||
{
|
||||
msg_putchar('\n');
|
||||
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
if (fp->uf_def_status != UF_NOT_COMPILED)
|
||||
msg_puts(" enddef");
|
||||
else
|
||||
msg_puts(" endfunction");
|
||||
@ -3097,6 +3098,7 @@ def_function(exarg_T *eap, char_u *name_arg)
|
||||
fp->uf_profiling = FALSE;
|
||||
fp->uf_prof_initialized = FALSE;
|
||||
#endif
|
||||
clear_def_function(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3162,7 +3164,7 @@ def_function(exarg_T *eap, char_u *name_arg)
|
||||
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
||||
if (fp == NULL)
|
||||
goto erret;
|
||||
fp->uf_dfunc_idx = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
|
||||
fp->uf_def_status = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
|
||||
: UF_NOT_COMPILED;
|
||||
|
||||
if (fudi.fd_dict != NULL)
|
||||
@ -3219,7 +3221,7 @@ def_function(exarg_T *eap, char_u *name_arg)
|
||||
{
|
||||
int lnum_save = SOURCING_LNUM;
|
||||
|
||||
fp->uf_dfunc_idx = UF_TO_BE_COMPILED;
|
||||
fp->uf_def_status = UF_TO_BE_COMPILED;
|
||||
|
||||
// error messages are for the first function line
|
||||
SOURCING_LNUM = sourcing_lnum_top;
|
||||
@ -3289,7 +3291,7 @@ def_function(exarg_T *eap, char_u *name_arg)
|
||||
SOURCING_LNUM = lnum_save;
|
||||
}
|
||||
else
|
||||
fp->uf_dfunc_idx = UF_NOT_COMPILED;
|
||||
fp->uf_def_status = UF_NOT_COMPILED;
|
||||
|
||||
fp->uf_lines = newlines;
|
||||
if ((flags & FC_CLOSURE) != 0)
|
||||
@ -3323,6 +3325,9 @@ def_function(exarg_T *eap, char_u *name_arg)
|
||||
|
||||
if (eap->cmdidx == CMD_def)
|
||||
set_function_type(fp);
|
||||
else if (fp->uf_script_ctx.sc_version == SCRIPT_VERSION_VIM9)
|
||||
// :func does not use Vim9 script syntax, even in a Vim9 script file
|
||||
fp->uf_script_ctx.sc_version = SCRIPT_VERSION_MAX;
|
||||
|
||||
goto ret_free;
|
||||
|
||||
@ -3372,7 +3377,7 @@ ex_defcompile(exarg_T *eap UNUSED)
|
||||
--todo;
|
||||
ufunc = HI2UF(hi);
|
||||
if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
|
||||
&& ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
|
||||
&& ufunc->uf_def_status == UF_TO_BE_COMPILED)
|
||||
{
|
||||
compile_def_function(ufunc, FALSE, NULL);
|
||||
|
||||
|
@ -754,6 +754,96 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1036,
|
||||
/**/
|
||||
1035,
|
||||
/**/
|
||||
1034,
|
||||
/**/
|
||||
1033,
|
||||
/**/
|
||||
1032,
|
||||
/**/
|
||||
1031,
|
||||
/**/
|
||||
1030,
|
||||
/**/
|
||||
1029,
|
||||
/**/
|
||||
1028,
|
||||
/**/
|
||||
1027,
|
||||
/**/
|
||||
1026,
|
||||
/**/
|
||||
1025,
|
||||
/**/
|
||||
1024,
|
||||
/**/
|
||||
1023,
|
||||
/**/
|
||||
1022,
|
||||
/**/
|
||||
1021,
|
||||
/**/
|
||||
1020,
|
||||
/**/
|
||||
1019,
|
||||
/**/
|
||||
1018,
|
||||
/**/
|
||||
1017,
|
||||
/**/
|
||||
1016,
|
||||
/**/
|
||||
1015,
|
||||
/**/
|
||||
1014,
|
||||
/**/
|
||||
1013,
|
||||
/**/
|
||||
1012,
|
||||
/**/
|
||||
1011,
|
||||
/**/
|
||||
1010,
|
||||
/**/
|
||||
1009,
|
||||
/**/
|
||||
1008,
|
||||
/**/
|
||||
1007,
|
||||
/**/
|
||||
1006,
|
||||
/**/
|
||||
1005,
|
||||
/**/
|
||||
1004,
|
||||
/**/
|
||||
1003,
|
||||
/**/
|
||||
1002,
|
||||
/**/
|
||||
1001,
|
||||
/**/
|
||||
1000,
|
||||
/**/
|
||||
999,
|
||||
/**/
|
||||
998,
|
||||
/**/
|
||||
997,
|
||||
/**/
|
||||
996,
|
||||
/**/
|
||||
995,
|
||||
/**/
|
||||
994,
|
||||
/**/
|
||||
993,
|
||||
/**/
|
||||
992,
|
||||
/**/
|
||||
991,
|
||||
/**/
|
||||
|
@ -23,6 +23,13 @@
|
||||
#define DEFINE_VIM9_GLOBALS
|
||||
#include "vim9.h"
|
||||
|
||||
// values for ctx_skip
|
||||
typedef enum {
|
||||
SKIP_NOT, // condition is a constant, produce code
|
||||
SKIP_YES, // condition is a constant, do NOT produce code
|
||||
SKIP_UNKNOWN // condition is not a constant, produce code
|
||||
} skip_T;
|
||||
|
||||
/*
|
||||
* Chain of jump instructions where the end label needs to be set.
|
||||
*/
|
||||
@ -36,6 +43,8 @@ struct endlabel_S {
|
||||
* info specific for the scope of :if / elseif / else
|
||||
*/
|
||||
typedef struct {
|
||||
int is_seen_else;
|
||||
int is_had_return; // every block ends in :return
|
||||
int is_if_label; // instruction idx at IF or ELSEIF
|
||||
endlabel_T *is_end_label; // instructions to set end label
|
||||
} ifscope_T;
|
||||
@ -83,6 +92,7 @@ struct scope_S {
|
||||
scope_T *se_outer; // scope containing this one
|
||||
scopetype_T se_type;
|
||||
int se_local_count; // ctx_locals.ga_len before scope
|
||||
skip_T se_skip_save; // ctx_skip before the block
|
||||
union {
|
||||
ifscope_T se_if;
|
||||
whilescope_T se_while;
|
||||
@ -121,9 +131,9 @@ struct cctx_S {
|
||||
|
||||
garray_T ctx_imports; // imported items
|
||||
|
||||
int ctx_skip; // when TRUE skip commands, when FALSE skip
|
||||
// commands after "else"
|
||||
skip_T ctx_skip;
|
||||
scope_T *ctx_scope; // current scope, NULL at toplevel
|
||||
int ctx_had_return; // last seen statement was "return"
|
||||
|
||||
cctx_T *ctx_outer; // outer scope for lambda or nested
|
||||
// function
|
||||
@ -545,8 +555,8 @@ check_type(type_T *expected, type_T *actual, int give_msg)
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Following generate_ functions expect the caller to call ga_grow().
|
||||
|
||||
#define RETURN_NULL_IF_SKIP(cctx) if (cctx->ctx_skip == TRUE) return NULL
|
||||
#define RETURN_OK_IF_SKIP(cctx) if (cctx->ctx_skip == TRUE) return OK
|
||||
#define RETURN_NULL_IF_SKIP(cctx) if (cctx->ctx_skip == SKIP_YES) return NULL
|
||||
#define RETURN_OK_IF_SKIP(cctx) if (cctx->ctx_skip == SKIP_YES) return OK
|
||||
|
||||
/*
|
||||
* Generate an instruction without arguments.
|
||||
@ -1483,7 +1493,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
if (ufunc->uf_def_status != UF_NOT_COMPILED)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1507,16 +1517,16 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
|
||||
if (ufunc->uf_def_status == UF_TO_BE_COMPILED)
|
||||
if (compile_def_function(ufunc, TRUE, NULL) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if ((isn = generate_instr(cctx,
|
||||
ufunc->uf_dfunc_idx != UF_NOT_COMPILED ? ISN_DCALL
|
||||
ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL
|
||||
: ISN_UCALL)) == NULL)
|
||||
return FAIL;
|
||||
if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
if (ufunc->uf_def_status != UF_NOT_COMPILED)
|
||||
{
|
||||
isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
|
||||
isn->isn_arg.dfunc.cdf_argcount = argcount;
|
||||
@ -2370,12 +2380,43 @@ free_imported(cctx_T *cctx)
|
||||
ga_clear(&cctx->ctx_imports);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if "p" points at a "#" but not at "#{".
|
||||
*/
|
||||
static int
|
||||
comment_start(char_u *p)
|
||||
{
|
||||
return p[0] == '#' && p[1] != '{';
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a pointer to the next line that isn't empty or only contains a
|
||||
* comment. Skips over white space.
|
||||
* Returns NULL if there is none.
|
||||
*/
|
||||
static char_u *
|
||||
peek_next_line(cctx_T *cctx)
|
||||
{
|
||||
int lnum = cctx->ctx_lnum;
|
||||
|
||||
while (++lnum < cctx->ctx_ufunc->uf_lines.ga_len)
|
||||
{
|
||||
char_u *line = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[lnum];
|
||||
char_u *p = skipwhite(line);
|
||||
|
||||
if (*p != NUL && !comment_start(p))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next line of the function from "cctx".
|
||||
* Skips over empty lines. Skips over comment lines if "skip_comment" is TRUE.
|
||||
* Returns NULL when at the end.
|
||||
*/
|
||||
static char_u *
|
||||
next_line_from_context(cctx_T *cctx)
|
||||
next_line_from_context(cctx_T *cctx, int skip_comment)
|
||||
{
|
||||
char_u *line;
|
||||
|
||||
@ -2390,19 +2431,11 @@ next_line_from_context(cctx_T *cctx)
|
||||
line = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum];
|
||||
cctx->ctx_line_start = line;
|
||||
SOURCING_LNUM = cctx->ctx_lnum + 1;
|
||||
} while (line == NULL || *skipwhite(line) == NUL);
|
||||
} while (line == NULL || *skipwhite(line) == NUL
|
||||
|| (skip_comment && comment_start(skipwhite(line))));
|
||||
return line;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if "p" points at a "#" but not at "#{".
|
||||
*/
|
||||
static int
|
||||
comment_start(char_u *p)
|
||||
{
|
||||
return p[0] == '#' && p[1] != '{';
|
||||
}
|
||||
|
||||
/*
|
||||
* If "*arg" is at the end of the line, advance to the next line.
|
||||
* Also when "whitep" points to white space and "*arg" is on a "#".
|
||||
@ -2413,7 +2446,7 @@ may_get_next_line(char_u *whitep, char_u **arg, cctx_T *cctx)
|
||||
{
|
||||
if (**arg == NUL || (VIM_ISWHITE(*whitep) && comment_start(*arg)))
|
||||
{
|
||||
char_u *next = next_line_from_context(cctx);
|
||||
char_u *next = next_line_from_context(cctx, TRUE);
|
||||
|
||||
if (next == NULL)
|
||||
return FAIL;
|
||||
@ -2493,7 +2526,7 @@ generate_ppconst(cctx_T *cctx, ppconst_T *ppconst)
|
||||
int ret = OK;
|
||||
int save_skip = cctx->ctx_skip;
|
||||
|
||||
cctx->ctx_skip = FALSE;
|
||||
cctx->ctx_skip = SKIP_NOT;
|
||||
for (i = 0; i < ppconst->pp_used; ++i)
|
||||
if (generate_tv_PUSH(cctx, &ppconst->pp_tv[i]) == FAIL)
|
||||
ret = FAIL;
|
||||
@ -2742,14 +2775,8 @@ compile_arguments(char_u **arg, cctx_T *cctx, int *argcount)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (*p == NUL || (VIM_ISWHITE(*whitep) && comment_start(p)))
|
||||
{
|
||||
p = next_line_from_context(cctx);
|
||||
if (p == NULL)
|
||||
goto failret;
|
||||
whitep = (char_u *)" ";
|
||||
p = skipwhite(p);
|
||||
}
|
||||
if (may_get_next_line(whitep, &p, cctx) == FAIL)
|
||||
goto failret;
|
||||
if (*p == ')')
|
||||
{
|
||||
*arg = p + 1;
|
||||
@ -2976,16 +3003,10 @@ compile_list(char_u **arg, cctx_T *cctx)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (*p == NUL || (VIM_ISWHITE(*whitep) && comment_start(p)))
|
||||
if (may_get_next_line(whitep, &p, cctx) == FAIL)
|
||||
{
|
||||
p = next_line_from_context(cctx);
|
||||
if (p == NULL)
|
||||
{
|
||||
semsg(_(e_list_end), *arg);
|
||||
return FAIL;
|
||||
}
|
||||
whitep = (char_u *)" ";
|
||||
p = skipwhite(p);
|
||||
semsg(_(e_list_end), *arg);
|
||||
return FAIL;
|
||||
}
|
||||
if (*p == ']')
|
||||
{
|
||||
@ -3032,7 +3053,7 @@ compile_lambda(char_u **arg, cctx_T *cctx)
|
||||
// Compile it into instructions.
|
||||
compile_def_function(ufunc, TRUE, cctx);
|
||||
|
||||
if (ufunc->uf_dfunc_idx >= 0)
|
||||
if (ufunc->uf_def_status == UF_COMPILED)
|
||||
return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
|
||||
return FAIL;
|
||||
}
|
||||
@ -3102,14 +3123,10 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal)
|
||||
{
|
||||
char_u *key = NULL;
|
||||
|
||||
while (**arg == NUL || (literal && **arg == '"')
|
||||
|| (VIM_ISWHITE(*whitep) && comment_start(*arg)))
|
||||
if (may_get_next_line(whitep, arg, cctx) == FAIL)
|
||||
{
|
||||
*arg = next_line_from_context(cctx);
|
||||
if (*arg == NULL)
|
||||
goto failret;
|
||||
whitep = (char_u *)" ";
|
||||
*arg = skipwhite(*arg);
|
||||
*arg = NULL;
|
||||
goto failret;
|
||||
}
|
||||
|
||||
if (**arg == '}')
|
||||
@ -3169,13 +3186,10 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal)
|
||||
|
||||
whitep = *arg + 1;
|
||||
*arg = skipwhite(*arg + 1);
|
||||
while (**arg == NUL || (VIM_ISWHITE(*whitep) && comment_start(*arg)))
|
||||
if (may_get_next_line(whitep, arg, cctx) == FAIL)
|
||||
{
|
||||
*arg = next_line_from_context(cctx);
|
||||
if (*arg == NULL)
|
||||
goto failret;
|
||||
whitep = (char_u *)" ";
|
||||
*arg = skipwhite(*arg);
|
||||
*arg = NULL;
|
||||
goto failret;
|
||||
}
|
||||
|
||||
if (compile_expr0(arg, cctx) == FAIL)
|
||||
@ -3183,15 +3197,11 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal)
|
||||
++count;
|
||||
|
||||
whitep = *arg;
|
||||
p = skipwhite(*arg);
|
||||
while (*p == NUL || (VIM_ISWHITE(*whitep) && comment_start(p)))
|
||||
*arg = skipwhite(*arg);
|
||||
if (may_get_next_line(whitep, arg, cctx) == FAIL)
|
||||
{
|
||||
*arg = next_line_from_context(cctx);
|
||||
if (*arg == NULL)
|
||||
goto failret;
|
||||
whitep = (char_u *)" ";
|
||||
*arg = skipwhite(*arg);
|
||||
p = *arg;
|
||||
*arg = NULL;
|
||||
goto failret;
|
||||
}
|
||||
if (**arg == '}')
|
||||
break;
|
||||
@ -3496,6 +3506,24 @@ compile_subscript(
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
char_u *p = skipwhite(*arg);
|
||||
|
||||
if (*p == NUL || (VIM_ISWHITE(**arg) && comment_start(p)))
|
||||
{
|
||||
char_u *next = peek_next_line(cctx);
|
||||
|
||||
// If a following line starts with "->{" or "->X" advance to that
|
||||
// line, so that a line break before "->" is allowed.
|
||||
if (next != NULL && next[0] == '-' && next[1] == '>'
|
||||
&& (next[2] == '{' || ASCII_ISALPHA(next[2])))
|
||||
{
|
||||
next = next_line_from_context(cctx, TRUE);
|
||||
if (next == NULL)
|
||||
return FAIL;
|
||||
*arg = skipwhite(next);
|
||||
}
|
||||
}
|
||||
|
||||
if (**arg == '(')
|
||||
{
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
@ -3516,8 +3544,6 @@ compile_subscript(
|
||||
}
|
||||
else if (**arg == '-' && (*arg)[1] == '>')
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
if (generate_ppconst(cctx, ppconst) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
@ -3528,7 +3554,10 @@ compile_subscript(
|
||||
return FAIL;
|
||||
*start_leader = end_leader; // don't apply again later
|
||||
|
||||
*arg = skipwhite(*arg + 2);
|
||||
p = *arg + 2;
|
||||
*arg = skipwhite(p);
|
||||
if (may_get_next_line(p, arg, cctx) == FAIL)
|
||||
return FAIL;
|
||||
if (**arg == '{')
|
||||
{
|
||||
// lambda call: list->{lambda}
|
||||
@ -3566,7 +3595,10 @@ compile_subscript(
|
||||
if (generate_ppconst(cctx, ppconst) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
*arg = skipwhite(*arg + 1);
|
||||
p = *arg + 1;
|
||||
*arg = skipwhite(p);
|
||||
if (may_get_next_line(p, arg, cctx) == FAIL)
|
||||
return FAIL;
|
||||
if (compile_expr0(arg, cctx) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
@ -3601,14 +3633,14 @@ compile_subscript(
|
||||
}
|
||||
else if (**arg == '.' && (*arg)[1] != '.')
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
if (generate_ppconst(cctx, ppconst) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
++*arg;
|
||||
p = *arg;
|
||||
if (may_get_next_line(*arg, arg, cctx) == FAIL)
|
||||
return FAIL;
|
||||
// dictionary member: dict.name
|
||||
p = *arg;
|
||||
if (eval_isnamec1(*p))
|
||||
while (eval_isnamec(*p))
|
||||
MB_PTR_ADV(p);
|
||||
@ -3851,7 +3883,7 @@ compile_expr7(
|
||||
}
|
||||
start_leader = end_leader; // don't apply again below
|
||||
|
||||
if (cctx->ctx_skip == TRUE)
|
||||
if (cctx->ctx_skip == SKIP_YES)
|
||||
clear_tv(rettv);
|
||||
else
|
||||
// A constant expression can possibly be handled compile time,
|
||||
@ -4325,9 +4357,9 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
garray_T *instr = &cctx->ctx_instr;
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
int alt_idx = instr->ga_len;
|
||||
int end_idx;
|
||||
int end_idx = 0;
|
||||
isn_T *isn;
|
||||
type_T *type1;
|
||||
type_T *type1 = NULL;
|
||||
type_T *type2;
|
||||
int has_const_expr = FALSE;
|
||||
int const_value = FALSE;
|
||||
@ -4347,7 +4379,8 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
const_value = tv2bool(&ppconst->pp_tv[ppconst_used]);
|
||||
clear_tv(&ppconst->pp_tv[ppconst_used]);
|
||||
--ppconst->pp_used;
|
||||
cctx->ctx_skip = save_skip == TRUE || !const_value;
|
||||
cctx->ctx_skip = save_skip == SKIP_YES || !const_value
|
||||
? SKIP_YES : SKIP_NOT;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -4393,7 +4426,8 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
|
||||
// evaluate the third expression
|
||||
if (has_const_expr)
|
||||
cctx->ctx_skip = save_skip == TRUE || const_value;
|
||||
cctx->ctx_skip = save_skip == SKIP_YES || const_value
|
||||
? SKIP_YES : SKIP_NOT;
|
||||
*arg = skipwhite(p + 1);
|
||||
if (may_get_next_line(p + 1, arg, cctx) == FAIL)
|
||||
return FAIL;
|
||||
@ -4521,13 +4555,13 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
|
||||
eap->arg = name_end;
|
||||
eap->getline = exarg_getline;
|
||||
eap->cookie = cctx;
|
||||
eap->skip = cctx->ctx_skip == TRUE;
|
||||
eap->skip = cctx->ctx_skip == SKIP_YES;
|
||||
eap->forceit = FALSE;
|
||||
ufunc = def_function(eap, name);
|
||||
|
||||
if (ufunc == NULL)
|
||||
return NULL;
|
||||
if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
|
||||
if (ufunc->uf_def_status == UF_TO_BE_COMPILED
|
||||
&& compile_def_function(ufunc, TRUE, cctx) == FAIL)
|
||||
return NULL;
|
||||
|
||||
@ -4638,6 +4672,24 @@ generate_loadvar(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vim9_declare_error(char_u *name)
|
||||
{
|
||||
char *scope = "";
|
||||
|
||||
switch (*name)
|
||||
{
|
||||
case 'g': scope = _("global"); break;
|
||||
case 'b': scope = _("buffer"); break;
|
||||
case 'w': scope = _("window"); break;
|
||||
case 't': scope = _("tab"); break;
|
||||
case 'v': scope = "v:"; break;
|
||||
case '$': semsg(_(e_declare_env_var), name); return;
|
||||
default: return;
|
||||
}
|
||||
semsg(_(e_declare_var), scope, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile declaration and assignment:
|
||||
* "let var", "let var = expr", "const var = expr" and "var = expr"
|
||||
@ -4728,7 +4780,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
return NULL;
|
||||
end = p;
|
||||
|
||||
if (cctx->ctx_skip != TRUE)
|
||||
if (cctx->ctx_skip != SKIP_YES)
|
||||
{
|
||||
type_T *stacktype;
|
||||
|
||||
@ -4787,7 +4839,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
if (!heredoc)
|
||||
type = &t_any;
|
||||
|
||||
if (cctx->ctx_skip != TRUE)
|
||||
if (cctx->ctx_skip != SKIP_YES)
|
||||
{
|
||||
if (*var_start == '&')
|
||||
{
|
||||
@ -4834,8 +4886,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
type = &t_string;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1065: Cannot declare an environment variable: %s"),
|
||||
name);
|
||||
vim9_declare_error(name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@ -4859,8 +4910,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
dest = dest_global;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1016: Cannot declare a global variable: %s"),
|
||||
name);
|
||||
vim9_declare_error(name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@ -4869,8 +4919,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
dest = dest_buffer;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1078: Cannot declare a buffer variable: %s"),
|
||||
name);
|
||||
vim9_declare_error(name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@ -4879,8 +4928,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
dest = dest_window;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1079: Cannot declare a window variable: %s"),
|
||||
name);
|
||||
vim9_declare_error(name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@ -4889,7 +4937,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
dest = dest_tab;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1080: Cannot declare a tab variable: %s"), name);
|
||||
vim9_declare_error(name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@ -4912,7 +4960,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
type = typval2type(vtv);
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1064: Cannot declare a v: variable: %s"), name);
|
||||
vim9_declare_error(name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@ -5013,7 +5061,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
goto theend;
|
||||
}
|
||||
|
||||
if (lvar == NULL && dest == dest_local && cctx->ctx_skip != TRUE)
|
||||
if (lvar == NULL && dest == dest_local && cctx->ctx_skip != SKIP_YES)
|
||||
{
|
||||
if (oplen > 1 && !heredoc)
|
||||
{
|
||||
@ -5067,8 +5115,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
|
||||
if (!heredoc)
|
||||
{
|
||||
if (oplen > 0)
|
||||
if (cctx->ctx_skip == SKIP_YES)
|
||||
{
|
||||
if (oplen > 0 && var_count == 0)
|
||||
{
|
||||
// skip over the "=" and the expression
|
||||
p = skipwhite(op + oplen);
|
||||
compile_expr0(&p, cctx);
|
||||
}
|
||||
}
|
||||
else if (oplen > 0)
|
||||
{
|
||||
type_T *stacktype;
|
||||
|
||||
// For "var = expr" evaluate the expression.
|
||||
if (var_count == 0)
|
||||
{
|
||||
@ -5113,52 +5172,47 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (cctx->ctx_skip != TRUE)
|
||||
stacktype = stack->ga_len == 0 ? &t_void
|
||||
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
if (lvar != NULL && (is_decl || !has_type))
|
||||
{
|
||||
type_T *stacktype;
|
||||
|
||||
stacktype = stack->ga_len == 0 ? &t_void
|
||||
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
if (lvar != NULL && (is_decl || !has_type))
|
||||
if (new_local && !has_type)
|
||||
{
|
||||
if (new_local && !has_type)
|
||||
if (stacktype->tt_type == VAR_VOID)
|
||||
{
|
||||
if (stacktype->tt_type == VAR_VOID)
|
||||
{
|
||||
emsg(_(e_cannot_use_void));
|
||||
goto theend;
|
||||
}
|
||||
else
|
||||
{
|
||||
// An empty list or dict has a &t_void member,
|
||||
// for a variable that implies &t_any.
|
||||
if (stacktype == &t_list_empty)
|
||||
lvar->lv_type = &t_list_any;
|
||||
else if (stacktype == &t_dict_empty)
|
||||
lvar->lv_type = &t_dict_any;
|
||||
else
|
||||
lvar->lv_type = stacktype;
|
||||
}
|
||||
emsg(_(e_cannot_use_void));
|
||||
goto theend;
|
||||
}
|
||||
else
|
||||
{
|
||||
type_T *use_type = lvar->lv_type;
|
||||
|
||||
if (has_index)
|
||||
{
|
||||
use_type = use_type->tt_member;
|
||||
if (use_type == NULL)
|
||||
use_type = &t_void;
|
||||
}
|
||||
if (need_type(stacktype, use_type, -1, cctx)
|
||||
== FAIL)
|
||||
goto theend;
|
||||
// An empty list or dict has a &t_void member,
|
||||
// for a variable that implies &t_any.
|
||||
if (stacktype == &t_list_empty)
|
||||
lvar->lv_type = &t_list_any;
|
||||
else if (stacktype == &t_dict_empty)
|
||||
lvar->lv_type = &t_dict_any;
|
||||
else
|
||||
lvar->lv_type = stacktype;
|
||||
}
|
||||
}
|
||||
else if (*p != '=' && need_type(stacktype, member_type, -1,
|
||||
cctx) == FAIL)
|
||||
goto theend;
|
||||
else
|
||||
{
|
||||
type_T *use_type = lvar->lv_type;
|
||||
|
||||
if (has_index)
|
||||
{
|
||||
use_type = use_type->tt_member;
|
||||
if (use_type == NULL)
|
||||
use_type = &t_void;
|
||||
}
|
||||
if (need_type(stacktype, use_type, -1, cctx)
|
||||
== FAIL)
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
else if (*p != '=' && need_type(stacktype, member_type, -1,
|
||||
cctx) == FAIL)
|
||||
goto theend;
|
||||
}
|
||||
else if (cmdidx == CMD_const)
|
||||
{
|
||||
@ -5220,6 +5274,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
end = p;
|
||||
}
|
||||
|
||||
// no need to parse more when skipping
|
||||
if (cctx->ctx_skip == SKIP_YES)
|
||||
break;
|
||||
|
||||
if (oplen > 0 && *op != '=')
|
||||
{
|
||||
type_T *expected = &t_number;
|
||||
@ -5646,6 +5704,7 @@ compile_if(char_u *arg, cctx_T *cctx)
|
||||
garray_T *instr = &cctx->ctx_instr;
|
||||
int instr_count = instr->ga_len;
|
||||
scope_T *scope;
|
||||
skip_T skip_save = cctx->ctx_skip;
|
||||
ppconst_T ppconst;
|
||||
|
||||
CLEAR_FIELD(ppconst);
|
||||
@ -5654,17 +5713,18 @@ compile_if(char_u *arg, cctx_T *cctx)
|
||||
clear_ppconst(&ppconst);
|
||||
return NULL;
|
||||
}
|
||||
if (instr->ga_len == instr_count && ppconst.pp_used == 1)
|
||||
if (cctx->ctx_skip == SKIP_YES)
|
||||
clear_ppconst(&ppconst);
|
||||
else if (instr->ga_len == instr_count && ppconst.pp_used == 1)
|
||||
{
|
||||
// The expression results in a constant.
|
||||
// TODO: how about nesting?
|
||||
cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? FALSE : TRUE;
|
||||
cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? SKIP_NOT : SKIP_YES;
|
||||
clear_ppconst(&ppconst);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not a constant, generate instructions for the expression.
|
||||
cctx->ctx_skip = MAYBE;
|
||||
cctx->ctx_skip = SKIP_UNKNOWN;
|
||||
if (generate_ppconst(cctx, &ppconst) == FAIL)
|
||||
return NULL;
|
||||
}
|
||||
@ -5672,8 +5732,11 @@ compile_if(char_u *arg, cctx_T *cctx)
|
||||
scope = new_scope(cctx, IF_SCOPE);
|
||||
if (scope == NULL)
|
||||
return NULL;
|
||||
scope->se_skip_save = skip_save;
|
||||
// "is_had_return" will be reset if any block does not end in :return
|
||||
scope->se_u.se_if.is_had_return = TRUE;
|
||||
|
||||
if (cctx->ctx_skip == MAYBE)
|
||||
if (cctx->ctx_skip == SKIP_UNKNOWN)
|
||||
{
|
||||
// "where" is set when ":elseif", "else" or ":endif" is found
|
||||
scope->se_u.se_if.is_if_label = instr->ga_len;
|
||||
@ -5701,8 +5764,10 @@ compile_elseif(char_u *arg, cctx_T *cctx)
|
||||
return NULL;
|
||||
}
|
||||
unwind_locals(cctx, scope->se_local_count);
|
||||
if (!cctx->ctx_had_return)
|
||||
scope->se_u.se_if.is_had_return = FALSE;
|
||||
|
||||
if (cctx->ctx_skip == MAYBE)
|
||||
if (cctx->ctx_skip == SKIP_UNKNOWN)
|
||||
{
|
||||
if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
|
||||
JUMP_ALWAYS, cctx) == FAIL)
|
||||
@ -5719,18 +5784,20 @@ compile_elseif(char_u *arg, cctx_T *cctx)
|
||||
clear_ppconst(&ppconst);
|
||||
return NULL;
|
||||
}
|
||||
if (instr->ga_len == instr_count && ppconst.pp_used == 1)
|
||||
if (scope->se_skip_save == SKIP_YES)
|
||||
clear_ppconst(&ppconst);
|
||||
else if (instr->ga_len == instr_count && ppconst.pp_used == 1)
|
||||
{
|
||||
// The expression results in a constant.
|
||||
// TODO: how about nesting?
|
||||
cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? FALSE : TRUE;
|
||||
cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? SKIP_NOT : SKIP_YES;
|
||||
clear_ppconst(&ppconst);
|
||||
scope->se_u.se_if.is_if_label = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not a constant, generate instructions for the expression.
|
||||
cctx->ctx_skip = MAYBE;
|
||||
cctx->ctx_skip = SKIP_UNKNOWN;
|
||||
if (generate_ppconst(cctx, &ppconst) == FAIL)
|
||||
return NULL;
|
||||
|
||||
@ -5756,28 +5823,35 @@ compile_else(char_u *arg, cctx_T *cctx)
|
||||
return NULL;
|
||||
}
|
||||
unwind_locals(cctx, scope->se_local_count);
|
||||
if (!cctx->ctx_had_return)
|
||||
scope->se_u.se_if.is_had_return = FALSE;
|
||||
scope->se_u.se_if.is_seen_else = TRUE;
|
||||
|
||||
// jump from previous block to the end, unless the else block is empty
|
||||
if (cctx->ctx_skip == MAYBE)
|
||||
if (scope->se_skip_save != SKIP_YES)
|
||||
{
|
||||
if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
|
||||
JUMP_ALWAYS, cctx) == FAIL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cctx->ctx_skip == MAYBE)
|
||||
{
|
||||
if (scope->se_u.se_if.is_if_label >= 0)
|
||||
// jump from previous block to the end, unless the else block is empty
|
||||
if (cctx->ctx_skip == SKIP_UNKNOWN)
|
||||
{
|
||||
// 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;
|
||||
if (!cctx->ctx_had_return
|
||||
&& compile_jump_to_end(&scope->se_u.se_if.is_end_label,
|
||||
JUMP_ALWAYS, cctx) == FAIL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cctx->ctx_skip != MAYBE)
|
||||
cctx->ctx_skip = !cctx->ctx_skip;
|
||||
if (cctx->ctx_skip == SKIP_UNKNOWN)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (cctx->ctx_skip != SKIP_UNKNOWN)
|
||||
cctx->ctx_skip = cctx->ctx_skip == SKIP_YES ? SKIP_NOT : SKIP_YES;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
@ -5797,6 +5871,8 @@ compile_endif(char_u *arg, cctx_T *cctx)
|
||||
}
|
||||
ifscope = &scope->se_u.se_if;
|
||||
unwind_locals(cctx, scope->se_local_count);
|
||||
if (!cctx->ctx_had_return)
|
||||
ifscope->is_had_return = FALSE;
|
||||
|
||||
if (scope->se_u.se_if.is_if_label >= 0)
|
||||
{
|
||||
@ -5806,7 +5882,11 @@ compile_endif(char_u *arg, cctx_T *cctx)
|
||||
}
|
||||
// Fill in the "end" label in jumps at the end of the blocks.
|
||||
compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
|
||||
cctx->ctx_skip = FALSE;
|
||||
cctx->ctx_skip = scope->se_skip_save;
|
||||
|
||||
// If all the blocks end in :return and there is an :else then the
|
||||
// had_return flag is set.
|
||||
cctx->ctx_had_return = ifscope->is_had_return && ifscope->is_seen_else;
|
||||
|
||||
drop_scope(cctx);
|
||||
return arg;
|
||||
@ -6405,7 +6485,7 @@ compile_exec(char_u *line, exarg_T *eap, cctx_T *cctx)
|
||||
char_u *p;
|
||||
int has_expr = FALSE;
|
||||
|
||||
if (cctx->ctx_skip == TRUE)
|
||||
if (cctx->ctx_skip == SKIP_YES)
|
||||
goto theend;
|
||||
|
||||
if (eap->cmdidx >= 0 && eap->cmdidx < CMD_SIZE)
|
||||
@ -6473,13 +6553,22 @@ theend:
|
||||
|
||||
/*
|
||||
* Add a function to the list of :def functions.
|
||||
* This "sets ufunc->uf_dfunc_idx" but the function isn't compiled yet.
|
||||
* This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet.
|
||||
*/
|
||||
static int
|
||||
add_def_function(ufunc_T *ufunc)
|
||||
{
|
||||
dfunc_T *dfunc;
|
||||
|
||||
if (def_functions.ga_len == 0)
|
||||
{
|
||||
// The first position is not used, so that a zero uf_dfunc_idx means it
|
||||
// wasn't set.
|
||||
if (ga_grow(&def_functions, 1) == FAIL)
|
||||
return FAIL;
|
||||
++def_functions.ga_len;
|
||||
}
|
||||
|
||||
// Add the function to "def_functions".
|
||||
if (ga_grow(&def_functions, 1) == FAIL)
|
||||
return FAIL;
|
||||
@ -6509,7 +6598,6 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
char_u *line = NULL;
|
||||
char_u *p;
|
||||
char *errormsg = NULL; // error message
|
||||
int had_return = FALSE;
|
||||
cctx_T cctx;
|
||||
garray_T *instr;
|
||||
int called_emsg_before = called_emsg;
|
||||
@ -6520,7 +6608,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
|
||||
// When using a function that was compiled before: Free old instructions.
|
||||
// Otherwise add a new entry in "def_functions".
|
||||
if (ufunc->uf_dfunc_idx >= 0)
|
||||
if (ufunc->uf_dfunc_idx > 0)
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ ufunc->uf_dfunc_idx;
|
||||
@ -6613,7 +6701,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
if (line != NULL && *line == '|')
|
||||
// the line continues after a '|'
|
||||
++line;
|
||||
else if (line != NULL && *line != NUL
|
||||
else if (line != NULL && *skipwhite(line) != NUL
|
||||
&& !(*line == '#' && (line == cctx.ctx_line_start
|
||||
|| VIM_ISWHITE(line[-1]))))
|
||||
{
|
||||
@ -6622,14 +6710,13 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
line = next_line_from_context(&cctx);
|
||||
line = next_line_from_context(&cctx, FALSE);
|
||||
if (cctx.ctx_lnum >= ufunc->uf_lines.ga_len)
|
||||
// beyond the last line
|
||||
break;
|
||||
}
|
||||
emsg_before = called_emsg;
|
||||
|
||||
had_return = FALSE;
|
||||
CLEAR_FIELD(ea);
|
||||
ea.cmdlinep = &line;
|
||||
ea.cmd = skipwhite(line);
|
||||
@ -6770,7 +6857,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
|
||||
if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
|
||||
{
|
||||
if (cctx.ctx_skip == TRUE)
|
||||
if (cctx.ctx_skip == SKIP_YES)
|
||||
{
|
||||
line += STRLEN(line);
|
||||
continue;
|
||||
@ -6795,7 +6882,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
|
||||
p = skipwhite(p);
|
||||
|
||||
if (cctx.ctx_skip == TRUE
|
||||
if (cctx.ctx_skip == SKIP_YES
|
||||
&& ea.cmdidx != CMD_if
|
||||
&& ea.cmdidx != CMD_elseif
|
||||
&& ea.cmdidx != CMD_else
|
||||
&& ea.cmdidx != CMD_endif)
|
||||
@ -6804,6 +6892,22 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ea.cmdidx != CMD_elseif
|
||||
&& ea.cmdidx != CMD_else
|
||||
&& ea.cmdidx != CMD_endif
|
||||
&& ea.cmdidx != CMD_endfor
|
||||
&& ea.cmdidx != CMD_endwhile
|
||||
&& ea.cmdidx != CMD_catch
|
||||
&& ea.cmdidx != CMD_finally
|
||||
&& ea.cmdidx != CMD_endtry)
|
||||
{
|
||||
if (cctx.ctx_had_return)
|
||||
{
|
||||
emsg(_("E1095: Unreachable code after :return"));
|
||||
goto erret;
|
||||
}
|
||||
}
|
||||
|
||||
switch (ea.cmdidx)
|
||||
{
|
||||
case CMD_def:
|
||||
@ -6817,7 +6921,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
|
||||
case CMD_return:
|
||||
line = compile_return(p, set_return_type, &cctx);
|
||||
had_return = TRUE;
|
||||
cctx.ctx_had_return = TRUE;
|
||||
break;
|
||||
|
||||
case CMD_let:
|
||||
@ -6842,9 +6946,11 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
break;
|
||||
case CMD_elseif:
|
||||
line = compile_elseif(p, &cctx);
|
||||
cctx.ctx_had_return = FALSE;
|
||||
break;
|
||||
case CMD_else:
|
||||
line = compile_else(p, &cctx);
|
||||
cctx.ctx_had_return = FALSE;
|
||||
break;
|
||||
case CMD_endif:
|
||||
line = compile_endif(p, &cctx);
|
||||
@ -6855,6 +6961,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
break;
|
||||
case CMD_endwhile:
|
||||
line = compile_endwhile(p, &cctx);
|
||||
cctx.ctx_had_return = FALSE;
|
||||
break;
|
||||
|
||||
case CMD_for:
|
||||
@ -6862,6 +6969,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
break;
|
||||
case CMD_endfor:
|
||||
line = compile_endfor(p, &cctx);
|
||||
cctx.ctx_had_return = FALSE;
|
||||
break;
|
||||
case CMD_continue:
|
||||
line = compile_continue(p, &cctx);
|
||||
@ -6875,12 +6983,15 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
break;
|
||||
case CMD_catch:
|
||||
line = compile_catch(p, &cctx);
|
||||
cctx.ctx_had_return = FALSE;
|
||||
break;
|
||||
case CMD_finally:
|
||||
line = compile_finally(p, &cctx);
|
||||
cctx.ctx_had_return = FALSE;
|
||||
break;
|
||||
case CMD_endtry:
|
||||
line = compile_endtry(p, &cctx);
|
||||
cctx.ctx_had_return = FALSE;
|
||||
break;
|
||||
case CMD_throw:
|
||||
line = compile_throw(p, &cctx);
|
||||
@ -6925,7 +7036,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
goto erret;
|
||||
}
|
||||
|
||||
if (!had_return)
|
||||
if (!cctx.ctx_had_return)
|
||||
{
|
||||
if (ufunc->uf_ret_type->tt_type != VAR_VOID)
|
||||
{
|
||||
@ -6948,6 +7059,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
dfunc->df_closure_count = cctx.ctx_closure_count;
|
||||
if (cctx.ctx_outer_used)
|
||||
ufunc->uf_flags |= FC_CLOSURE;
|
||||
ufunc->uf_def_status = UF_COMPILED;
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
@ -6967,7 +7079,7 @@ erret:
|
||||
if (!dfunc->df_deleted
|
||||
&& ufunc->uf_dfunc_idx == def_functions.ga_len - 1)
|
||||
--def_functions.ga_len;
|
||||
ufunc->uf_dfunc_idx = UF_NOT_COMPILED;
|
||||
ufunc->uf_def_status = UF_NOT_COMPILED;
|
||||
|
||||
while (cctx.ctx_scope != NULL)
|
||||
drop_scope(&cctx);
|
||||
@ -7195,17 +7307,19 @@ delete_def_function_contents(dfunc_T *dfunc)
|
||||
}
|
||||
|
||||
/*
|
||||
* When a user function is deleted, delete any associated def function.
|
||||
* When a user function is deleted, clear the contents of any associated def
|
||||
* function. The position in def_functions can be re-used.
|
||||
*/
|
||||
void
|
||||
delete_def_function(ufunc_T *ufunc)
|
||||
clear_def_function(ufunc_T *ufunc)
|
||||
{
|
||||
if (ufunc->uf_dfunc_idx >= 0)
|
||||
if (ufunc->uf_dfunc_idx > 0)
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ ufunc->uf_dfunc_idx;
|
||||
|
||||
delete_def_function_contents(dfunc);
|
||||
ufunc->uf_def_status = UF_NOT_COMPILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,10 +487,10 @@ call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
|
||||
int error;
|
||||
int idx;
|
||||
|
||||
if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
|
||||
if (ufunc->uf_def_status == UF_TO_BE_COMPILED
|
||||
&& compile_def_function(ufunc, FALSE, NULL) == FAIL)
|
||||
return FAIL;
|
||||
if (ufunc->uf_dfunc_idx >= 0)
|
||||
if (ufunc->uf_def_status == UF_COMPILED)
|
||||
{
|
||||
// The function has been compiled, can call it quickly. For a function
|
||||
// that was defined later: we can call it directly next time.
|
||||
@ -671,8 +671,8 @@ call_def_function(
|
||||
// Like STACK_TV_VAR but use the outer scope
|
||||
#define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
|
||||
|
||||
if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED
|
||||
|| (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
|
||||
if (ufunc->uf_def_status == UF_NOT_COMPILED
|
||||
|| (ufunc->uf_def_status == UF_TO_BE_COMPILED
|
||||
&& compile_def_function(ufunc, FALSE, NULL) == FAIL))
|
||||
{
|
||||
if (called_emsg == called_emsg_before)
|
||||
@ -2119,12 +2119,8 @@ call_def_function(
|
||||
list_T *list;
|
||||
int count = iptr->isn_arg.number;
|
||||
|
||||
// type will have been checked to be a list
|
||||
tv = STACK_TV_BOT(-1);
|
||||
if (tv->v_type != VAR_LIST)
|
||||
{
|
||||
emsg(_(e_listreq));
|
||||
goto failed;
|
||||
}
|
||||
list = tv->vval.v_list;
|
||||
|
||||
// no error for short list, expect it to be checked earlier
|
||||
@ -2148,18 +2144,10 @@ call_def_function(
|
||||
listitem_T *li;
|
||||
int index = iptr->isn_arg.number;
|
||||
|
||||
// get list item: list is at stack-1, push item
|
||||
// Get list item: list is at stack-1, push item.
|
||||
// List type and length is checked for when compiling.
|
||||
tv = STACK_TV_BOT(-1);
|
||||
if (tv->v_type != VAR_LIST)
|
||||
{
|
||||
emsg(_(e_listreq));
|
||||
goto failed;
|
||||
}
|
||||
if ((li = list_find(tv->vval.v_list, index)) == NULL)
|
||||
{
|
||||
semsg(_(e_listidx), index);
|
||||
goto failed;
|
||||
}
|
||||
li = list_find(tv->vval.v_list, index);
|
||||
|
||||
if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
|
||||
goto failed;
|
||||
@ -2391,10 +2379,10 @@ ex_disassemble(exarg_T *eap)
|
||||
semsg(_("E1061: Cannot find function %s"), eap->arg);
|
||||
return;
|
||||
}
|
||||
if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
|
||||
if (ufunc->uf_def_status == UF_TO_BE_COMPILED
|
||||
&& compile_def_function(ufunc, FALSE, NULL) == FAIL)
|
||||
return;
|
||||
if (ufunc->uf_dfunc_idx < 0)
|
||||
if (ufunc->uf_def_status != UF_COMPILED)
|
||||
{
|
||||
semsg(_("E1062: Function %s is not compiled"), eap->arg);
|
||||
return;
|
||||
|
@ -32,13 +32,14 @@ in_vim9script(void)
|
||||
void
|
||||
ex_vim9script(exarg_T *eap)
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||
scriptitem_T *si;
|
||||
|
||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
||||
{
|
||||
emsg(_("E1038: vim9script can only be used in a script"));
|
||||
return;
|
||||
}
|
||||
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||
if (si->sn_had_command)
|
||||
{
|
||||
emsg(_("E1039: vim9script must be the first command in a script"));
|
||||
@ -141,8 +142,15 @@ free_imports(int sid)
|
||||
void
|
||||
ex_import(exarg_T *eap)
|
||||
{
|
||||
char_u *cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, NULL);
|
||||
char_u *cmd_end;
|
||||
|
||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
||||
{
|
||||
emsg(_("E1094: import can only be used in a script"));
|
||||
return;
|
||||
}
|
||||
|
||||
cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, NULL);
|
||||
if (cmd_end != NULL)
|
||||
eap->nextcmd = check_nextcmd(cmd_end);
|
||||
}
|
||||
@ -463,7 +471,7 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
|
||||
}
|
||||
|
||||
for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p))
|
||||
if (*p == ':' && p != arg + 1)
|
||||
if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1))
|
||||
break;
|
||||
|
||||
if (*p != ':')
|
||||
@ -499,7 +507,7 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
|
||||
/*
|
||||
* Check if the type of script variable "dest" allows assigning "value".
|
||||
*/
|
||||
void
|
||||
int
|
||||
check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||
@ -513,13 +521,15 @@ check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
|
||||
if (sv->sv_tv == dest)
|
||||
{
|
||||
if (sv->sv_const)
|
||||
{
|
||||
semsg(_(e_readonlyvar), name);
|
||||
else
|
||||
check_type(sv->sv_type, typval2type(value), TRUE);
|
||||
return;
|
||||
return FAIL;
|
||||
}
|
||||
return check_type(sv->sv_type, typval2type(value), TRUE);
|
||||
}
|
||||
}
|
||||
iemsg("check_script_var_type(): not found");
|
||||
return OK; // not really
|
||||
}
|
||||
|
||||
#endif // FEAT_EVAL
|
||||
|
Reference in New Issue
Block a user