diff options
-rw-r--r-- | runtime/autoload/dist/ft.vim | 22 | ||||
-rw-r--r-- | runtime/doc/lua.txt | 43 | ||||
-rw-r--r-- | runtime/filetype.vim | 18 | ||||
-rw-r--r-- | runtime/lua/vim/filetype.lua | 5 | ||||
-rw-r--r-- | runtime/syntax/query.lua | 6 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 52 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 22 | ||||
-rw-r--r-- | src/nvim/testdir/test_filetype.vim | 52 | ||||
-rw-r--r-- | test/functional/api/command_spec.lua | 48 |
9 files changed, 214 insertions, 54 deletions
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index 0063e9da0b..866196a7df 100644 --- a/runtime/autoload/dist/ft.vim +++ b/runtime/autoload/dist/ft.vim @@ -773,6 +773,28 @@ func dist#ft#SQL() endif endfunc +" This function checks the first 25 lines of file extension "sc" to resolve +" detection between scala and SuperCollider +func dist#ft#FTsc() + for lnum in range(1, min([line("$"), 25])) + if getline(lnum) =~# '[A-Za-z0-9]*\s:\s[A-Za-z0-9]\|var\s<\|classvar\s<\|\^this.*\||\w*|\|+\s\w*\s{\|\*ar\s' + setf supercollider + return + endif + endfor + setf scala +endfunc + +" This function checks the first line of file extension "scd" to resolve +" detection between scdoc and SuperCollider +func dist#ft#FTscd() + if getline(1) =~# '\%^\S\+(\d[0-9A-Za-z]*)\%(\s\+\"[^"]*\"\%(\s\+\"[^"]*\"\)\=\)\=$' + setf scdoc + else + setf supercollider + endif +endfunc + " If the file has an extension of 't' and is in a directory 't' or 'xt' then " it is almost certainly a Perl test file. " If the first line starts with '#' and contains 'perl' it's probably a Perl diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 25c5dd326e..46b9f0576f 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -21,19 +21,44 @@ Nvim includes a "standard library" |lua-stdlib| for Lua. It complements the which can be used from Lua code. A good overview of using Lua in neovim is given by https://github.com/nanotee/nvim-lua-guide. -Module conflicts are resolved by "last wins". For example if both of these -are on 'runtimepath': - runtime/lua/foo.lua - ~/.config/nvim/lua/foo.lua -then `require('foo')` loads "~/.config/nvim/lua/foo.lua", and -"runtime/lua/foo.lua" is not used. See |lua-require| to understand how Nvim -finds and loads Lua modules. The conventions are similar to those of -Vimscript |plugin|s, with some extra features. See |lua-require-example| for -a walkthrough. +The |:source| and |:runtime| commands can run Lua scripts as well as Vim +scripts. Lua modules can be loaded with `require('name')`, which +conventionally returns a table but can return any value. + +See |lua-require| for details on how Nvim finds and loads Lua modules. +See |lua-require-example| for an example of how to write and use a module. ============================================================================== IMPORTING LUA MODULES *lua-require* +Modules are searched for under the directories specified in 'runtimepath', in +the order they appear. Any `.` in the module name is treated as a directory +separator when searching. For a module `foo.bar`, each directory is searched +for `lua/foo/bar.lua`, then `lua/foo/bar/init.lua`. If no files are found, +the directories are searched again for a shared library with a name matching +`lua/foo/bar.?`, where `?` is a list of suffixes (such as `so` or `dll`) +derived from the initial value of `package.cpath`. If still no files are +found, Nvim falls back to Lua's default search mechanism. The first script +found is run and `require()` returns the value returned by the script if any, +else `true`. + +The return value is cached after the first call to `require()` for each +module, with subsequent calls returning the cached value without searching for +or executing any script. For further details on `require()`, see the Lua +documentation at https://www.lua.org/manual/5.1/manual.html#pdf-require. + +For example, if 'runtimepath' is `foo,bar` and `package.cpath` was +`./?.so;./?.dll` at startup, `require('mod')` searches these paths in order +and loads the first module found: + foo/lua/mod.lua + foo/lua/mod/init.lua + bar/lua/mod.lua + bar/lua/mod/init.lua + foo/lua/mod.so + foo/lua/mod.dll + bar/lua/mod.so + bar/lua/mod.dll + *lua-package-path* Nvim automatically adjusts `package.path` and `package.cpath` according to effective 'runtimepath' value. Adjustment happens whenever 'runtimepath' is diff --git a/runtime/filetype.vim b/runtime/filetype.vim index c5690ba716..f7c0317eff 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -202,12 +202,12 @@ au BufNewFile,BufRead *.iba,*.ibi setf ibasic au BufNewFile,BufRead *.fb setf freebasic " Batch file for MSDOS. See dist#ft#FTsys for *.sys -au BufNewFile,BufRead *.bat setf dosbatch +au BufNewFile,BufRead *.bat setf dosbatch " *.cmd is close to a Batch file, but on OS/2 Rexx files also use *.cmd. au BufNewFile,BufRead *.cmd \ if getline(1) =~ '^/\*' | setf rexx | else | setf dosbatch | endif " ABB RAPID or Batch file for MSDOS. -au BufNewFile,BufRead *.sys\c call dist#ft#FTsys() +au BufNewFile,BufRead *.sys\c call dist#ft#FTsys() " Batch file for 4DOS au BufNewFile,BufRead *.btm call dist#ft#FTbtm() @@ -1140,7 +1140,7 @@ au BufNewFile,BufRead *.mms call dist#ft#FTmms() au BufNewFile,BufRead *.mmp setf mmp " ABB Rapid, Modula-2, Modsim III or LambdaProlog -au BufNewFile,BufRead *.mod\c call dist#ft#FTmod() +au BufNewFile,BufRead *.mod\c call dist#ft#FTmod() " Modula-2 (.md removed in favor of Markdown, see dist#ft#FTmod for *.MOD) au BufNewFile,BufRead *.m2,*.DEF,*.mi setf modula2 @@ -1630,16 +1630,22 @@ au BufNewFile,BufRead *.sass setf sass au BufNewFile,BufRead *.sa setf sather " Scala -au BufNewFile,BufRead *.scala,*.sc setf scala +au BufNewFile,BufRead *.scala setf scala " SBT - Scala Build Tool au BufNewFile,BufRead *.sbt setf sbt +" SuperCollider +au BufNewFile,BufRead *.sc call dist#ft#FTsc() + +au BufNewFile,BufRead *.quark setf supercollider + +" scdoc +au BufNewFile,BufRead *.scd call dist#ft#FTscd() + " Scilab au BufNewFile,BufRead *.sci,*.sce setf scilab -" scdoc -au BufNewFile,BufRead *.scd setf scdoc " SCSS au BufNewFile,BufRead *.scss setf scss diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 880b99a2fa..603f9f854a 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -569,8 +569,6 @@ local extension = { sa = "sather", sbt = "sbt", scala = "scala", - sc = "scala", - scd = "scdoc", ss = "scheme", scm = "scheme", sld = "scheme", @@ -644,6 +642,7 @@ local extension = { mata = "stata", ado = "stata", stp = "stp", + quark = "supercollider", sface = "surface", svelte = "svelte", svg = "svg", @@ -830,6 +829,8 @@ local extension = { r = function() vim.fn["dist#ft#FTr"]() end, rdf = function() vim.fn["dist#ft#Redif"]() end, rules = function() vim.fn["dist#ft#FTRules"]() end, + sc = function() vim.fn["dist#ft#FTsc"]() end, + scd = function() vim.fn["dist#ft#FTscd"]() end, sh = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, shtml = function() vim.fn["dist#ft#FThtml"]() end, sql = function() vim.fn["dist#ft#SQL"]() end, diff --git a/runtime/syntax/query.lua b/runtime/syntax/query.lua new file mode 100644 index 0000000000..e24ff65360 --- /dev/null +++ b/runtime/syntax/query.lua @@ -0,0 +1,6 @@ +-- Neovim syntax file +-- Language: Tree-sitter query +-- Last Change: 2022 Apr 13 + +-- it's a lisp! +vim.cmd [[ runtime! syntax/lisp.vim ]] diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 482bf69f67..cbfe6e3789 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5774,26 +5774,44 @@ static void ex_delcommand(exarg_T *eap) /// Split a string by unescaped whitespace (space & tab), used for f-args on Lua commands callback. /// Similar to uc_split_args(), but does not allocate, add quotes, add commas and is an iterator. /// -/// @note If no separator is found start = 0 and end = length - 1 -/// @param[in] arg String to split -/// @param[in] iter Iteration counter -/// @param[out] start Start of the split -/// @param[out] end End of the split -/// @param[in] length Length of the string +/// @param[in] arg String to split +/// @param[in] arglen Length of {arg} +/// @param[inout] end Index of last character of previous iteration +/// @param[out] buf Buffer to copy string into +/// @param[out] len Length of string in {buf} /// -/// @return false if it's the last split (don't call again), true otherwise (call again). -bool uc_split_args_iter(const char_u *arg, int iter, int *start, int *end, int length) -{ - int pos; - *start = *end + (iter > 1 ? 2 : 0); // Skip whitespace after the first split - for (pos = *start; pos < length - 2; pos++) { - if (arg[pos] != '\\' && ascii_iswhite(arg[pos + 1])) { - *end = pos; - return true; +/// @return true if iteration is complete, else false +bool uc_split_args_iter(const char_u *arg, size_t arglen, size_t *end, char *buf, size_t *len) +{ + if (!arglen) { + return true; + } + + size_t pos = *end; + while (pos < arglen && ascii_iswhite(arg[pos])) { + pos++; + } + + size_t l = 0; + for (; pos < arglen - 1; pos++) { + if (arg[pos] == '\\' && (arg[pos + 1] == '\\' || ascii_iswhite(arg[pos + 1]))) { + buf[l++] = arg[++pos]; + } else { + buf[l++] = arg[pos]; + if (ascii_iswhite(arg[pos + 1])) { + *end = pos + 1; + *len = l; + return false; + } } } - *end = length - 1; - return false; + + if (pos < arglen && !ascii_iswhite(arg[pos])) { + buf[l++] = arg[pos]; + } + + *len = l; + return true; } /// split and quote args for <f-args> diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 21625854fb..81396f1715 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1869,17 +1869,21 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) } else { // Commands with more than one possible argument we split lua_pop(lstate, 1); // Pop the reference of opts.args - int length = (int)STRLEN(eap->arg); - int start = 0; - int end = 0; + size_t length = STRLEN(eap->arg); + size_t end = 0; + size_t len = 0; int i = 1; - bool res = true; - while (res) { - res = uc_split_args_iter(eap->arg, i, &start, &end, length); - lua_pushlstring(lstate, (const char *)eap->arg + start, (size_t)(end - start + 1)); - lua_rawseti(lstate, -2, i); - i++; + char *buf = xcalloc(length, sizeof(char)); + bool done = false; + while (!done) { + done = uc_split_args_iter(eap->arg, length, &end, buf, &len); + if (len > 0) { + lua_pushlstring(lstate, buf, len); + lua_rawseti(lstate, -2, i); + i++; + } } + xfree(buf); } lua_setfield(lstate, -2, "fargs"); diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index aeb6e12ead..197a9edb76 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -463,12 +463,11 @@ let s:filename_checks = { \ 'sass': ['file.sass'], \ 'sather': ['file.sa'], \ 'sbt': ['file.sbt'], - \ 'scala': ['file.scala', 'file.sc'], + \ 'scala': ['file.scala'], \ 'scheme': ['file.scm', 'file.ss', 'file.sld', 'file.rkt', 'file.rktd', 'file.rktl'], \ 'scilab': ['file.sci', 'file.sce'], \ 'screen': ['.screenrc', 'screenrc'], \ 'sexplib': ['file.sexp'], - \ 'scdoc': ['file.scd'], \ 'scss': ['file.scss'], \ 'sd': ['file.sd'], \ 'sdc': ['file.sdc'], @@ -516,6 +515,7 @@ let s:filename_checks = { \ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'], \ 'stp': ['file.stp'], \ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'], + \ 'supercollider': ['file.quark'], \ 'surface': ['file.sface'], \ 'svg': ['file.svg'], \ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'], @@ -1470,6 +1470,54 @@ func Test_prg_file() filetype off endfunc +" Test dist#ft#FTsc() +func Test_sc_file() + filetype on + + " SC file mehtods are defined 'Class : Method' + call writefile(['SCNvimDocRenderer : SCDocHTMLRenderer {'], 'srcfile.sc') + split srcfile.sc + call assert_equal('supercollider', &filetype) + bwipe! + call delete('srcfile.sc') + + " SC classes are defined with '+ Class {}' + call writefile(['+ SCNvim {', '*methodArgs {|method|'], 'srcfile.sc') + split srcfile.sc + call assert_equal('supercollider', &filetype) + bwipe! + call delete('srcfile.sc') + + " Some SC class files start with comment and define methods many lines later + call writefile(['// Query', '//Method','^this {'], 'srcfile.sc') + split srcfile.sc + call assert_equal('supercollider', &filetype) + bwipe! + call delete('srcfile.sc') + + " Some SC class files put comments between method declaration after class + call writefile(['PingPong {', '//comment','*ar { arg'], 'srcfile.sc') + split srcfile.sc + call assert_equal('supercollider', &filetype) + bwipe! + call delete('srcfile.sc') + + filetype off +endfunc + +" Test dist#ft#FTscd() +func Test_scd_file() + filetype on + + call writefile(['ijq(1)'], 'srcfile.scd') + split srcfile.scd + call assert_equal('scdoc', &filetype) + bwipe! + call delete('srcfile.scd') + + filetype off +endfunc + func Test_src_file() filetype on diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index ad162473ec..e4963e8a65 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -114,8 +114,8 @@ describe('nvim_create_user_command', function() ]] eq({ - args = [[hello my\ friend how\ are\ you?]], - fargs = {[[hello]], [[my\ friend]], [[how\ are\ you?]]}, + args = [[this is a\ test]], + fargs = {"this", "is", "a test"}, bang = false, line1 = 1, line2 = 1, @@ -124,12 +124,42 @@ describe('nvim_create_user_command', function() count = 2, reg = "", }, exec_lua [=[ - vim.api.nvim_command([[CommandWithLuaCallback hello my\ friend how\ are\ you?]]) + vim.api.nvim_command([[CommandWithLuaCallback this is a\ test]]) return result ]=]) eq({ - args = 'h\tey', + args = [[this includes\ a backslash: \\]], + fargs = {"this", "includes a", "backslash:", "\\"}, + bang = false, + line1 = 1, + line2 = 1, + mods = "", + range = 0, + count = 2, + reg = "", + }, exec_lua [=[ + vim.api.nvim_command([[CommandWithLuaCallback this includes\ a backslash: \\]]) + return result + ]=]) + + eq({ + args = "a\\b", + fargs = {"a\\b"}, + bang = false, + line1 = 1, + line2 = 1, + mods = "", + range = 0, + count = 2, + reg = "", + }, exec_lua [=[ + vim.api.nvim_command('CommandWithLuaCallback a\\b') + return result + ]=]) + + eq({ + args = 'h\tey ', fargs = {[[h]], [[ey]]}, bang = true, line1 = 10, @@ -139,7 +169,7 @@ describe('nvim_create_user_command', function() count = 10, reg = "", }, exec_lua [=[ - vim.api.nvim_command('botright 10CommandWithLuaCallback! h\tey') + vim.api.nvim_command('botright 10CommandWithLuaCallback! h\tey ') return result ]=]) @@ -160,7 +190,7 @@ describe('nvim_create_user_command', function() eq({ args = "", - fargs = {""}, -- fargs works without args + fargs = {}, -- fargs works without args bang = false, line1 = 1, line2 = 1, @@ -186,8 +216,8 @@ describe('nvim_create_user_command', function() ]] eq({ - args = "hello I'm one argmuent", - fargs = {"hello I'm one argmuent"}, -- Doesn't split args + args = "hello I'm one argument", + fargs = {"hello I'm one argument"}, -- Doesn't split args bang = false, line1 = 1, line2 = 1, @@ -196,7 +226,7 @@ describe('nvim_create_user_command', function() count = 2, reg = "", }, exec_lua [[ - vim.api.nvim_command('CommandWithOneArg hello I\'m one argmuent') + vim.api.nvim_command('CommandWithOneArg hello I\'m one argument') return result ]]) |