mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
Merge remote-tracking branch 'vim/master'
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
||||
" Maintainer: <vacancy>
|
||||
" Previous Maintainer: Aaron Griffin <aaronmgriffin@gmail.com>
|
||||
" Version: 0.9
|
||||
" Last Updated: 2020 Oct 9
|
||||
" Last Updated: 2022 Mar 30
|
||||
"
|
||||
" Roland Puntaier: this file contains adaptations for python3 and is parallel to pythoncomplete.vim
|
||||
"
|
||||
@@ -91,6 +91,9 @@ endfunction
|
||||
|
||||
function! s:DefPython()
|
||||
py3 << PYTHONEOF
|
||||
import warnings
|
||||
warnings.simplefilter(action='ignore', category=FutureWarning)
|
||||
|
||||
import sys, tokenize, io, types
|
||||
from token import NAME, DEDENT, NEWLINE, STRING
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
" Maintainer: Drew Vogel <dvogel@sidejump.org>
|
||||
" Last Change: 2021 Jul 25
|
||||
" Last Change: 2022 Mar 20
|
||||
"
|
||||
" Replaced rgb.txt as the source of de facto standard color names. This is
|
||||
" sourced each time the colorscheme command is run. It is also sourced each
|
||||
@@ -430,6 +430,8 @@ call extend(v:colornames, {
|
||||
\ 'yellow2': '#eeee00',
|
||||
\ 'yellow3': '#cdcd00',
|
||||
\ 'yellow4': '#8b8b00',
|
||||
\ 'dark yellow': '#8b8b00',
|
||||
\ 'darkyellow': '#8b8b00',
|
||||
\ 'gold1': '#ffd700',
|
||||
\ 'gold2': '#eec900',
|
||||
\ 'gold3': '#cdad00',
|
||||
@@ -506,6 +508,8 @@ call extend(v:colornames, {
|
||||
\ 'orangered2': '#ee4000',
|
||||
\ 'orangered3': '#cd3700',
|
||||
\ 'orangered4': '#8b2500',
|
||||
\ 'light red': '#ff8b8b',
|
||||
\ 'lightred': '#ff8b8b',
|
||||
\ 'red1': '#ff0000',
|
||||
\ 'red2': '#ee0000',
|
||||
\ 'red3': '#cd0000',
|
||||
@@ -538,6 +542,8 @@ call extend(v:colornames, {
|
||||
\ 'violetred2': '#ee3a8c',
|
||||
\ 'violetred3': '#cd3278',
|
||||
\ 'violetred4': '#8b2252',
|
||||
\ 'light magenta': '#ff8bff',
|
||||
\ 'lightmagenta': '#ff8bff',
|
||||
\ 'magenta1': '#ff00ff',
|
||||
\ 'magenta2': '#ee00ee',
|
||||
\ 'magenta3': '#cd00cd',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*autocmd.txt* For Vim version 8.2. Last change: 2022 Mar 04
|
||||
*autocmd.txt* For Vim version 8.2. Last change: 2022 Mar 27
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -692,9 +692,9 @@ CursorHoldI Just like CursorHold, but in Insert mode.
|
||||
CursorMoved After the cursor was moved in Normal or Visual
|
||||
mode. Also when the text of the cursor line
|
||||
has been changed, e.g., with "x", "rx" or "p".
|
||||
Not triggered when there is typeahead, while
|
||||
executing commands in a script file, when
|
||||
an operator is pending or when moving to
|
||||
Not always triggered when there is typeahead,
|
||||
while executing commands in a script file,
|
||||
when an operator is pending or when moving to
|
||||
another window while remaining at the same
|
||||
cursor position.
|
||||
For an example see |match-parens|.
|
||||
|
||||
+10
-9
@@ -1,4 +1,4 @@
|
||||
*builtin.txt* For Vim version 8.2. Last change: 2022 Mar 08
|
||||
*builtin.txt* For Vim version 8.2. Last change: 2022 Mar 26
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -1562,14 +1562,15 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
|
||||
or another valid interrupt key, confirm() returns 0.
|
||||
|
||||
An example: >
|
||||
:let choice = confirm("What do you want?", "&Apples\n&Oranges\n&Bananas", 2)
|
||||
:if choice == 0
|
||||
: echo "make up your mind!"
|
||||
:elseif choice == 3
|
||||
: echo "tasteful"
|
||||
:else
|
||||
: echo "I prefer bananas myself."
|
||||
:endif
|
||||
let choice = confirm("What do you want?",
|
||||
\ "&Apples\n&Oranges\n&Bananas", 2)
|
||||
if choice == 0
|
||||
echo "make up your mind!"
|
||||
elseif choice == 3
|
||||
echo "tasteful"
|
||||
else
|
||||
echo "I prefer bananas myself."
|
||||
endif
|
||||
< In a GUI dialog, buttons are used. The layout of the buttons
|
||||
depends on the 'v' flag in 'guioptions'. If it is included,
|
||||
the buttons are always put vertically. Otherwise, confirm()
|
||||
|
||||
+93
-6
@@ -1,4 +1,4 @@
|
||||
*channel.txt* For Vim version 8.2. Last change: 2022 Feb 27
|
||||
*channel.txt* For Vim version 8.2. Last change: 2022 Mar 26
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -53,6 +53,7 @@ RAW nothing known, Vim cannot tell where a message ends
|
||||
NL every message ends in a NL (newline) character
|
||||
JSON JSON encoding |json_encode()|
|
||||
JS JavaScript style JSON-like encoding |js_encode()|
|
||||
LSP Language Server Protocol encoding |language-server-protocol|
|
||||
|
||||
Common combination are:
|
||||
- Using a job connected through pipes in NL mode. E.g., to run a style
|
||||
@@ -130,6 +131,7 @@ When using an IPv6 address, enclose it within square brackets. E.g.,
|
||||
"js" - Use JS (JavaScript) encoding, more efficient than JSON.
|
||||
"nl" - Use messages that end in a NL character
|
||||
"raw" - Use raw messages
|
||||
"lsp" - Use language server protocol encoding
|
||||
*channel-callback* *E921*
|
||||
"callback" A function that is called when a message is received that is
|
||||
not handled otherwise (e.g. a JSON message with ID zero). It
|
||||
@@ -140,8 +142,8 @@ When using an IPv6 address, enclose it within square brackets. E.g.,
|
||||
endfunc
|
||||
let channel = ch_open("localhost:8765", {"callback": "Handle"})
|
||||
<
|
||||
When "mode" is "json" or "js" the "msg" argument is the body
|
||||
of the received message, converted to Vim types.
|
||||
When "mode" is "json" or "js" or "lsp" the "msg" argument is
|
||||
the body of the received message, converted to Vim types.
|
||||
When "mode" is "nl" the "msg" argument is one message,
|
||||
excluding the NL.
|
||||
When "mode" is "raw" the "msg" argument is the whole message
|
||||
@@ -165,7 +167,19 @@ When using an IPv6 address, enclose it within square brackets. E.g.,
|
||||
to check for messages, the close_cb may be invoked while still
|
||||
in the callback. The plugin must handle this somehow, it can
|
||||
be useful to know that no more data is coming.
|
||||
*channel-drop*
|
||||
If it is not known if there is a message to be read, use a
|
||||
try/catch block: >
|
||||
try
|
||||
let msg = ch_readraw(a:channel)
|
||||
catch
|
||||
let msg = 'no message'
|
||||
endtry
|
||||
try
|
||||
let err = ch_readraw(a:channel, #{part: 'err'})
|
||||
catch
|
||||
let err = 'no error'
|
||||
endtry
|
||||
< *channel-drop*
|
||||
"drop" Specifies when to drop messages:
|
||||
"auto" When there is no callback to handle a message.
|
||||
The "close_cb" is also considered for this.
|
||||
@@ -443,7 +457,7 @@ to check if there is something to read.
|
||||
Note that when there is no callback, messages are dropped. To avoid that add
|
||||
a close callback to the channel.
|
||||
|
||||
To read all output from a RAW channel that is available: >
|
||||
To read all normal output from a RAW channel that is available: >
|
||||
let output = ch_readraw(channel)
|
||||
To read the error output: >
|
||||
let output = ch_readraw(channel, {"part": "err"})
|
||||
@@ -503,6 +517,7 @@ ch_evalexpr({handle}, {expr} [, {options}]) *ch_evalexpr()*
|
||||
according to the type of channel. The function cannot be used
|
||||
with a raw channel. See |channel-use|.
|
||||
{handle} can be a Channel or a Job that has a Channel.
|
||||
When using the "lsp" channel mode, {expr} must be a |Dict|.
|
||||
*E917*
|
||||
{options} must be a Dictionary. It must not have a "callback"
|
||||
entry. It can have a "timeout" entry to specify the timeout
|
||||
@@ -578,7 +593,7 @@ ch_info({handle}) *ch_info()*
|
||||
"err_io" "out", "null", "pipe", "file" or "buffer"
|
||||
"err_timeout" timeout in msec
|
||||
"in_status" "open" or "closed"
|
||||
"in_mode" "NL", "RAW", "JSON" or "JS"
|
||||
"in_mode" "NL", "RAW", "JSON", "JS" or "LSP"
|
||||
"in_io" "null", "pipe", "file" or "buffer"
|
||||
"in_timeout" timeout in msec
|
||||
|
||||
@@ -674,6 +689,7 @@ ch_sendexpr({handle}, {expr} [, {options}]) *ch_sendexpr()*
|
||||
with a raw channel.
|
||||
See |channel-use|. *E912*
|
||||
{handle} can be a Channel or a Job that has a Channel.
|
||||
When using the "lsp" channel mode, {expr} must be a |Dict|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetChannel()->ch_sendexpr(expr)
|
||||
@@ -1361,5 +1377,76 @@ The same in |Vim9| script: >
|
||||
# start accepting shell commands
|
||||
startinsert
|
||||
|
||||
==============================================================================
|
||||
14. Language Server Protocol *language-server-protocol*
|
||||
|
||||
The language server protocol specification is available at:
|
||||
|
||||
https://microsoft.github.io/language-server-protocol/specification
|
||||
|
||||
Each LSP protocol message starts with a simple HTTP header followed by the
|
||||
payload encoded in JSON-RPC format. This is described in:
|
||||
|
||||
https://www.jsonrpc.org/specification
|
||||
|
||||
For messages received on a channel with mode set to "lsp", Vim will process
|
||||
the HTTP header and decode the payload into a Vim |Dict| type and call the
|
||||
channel callback or the specified callback function. When sending messages on
|
||||
a channel using |ch_evalexpr()| or |ch_sendexpr()|, Vim will add the HTTP
|
||||
header and encode the Vim expression into JSON-RPC.
|
||||
|
||||
To open a channel using the 'lsp' mode, set the 'mode' item in the |ch_open()|
|
||||
{options} argument to 'lsp'. Example: >
|
||||
|
||||
let ch = ch_open(..., #{mode: 'lsp'})
|
||||
|
||||
To open a channel using the 'lsp' mode with a job, set the 'in_mode' and
|
||||
'out_mode' items in the |job_start()| {options} argument to 'lsp'. Example: >
|
||||
|
||||
let job = job_start(...., #{in_mode: 'lsp', out_mode: 'lsp'})
|
||||
|
||||
To synchronously send a JSON-RPC request to the server, use the |ch_evalexpr()|
|
||||
function. This function will return the response from the server. You can use
|
||||
the 'timeout' field in the {options} argument to control the response wait
|
||||
time. Example: >
|
||||
|
||||
let req = {}
|
||||
let req.method = 'textDocument/definition'
|
||||
let req.params = {}
|
||||
let req.params.textDocument = #{uri: 'a.c'}
|
||||
let req.params.position = #{line: 10, character: 3}
|
||||
let resp = ch_evalexpr(ch, req, #{timeout: 100})
|
||||
|
||||
Note that in the request message the 'id' field should not be specified. If it
|
||||
is specified, then Vim will overwrite the value with an internally generated
|
||||
identifier. Vim currently supports only a number type for the 'id' field.
|
||||
|
||||
To send a JSON-RPC request to the server and asynchronously process the
|
||||
response, use the |ch_sendexpr()| function and supply a callback function.
|
||||
Example: >
|
||||
|
||||
let req = {}
|
||||
let req.method = 'textDocument/hover'
|
||||
let req.params = {}
|
||||
let req.params.textDocument = #{uri: 'a.c'}
|
||||
let req.params.position = #{line: 10, character: 3}
|
||||
let resp = ch_sendexpr(ch, req, #{callback: 'MyFn'})
|
||||
|
||||
To send a JSON-RPC notification message to the server, use the |ch_sendexpr()|
|
||||
function. Example: >
|
||||
|
||||
call ch_sendexpr(ch, #{method: 'initialized'})
|
||||
|
||||
To respond to a JSON-RPC request message from the server, use the
|
||||
|ch_sendexpr()| function. In the response message, copy the 'id' field value
|
||||
from the server request message. Example: >
|
||||
|
||||
let resp = {}
|
||||
let resp.id = req.id
|
||||
let resp.result = 1
|
||||
call ch_sendexpr(ch, resp)
|
||||
|
||||
The JSON-RPC notification messages from the server are delivered through the
|
||||
|channel-callback| function.
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*insert.txt* For Vim version 8.2. Last change: 2022 Mar 13
|
||||
*insert.txt* For Vim version 8.2. Last change: 2022 Mar 28
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -800,7 +800,7 @@ If the previous expansion was split, because it got longer than 'textwidth',
|
||||
then just the text in the current line will be used.
|
||||
|
||||
If the match found is at the end of a line, then the first word in the next
|
||||
line will be inserted and the message "word from next line" displayed, if
|
||||
line will be inserted and the message "Word from other line" displayed, if
|
||||
this word is accepted the next CTRL-X CTRL-P or CTRL-X CTRL-N will search
|
||||
for those lines starting with this word.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*options.txt* For Vim version 8.2. Last change: 2022 Mar 13
|
||||
*options.txt* For Vim version 8.2. Last change: 2022 Mar 29
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -984,7 +984,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
nostop like start, except CTRL-W and CTRL-U do not stop at the start of
|
||||
insert.
|
||||
|
||||
When the value is empty, Vi compatible backspacing is used.
|
||||
When the value is empty, Vi compatible backspacing is used, none of
|
||||
the ways mentioned for the items above are possible.
|
||||
|
||||
For backwards compatibility with version 5.4 and earlier:
|
||||
value effect ~
|
||||
|
||||
+10
-6
@@ -1,4 +1,4 @@
|
||||
*repeat.txt* For Vim version 8.2. Last change: 2022 Jan 21
|
||||
*repeat.txt* For Vim version 8.2. Last change: 2022 Mar 30
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -210,22 +210,26 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|
||||
|
||||
To source a range of lines that doesn't start with the
|
||||
|:vim9script| command in Vim9 script context, the
|
||||
|:vim9cmd| modifier can be used.
|
||||
|:vim9cmd| modifier can be used. If you use a Visual
|
||||
selection and type ":", the range in the form "'<,'>"
|
||||
can come before it: >
|
||||
:'<,'>vim9cmd source
|
||||
< Otherwise the range goes after the modifier and must
|
||||
have a colon prefixed, like all Vim9 ranges: >
|
||||
:vim9cmd :5,9source
|
||||
|
||||
When a range of lines in a buffer is sourced in the
|
||||
< When a range of lines in a buffer is sourced in the
|
||||
Vim9 script context, the previously defined
|
||||
script-local variables and functions are not cleared.
|
||||
This works like the range started with the
|
||||
":vim9script noclear" command. The "++clear" argument
|
||||
can be used to clear the script-local variables and
|
||||
functions before sourcing the script. This works like
|
||||
the range started with the |:vimscript| command
|
||||
the range started with the `:vim9script` command
|
||||
without the "noclear" argument. See |vim9-reload| for
|
||||
more information.
|
||||
Examples: >
|
||||
|
||||
:4,5source
|
||||
:vim9cmd :'<,'>source
|
||||
:10,18source ++clear
|
||||
|
||||
*:source!*
|
||||
|
||||
@@ -8094,6 +8094,7 @@ lace.vim syntax.txt /*lace.vim*
|
||||
lambda eval.txt /*lambda*
|
||||
lang-variable eval.txt /*lang-variable*
|
||||
language-mapping map.txt /*language-mapping*
|
||||
language-server-protocol channel.txt /*language-server-protocol*
|
||||
last-pattern pattern.txt /*last-pattern*
|
||||
last-position-jump usr_05.txt /*last-position-jump*
|
||||
last_buffer_nr() builtin.txt /*last_buffer_nr()*
|
||||
|
||||
+5
-17
@@ -1,4 +1,4 @@
|
||||
*todo.txt* For Vim version 8.2. Last change: 2022 Mar 18
|
||||
*todo.txt* For Vim version 8.2. Last change: 2022 Mar 30
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -38,6 +38,9 @@ browser use: https://github.com/vim/vim/issues/1234
|
||||
*known-bugs*
|
||||
-------------------- Known bugs and current work -----------------------
|
||||
|
||||
Allow for: "import autoload '../lib/script.vim'"
|
||||
avoids going through 'runtimepath' and avoids name collisions.
|
||||
|
||||
Really drop the Athena and NeXtaw GUI? Decide end of March.
|
||||
|
||||
Once Vim9 is stable:
|
||||
@@ -48,6 +51,7 @@ Once Vim9 is stable:
|
||||
vim9instr.c
|
||||
vim9script.c
|
||||
vim9type.c
|
||||
- Adjust intro message to say "help version9".
|
||||
|
||||
Further Vim9 improvements, possibly after launch:
|
||||
- Check performance with callgrind and kcachegrind.
|
||||
@@ -417,13 +421,6 @@ register, then "" doesn't contain anything. Make it still follow "+.
|
||||
|
||||
File marks merging has duplicates since 7.4.1925. (Ingo Karkat, #5733)
|
||||
|
||||
"make test_gui" crashed in submenu_change(). Fix and remove workaround in
|
||||
add_pixmap_args().
|
||||
Athena is OK.
|
||||
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?
|
||||
|
||||
When editing a file with ":edit" the output of :swapname is relative, while
|
||||
editing it with "vim file" it is absolute. (#355)
|
||||
Which one should it be?
|
||||
@@ -478,11 +475,6 @@ Test loose_clipboard() by selecting text before suspending.
|
||||
|
||||
Undo puts cursor in wrong line after "cG<Esc>" undo.
|
||||
|
||||
Implement completion for "breakadd". Should expand the second argument, e.g.
|
||||
"func", and then function names after ":breakadd func". Including
|
||||
script-local functions.
|
||||
Also for ":profile".
|
||||
|
||||
:unmap <c-n> gives error but does remove the mapping. (Antony Scriven, 2019
|
||||
Dec 19)
|
||||
|
||||
@@ -2501,10 +2493,6 @@ Works OK when 'cmdheight' is 2.
|
||||
8 Use a mechanism similar to omni completion to figure out the kind of tab
|
||||
for CTRL-] and jump to the appropriate matching tag (if there are
|
||||
several).
|
||||
Alternative: be able to define a function that takes the tag name and uses
|
||||
taglist() to find the right location. With indication of using CTRL-] so
|
||||
that the context can be taken into account. (Robert Webb)
|
||||
Patch by Christian Brabandt, 2013 May 31.
|
||||
|
||||
The utf class table is missing some entries:
|
||||
0x2212, minus sign
|
||||
|
||||
+16
-6
@@ -1,4 +1,4 @@
|
||||
*vim9.txt* For Vim version 8.2. Last change: 2022 Mar 18
|
||||
*vim9.txt* For Vim version 8.2. Last change: 2022 Mar 28
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -184,8 +184,8 @@ For now you will need to pass the dictionary explicitly: >
|
||||
def DictFunc(d: dict<any>, arg: string)
|
||||
echo d[arg]
|
||||
enddef
|
||||
var d = {item: 'value', func: DictFunc}
|
||||
d.func(d, 'item')
|
||||
var ad = {item: 'value', func: DictFunc}
|
||||
ad.func(d, 'item')
|
||||
|
||||
You can call a legacy dict function though: >
|
||||
func Legacy() dict
|
||||
@@ -376,13 +376,23 @@ And with autocommands: >
|
||||
}
|
||||
|
||||
Although using a :def function probably works better.
|
||||
|
||||
*E1022* *E1103* *E1130* *E1131* *E1133*
|
||||
*E1134* *E1235*
|
||||
Declaring a variable with a type but without an initializer will initialize to
|
||||
false (for bool), empty (for string, list, dict, etc.) or zero (for number,
|
||||
any, etc.). This matters especially when using the "any" type, the value will
|
||||
default to the number zero.
|
||||
*E1016* *E1052* *E1066*
|
||||
default to the number zero. For example, when declaring a list, items can be
|
||||
added: >
|
||||
var myList: list<number>
|
||||
myList->add(7)
|
||||
|
||||
Initializing a variable to a null value, e.g. `null_list`, differs from not
|
||||
initializing the variable. This throws an error: >
|
||||
var myList = null_list
|
||||
myList->add(7) # E1130: Cannot add to null list
|
||||
|
||||
< *E1016* *E1052* *E1066*
|
||||
In Vim9 script `:let` cannot be used. An existing variable is assigned to
|
||||
without any command. The same for global, window, tab, buffer and Vim
|
||||
variables, because they are not really declared. Those can also be deleted
|
||||
@@ -1243,7 +1253,7 @@ Closures defined in a loop will share the same context. For example: >
|
||||
A closure must be compiled in the context that it is defined in, so that
|
||||
variables in that context can be found. This mostly happens correctly, except
|
||||
when a function is marked for debugging with `breakadd` after it was compiled.
|
||||
Make sure the define the breakpoint before compiling the outerh function.
|
||||
Make sure to define the breakpoint before compiling the outer function.
|
||||
|
||||
The "inloop" variable will exist only once, all closures put in the list refer
|
||||
to the same instance, which in the end will have the value 4. This is
|
||||
|
||||
@@ -1277,6 +1277,9 @@ au BufNewFile,BufRead *.[Oo][Pp][Ll] setf opl
|
||||
" Oracle config file
|
||||
au BufNewFile,BufRead *.ora setf ora
|
||||
|
||||
" Org
|
||||
au BufNewFile,BufRead *.org,*.org_archive setf org
|
||||
|
||||
" Packet filter conf
|
||||
au BufNewFile,BufRead pf.conf setf pf
|
||||
|
||||
@@ -1732,7 +1735,7 @@ au BufNewFile,BufRead .zshrc,.zshenv,.zlogin,.zlogout,.zcompdump setf zsh
|
||||
au BufNewFile,BufRead *.zsh setf zsh
|
||||
|
||||
" Scheme
|
||||
au BufNewFile,BufRead *.scm,*.ss,*.sld,*.rkt,*.rktd,*.rktl setf scheme
|
||||
au BufNewFile,BufRead *.scm,*.ss,*.sld,*.rkt,*.rktd,*.rktl setf scheme
|
||||
|
||||
" Screen RC
|
||||
au BufNewFile,BufRead .screenrc,screenrc setf screen
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
" Meikel Brandmeyer <mb@kotka.de>
|
||||
" URL: https://github.com/clojure-vim/clojure.vim
|
||||
" License: Vim (see :h license)
|
||||
" Last Change: 2021-10-26
|
||||
" Last Change: 2022-03-24
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
@@ -43,7 +43,7 @@ setlocal commentstring=;\ %s
|
||||
" specially and hence are not indented specially.
|
||||
"
|
||||
" -*- LISPWORDS -*-
|
||||
" Generated from https://github.com/clojure-vim/clojure.vim/blob/62b215f079ce0f3834fd295c7a7f6bd8cc54bcc3/clj/src/vim_clojure_static/generate.clj
|
||||
" Generated from https://github.com/clojure-vim/clojure.vim/blob/fd280e33e84c88e97860930557dba3ff80b1a82d/clj/src/vim_clojure_static/generate.clj
|
||||
setlocal lispwords=as->,binding,bound-fn,case,catch,cond->,cond->>,condp,def,definline,definterface,defmacro,defmethod,defmulti,defn,defn-,defonce,defprotocol,defrecord,defstruct,deftest,deftest-,deftype,doseq,dotimes,doto,extend,extend-protocol,extend-type,fn,for,if,if-let,if-not,if-some,let,letfn,locking,loop,ns,proxy,reify,set-test,testing,when,when-first,when-let,when-not,when-some,while,with-bindings,with-in-str,with-local-vars,with-open,with-precision,with-redefs,with-redefs-fn,with-test
|
||||
|
||||
" Provide insert mode completions for special forms and clojure.core. As
|
||||
@@ -66,10 +66,10 @@ endif
|
||||
|
||||
" Filter files in the browse dialog
|
||||
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
|
||||
let b:browsefilter = "Clojure Source Files (*.clj)\t*.clj\n" .
|
||||
\ "ClojureScript Source Files (*.cljs)\t*.cljs\n" .
|
||||
\ "Java Source Files (*.java)\t*.java\n" .
|
||||
\ "All Files (*.*)\t*.*\n"
|
||||
let b:browsefilter = "All Files\t*\n" .
|
||||
\ "Clojure Files\t*.clj;*.cljc;*.cljs;*.cljx\n" .
|
||||
\ "EDN Files\t*.edn\n" .
|
||||
\ "Java Files\t*.java\n"
|
||||
let b:undo_ftplugin .= ' | unlet! b:browsefilter'
|
||||
endif
|
||||
|
||||
|
||||
+25
-17
@@ -3,7 +3,7 @@
|
||||
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
|
||||
" URL: https://github.com/vim-ruby/vim-ruby
|
||||
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
|
||||
" Last Change: 2020 Feb 13
|
||||
" Last Change: 2022 Mar 21
|
||||
|
||||
if (exists("b:did_ftplugin"))
|
||||
finish
|
||||
@@ -53,7 +53,7 @@ endif
|
||||
" TODO:
|
||||
"setlocal define=^\\s*def
|
||||
|
||||
setlocal comments=:#
|
||||
setlocal comments=b:#
|
||||
setlocal commentstring=#\ %s
|
||||
|
||||
if !exists('g:ruby_version_paths')
|
||||
@@ -87,8 +87,14 @@ endfunction
|
||||
|
||||
function! s:build_path(path) abort
|
||||
let path = join(map(copy(a:path), 'v:val ==# "." ? "" : v:val'), ',')
|
||||
if &g:path !~# '\v^%(\.,)=%(/%(usr|emx)/include,)=,$'
|
||||
let path = substitute(&g:path,',,$',',','') . ',' . path
|
||||
if &g:path =~# '\v^%(\.,)=%(/%(usr|emx)/include,)=,$'
|
||||
let path = path . ',.,,'
|
||||
elseif &g:path =~# ',\.,,$'
|
||||
let path = &g:path[0:-4] . path . ',.,,'
|
||||
elseif &g:path =~# ',,$'
|
||||
let path = &g:path[0:-2] . path . ',,'
|
||||
else
|
||||
let path = substitute(&g:path, '[^,]\zs$', ',', '') . path
|
||||
endif
|
||||
return path
|
||||
endfunction
|
||||
@@ -164,6 +170,8 @@ let b:undo_ftplugin .= "| sil! cunmap <buffer> <Plug><ctag>| sil! cunmap <buffer
|
||||
if !exists("g:no_plugin_maps") && !exists("g:no_ruby_maps")
|
||||
nmap <buffer><script> <SID>: :<C-U>
|
||||
nmap <buffer><script> <SID>c: :<C-U><C-R>=v:count ? v:count : ''<CR>
|
||||
cmap <buffer> <SID><cfile> <Plug><cfile>
|
||||
cmap <buffer> <SID><ctag> <Plug><ctag>
|
||||
|
||||
nnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'b','n')<CR>
|
||||
nnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'','n')<CR>
|
||||
@@ -210,20 +218,20 @@ if !exists("g:no_plugin_maps") && !exists("g:no_ruby_maps")
|
||||
call s:map('c', '', '<C-R><C-F> <Plug><cfile>')
|
||||
|
||||
cmap <buffer><script><expr> <SID>tagzv &foldopen =~# 'tag' ? '<Bar>norm! zv' : ''
|
||||
call s:map('n', '<silent>', '<C-]> <SID>:exe v:count1."tag <Plug><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<silent>', 'g<C-]> <SID>:exe "tjump <Plug><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<silent>', 'g] <SID>:exe "tselect <Plug><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<silent>', '<C-W>] <SID>:exe v:count1."stag <Plug><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<silent>', '<C-W><C-]> <SID>:exe v:count1."stag <Plug><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<silent>', '<C-W>g<C-]> <SID>:exe "stjump <Plug><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<silent>', '<C-W>g] <SID>:exe "stselect <Plug><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<silent>', '<C-W>} <SID>:exe v:count1."ptag <Plug><ctag>"<CR>')
|
||||
call s:map('n', '<silent>', '<C-W>g} <SID>:exe "ptjump <Plug><ctag>"<CR>')
|
||||
call s:map('n', '<script><silent>', '<C-]> <SID>:exe v:count1."tag <SID><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<script><silent>', 'g<C-]> <SID>:exe "tjump <SID><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<script><silent>', 'g] <SID>:exe "tselect <SID><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W>] <SID>:exe v:count1."stag <SID><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W><C-]> <SID>:exe v:count1."stag <SID><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W>g<C-]> <SID>:exe "stjump <SID><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W>g] <SID>:exe "stselect <SID><ctag>"<SID>tagzv<CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W>} <SID>:exe v:count1."ptag <SID><ctag>"<CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W>g} <SID>:exe "ptjump <SID><ctag>"<CR>')
|
||||
|
||||
call s:map('n', '<silent>', 'gf <SID>c:find <Plug><cfile><CR>')
|
||||
call s:map('n', '<silent>', '<C-W>f <SID>c:sfind <Plug><cfile><CR>')
|
||||
call s:map('n', '<silent>', '<C-W><C-F> <SID>c:sfind <Plug><cfile><CR>')
|
||||
call s:map('n', '<silent>', '<C-W>gf <SID>c:tabfind <Plug><cfile><CR>')
|
||||
call s:map('n', '<script><silent>', 'gf <SID>c:find <SID><cfile><CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W>f <SID>c:sfind <SID><cfile><CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W><C-F> <SID>c:sfind <SID><cfile><CR>')
|
||||
call s:map('n', '<script><silent>', '<C-W>gf <SID>c:tabfind <SID><cfile><CR>')
|
||||
endif
|
||||
|
||||
let &cpo = s:cpo_save
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
" Meikel Brandmeyer <mb@kotka.de>
|
||||
" URL: https://github.com/clojure-vim/clojure.vim
|
||||
" License: Vim (see :h license)
|
||||
" Last Change: 2021-10-26
|
||||
" Last Change: 2022-03-24
|
||||
|
||||
if exists("b:did_indent")
|
||||
finish
|
||||
|
||||
+37
-11
@@ -4,7 +4,7 @@
|
||||
" Previous Maintainer: Nikolai Weibull <now at bitwi.se>
|
||||
" URL: https://github.com/vim-ruby/vim-ruby
|
||||
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
|
||||
" Last Change: 2021 Feb 03
|
||||
" Last Change: 2022 Mar 22
|
||||
|
||||
" 0. Initialization {{{1
|
||||
" =================
|
||||
@@ -40,9 +40,11 @@ setlocal nosmartindent
|
||||
" Now, set up our indentation expression and keys that trigger it.
|
||||
setlocal indentexpr=GetRubyIndent(v:lnum)
|
||||
setlocal indentkeys=0{,0},0),0],!^F,o,O,e,:,.
|
||||
setlocal indentkeys+==end,=else,=elsif,=when,=ensure,=rescue,==begin,==end
|
||||
setlocal indentkeys+==end,=else,=elsif,=when,=in\ ,=ensure,=rescue,==begin,==end
|
||||
setlocal indentkeys+==private,=protected,=public
|
||||
|
||||
let b:undo_indent = "setlocal indentexpr< indentkeys< smartindent<"
|
||||
|
||||
" Only define the function once.
|
||||
if exists("*GetRubyIndent")
|
||||
finish
|
||||
@@ -85,14 +87,17 @@ let s:skip_expr =
|
||||
" Regex used for words that, at the start of a line, add a level of indent.
|
||||
let s:ruby_indent_keywords =
|
||||
\ '^\s*\zs\<\%(module\|class\|if\|for' .
|
||||
\ '\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure\|rescue' .
|
||||
\ '\|while\|until\|else\|elsif\|case\|when\|in\|unless\|begin\|ensure\|rescue' .
|
||||
\ '\|\%(\K\k*[!?]\?\s\+\)\=def\):\@!\>' .
|
||||
\ '\|\%([=,*/%+-]\|<<\|>>\|:\s\)\s*\zs' .
|
||||
\ '\<\%(if\|for\|while\|until\|case\|unless\|begin\):\@!\>'
|
||||
|
||||
" Def without an end clause: def method_call(...) = <expression>
|
||||
let s:ruby_endless_def = '\<def\s\+\k\+[!?]\=\%((.*)\|\s\)\s*='
|
||||
|
||||
" Regex used for words that, at the start of a line, remove a level of indent.
|
||||
let s:ruby_deindent_keywords =
|
||||
\ '^\s*\zs\<\%(ensure\|else\|rescue\|elsif\|when\|end\):\@!\>'
|
||||
\ '^\s*\zs\<\%(ensure\|else\|rescue\|elsif\|when\|in\|end\):\@!\>'
|
||||
|
||||
" Regex that defines the start-match for the 'end' keyword.
|
||||
"let s:end_start_regex = '\%(^\|[^.]\)\<\%(module\|class\|def\|if\|for\|while\|until\|case\|unless\|begin\|do\)\>'
|
||||
@@ -104,15 +109,31 @@ let s:end_start_regex =
|
||||
\ '\|\%(^\|[^.:@$]\)\@<=\<do:\@!\>'
|
||||
|
||||
" Regex that defines the middle-match for the 'end' keyword.
|
||||
let s:end_middle_regex = '\<\%(ensure\|else\|\%(\%(^\|;\)\s*\)\@<=\<rescue:\@!\>\|when\|elsif\):\@!\>'
|
||||
let s:end_middle_regex = '\<\%(ensure\|else\|\%(\%(^\|;\)\s*\)\@<=\<rescue:\@!\>\|when\|\%(\%(^\|;\)\s*\)\@<=\<in\|elsif\):\@!\>'
|
||||
|
||||
" Regex that defines the end-match for the 'end' keyword.
|
||||
let s:end_end_regex = '\%(^\|[^.:@$]\)\@<=\<end:\@!\>'
|
||||
|
||||
" Expression used for searchpair() call for finding match for 'end' keyword.
|
||||
let s:end_skip_expr = s:skip_expr .
|
||||
\ ' || (expand("<cword>") == "do"' .
|
||||
\ ' && getline(".") =~ "^\\s*\\<\\(while\\|until\\|for\\):\\@!\\>")'
|
||||
" Expression used for searchpair() call for finding a match for an 'end' keyword.
|
||||
function! s:EndSkipExpr()
|
||||
if eval(s:skip_expr)
|
||||
return 1
|
||||
elseif expand('<cword>') == 'do'
|
||||
\ && getline(".") =~ '^\s*\<\(while\|until\|for\):\@!\>'
|
||||
return 1
|
||||
elseif getline('.') =~ s:ruby_endless_def
|
||||
return 1
|
||||
elseif getline('.') =~ '\<def\s\+\k\+[!?]\=([^)]*$'
|
||||
" Then it's a `def method(` with a possible `) =` later
|
||||
call search('\<def\s\+\k\+\zs(', 'W', line('.'))
|
||||
normal! %
|
||||
return getline('.') =~ ')\s*='
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:end_skip_expr = function('s:EndSkipExpr')
|
||||
|
||||
" Regex that defines continuation lines, not including (, {, or [.
|
||||
let s:non_bracket_continuation_regex =
|
||||
@@ -572,6 +593,11 @@ function! s:AfterUnbalancedBracket(pline_info) abort
|
||||
call cursor(info.plnum, closing.pos + 1)
|
||||
normal! %
|
||||
|
||||
if strpart(info.pline, closing.pos) =~ '^)\s*='
|
||||
" special case: the closing `) =` of an endless def
|
||||
return indent(s:GetMSL(line('.')))
|
||||
endif
|
||||
|
||||
if s:Match(line('.'), s:ruby_indent_keywords)
|
||||
return indent('.') + info.sw
|
||||
else
|
||||
@@ -610,7 +636,7 @@ function! s:AfterIndentKeyword(pline_info) abort
|
||||
let info = a:pline_info
|
||||
let col = s:Match(info.plnum, s:ruby_indent_keywords)
|
||||
|
||||
if col > 0
|
||||
if col > 0 && s:Match(info.plnum, s:ruby_endless_def) <= 0
|
||||
call cursor(info.plnum, col)
|
||||
let ind = virtcol('.') - 1 + info.sw
|
||||
" TODO: make this better (we need to count them) (or, if a searchpair
|
||||
@@ -657,7 +683,7 @@ function! s:IndentingKeywordInMSL(msl_info) abort
|
||||
" TODO: this does not take into account contrived things such as
|
||||
" module Foo; class Bar; end
|
||||
let col = s:Match(info.plnum_msl, s:ruby_indent_keywords)
|
||||
if col > 0
|
||||
if col > 0 && s:Match(info.plnum_msl, s:ruby_endless_def) <= 0
|
||||
let ind = indent(info.plnum_msl) + info.sw
|
||||
if s:Match(info.plnum_msl, s:end_end_regex)
|
||||
let ind = ind - info.sw
|
||||
|
||||
+20
-22
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
||||
" Maintainer: Debian Vim Maintainers
|
||||
" Former Maintainers: Gerfried Fuchs <alfie@ist.org>
|
||||
" Wichert Akkerman <wakkerma@debian.org>
|
||||
" Last Change: 2021 Oct 19
|
||||
" Last Change: 2022 Mar 28
|
||||
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debchangelog.vim
|
||||
|
||||
" Standard syntax initialization
|
||||
@@ -24,7 +24,7 @@ let s:supported = [
|
||||
\ 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
|
||||
\ 'trixie', 'sid', 'rc-buggy',
|
||||
\
|
||||
\ 'trusty', 'xenial', 'bionic', 'focal', 'hirsute', 'impish', 'jammy',
|
||||
\ 'trusty', 'xenial', 'bionic', 'focal', 'impish', 'jammy',
|
||||
\ 'devel'
|
||||
\ ]
|
||||
let s:unsupported = [
|
||||
@@ -35,7 +35,7 @@ let s:unsupported = [
|
||||
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
|
||||
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
|
||||
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
|
||||
\ 'disco', 'eoan', 'groovy'
|
||||
\ 'disco', 'eoan', 'hirsute', 'groovy'
|
||||
\ ]
|
||||
let &cpo=s:cpo
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
" Language: Debian sources.list
|
||||
" Maintainer: Debian Vim Maintainers
|
||||
" Former Maintainer: Matthijs Mohlmann <matthijs@cacholong.nl>
|
||||
" Last Change: 2021 Oct 19
|
||||
" Last Change: 2022 Mar 28
|
||||
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debsources.vim
|
||||
|
||||
" Standard syntax initialization
|
||||
@@ -26,7 +26,7 @@ let s:supported = [
|
||||
\ 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
|
||||
\ 'trixie', 'sid', 'rc-buggy',
|
||||
\
|
||||
\ 'trusty', 'xenial', 'bionic', 'focal', 'hirsute', 'impish', 'jammy',
|
||||
\ 'trusty', 'xenial', 'bionic', 'focal', 'impish', 'jammy',
|
||||
\ 'devel'
|
||||
\ ]
|
||||
let s:unsupported = [
|
||||
@@ -37,7 +37,7 @@ let s:unsupported = [
|
||||
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
|
||||
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
|
||||
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
|
||||
\ 'disco', 'eoan', 'groovy'
|
||||
\ 'disco', 'eoan', 'hirsute', 'groovy'
|
||||
\ ]
|
||||
let &cpo=s:cpo
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
|
||||
" URL: https://github.com/vim-ruby/vim-ruby
|
||||
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
|
||||
" Last Change: 2018 Jul 04
|
||||
" Last Change: 2022 Mar 18
|
||||
|
||||
if &syntax !~# '\<eruby\>' || get(b:, 'current_syntax') =~# '\<eruby\>'
|
||||
if exists("b:current_syntax")
|
||||
finish
|
||||
endif
|
||||
|
||||
@@ -19,8 +19,6 @@ endif
|
||||
|
||||
if &filetype =~ '^eruby\.'
|
||||
let b:eruby_subtype = matchstr(&filetype,'^eruby\.\zs\w\+')
|
||||
elseif &filetype =~ '^.*\.eruby\>'
|
||||
let b:eruby_subtype = matchstr(&filetype,'^.\{-\}\ze\.eruby\>')
|
||||
elseif !exists("b:eruby_subtype") && main_syntax == 'eruby'
|
||||
let s:lines = getline(1)."\n".getline(2)."\n".getline(3)."\n".getline(4)."\n".getline(5)."\n".getline("$")
|
||||
let b:eruby_subtype = matchstr(s:lines,'eruby_subtype=\zs\w\+')
|
||||
@@ -54,10 +52,10 @@ if !b:eruby_nest_level
|
||||
let b:eruby_nest_level = 1
|
||||
endif
|
||||
|
||||
if get(b:, 'eruby_subtype', '') !~# '^\%(eruby\)\=$' && &syntax =~# '^eruby\>'
|
||||
if exists("b:eruby_subtype") && b:eruby_subtype != '' && b:eruby_subtype !=? 'eruby'
|
||||
exe "runtime! syntax/".b:eruby_subtype.".vim"
|
||||
unlet! b:current_syntax
|
||||
endif
|
||||
unlet! b:current_syntax
|
||||
syn include @rubyTop syntax/ruby.vim
|
||||
|
||||
syn cluster erubyRegions contains=erubyOneLiner,erubyBlock,erubyExpression,erubyComment
|
||||
@@ -72,7 +70,7 @@ exe 'syn region erubyComment matchgroup=erubyDelimiter start="<%\{1,'.b:erub
|
||||
hi def link erubyDelimiter PreProc
|
||||
hi def link erubyComment Comment
|
||||
|
||||
let b:current_syntax = matchstr(&syntax, '^.*\<eruby\>')
|
||||
let b:current_syntax = 'eruby'
|
||||
|
||||
if main_syntax == 'eruby'
|
||||
unlet main_syntax
|
||||
|
||||
+13
-3
@@ -3,7 +3,7 @@
|
||||
" Maintainer: Doug Kearns <dougkearns@gmail.com>
|
||||
" URL: https://github.com/vim-ruby/vim-ruby
|
||||
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
|
||||
" Last Change: 2021 Jun 06
|
||||
" Last Change: 2021 Nov 03
|
||||
" ----------------------------------------------------------------------------
|
||||
"
|
||||
" Previous Maintainer: Mirko Nasato
|
||||
@@ -66,7 +66,7 @@ endfunction
|
||||
com! -nargs=* SynFold call s:run_syntax_fold(<q-args>)
|
||||
|
||||
" Not-Top Cluster {{{1
|
||||
syn cluster rubyNotTop contains=@rubyCommentNotTop,@rubyStringNotTop,@rubyRegexpSpecial,@rubyDeclaration,@rubyExceptionHandler,@rubyClassOperator,rubyConditional,rubyModuleName,rubyClassName,rubySymbolDelimiter,rubyParentheses,@Spell
|
||||
syn cluster rubyNotTop contains=@rubyCommentNotTop,@rubyStringNotTop,@rubyRegexpSpecial,@rubyDeclaration,@rubyExceptionHandler,@rubyClassOperator,rubyConditional,rubyModuleName,rubyClassName,rubySymbolDelimiter,rubyDoubleQuoteSymbolDelimiter,rubySingleQuoteSymbolDelimiter,rubyParentheses,@Spell
|
||||
|
||||
" Whitespace Errors {{{1
|
||||
if exists("ruby_space_errors")
|
||||
@@ -364,6 +364,9 @@ if !exists("b:ruby_no_expensive") && !exists("ruby_no_expensive")
|
||||
SynFold 'class' syn region rubyClassBlock start="\<class\>" matchgroup=rubyClass skip="\<end:" end="\<end\>" contains=ALLBUT,@rubyNotTop
|
||||
SynFold 'module' syn region rubyModuleBlock start="\<module\>" matchgroup=rubyModule skip="\<end:" end="\<end\>" contains=ALLBUT,@rubyNotTop
|
||||
|
||||
" endless def
|
||||
syn match rubyDefine "\<def\s\+\ze[^[:space:];#(]\+\%(\s\+\|\s*(.*)\s*\)=" nextgroup=rubyMethodDeclaration skipwhite
|
||||
|
||||
" modifiers
|
||||
syn match rubyLineContinuation "\\$" nextgroup=@rubyModifier skipwhite skipnl
|
||||
syn match rubyConditionalModifier "\<\%(if\|unless\)\>"
|
||||
@@ -430,9 +433,10 @@ endif
|
||||
" Comments and Documentation {{{1
|
||||
syn match rubySharpBang "\%^#!.*" display
|
||||
syn keyword rubyTodo FIXME NOTE TODO OPTIMIZE HACK REVIEW XXX todo contained
|
||||
syn match rubyEncoding "[[:alnum:]-]\+" contained display
|
||||
syn match rubyEncoding "[[:alnum:]-_]\+" contained display
|
||||
syn match rubyMagicComment "\c\%<3l#\s*\zs\%(coding\|encoding\):" contained nextgroup=rubyEncoding skipwhite
|
||||
syn match rubyMagicComment "\c\%<10l#\s*\zs\%(frozen_string_literal\|warn_indent\|warn_past_scope\):" contained nextgroup=rubyBoolean skipwhite
|
||||
syn match rubyMagicComment "\c\%<10l#\s*\zs\%(shareable_constant_value\):" contained nextgroup=rubyEncoding skipwhite
|
||||
syn match rubyComment "#.*" contains=@rubyCommentSpecial,rubySpaceError,@Spell
|
||||
|
||||
syn cluster rubyCommentSpecial contains=rubySharpBang,rubyTodo,rubyMagicComment
|
||||
@@ -465,6 +469,10 @@ syn match rubyDefinedOperator "\%#=1\<defined?" display
|
||||
syn match rubySymbol "\%(\w\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[?!]\=::\@!"he=e-1 contained containedin=rubyBlockParameterList,rubyCurlyBlock
|
||||
syn match rubySymbol "[]})\"':]\@1<!\<\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],;]\@="he=e-1
|
||||
syn match rubySymbol "[[:space:],{(]\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],;]\@="hs=s+1,he=e-1
|
||||
syn match rubySingleQuoteSymbolDelimiter "'" contained
|
||||
syn match rubySymbol "'\%(\\.\|[^']\)*'::\@!"he=e-1 contains=rubyQuoteEscape,rubyBackslashEscape,rubySingleQuoteSymbolDelimiter
|
||||
syn match rubyDoubleQuoteSymbolDelimiter "\"" contained
|
||||
syn match rubySymbol "\"\%(\\.\|[^\"]\)*\"::\@!"he=e-1 contains=@rubyStringSpecial,rubyDoubleQuoteSymbolDelimiter
|
||||
|
||||
" __END__ Directive {{{1
|
||||
SynFold '__END__' syn region rubyData matchgroup=rubyDataDirective start="^__END__$" end="\%$"
|
||||
@@ -565,6 +573,8 @@ hi def link rubyHeredocDelimiter rubyStringDelimiter
|
||||
hi def link rubyPercentRegexpDelimiter rubyRegexpDelimiter
|
||||
hi def link rubyPercentStringDelimiter rubyStringDelimiter
|
||||
hi def link rubyPercentSymbolDelimiter rubySymbolDelimiter
|
||||
hi def link rubyDoubleQuoteSymbolDelimiter rubySymbolDelimiter
|
||||
hi def link rubySingleQuoteSymbolDelimiter rubySymbolDelimiter
|
||||
hi def link rubyRegexpDelimiter rubyStringDelimiter
|
||||
hi def link rubySymbolDelimiter rubySymbol
|
||||
hi def link rubyString String
|
||||
|
||||
+79
-48
@@ -1,5 +1,5 @@
|
||||
" Language: tmux(1) configuration file
|
||||
" Version: 3.2a (git-44ada9cd)
|
||||
" Version: 3.3-rc (git-964deae4)
|
||||
" URL: https://github.com/ericpruitt/tmux.vim/
|
||||
" Maintainer: Eric Pruitt <eric.pruitt@gmail.com>
|
||||
" License: 2-Clause BSD (http://opensource.org/licenses/BSD-2-Clause)
|
||||
@@ -18,40 +18,49 @@ syntax iskeyword @,48-57,_,192-255,-
|
||||
syntax case match
|
||||
|
||||
syn keyword tmuxAction none any current other
|
||||
syn keyword tmuxBoolean off on
|
||||
syn keyword tmuxBoolean off on yes no
|
||||
|
||||
syn keyword tmuxTodo FIXME NOTE TODO XXX contained
|
||||
|
||||
syn match tmuxColour /\<colour[0-9]\+/ display
|
||||
syn match tmuxColour /\<colou\?r[0-9]\+\>/ display
|
||||
syn match tmuxKey /\(C-\|M-\|\^\)\+\S\+/ display
|
||||
syn match tmuxNumber /\<\d\+\>/ display
|
||||
syn match tmuxFlags /\s-\a\+/ display
|
||||
syn match tmuxVariable /\w\+=/ display
|
||||
syn match tmuxVariableExpansion /\${\=\w\+}\=/ display
|
||||
syn match tmuxControl /%\(if\|elif\|else\|endif\)/
|
||||
syn match tmuxVariableExpansion /\$\({[A-Za-z_]\w*}\|[A-Za-z_]\w*\)/ display
|
||||
syn match tmuxControl /^\s*%\(if\|elif\|else\|endif\)\>/
|
||||
syn match tmuxEscape /\\\(u\x\{4\}\|U\x\{8\}\|\o\{3\}\|[\\ernt$]\)/ display
|
||||
|
||||
syn region tmuxComment start=/#/ skip=/\\\@<!\\$/ end=/$/ contains=tmuxTodo,@Spell
|
||||
|
||||
syn region tmuxString start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=tmuxFormatString,@Spell
|
||||
syn region tmuxString start=+'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end='$' contains=tmuxFormatString,@Spell
|
||||
syn region tmuxString start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=tmuxFormatString,tmuxEscape,tmuxVariableExpansion,@Spell
|
||||
syn region tmuxUninterpolatedString start=+'+ skip=+\\$+ excludenl end=+'+ end='$' contains=tmuxFormatString,@Spell
|
||||
|
||||
" TODO: Figure out how escaping works inside of #(...) and #{...} blocks.
|
||||
syn region tmuxFormatString start=/#[#DFhHIPSTW]/ end=// contained keepend
|
||||
syn region tmuxFormatString start=/#{/ skip=/#{.\{-}}/ end=/}/ keepend
|
||||
syn region tmuxFormatString start=/#(/ skip=/#(.\{-})/ end=/)/ contained keepend
|
||||
|
||||
" At the time of this writing, the latest tmux release will parse a line
|
||||
" reading "abc=xyz set-option ..." as an assignment followed by a command
|
||||
" hence the presence of "\s" in the "end" argument.
|
||||
syn region tmuxAssignment matchgroup=tmuxVariable start=/^\s*[A-Za-z_]\w*=\@=/ skip=/\\$\|\\\s/ end=/\s\|$/ contains=tmuxString,tmuxUninterpolatedString,tmuxVariableExpansion,tmuxControl,tmuxEscape
|
||||
|
||||
hi def link tmuxFormatString Identifier
|
||||
hi def link tmuxAction Boolean
|
||||
hi def link tmuxBoolean Boolean
|
||||
hi def link tmuxCommands Keyword
|
||||
hi def link tmuxControl Keyword
|
||||
hi def link tmuxControl PreCondit
|
||||
hi def link tmuxComment Comment
|
||||
hi def link tmuxEscape Special
|
||||
hi def link tmuxEscapeUnquoted Special
|
||||
hi def link tmuxKey Special
|
||||
hi def link tmuxNumber Number
|
||||
hi def link tmuxFlags Identifier
|
||||
hi def link tmuxOptions Function
|
||||
hi def link tmuxString String
|
||||
hi def link tmuxTodo Todo
|
||||
hi def link tmuxUninterpolatedString
|
||||
\ String
|
||||
hi def link tmuxVariable Identifier
|
||||
hi def link tmuxVariableExpansion Identifier
|
||||
|
||||
@@ -61,63 +70,85 @@ hi def link tmuxVariableExpansion Identifier
|
||||
if get(g:, "tmux_syntax_colors", 1)
|
||||
for s:i in range(0, 255)
|
||||
let s:bg = (!s:i || s:i == 16 || (s:i > 231 && s:i < 235)) ? 15 : "none"
|
||||
exec "syn match tmuxColour" . s:i . " /\\<colour" . s:i . "\\>/ display"
|
||||
exec "syn match tmuxColour" . s:i . " /\\<colou\\?r" . s:i . "\\>/ display"
|
||||
\ " | highlight tmuxColour" . s:i . " ctermfg=" . s:i . " ctermbg=" . s:bg
|
||||
endfor
|
||||
endif
|
||||
|
||||
syn keyword tmuxOptions
|
||||
\ backspace buffer-limit command-alias copy-command default-terminal editor
|
||||
\ escape-time exit-empty activity-action assume-paste-time base-index
|
||||
\ bell-action default-command default-shell default-size destroy-unattached
|
||||
\ activity-action after-bind-key after-capture-pane after-copy-mode
|
||||
\ after-display-message after-display-panes after-kill-pane
|
||||
\ after-list-buffers after-list-clients after-list-keys after-list-panes
|
||||
\ after-list-sessions after-list-windows after-load-buffer after-lock-server
|
||||
\ after-new-session after-new-window after-paste-buffer after-pipe-pane
|
||||
\ after-queue after-refresh-client after-rename-session after-rename-window
|
||||
\ after-resize-pane after-resize-window after-save-buffer
|
||||
\ after-select-layout after-select-pane after-select-window after-send-keys
|
||||
\ after-set-buffer after-set-environment after-set-hook after-set-option
|
||||
\ after-show-environment after-show-messages after-show-options
|
||||
\ after-split-window after-unbind-key aggressive-resize alert-activity
|
||||
\ alert-bell alert-silence allow-passthrough allow-rename alternate-screen
|
||||
\ assume-paste-time automatic-rename automatic-rename-format backspace
|
||||
\ base-index bell-action buffer-limit client-active client-attached
|
||||
\ client-detached client-focus-in client-focus-out client-resized
|
||||
\ client-session-changed clock-mode-colour clock-mode-style command-alias
|
||||
\ copy-command copy-mode-current-match-style copy-mode-mark-style
|
||||
\ copy-mode-match-style cursor-colour cursor-style default-command
|
||||
\ default-shell default-size default-terminal destroy-unattached
|
||||
\ detach-on-destroy display-panes-active-colour display-panes-colour
|
||||
\ display-panes-time display-time exit-unattached extended-keys focus-events
|
||||
\ history-file history-limit key-table lock-after-time lock-command
|
||||
\ message-command-style message-limit message-style aggressive-resize
|
||||
\ allow-rename alternate-screen automatic-rename automatic-rename-format
|
||||
\ clock-mode-colour clock-mode-style copy-mode-current-match-style
|
||||
\ copy-mode-mark-style copy-mode-match-style main-pane-height
|
||||
\ main-pane-width mode-keys mode-style monitor-activity monitor-bell
|
||||
\ monitor-silence mouse other-pane-height other-pane-width
|
||||
\ pane-active-border-style pane-base-index pane-border-format
|
||||
\ pane-border-lines pane-border-status pane-border-style pane-colours prefix
|
||||
\ prefix2 prompt-history-limit remain-on-exit renumber-windows repeat-time
|
||||
\ set-clipboard set-titles set-titles-string silence-action status status-bg
|
||||
\ status-fg status-format status-interval status-justify status-keys
|
||||
\ status-left status-left-length status-left-style status-position
|
||||
\ status-right status-right-length status-right-style status-style
|
||||
\ synchronize-panes terminal-features terminal-overrides update-environment
|
||||
\ user-keys visual-activity visual-bell visual-silence window-active-style
|
||||
\ display-panes-time display-time editor escape-time exit-empty
|
||||
\ exit-unattached extended-keys fill-character focus-events history-file
|
||||
\ history-limit key-table lock-after-time lock-command main-pane-height
|
||||
\ main-pane-width message-command-style message-limit message-style
|
||||
\ mode-keys mode-style monitor-activity monitor-bell monitor-silence mouse
|
||||
\ other-pane-height other-pane-width pane-active-border-style
|
||||
\ pane-base-index pane-border-format pane-border-indicators
|
||||
\ pane-border-lines pane-border-status pane-border-style pane-colours
|
||||
\ pane-died pane-exited pane-focus-in pane-focus-out pane-mode-changed
|
||||
\ pane-set-clipboard pane-title-changed popup-border-lines
|
||||
\ popup-border-style popup-style prefix prefix2 prompt-history-limit
|
||||
\ remain-on-exit remain-on-exit-format renumber-windows repeat-time
|
||||
\ scroll-on-clear session-closed session-created session-renamed
|
||||
\ session-window-changed set-clipboard set-titles set-titles-string
|
||||
\ silence-action status status-bg status-fg status-format status-interval
|
||||
\ status-justify status-keys status-left status-left-length
|
||||
\ status-left-style status-position status-right status-right-length
|
||||
\ status-right-style status-style synchronize-panes terminal-features
|
||||
\ terminal-overrides update-environment user-keys visual-activity
|
||||
\ visual-bell visual-silence window-active-style window-layout-changed
|
||||
\ window-linked window-pane-changed window-renamed window-resized
|
||||
\ window-size window-status-activity-style window-status-bell-style
|
||||
\ window-status-current-format window-status-current-style
|
||||
\ window-status-format window-status-last-style window-status-separator
|
||||
\ window-status-style window-style word-separators wrap-search
|
||||
\ window-status-style window-style window-unlinked word-separators
|
||||
\ wrap-search xterm-keys
|
||||
|
||||
syn keyword tmuxCommands
|
||||
\ attach attach-session bind bind-key break-pane breakp capture-pane
|
||||
\ capturep choose-buffer choose-client choose-tree clear-history clearhist
|
||||
\ capturep choose-buffer choose-client choose-session choose-tree
|
||||
\ choose-window clear-history clear-prompt-history clearhist clearphist
|
||||
\ clock-mode command-prompt confirm confirm-before copy-mode customize-mode
|
||||
\ detach detach-client display display-menu display-message display-panes
|
||||
\ display-popup displayp find-window findw if if-shell join-pane joinp
|
||||
\ kill-pane kill-server kill-session kill-window killp has has-session killw
|
||||
\ delete-buffer deleteb detach detach-client display display-menu
|
||||
\ display-message display-panes display-popup displayp find-window findw has
|
||||
\ has-session if if-shell info join-pane joinp kill-pane kill-server
|
||||
\ kill-session kill-window killp killw last last-pane last-window lastp
|
||||
\ link-window linkw list-buffers list-clients list-commands list-keys
|
||||
\ list-panes list-sessions list-windows load-buffer loadb lock lock-client
|
||||
\ lock-server lock-session lockc last-pane lastp locks ls last last-window
|
||||
\ lsb delete-buffer deleteb lsc lscm lsk lsp lsw menu move-pane move-window
|
||||
\ clear-prompt-history clearphist movep movew new new-session new-window
|
||||
\ neww next next-layout next-window nextl paste-buffer pasteb pipe-pane
|
||||
\ pipep popup prev previous-layout previous-window prevl refresh
|
||||
\ refresh-client rename rename-session rename-window renamew resize-pane
|
||||
\ resize-window resizep resizew respawn-pane respawn-window respawnp
|
||||
\ respawnw rotate-window rotatew run run-shell save-buffer saveb
|
||||
\ select-layout select-pane select-window selectl selectp selectw send
|
||||
\ send-keys send-prefix set set-buffer set-environment set-hook set-option
|
||||
\ lock-server lock-session lockc locks ls lsb lsc lscm lsk lsp lsw menu
|
||||
\ move-pane move-window movep movew new new-session new-window neww next
|
||||
\ next-layout next-window nextl paste-buffer pasteb pipe-pane pipep popup
|
||||
\ prev previous-layout previous-window prevl refresh refresh-client rename
|
||||
\ rename-session rename-window renamew resize-pane resize-window resizep
|
||||
\ resizew respawn-pane respawn-window respawnp respawnw rotate-window
|
||||
\ rotatew run run-shell save-buffer saveb select-layout select-pane
|
||||
\ select-window selectl selectp selectw send send-keys send-prefix
|
||||
\ server-info set set-buffer set-environment set-hook set-option
|
||||
\ set-window-option setb setenv setw show show-buffer show-environment
|
||||
\ show-hooks show-messages show-options show-prompt-history
|
||||
\ show-window-options showb showenv showmsgs showphist showw source
|
||||
\ source-file split-window splitw start start-server suspend-client suspendc
|
||||
\ swap-pane swap-window swapp swapw switch-client switchc unbind unbind-key
|
||||
\ unlink-window unlinkw wait wait-for
|
||||
\ source-file split-pane split-window splitp splitw start start-server
|
||||
\ suspend-client suspendc swap-pane swap-window swapp swapw switch-client
|
||||
\ switchc unbind unbind-key unlink-window unlinkw wait wait-for
|
||||
|
||||
let &cpo = s:original_cpo
|
||||
unlet! s:original_cpo s:bg s:i
|
||||
|
||||
+1
-1
@@ -641,7 +641,7 @@ changed_common(
|
||||
set_topline(wp, wp->w_topline);
|
||||
#endif
|
||||
// Relative numbering may require updating more.
|
||||
if (wp->w_p_rnu)
|
||||
if (wp->w_p_rnu && xtra != 0)
|
||||
redraw_win_later(wp, SOME_VALID);
|
||||
#ifdef FEAT_SYN_HL
|
||||
// Cursor line highlighting probably need to be updated with
|
||||
|
||||
+253
-45
@@ -2137,6 +2137,83 @@ channel_fill(js_read_T *reader)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the HTTP header in a Language Server Protocol (LSP) message.
|
||||
*
|
||||
* The message format is described in the LSP specification:
|
||||
* https://microsoft.github.io/language-server-protocol/specification
|
||||
*
|
||||
* It has the following two fields:
|
||||
*
|
||||
* Content-Length: ...
|
||||
* Content-Type: application/vscode-jsonrpc; charset=utf-8
|
||||
*
|
||||
* Each field ends with "\r\n". The header ends with an additional "\r\n".
|
||||
*
|
||||
* Returns OK if a valid header is received and FAIL if some fields in the
|
||||
* header are not correct. Returns MAYBE if a partial header is received and
|
||||
* need to wait for more data to arrive.
|
||||
*/
|
||||
static int
|
||||
channel_process_lsp_http_hdr(js_read_T *reader)
|
||||
{
|
||||
char_u *line_start;
|
||||
char_u *p;
|
||||
int_u hdr_len;
|
||||
int payload_len = -1;
|
||||
int_u jsbuf_len;
|
||||
|
||||
// We find the end once, to avoid calling strlen() many times.
|
||||
jsbuf_len = (int_u)STRLEN(reader->js_buf);
|
||||
reader->js_end = reader->js_buf + jsbuf_len;
|
||||
|
||||
p = reader->js_buf;
|
||||
|
||||
// Process each line in the header till an empty line is read (header
|
||||
// separator).
|
||||
while (TRUE)
|
||||
{
|
||||
line_start = p;
|
||||
while (*p != NUL && *p != '\n')
|
||||
p++;
|
||||
if (*p == NUL) // partial header
|
||||
return MAYBE;
|
||||
p++;
|
||||
|
||||
// process the content length field (if present)
|
||||
if ((p - line_start > 16)
|
||||
&& STRNICMP(line_start, "Content-Length: ", 16) == 0)
|
||||
{
|
||||
errno = 0;
|
||||
payload_len = strtol((char *)line_start + 16, NULL, 10);
|
||||
if (errno == ERANGE || payload_len < 0)
|
||||
// invalid length, discard the payload
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if ((p - line_start) == 2 && line_start[0] == '\r' &&
|
||||
line_start[1] == '\n')
|
||||
// reached the empty line
|
||||
break;
|
||||
}
|
||||
|
||||
if (payload_len == -1)
|
||||
// Content-Length field is not present in the header
|
||||
return FAIL;
|
||||
|
||||
hdr_len = p - reader->js_buf;
|
||||
|
||||
// if the entire payload is not received, wait for more data to arrive
|
||||
if (jsbuf_len < hdr_len + payload_len)
|
||||
return MAYBE;
|
||||
|
||||
reader->js_used += hdr_len;
|
||||
// recalculate the end based on the length read from the header.
|
||||
reader->js_end = reader->js_buf + hdr_len + payload_len;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the read buffer of "channel"/"part" and parse a JSON message that is
|
||||
* complete. The messages are added to the queue.
|
||||
@@ -2150,7 +2227,7 @@ channel_parse_json(channel_T *channel, ch_part_T part)
|
||||
jsonq_T *item;
|
||||
chanpart_T *chanpart = &channel->ch_part[part];
|
||||
jsonq_T *head = &chanpart->ch_json_head;
|
||||
int status;
|
||||
int status = OK;
|
||||
int ret;
|
||||
|
||||
if (channel_peek(channel, part) == NULL)
|
||||
@@ -2162,19 +2239,31 @@ channel_parse_json(channel_T *channel, ch_part_T part)
|
||||
reader.js_cookie = channel;
|
||||
reader.js_cookie_arg = part;
|
||||
|
||||
if (chanpart->ch_mode == MODE_LSP)
|
||||
status = channel_process_lsp_http_hdr(&reader);
|
||||
|
||||
// When a message is incomplete we wait for a short while for more to
|
||||
// arrive. After the delay drop the input, otherwise a truncated string
|
||||
// or list will make us hang.
|
||||
// Do not generate error messages, they will be written in a channel log.
|
||||
++emsg_silent;
|
||||
status = json_decode(&reader, &listtv,
|
||||
chanpart->ch_mode == MODE_JS ? JSON_JS : 0);
|
||||
--emsg_silent;
|
||||
if (status == OK)
|
||||
{
|
||||
++emsg_silent;
|
||||
status = json_decode(&reader, &listtv,
|
||||
chanpart->ch_mode == MODE_JS ? JSON_JS : 0);
|
||||
--emsg_silent;
|
||||
}
|
||||
if (status == OK)
|
||||
{
|
||||
// Only accept the response when it is a list with at least two
|
||||
// items.
|
||||
if (listtv.v_type != VAR_LIST || listtv.vval.v_list->lv_len < 2)
|
||||
if (chanpart->ch_mode == MODE_LSP && listtv.v_type != VAR_DICT)
|
||||
{
|
||||
ch_error(channel, "Did not receive a LSP dict, discarding");
|
||||
clear_tv(&listtv);
|
||||
}
|
||||
else if (chanpart->ch_mode != MODE_LSP &&
|
||||
(listtv.v_type != VAR_LIST || listtv.vval.v_list->lv_len < 2))
|
||||
{
|
||||
if (listtv.v_type != VAR_LIST)
|
||||
ch_error(channel, "Did not receive a list, discarding");
|
||||
@@ -2401,11 +2490,38 @@ channel_get_json(
|
||||
|
||||
while (item != NULL)
|
||||
{
|
||||
list_T *l = item->jq_value->vval.v_list;
|
||||
list_T *l;
|
||||
typval_T *tv;
|
||||
|
||||
CHECK_LIST_MATERIALIZE(l);
|
||||
tv = &l->lv_first->li_tv;
|
||||
if (channel->ch_part[part].ch_mode != MODE_LSP)
|
||||
{
|
||||
l = item->jq_value->vval.v_list;
|
||||
CHECK_LIST_MATERIALIZE(l);
|
||||
tv = &l->lv_first->li_tv;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict_T *d;
|
||||
dictitem_T *di;
|
||||
|
||||
// LSP message payload is a JSON-RPC dict.
|
||||
// For RPC requests and responses, the 'id' item will be present.
|
||||
// For notifications, it will not be present.
|
||||
if (id > 0)
|
||||
{
|
||||
if (item->jq_value->v_type != VAR_DICT)
|
||||
goto nextitem;
|
||||
d = item->jq_value->vval.v_dict;
|
||||
if (d == NULL)
|
||||
goto nextitem;
|
||||
di = dict_find(d, (char_u *)"id", -1);
|
||||
if (di == NULL)
|
||||
goto nextitem;
|
||||
tv = &di->di_tv;
|
||||
}
|
||||
else
|
||||
tv = item->jq_value;
|
||||
}
|
||||
|
||||
if ((without_callback || !item->jq_no_callback)
|
||||
&& ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
|
||||
@@ -2421,6 +2537,7 @@ channel_get_json(
|
||||
remove_json_node(head, item);
|
||||
return OK;
|
||||
}
|
||||
nextitem:
|
||||
item = item->jq_next;
|
||||
}
|
||||
return FAIL;
|
||||
@@ -2788,6 +2905,7 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
|
||||
callback_T *callback = NULL;
|
||||
buf_T *buffer = NULL;
|
||||
char_u *p;
|
||||
int called_otc; // one time callbackup
|
||||
|
||||
if (channel->ch_nb_close_cb != NULL)
|
||||
// this channel is handled elsewhere (netbeans)
|
||||
@@ -2814,7 +2932,7 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
|
||||
if (ch_mode == MODE_JSON || ch_mode == MODE_JS || ch_mode == MODE_LSP)
|
||||
{
|
||||
listitem_T *item;
|
||||
int argc = 0;
|
||||
@@ -2828,29 +2946,47 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (item = listtv->vval.v_list->lv_first;
|
||||
item != NULL && argc < CH_JSON_MAX_ARGS;
|
||||
item = item->li_next)
|
||||
argv[argc++] = item->li_tv;
|
||||
while (argc < CH_JSON_MAX_ARGS)
|
||||
argv[argc++].v_type = VAR_UNKNOWN;
|
||||
|
||||
if (argv[0].v_type == VAR_STRING)
|
||||
if (ch_mode == MODE_LSP)
|
||||
{
|
||||
// ["cmd", arg] or ["cmd", arg, arg] or ["cmd", arg, arg, arg]
|
||||
channel_exe_cmd(channel, part, argv);
|
||||
free_tv(listtv);
|
||||
return TRUE;
|
||||
}
|
||||
dict_T *d = listtv->vval.v_dict;
|
||||
dictitem_T *di;
|
||||
|
||||
if (argv[0].v_type != VAR_NUMBER)
|
||||
{
|
||||
ch_error(channel,
|
||||
"Dropping message with invalid sequence number type");
|
||||
free_tv(listtv);
|
||||
return FALSE;
|
||||
seq_nr = 0;
|
||||
if (d != NULL)
|
||||
{
|
||||
di = dict_find(d, (char_u *)"id", -1);
|
||||
if (di != NULL && di->di_tv.v_type == VAR_NUMBER)
|
||||
seq_nr = di->di_tv.vval.v_number;
|
||||
}
|
||||
|
||||
argv[1] = *listtv;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (item = listtv->vval.v_list->lv_first;
|
||||
item != NULL && argc < CH_JSON_MAX_ARGS;
|
||||
item = item->li_next)
|
||||
argv[argc++] = item->li_tv;
|
||||
while (argc < CH_JSON_MAX_ARGS)
|
||||
argv[argc++].v_type = VAR_UNKNOWN;
|
||||
|
||||
if (argv[0].v_type == VAR_STRING)
|
||||
{
|
||||
// ["cmd", arg] or ["cmd", arg, arg] or ["cmd", arg, arg, arg]
|
||||
channel_exe_cmd(channel, part, argv);
|
||||
free_tv(listtv);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (argv[0].v_type != VAR_NUMBER)
|
||||
{
|
||||
ch_error(channel,
|
||||
"Dropping message with invalid sequence number type");
|
||||
free_tv(listtv);
|
||||
return FALSE;
|
||||
}
|
||||
seq_nr = argv[0].vval.v_number;
|
||||
}
|
||||
seq_nr = argv[0].vval.v_number;
|
||||
}
|
||||
else if (channel_peek(channel, part) == NULL)
|
||||
{
|
||||
@@ -2932,24 +3068,35 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
|
||||
argv[1].vval.v_string = msg;
|
||||
}
|
||||
|
||||
called_otc = FALSE;
|
||||
if (seq_nr > 0)
|
||||
{
|
||||
int done = FALSE;
|
||||
|
||||
// JSON or JS mode: invoke the one-time callback with the matching nr
|
||||
// JSON or JS or LSP mode: invoke the one-time callback with the
|
||||
// matching nr
|
||||
for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
|
||||
if (cbitem->cq_seq_nr == seq_nr)
|
||||
{
|
||||
invoke_one_time_callback(channel, cbhead, cbitem, argv);
|
||||
done = TRUE;
|
||||
called_otc = TRUE;
|
||||
break;
|
||||
}
|
||||
if (!done)
|
||||
}
|
||||
|
||||
if (seq_nr > 0 && (ch_mode != MODE_LSP || called_otc))
|
||||
{
|
||||
if (!called_otc)
|
||||
{
|
||||
// If the 'drop' channel attribute is set to 'never' or if
|
||||
// ch_evalexpr() is waiting for this response message, then don't
|
||||
// drop this message.
|
||||
if (channel->ch_drop_never)
|
||||
{
|
||||
// message must be read with ch_read()
|
||||
channel_push_json(channel, part, listtv);
|
||||
|
||||
// Change the type to avoid the value being freed.
|
||||
listtv->v_type = VAR_NUMBER;
|
||||
free_tv(listtv);
|
||||
listtv = NULL;
|
||||
}
|
||||
else
|
||||
@@ -3032,7 +3179,7 @@ channel_has_readahead(channel_T *channel, ch_part_T part)
|
||||
{
|
||||
ch_mode_T ch_mode = channel->ch_part[part].ch_mode;
|
||||
|
||||
if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
|
||||
if (ch_mode == MODE_JSON || ch_mode == MODE_JS || ch_mode == MODE_LSP)
|
||||
{
|
||||
jsonq_T *head = &channel->ch_part[part].ch_json_head;
|
||||
|
||||
@@ -3118,6 +3265,7 @@ channel_part_info(channel_T *channel, dict_T *dict, char *name, ch_part_T part)
|
||||
case MODE_RAW: s = "RAW"; break;
|
||||
case MODE_JSON: s = "JSON"; break;
|
||||
case MODE_JS: s = "JS"; break;
|
||||
case MODE_LSP: s = "LSP"; break;
|
||||
}
|
||||
dict_add_string(dict, namebuf, (char_u *)s);
|
||||
|
||||
@@ -4354,9 +4502,59 @@ ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
|
||||
return;
|
||||
}
|
||||
|
||||
id = ++channel->ch_last_msg_id;
|
||||
text = json_encode_nr_expr(id, &argvars[1],
|
||||
(ch_mode == MODE_JS ? JSON_JS : 0) | JSON_NL);
|
||||
if (ch_mode == MODE_LSP)
|
||||
{
|
||||
dict_T *d;
|
||||
dictitem_T *di;
|
||||
int callback_present = FALSE;
|
||||
|
||||
if (argvars[1].v_type != VAR_DICT)
|
||||
{
|
||||
semsg(_(e_dict_required_for_argument_nr), 2);
|
||||
return;
|
||||
}
|
||||
d = argvars[1].vval.v_dict;
|
||||
di = dict_find(d, (char_u *)"id", -1);
|
||||
if (di != NULL && di->di_tv.v_type != VAR_NUMBER)
|
||||
{
|
||||
// only number type is supported for the 'id' item
|
||||
semsg(_(e_invalid_value_for_argument_str), "id");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argvars[2].v_type == VAR_DICT)
|
||||
if (dict_find(argvars[2].vval.v_dict, (char_u *)"callback", -1)
|
||||
!= NULL)
|
||||
callback_present = TRUE;
|
||||
|
||||
if (eval || callback_present)
|
||||
{
|
||||
// When evaluating an expression or sending an expression with a
|
||||
// callback, always assign a generated ID
|
||||
id = ++channel->ch_last_msg_id;
|
||||
if (di == NULL)
|
||||
dict_add_number(d, "id", id);
|
||||
else
|
||||
di->di_tv.vval.v_number = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
// When sending an expression, if the message has an 'id' item,
|
||||
// then use it.
|
||||
id = 0;
|
||||
if (di != NULL)
|
||||
id = di->di_tv.vval.v_number;
|
||||
}
|
||||
if (dict_find(d, (char_u *)"jsonrpc", -1) == NULL)
|
||||
dict_add_string(d, "jsonrpc", (char_u *)"2.0");
|
||||
text = json_encode_lsp_msg(&argvars[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = ++channel->ch_last_msg_id;
|
||||
text = json_encode_nr_expr(id, &argvars[1],
|
||||
(ch_mode == MODE_JS ? JSON_JS : 0) | JSON_NL);
|
||||
}
|
||||
if (text == NULL)
|
||||
return;
|
||||
|
||||
@@ -4372,13 +4570,23 @@ ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
|
||||
if (channel_read_json_block(channel, part_read, timeout, id, &listtv)
|
||||
== OK)
|
||||
{
|
||||
list_T *list = listtv->vval.v_list;
|
||||
if (ch_mode == MODE_LSP)
|
||||
{
|
||||
*rettv = *listtv;
|
||||
// Change the type to avoid the value being freed.
|
||||
listtv->v_type = VAR_NUMBER;
|
||||
free_tv(listtv);
|
||||
}
|
||||
else
|
||||
{
|
||||
list_T *list = listtv->vval.v_list;
|
||||
|
||||
// Move the item from the list and then change the type to
|
||||
// avoid the value being freed.
|
||||
*rettv = list->lv_u.mat.lv_last->li_tv;
|
||||
list->lv_u.mat.lv_last->li_tv.v_type = VAR_NUMBER;
|
||||
free_tv(listtv);
|
||||
// Move the item from the list and then change the type to
|
||||
// avoid the value being freed.
|
||||
*rettv = list->lv_u.mat.lv_last->li_tv;
|
||||
list->lv_u.mat.lv_last->li_tv.v_type = VAR_NUMBER;
|
||||
free_tv(listtv);
|
||||
}
|
||||
}
|
||||
}
|
||||
free_job_options(&opt);
|
||||
|
||||
+4
-3
@@ -2507,11 +2507,11 @@ win_update(win_T *wp)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wp->w_p_rnu)
|
||||
if (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum)
|
||||
{
|
||||
#ifdef FEAT_FOLDING
|
||||
// 'relativenumber' set: The text doesn't need to be drawn, but
|
||||
// the number column nearly always does.
|
||||
// 'relativenumber' set and the cursor moved vertically: The
|
||||
// text doesn't need to be drawn, but the number column does.
|
||||
fold_count = foldedCount(wp, lnum, &win_foldinfo);
|
||||
if (fold_count != 0)
|
||||
fold_line(wp, fold_count, &win_foldinfo, lnum, row);
|
||||
@@ -2553,6 +2553,7 @@ win_update(win_T *wp)
|
||||
// update w_last_cursorline.
|
||||
wp->w_last_cursorline = wp->w_p_cul ? wp->w_cursor.lnum : 0;
|
||||
#endif
|
||||
wp->w_last_cursor_lnum_rnu = wp->w_p_rnu ? wp->w_cursor.lnum : 0;
|
||||
|
||||
#ifdef FEAT_VTP
|
||||
// Rewrite the character at the end of the screen line.
|
||||
|
||||
+3
-2
@@ -30,8 +30,9 @@ EXTERN char e_invalid_expression_str[]
|
||||
#endif
|
||||
EXTERN char e_invalid_range[]
|
||||
INIT(= N_("E16: Invalid range"));
|
||||
#if defined(UNIX) || defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
|
||||
EXTERN char e_src_is_directory[]
|
||||
#if defined(UNIX) || defined(FEAT_SYN_HL) \
|
||||
|| defined(FEAT_SPELL) || defined(FEAT_EVAL)
|
||||
EXTERN char e_str_is_directory[]
|
||||
INIT(= N_("E17: \"%s\" is a directory"));
|
||||
#endif
|
||||
#ifdef FEAT_EVAL
|
||||
|
||||
+22
-8
@@ -5296,15 +5296,29 @@ echo_string_core(
|
||||
break;
|
||||
|
||||
case VAR_FUNC:
|
||||
if (echo_style)
|
||||
{
|
||||
*tofree = NULL;
|
||||
r = tv->vval.v_string;
|
||||
}
|
||||
else
|
||||
{
|
||||
*tofree = string_quote(tv->vval.v_string, TRUE);
|
||||
r = *tofree;
|
||||
char_u buf[MAX_FUNC_NAME_LEN];
|
||||
|
||||
if (echo_style)
|
||||
{
|
||||
r = make_ufunc_name_readable(tv->vval.v_string,
|
||||
buf, MAX_FUNC_NAME_LEN);
|
||||
if (r == buf)
|
||||
{
|
||||
r = vim_strsave(buf);
|
||||
*tofree = r;
|
||||
}
|
||||
else
|
||||
*tofree = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*tofree = string_quote(tv->vval.v_string == NULL ? NULL
|
||||
: make_ufunc_name_readable(
|
||||
tv->vval.v_string, buf, MAX_FUNC_NAME_LEN),
|
||||
TRUE);
|
||||
r = *tofree;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+9
-1
@@ -2825,7 +2825,7 @@ eval_variable(
|
||||
{
|
||||
if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
|
||||
&& ((type != NULL && type != &t_dict_empty)
|
||||
|| !in_vim9script()))
|
||||
|| !in_vim9script()))
|
||||
{
|
||||
tv->vval.v_dict = dict_alloc();
|
||||
if (tv->vval.v_dict != NULL)
|
||||
@@ -2845,6 +2845,14 @@ eval_variable(
|
||||
tv->vval.v_list->lv_type = alloc_type(type);
|
||||
}
|
||||
}
|
||||
else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL
|
||||
&& ((type != NULL && type != &t_blob_null)
|
||||
|| !in_vim9script()))
|
||||
{
|
||||
tv->vval.v_blob = blob_alloc();
|
||||
if (tv->vval.v_blob != NULL)
|
||||
++tv->vval.v_blob->bv_refcount;
|
||||
}
|
||||
}
|
||||
copy_tv(tv, rettv);
|
||||
}
|
||||
|
||||
+1
-1
@@ -2116,7 +2116,7 @@ check_overwrite(
|
||||
// with UNIX it is possible to open a directory
|
||||
if (mch_isdir(ffname))
|
||||
{
|
||||
semsg(_(e_src_is_directory), ffname);
|
||||
semsg(_(e_str_is_directory), ffname);
|
||||
return FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -8402,7 +8402,7 @@ open_exfile(
|
||||
// with Unix it is possible to open a directory
|
||||
if (mch_isdir(fname))
|
||||
{
|
||||
semsg(_(e_src_is_directory), fname);
|
||||
semsg(_(e_str_is_directory), fname);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
+22
-20
@@ -892,33 +892,35 @@ f_exepath(typval_T *argvars, typval_T *rettv)
|
||||
rettv->vval.v_string = p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if "fname" is a readable file.
|
||||
*/
|
||||
int
|
||||
file_is_readable(char_u *fname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#ifndef O_NONBLOCK
|
||||
# define O_NONBLOCK 0
|
||||
#endif
|
||||
if (*fname && !mch_isdir(fname)
|
||||
&& (fd = mch_open((char *)fname, O_RDONLY | O_NONBLOCK, 0)) >= 0)
|
||||
{
|
||||
close(fd);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* "filereadable()" function
|
||||
*/
|
||||
void
|
||||
f_filereadable(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
int fd;
|
||||
char_u *p;
|
||||
int n;
|
||||
|
||||
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
|
||||
return;
|
||||
|
||||
#ifndef O_NONBLOCK
|
||||
# define O_NONBLOCK 0
|
||||
#endif
|
||||
p = tv_get_string(&argvars[0]);
|
||||
if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
|
||||
O_RDONLY | O_NONBLOCK, 0)) >= 0)
|
||||
{
|
||||
n = TRUE;
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
n = FALSE;
|
||||
|
||||
rettv->vval.v_number = n;
|
||||
rettv->vval.v_number = file_is_readable(tv_get_string(&argvars[0]));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1761,7 +1763,7 @@ read_file_or_blob(typval_T *argvars, typval_T *rettv, int always_blob)
|
||||
|
||||
if (mch_isdir(fname))
|
||||
{
|
||||
semsg(_(e_src_is_directory), fname);
|
||||
semsg(_(e_str_is_directory), fname);
|
||||
return;
|
||||
}
|
||||
if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
|
||||
|
||||
@@ -405,6 +405,7 @@ EXTERN type_T t_number_bool INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC|TTFLAG_BOOL_OK
|
||||
EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_blob_null INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, &t_void, NULL);
|
||||
EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
|
||||
|
||||
+1
-1
@@ -1191,7 +1191,7 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED)
|
||||
#endif
|
||||
|
||||
menu->parent = parent;
|
||||
menu->submenu_id = NULL;
|
||||
menu->submenu_id = (Widget)0;
|
||||
if (!XtIsManaged(toolBar)
|
||||
&& vim_strchr(p_go, GO_TOOLBAR) != NULL)
|
||||
gui_mch_show_toolbar(TRUE);
|
||||
|
||||
+12
-15
@@ -944,13 +944,21 @@ gui_mch_add_menu(vimmenu_T *menu, int idx)
|
||||
&& tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0),
|
||||
#endif
|
||||
NULL);
|
||||
gui_motif_menu_colors(menu->id);
|
||||
gui_motif_menu_fontlist(menu->id);
|
||||
XmStringFree(label);
|
||||
|
||||
if (menu->id == (Widget)0) // failed
|
||||
return;
|
||||
|
||||
// The "Help" menu is a special case, and should be placed at the far
|
||||
// right hand side of the menu-bar. It's recognized by its high priority.
|
||||
if (parent == NULL && menu->priority >= 9999)
|
||||
XtVaSetValues(menuBar,
|
||||
XmNmenuHelpWidget, menu->id,
|
||||
NULL);
|
||||
|
||||
gui_motif_menu_colors(menu->id);
|
||||
gui_motif_menu_fontlist(menu->id);
|
||||
|
||||
// add accelerator text
|
||||
gui_motif_add_actext(menu);
|
||||
|
||||
@@ -978,19 +986,8 @@ gui_mch_add_menu(vimmenu_T *menu, int idx)
|
||||
XmNsubMenuId, menu->submenu_id,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* The "Help" menu is a special case, and should be placed at the far
|
||||
* right hand side of the menu-bar. It's recognized by its high priority.
|
||||
*/
|
||||
if (parent == NULL && menu->priority >= 9999)
|
||||
XtVaSetValues(menuBar,
|
||||
XmNmenuHelpWidget, menu->id,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* When we add a top-level item to the menu bar, we can figure out how
|
||||
* high the menu bar should be.
|
||||
*/
|
||||
// When we add a top-level item to the menu bar, we can figure out how
|
||||
// high the menu bar should be.
|
||||
if (parent == NULL)
|
||||
gui_mch_compute_menu_height(menu->id);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ handle_mode(typval_T *item, jobopt_T *opt, ch_mode_T *modep, int jo)
|
||||
*modep = MODE_JS;
|
||||
else if (STRCMP(val, "json") == 0)
|
||||
*modep = MODE_JSON;
|
||||
else if (STRCMP(val, "lsp") == 0)
|
||||
*modep = MODE_LSP;
|
||||
else
|
||||
{
|
||||
semsg(_(e_invalid_argument_str), val);
|
||||
|
||||
+26
@@ -86,6 +86,32 @@ json_encode_nr_expr(int nr, typval_T *val, int options)
|
||||
ga_append(&ga, NUL);
|
||||
return ga.ga_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode "val" into a JSON format string prefixed by the LSP HTTP header.
|
||||
* Returns NULL when out of memory.
|
||||
*/
|
||||
char_u *
|
||||
json_encode_lsp_msg(typval_T *val)
|
||||
{
|
||||
garray_T ga;
|
||||
garray_T lspga;
|
||||
|
||||
ga_init2(&ga, 1, 4000);
|
||||
if (json_encode_gap(&ga, val, 0) == FAIL)
|
||||
return NULL;
|
||||
ga_append(&ga, NUL);
|
||||
|
||||
ga_init2(&lspga, 1, 4000);
|
||||
vim_snprintf((char *)IObuff, IOSIZE,
|
||||
"Content-Length: %u\r\n"
|
||||
"Content-Type: application/vim-jsonrpc; charset=utf-8\r\n\r\n",
|
||||
ga.ga_len - 1);
|
||||
ga_concat(&lspga, IObuff);
|
||||
ga_concat_len(&lspga, ga.ga_data, ga.ga_len);
|
||||
ga_clear(&ga);
|
||||
return lspga.ga_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
|
||||
+9
-9
@@ -1002,21 +1002,21 @@ mark_adjust(
|
||||
|
||||
void
|
||||
mark_adjust_nofold(
|
||||
linenr_T line1,
|
||||
linenr_T line2,
|
||||
long amount,
|
||||
long amount_after)
|
||||
linenr_T line1,
|
||||
linenr_T line2,
|
||||
long amount,
|
||||
long amount_after)
|
||||
{
|
||||
mark_adjust_internal(line1, line2, amount, amount_after, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
mark_adjust_internal(
|
||||
linenr_T line1,
|
||||
linenr_T line2,
|
||||
long amount,
|
||||
long amount_after,
|
||||
int adjust_folds UNUSED)
|
||||
linenr_T line1,
|
||||
linenr_T line2,
|
||||
long amount,
|
||||
long amount_after,
|
||||
int adjust_folds UNUSED)
|
||||
{
|
||||
int i;
|
||||
int fnum = curbuf->b_fnum;
|
||||
|
||||
+2
-2
@@ -147,10 +147,10 @@ redraw_for_cursorcolumn(win_T *wp)
|
||||
{
|
||||
// When 'cursorcolumn' is set need to redraw with SOME_VALID.
|
||||
if (wp->w_p_cuc)
|
||||
redraw_later(SOME_VALID);
|
||||
redraw_win_later(wp, SOME_VALID);
|
||||
// When 'cursorlineopt' contains "screenline" need to redraw with VALID.
|
||||
else if (wp->w_p_cul && (wp->w_p_culopt_flags & CULOPT_SCRLINE))
|
||||
redraw_later(VALID);
|
||||
redraw_win_later(wp, VALID);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -570,7 +570,7 @@ EXTERN char_u *p_fenc; // 'fileencoding'
|
||||
EXTERN char_u *p_fencs; // 'fileencodings'
|
||||
EXTERN char_u *p_ff; // 'fileformat'
|
||||
EXTERN char_u *p_ffs; // 'fileformats'
|
||||
EXTERN long p_fic; // 'fileignorecase'
|
||||
EXTERN int p_fic; // 'fileignorecase'
|
||||
EXTERN char_u *p_ft; // 'filetype'
|
||||
EXTERN char_u *p_fcs; // 'fillchar'
|
||||
EXTERN int p_fixeol; // 'fixendofline'
|
||||
@@ -767,7 +767,7 @@ EXTERN long p_mis; // 'menuitems'
|
||||
EXTERN char_u *p_msm; // 'mkspellmem'
|
||||
#endif
|
||||
EXTERN int p_ml; // 'modeline'
|
||||
EXTERN long p_mle; // 'modelineexpr'
|
||||
EXTERN int p_mle; // 'modelineexpr'
|
||||
EXTERN long p_mls; // 'modelines'
|
||||
EXTERN int p_ma; // 'modifiable'
|
||||
#ifdef FEAT_GUI_MACVIM
|
||||
@@ -1104,7 +1104,7 @@ EXTERN int p_wiv; // 'weirdinvert'
|
||||
EXTERN char_u *p_ww; // 'whichwrap'
|
||||
EXTERN long p_wc; // 'wildchar'
|
||||
EXTERN long p_wcm; // 'wildcharm'
|
||||
EXTERN long p_wic; // 'wildignorecase'
|
||||
EXTERN int p_wic; // 'wildignorecase'
|
||||
EXTERN char_u *p_wim; // 'wildmode'
|
||||
#ifdef FEAT_WILDMENU
|
||||
EXTERN int p_wmnu; // 'wildmenu'
|
||||
|
||||
+1
-1
@@ -3768,7 +3768,7 @@ get_tty_info(int fd, ttyinfo_T *info)
|
||||
static int mouse_ison = FALSE;
|
||||
|
||||
/*
|
||||
* Set mouse clicks on or off.
|
||||
* Set mouse clicks on or off and possible enable mouse movement events.
|
||||
*/
|
||||
void
|
||||
mch_setmouse(int on)
|
||||
|
||||
+39
-26
@@ -100,6 +100,9 @@ pum_display(
|
||||
#if defined(FEAT_QUICKFIX)
|
||||
win_T *pvwin;
|
||||
#endif
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
int right_left = State == CMDLINE ? FALSE : curwin->w_p_rl;
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
@@ -156,11 +159,17 @@ pum_display(
|
||||
{
|
||||
// pum above "pum_win_row"
|
||||
|
||||
// Leave two lines of context if possible
|
||||
if (curwin->w_wrow - curwin->w_cline_row >= 2)
|
||||
context_lines = 2;
|
||||
if (State == CMDLINE)
|
||||
// for cmdline pum, no need for context lines
|
||||
context_lines = 0;
|
||||
else
|
||||
context_lines = curwin->w_wrow - curwin->w_cline_row;
|
||||
{
|
||||
// Leave two lines of context if possible
|
||||
if (curwin->w_wrow - curwin->w_cline_row >= 2)
|
||||
context_lines = 2;
|
||||
else
|
||||
context_lines = curwin->w_wrow - curwin->w_cline_row;
|
||||
}
|
||||
|
||||
if (pum_win_row >= size + context_lines)
|
||||
{
|
||||
@@ -182,14 +191,20 @@ pum_display(
|
||||
{
|
||||
// pum below "pum_win_row"
|
||||
|
||||
// Leave two lines of context if possible
|
||||
validate_cheight();
|
||||
if (curwin->w_cline_row
|
||||
+ curwin->w_cline_height - curwin->w_wrow >= 3)
|
||||
context_lines = 3;
|
||||
if (State == CMDLINE)
|
||||
// for cmdline pum, no need for context lines
|
||||
context_lines = 0;
|
||||
else
|
||||
context_lines = curwin->w_cline_row
|
||||
+ curwin->w_cline_height - curwin->w_wrow;
|
||||
{
|
||||
// Leave two lines of context if possible
|
||||
validate_cheight();
|
||||
if (curwin->w_cline_row
|
||||
+ curwin->w_cline_height - curwin->w_wrow >= 3)
|
||||
context_lines = 3;
|
||||
else
|
||||
context_lines = curwin->w_cline_row
|
||||
+ curwin->w_cline_height - curwin->w_wrow;
|
||||
}
|
||||
|
||||
pum_row = pum_win_row + context_lines;
|
||||
if (size > below_row - pum_row)
|
||||
@@ -226,7 +241,7 @@ pum_display(
|
||||
else
|
||||
#endif
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (curwin->w_p_rl)
|
||||
if (right_left)
|
||||
cursor_col = curwin->w_wincol + curwin->w_width
|
||||
- curwin->w_wcol - 1;
|
||||
else
|
||||
@@ -245,12 +260,10 @@ pum_display(
|
||||
if (def_width < max_width)
|
||||
def_width = max_width;
|
||||
|
||||
if (((cursor_col < Columns - p_pw
|
||||
|| cursor_col < Columns - max_width)
|
||||
if (((cursor_col < Columns - p_pw || cursor_col < Columns - max_width)
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
&& !curwin->w_p_rl)
|
||||
|| (curwin->w_p_rl
|
||||
&& (cursor_col > p_pw || cursor_col > max_width)
|
||||
&& !right_left)
|
||||
|| (right_left && (cursor_col > p_pw || cursor_col > max_width)
|
||||
#endif
|
||||
))
|
||||
{
|
||||
@@ -259,7 +272,7 @@ pum_display(
|
||||
|
||||
// start with the maximum space available
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (curwin->w_p_rl)
|
||||
if (right_left)
|
||||
pum_width = pum_col - pum_scrollbar + 1;
|
||||
else
|
||||
#endif
|
||||
@@ -276,22 +289,22 @@ pum_display(
|
||||
}
|
||||
else if (((cursor_col > p_pw || cursor_col > max_width)
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
&& !curwin->w_p_rl)
|
||||
|| (curwin->w_p_rl && (cursor_col < Columns - p_pw
|
||||
&& !right_left)
|
||||
|| (right_left && (cursor_col < Columns - p_pw
|
||||
|| cursor_col < Columns - max_width)
|
||||
#endif
|
||||
))
|
||||
{
|
||||
// align pum edge with "cursor_col"
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (curwin->w_p_rl
|
||||
if (right_left
|
||||
&& W_ENDCOL(curwin) < max_width + pum_scrollbar + 1)
|
||||
{
|
||||
pum_col = cursor_col + max_width + pum_scrollbar + 1;
|
||||
if (pum_col >= Columns)
|
||||
pum_col = Columns - 1;
|
||||
}
|
||||
else if (!curwin->w_p_rl)
|
||||
else if (!right_left)
|
||||
#endif
|
||||
{
|
||||
if (curwin->w_wincol > Columns - max_width - pum_scrollbar
|
||||
@@ -305,7 +318,7 @@ pum_display(
|
||||
}
|
||||
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (curwin->w_p_rl)
|
||||
if (right_left)
|
||||
pum_width = pum_col - pum_scrollbar + 1;
|
||||
else
|
||||
#endif
|
||||
@@ -315,7 +328,7 @@ pum_display(
|
||||
{
|
||||
pum_width = p_pw;
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (curwin->w_p_rl)
|
||||
if (right_left)
|
||||
{
|
||||
if (pum_width > pum_col)
|
||||
pum_width = pum_col;
|
||||
@@ -343,7 +356,7 @@ pum_display(
|
||||
{
|
||||
// not enough room, will use what we have
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (curwin->w_p_rl)
|
||||
if (right_left)
|
||||
pum_col = Columns - 1;
|
||||
else
|
||||
#endif
|
||||
@@ -355,7 +368,7 @@ pum_display(
|
||||
if (max_width > p_pw)
|
||||
max_width = p_pw; // truncate
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (curwin->w_p_rl)
|
||||
if (right_left)
|
||||
pum_col = max_width - 1;
|
||||
else
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,7 @@ void f_chdir(typval_T *argvars, typval_T *rettv);
|
||||
void f_delete(typval_T *argvars, typval_T *rettv);
|
||||
void f_executable(typval_T *argvars, typval_T *rettv);
|
||||
void f_exepath(typval_T *argvars, typval_T *rettv);
|
||||
int file_is_readable(char_u *fname);
|
||||
void f_filereadable(typval_T *argvars, typval_T *rettv);
|
||||
void f_filewritable(typval_T *argvars, typval_T *rettv);
|
||||
void f_finddir(typval_T *argvars, typval_T *rettv);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* json.c */
|
||||
char_u *json_encode(typval_T *val, int options);
|
||||
char_u *json_encode_nr_expr(int nr, typval_T *val, int options);
|
||||
char_u *json_encode_lsp_msg(typval_T *val);
|
||||
int json_decode(js_read_T *reader, typval_T *res, int options);
|
||||
int json_find_end(js_read_T *reader, int options);
|
||||
void f_js_decode(typval_T *argvars, typval_T *rettv);
|
||||
|
||||
@@ -6,6 +6,8 @@ int estack_top_is_ufunc(ufunc_T *ufunc, long lnum);
|
||||
estack_T *estack_pop(void);
|
||||
char_u *estack_sfile(estack_arg_T which);
|
||||
void ex_runtime(exarg_T *eap);
|
||||
int find_script_by_name(char_u *name);
|
||||
int get_new_scriptitem_for_fname(int *error, char_u *fname);
|
||||
int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
|
||||
int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
|
||||
int source_runtime(char_u *name, int flags);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* userfunc.c */
|
||||
void func_init(void);
|
||||
hashtab_T *func_tbl_get(void);
|
||||
char_u *make_ufunc_name_readable(char_u *name, char_u *buf, size_t bufsize);
|
||||
char_u *get_lambda_name(void);
|
||||
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state);
|
||||
int get_lambda_tv(char_u **arg, typval_T *rettv, int types_optional, evalarg_T *evalarg);
|
||||
@@ -8,6 +9,7 @@ char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, type_T **
|
||||
void emsg_funcname(char *ermsg, char_u *name);
|
||||
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe);
|
||||
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
|
||||
void func_name_with_sid(char_u *name, int sid, char_u *buffer);
|
||||
ufunc_T *find_func_even_dead(char_u *name, int flags);
|
||||
ufunc_T *find_func(char_u *name, int is_global);
|
||||
int func_is_global(ufunc_T *ufunc);
|
||||
|
||||
@@ -54,6 +54,7 @@ int generate_PCALL(cctx_T *cctx, int argcount, char_u *name, type_T *type, int a
|
||||
int generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len);
|
||||
int generate_ECHO(cctx_T *cctx, int with_white, int count);
|
||||
int generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count);
|
||||
int generate_SOURCE(cctx_T *cctx, int sid);
|
||||
int generate_PUT(cctx_T *cctx, int regname, linenr_T lnum);
|
||||
int generate_EXEC_copy(cctx_T *cctx, isntype_T isntype, char_u *line);
|
||||
int generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *str);
|
||||
|
||||
@@ -3194,6 +3194,7 @@ qf_jump_edit_buffer(
|
||||
if (qfl_type == QFLT_LOCATION)
|
||||
{
|
||||
win_T *wp = win_id2wp(prev_winid);
|
||||
|
||||
if (wp == NULL && curwin->w_llist != qi)
|
||||
{
|
||||
emsg(_(e_current_window_was_closed));
|
||||
|
||||
@@ -3360,8 +3360,17 @@ regmatch(
|
||||
int mark = OPERAND(scan)[0];
|
||||
int cmp = OPERAND(scan)[1];
|
||||
pos_T *pos;
|
||||
size_t col = REG_MULTI ? rex.input - rex.line : 0;
|
||||
|
||||
pos = getmark_buf(rex.reg_buf, mark, FALSE);
|
||||
|
||||
// Line may have been freed, get it again.
|
||||
if (REG_MULTI)
|
||||
{
|
||||
rex.line = reg_getline(rex.lnum);
|
||||
rex.input = rex.line + col;
|
||||
}
|
||||
|
||||
if (pos == NULL // mark doesn't exist
|
||||
|| pos->lnum <= 0) // mark isn't set in reg_buf
|
||||
{
|
||||
|
||||
+4
-2
@@ -6764,8 +6764,10 @@ nfa_regmatch(
|
||||
case NFA_MARK_GT:
|
||||
case NFA_MARK_LT:
|
||||
{
|
||||
size_t col = rex.input - rex.line;
|
||||
pos_T *pos = getmark_buf(rex.reg_buf, t->state->val, FALSE);
|
||||
pos_T *pos;
|
||||
size_t col = REG_MULTI ? rex.input - rex.line : 0;
|
||||
|
||||
pos = getmark_buf(rex.reg_buf, t->state->val, FALSE);
|
||||
|
||||
// Line may have been freed, get it again.
|
||||
if (REG_MULTI)
|
||||
|
||||
+2
-2
@@ -2399,8 +2399,8 @@ ex_display(exarg_T *eap)
|
||||
msg_puts_attr("^J", attr);
|
||||
n -= 2;
|
||||
}
|
||||
for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0;
|
||||
++p)
|
||||
for (p = yb->y_array[j];
|
||||
*p != NUL && (n -= ptr2cells(p)) >= 0; ++p)
|
||||
{
|
||||
clen = (*mb_ptr2len)(p);
|
||||
msg_outtrans_len(p, clen);
|
||||
|
||||
+20
-11
@@ -251,7 +251,7 @@ source_callback(char_u *fname, void *cookie)
|
||||
* Find an already loaded script "name".
|
||||
* If found returns its script ID. If not found returns -1.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
find_script_by_name(char_u *name)
|
||||
{
|
||||
int sid;
|
||||
@@ -320,6 +320,21 @@ get_new_scriptitem(int *error)
|
||||
return sid;
|
||||
}
|
||||
|
||||
int
|
||||
get_new_scriptitem_for_fname(int *error, char_u *fname)
|
||||
{
|
||||
int sid = get_new_scriptitem(error);
|
||||
|
||||
if (*error == OK)
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(sid);
|
||||
|
||||
si->sn_name = vim_strsave(fname);
|
||||
si->sn_state = SN_STATE_NOT_LOADED;
|
||||
}
|
||||
return sid;
|
||||
}
|
||||
|
||||
static void
|
||||
find_script_callback(char_u *fname, void *cookie)
|
||||
{
|
||||
@@ -329,17 +344,8 @@ find_script_callback(char_u *fname, void *cookie)
|
||||
|
||||
sid = find_script_by_name(fname);
|
||||
if (sid < 0)
|
||||
{
|
||||
// script does not exist yet, create a new scriptitem
|
||||
sid = get_new_scriptitem(&error);
|
||||
if (error == OK)
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(sid);
|
||||
|
||||
si->sn_name = vim_strsave(fname);
|
||||
si->sn_state = SN_STATE_NOT_LOADED;
|
||||
}
|
||||
}
|
||||
sid = get_new_scriptitem_for_fname(&error, fname);
|
||||
*ret_sid = sid;
|
||||
}
|
||||
#endif
|
||||
@@ -1918,7 +1924,10 @@ get_one_sourceline(source_cookie_T *sp)
|
||||
break; // all the lines are processed
|
||||
ga_concat(&ga, ((char_u **)sp->buflines.ga_data)[sp->buf_lnum]);
|
||||
sp->buf_lnum++;
|
||||
if (ga_grow(&ga, 1) == FAIL)
|
||||
break;
|
||||
buf = (char_u *)ga.ga_data;
|
||||
buf[ga.ga_len++] = NUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+21
-3
@@ -686,6 +686,11 @@ makeopens(
|
||||
if (put_line(fd, "endif") == FAIL)
|
||||
goto fail;
|
||||
|
||||
// save 'shortmess' if not storing options
|
||||
if ((ssop_flags & SSOP_OPTIONS) == 0
|
||||
&& put_line(fd, "let s:shortmess_save = &shortmess") == FAIL)
|
||||
goto fail;
|
||||
|
||||
// Now save the current files, current buffer first.
|
||||
if (put_line(fd, "set shortmess=aoO") == FAIL)
|
||||
goto fail;
|
||||
@@ -964,10 +969,23 @@ makeopens(
|
||||
if (put_line(fd, "unlet! s:wipebuf") == FAIL)
|
||||
goto fail;
|
||||
|
||||
// Re-apply 'winheight', 'winwidth' and 'shortmess'.
|
||||
if (fprintf(fd, "set winheight=%ld winwidth=%ld shortmess=%s",
|
||||
p_wh, p_wiw, p_shm) < 0 || put_eol(fd) == FAIL)
|
||||
// Re-apply 'winheight' and 'winwidth'.
|
||||
if (fprintf(fd, "set winheight=%ld winwidth=%ld",
|
||||
p_wh, p_wiw) < 0 || put_eol(fd) == FAIL)
|
||||
goto fail;
|
||||
|
||||
// Restore 'shortmess'.
|
||||
if (ssop_flags & SSOP_OPTIONS)
|
||||
{
|
||||
if (fprintf(fd, "set shortmess=%s", p_shm) < 0 || put_eol(fd) == FAIL)
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (put_line(fd, "let &shortmess = s:shortmess_save") == FAIL)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (tab_firstwin->w_next != NULL)
|
||||
{
|
||||
// Restore 'winminheight' and 'winminwidth'.
|
||||
|
||||
+1
-1
@@ -5976,7 +5976,7 @@ mkspell(
|
||||
}
|
||||
if (mch_isdir(wfname))
|
||||
{
|
||||
semsg(_(e_src_is_directory), wfname);
|
||||
semsg(_(e_str_is_directory), wfname);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -1833,7 +1833,7 @@ typedef struct {
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char_u *sn_name;
|
||||
char_u *sn_name; // full path of script file
|
||||
int sn_script_seq; // latest sctx_T sc_seq value
|
||||
|
||||
// "sn_vars" stores the s: variables currently valid. When leaving a block
|
||||
@@ -1864,9 +1864,13 @@ typedef struct
|
||||
char_u *sn_save_cpo; // 'cpo' value when :vim9script found
|
||||
char sn_is_vimrc; // .vimrc file, do not restore 'cpo'
|
||||
|
||||
// for "vim9script autoload" this is "dir#scriptname#"
|
||||
// for a Vim9 script under "rtp/autoload/" this is "dir#scriptname#"
|
||||
char_u *sn_autoload_prefix;
|
||||
|
||||
// TRUE for a script used with "import autoload './dirname/script.vim'"
|
||||
// For "../autoload/script.vim" sn_autoload_prefix is also set.
|
||||
int sn_import_autoload;
|
||||
|
||||
# ifdef FEAT_PROFILE
|
||||
int sn_prof_on; // TRUE when script is/was profiled
|
||||
int sn_pr_force; // forceit: profile functions in this script
|
||||
@@ -2193,6 +2197,7 @@ typedef enum
|
||||
MODE_RAW,
|
||||
MODE_JSON,
|
||||
MODE_JS,
|
||||
MODE_LSP // Language Server Protocol (http + json)
|
||||
} ch_mode_T;
|
||||
|
||||
typedef enum {
|
||||
@@ -3477,6 +3482,9 @@ struct window_S
|
||||
colnr_T w_old_visual_col; // last known start of visual part
|
||||
colnr_T w_old_curswant; // last known value of Curswant
|
||||
|
||||
linenr_T w_last_cursor_lnum_rnu; // cursor lnum when 'rnu' was last
|
||||
// redrawn
|
||||
|
||||
lcs_chars_T w_lcs_chars; // 'listchars' characters
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
| +0&#ffffff0@74
|
||||
@75
|
||||
@75
|
||||
@5| +0#0000001#e0e0e08|d|e|f|i|n|e| @8| +0#0000000#ffffff0@53
|
||||
|<+2#ffffff16#00e0003|o|r|t| | +0#0000001#ffd7ff255|j|u|m|p| @10|w+2#ffffff16#00e0003|r|i|t|e|(|s|y|s|.|s|t|d|i|n|.|r|e|a|d|(|)@1|"| |[|r|u|n@1|i|n|g|]| @1|0|,|0|-|1| @9|A|l@1
|
||||
| +0#0000000#ffffff0@4| +0#0000001#ffd7ff255|l|i|s|t| @10| +0#0000000#ffffff0@53
|
||||
|~+0#4040ff13&| @3| +0#0000001#ffd7ff255|p|l|a|c|e| @9| +0#4040ff13#ffffff0@53
|
||||
|~| @3| +0#0000001#ffd7ff255|u|n|d|e|f|i|n|e| @6| +0#4040ff13#ffffff0@53
|
||||
|[+1#0000000&|N|o| |N| +0#0000001#ffd7ff255|u|n|p|l|a|c|e| @7| +1#0000000#ffffff0@35|0|,|0|-|1| @9|A|l@1
|
||||
|:+0&&|s|i|g|n| |d|e|f|i|n|e> @62
|
||||
@@ -2378,5 +2378,214 @@ func Test_job_start_with_invalid_argument()
|
||||
call assert_fails('call job_start([0zff])', 'E976:')
|
||||
endfunc
|
||||
|
||||
" Test for the 'lsp' channel mode
|
||||
func LspCb(chan, msg)
|
||||
call add(g:lspNotif, a:msg)
|
||||
endfunc
|
||||
|
||||
func LspOtCb(chan, msg)
|
||||
call add(g:lspOtMsgs, a:msg)
|
||||
endfunc
|
||||
|
||||
func LspTests(port)
|
||||
" call ch_logfile('Xlsprpc.log', 'w')
|
||||
let ch = ch_open(s:localhost .. a:port, #{mode: 'lsp', callback: 'LspCb'})
|
||||
if ch_status(ch) == "fail"
|
||||
call assert_report("Can't open the lsp channel")
|
||||
return
|
||||
endif
|
||||
|
||||
" check for channel information
|
||||
let info = ch_info(ch)
|
||||
call assert_equal('LSP', info.sock_mode)
|
||||
|
||||
" Evaluate an expression
|
||||
let resp = ch_evalexpr(ch, #{method: 'simple-rpc', params: [10, 20]})
|
||||
call assert_false(empty(resp))
|
||||
call assert_equal(#{id: 1, jsonrpc: '2.0', result: 'simple-rpc'}, resp)
|
||||
|
||||
" Evaluate an expression. While waiting for the response, a notification
|
||||
" message is delivered.
|
||||
let g:lspNotif = []
|
||||
let resp = ch_evalexpr(ch, #{method: 'rpc-with-notif', params: {'v': 10}})
|
||||
call assert_false(empty(resp))
|
||||
call assert_equal(#{id: 2, jsonrpc: '2.0', result: 'rpc-with-notif-resp'},
|
||||
\ resp)
|
||||
call assert_equal([#{jsonrpc: '2.0', result: 'rpc-with-notif-notif'}],
|
||||
\ g:lspNotif)
|
||||
|
||||
" Wrong payload notification test
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'wrong-payload', params: {}})
|
||||
" Send a ping to wait for all the notification messages to arrive
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([#{jsonrpc: '2.0', result: 'wrong-payload'}], g:lspNotif)
|
||||
|
||||
" Test for receiving a response with incorrect 'id' and additional
|
||||
" notification messages while evaluating an expression.
|
||||
let g:lspNotif = []
|
||||
let resp = ch_evalexpr(ch, #{method: 'rpc-resp-incorrect-id',
|
||||
\ params: {'a': [1, 2]}})
|
||||
call assert_false(empty(resp))
|
||||
call assert_equal(#{id: 4, jsonrpc: '2.0',
|
||||
\ result: 'rpc-resp-incorrect-id-4'}, resp)
|
||||
call assert_equal([#{jsonrpc: '2.0', result: 'rpc-resp-incorrect-id-1'},
|
||||
\ #{jsonrpc: '2.0', result: 'rpc-resp-incorrect-id-2'},
|
||||
\ #{jsonrpc: '2.0', id: 1, result: 'rpc-resp-incorrect-id-3'}],
|
||||
\ g:lspNotif)
|
||||
|
||||
" simple notification test
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'simple-notif', params: [#{a: 10, b: []}]})
|
||||
" Send a ping to wait for all the notification messages to arrive
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([#{jsonrpc: '2.0', result: 'simple-notif'}], g:lspNotif)
|
||||
|
||||
" multiple notifications test
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'multi-notif', params: [#{a: {}, b: {}}]})
|
||||
" Send a ping to wait for all the notification messages to arrive
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([#{jsonrpc: '2.0', result: 'multi-notif1'},
|
||||
\ #{jsonrpc: '2.0', result: 'multi-notif2'}], g:lspNotif)
|
||||
|
||||
" Test for sending a message with an identifier.
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'msg-with-id', id: 93, params: #{s: 'str'}})
|
||||
" Send a ping to wait for all the notification messages to arrive
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([#{jsonrpc: '2.0', id: 93, result: 'msg-with-id'}],
|
||||
\ g:lspNotif)
|
||||
|
||||
" Test for setting the 'id' value in a request message
|
||||
let resp = ch_evalexpr(ch, #{method: 'ping', id: 1, params: {}})
|
||||
call assert_equal(#{id: 8, jsonrpc: '2.0', result: 'alive'}, resp)
|
||||
|
||||
" Test for using a one time callback function to process a response
|
||||
let g:lspOtMsgs = []
|
||||
call ch_sendexpr(ch, #{method: 'msg-specifc-cb', params: {}},
|
||||
\ #{callback: 'LspOtCb'})
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([#{id: 9, jsonrpc: '2.0', result: 'msg-specifc-cb'}],
|
||||
\ g:lspOtMsgs)
|
||||
|
||||
" Test for generating a request message from the other end (server)
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'server-req', params: #{}})
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([{'id': 201, 'jsonrpc': '2.0',
|
||||
\ 'result': {'method': 'checkhealth', 'params': {'a': 20}}}],
|
||||
\ g:lspNotif)
|
||||
|
||||
" Test for sending a message without an id
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'echo', params: #{s: 'msg-without-id'}})
|
||||
" Send a ping to wait for all the notification messages to arrive
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([#{jsonrpc: '2.0', result:
|
||||
\ #{method: 'echo', jsonrpc: '2.0', params: #{s: 'msg-without-id'}}}],
|
||||
\ g:lspNotif)
|
||||
|
||||
" Test for sending a notification message with an id
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'echo', id: 110, params: #{s: 'msg-with-id'}})
|
||||
" Send a ping to wait for all the notification messages to arrive
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([#{jsonrpc: '2.0', result:
|
||||
\ #{method: 'echo', jsonrpc: '2.0', id: 110,
|
||||
\ params: #{s: 'msg-with-id'}}}], g:lspNotif)
|
||||
|
||||
" Test for processing the extra fields in the HTTP header
|
||||
let resp = ch_evalexpr(ch, #{method: 'extra-hdr-fields', params: {}})
|
||||
call assert_equal({'id': 14, 'jsonrpc': '2.0', 'result': 'extra-hdr-fields'},
|
||||
\ resp)
|
||||
|
||||
" Test for processing a HTTP header without the Content-Length field
|
||||
let resp = ch_evalexpr(ch, #{method: 'hdr-without-len', params: {}},
|
||||
\ #{timeout: 200})
|
||||
call assert_equal('', resp)
|
||||
" send a ping to make sure communication still works
|
||||
let resp = ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal({'id': 16, 'jsonrpc': '2.0', 'result': 'alive'}, resp)
|
||||
|
||||
" Test for processing a HTTP header with wrong length
|
||||
let resp = ch_evalexpr(ch, #{method: 'hdr-with-wrong-len', params: {}},
|
||||
\ #{timeout: 200})
|
||||
call assert_equal('', resp)
|
||||
" send a ping to make sure communication still works
|
||||
let resp = ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal({'id': 18, 'jsonrpc': '2.0', 'result': 'alive'}, resp)
|
||||
|
||||
" Test for processing a HTTP header with negative length
|
||||
let resp = ch_evalexpr(ch, #{method: 'hdr-with-negative-len', params: {}},
|
||||
\ #{timeout: 200})
|
||||
call assert_equal('', resp)
|
||||
" send a ping to make sure communication still works
|
||||
let resp = ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal({'id': 20, 'jsonrpc': '2.0', 'result': 'alive'}, resp)
|
||||
|
||||
" Test for an empty header
|
||||
let resp = ch_evalexpr(ch, #{method: 'empty-header', params: {}},
|
||||
\ #{timeout: 200})
|
||||
call assert_equal('', resp)
|
||||
" send a ping to make sure communication still works
|
||||
let resp = ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal({'id': 22, 'jsonrpc': '2.0', 'result': 'alive'}, resp)
|
||||
|
||||
" Test for an empty payload
|
||||
let resp = ch_evalexpr(ch, #{method: 'empty-payload', params: {}},
|
||||
\ #{timeout: 200})
|
||||
call assert_equal('', resp)
|
||||
" send a ping to make sure communication still works
|
||||
let resp = ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal({'id': 24, 'jsonrpc': '2.0', 'result': 'alive'}, resp)
|
||||
|
||||
" Test for invoking an unsupported method
|
||||
let resp = ch_evalexpr(ch, #{method: 'xyz', params: {}}, #{timeout: 200})
|
||||
call assert_equal('', resp)
|
||||
|
||||
" Test for sending a message without a callback function. Notification
|
||||
" message should be dropped but RPC response should not be dropped.
|
||||
call ch_setoptions(ch, #{callback: ''})
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'echo', params: #{s: 'no-callback'}})
|
||||
" Send a ping to wait for all the notification messages to arrive
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([], g:lspNotif)
|
||||
" Restore the callback function
|
||||
call ch_setoptions(ch, #{callback: 'LspCb'})
|
||||
let g:lspNotif = []
|
||||
call ch_sendexpr(ch, #{method: 'echo', params: #{s: 'no-callback'}})
|
||||
" Send a ping to wait for all the notification messages to arrive
|
||||
call ch_evalexpr(ch, #{method: 'ping'})
|
||||
call assert_equal([#{jsonrpc: '2.0', result:
|
||||
\ #{method: 'echo', jsonrpc: '2.0', params: #{s: 'no-callback'}}}],
|
||||
\ g:lspNotif)
|
||||
|
||||
" " Test for sending a raw message
|
||||
" let g:lspNotif = []
|
||||
" let s = "Content-Length: 62\r\n"
|
||||
" let s ..= "Content-Type: application/vim-jsonrpc; charset=utf-8\r\n"
|
||||
" let s ..= "\r\n"
|
||||
" let s ..= '{"method":"echo","jsonrpc":"2.0","params":{"m":"raw-message"}}'
|
||||
" call ch_sendraw(ch, s)
|
||||
" call ch_evalexpr(ch, #{method: 'ping'})
|
||||
" call assert_equal([{'jsonrpc': '2.0',
|
||||
" \ 'result': {'method': 'echo', 'jsonrpc': '2.0',
|
||||
" \ 'params': {'m': 'raw-message'}}}], g:lspNotif)
|
||||
|
||||
" Invalid arguments to ch_evalexpr() and ch_sendexpr()
|
||||
call assert_fails('call ch_sendexpr(ch, #{method: "cookie", id: "cookie"})',
|
||||
\ 'E475:')
|
||||
call assert_fails('call ch_evalexpr(ch, #{method: "ping", id: [{}]})', 'E475:')
|
||||
call assert_fails('call ch_evalexpr(ch, [1, 2, 3])', 'E1206:')
|
||||
call assert_fails('call ch_sendexpr(ch, "abc")', 'E1206:')
|
||||
call assert_fails('call ch_evalexpr(ch, #{method: "ping"}, #{callback: "LspOtCb"})', 'E917:')
|
||||
" call ch_logfile('', 'w')
|
||||
endfunc
|
||||
|
||||
func Test_channel_lsp_mode()
|
||||
call RunServer('test_channel_lsp.py', 'LspTests', [])
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Server that will accept connections from a Vim channel.
|
||||
# Used by test_channel.vim to test LSP functionality.
|
||||
#
|
||||
# This requires Python 2.6 or later.
|
||||
|
||||
from __future__ import print_function
|
||||
import json
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
import threading
|
||||
|
||||
try:
|
||||
# Python 3
|
||||
import socketserver
|
||||
except ImportError:
|
||||
# Python 2
|
||||
import SocketServer as socketserver
|
||||
|
||||
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
|
||||
def setup(self):
|
||||
self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
|
||||
def send_lsp_msg(self, msgid, resp_dict):
|
||||
v = {'jsonrpc': '2.0', 'result': resp_dict}
|
||||
if msgid != -1:
|
||||
v['id'] = msgid
|
||||
s = json.dumps(v)
|
||||
resp = "Content-Length: " + str(len(s)) + "\r\n"
|
||||
resp += "Content-Type: application/vim-jsonrpc; charset=utf-8\r\n"
|
||||
resp += "\r\n"
|
||||
resp += s
|
||||
if self.debug:
|
||||
with open("Xlspdebug.log", "a") as myfile:
|
||||
myfile.write("\n=> send\n" + resp)
|
||||
self.request.sendall(resp.encode('utf-8'))
|
||||
|
||||
def send_wrong_payload(self):
|
||||
v = 'wrong-payload'
|
||||
s = json.dumps(v)
|
||||
resp = "Content-Length: " + str(len(s)) + "\r\n"
|
||||
resp += "Content-Type: application/vim-jsonrpc; charset=utf-8\r\n"
|
||||
resp += "\r\n"
|
||||
resp += s
|
||||
self.request.sendall(resp.encode('utf-8'))
|
||||
|
||||
def send_empty_header(self, msgid, resp_dict):
|
||||
v = {'jsonrpc': '2.0', 'id': msgid, 'result': resp_dict}
|
||||
s = json.dumps(v)
|
||||
resp = "\r\n"
|
||||
resp += s
|
||||
self.request.sendall(resp.encode('utf-8'))
|
||||
|
||||
def send_empty_payload(self):
|
||||
resp = "Content-Length: 0\r\n"
|
||||
resp += "Content-Type: application/vim-jsonrpc; charset=utf-8\r\n"
|
||||
resp += "\r\n"
|
||||
self.request.sendall(resp.encode('utf-8'))
|
||||
|
||||
def send_extra_hdr_fields(self, msgid, resp_dict):
|
||||
# test for sending extra fields in the http header
|
||||
v = {'jsonrpc': '2.0', 'id': msgid, 'result': resp_dict}
|
||||
s = json.dumps(v)
|
||||
resp = "Host: abc.vim.org\r\n"
|
||||
resp += "User-Agent: Python\r\n"
|
||||
resp += "Accept-Language: en-US,en\r\n"
|
||||
resp += "Content-Type: application/vim-jsonrpc; charset=utf-8\r\n"
|
||||
resp += "Content-Length: " + str(len(s)) + "\r\n"
|
||||
resp += "\r\n"
|
||||
resp += s
|
||||
self.request.sendall(resp.encode('utf-8'))
|
||||
|
||||
def send_hdr_without_len(self, msgid, resp_dict):
|
||||
# test for sending the http header without length
|
||||
v = {'jsonrpc': '2.0', 'id': msgid, 'result': resp_dict}
|
||||
s = json.dumps(v)
|
||||
resp = "Content-Type: application/vim-jsonrpc; charset=utf-8\r\n"
|
||||
resp += "\r\n"
|
||||
resp += s
|
||||
self.request.sendall(resp.encode('utf-8'))
|
||||
|
||||
def send_hdr_with_wrong_len(self, msgid, resp_dict):
|
||||
# test for sending the http header with wrong length
|
||||
v = {'jsonrpc': '2.0', 'id': msgid, 'result': resp_dict}
|
||||
s = json.dumps(v)
|
||||
resp = "Content-Length: 1000\r\n"
|
||||
resp += "\r\n"
|
||||
resp += s
|
||||
self.request.sendall(resp.encode('utf-8'))
|
||||
|
||||
def send_hdr_with_negative_len(self, msgid, resp_dict):
|
||||
# test for sending the http header with negative length
|
||||
v = {'jsonrpc': '2.0', 'id': msgid, 'result': resp_dict}
|
||||
s = json.dumps(v)
|
||||
resp = "Content-Length: -1\r\n"
|
||||
resp += "\r\n"
|
||||
resp += s
|
||||
self.request.sendall(resp.encode('utf-8'))
|
||||
|
||||
def do_ping(self, payload):
|
||||
time.sleep(0.2)
|
||||
self.send_lsp_msg(payload['id'], 'alive')
|
||||
|
||||
def do_echo(self, payload):
|
||||
self.send_lsp_msg(-1, payload)
|
||||
|
||||
def do_simple_rpc(self, payload):
|
||||
# test for a simple RPC request
|
||||
self.send_lsp_msg(payload['id'], 'simple-rpc')
|
||||
|
||||
def do_rpc_with_notif(self, payload):
|
||||
# test for sending a notification before replying to a request message
|
||||
self.send_lsp_msg(-1, 'rpc-with-notif-notif')
|
||||
# sleep for some time to make sure the notification is delivered
|
||||
time.sleep(0.2)
|
||||
self.send_lsp_msg(payload['id'], 'rpc-with-notif-resp')
|
||||
|
||||
def do_wrong_payload(self, payload):
|
||||
# test for sending a non dict payload
|
||||
self.send_wrong_payload()
|
||||
time.sleep(0.2)
|
||||
self.send_lsp_msg(-1, 'wrong-payload')
|
||||
|
||||
def do_rpc_resp_incorrect_id(self, payload):
|
||||
self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-1')
|
||||
self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-2')
|
||||
self.send_lsp_msg(1, 'rpc-resp-incorrect-id-3')
|
||||
time.sleep(0.2)
|
||||
self.send_lsp_msg(payload['id'], 'rpc-resp-incorrect-id-4')
|
||||
|
||||
def do_simple_notif(self, payload):
|
||||
# notification message test
|
||||
self.send_lsp_msg(-1, 'simple-notif')
|
||||
|
||||
def do_multi_notif(self, payload):
|
||||
# send multiple notifications
|
||||
self.send_lsp_msg(-1, 'multi-notif1')
|
||||
self.send_lsp_msg(-1, 'multi-notif2')
|
||||
|
||||
def do_msg_with_id(self, payload):
|
||||
self.send_lsp_msg(payload['id'], 'msg-with-id')
|
||||
|
||||
def do_msg_specific_cb(self, payload):
|
||||
self.send_lsp_msg(payload['id'], 'msg-specifc-cb')
|
||||
|
||||
def do_server_req(self, payload):
|
||||
self.send_lsp_msg(201, {'method': 'checkhealth', 'params': {'a': 20}})
|
||||
|
||||
def do_extra_hdr_fields(self, payload):
|
||||
self.send_extra_hdr_fields(payload['id'], 'extra-hdr-fields')
|
||||
|
||||
def do_hdr_without_len(self, payload):
|
||||
self.send_hdr_without_len(payload['id'], 'hdr-without-len')
|
||||
|
||||
def do_hdr_with_wrong_len(self, payload):
|
||||
self.send_hdr_with_wrong_len(payload['id'], 'hdr-with-wrong-len')
|
||||
|
||||
def do_hdr_with_negative_len(self, payload):
|
||||
self.send_hdr_with_negative_len(payload['id'], 'hdr-with-negative-len')
|
||||
|
||||
def do_empty_header(self, payload):
|
||||
self.send_empty_header(payload['id'], 'empty-header')
|
||||
|
||||
def do_empty_payload(self, payload):
|
||||
self.send_empty_payload()
|
||||
|
||||
def process_msg(self, msg):
|
||||
try:
|
||||
decoded = json.loads(msg)
|
||||
print("Decoded:")
|
||||
print(str(decoded))
|
||||
if 'method' in decoded:
|
||||
test_map = {
|
||||
'ping': self.do_ping,
|
||||
'echo': self.do_echo,
|
||||
'simple-rpc': self.do_simple_rpc,
|
||||
'rpc-with-notif': self.do_rpc_with_notif,
|
||||
'wrong-payload': self.do_wrong_payload,
|
||||
'rpc-resp-incorrect-id': self.do_rpc_resp_incorrect_id,
|
||||
'simple-notif': self.do_simple_notif,
|
||||
'multi-notif': self.do_multi_notif,
|
||||
'msg-with-id': self.do_msg_with_id,
|
||||
'msg-specifc-cb': self.do_msg_specific_cb,
|
||||
'server-req': self.do_server_req,
|
||||
'extra-hdr-fields': self.do_extra_hdr_fields,
|
||||
'hdr-without-len': self.do_hdr_without_len,
|
||||
'hdr-with-wrong-len': self.do_hdr_with_wrong_len,
|
||||
'hdr-with-negative-len': self.do_hdr_with_negative_len,
|
||||
'empty-header': self.do_empty_header,
|
||||
'empty-payload': self.do_empty_payload
|
||||
}
|
||||
if decoded['method'] in test_map:
|
||||
test_map[decoded['method']](decoded)
|
||||
else:
|
||||
print("Error: Unsupported method: " + decoded['method'])
|
||||
else:
|
||||
print("Error: 'method' field is not found")
|
||||
|
||||
except ValueError:
|
||||
print("json decoding failed")
|
||||
|
||||
def process_msgs(self, msgbuf):
|
||||
while True:
|
||||
sidx = msgbuf.find('Content-Length: ')
|
||||
if sidx == -1:
|
||||
return msgbuf
|
||||
sidx += 16
|
||||
eidx = msgbuf.find('\r\n')
|
||||
if eidx == -1:
|
||||
return msgbuf
|
||||
msglen = int(msgbuf[sidx:eidx])
|
||||
|
||||
hdrend = msgbuf.find('\r\n\r\n')
|
||||
if hdrend == -1:
|
||||
return msgbuf
|
||||
|
||||
# Remove the header
|
||||
msgbuf = msgbuf[hdrend + 4:]
|
||||
payload = msgbuf[:msglen]
|
||||
|
||||
self.process_msg(payload)
|
||||
|
||||
# Remove the processed message
|
||||
msgbuf = msgbuf[msglen:]
|
||||
|
||||
def handle(self):
|
||||
print("=== socket opened ===")
|
||||
self.debug = False
|
||||
msgbuf = ''
|
||||
while True:
|
||||
try:
|
||||
received = self.request.recv(4096).decode('utf-8')
|
||||
except socket.error:
|
||||
print("=== socket error ===")
|
||||
break
|
||||
except IOError:
|
||||
print("=== socket closed ===")
|
||||
break
|
||||
if received == '':
|
||||
print("=== socket closed ===")
|
||||
break
|
||||
print("\nReceived:\n{0}".format(received))
|
||||
|
||||
# Write the received lines into the file for debugging
|
||||
if self.debug:
|
||||
with open("Xlspdebug.log", "a") as myfile:
|
||||
myfile.write("\n<= recv\n" + received)
|
||||
|
||||
# Can receive more than one line in a response or a partial line.
|
||||
# Accumulate all the received characters and process one line at
|
||||
# a time.
|
||||
msgbuf += received
|
||||
msgbuf = self.process_msgs(msgbuf)
|
||||
|
||||
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
pass
|
||||
|
||||
def writePortInFile(port):
|
||||
# Write the port number in Xportnr, so that the test knows it.
|
||||
f = open("Xportnr", "w")
|
||||
f.write("{0}".format(port))
|
||||
f.close()
|
||||
|
||||
def main(host, port, server_class=ThreadedTCPServer):
|
||||
# Wait half a second before opening the port to test waittime in ch_open().
|
||||
# We do want to get the port number, get that first. We cannot open the
|
||||
# socket, guess a port is free.
|
||||
if len(sys.argv) >= 2 and sys.argv[1] == 'delay':
|
||||
port = 13684
|
||||
writePortInFile(port)
|
||||
|
||||
print("Wait for it...")
|
||||
time.sleep(0.5)
|
||||
|
||||
server = server_class((host, port), ThreadedTCPRequestHandler)
|
||||
ip, port = server.server_address[0:2]
|
||||
|
||||
# Start a thread with the server. That thread will then start a new thread
|
||||
# for each connection.
|
||||
server_thread = threading.Thread(target=server.serve_forever)
|
||||
server_thread.start()
|
||||
|
||||
writePortInFile(port)
|
||||
|
||||
print("Listening on port {0}".format(port))
|
||||
|
||||
# Main thread terminates, but the server continues running
|
||||
# until server.shutdown() is called.
|
||||
try:
|
||||
while server_thread.is_alive():
|
||||
server_thread.join(1)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
server.shutdown()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main("localhost", 0)
|
||||
@@ -2510,6 +2510,30 @@ func Test_wildmenumode_with_pum()
|
||||
cunmap <F2>
|
||||
endfunc
|
||||
|
||||
" Test for opening the cmdline completion popup menu from the terminal window.
|
||||
" The popup menu should be positioned correctly over the status line of the
|
||||
" bottom-most window.
|
||||
func Test_wildmenu_pum_from_terminal()
|
||||
CheckRunVimInTerminal
|
||||
let python = PythonProg()
|
||||
call CheckPython(python)
|
||||
|
||||
%bw!
|
||||
let cmds = ['set wildmenu wildoptions=pum']
|
||||
let pcmd = python .. ' -c "import sys; sys.stdout.write(sys.stdin.read())"'
|
||||
call add(cmds, "call term_start('" .. pcmd .. "')")
|
||||
call writefile(cmds, 'Xtest')
|
||||
let buf = RunVimInTerminal('-S Xtest', #{rows: 10})
|
||||
call term_sendkeys(buf, "\r\r\r")
|
||||
call term_wait(buf)
|
||||
call term_sendkeys(buf, "\<C-W>:sign \<Tab>")
|
||||
call term_wait(buf)
|
||||
call VerifyScreenDump(buf, 'Test_wildmenu_pum_term_01', {})
|
||||
call term_wait(buf)
|
||||
call StopVimInTerminal(buf)
|
||||
call delete('Xtest')
|
||||
endfunc
|
||||
|
||||
" Test for completion after a :substitute command followed by a pipe (|)
|
||||
" character
|
||||
func Test_cmdline_complete_substitute()
|
||||
|
||||
@@ -139,8 +139,7 @@ endfunc
|
||||
|
||||
func Test_FileChangedShell_edit_dialog()
|
||||
CheckNotGui
|
||||
" FIXME: why does this not work on MS-Windows?
|
||||
CheckUnix
|
||||
CheckUnix " Using low level feedkeys() does not work on MS-Windows.
|
||||
|
||||
new Xchanged_r
|
||||
call setline(1, 'reload this')
|
||||
|
||||
@@ -382,6 +382,7 @@ let s:filename_checks = {
|
||||
\ 'opam': ['opam', 'file.opam', 'file.opam.template'],
|
||||
\ 'openroad': ['file.or'],
|
||||
\ 'ora': ['file.ora'],
|
||||
\ 'org': ['file.org', 'file.org_archive'],
|
||||
\ 'pamconf': ['/etc/pam.conf', '/etc/pam.d/file', 'any/etc/pam.conf', 'any/etc/pam.d/file'],
|
||||
\ 'pamenv': ['/etc/security/pam_env.conf', '/home/user/.pam_environment', '.pam_environment', 'pam_env.conf'],
|
||||
\ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'],
|
||||
|
||||
@@ -1007,6 +1007,49 @@ func Test_mksession_winminheight()
|
||||
set sessionoptions&
|
||||
endfunc
|
||||
|
||||
" Test for mksession with and without options restores shortmess
|
||||
func Test_mksession_shortmess()
|
||||
" Without options
|
||||
set sessionoptions-=options
|
||||
split
|
||||
mksession! Xtest_mks.out
|
||||
let found_save = 0
|
||||
let found_restore = 0
|
||||
let lines = readfile('Xtest_mks.out')
|
||||
for line in lines
|
||||
let line = trim(line)
|
||||
|
||||
if line ==# 'let s:shortmess_save = &shortmess'
|
||||
let found_save += 1
|
||||
endif
|
||||
|
||||
if found_save !=# 0 && line ==# 'let &shortmess = s:shortmess_save'
|
||||
let found_restore += 1
|
||||
endif
|
||||
endfor
|
||||
call assert_equal(1, found_save)
|
||||
call assert_equal(1, found_restore)
|
||||
call delete('Xtest_mks.out')
|
||||
close
|
||||
set sessionoptions&
|
||||
|
||||
" With options
|
||||
set sessionoptions+=options
|
||||
split
|
||||
mksession! Xtest_mks.out
|
||||
let found_restore = 0
|
||||
let lines = readfile('Xtest_mks.out')
|
||||
for line in lines
|
||||
if line =~# 's:shortmess_save'
|
||||
let found_restore += 1
|
||||
endif
|
||||
endfor
|
||||
call assert_equal(0, found_restore)
|
||||
call delete('Xtest_mks.out')
|
||||
close
|
||||
set sessionoptions&
|
||||
endfunc
|
||||
|
||||
" Test for mksession with 'compatible' option
|
||||
func Test_mksession_compatible()
|
||||
mksession! Xtest_mks1.out
|
||||
|
||||
@@ -1042,10 +1042,17 @@ endfunc
|
||||
|
||||
func Test_using_mark_position()
|
||||
" this was using freed memory
|
||||
" new engine
|
||||
new
|
||||
norm O0
|
||||
call assert_fails("s/\\%')", 'E486:')
|
||||
bwipe!
|
||||
|
||||
" old engine
|
||||
new
|
||||
norm O0
|
||||
call assert_fails("s/\\%#=1\\%')", 'E486:')
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_using_visual_position()
|
||||
|
||||
@@ -646,4 +646,13 @@ func Test_source_buffer_vim9()
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
func Test_source_buffer_long_line()
|
||||
" This was reading past the end of the line.
|
||||
new
|
||||
norm300gr0
|
||||
so
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -935,7 +935,7 @@ func TerminalTmap(remap)
|
||||
tunmap 123
|
||||
tunmap 456
|
||||
call assert_equal('', maparg('123', 't'))
|
||||
close
|
||||
exe buf . 'bwipe'
|
||||
unlet g:job
|
||||
endfunc
|
||||
|
||||
|
||||
@@ -371,10 +371,17 @@ def Test_bufname()
|
||||
assert_fails('bufname([])', 'E1220:')
|
||||
enddef
|
||||
|
||||
let s:bufnr_res = 0
|
||||
|
||||
def Test_bufnr()
|
||||
var buf = bufnr()
|
||||
bufnr('%')->assert_equal(buf)
|
||||
|
||||
# check the lock is not taken over through the stack
|
||||
const nr = 10
|
||||
bufnr_res = bufnr()
|
||||
bufnr_res = 12345
|
||||
|
||||
buf = bufnr('Xdummy', true)
|
||||
buf->assert_notequal(-1)
|
||||
exe 'bwipe! ' .. buf
|
||||
|
||||
@@ -318,6 +318,46 @@ def Test_disassemble_push()
|
||||
&rtp = save_rtp
|
||||
enddef
|
||||
|
||||
def Test_disassemble_import_autoload()
|
||||
writefile(['vim9script'], 'XimportAL.vim')
|
||||
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportAL.vim'
|
||||
|
||||
def AutoloadFunc()
|
||||
echo XimportAL.SomeFunc()
|
||||
echo XimportAL.someVar
|
||||
XimportAL.someVar = "yes"
|
||||
enddef
|
||||
|
||||
var res = execute('disass AutoloadFunc')
|
||||
assert_match('<SNR>\d*_AutoloadFunc.*' ..
|
||||
'echo XimportAL.SomeFunc()\_s*' ..
|
||||
'\d SOURCE .*/testdir/XimportAL.vim\_s*' ..
|
||||
'\d PUSHFUNC "<80><fd>R\d\+_SomeFunc"\_s*' ..
|
||||
'\d PCALL top (argc 0)\_s*' ..
|
||||
'\d PCALL end\_s*' ..
|
||||
'\d ECHO 1\_s*' ..
|
||||
|
||||
'echo XimportAL.someVar\_s*' ..
|
||||
'\d SOURCE .*/testdir/XimportAL.vim\_s*' ..
|
||||
'\d LOADEXPORT s:someVar from .*/testdir/XimportAL.vim\_s*' ..
|
||||
'\d ECHO 1\_s*' ..
|
||||
|
||||
'XimportAL.someVar = "yes"\_s*' ..
|
||||
'\d\+ PUSHS "yes"\_s*' ..
|
||||
'\d\+ SOURCE .*/testdir/XimportAL.vim\_s*' ..
|
||||
'\d\+ STOREEXPORT someVar in .*/testdir/XimportAL.vim\_s*' ..
|
||||
|
||||
'\d\+ RETURN void',
|
||||
res)
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
delete('XimportAL.vim')
|
||||
enddef
|
||||
|
||||
def s:ScriptFuncStore()
|
||||
var localnr = 1
|
||||
localnr = 2
|
||||
|
||||
@@ -890,6 +890,93 @@ def Test_expr4_compare_null()
|
||||
unlet g:null_dict
|
||||
unlet g:not_null_list
|
||||
|
||||
# variables declared at script level used in a :def function
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
var l_decl: list<number>
|
||||
var l_empty = []
|
||||
var l_null = null_list
|
||||
|
||||
def TestList()
|
||||
assert_false(l_decl == null)
|
||||
assert_false(l_decl is null_list)
|
||||
assert_false(l_empty == null)
|
||||
assert_false(l_empty is null_list)
|
||||
assert_true(l_null == null)
|
||||
assert_true(l_null is null_list)
|
||||
assert_true(l_null == null_list)
|
||||
|
||||
add(l_decl, 6)
|
||||
assert_equal([6], l_decl)
|
||||
add(l_empty, 7)
|
||||
assert_equal([7], l_empty)
|
||||
var caught = false
|
||||
try
|
||||
add(l_null, 9)
|
||||
catch /E1130:/
|
||||
caught = true
|
||||
endtry
|
||||
assert_true(caught)
|
||||
enddef
|
||||
TestList()
|
||||
|
||||
var b_decl: blob
|
||||
var b_empty = 0z
|
||||
var b_null = null_blob
|
||||
|
||||
def TestBlob()
|
||||
assert_false(b_decl == null)
|
||||
assert_false(b_decl is null_blob)
|
||||
assert_false(b_empty == null)
|
||||
assert_false(b_empty is null_blob)
|
||||
assert_true(b_null == null)
|
||||
assert_true(b_null is null_blob)
|
||||
assert_true(b_null == null_blob)
|
||||
|
||||
add(b_decl, 6)
|
||||
assert_equal(0z06, b_decl)
|
||||
add(b_empty, 7)
|
||||
assert_equal(0z07, b_empty)
|
||||
var caught = false
|
||||
try
|
||||
add(b_null, 9)
|
||||
catch /E1131:/
|
||||
caught = true
|
||||
endtry
|
||||
assert_true(caught)
|
||||
enddef
|
||||
TestBlob()
|
||||
|
||||
var d_decl: dict<number>
|
||||
var d_empty = {}
|
||||
var d_null = null_dict
|
||||
|
||||
def TestDict()
|
||||
assert_false(d_decl == null)
|
||||
assert_false(d_decl is null_dict)
|
||||
assert_false(d_empty == null)
|
||||
assert_false(d_empty is null_dict)
|
||||
assert_true(d_null == null)
|
||||
assert_true(d_null is null_dict)
|
||||
assert_true(d_null == null_dict)
|
||||
|
||||
d_decl['a'] = 6
|
||||
assert_equal({a: 6}, d_decl)
|
||||
d_empty['b'] = 7
|
||||
assert_equal({b: 7}, d_empty)
|
||||
var caught = false
|
||||
try
|
||||
d_null['c'] = 9
|
||||
catch /E1103:/
|
||||
caught = true
|
||||
endtry
|
||||
assert_true(caught)
|
||||
enddef
|
||||
TestDict()
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
lines =<< trim END
|
||||
var d: dict<func> = {f: null_function}
|
||||
assert_equal(null_function, d.f)
|
||||
@@ -3923,7 +4010,7 @@ func Test_expr_fails()
|
||||
call v9.CheckDefFailure(["echo len('asdf'"], 'E110:', 2)
|
||||
call v9.CheckScriptFailure(['vim9script', "echo len('asdf'"], 'E116:', 2)
|
||||
|
||||
call v9.CheckDefAndScriptFailure(["echo Func0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789()"], ['E1011:', 'E117:'], 1)
|
||||
call v9.CheckDefAndScriptFailure(["echo Func01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789()"], ['E1011:', 'E117:'], 1)
|
||||
call v9.CheckDefAndScriptFailure(["echo doesnotexist()"], 'E117:', 1)
|
||||
endfunc
|
||||
|
||||
|
||||
@@ -840,6 +840,160 @@ def Test_use_autoload_import_in_fold_expression()
|
||||
&rtp = save_rtp
|
||||
enddef
|
||||
|
||||
def Test_autoload_import_relative()
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
|
||||
g:loaded = 'yes'
|
||||
export def RelFunc(): string
|
||||
return 'relfunc'
|
||||
enddef
|
||||
def NotExported()
|
||||
echo 'not'
|
||||
enddef
|
||||
|
||||
export var someText = 'some text'
|
||||
var notexp = 'bad'
|
||||
END
|
||||
writefile(lines, 'XimportRel.vim')
|
||||
writefile(lines, 'XimportRel2.vim')
|
||||
writefile(lines, 'XimportRel3.vim')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
g:loaded = 'no'
|
||||
import autoload './XimportRel.vim'
|
||||
assert_equal('no', g:loaded)
|
||||
|
||||
def AFunc(): string
|
||||
var res = ''
|
||||
res ..= XimportRel.RelFunc()
|
||||
res ..= '/'
|
||||
res ..= XimportRel.someText
|
||||
XimportRel.someText = 'from AFunc'
|
||||
return res
|
||||
enddef
|
||||
# script not loaded when compiling
|
||||
defcompile
|
||||
assert_equal('no', g:loaded)
|
||||
|
||||
assert_equal('relfunc/some text', AFunc())
|
||||
assert_equal('yes', g:loaded)
|
||||
unlet g:loaded
|
||||
|
||||
assert_equal('from AFunc', XimportRel.someText)
|
||||
XimportRel.someText = 'from script'
|
||||
assert_equal('from script', XimportRel.someText)
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportRel.vim'
|
||||
echo XimportRel.NotExported()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExported', 3)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportRel.vim'
|
||||
echo XimportRel.notexp
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 3)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportRel.vim'
|
||||
XimportRel.notexp = 'bad'
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 3)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportRel.vim'
|
||||
def Func()
|
||||
echo XimportRel.NotExported()
|
||||
enddef
|
||||
Func()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExported', 1)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportRel.vim'
|
||||
def Func()
|
||||
echo XimportRel.notexp
|
||||
enddef
|
||||
Func()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportRel.vim'
|
||||
def Func()
|
||||
XimportRel.notexp = 'bad'
|
||||
enddef
|
||||
Func()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1)
|
||||
|
||||
# does not fail if the script wasn't loaded yet
|
||||
g:loaded = 'no'
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportRel2.vim'
|
||||
def Func()
|
||||
echo XimportRel2.notexp
|
||||
enddef
|
||||
defcompile
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
assert_equal('no', g:loaded)
|
||||
|
||||
# fails with a not loaded import
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './XimportRel3.vim'
|
||||
def Func()
|
||||
XimportRel3.notexp = 'bad'
|
||||
enddef
|
||||
Func()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1)
|
||||
assert_equal('yes', g:loaded)
|
||||
unlet g:loaded
|
||||
|
||||
delete('XimportRel.vim')
|
||||
delete('XimportRel2.vim')
|
||||
delete('XimportRel3.vim')
|
||||
enddef
|
||||
|
||||
def Test_autoload_import_relative_autoload_dir()
|
||||
mkdir('autoload', 'p')
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
export def Bar()
|
||||
g:called_bar = 'yes'
|
||||
enddef
|
||||
END
|
||||
writefile(lines, 'autoload/script.vim')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload './autoload/script.vim'
|
||||
def Foo()
|
||||
script.Bar()
|
||||
enddef
|
||||
Foo()
|
||||
assert_equal('yes', g:called_bar)
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
unlet g:called_bar
|
||||
delete('autoload', 'rf')
|
||||
enddef
|
||||
|
||||
func Test_import_in_diffexpr()
|
||||
CheckExecutable diff
|
||||
|
||||
@@ -2379,13 +2533,19 @@ def Test_import_autoload_fails()
|
||||
vim9script
|
||||
import autoload './doesNotExist.vim'
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1264:')
|
||||
v9.CheckScriptFailure(lines, 'E282:', 2)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload '/dir/doesNotExist.vim'
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1264:')
|
||||
v9.CheckScriptFailure(lines, 'E282:', 2)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
import autoload '../testdir'
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E17:', 2)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
+43
-15
@@ -526,6 +526,28 @@ set_ufunc_name(ufunc_T *fp, char_u *name)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If "name" starts with K_SPECIAL and "buf[bufsize]" is big enough
|
||||
* return "buf" filled with a readable function name.
|
||||
* Otherwise just return "name", thus the return value can always be used.
|
||||
* "name" and "buf" may be equal.
|
||||
*/
|
||||
char_u *
|
||||
make_ufunc_name_readable(char_u *name, char_u *buf, size_t bufsize)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (name[0] != K_SPECIAL)
|
||||
return name;
|
||||
len = STRLEN(name);
|
||||
if (len + 3 > bufsize)
|
||||
return name;
|
||||
|
||||
mch_memmove(buf + 5, name + 3, len + 1);
|
||||
mch_memmove(buf, "<SNR>", 5);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a name for a lambda. Returned in static memory.
|
||||
*/
|
||||
@@ -1883,6 +1905,21 @@ fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
|
||||
return fname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenate the script ID and function name into "<SNR>99_name".
|
||||
* "buffer" must have size MAX_FUNC_NAME_LEN.
|
||||
*/
|
||||
void
|
||||
func_name_with_sid(char_u *name, int sid, char_u *buffer)
|
||||
{
|
||||
// A script-local function is stored as "<SNR>99_name".
|
||||
buffer[0] = K_SPECIAL;
|
||||
buffer[1] = KS_EXTRA;
|
||||
buffer[2] = (int)KE_SNR;
|
||||
vim_snprintf((char *)buffer + 3, MAX_FUNC_NAME_LEN - 3, "%ld_%s",
|
||||
(long)sid, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a function "name" in script "sid".
|
||||
*/
|
||||
@@ -1890,17 +1927,12 @@ fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
|
||||
find_func_with_sid(char_u *name, int sid)
|
||||
{
|
||||
hashitem_T *hi;
|
||||
char_u buffer[200];
|
||||
char_u buffer[MAX_FUNC_NAME_LEN];
|
||||
|
||||
if (!SCRIPT_ID_VALID(sid))
|
||||
return NULL; // not in a script
|
||||
|
||||
// A script-local function is stored as "<SNR>99_name".
|
||||
buffer[0] = K_SPECIAL;
|
||||
buffer[1] = KS_EXTRA;
|
||||
buffer[2] = (int)KE_SNR;
|
||||
vim_snprintf((char *)buffer + 3, sizeof(buffer) - 3, "%ld_%s",
|
||||
(long)sid, name);
|
||||
func_name_with_sid(name, sid, buffer);
|
||||
hi = hash_find(&func_hashtab, buffer);
|
||||
if (!HASHITEM_EMPTY(hi))
|
||||
return HI2UF(hi);
|
||||
@@ -1914,7 +1946,7 @@ find_func_with_sid(char_u *name, int sid)
|
||||
find_func_with_prefix(char_u *name, int sid)
|
||||
{
|
||||
hashitem_T *hi;
|
||||
char_u buffer[200];
|
||||
char_u buffer[MAX_FUNC_NAME_LEN];
|
||||
scriptitem_T *si;
|
||||
|
||||
if (vim_strchr(name, AUTOLOAD_CHAR) != NULL)
|
||||
@@ -3344,13 +3376,12 @@ user_func_error(int error, char_u *name, funcexe_T *funcexe)
|
||||
{
|
||||
case FCERR_UNKNOWN:
|
||||
if (funcexe->fe_found_var)
|
||||
semsg(_(e_not_callable_type_str), name);
|
||||
emsg_funcname(e_not_callable_type_str, name);
|
||||
else
|
||||
emsg_funcname(e_unknown_function_str, name);
|
||||
break;
|
||||
case FCERR_NOTMETHOD:
|
||||
emsg_funcname(
|
||||
N_(e_cannot_use_function_as_method_str), name);
|
||||
emsg_funcname(e_cannot_use_function_as_method_str, name);
|
||||
break;
|
||||
case FCERR_DELETED:
|
||||
emsg_funcname(e_function_was_deleted_str, name);
|
||||
@@ -3362,8 +3393,7 @@ user_func_error(int error, char_u *name, funcexe_T *funcexe)
|
||||
emsg_funcname(e_not_enough_arguments_for_function_str, name);
|
||||
break;
|
||||
case FCERR_SCRIPT:
|
||||
emsg_funcname(
|
||||
e_using_sid_not_in_script_context_str, name);
|
||||
emsg_funcname(e_using_sid_not_in_script_context_str, name);
|
||||
break;
|
||||
case FCERR_DICT:
|
||||
emsg_funcname(e_calling_dict_function_without_dictionary_str,
|
||||
@@ -3603,9 +3633,7 @@ theend:
|
||||
* cancelled due to an aborting error, an interrupt, or an exception.
|
||||
*/
|
||||
if (!aborting())
|
||||
{
|
||||
user_func_error(error, (name != NULL) ? name : funcname, funcexe);
|
||||
}
|
||||
|
||||
// clear the copies made from the partial
|
||||
while (argv_clear > 0)
|
||||
|
||||
@@ -765,6 +765,44 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
4658,
|
||||
/**/
|
||||
4657,
|
||||
/**/
|
||||
4656,
|
||||
/**/
|
||||
4655,
|
||||
/**/
|
||||
4654,
|
||||
/**/
|
||||
4653,
|
||||
/**/
|
||||
4652,
|
||||
/**/
|
||||
4651,
|
||||
/**/
|
||||
4650,
|
||||
/**/
|
||||
4649,
|
||||
/**/
|
||||
4648,
|
||||
/**/
|
||||
4647,
|
||||
/**/
|
||||
4646,
|
||||
/**/
|
||||
4645,
|
||||
/**/
|
||||
4644,
|
||||
/**/
|
||||
4643,
|
||||
/**/
|
||||
4642,
|
||||
/**/
|
||||
4641,
|
||||
/**/
|
||||
4640,
|
||||
/**/
|
||||
4639,
|
||||
/**/
|
||||
|
||||
@@ -1580,6 +1580,9 @@ typedef UINT32_TYPEDEF UINT32_T;
|
||||
*/
|
||||
#define MAXMAPLEN 50
|
||||
|
||||
// maximum length of a function name, including SID and NUL
|
||||
#define MAX_FUNC_NAME_LEN 200
|
||||
|
||||
// Size in bytes of the hash used in the undo file.
|
||||
#define UNDO_HASH_SIZE 32
|
||||
|
||||
@@ -2240,6 +2243,7 @@ typedef enum {
|
||||
#define ASSIGN_UNPACK 0x10 // using [a, b] = list
|
||||
#define ASSIGN_NO_MEMBER_TYPE 0x20 // use "any" for list and dict member type
|
||||
#define ASSIGN_FOR_LOOP 0x40 // assigning to loop variable
|
||||
#define ASSIGN_INIT 0x80 // not assigning a value, just a declaration
|
||||
|
||||
#include "ex_cmds.h" // Ex command defines
|
||||
#include "spell.h" // spell checking stuff
|
||||
|
||||
@@ -28,6 +28,8 @@ typedef enum {
|
||||
ISN_ECHOERR, // :echoerr with isn_arg.number items on top of stack
|
||||
ISN_RANGE, // compute range from isn_arg.string, push to stack
|
||||
ISN_SUBSTITUTE, // :s command with expression
|
||||
|
||||
ISN_SOURCE, // source autoload script, isn_arg.number is the script ID
|
||||
ISN_INSTR, // instructions compiled from expression
|
||||
|
||||
// get and set variables
|
||||
@@ -43,6 +45,7 @@ typedef enum {
|
||||
ISN_LOADWDICT, // push w: dict
|
||||
ISN_LOADTDICT, // push t: dict
|
||||
ISN_LOADS, // push s: variable isn_arg.loadstore
|
||||
ISN_LOADEXPORT, // push exported variable isn_arg.loadstore
|
||||
ISN_LOADOUTER, // push variable from outer scope isn_arg.outer
|
||||
ISN_LOADSCRIPT, // push script-local variable isn_arg.script.
|
||||
ISN_LOADOPT, // push option isn_arg.string
|
||||
@@ -57,6 +60,7 @@ typedef enum {
|
||||
ISN_STOREW, // pop into window-local variable isn_arg.string
|
||||
ISN_STORET, // pop into tab-local variable isn_arg.string
|
||||
ISN_STORES, // pop into script variable isn_arg.loadstore
|
||||
ISN_STOREEXPORT, // pop into exported script variable isn_arg.loadstore
|
||||
ISN_STOREOUTER, // pop variable into outer scope isn_arg.outer
|
||||
ISN_STORESCRIPT, // pop into script variable isn_arg.script
|
||||
ISN_STOREOPT, // pop into option isn_arg.storeopt
|
||||
|
||||
+112
-31
@@ -937,6 +937,7 @@ call_prepare(int argcount, typval_T *argvars, ectx_T *ectx)
|
||||
tv = STACK_TV_BOT(-1);
|
||||
tv->v_type = VAR_NUMBER;
|
||||
tv->vval.v_number = 0;
|
||||
tv->v_lock = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -1011,10 +1012,11 @@ call_ufunc(
|
||||
if (error != FCERR_UNKNOWN)
|
||||
{
|
||||
if (error == FCERR_TOOMANY)
|
||||
semsg(_(e_too_many_arguments_for_function_str), ufunc->uf_name);
|
||||
semsg(_(e_too_many_arguments_for_function_str),
|
||||
printable_func_name(ufunc));
|
||||
else
|
||||
semsg(_(e_not_enough_arguments_for_function_str),
|
||||
ufunc->uf_name);
|
||||
printable_func_name(ufunc));
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
@@ -1046,7 +1048,7 @@ call_ufunc(
|
||||
|
||||
if (error != FCERR_NONE)
|
||||
{
|
||||
user_func_error(error, ufunc->uf_name, &funcexe);
|
||||
user_func_error(error, printable_func_name(ufunc), &funcexe);
|
||||
return FAIL;
|
||||
}
|
||||
if (did_emsg > did_emsg_before)
|
||||
@@ -1210,7 +1212,7 @@ call_partial(
|
||||
if (res == FAIL)
|
||||
{
|
||||
if (called_emsg == called_emsg_before)
|
||||
semsg(_(e_unknown_function_str),
|
||||
emsg_funcname(e_unknown_function_str,
|
||||
name == NULL ? (char_u *)"[unknown]" : name);
|
||||
return FAIL;
|
||||
}
|
||||
@@ -1336,20 +1338,22 @@ do_2string(typval_T *tv, int is_2string_any, int tolerant)
|
||||
* When the value of "sv" is a null list of dict, allocate it.
|
||||
*/
|
||||
static void
|
||||
allocate_if_null(typval_T *tv)
|
||||
allocate_if_null(svar_T *sv)
|
||||
{
|
||||
typval_T *tv = sv->sv_tv;
|
||||
|
||||
switch (tv->v_type)
|
||||
{
|
||||
case VAR_LIST:
|
||||
if (tv->vval.v_list == NULL)
|
||||
if (tv->vval.v_list == NULL && sv->sv_type != &t_list_empty)
|
||||
(void)rettv_list_alloc(tv);
|
||||
break;
|
||||
case VAR_DICT:
|
||||
if (tv->vval.v_dict == NULL)
|
||||
if (tv->vval.v_dict == NULL && sv->sv_type != &t_dict_empty)
|
||||
(void)rettv_dict_alloc(tv);
|
||||
break;
|
||||
case VAR_BLOB:
|
||||
if (tv->vval.v_blob == NULL)
|
||||
if (tv->vval.v_blob == NULL && sv->sv_type != &t_blob_null)
|
||||
(void)rettv_blob_alloc(tv);
|
||||
break;
|
||||
default:
|
||||
@@ -1507,6 +1511,13 @@ get_script_svar(scriptref_T *sref, int dfunc_idx)
|
||||
emsg(_(e_script_variable_type_changed));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!sv->sv_export && sref->sref_sid != current_sctx.sc_sid)
|
||||
{
|
||||
if (dfunc != NULL)
|
||||
semsg(_(e_item_not_exported_in_script_str), sv->sv_name);
|
||||
return NULL;
|
||||
}
|
||||
return sv;
|
||||
}
|
||||
|
||||
@@ -1560,14 +1571,10 @@ call_eval_func(
|
||||
dictitem_T *v;
|
||||
|
||||
v = find_var(name, NULL, FALSE);
|
||||
if (v == NULL)
|
||||
if (v == NULL || (v->di_tv.v_type != VAR_PARTIAL
|
||||
&& v->di_tv.v_type != VAR_FUNC))
|
||||
{
|
||||
semsg(_(e_unknown_function_str), name);
|
||||
return FAIL;
|
||||
}
|
||||
if (v->di_tv.v_type != VAR_PARTIAL && v->di_tv.v_type != VAR_FUNC)
|
||||
{
|
||||
semsg(_(e_unknown_function_str), name);
|
||||
emsg_funcname(e_unknown_function_str, name);
|
||||
return FAIL;
|
||||
}
|
||||
return call_partial(&v->di_tv, argcount, ectx);
|
||||
@@ -2620,6 +2627,20 @@ exec_instructions(ectx_T *ectx)
|
||||
}
|
||||
break;
|
||||
|
||||
case ISN_SOURCE:
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(iptr->isn_arg.number);
|
||||
|
||||
if (si->sn_state == SN_STATE_NOT_LOADED)
|
||||
{
|
||||
SOURCING_LNUM = iptr->isn_lnum;
|
||||
if (do_source(si->sn_name, FALSE, DOSO_NONE, NULL)
|
||||
== FAIL)
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// execute :substitute with an expression
|
||||
case ISN_SUBSTITUTE:
|
||||
{
|
||||
@@ -2891,7 +2912,7 @@ exec_instructions(ectx_T *ectx)
|
||||
sv = get_script_svar(sref, ectx->ec_dfunc_idx);
|
||||
if (sv == NULL)
|
||||
goto theend;
|
||||
allocate_if_null(sv->sv_tv);
|
||||
allocate_if_null(sv);
|
||||
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
|
||||
goto theend;
|
||||
copy_tv(sv->sv_tv, STACK_TV_BOT(0));
|
||||
@@ -2899,11 +2920,12 @@ exec_instructions(ectx_T *ectx)
|
||||
}
|
||||
break;
|
||||
|
||||
// load s: variable in old script
|
||||
// load s: variable in old script or autoload import
|
||||
case ISN_LOADS:
|
||||
case ISN_LOADEXPORT:
|
||||
{
|
||||
hashtab_T *ht = &SCRIPT_VARS(
|
||||
iptr->isn_arg.loadstore.ls_sid);
|
||||
int sid = iptr->isn_arg.loadstore.ls_sid;
|
||||
hashtab_T *ht = &SCRIPT_VARS(sid);
|
||||
char_u *name = iptr->isn_arg.loadstore.ls_name;
|
||||
dictitem_T *di = find_var_in_ht(ht, 0, name, TRUE);
|
||||
|
||||
@@ -2915,6 +2937,25 @@ exec_instructions(ectx_T *ectx)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iptr->isn_type == ISN_LOADEXPORT)
|
||||
{
|
||||
int idx = get_script_item_idx(sid, name, 0,
|
||||
NULL, NULL);
|
||||
svar_T *sv;
|
||||
|
||||
if (idx >= 0)
|
||||
{
|
||||
sv = ((svar_T *)SCRIPT_ITEM(sid)
|
||||
->sn_var_vals.ga_data) + idx;
|
||||
if (!sv->sv_export)
|
||||
{
|
||||
SOURCING_LNUM = iptr->isn_lnum;
|
||||
semsg(_(e_item_not_exported_in_script_str),
|
||||
name);
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
|
||||
goto theend;
|
||||
copy_tv(&di->di_tv, STACK_TV_BOT(0));
|
||||
@@ -3036,20 +3077,50 @@ exec_instructions(ectx_T *ectx)
|
||||
*tv = *STACK_TV_BOT(0);
|
||||
break;
|
||||
|
||||
// store s: variable in old script
|
||||
// store s: variable in old script or autoload import
|
||||
case ISN_STORES:
|
||||
case ISN_STOREEXPORT:
|
||||
{
|
||||
hashtab_T *ht = &SCRIPT_VARS(
|
||||
iptr->isn_arg.loadstore.ls_sid);
|
||||
int sid = iptr->isn_arg.loadstore.ls_sid;
|
||||
hashtab_T *ht = &SCRIPT_VARS(sid);
|
||||
char_u *name = iptr->isn_arg.loadstore.ls_name;
|
||||
dictitem_T *di = find_var_in_ht(ht, 0, name + 2, TRUE);
|
||||
dictitem_T *di = find_var_in_ht(ht, 0,
|
||||
iptr->isn_type == ISN_STORES
|
||||
? name + 2 : name, TRUE);
|
||||
|
||||
--ectx->ec_stack.ga_len;
|
||||
SOURCING_LNUM = iptr->isn_lnum;
|
||||
if (di == NULL)
|
||||
{
|
||||
if (iptr->isn_type == ISN_STOREEXPORT)
|
||||
{
|
||||
semsg(_(e_undefined_variable_str), name);
|
||||
clear_tv(STACK_TV_BOT(0));
|
||||
goto on_error;
|
||||
}
|
||||
store_var(name, STACK_TV_BOT(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
SOURCING_LNUM = iptr->isn_lnum;
|
||||
if (iptr->isn_type == ISN_STOREEXPORT)
|
||||
{
|
||||
int idx = get_script_item_idx(sid, name, 0,
|
||||
NULL, NULL);
|
||||
|
||||
if (idx >= 0)
|
||||
{
|
||||
svar_T *sv = ((svar_T *)SCRIPT_ITEM(sid)
|
||||
->sn_var_vals.ga_data) + idx;
|
||||
|
||||
if (!sv->sv_export)
|
||||
{
|
||||
semsg(_(e_item_not_exported_in_script_str),
|
||||
name);
|
||||
clear_tv(STACK_TV_BOT(0));
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (var_check_permission(di, name) == FAIL)
|
||||
{
|
||||
clear_tv(STACK_TV_BOT(0));
|
||||
@@ -5406,11 +5477,15 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
||||
#endif
|
||||
break;
|
||||
case ISN_INSTR:
|
||||
smsg("%s%4d INSTR", pfx, current);
|
||||
list_instructions(" ", iptr->isn_arg.instr, INT_MAX, NULL);
|
||||
msg(" -------------");
|
||||
break;
|
||||
case ISN_SOURCE:
|
||||
{
|
||||
smsg("%s%4d INSTR", pfx, current);
|
||||
list_instructions(" ", iptr->isn_arg.instr,
|
||||
INT_MAX, NULL);
|
||||
msg(" -------------");
|
||||
scriptitem_T *si = SCRIPT_ITEM(iptr->isn_arg.number);
|
||||
|
||||
smsg("%s%4d SOURCE %s", pfx, current, si->sn_name);
|
||||
}
|
||||
break;
|
||||
case ISN_SUBSTITUTE:
|
||||
@@ -5497,12 +5572,15 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
||||
}
|
||||
break;
|
||||
case ISN_LOADS:
|
||||
case ISN_LOADEXPORT:
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(
|
||||
iptr->isn_arg.loadstore.ls_sid);
|
||||
|
||||
smsg("%s%4d LOADS s:%s from %s", pfx, current,
|
||||
iptr->isn_arg.loadstore.ls_name, si->sn_name);
|
||||
smsg("%s%4d %s s:%s from %s", pfx, current,
|
||||
iptr->isn_type == ISN_LOADS ? "LOADS"
|
||||
: "LOADEXPORT",
|
||||
iptr->isn_arg.loadstore.ls_name, si->sn_name);
|
||||
}
|
||||
break;
|
||||
case ISN_LOADAUTO:
|
||||
@@ -5583,11 +5661,14 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
||||
smsg("%s%4d STORET %s", pfx, current, iptr->isn_arg.string);
|
||||
break;
|
||||
case ISN_STORES:
|
||||
case ISN_STOREEXPORT:
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(
|
||||
iptr->isn_arg.loadstore.ls_sid);
|
||||
|
||||
smsg("%s%4d STORES %s in %s", pfx, current,
|
||||
smsg("%s%4d %s %s in %s", pfx, current,
|
||||
iptr->isn_type == ISN_STORES
|
||||
? "STORES" : "STOREEXPORT",
|
||||
iptr->isn_arg.loadstore.ls_name, si->sn_name);
|
||||
}
|
||||
break;
|
||||
|
||||
+48
-21
@@ -298,26 +298,53 @@ compile_load_scriptvar(
|
||||
*p = NUL;
|
||||
|
||||
si = SCRIPT_ITEM(import->imp_sid);
|
||||
if (si->sn_autoload_prefix != NULL
|
||||
&& si->sn_state == SN_STATE_NOT_LOADED)
|
||||
{
|
||||
char_u *auto_name = concat_str(si->sn_autoload_prefix, exp_name);
|
||||
if (si->sn_import_autoload && si->sn_state == SN_STATE_NOT_LOADED)
|
||||
// "import autoload './dir/script.vim'" or
|
||||
// "import autoload './autoload/script.vim'" - load script first
|
||||
res = generate_SOURCE(cctx, import->imp_sid);
|
||||
|
||||
// autoload script must be loaded later, access by the autoload
|
||||
// name. If a '(' follows it must be a function. Otherwise we
|
||||
// don't know, it can be "script.Func".
|
||||
if (cc == '(' || paren_follows_after_expr)
|
||||
res = generate_PUSHFUNC(cctx, auto_name, &t_func_any);
|
||||
else
|
||||
res = generate_AUTOLOAD(cctx, auto_name, &t_any);
|
||||
vim_free(auto_name);
|
||||
done = TRUE;
|
||||
}
|
||||
else
|
||||
if (res == OK)
|
||||
{
|
||||
idx = find_exported(import->imp_sid, exp_name, &ufunc, &type,
|
||||
cctx, NULL, TRUE);
|
||||
if (si->sn_autoload_prefix != NULL
|
||||
&& si->sn_state == SN_STATE_NOT_LOADED)
|
||||
{
|
||||
char_u *auto_name =
|
||||
concat_str(si->sn_autoload_prefix, exp_name);
|
||||
|
||||
// autoload script must be loaded later, access by the autoload
|
||||
// name. If a '(' follows it must be a function. Otherwise we
|
||||
// don't know, it can be "script.Func".
|
||||
if (cc == '(' || paren_follows_after_expr)
|
||||
res = generate_PUSHFUNC(cctx, auto_name, &t_func_any);
|
||||
else
|
||||
res = generate_AUTOLOAD(cctx, auto_name, &t_any);
|
||||
vim_free(auto_name);
|
||||
done = TRUE;
|
||||
}
|
||||
else if (si->sn_import_autoload
|
||||
&& si->sn_state == SN_STATE_NOT_LOADED)
|
||||
{
|
||||
// If a '(' follows it must be a function. Otherwise we don't
|
||||
// know, it can be "script.Func".
|
||||
if (cc == '(' || paren_follows_after_expr)
|
||||
{
|
||||
char_u sid_name[MAX_FUNC_NAME_LEN];
|
||||
|
||||
func_name_with_sid(exp_name, import->imp_sid, sid_name);
|
||||
res = generate_PUSHFUNC(cctx, sid_name, &t_func_any);
|
||||
}
|
||||
else
|
||||
res = generate_OLDSCRIPT(cctx, ISN_LOADEXPORT, exp_name,
|
||||
import->imp_sid, &t_any);
|
||||
done = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = find_exported(import->imp_sid, exp_name, &ufunc, &type,
|
||||
cctx, NULL, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
*p = cc;
|
||||
*end = p;
|
||||
if (done)
|
||||
@@ -671,7 +698,7 @@ compile_call(
|
||||
char_u *name = *arg;
|
||||
char_u *p;
|
||||
int argcount = argcount_init;
|
||||
char_u namebuf[100];
|
||||
char_u namebuf[MAX_FUNC_NAME_LEN];
|
||||
char_u fname_buf[FLEN_FIXED + 1];
|
||||
char_u *tofree = NULL;
|
||||
int error = FCERR_NONE;
|
||||
@@ -791,7 +818,7 @@ compile_call(
|
||||
res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
|
||||
}
|
||||
else
|
||||
semsg(_(e_unknown_function_str), namebuf);
|
||||
emsg_funcname(e_unknown_function_str, namebuf);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
@@ -816,7 +843,7 @@ compile_call(
|
||||
&& vim_strchr(ufunc->uf_name, AUTOLOAD_CHAR) == NULL)
|
||||
{
|
||||
// A function name without g: prefix must be found locally.
|
||||
semsg(_(e_unknown_function_str), namebuf);
|
||||
emsg_funcname(e_unknown_function_str, namebuf);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@@ -847,7 +874,7 @@ compile_call(
|
||||
if (has_g_namespace || is_autoload)
|
||||
res = generate_UCALL(cctx, name, argcount);
|
||||
else
|
||||
semsg(_(e_unknown_function_str), namebuf);
|
||||
emsg_funcname(e_unknown_function_str, namebuf);
|
||||
|
||||
theend:
|
||||
vim_free(tofree);
|
||||
|
||||
+58
-25
@@ -1066,7 +1066,7 @@ generate_OLDSCRIPT(
|
||||
isn_T *isn;
|
||||
|
||||
RETURN_OK_IF_SKIP(cctx);
|
||||
if (isn_type == ISN_LOADS)
|
||||
if (isn_type == ISN_LOADS || isn_type == ISN_LOADEXPORT)
|
||||
isn = generate_instr_type(cctx, isn_type, type);
|
||||
else
|
||||
isn = generate_instr_drop(cctx, isn_type, 1);
|
||||
@@ -1517,7 +1517,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
||||
}
|
||||
if (ufunc->uf_def_status == UF_COMPILE_ERROR)
|
||||
{
|
||||
emsg_funcname(_(e_call_to_function_that_failed_to_compile_str),
|
||||
emsg_funcname(e_call_to_function_that_failed_to_compile_str,
|
||||
ufunc->uf_name);
|
||||
return FAIL;
|
||||
}
|
||||
@@ -1594,12 +1594,12 @@ generate_PCALL(
|
||||
|
||||
if (argcount < type->tt_min_argcount - varargs)
|
||||
{
|
||||
semsg(_(e_not_enough_arguments_for_function_str), name);
|
||||
emsg_funcname(e_not_enough_arguments_for_function_str, name);
|
||||
return FAIL;
|
||||
}
|
||||
if (!varargs && argcount > type->tt_argcount)
|
||||
{
|
||||
semsg(_(e_too_many_arguments_for_function_str), name);
|
||||
emsg_funcname(e_too_many_arguments_for_function_str, name);
|
||||
return FAIL;
|
||||
}
|
||||
if (type->tt_args != NULL)
|
||||
@@ -1727,6 +1727,21 @@ generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an ISN_SOURCE instruction.
|
||||
*/
|
||||
int
|
||||
generate_SOURCE(cctx_T *cctx, int sid)
|
||||
{
|
||||
isn_T *isn;
|
||||
|
||||
if ((isn = generate_instr(cctx, ISN_SOURCE)) == NULL)
|
||||
return FAIL;
|
||||
isn->isn_arg.number = sid;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an ISN_PUT instruction.
|
||||
*/
|
||||
@@ -1913,9 +1928,24 @@ generate_store_var(
|
||||
return generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL);
|
||||
case dest_script:
|
||||
if (scriptvar_idx < 0)
|
||||
{
|
||||
isntype_T isn_type = ISN_STORES;
|
||||
|
||||
if (SCRIPT_ID_VALID(scriptvar_sid)
|
||||
&& SCRIPT_ITEM(scriptvar_sid)->sn_import_autoload
|
||||
&& SCRIPT_ITEM(scriptvar_sid)->sn_autoload_prefix
|
||||
== NULL)
|
||||
{
|
||||
// "import autoload './dir/script.vim'" - load script first
|
||||
if (generate_SOURCE(cctx, scriptvar_sid) == FAIL)
|
||||
return FAIL;
|
||||
isn_type = ISN_STOREEXPORT;
|
||||
}
|
||||
|
||||
// "s:" may be included in the name.
|
||||
return generate_OLDSCRIPT(cctx, ISN_STORES, name,
|
||||
scriptvar_sid, type);
|
||||
return generate_OLDSCRIPT(cctx, isn_type, name,
|
||||
scriptvar_sid, type);
|
||||
}
|
||||
return generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
|
||||
scriptvar_sid, scriptvar_idx, type);
|
||||
case dest_local:
|
||||
@@ -2062,7 +2092,9 @@ delete_instr(isn_T *isn)
|
||||
break;
|
||||
|
||||
case ISN_LOADS:
|
||||
case ISN_LOADEXPORT:
|
||||
case ISN_STORES:
|
||||
case ISN_STOREEXPORT:
|
||||
vim_free(isn->isn_arg.loadstore.ls_name);
|
||||
break;
|
||||
|
||||
@@ -2089,7 +2121,7 @@ delete_instr(isn_T *isn)
|
||||
if (isn->isn_arg.funcref.fr_func_name == NULL)
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ isn->isn_arg.funcref.fr_dfunc_idx;
|
||||
+ isn->isn_arg.funcref.fr_dfunc_idx;
|
||||
ufunc_T *ufunc = dfunc->df_ufunc;
|
||||
|
||||
if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
|
||||
@@ -2109,10 +2141,10 @@ delete_instr(isn_T *isn)
|
||||
case ISN_DCALL:
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ isn->isn_arg.dfunc.cdf_idx;
|
||||
+ isn->isn_arg.dfunc.cdf_idx;
|
||||
|
||||
if (dfunc->df_ufunc != NULL
|
||||
&& func_name_refcount(dfunc->df_ufunc->uf_name))
|
||||
&& func_name_refcount(dfunc->df_ufunc->uf_name))
|
||||
func_ptr_unref(dfunc->df_ufunc);
|
||||
}
|
||||
break;
|
||||
@@ -2140,7 +2172,7 @@ delete_instr(isn_T *isn)
|
||||
|
||||
case ISN_CMDMOD:
|
||||
vim_regfree(isn->isn_arg.cmdmod.cf_cmdmod
|
||||
->cmod_filter_regmatch.regprog);
|
||||
->cmod_filter_regmatch.regprog);
|
||||
vim_free(isn->isn_arg.cmdmod.cf_cmdmod);
|
||||
break;
|
||||
|
||||
@@ -2243,21 +2275,22 @@ delete_instr(isn_T *isn)
|
||||
case ISN_STORE:
|
||||
case ISN_STOREINDEX:
|
||||
case ISN_STORENR:
|
||||
case ISN_STOREOUTER:
|
||||
case ISN_STORERANGE:
|
||||
case ISN_STOREREG:
|
||||
case ISN_STOREV:
|
||||
case ISN_STRINDEX:
|
||||
case ISN_STRSLICE:
|
||||
case ISN_THROW:
|
||||
case ISN_TRYCONT:
|
||||
case ISN_UNLETINDEX:
|
||||
case ISN_UNLETRANGE:
|
||||
case ISN_UNPACK:
|
||||
case ISN_USEDICT:
|
||||
// nothing allocated
|
||||
break;
|
||||
}
|
||||
case ISN_SOURCE:
|
||||
case ISN_STOREOUTER:
|
||||
case ISN_STORERANGE:
|
||||
case ISN_STOREREG:
|
||||
case ISN_STOREV:
|
||||
case ISN_STRINDEX:
|
||||
case ISN_STRSLICE:
|
||||
case ISN_THROW:
|
||||
case ISN_TRYCONT:
|
||||
case ISN_UNLETINDEX:
|
||||
case ISN_UNLETRANGE:
|
||||
case ISN_UNPACK:
|
||||
case ISN_USEDICT:
|
||||
// nothing allocated
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+68
-23
@@ -383,6 +383,48 @@ mark_imports_for_reload(int sid)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Part of "import" that handles a relative or absolute file name/
|
||||
* Returns OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
handle_import_fname(char_u *fname, int is_autoload, int *sid)
|
||||
{
|
||||
if (is_autoload)
|
||||
{
|
||||
scriptitem_T *si;
|
||||
|
||||
*sid = find_script_by_name(fname);
|
||||
if (*sid < 0)
|
||||
{
|
||||
int error = OK;
|
||||
|
||||
// Script does not exist yet, check name and create a new
|
||||
// scriptitem.
|
||||
if (!file_is_readable(fname))
|
||||
{
|
||||
semsg(_(mch_isdir(fname) ? e_str_is_directory
|
||||
: e_cannot_read_from_str_2), fname);
|
||||
return FAIL;
|
||||
}
|
||||
*sid = get_new_scriptitem_for_fname(&error, fname);
|
||||
if (error == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
si = SCRIPT_ITEM(*sid);
|
||||
si->sn_import_autoload = TRUE;
|
||||
|
||||
if (si->sn_autoload_prefix == NULL)
|
||||
si->sn_autoload_prefix = get_autoload_prefix(si);
|
||||
|
||||
// with testing override: load autoload script right away
|
||||
if (!override_autoload || si->sn_state != SN_STATE_NOT_LOADED)
|
||||
return OK;
|
||||
}
|
||||
return do_source(fname, FALSE, DOSO_NONE, sid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle an ":import" command and add the resulting imported_T to "gap", when
|
||||
* not NULL, or script "import_sid" sn_imports.
|
||||
@@ -442,25 +484,18 @@ handle_import(
|
||||
char_u *tail = gettail(si->sn_name);
|
||||
char_u *from_name;
|
||||
|
||||
if (is_autoload)
|
||||
res = FAIL;
|
||||
else
|
||||
{
|
||||
// Relative to current script: "./name.vim", "../../name.vim".
|
||||
len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
|
||||
from_name = alloc((int)len);
|
||||
if (from_name == NULL)
|
||||
goto erret;
|
||||
vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
|
||||
add_pathsep(from_name);
|
||||
STRCAT(from_name, tv.vval.v_string);
|
||||
simplify_filename(from_name);
|
||||
|
||||
// Relative to current script: "./name.vim", "../../name.vim".
|
||||
len = STRLEN(si->sn_name) - STRLEN(tail)
|
||||
+ STRLEN(tv.vval.v_string) + 2;
|
||||
from_name = alloc((int)len);
|
||||
if (from_name == NULL)
|
||||
goto erret;
|
||||
vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
|
||||
add_pathsep(from_name);
|
||||
STRCAT(from_name, tv.vval.v_string);
|
||||
simplify_filename(from_name);
|
||||
|
||||
res = do_source(from_name, FALSE, DOSO_NONE, &sid);
|
||||
vim_free(from_name);
|
||||
}
|
||||
res = handle_import_fname(from_name, is_autoload, &sid);
|
||||
vim_free(from_name);
|
||||
}
|
||||
else if (mch_isFullName(tv.vval.v_string)
|
||||
#ifdef BACKSLASH_IN_FILENAME
|
||||
@@ -471,10 +506,7 @@ handle_import(
|
||||
)
|
||||
{
|
||||
// Absolute path: "/tmp/name.vim"
|
||||
if (is_autoload)
|
||||
res = FAIL;
|
||||
else
|
||||
res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
|
||||
res = handle_import_fname(tv.vval.v_string, is_autoload, &sid);
|
||||
}
|
||||
else if (is_autoload)
|
||||
{
|
||||
@@ -677,6 +709,12 @@ find_exported(
|
||||
svar_T *sv;
|
||||
scriptitem_T *script = SCRIPT_ITEM(sid);
|
||||
|
||||
if (script->sn_import_autoload && script->sn_state == SN_STATE_NOT_LOADED)
|
||||
{
|
||||
if (do_source(script->sn_name, FALSE, DOSO_NONE, NULL) == FAIL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find name in "script".
|
||||
idx = get_script_item_idx(sid, name, 0, cctx, cstack);
|
||||
if (idx >= 0)
|
||||
@@ -822,7 +860,7 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
|
||||
init_tv.v_type = VAR_NUMBER;
|
||||
else
|
||||
init_tv.v_type = type->tt_type;
|
||||
set_var_const(name, 0, type, &init_tv, FALSE, 0, 0);
|
||||
set_var_const(name, 0, type, &init_tv, FALSE, ASSIGN_INIT, 0);
|
||||
|
||||
vim_free(name);
|
||||
return p;
|
||||
@@ -925,6 +963,13 @@ update_vim9_script_var(
|
||||
if (*type == NULL)
|
||||
*type = typval2type(tv, get_copyID(), &si->sn_type_list,
|
||||
do_member ? TVTT_DO_MEMBER : 0);
|
||||
else if ((flags & ASSIGN_INIT) == 0
|
||||
&& (*type)->tt_type == VAR_BLOB && tv->v_type == VAR_BLOB
|
||||
&& tv->vval.v_blob == NULL)
|
||||
{
|
||||
// "var b: blob = null_blob" has a different type.
|
||||
*type = &t_blob_null;
|
||||
}
|
||||
if (sv->sv_type_allocated)
|
||||
free_type(sv->sv_type);
|
||||
if (*type != NULL && ((*type)->tt_type == VAR_FUNC
|
||||
|
||||
+6
-2
@@ -337,7 +337,11 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags)
|
||||
if (tv->v_type == VAR_STRING)
|
||||
return &t_string;
|
||||
if (tv->v_type == VAR_BLOB)
|
||||
{
|
||||
if (tv->vval.v_blob == NULL)
|
||||
return &t_blob_null;
|
||||
return &t_blob;
|
||||
}
|
||||
|
||||
if (tv->v_type == VAR_LIST)
|
||||
{
|
||||
@@ -776,12 +780,12 @@ check_argument_types(
|
||||
return OK; // just in case
|
||||
if (totcount < type->tt_min_argcount - varargs)
|
||||
{
|
||||
semsg(_(e_not_enough_arguments_for_function_str), name);
|
||||
emsg_funcname(e_not_enough_arguments_for_function_str, name);
|
||||
return FAIL;
|
||||
}
|
||||
if (!varargs && type->tt_argcount >= 0 && totcount > type->tt_argcount)
|
||||
{
|
||||
semsg(_(e_too_many_arguments_for_function_str), name);
|
||||
emsg_funcname(e_too_many_arguments_for_function_str, name);
|
||||
return FAIL;
|
||||
}
|
||||
if (type->tt_args == NULL)
|
||||
|
||||
Reference in New Issue
Block a user