aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/linux.yml6
-rwxr-xr-xci/install.sh6
-rw-r--r--runtime/autoload/health/provider.vim2
-rw-r--r--runtime/autoload/man.vim11
-rw-r--r--runtime/autoload/xmlformat.vim164
-rw-r--r--runtime/compiler/xmllint.vim18
-rw-r--r--runtime/doc/options.txt1
-rw-r--r--runtime/doc/treesitter.txt13
-rw-r--r--runtime/filetype.vim15
-rw-r--r--runtime/indent/xml.vim15
-rw-r--r--runtime/lua/vim/treesitter.lua141
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua239
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua454
-rw-r--r--runtime/syntax/gitconfig.vim12
-rw-r--r--runtime/syntax/xml.vim43
-rw-r--r--src/nvim/buffer.c4
-rw-r--r--src/nvim/eval.c3
-rw-r--r--src/nvim/ex_cmds.c7
-rw-r--r--src/nvim/ex_cmds2.c32
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/fold.c9
-rw-r--r--src/nvim/hardcopy.c2
-rw-r--r--src/nvim/indent.c3
-rw-r--r--src/nvim/lua/treesitter.c170
-rw-r--r--src/nvim/ops.c4
-rw-r--r--src/nvim/option.c80
-rw-r--r--src/nvim/path.c8
-rw-r--r--src/nvim/po/af.po4
-rw-r--r--src/nvim/po/ca.po4
-rw-r--r--src/nvim/po/cs.cp1250.po4
-rw-r--r--src/nvim/po/cs.po4
-rw-r--r--src/nvim/po/da.po3
-rw-r--r--src/nvim/po/de.po6
-rw-r--r--src/nvim/po/en_GB.po4
-rw-r--r--src/nvim/po/eo.po3
-rw-r--r--src/nvim/po/es.po4
-rw-r--r--src/nvim/po/fi.po4
-rw-r--r--src/nvim/po/fr.po6
-rw-r--r--src/nvim/po/ga.po3
-rw-r--r--src/nvim/po/it.po4
-rw-r--r--src/nvim/po/ja.euc-jp.po3
-rw-r--r--src/nvim/po/ja.po3
-rw-r--r--src/nvim/po/ko.UTF-8.po4
-rw-r--r--src/nvim/po/nb.po4
-rw-r--r--src/nvim/po/nl.po4
-rw-r--r--src/nvim/po/no.po4
-rw-r--r--src/nvim/po/pl.UTF-8.po4
-rw-r--r--src/nvim/po/pt_BR.po4
-rw-r--r--src/nvim/po/ru.po4
-rw-r--r--src/nvim/po/sk.cp1250.po4
-rw-r--r--src/nvim/po/sk.po4
-rw-r--r--src/nvim/po/sr.po13
-rw-r--r--src/nvim/po/sv.po4
-rw-r--r--src/nvim/po/uk.po4
-rw-r--r--src/nvim/po/vi.po4
-rw-r--r--src/nvim/po/zh_CN.UTF-8.po4
-rw-r--r--src/nvim/po/zh_TW.UTF-8.po8
-rw-r--r--src/nvim/quickfix.c10
-rw-r--r--src/nvim/screen.c9
-rw-r--r--src/nvim/search.c62
-rw-r--r--src/nvim/testdir/test_filetype.vim2
-rw-r--r--src/nvim/testdir/test_highlight.vim2
-rw-r--r--src/nvim/testdir/test_quickfix.vim35
-rw-r--r--src/nvim/testdir/test_startup.vim21
-rw-r--r--src/nvim/testdir/test_system.vim54
-rw-r--r--test/functional/lua/treesitter_spec.lua678
-rw-r--r--test/functional/ui/fold_spec.lua27
-rw-r--r--test/helpers.lua5
68 files changed, 1632 insertions, 869 deletions
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index d693f5e593..b8a8c01137 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -4,7 +4,7 @@ on: [push, pull_request]
jobs:
linux:
name: ${{ matrix.flavor }} (cc=${{ matrix.cc }})
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
strategy:
matrix:
include:
@@ -26,12 +26,12 @@ jobs:
if: matrix.flavor == 'asan' || matrix.flavor == 'tsan'
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
- sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main'
+ sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-11 main'
- name: Install apt packages
run: |
sudo apt-get update
- sudo apt-get install -y autoconf automake build-essential ccache cmake cpanminus cscope gcc-multilib gdb gettext gperf language-pack-tr libtool-bin locales ninja-build pkg-config python python-pip python-setuptools python3 python3-pip python3-setuptools unzip valgrind xclip
+ sudo apt-get install -y autoconf automake build-essential ccache cmake cpanminus cscope gcc-multilib gdb gettext gperf language-pack-tr libtool-bin locales ninja-build pkg-config python3 python3-pip python3-setuptools unzip valgrind xclip
- name: Install new clang
if: matrix.flavor == 'asan' || matrix.flavor == 'tsan'
diff --git a/ci/install.sh b/ci/install.sh
index ebbd820d9f..1edc1138ee 100755
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -15,8 +15,10 @@ fi
# Use default CC to avoid compilation problems when installing Python modules.
echo "Install neovim module for Python 3."
CC=cc python3 -m pip -q install --user --upgrade pynvim
-echo "Install neovim module for Python 2."
-CC=cc python2 -m pip -q install --user --upgrade pynvim
+if python2 -m pip -c True 2>&1; then
+ echo "Install neovim module for Python 2."
+ CC=cc python2 -m pip -q install --user --upgrade pynvim
+fi
echo "Install neovim RubyGem."
gem install --no-document --bindir "$HOME/.local/bin" --user-install --pre neovim
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index 94fd7cf505..112dd4354f 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -487,7 +487,7 @@ endfunction
" Resolves Python executable path by invoking and checking `sys.executable`.
function! s:python_exepath(invocation) abort
- return s:normalize_path(system(a:invocation
+ return s:normalize_path(system(fnameescape(a:invocation)
\ . ' -c "import sys; sys.stdout.write(sys.executable)"'))
endfunction
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
index dab88fde23..486ed99e3f 100644
--- a/runtime/autoload/man.vim
+++ b/runtime/autoload/man.vim
@@ -13,8 +13,6 @@ function! man#init() abort
try
" Check for -l support.
call s:get_page(s:get_path('', 'man'))
- catch /E145:/
- " Ignore the error in restricted mode
catch /command error .*/
let s:localfile_arg = v:false
endtry
@@ -436,8 +434,11 @@ function! man#goto_tag(pattern, flags, info) abort
let l:structured = []
for l:path in l:paths
- let l:n = s:extract_sect_and_name_path(l:path)[1]
- let l:structured += [{ 'name': l:n, 'path': l:path }]
+ let [l:sect, l:name] = s:extract_sect_and_name_path(l:path)
+ let l:structured += [{
+ \ 'name': l:name,
+ \ 'title': l:name . '(' . l:sect . ')'
+ \ }]
endfor
if &cscopetag
@@ -448,7 +449,7 @@ function! man#goto_tag(pattern, flags, info) abort
return map(l:structured, {
\ _, entry -> {
\ 'name': entry.name,
- \ 'filename': 'man://' . entry.path,
+ \ 'filename': 'man://' . entry.title,
\ 'cmd': '1'
\ }
\ })
diff --git a/runtime/autoload/xmlformat.vim b/runtime/autoload/xmlformat.vim
index ea89401977..712e6f7351 100644
--- a/runtime/autoload/xmlformat.vim
+++ b/runtime/autoload/xmlformat.vim
@@ -1,6 +1,6 @@
" Vim plugin for formatting XML
-" Last Change: Thu, 07 Dec 2018
-" Version: 0.1
+" Last Change: 2020 Jan 06
+" Version: 0.3
" Author: Christian Brabandt <cb@256bit.org>
" Repository: https://github.com/chrisbra/vim-xml-ftplugin
" License: VIM License
@@ -15,51 +15,92 @@ let s:keepcpo = &cpo
set cpo&vim
" Main function: Format the input {{{1
-func! xmlformat#Format()
+func! xmlformat#Format() abort
" only allow reformatting through the gq command
" (e.g. Vim is in normal mode)
if mode() != 'n'
" do not fall back to internal formatting
return 0
endif
+ let count_orig = v:count
let sw = shiftwidth()
let prev = prevnonblank(v:lnum-1)
let s:indent = indent(prev)/sw
let result = []
let lastitem = prev ? getline(prev) : ''
let is_xml_decl = 0
- " split on `<`, but don't split on very first opening <
- for item in split(join(getline(v:lnum, (v:lnum + v:count - 1))), '.\@<=[>]\zs')
- if s:EndTag(item)
- let s:indent = s:DecreaseIndent()
- call add(result, s:Indent(item))
- elseif s:EmptyTag(lastitem)
- call add(result, s:Indent(item))
- elseif s:StartTag(lastitem) && s:IsTag(item)
- let s:indent += 1
- call add(result, s:Indent(item))
- else
- if !s:IsTag(item)
- " Simply split on '<'
- let t=split(item, '.<\@=\zs')
- let s:indent+=1
- call add(result, s:Indent(t[0]))
- let s:indent = s:DecreaseIndent()
- call add(result, s:Indent(t[1]))
- else
+ " go through every line, but don't join all content together and join it
+ " back. We might lose empty lines
+ let list = getline(v:lnum, (v:lnum + count_orig - 1))
+ let current = 0
+ for line in list
+ " Keep empty input lines?
+ if empty(line)
+ call add(result, '')
+ continue
+ elseif line !~# '<[/]\?[^>]*>'
+ let nextmatch = match(list, '<[/]\?[^>]*>', current)
+ if nextmatch > -1
+ let line .= ' '. join(list[(current + 1):(nextmatch-1)], " ")
+ call remove(list, current+1, nextmatch-1)
+ endif
+ endif
+ " split on `>`, but don't split on very first opening <
+ " this means, items can be like ['<tag>', 'tag content</tag>']
+ for item in split(line, '.\@<=[>]\zs')
+ if s:EndTag(item)
+ call s:DecreaseIndent()
+ call add(result, s:Indent(item))
+ elseif s:EmptyTag(lastitem)
call add(result, s:Indent(item))
+ elseif s:StartTag(lastitem) && s:IsTag(item)
+ let s:indent += 1
+ call add(result, s:Indent(item))
+ else
+ if !s:IsTag(item)
+ " Simply split on '<', if there is one,
+ " but reformat according to &textwidth
+ let t=split(item, '.<\@=\zs')
+
+ " if the content fits well within a single line, add it there
+ " so that the output looks like this:
+ "
+ " <foobar>1</foobar>
+ if s:TagContent(lastitem) is# s:TagContent(t[1]) && strlen(result[-1]) + strlen(item) <= s:Textwidth()
+ let result[-1] .= item
+ let lastitem = t[1]
+ continue
+ endif
+ " t should only contain 2 items, but just be safe here
+ if s:IsTag(lastitem)
+ let s:indent+=1
+ endif
+ let result+=s:FormatContent([t[0]])
+ if s:EndTag(t[1])
+ call s:DecreaseIndent()
+ endif
+ "for y in t[1:]
+ let result+=s:FormatContent(t[1:])
+ "endfor
+ else
+ call add(result, s:Indent(item))
+ endif
endif
- endif
- let lastitem = item
- endfor
+ let lastitem = item
+ endfor
+ let current += 1
+ endfor
- if !empty(result)
- exe v:lnum. ",". (v:lnum + v:count - 1). 'd'
+ if !empty(result)
+ let lastprevline = getline(v:lnum + count_orig)
+ let delete_lastline = v:lnum + count_orig - 1 == line('$')
+ exe v:lnum. ",". (v:lnum + count_orig - 1). 'd'
call append(v:lnum - 1, result)
" Might need to remove the last line, if it became empty because of the
" append() call
let last = v:lnum + len(result)
- if getline(last) is ''
+ " do not use empty(), it returns true for `empty(0)`
+ if getline(last) is '' && lastprevline is '' && delete_lastline
exe last. 'd'
endif
endif
@@ -68,15 +109,15 @@ func! xmlformat#Format()
return 0
endfunc
" Check if given tag is XML Declaration header {{{1
-func! s:IsXMLDecl(tag)
+func! s:IsXMLDecl(tag) abort
return a:tag =~? '^\s*<?xml\s\?\%(version="[^"]*"\)\?\s\?\%(encoding="[^"]*"\)\? ?>\s*$'
endfunc
" Return tag indented by current level {{{1
-func! s:Indent(item)
+func! s:Indent(item) abort
return repeat(' ', shiftwidth()*s:indent). s:Trim(a:item)
endfu
" Return item trimmed from leading whitespace {{{1
-func! s:Trim(item)
+func! s:Trim(item) abort
if exists('*trim')
return trim(a:item)
else
@@ -84,30 +125,77 @@ func! s:Trim(item)
endif
endfunc
" Check if tag is a new opening tag <tag> {{{1
-func! s:StartTag(tag)
+func! s:StartTag(tag) abort
let is_comment = s:IsComment(a:tag)
return a:tag =~? '^\s*<[^/?]' && !is_comment
endfunc
-func! s:IsComment(tag)
+" Check if tag is a Comment start {{{1
+func! s:IsComment(tag) abort
return a:tag =~? '<!--'
endfunc
" Remove one level of indentation {{{1
-func! s:DecreaseIndent()
- return (s:indent > 0 ? s:indent - 1 : 0)
+func! s:DecreaseIndent() abort
+ let s:indent = (s:indent > 0 ? s:indent - 1 : 0)
endfunc
" Check if tag is a closing tag </tag> {{{1
-func! s:EndTag(tag)
+func! s:EndTag(tag) abort
return a:tag =~? '^\s*</'
endfunc
" Check that the tag is actually a tag and not {{{1
" something like "foobar</foobar>"
-func! s:IsTag(tag)
+func! s:IsTag(tag) abort
return s:Trim(a:tag)[0] == '<'
endfunc
" Check if tag is empty <tag/> {{{1
-func! s:EmptyTag(tag)
+func! s:EmptyTag(tag) abort
return a:tag =~ '/>\s*$'
endfunc
+func! s:TagContent(tag) abort "{{{1
+ " Return content of a tag
+ return substitute(a:tag, '^\s*<[/]\?\([^>]*\)>\s*$', '\1', '')
+endfunc
+func! s:Textwidth() abort "{{{1
+ " return textwidth (or 80 if not set)
+ return &textwidth == 0 ? 80 : &textwidth
+endfunc
+" Format input line according to textwidth {{{1
+func! s:FormatContent(list) abort
+ let result=[]
+ let limit = s:Textwidth()
+ let column=0
+ let idx = -1
+ let add_indent = 0
+ let cnt = 0
+ for item in a:list
+ for word in split(item, '\s\+\S\+\zs')
+ if match(word, '^\s\+$') > -1
+ " skip empty words
+ continue
+ endif
+ let column += strdisplaywidth(word, column)
+ if match(word, "^\\s*\n\\+\\s*$") > -1
+ call add(result, '')
+ let idx += 1
+ let column = 0
+ let add_indent = 1
+ elseif column > limit || cnt == 0
+ let add = s:Indent(s:Trim(word))
+ call add(result, add)
+ let column = strdisplaywidth(add)
+ let idx += 1
+ else
+ if add_indent
+ let result[idx] = s:Indent(s:Trim(word))
+ else
+ let result[idx] .= ' '. s:Trim(word)
+ endif
+ let add_indent = 0
+ endif
+ let cnt += 1
+ endfor
+ endfor
+ return result
+endfunc
" Restoration And Modelines: {{{1
let &cpo= s:keepcpo
unlet s:keepcpo
diff --git a/runtime/compiler/xmllint.vim b/runtime/compiler/xmllint.vim
index 96cfa55383..79d38b4d14 100644
--- a/runtime/compiler/xmllint.vim
+++ b/runtime/compiler/xmllint.vim
@@ -1,7 +1,7 @@
" Vim compiler file
-" Compiler: xmllint
+" Compiler: Libxml2 Command-Line Tool
" Maintainer: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2013 Jul 8
+" Last Change: 2020 Jul 30
if exists("current_compiler")
finish
@@ -13,14 +13,16 @@ if exists(":CompilerSet") != 2 " older Vim always used :setlocal
endif
let s:cpo_save = &cpo
-set cpo-=C
+set cpo&vim
CompilerSet makeprg=xmllint\ --valid\ --noout
-
-CompilerSet errorformat=%+E%f:%l:\ %.%#\ error\ :\ %m,
- \%+W%f:%l:\ %.%#\ warning\ :\ %m,
- \%-Z%p^,
- \%-G%.%#
+CompilerSet errorformat=%E%f:%l:\ %.%#\ error\ :\ %m,
+ \%W%f:%l:\ %.%#\ warning\ :\ %m,
+ \%-Z%p^,
+ \%C%.%#,
+ \%terror:\ %m,
+ \%tarning:\ %m,
+ \%-G%.%#
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index b83d2c4484..6c42dd6739 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5166,6 +5166,7 @@ A jump table for the options with a short description can be found at |Q_op|.
It is allowed to give an argument to the command, e.g. "csh -f".
See |option-backslash| about including spaces and backslashes.
Environment variables are expanded |:set_env|.
+
If the name of the shell contains a space, you might need to enclose
it in quotes. Example: >
:set shell=\"c:\program\ files\unix\sh.exe\"\ -f
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 58cd535e98..b6a238f158 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -59,15 +59,16 @@ shouldn't be done directly in the change callback anyway as they will be very
frequent. Rather a plugin that does any kind of analysis on a tree should use
a timer to throttle too frequent updates.
-tsparser:set_included_ranges({ranges}) *tsparser:set_included_ranges()*
- Changes the ranges the parser should consider. This is used for
- language injection. {ranges} should be of the form (all zero-based): >
+tsparser:set_included_regions({region_list}) *tsparser:set_included_regions()*
+ Changes the regions the parser should consider. This is used for
+ language injection. {region_list} should be of the form (all zero-based): >
{
- {start_node, end_node},
+ {node1, node2},
...
}
<
- NOTE: `start_node` and `end_node` are both inclusive.
+ `node1` and `node2` are both considered part of the same region and
+ will be parsed together with the parser in the same context.
Tree methods *lua-treesitter-tree*
@@ -253,7 +254,7 @@ Here is a list of built-in predicates :
`lua-match?` *ts-predicate-lua-match?*
This will match the same way than |match?| but using lua
regexes.
-
+
`contains?` *ts-predicate-contains?*
Will check if any of the following arguments appears in the
text corresponding to the node : >
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 4e617052a9..4e54bcaefd 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -692,12 +692,21 @@ au BufNewFile,BufRead .gtkrc,gtkrc setf gtkrc
au BufNewFile,BufRead *.haml setf haml
" Hamster Classic | Playground files
-au BufNewFile,BufRead *.hsc,*.hsm setf hamster
+au BufNewFile,BufRead *.hsm setf hamster
+au BufNewFile,BufRead *.hsc
+ \ if match(join(getline(1,10), "\n"), '\%(^\|\n\)\s*\%({-#\_s*LANGUAGE\>\|\<module\>\)') != -1 |
+ \ setf haskell |
+ \ else |
+ \ setf hamster |
+ \ endif
" Haskell
au BufNewFile,BufRead *.hs,*.hs-boot setf haskell
au BufNewFile,BufRead *.lhs setf lhaskell
au BufNewFile,BufRead *.chs setf chaskell
+au BufNewFile,BufRead cabal.project setf cabalproject
+au BufNewFile,BufRead $HOME/.cabal/config setf cabalconfig
+au BufNewFile,BufRead cabal.config setf cabalconfig
" Haste
au BufNewFile,BufRead *.ht setf haste
@@ -2042,12 +2051,14 @@ au BufNewFile,BufRead bzr_log.* setf bzr
" Bazel build file
if !has("fname_case")
- au BufNewFile,BufRead *.BUILD,BUILD setf bzl
+ au BufNewFile,BufRead *.BUILD,BUILD setf bzl
endif
" BIND zone
au BufNewFile,BufRead */named/db.*,*/bind/db.* call s:StarSetf('bindzone')
+au BufNewFile,BufRead cabal.project.* call s:StarSetf('cabalproject')
+
" Calendar
au BufNewFile,BufRead */.calendar/*,
\*/share/calendar/*/calendar.*,*/share/calendar/calendar.*
diff --git a/runtime/indent/xml.vim b/runtime/indent/xml.vim
index 883af98563..413a3ddb53 100644
--- a/runtime/indent/xml.vim
+++ b/runtime/indent/xml.vim
@@ -1,9 +1,10 @@
-" Language: xml
-" Repository: https://github.com/chrisbra/vim-xml-ftplugin
-" Last Changed: July 27, 2019
-" Maintainer: Christian Brabandt <cb@256bit.org>
-" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
+" Language: XML
+" Maintainer: Christian Brabandt <cb@256bit.org>
+" Repository: https://github.com/chrisbra/vim-xml-ftplugin
+" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
+" Last Changed: 2019 Dec 02
" Last Change:
+" 20191202 - Handle docbk filetype
" 20190726 - Correctly handle non-tagged data
" 20190204 - correctly handle wrap tags
" https://github.com/chrisbra/vim-xml-ftplugin/issues/5
@@ -134,7 +135,7 @@ fun! XmlIndentGet(lnum, use_syntax_check)
if syn_name_end =~ 'Comment' && syn_name_start =~ 'Comment'
return <SID>XmlIndentComment(a:lnum)
- elseif empty(syn_name_start) && empty(syn_name_end)
+ elseif empty(syn_name_start) && empty(syn_name_end) && a:use_syntax_check
" non-xml tag content: use indent from 'autoindent'
return pind + shiftwidth()
endif
@@ -148,7 +149,7 @@ endfun
func! <SID>IsXMLContinuation(line)
" Checks, whether or not the line matches a start-of-tag
- return a:line !~ '^\s*<'
+ return a:line !~ '^\s*<' && &ft is# 'xml'
endfunc
func! <SID>HasNoTagEnd(line)
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index 19ef148afc..6886f0c178 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -1,98 +1,13 @@
local a = vim.api
local query = require'vim.treesitter.query'
local language = require'vim.treesitter.language'
+local LanguageTree = require'vim.treesitter.languagetree'
-- TODO(bfredl): currently we retain parsers for the lifetime of the buffer.
-- Consider use weak references to release parser if all plugins are done with
-- it.
local parsers = {}
-local Parser = {}
-Parser.__index = Parser
-
---- Parses the buffer if needed and returns a tree.
---
--- Calling this will call the on_changedtree callbacks if the tree has changed.
---
--- @returns An up to date tree
--- @returns If the tree changed with this call, the changed ranges
-function Parser:parse()
- if self.valid then
- return self._tree_immutable
- end
- local changes
-
- self._tree, changes = self._parser:parse(self._tree, self:input_source())
-
- self._tree_immutable = self._tree:copy()
-
- self.valid = true
-
- if not vim.tbl_isempty(changes) then
- for _, cb in ipairs(self.changedtree_cbs) do
- cb(changes)
- end
- end
-
- return self._tree_immutable, changes
-end
-
-function Parser:input_source()
- return self.bufnr or self.str
-end
-
-function Parser:_on_bytes(bufnr, changed_tick,
- start_row, start_col, start_byte,
- old_row, old_col, old_byte,
- new_row, new_col, new_byte)
- local old_end_col = old_col + ((old_row == 0) and start_col or 0)
- local new_end_col = new_col + ((new_row == 0) and start_col or 0)
- self._tree:edit(start_byte,start_byte+old_byte,start_byte+new_byte,
- start_row, start_col,
- start_row+old_row, old_end_col,
- start_row+new_row, new_end_col)
- self.valid = false
-
- for _, cb in ipairs(self.bytes_cbs) do
- cb(bufnr, changed_tick,
- start_row, start_col, start_byte,
- old_row, old_col, old_byte,
- new_row, new_col, new_byte)
- end
-end
-
---- Registers callbacks for the parser
--- @param cbs An `nvim_buf_attach`-like table argument with the following keys :
--- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
--- `on_changedtree` : a callback that will be called everytime the tree has syntactical changes.
--- it will only be passed one argument, that is a table of the ranges (as node ranges) that
--- changed.
-function Parser:register_cbs(cbs)
- if not cbs then return end
-
- if cbs.on_changedtree then
- table.insert(self.changedtree_cbs, cbs.on_changedtree)
- end
-
- if cbs.on_bytes then
- table.insert(self.bytes_cbs, cbs.on_bytes)
- end
-end
-
---- Sets the included ranges for the current parser
---
--- @param ranges A table of nodes that will be used as the ranges the parser should include.
-function Parser:set_included_ranges(ranges)
- self._parser:set_included_ranges(ranges)
- -- The buffer will need to be parsed again later
- self.valid = false
-end
-
---- Gets the included ranges for the parsers
-function Parser:included_ranges()
- return self._parser:included_ranges()
-end
-
local M = vim.tbl_extend("error", query, language)
setmetatable(M, {
@@ -113,9 +28,9 @@ setmetatable(M, {
-- It is not recommended to use this, use vim.treesitter.get_parser() instead.
--
-- @param bufnr The buffer the parser will be tied to
--- @param lang The language of the parser.
--- @param id The id the parser will have
-function M._create_parser(bufnr, lang, id)
+-- @param lang The language of the parser
+-- @param opts Options to pass to the language tree
+function M._create_parser(bufnr, lang, opts)
language.require_language(lang)
if bufnr == 0 then
bufnr = a.nvim_get_current_buf()
@@ -123,25 +38,22 @@ function M._create_parser(bufnr, lang, id)
vim.fn.bufload(bufnr)
- local self = setmetatable({bufnr=bufnr, lang=lang, valid=false}, Parser)
- self._parser = vim._create_ts_parser(lang)
- self.changedtree_cbs = {}
- self.bytes_cbs = {}
- self:parse()
- -- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is
- -- using it.
+ local self = LanguageTree.new(bufnr, lang, opts)
+
local function bytes_cb(_, ...)
- return self:_on_bytes(...)
+ self:_on_bytes(...)
end
- local detach_cb = nil
- if id ~= nil then
- detach_cb = function()
- if parsers[id] == self then
- parsers[id] = nil
- end
+
+ local function detach_cb()
+ if parsers[bufnr] == self then
+ parsers[bufnr] = nil
end
end
+
a.nvim_buf_attach(self.bufnr, false, {on_bytes=bytes_cb, on_detach=detach_cb})
+
+ self:parse()
+
return self
end
@@ -152,39 +64,36 @@ end
--
-- @param bufnr The buffer the parser should be tied to
-- @param ft The filetype of this parser
--- @param buf_attach_cbs See Parser:register_cbs
+-- @param opts Options object to pass to the parser
--
-- @returns The parser
-function M.get_parser(bufnr, lang, buf_attach_cbs)
+function M.get_parser(bufnr, lang, opts)
+ opts = opts or {}
+
if bufnr == nil or bufnr == 0 then
bufnr = a.nvim_get_current_buf()
end
if lang == nil then
lang = a.nvim_buf_get_option(bufnr, "filetype")
end
- local id = tostring(bufnr)..'_'..lang
- if parsers[id] == nil then
- parsers[id] = M._create_parser(bufnr, lang, id)
+ if parsers[bufnr] == nil then
+ parsers[bufnr] = M._create_parser(bufnr, lang, opts)
end
- parsers[id]:register_cbs(buf_attach_cbs)
+ parsers[bufnr]:register_cbs(opts.buf_attach_cbs)
- return parsers[id]
+ return parsers[bufnr]
end
-function M.get_string_parser(str, lang)
+function M.get_string_parser(str, lang, opts)
vim.validate {
str = { str, 'string' },
lang = { lang, 'string' }
}
language.require_language(lang)
- local self = setmetatable({str=str, lang=lang, valid=false}, Parser)
- self._parser = vim._create_ts_parser(lang)
- self:parse()
-
- return self
+ return LanguageTree.new(str, lang, opts)
end
return M
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 6714bb6354..60db7f24cf 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -1,4 +1,5 @@
local a = vim.api
+local query = require"vim.treesitter.query"
-- support reload for quick experimentation
local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {}
@@ -6,6 +7,9 @@ TSHighlighter.__index = TSHighlighter
TSHighlighter.active = TSHighlighter.active or {}
+local TSHighlighterQuery = {}
+TSHighlighterQuery.__index = TSHighlighterQuery
+
local ns = a.nvim_create_namespace("treesitter/highlighter")
-- These are conventions defined by nvim-treesitter, though it
@@ -56,27 +60,83 @@ TSHighlighter.hl_map = {
["include"] = "Include",
}
-function TSHighlighter.new(parser, query)
+local function is_highlight_name(capture_name)
+ local firstc = string.sub(capture_name, 1, 1)
+ return firstc ~= string.lower(firstc)
+end
+
+function TSHighlighterQuery.new(lang, query_string)
+ local self = setmetatable({}, { __index = TSHighlighterQuery })
+
+ self.hl_cache = setmetatable({}, {
+ __index = function(table, capture)
+ local hl = self:get_hl_from_capture(capture)
+ rawset(table, capture, hl)
+
+ return hl
+ end
+ })
+
+ if query_string then
+ self._query = query.parse_query(lang, query_string)
+ else
+ self._query = query.get_query(lang, "highlights")
+ end
+
+ return self
+end
+
+function TSHighlighterQuery:query()
+ return self._query
+end
+
+function TSHighlighterQuery:get_hl_from_capture(capture)
+ local name = self._query.captures[capture]
+
+ if is_highlight_name(name) then
+ -- From "Normal.left" only keep "Normal"
+ return vim.split(name, '.', true)[1]
+ else
+ -- Default to false to avoid recomputing
+ local hl = TSHighlighter.hl_map[name]
+ return hl and a.nvim_get_hl_id_by_name(hl) or 0
+ end
+end
+
+function TSHighlighter.new(tree, opts)
local self = setmetatable({}, TSHighlighter)
- self.parser = parser
- parser:register_cbs {
- on_changedtree = function(...) self:on_changedtree(...) end
+ if type(tree:source()) ~= "number" then
+ error("TSHighlighter can not be used with a string parser source.")
+ end
+
+ opts = opts or {}
+ self.tree = tree
+ tree:register_cbs {
+ on_changedtree = function(...) self:on_changedtree(...) end,
+ on_bytes = function(...) self:on_bytes(...) end
}
- self:set_query(query)
+ self.bufnr = tree:source()
self.edit_count = 0
self.redraw_count = 0
self.line_count = {}
- self.root = self.parser:parse():root()
- a.nvim_buf_set_option(self.buf, "syntax", "")
-
- -- TODO(bfredl): can has multiple highlighters per buffer????
- if not TSHighlighter.active[parser.bufnr] then
- TSHighlighter.active[parser.bufnr] = {}
+ -- A map of highlight states.
+ -- This state is kept during rendering across each line update.
+ self._highlight_states = {}
+ self._queries = {}
+
+ -- Queries for a specific language can be overridden by a custom
+ -- string query... if one is not provided it will be looked up by file.
+ if opts.queries then
+ for lang, query_string in pairs(opts.queries) do
+ self._queries[lang] = TSHighlighterQuery.new(lang, query_string)
+ end
end
- TSHighlighter.active[parser.bufnr][parser.lang] = self
+ a.nvim_buf_set_option(self.bufnr, "syntax", "")
+
+ TSHighlighter.active[self.bufnr] = self
-- Tricky: if syntax hasn't been enabled, we need to reload color scheme
-- but use synload.vim rather than syntax.vim to not enable
@@ -85,119 +145,112 @@ function TSHighlighter.new(parser, query)
if vim.g.syntax_on ~= 1 then
vim.api.nvim_command("runtime! syntax/synload.vim")
end
+
+ self.tree:parse()
+
return self
end
-local function is_highlight_name(capture_name)
- local firstc = string.sub(capture_name, 1, 1)
- return firstc ~= string.lower(firstc)
+function TSHighlighter:destroy()
+ if TSHighlighter.active[self.bufnr] then
+ TSHighlighter.active[self.bufnr] = nil
+ end
end
-function TSHighlighter:get_hl_from_capture(capture)
+function TSHighlighter:get_highlight_state(tstree)
+ if not self._highlight_states[tstree] then
+ self._highlight_states[tstree] = {
+ next_row = 0,
+ iter = nil
+ }
+ end
- local name = self.query.captures[capture]
+ return self._highlight_states[tstree]
+end
- if is_highlight_name(name) then
- -- From "Normal.left" only keep "Normal"
- return vim.split(name, '.', true)[1]
- else
- -- Default to false to avoid recomputing
- local hl = TSHighlighter.hl_map[name]
- return hl and a.nvim_get_hl_id_by_name(hl) or 0
- end
+function TSHighlighter:reset_highlight_state()
+ self._highlight_states = {}
+end
+
+function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end)
+ a.nvim__buf_redraw_range(self.bufnr, start_row, start_row + new_end + 1)
end
function TSHighlighter:on_changedtree(changes)
for _, ch in ipairs(changes or {}) do
- a.nvim__buf_redraw_range(self.buf, ch[1], ch[3]+1)
+ a.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3]+1)
end
end
-function TSHighlighter:set_query(query)
- if type(query) == "string" then
- query = vim.treesitter.parse_query(self.parser.lang, query)
+function TSHighlighter:get_query(lang)
+ if not self._queries[lang] then
+ self._queries[lang] = TSHighlighterQuery.new(lang)
end
- self.query = query
+ return self._queries[lang]
+end
- self.hl_cache = setmetatable({}, {
- __index = function(table, capture)
- local hl = self:get_hl_from_capture(capture)
- rawset(table, capture, hl)
+local function on_line_impl(self, buf, line)
+ self.tree:for_each_tree(function(tstree, tree)
+ if not tstree then return end
- return hl
+ local root_node = tstree:root()
+ local root_start_row, _, root_end_row, _ = root_node:range()
+
+ -- Only worry about trees within the line range
+ if root_start_row > line or root_end_row < line then return end
+
+ local state = self:get_highlight_state(tstree)
+ local highlighter_query = self:get_query(tree:lang())
+
+ if state.iter == nil then
+ state.iter = highlighter_query:query():iter_captures(root_node, self.bufnr, line, root_end_row + 1)
end
- })
- a.nvim__buf_redraw_range(self.parser.bufnr, 0, a.nvim_buf_line_count(self.parser.bufnr))
-end
+ while line >= state.next_row do
+ local capture, node = state.iter()
-local function iter_active_tshl(buf, fn)
- for _, hl in pairs(TSHighlighter.active[buf] or {}) do
- fn(hl)
- end
-end
+ if capture == nil then break end
-local function on_line_impl(self, buf, line)
- if self.root == nil then
- return -- parser bought the farm already
- end
+ local start_row, start_col, end_row, end_col = node:range()
+ local hl = highlighter_query.hl_cache[capture]
- if self.iter == nil then
- self.iter = self.query:iter_captures(self.root,buf,line,self.botline)
- end
- while line >= self.nextrow do
- local capture, node = self.iter()
- if capture == nil then
- break
+ if hl and end_row >= line then
+ a.nvim_buf_set_extmark(buf, ns, start_row, start_col,
+ { end_line = end_row, end_col = end_col,
+ hl_group = hl,
+ ephemeral = true
+ })
+ end
+ if start_row > line then
+ state.next_row = start_row
+ end
end
- local start_row, start_col, end_row, end_col = node:range()
- local hl = self.hl_cache[capture]
- if hl and end_row >= line then
- a.nvim_buf_set_extmark(buf, ns, start_row, start_col,
- { end_line = end_row, end_col = end_col,
- hl_group = hl,
- ephemeral = true,
- })
- end
- if start_row > line then
- self.nextrow = start_row
- end
- end
+ end, true)
end
-function TSHighlighter._on_line(_, _win, buf, line, highlighter)
- -- on_line is only called when this is non-nil
- if highlighter then
- on_line_impl(highlighter, buf, line)
- else
- iter_active_tshl(buf, function(self)
- on_line_impl(self, buf, line)
- end)
- end
+function TSHighlighter._on_line(_, _win, buf, line, _)
+ local self = TSHighlighter.active[buf]
+ if not self then return end
+
+ on_line_impl(self, buf, line)
end
function TSHighlighter._on_buf(_, buf)
- iter_active_tshl(buf, function(self)
- if self then
- local tree = self.parser:parse()
- self.root = (tree and tree:root()) or nil
- end
- end)
+ local self = TSHighlighter.active[buf]
+ if self then
+ self.tree:parse()
+ end
end
-function TSHighlighter._on_win(_, _win, buf, _topline, botline)
- iter_active_tshl(buf, function(self)
- if not self then
- return false
- end
+function TSHighlighter._on_win(_, _win, buf, _topline)
+ local self = TSHighlighter.active[buf]
+ if not self then
+ return false
+ end
- self.iter = nil
- self.nextrow = 0
- self.botline = botline
- self.redraw_count = self.redraw_count + 1
- return true
- end)
+ self:reset_highlight_state()
+ self.redraw_count = self.redraw_count + 1
return true
end
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
new file mode 100644
index 0000000000..70e2ac4c62
--- /dev/null
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -0,0 +1,454 @@
+local a = vim.api
+local query = require'vim.treesitter.query'
+local language = require'vim.treesitter.language'
+
+local LanguageTree = {}
+LanguageTree.__index = LanguageTree
+
+-- Represents a single treesitter parser for a language.
+-- The language can contain child languages with in it's range,
+-- hence the tree.
+--
+-- @param source Can be a bufnr or a string of text to parse
+-- @param lang The language this tree represents
+-- @param opts Options table
+-- @param opts.queries A table of language to injection query strings
+-- This is useful for overridding the built in runtime file
+-- searching for the injection language query per language.
+function LanguageTree.new(source, lang, opts)
+ language.require_language(lang)
+ opts = opts or {}
+
+ local custom_queries = opts.queries or {}
+ local self = setmetatable({
+ _source=source,
+ _lang=lang,
+ _children = {},
+ _regions = {},
+ _trees = {},
+ _opts = opts,
+ _injection_query = custom_queries[lang]
+ and query.parse_query(lang, custom_queries[lang])
+ or query.get_query(lang, "injections"),
+ _valid = false,
+ _parser = vim._create_ts_parser(lang),
+ _callbacks = {
+ changedtree = {},
+ bytes = {},
+ child_added = {},
+ child_removed = {}
+ },
+ }, LanguageTree)
+
+
+ return self
+end
+
+-- Invalidates this parser and all it's children
+function LanguageTree:invalidate()
+ self._valid = false
+
+ for _, child in ipairs(self._children) do
+ child:invalidate()
+ end
+end
+
+-- Returns all trees this language tree contains.
+-- Does not include child languages.
+function LanguageTree:trees()
+ return self._trees
+end
+
+-- Gets the language of this tree layer.
+function LanguageTree:lang()
+ return self._lang
+end
+
+-- Determines whether this tree is valid.
+-- If the tree is invalid, `parse()` must be called
+-- to get the an updated tree.
+function LanguageTree:is_valid()
+ return self._valid
+end
+
+-- Returns a map of language to child tree.
+function LanguageTree:children()
+ return self._children
+end
+
+-- Returns the source content of the language tree (bufnr or string).
+function LanguageTree:source()
+ return self._source
+end
+
+-- Parses all defined regions using a treesitter parser
+-- for the language this tree represents.
+-- This will run the injection query for this language to
+-- determine if any child languages should be created.
+function LanguageTree:parse()
+ if self._valid then
+ return self._trees
+ end
+
+ local parser = self._parser
+ local changes = {}
+
+ local old_trees = self._trees
+ self._trees = {}
+
+ -- If there are no ranges, set to an empty list
+ -- so the included ranges in the parser ar cleared.
+ if self._regions and #self._regions > 0 then
+ for i, ranges in ipairs(self._regions) do
+ local old_tree = old_trees[i]
+ parser:set_included_ranges(ranges)
+
+ local tree, tree_changes = parser:parse(old_tree, self._source)
+
+ table.insert(self._trees, tree)
+ vim.list_extend(changes, tree_changes)
+ end
+ else
+ local tree, tree_changes = parser:parse(old_trees[1], self._source)
+
+ table.insert(self._trees, tree)
+ vim.list_extend(changes, tree_changes)
+ end
+
+ local injections_by_lang = self:_get_injections()
+ local seen_langs = {}
+
+ for lang, injection_ranges in pairs(injections_by_lang) do
+ local child = self._children[lang]
+
+ if not child then
+ child = self:add_child(lang)
+ end
+
+ child:set_included_regions(injection_ranges)
+
+ local _, child_changes = child:parse()
+
+ -- Propagate any child changes so they are included in the
+ -- the change list for the callback.
+ if child_changes then
+ vim.list_extend(changes, child_changes)
+ end
+
+ seen_langs[lang] = true
+ end
+
+ for lang, _ in pairs(self._children) do
+ if not seen_langs[lang] then
+ self:remove_child(lang)
+ end
+ end
+
+ self._valid = true
+
+ self:_do_callback('changedtree', changes)
+ return self._trees, changes
+end
+
+-- Invokes the callback for each LanguageTree and it's children recursively
+-- @param fn The function to invoke. This is invoked with arguments (tree: LanguageTree, lang: string)
+-- @param include_self Whether to include the invoking tree in the results.
+function LanguageTree:for_each_child(fn, include_self)
+ if include_self then
+ fn(self, self._lang)
+ end
+
+ for _, child in pairs(self._children) do
+ child:for_each_child(fn, true)
+ end
+end
+
+-- Invokes the callback for each treesitter trees recursively.
+-- Note, this includes the invoking language tree's trees as well.
+-- @param fn The callback to invoke. The callback is invoked with arguments
+-- (tree: TSTree, languageTree: LanguageTree)
+function LanguageTree:for_each_tree(fn)
+ for _, tree in ipairs(self._trees) do
+ fn(tree, self)
+ end
+
+ for _, child in pairs(self._children) do
+ child:for_each_tree(fn)
+ end
+end
+
+-- Adds a child language to this tree.
+-- If the language already exists as a child, it will first be removed.
+-- @param lang The language to add.
+function LanguageTree:add_child(lang)
+ if self._children[lang] then
+ self:remove_child(lang)
+ end
+
+ self._children[lang] = LanguageTree.new(self._source, lang, self._opts)
+
+ self:invalidate()
+ self:_do_callback('child_added', self._children[lang])
+
+ return self._children[lang]
+end
+
+-- Removes a child language from this tree.
+-- @param lang The language to remove.
+function LanguageTree:remove_child(lang)
+ local child = self._children[lang]
+
+ if child then
+ self._children[lang] = nil
+ child:destroy()
+ self:invalidate()
+ self:_do_callback('child_removed', child)
+ end
+end
+
+-- Destroys this language tree and all it's children.
+-- Any cleanup logic should be performed here.
+-- Note, this DOES NOT remove this tree from a parent.
+-- `remove_child` must be called on the parent to remove it.
+function LanguageTree:destroy()
+ -- Cleanup here
+ for _, child in ipairs(self._children) do
+ child:destroy()
+ end
+end
+
+-- Sets the included regions that should be parsed by this parser.
+-- A region is a set of nodes and/or ranges that will be parsed in the same context.
+--
+-- For example, `{ { node1 }, { node2} }` is two separate regions.
+-- This will be parsed by the parser in two different contexts... thus resulting
+-- in two separate trees.
+--
+-- `{ { node1, node2 } }` is a single region consisting of two nodes.
+-- This will be parsed by the parser in a single context... thus resulting
+-- in a single tree.
+--
+-- This allows for embedded languages to be parsed together across different
+-- nodes, which is useful for templating languages like ERB and EJS.
+--
+-- Note, this call invalidates the tree and requires it to be parsed again.
+--
+-- @param regions A list of regions this tree should manange and parse.
+function LanguageTree:set_included_regions(regions)
+ -- Transform the tables from 4 element long to 6 element long (with byte offset)
+ for _, region in ipairs(regions) do
+ for i, range in ipairs(region) do
+ if type(range) == "table" and #range == 4 then
+ -- TODO(vigoux): I don't think string parsers are useful for now
+ if type(self._source) == "number" then
+ local start_row, start_col, end_row, end_col = unpack(range)
+ -- Easy case, this is a buffer parser
+ -- TODO(vigoux): proper byte computation here, and account for EOL ?
+ local start_byte = a.nvim_buf_get_offset(self.bufnr, start_row) + start_col
+ local end_byte = a.nvim_buf_get_offset(self.bufnr, end_row) + end_col
+
+ region[i] = { start_row, start_col, start_byte, end_row, end_col, end_byte }
+ end
+ end
+ end
+ end
+
+ self._regions = regions
+ -- Trees are no longer valid now that we have changed regions.
+ -- TODO(vigoux,steelsojka): Look into doing this smarter so we can use some of the
+ -- old trees for incremental parsing. Currently, this only
+ -- effects injected languages.
+ self._trees = {}
+ self:invalidate()
+end
+
+-- Gets the set of included regions
+function LanguageTree:included_regions()
+ return self._regions
+end
+
+-- Gets language injection points by language.
+-- This is where most of the injection processing occurs.
+-- TODO: Allow for an offset predicate to tailor the injection range
+-- instead of using the entire nodes range.
+-- @private
+function LanguageTree:_get_injections()
+ if not self._injection_query then return {} end
+
+ local injections = {}
+
+ for tree_index, tree in ipairs(self._trees) do
+ local root_node = tree:root()
+ local start_line, _, end_line, _ = root_node:range()
+
+ for pattern, match in self._injection_query:iter_matches(root_node, self._source, start_line, end_line+1) do
+ local lang = nil
+ local injection_node = nil
+ local combined = false
+
+ -- You can specify the content and language together
+ -- using a tag with the language, for example
+ -- @javascript
+ for id, node in pairs(match) do
+ local name = self._injection_query.captures[id]
+ -- TODO add a way to offset the content passed to the parser.
+ -- Needed to shave off leading quotes and things of that nature.
+
+ -- Lang should override any other language tag
+ if name == "language" then
+ lang = query.get_node_text(node, self._source)
+ elseif name == "combined" then
+ combined = true
+ elseif name == "content" then
+ injection_node = node
+ -- Ignore any tags that start with "_"
+ -- Allows for other tags to be used in matches
+ elseif string.sub(name, 1, 1) ~= "_" then
+ if lang == nil then
+ lang = name
+ end
+
+ if not injection_node then
+ injection_node = node
+ end
+ end
+ end
+
+ -- Each tree index should be isolated from the other nodes.
+ if not injections[tree_index] then
+ injections[tree_index] = {}
+ end
+
+ if not injections[tree_index][lang] then
+ injections[tree_index][lang] = {}
+ end
+
+ -- Key by pattern so we can either combine each node to parse in the same
+ -- context or treat each node independently.
+ if not injections[tree_index][lang][pattern] then
+ injections[tree_index][lang][pattern] = { combined = combined, nodes = {} }
+ end
+
+ table.insert(injections[tree_index][lang][pattern].nodes, injection_node)
+ end
+ end
+
+ local result = {}
+
+ -- Generate a map by lang of node lists.
+ -- Each list is a set of ranges that should be parsed
+ -- together.
+ for _, lang_map in ipairs(injections) do
+ for lang, patterns in pairs(lang_map) do
+ if not result[lang] then
+ result[lang] = {}
+ end
+
+ for _, entry in pairs(patterns) do
+ if entry.combined then
+ table.insert(result[lang], entry.nodes)
+ else
+ for _, node in ipairs(entry.nodes) do
+ table.insert(result[lang], {node})
+ end
+ end
+ end
+ end
+ end
+
+ return result
+end
+
+function LanguageTree:_do_callback(cb_name, ...)
+ for _, cb in ipairs(self._callbacks[cb_name]) do
+ cb(...)
+ end
+end
+
+function LanguageTree:_on_bytes(bufnr, changed_tick,
+ start_row, start_col, start_byte,
+ old_row, old_col, old_byte,
+ new_row, new_col, new_byte)
+ self:invalidate()
+
+ local old_end_col = old_col + ((old_row == 0) and start_col or 0)
+ local new_end_col = new_col + ((new_row == 0) and start_col or 0)
+
+ -- Edit all trees recursively, together BEFORE emitting a bytes callback.
+ -- In most cases this callback should only be called from the root tree.
+ self:for_each_tree(function(tree)
+ tree:edit(start_byte,start_byte+old_byte,start_byte+new_byte,
+ start_row, start_col,
+ start_row+old_row, old_end_col,
+ start_row+new_row, new_end_col)
+ end)
+
+ self:_do_callback('bytes', bufnr, changed_tick,
+ start_row, start_col, start_byte,
+ old_row, old_col, old_byte,
+ new_row, new_col, new_byte)
+end
+
+--- Registers callbacks for the parser
+-- @param cbs An `nvim_buf_attach`-like table argument with the following keys :
+-- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
+-- `on_changedtree` : a callback that will be called everytime the tree has syntactical changes.
+-- it will only be passed one argument, that is a table of the ranges (as node ranges) that
+-- changed.
+-- `on_child_added` : emitted when a child is added to the tree.
+-- `on_child_removed` : emitted when a child is remvoed from the tree.
+function LanguageTree:register_cbs(cbs)
+ if not cbs then return end
+
+ if cbs.on_changedtree then
+ table.insert(self._callbacks.changedtree, cbs.on_changedtree)
+ end
+
+ if cbs.on_bytes then
+ table.insert(self._callbacks.bytes, cbs.on_bytes)
+ end
+
+ if cbs.on_child_added then
+ table.insert(self._callbacks.child_added, cbs.on_child_added)
+ end
+
+ if cbs.on_child_removed then
+ table.insert(self._callbacks.child_removed, cbs.on_child_removed)
+ end
+end
+
+local function region_contains(region, range)
+ for _, node in ipairs(region) do
+ local start_row, start_col, end_row, end_col = node:range()
+ local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2])
+ local end_fits = end_row > range[3] or (end_row == range[3] and end_col >= range[4])
+
+ if start_fits and end_fits then
+ return true
+ end
+ end
+
+ return false
+end
+
+function LanguageTree:contains(range)
+ for _, region in pairs(self._region) do
+ if region_contains(region, range) then
+ return true
+ end
+ end
+
+ return false
+end
+
+function LanguageTree:language_for_range(range)
+ for _, child in pairs(self._children) do
+ if child:contains(range) then
+ return child:node_for_range(range)
+ end
+ end
+
+ return self
+end
+
+return LanguageTree
diff --git a/runtime/syntax/gitconfig.vim b/runtime/syntax/gitconfig.vim
index c6c56f77b6..e5eaf10f94 100644
--- a/runtime/syntax/gitconfig.vim
+++ b/runtime/syntax/gitconfig.vim
@@ -2,24 +2,22 @@
" Language: git config file
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" Filenames: gitconfig, .gitconfig, *.git/config
-" Last Change: 2010 May 21
+" Last Change: 2019 Dec 05
if exists("b:current_syntax")
finish
endif
-setlocal iskeyword+=-
-setlocal iskeyword-=_
syn case ignore
syn sync minlines=10
-syn match gitconfigComment "[#;].*"
+syn match gitconfigComment "[#;].*" contains=@Spell
syn match gitconfigSection "\%(^\s*\)\@<=\[[a-z0-9.-]\+\]"
syn match gitconfigSection '\%(^\s*\)\@<=\[[a-z0-9.-]\+ \+\"\%([^\\"]\|\\.\)*"\]'
-syn match gitconfigVariable "\%(^\s*\)\@<=\a\k*\%(\s*\%([=#;]\|$\)\)\@=" nextgroup=gitconfigAssignment skipwhite
+syn match gitconfigVariable "\%(^\s*\)\@<=\a[a-z0-9-]*\%(\s*\%([=#;]\|$\)\)\@=" nextgroup=gitconfigAssignment skipwhite
syn region gitconfigAssignment matchgroup=gitconfigNone start=+=\s*+ skip=+\\+ end=+\s*$+ contained contains=gitconfigBoolean,gitconfigNumber,gitConfigString,gitConfigEscape,gitConfigError,gitconfigComment keepend
syn keyword gitconfigBoolean true false yes no contained
-syn match gitconfigNumber "\d\+" contained
+syn match gitconfigNumber "\<\d\+\>" contained
syn region gitconfigString matchgroup=gitconfigDelim start=+"+ skip=+\\+ end=+"+ matchgroup=gitconfigError end=+[^\\"]\%#\@!$+ contained contains=gitconfigEscape,gitconfigEscapeError
syn match gitconfigError +\\.+ contained
syn match gitconfigEscape +\\[\\"ntb]+ contained
@@ -32,7 +30,7 @@ hi def link gitconfigBoolean Boolean
hi def link gitconfigNumber Number
hi def link gitconfigString String
hi def link gitconfigDelim Delimiter
-hi def link gitconfigEscape Delimiter
+hi def link gitconfigEscape Special
hi def link gitconfigError Error
let b:current_syntax = "gitconfig"
diff --git a/runtime/syntax/xml.vim b/runtime/syntax/xml.vim
index 7b503abf49..7c9791a7cc 100644
--- a/runtime/syntax/xml.vim
+++ b/runtime/syntax/xml.vim
@@ -1,11 +1,15 @@
" Vim syntax file
-" Language: XML
-" Maintainer: Johannes Zellner <johannes@zellner.org>
-" Author and previous maintainer:
-" Paul Siegmann <pauls@euronet.nl>
-" Last Change: 2013 Jun 07
+" Language: XML
+" Maintainer: Christian Brabandt <cb@256bit.org>
+" Repository: https://github.com/chrisbra/vim-xml-ftplugin
+" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
+" Author: Paul Siegmann <pauls@euronet.nl>
+" Last Changed: Nov 03, 2019
" Filenames: *.xml
-" $Id: xml.vim,v 1.3 2006/04/11 21:32:00 vimboss Exp $
+" Last Change:
+" 20190923 - Fix xmlEndTag to match xmlTag (vim/vim#884)
+" 20190924 - Fix xmlAttribute property (amadeus/vim-xml@d8ce1c946)
+" 20191103 - Enable spell checking globally
" CONFIGURATION:
" syntax folding can be turned on by
@@ -49,6 +53,12 @@ set cpo&vim
syn case match
+" Allow spell checking in tag values,
+" there is no syntax region for that,
+" so enable spell checking in top-level elements
+" <tag>This text is spell checked</tag>
+syn spell toplevel
+
" mark illegal characters
syn match xmlError "[<&]"
@@ -81,7 +91,7 @@ syn match xmlEqual +=+ display
" ^^^^^^^^^^^^^
"
syn match xmlAttrib
- \ +[-'"<]\@1<!\<[a-zA-Z:_][-.0-9a-zA-Z:_]*\>\%(['">]\@!\|$\)+
+ \ +[-'"<]\@1<!\<[a-zA-Z:_][-.0-9a-zA-Z:_]*\>\%(['"]\@!\|$\)+
\ contained
\ contains=xmlAttribPunct,@xmlAttribHook
\ display
@@ -122,7 +132,7 @@ endif
" ^^^
"
syn match xmlTagName
- \ +<\@1<=[^ /!?<>"']\++
+ \ +\%(<\|</\)\@2<=[^ /!?<>"']\++
\ contained
\ contains=xmlNamespace,xmlAttribPunct,@xmlTagHook
\ display
@@ -157,11 +167,11 @@ if exists('g:xml_syntax_folding')
" </tag>
" ^^^^^^
"
- syn match xmlEndTag
- \ +</[^ /!?<>"']\+>+
+ syn region xmlEndTag
+ \ matchgroup=xmlTag start=+</[^ /!?<>"']\@=+
+ \ matchgroup=xmlTag end=+>+
\ contained
- \ contains=xmlNamespace,xmlAttribPunct,@xmlTagHook
-
+ \ contains=xmlTagName,xmlNamespace,xmlAttribPunct,@xmlTagHook
" tag elements with syntax-folding.
" NOTE: NO HIGHLIGHTING -- highlighting is done by contained elements
@@ -181,7 +191,7 @@ if exists('g:xml_syntax_folding')
\ start=+<\z([^ /!?<>"']\+\)+
\ skip=+<!--\_.\{-}-->+
\ end=+</\z1\_\s\{-}>+
- \ matchgroup=xmlEndTag end=+/>+
+ \ end=+/>+
\ fold
\ contains=xmlTag,xmlEndTag,xmlCdata,xmlRegion,xmlComment,xmlEntity,xmlProcessing,@xmlRegionHook,@Spell
\ keepend
@@ -198,9 +208,10 @@ else
\ matchgroup=xmlTag end=+>+
\ contains=xmlError,xmlTagName,xmlAttrib,xmlEqual,xmlString,@xmlStartTagHook
- syn match xmlEndTag
- \ +</[^ /!?<>"']\+>+
- \ contains=xmlNamespace,xmlAttribPunct,@xmlTagHook
+ syn region xmlEndTag
+ \ matchgroup=xmlTag start=+</[^ /!?<>"']\@=+
+ \ matchgroup=xmlTag end=+>+
+ \ contains=xmlTagName,xmlNamespace,xmlAttribPunct,@xmlTagHook
endif
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 99cdde300d..ffa44c33cd 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -3198,7 +3198,7 @@ void maketitle(void)
int use_sandbox = false;
int save_called_emsg = called_emsg;
- use_sandbox = was_set_insecurely((char_u *)"titlestring", 0);
+ use_sandbox = was_set_insecurely(curwin, (char_u *)"titlestring", 0);
called_emsg = false;
build_stl_str_hl(curwin, (char_u *)buf, sizeof(buf),
p_titlestring, use_sandbox,
@@ -3309,7 +3309,7 @@ void maketitle(void)
int use_sandbox = false;
int save_called_emsg = called_emsg;
- use_sandbox = was_set_insecurely((char_u *)"iconstring", 0);
+ use_sandbox = was_set_insecurely(curwin, (char_u *)"iconstring", 0);
called_emsg = false;
build_stl_str_hl(curwin, icon_str, sizeof(buf),
p_iconstring, use_sandbox,
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 402211080b..054b788940 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1178,8 +1178,7 @@ int eval_foldexpr(char_u *arg, int *cp)
{
typval_T tv;
varnumber_T retval;
- int use_sandbox = was_set_insecurely((char_u *)"foldexpr",
- OPT_LOCAL);
+ int use_sandbox = was_set_insecurely(curwin, (char_u *)"foldexpr", OPT_LOCAL);
++emsg_off;
if (use_sandbox)
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index b8a0c3184b..d2ccbe3e6d 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1182,6 +1182,7 @@ static void do_filter(
char_u *cmd_buf;
buf_T *old_curbuf = curbuf;
int shell_flags = 0;
+ const int stmp = p_stmp;
if (*cmd == NUL) /* no filter command */
return;
@@ -1210,16 +1211,16 @@ static void do_filter(
if (do_out)
shell_flags |= kShellOptDoOut;
- if (!do_in && do_out && !p_stmp) {
+ if (!do_in && do_out && !stmp) {
// Use a pipe to fetch stdout of the command, do not use a temp file.
shell_flags |= kShellOptRead;
curwin->w_cursor.lnum = line2;
- } else if (do_in && !do_out && !p_stmp) {
+ } else if (do_in && !do_out && !stmp) {
// Use a pipe to write stdin of the command, do not use a temp file.
shell_flags |= kShellOptWrite;
curbuf->b_op_start.lnum = line1;
curbuf->b_op_end.lnum = line2;
- } else if (do_in && do_out && !p_stmp) {
+ } else if (do_in && do_out && !stmp) {
// Use a pipe to write stdin and fetch stdout of the command, do not
// use a temp file.
shell_flags |= kShellOptRead | kShellOptWrite;
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 42454b7c9a..04624be9a2 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -4232,25 +4232,29 @@ static void script_host_execute(char *name, exarg_T *eap)
static void script_host_execute_file(char *name, exarg_T *eap)
{
- uint8_t buffer[MAXPATHL];
- vim_FullName((char *)eap->arg, (char *)buffer, sizeof(buffer), false);
+ if (!eap->skip) {
+ uint8_t buffer[MAXPATHL];
+ vim_FullName((char *)eap->arg, (char *)buffer, sizeof(buffer), false);
- list_T *args = tv_list_alloc(3);
- // filename
- tv_list_append_string(args, (const char *)buffer, -1);
- // current range
- tv_list_append_number(args, (int)eap->line1);
- tv_list_append_number(args, (int)eap->line2);
- (void)eval_call_provider(name, "execute_file", args, true);
+ list_T *args = tv_list_alloc(3);
+ // filename
+ tv_list_append_string(args, (const char *)buffer, -1);
+ // current range
+ tv_list_append_number(args, (int)eap->line1);
+ tv_list_append_number(args, (int)eap->line2);
+ (void)eval_call_provider(name, "execute_file", args, true);
+ }
}
static void script_host_do_range(char *name, exarg_T *eap)
{
- list_T *args = tv_list_alloc(3);
- tv_list_append_number(args, (int)eap->line1);
- tv_list_append_number(args, (int)eap->line2);
- tv_list_append_string(args, (const char *)eap->arg, -1);
- (void)eval_call_provider(name, "do_range", args, true);
+ if (!eap->skip) {
+ list_T *args = tv_list_alloc(3);
+ tv_list_append_number(args, (int)eap->line1);
+ tv_list_append_number(args, (int)eap->line2);
+ tv_list_append_string(args, (const char *)eap->arg, -1);
+ (void)eval_call_provider(name, "do_range", args, true);
+ }
}
/// ":drop"
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index fc699e8826..d65387f83b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1873,8 +1873,6 @@ static char_u * do_one_cmd(char_u **cmdlinep,
case CMD_python3:
case CMD_pythonx:
case CMD_pyx:
- case CMD_pyxdo:
- case CMD_pyxfile:
case CMD_return:
case CMD_rightbelow:
case CMD_ruby:
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 5e28ca6538..654aa6d5ba 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -1835,10 +1835,11 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
curwin = wp;
curbuf = wp->w_buffer;
- ++emsg_silent; /* handle exceptions, but don't display errors */
- text = eval_to_string_safe(wp->w_p_fdt, NULL,
- was_set_insecurely((char_u *)"foldtext", OPT_LOCAL));
- --emsg_silent;
+ emsg_silent++; // handle exceptions, but don't display errors
+ text = eval_to_string_safe(
+ wp->w_p_fdt, NULL,
+ was_set_insecurely(wp, (char_u *)"foldtext", OPT_LOCAL));
+ emsg_silent--;
if (text == NULL || did_emsg)
got_fdt_error = TRUE;
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index 4a64cc31b1..2c954008b3 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -546,7 +546,7 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum,
curwin->w_botline = lnum + 63;
printer_page_num = pagenum;
- use_sandbox = was_set_insecurely((char_u *)"printheader", 0);
+ use_sandbox = was_set_insecurely(curwin, (char_u *)"printheader", 0);
build_stl_str_hl(curwin, tbuf, (size_t)width + IOSIZE,
p_header, use_sandbox,
' ', width, NULL, NULL);
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 9e6693afdf..fae971b3b3 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -453,7 +453,8 @@ int get_expr_indent(void)
colnr_T save_curswant;
int save_set_curswant;
int save_State;
- int use_sandbox = was_set_insecurely((char_u *)"indentexpr", OPT_LOCAL);
+ int use_sandbox = was_set_insecurely(
+ curwin, (char_u *)"indentexpr", OPT_LOCAL);
// Save and restore cursor position and curswant, in case it was changed
// * via :normal commands.
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index a9a57d386b..a640b97d3b 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -22,6 +22,13 @@
#include "nvim/memline.h"
#include "nvim/buffer.h"
+#define TS_META_PARSER "treesitter_parser"
+#define TS_META_TREE "treesitter_tree"
+#define TS_META_NODE "treesitter_node"
+#define TS_META_QUERY "treesitter_query"
+#define TS_META_QUERYCURSOR "treesitter_querycursor"
+#define TS_META_TREECURSOR "treesitter_treecursor"
+
typedef struct {
TSQueryCursor *cursor;
int predicated_match;
@@ -115,12 +122,12 @@ void tslua_init(lua_State *L)
langs = pmap_new(cstr_t)();
// type metatables
- build_meta(L, "treesitter_parser", parser_meta);
- build_meta(L, "treesitter_tree", tree_meta);
- build_meta(L, "treesitter_node", node_meta);
- build_meta(L, "treesitter_query", query_meta);
- build_meta(L, "treesitter_querycursor", querycursor_meta);
- build_meta(L, "treesitter_treecursor", treecursor_meta);
+ build_meta(L, TS_META_PARSER, parser_meta);
+ build_meta(L, TS_META_TREE, tree_meta);
+ build_meta(L, TS_META_NODE, node_meta);
+ build_meta(L, TS_META_QUERY, query_meta);
+ build_meta(L, TS_META_QUERYCURSOR, querycursor_meta);
+ build_meta(L, TS_META_TREECURSOR, treecursor_meta);
}
int tslua_has_language(lua_State *L)
@@ -132,12 +139,8 @@ int tslua_has_language(lua_State *L)
int tslua_add_language(lua_State *L)
{
- if (lua_gettop(L) < 2 || !lua_isstring(L, 1) || !lua_isstring(L, 2)) {
- return luaL_error(L, "string expected");
- }
-
- const char *path = lua_tostring(L, 1);
- const char *lang_name = lua_tostring(L, 2);
+ const char *path = luaL_checkstring(L, 1);
+ const char *lang_name = luaL_checkstring(L, 2);
if (pmap_has(cstr_t)(langs, lang_name)) {
return 0;
@@ -176,8 +179,9 @@ int tslua_add_language(lua_State *L)
|| lang_version > TREE_SITTER_LANGUAGE_VERSION) {
return luaL_error(
L,
- "ABI version mismatch : expected %d, found %d",
- TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION, lang_version);
+ "ABI version mismatch : supported between %d and %d, found %d",
+ TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION,
+ TREE_SITTER_LANGUAGE_VERSION, lang_version);
}
pmap_put(cstr_t)(langs, xstrdup(lang_name), lang);
@@ -188,10 +192,7 @@ int tslua_add_language(lua_State *L)
int tslua_inspect_lang(lua_State *L)
{
- if (lua_gettop(L) < 1 || !lua_isstring(L, 1)) {
- return luaL_error(L, "string expected");
- }
- const char *lang_name = lua_tostring(L, 1);
+ const char *lang_name = luaL_checkstring(L, 1);
TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name);
if (!lang) {
@@ -232,11 +233,9 @@ int tslua_inspect_lang(lua_State *L)
int tslua_push_parser(lua_State *L)
{
- // Gather language
- if (lua_gettop(L) < 1 || !lua_isstring(L, 1)) {
- return luaL_error(L, "string expected");
- }
- const char *lang_name = lua_tostring(L, 1);
+ // Gather language name
+ const char *lang_name = luaL_checkstring(L, 1);
+
TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name);
if (!lang) {
return luaL_error(L, "no such language: %s", lang_name);
@@ -250,14 +249,14 @@ int tslua_push_parser(lua_State *L)
return luaL_error(L, "Failed to load language : %s", lang_name);
}
- lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_parser"); // [udata, meta]
+ lua_getfield(L, LUA_REGISTRYINDEX, TS_META_PARSER); // [udata, meta]
lua_setmetatable(L, -2); // [udata]
return 1;
}
static TSParser ** parser_check(lua_State *L, uint16_t index)
{
- return luaL_checkudata(L, index, "treesitter_parser");
+ return luaL_checkudata(L, index, TS_META_PARSER);
}
static int parser_gc(lua_State *L)
@@ -388,7 +387,7 @@ static int parser_parse(lua_State *L)
TSRange *changed = old_tree ? ts_tree_get_changed_ranges(
old_tree, new_tree, &n_ranges) : NULL;
- tslua_push_tree(L, new_tree, false); // [tree]
+ push_tree(L, new_tree, false); // [tree]
push_ranges(L, changed, n_ranges); // [tree, ranges]
@@ -403,7 +402,7 @@ static int tree_copy(lua_State *L)
return 0;
}
- tslua_push_tree(L, *tree, true); // [tree]
+ push_tree(L, *tree, true); // [tree]
return 1;
}
@@ -435,6 +434,72 @@ static int tree_edit(lua_State *L)
return 0;
}
+// Use the top of the stack (without popping it) to create a TSRange, it can be
+// either a lua table or a TSNode
+static void range_from_lua(lua_State *L, TSRange *range)
+{
+ TSNode node;
+
+ if (lua_istable(L, -1)) {
+ // should be a table of 6 elements
+ if (lua_objlen(L, -1) != 6) {
+ goto error;
+ }
+
+ uint32_t start_row, start_col, start_byte, end_row, end_col, end_byte;
+ lua_rawgeti(L, -1, 1); // [ range, start_row]
+ start_row = luaL_checkinteger(L, -1);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 2); // [ range, start_col]
+ start_col = luaL_checkinteger(L, -1);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 3); // [ range, start_byte]
+ start_byte = luaL_checkinteger(L, -1);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 4); // [ range, end_row]
+ end_row = luaL_checkinteger(L, -1);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 5); // [ range, end_col]
+ end_col = luaL_checkinteger(L, -1);
+ lua_pop(L, 1);
+
+ lua_rawgeti(L, -1, 6); // [ range, end_byte]
+ end_byte = luaL_checkinteger(L, -1);
+ lua_pop(L, 1); // [ range ]
+
+ *range = (TSRange) {
+ .start_point = (TSPoint) {
+ .row = start_row,
+ .column = start_col
+ },
+ .end_point = (TSPoint) {
+ .row = end_row,
+ .column = end_col
+ },
+ .start_byte = start_byte,
+ .end_byte = end_byte,
+ };
+ } else if (node_check(L, -1, &node)) {
+ *range = (TSRange) {
+ .start_point = ts_node_start_point(node),
+ .end_point = ts_node_end_point(node),
+ .start_byte = ts_node_start_byte(node),
+ .end_byte = ts_node_end_byte(node)
+ };
+ } else {
+ goto error;
+ }
+ return;
+error:
+ luaL_error(
+ L,
+ "Ranges can only be made from 6 element long tables or nodes.");
+}
+
static int parser_set_ranges(lua_State *L)
{
if (lua_gettop(L) < 2) {
@@ -461,22 +526,8 @@ static int parser_set_ranges(lua_State *L)
// [ parser, ranges ]
for (size_t index = 0; index < tbl_len; index++) {
lua_rawgeti(L, 2, index + 1); // [ parser, ranges, range ]
-
- TSNode node;
- if (!node_check(L, -1, &node)) {
- xfree(ranges);
- return luaL_error(
- L,
- "ranges should be tables of nodes.");
- }
- lua_pop(L, 1); // [ parser, ranges ]
-
- ranges[index] = (TSRange) {
- .start_point = ts_node_start_point(node),
- .end_point = ts_node_end_point(node),
- .start_byte = ts_node_start_byte(node),
- .end_byte = ts_node_end_byte(node)
- };
+ range_from_lua(L, ranges + index);
+ lua_pop(L, 1);
}
// This memcpies ranges, thus we can free it afterwards
@@ -506,7 +557,7 @@ static int parser_get_ranges(lua_State *L)
/// push tree interface on lua stack.
///
/// This makes a copy of the tree, so ownership of the argument is unaffected.
-void tslua_push_tree(lua_State *L, TSTree *tree, bool do_copy)
+void push_tree(lua_State *L, TSTree *tree, bool do_copy)
{
if (tree == NULL) {
lua_pushnil(L);
@@ -520,7 +571,7 @@ void tslua_push_tree(lua_State *L, TSTree *tree, bool do_copy)
*ud = tree;
}
- lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_tree"); // [udata, meta]
+ lua_getfield(L, LUA_REGISTRYINDEX, TS_META_TREE); // [udata, meta]
lua_setmetatable(L, -2); // [udata]
// table used for node wrappers to keep a reference to tree wrapper
@@ -534,7 +585,7 @@ void tslua_push_tree(lua_State *L, TSTree *tree, bool do_copy)
static TSTree **tree_check(lua_State *L, uint16_t index)
{
- TSTree **ud = luaL_checkudata(L, index, "treesitter_tree");
+ TSTree **ud = luaL_checkudata(L, index, TS_META_TREE);
return ud;
}
@@ -582,7 +633,7 @@ static void push_node(lua_State *L, TSNode node, int uindex)
}
TSNode *ud = lua_newuserdata(L, sizeof(TSNode)); // [udata]
*ud = node;
- lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_node"); // [udata, meta]
+ lua_getfield(L, LUA_REGISTRYINDEX, TS_META_NODE); // [udata, meta]
lua_setmetatable(L, -2); // [udata]
lua_getfenv(L, uindex); // [udata, reftable]
lua_setfenv(L, -2); // [udata]
@@ -590,7 +641,7 @@ static void push_node(lua_State *L, TSNode node, int uindex)
static bool node_check(lua_State *L, int index, TSNode *res)
{
- TSNode *ud = luaL_checkudata(L, index, "treesitter_node");
+ TSNode *ud = luaL_checkudata(L, index, TS_META_NODE);
if (ud) {
*res = *ud;
return true;
@@ -618,13 +669,12 @@ static int node_eq(lua_State *L)
if (!node_check(L, 1, &node)) {
return 0;
}
- // This should only be called if both x and y in "x == y" has the
- // treesitter_node metatable. So it is ok to error out otherwise.
- TSNode *ud = luaL_checkudata(L, 2, "treesitter_node");
- if (!ud) {
+
+ TSNode node2;
+ if (!node_check(L, 2, &node2)) {
return 0;
}
- TSNode node2 = *ud;
+
lua_pushboolean(L, ts_node_eq(node, node2));
return 1;
}
@@ -859,7 +909,7 @@ static int node_named_descendant_for_range(lua_State *L)
static int node_next_child(lua_State *L)
{
TSTreeCursor *ud = luaL_checkudata(
- L, lua_upvalueindex(1), "treesitter_treecursor");
+ L, lua_upvalueindex(1), TS_META_TREECURSOR);
if (!ud) {
return 0;
}
@@ -909,7 +959,7 @@ static int node_iter_children(lua_State *L)
TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata]
*ud = ts_tree_cursor_new(source);
- lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_treecursor"); // [udata, mt]
+ lua_getfield(L, LUA_REGISTRYINDEX, TS_META_TREECURSOR); // [udata, mt]
lua_setmetatable(L, -2); // [udata]
lua_pushvalue(L, 1); // [udata, source_node]
lua_pushcclosure(L, node_next_child, 2);
@@ -919,7 +969,7 @@ static int node_iter_children(lua_State *L)
static int treecursor_gc(lua_State *L)
{
- TSTreeCursor *ud = luaL_checkudata(L, 1, "treesitter_treecursor");
+ TSTreeCursor *ud = luaL_checkudata(L, 1, TS_META_TREECURSOR);
ts_tree_cursor_delete(ud);
return 0;
}
@@ -1031,7 +1081,7 @@ static int node_rawquery(lua_State *L)
ud->cursor = cursor;
ud->predicated_match = -1;
- lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_querycursor");
+ lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYCURSOR);
lua_setmetatable(L, -2); // [udata]
lua_pushvalue(L, 1); // [udata, node]
@@ -1051,7 +1101,7 @@ static int node_rawquery(lua_State *L)
static int querycursor_gc(lua_State *L)
{
- TSLua_cursor *ud = luaL_checkudata(L, 1, "treesitter_querycursor");
+ TSLua_cursor *ud = luaL_checkudata(L, 1, TS_META_QUERYCURSOR);
ts_query_cursor_delete(ud->cursor);
return 0;
}
@@ -1084,7 +1134,7 @@ int ts_lua_parse_query(lua_State *L)
TSQuery **ud = lua_newuserdata(L, sizeof(TSQuery *)); // [udata]
*ud = query;
- lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_query"); // [udata, meta]
+ lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERY); // [udata, meta]
lua_setmetatable(L, -2); // [udata]
return 1;
}
@@ -1102,7 +1152,7 @@ static const char *query_err_string(TSQueryError err) {
static TSQuery *query_check(lua_State *L, int index)
{
- TSQuery **ud = luaL_checkudata(L, index, "treesitter_query");
+ TSQuery **ud = luaL_checkudata(L, index, TS_META_QUERY);
return *ud;
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 9e7d81fc82..40dd5f0b5c 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -4117,8 +4117,8 @@ fex_format(
int c /* character to be inserted */
)
{
- int use_sandbox = was_set_insecurely((char_u *)"formatexpr",
- OPT_LOCAL);
+ int use_sandbox = was_set_insecurely(
+ curwin, (char_u *)"formatexpr", OPT_LOCAL);
int r;
char_u *fex;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 0a91687352..c1b071b04e 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -652,7 +652,14 @@ void set_init_1(bool clean_arg)
{
const char *shell = os_getenv("SHELL");
if (shell != NULL) {
- set_string_default("sh", (char *) shell, false);
+ if (vim_strchr((const char_u *)shell, ' ') != NULL) {
+ const size_t len = strlen(shell) + 3; // two quotes and a trailing NUL
+ char *const cmd = xmalloc(len);
+ snprintf(cmd, len, "\"%s\"", shell);
+ set_string_default("sh", cmd, true);
+ } else {
+ set_string_default("sh", (char *)shell, false);
+ }
}
}
@@ -945,7 +952,7 @@ set_option_default(
}
// The default value is not insecure.
- uint32_t *flagsp = insecure_flag(opt_idx, opt_flags);
+ uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags);
*flagsp = *flagsp & ~P_INSECURE;
}
@@ -987,10 +994,9 @@ static void set_string_default(const char *name, char *val, bool allocated)
xfree(options[opt_idx].def_val[VI_DEFAULT]);
}
- options[opt_idx].def_val[VI_DEFAULT] = (char_u *) (
- allocated
- ? (char_u *) val
- : (char_u *) xstrdup(val));
+ options[opt_idx].def_val[VI_DEFAULT] = allocated
+ ? (char_u *)val
+ : (char_u *)xstrdup(val);
options[opt_idx].flags |= P_DEF_ALLOCED;
}
}
@@ -1880,7 +1886,7 @@ int do_set(
saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0;
{
- uint32_t *p = insecure_flag(opt_idx, opt_flags);
+ uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags);
const int secure_saved = secure;
// When an option is set in the sandbox, from a
@@ -2007,7 +2013,7 @@ static void did_set_option(
/* When an option is set in the sandbox, from a modeline or in secure mode
* set the P_INSECURE flag. Otherwise, if a new value is stored reset the
* flag. */
- uint32_t *p = insecure_flag(opt_idx, opt_flags);
+ uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags);
if (!value_checked && (secure
|| sandbox != 0
|| (opt_flags & OPT_MODELINE))) {
@@ -2346,12 +2352,12 @@ static void check_string_option(char_u **pp)
/// Return true when option "opt" was set from a modeline or in secure mode.
/// Return false when it wasn't.
/// Return -1 for an unknown option.
-int was_set_insecurely(char_u *opt, int opt_flags)
+int was_set_insecurely(win_T *const wp, char_u *opt, int opt_flags)
{
int idx = findoption((const char *)opt);
if (idx >= 0) {
- uint32_t *flagp = insecure_flag(idx, opt_flags);
+ uint32_t *flagp = insecure_flag(wp, idx, opt_flags);
return (*flagp & P_INSECURE) != 0;
}
internal_error("was_set_insecurely()");
@@ -2360,16 +2366,16 @@ int was_set_insecurely(char_u *opt, int opt_flags)
/// Get a pointer to the flags used for the P_INSECURE flag of option
/// "opt_idx". For some local options a local flags field is used.
-static uint32_t *insecure_flag(int opt_idx, int opt_flags)
+static uint32_t *insecure_flag(win_T *const wp, int opt_idx, int opt_flags)
{
if (opt_flags & OPT_LOCAL)
switch ((int)options[opt_idx].indir) {
- case PV_STL: return &curwin->w_p_stl_flags;
- case PV_FDE: return &curwin->w_p_fde_flags;
- case PV_FDT: return &curwin->w_p_fdt_flags;
- case PV_INDE: return &curbuf->b_p_inde_flags;
- case PV_FEX: return &curbuf->b_p_fex_flags;
- case PV_INEX: return &curbuf->b_p_inex_flags;
+ case PV_STL: return &wp->w_p_stl_flags;
+ case PV_FDE: return &wp->w_p_fde_flags;
+ case PV_FDT: return &wp->w_p_fdt_flags;
+ case PV_INDE: return &wp->w_buffer->b_p_inde_flags;
+ case PV_FEX: return &wp->w_buffer->b_p_fex_flags;
+ case PV_INEX: return &wp->w_buffer->b_p_inex_flags;
}
// Nothing special, return global flags field.
@@ -7173,46 +7179,6 @@ int get_sts_value(void)
return (int)result;
}
-/// Check matchpairs option for "*initc".
-/// If there is a match set "*initc" to the matching character and "*findc" to
-/// the opposite character. Set "*backwards" to the direction.
-/// When "switchit" is true swap the direction.
-void find_mps_values(int *initc, int *findc, int *backwards, int switchit)
-{
- char_u *ptr = curbuf->b_p_mps;
-
- while (*ptr != NUL) {
- if (utf_ptr2char(ptr) == *initc) {
- if (switchit) {
- *findc = *initc;
- *initc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1);
- *backwards = true;
- } else {
- *findc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1);
- *backwards = false;
- }
- return;
- }
- char_u *prev = ptr;
- ptr += utfc_ptr2len(ptr) + 1;
- if (utf_ptr2char(ptr) == *initc) {
- if (switchit) {
- *findc = *initc;
- *initc = utf_ptr2char(prev);
- *backwards = false;
- } else {
- *findc = utf_ptr2char(prev);
- *backwards = true;
- }
- return;
- }
- ptr += utfc_ptr2len(ptr);
- if (*ptr == ',') {
- ptr++;
- }
- }
-}
-
/// This is called when 'breakindentopt' is changed and when a window is
/// initialized
static bool briopt_check(win_T *wp)
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 793f917f06..f52fbbd5c8 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1610,10 +1610,10 @@ void simplify_filename(char_u *filename)
static char *eval_includeexpr(const char *const ptr, const size_t len)
{
- set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t) len);
- char *res = (char *) eval_to_string_safe(
- curbuf->b_p_inex, NULL, was_set_insecurely((char_u *)"includeexpr",
- OPT_LOCAL));
+ set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
+ char *res = (char *)eval_to_string_safe(
+ curbuf->b_p_inex, NULL,
+ was_set_insecurely(curwin, (char_u *)"includeexpr", OPT_LOCAL));
set_vim_var_string(VV_FNAME, NULL, 0);
return res;
}
diff --git a/src/nvim/po/af.po b/src/nvim/po/af.po
index 79048eac39..fa6674469c 100644
--- a/src/nvim/po/af.po
+++ b/src/nvim/po/af.po
@@ -1348,10 +1348,6 @@ msgstr "E143: Outobevele het nuwe buffer %s onverwags geskrap"
msgid "E144: non-numeric argument to :z"
msgstr "E144: nie-numeriese parameter vir :z"
-#, fuzzy
-#~ msgid "E145: Shell commands not allowed in restricted mode"
-#~ msgstr "E145: Dop bevele nie toegelaat in rvim"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Patrone kan nie deur letters afgebaken word nie"
diff --git a/src/nvim/po/ca.po b/src/nvim/po/ca.po
index 7e83cb08ed..be4206f36e 100644
--- a/src/nvim/po/ca.po
+++ b/src/nvim/po/ca.po
@@ -1234,10 +1234,6 @@ msgstr "E143: Una auto-ordre ha eliminat el buffer nou %s inesperadament"
msgid "E144: non-numeric argument to :z"
msgstr "E144: Argument no numric per a :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Les ordres shell no estan permeses en l'rvim"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Les expressions regulars no poden estar delimitades per lletres"
diff --git a/src/nvim/po/cs.cp1250.po b/src/nvim/po/cs.cp1250.po
index 26bdbe8c45..5b9f3d3a58 100644
--- a/src/nvim/po/cs.cp1250.po
+++ b/src/nvim/po/cs.cp1250.po
@@ -1249,10 +1249,6 @@ msgstr "E143: Automatick pkazy neoekvan smazaly nov buffer %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: neseln argument pro :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvim nepovoluje pouit pkaz shellu"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regulrn vrazy nesm bt oddleny psmeny"
diff --git a/src/nvim/po/cs.po b/src/nvim/po/cs.po
index 986d6753a8..31a90dc514 100644
--- a/src/nvim/po/cs.po
+++ b/src/nvim/po/cs.po
@@ -1249,10 +1249,6 @@ msgstr "E143: Automatick pkazy neoekvan smazaly nov buffer %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: neseln argument pro :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvim nepovoluje pouit pkaz shellu"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regulrn vrazy nesm bt oddleny psmeny"
diff --git a/src/nvim/po/da.po b/src/nvim/po/da.po
index 58cd19210b..f35272810b 100644
--- a/src/nvim/po/da.po
+++ b/src/nvim/po/da.po
@@ -980,9 +980,6 @@ msgstr "E143: Autokommandoer slettede uventede ny buffer %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: ikke-numerisk argument til :z"
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Skalkommandoer er ikke tilladt i rvim"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regulære udtryk kan ikke afgrænses af bogstaver"
diff --git a/src/nvim/po/de.po b/src/nvim/po/de.po
index a6ba8476d8..a2e04965e5 100644
--- a/src/nvim/po/de.po
+++ b/src/nvim/po/de.po
@@ -3,7 +3,7 @@
# Do ":help uganda" in Vim to read copying and usage conditions.
# Do ":help credits" in Vim to see a list of people who contributed.
#
-# Previous-Translator(s):
+# Previous-Translator(s):
# Johannes Zellner <johannes@zellner.org>
# Gerfried Fuchs <alfie@ist.org>
msgid ""
@@ -659,10 +659,6 @@ msgstr "E143: Autokommandos lschten unerwartet neuen Puffer %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: Nicht-numerisches Argument fr :z"
-#: ../ex_cmds.c:3398
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Shell-Befehle sind in rvim nicht erlaubt"
-
#: ../ex_cmds.c:3492
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regulre Ausdrcke knnen nicht durch Buchstaben begrenzt werden"
diff --git a/src/nvim/po/en_GB.po b/src/nvim/po/en_GB.po
index 00a05195b4..7919fc8946 100644
--- a/src/nvim/po/en_GB.po
+++ b/src/nvim/po/en_GB.po
@@ -1194,10 +1194,6 @@ msgstr ""
msgid "E144: non-numeric argument to :z"
msgstr ""
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr ""
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regular expressions cannot be delimited by letters"
diff --git a/src/nvim/po/eo.po b/src/nvim/po/eo.po
index d1ce47d97c..99c46c7275 100644
--- a/src/nvim/po/eo.po
+++ b/src/nvim/po/eo.po
@@ -969,9 +969,6 @@ msgstr "E143: Aŭtokomandoj neatendite forviŝis novan bufron %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: nenumera argumento de :z"
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Ŝelkomandoj nepermeseblaj en rvim"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Ne eblas limigi regulesprimon per literoj"
diff --git a/src/nvim/po/es.po b/src/nvim/po/es.po
index f30e8780f9..eeea27610d 100644
--- a/src/nvim/po/es.po
+++ b/src/nvim/po/es.po
@@ -1234,10 +1234,6 @@ msgstr "E143: Las auto-órdenes han eliminado al nuevo búfer %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: Argumento no numérico para \":z\""
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: No se permiten órdenes de consola en rvim"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Las expresiones regulares no se pueden delimitar con letras"
diff --git a/src/nvim/po/fi.po b/src/nvim/po/fi.po
index f568a34b3c..4489139cfb 100644
--- a/src/nvim/po/fi.po
+++ b/src/nvim/po/fi.po
@@ -1515,10 +1515,6 @@ msgstr "E143: Autocommand poisti uuden puskurin odotuksen vastaisesti %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: :z:n argumentti ei ole numero"
-#, fuzzy
-#~ msgid "E145: Shell commands not allowed in restricted mode"
-#~ msgstr "E145: Kuoren komennot eivät toimi rvimissä"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Säännöllistä ilmausta ei voi rajata kirjaimilla"
diff --git a/src/nvim/po/fr.po b/src/nvim/po/fr.po
index ea6fe302fe..bb60649c91 100644
--- a/src/nvim/po/fr.po
+++ b/src/nvim/po/fr.po
@@ -1117,12 +1117,6 @@ msgstr "E143: Une autocommande a effac le nouveau tampon %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: L'argument de :z n'est pas numrique"
-# AB - La version franaise fera peut-tre mieux passer l'amre pilule.
-# La consultation de l'aide donnera l'explication complte ceux qui
-# ne comprendraient pas quoi ce message est d.
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Les commandes externes sont indisponibles dans rvim"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr ""
"E146: Les expressions rgulires ne peuvent pas tre dlimites par des "
diff --git a/src/nvim/po/ga.po b/src/nvim/po/ga.po
index 617b805eb8..1104b31c32 100644
--- a/src/nvim/po/ga.po
+++ b/src/nvim/po/ga.po
@@ -967,9 +967,6 @@ msgstr "E143: Scrios na huathorduithe maoln nua %s go tobann"
msgid "E144: non-numeric argument to :z"
msgstr "E144: argint neamhuimhriil chun :z"
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: N cheadatear orduithe blaoisce i rvim"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr ""
"E146: N cheadatear litreacha mar theormharcir ar shloinn ionadaochta"
diff --git a/src/nvim/po/it.po b/src/nvim/po/it.po
index 9d5709e1ab..511f910b71 100644
--- a/src/nvim/po/it.po
+++ b/src/nvim/po/it.po
@@ -1220,10 +1220,6 @@ msgstr ""
msgid "E144: non-numeric argument to :z"
msgstr "E144: argomento non-numerico a :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Comandi Shell non permessi in rvim"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Le espressioni regolari non possono essere delimitate da lettere"
diff --git a/src/nvim/po/ja.euc-jp.po b/src/nvim/po/ja.euc-jp.po
index dc3c4368ab..523e9ca4e3 100644
--- a/src/nvim/po/ja.euc-jp.po
+++ b/src/nvim/po/ja.euc-jp.po
@@ -987,9 +987,6 @@ msgstr "E143: autocommandͽХåե %s ޤ"
msgid "E144: non-numeric argument to :z"
msgstr "E144: ǤϤʤ :z Ϥޤ"
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvimǤϥ륳ޥɤȤޤ"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: ɽʸǶڤ뤳ȤǤޤ"
diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po
index 4c5661464a..5a69d0c5bf 100644
--- a/src/nvim/po/ja.po
+++ b/src/nvim/po/ja.po
@@ -987,9 +987,6 @@ msgstr "E143: autocommandが予期せず新しいバッファ %s を削除しま
msgid "E144: non-numeric argument to :z"
msgstr "E144: 数ではない引数が :z に渡されました"
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvimではシェルコマンドを使えません"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: 正規表現は文字で区切ることができません"
diff --git a/src/nvim/po/ko.UTF-8.po b/src/nvim/po/ko.UTF-8.po
index e90081bcfd..128b238f8b 100644
--- a/src/nvim/po/ko.UTF-8.po
+++ b/src/nvim/po/ko.UTF-8.po
@@ -1215,10 +1215,6 @@ msgstr "E143: Autocommand가 뜻 밖에 새 버퍼 %s을(를) 지웠습니다"
msgid "E144: non-numeric argument to :z"
msgstr "E144: 숫자가 아닌 인자가 :z에 주어졌습니다"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvim에서는 쉘 명령을 사용할 수 없습니다"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: 정규표현식은 글자로 구분될 수 없습니다"
diff --git a/src/nvim/po/nb.po b/src/nvim/po/nb.po
index b99e8ce465..34617ccf18 100644
--- a/src/nvim/po/nb.po
+++ b/src/nvim/po/nb.po
@@ -1231,10 +1231,6 @@ msgstr "E143: Autokommandoer slettet uventet den nye bufferen %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: Ikke-numerisk parameter til :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Skallkommandoer er ikke tillatt i rvim"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regulre uttrykk kan ikke bli adskilt av bokstaver"
diff --git a/src/nvim/po/nl.po b/src/nvim/po/nl.po
index 56bcd94e79..30f34508f5 100644
--- a/src/nvim/po/nl.po
+++ b/src/nvim/po/nl.po
@@ -1217,10 +1217,6 @@ msgstr "E143: 'Autocommands' hebben het nieuwe buffer %s onverwacht verwijderd"
msgid "E144: non-numeric argument to :z"
msgstr "E144: niet-numeriek argument voor :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: in rvim zijn shell-opdrachten zijn niet toegestaan"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: reguliere expressies kunnen niet begrensd worden door letters"
diff --git a/src/nvim/po/no.po b/src/nvim/po/no.po
index b99e8ce465..34617ccf18 100644
--- a/src/nvim/po/no.po
+++ b/src/nvim/po/no.po
@@ -1231,10 +1231,6 @@ msgstr "E143: Autokommandoer slettet uventet den nye bufferen %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: Ikke-numerisk parameter til :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Skallkommandoer er ikke tillatt i rvim"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regulre uttrykk kan ikke bli adskilt av bokstaver"
diff --git a/src/nvim/po/pl.UTF-8.po b/src/nvim/po/pl.UTF-8.po
index a348bf6203..f5c452e924 100644
--- a/src/nvim/po/pl.UTF-8.po
+++ b/src/nvim/po/pl.UTF-8.po
@@ -1201,10 +1201,6 @@ msgstr "E143: Autokomendy nieoczekiwanie skasowały nowy bufor %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: nienumeryczny argument dla :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Komendy powłoki są niedozwolone w rvim"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Wzorce regularne nie mogą być rozgraniczane literami"
diff --git a/src/nvim/po/pt_BR.po b/src/nvim/po/pt_BR.po
index 543f0bce27..4f39cb5bdb 100644
--- a/src/nvim/po/pt_BR.po
+++ b/src/nvim/po/pt_BR.po
@@ -4210,10 +4210,6 @@ msgstr ""
msgid "E144: non-numeric argument to :z"
msgstr "E144: argumento no-numrico passado a :z"
-#: ../ex_cmds.c:3398
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Comandos do shell no so permitidos no rvim"
-
#: ../ex_cmds.c:3492
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Expresses regulares no podem ser delimitadas por letras"
diff --git a/src/nvim/po/ru.po b/src/nvim/po/ru.po
index e5be489d72..62f892d257 100644
--- a/src/nvim/po/ru.po
+++ b/src/nvim/po/ru.po
@@ -1205,10 +1205,6 @@ msgstr "E143: Автокоманды неожиданно убили новый
msgid "E144: non-numeric argument to :z"
msgstr "E144: Параметр команды :z должен быть числом"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Использование команд оболочки не допускается в rvim."
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Регулярные выражения не могут разделяться буквами"
diff --git a/src/nvim/po/sk.cp1250.po b/src/nvim/po/sk.cp1250.po
index 74b8e1039c..ced343bf6b 100644
--- a/src/nvim/po/sk.cp1250.po
+++ b/src/nvim/po/sk.cp1250.po
@@ -1219,10 +1219,6 @@ msgstr "E143: Automatick prkazy neoakvane zmazali nov buffer %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: neseln argument pre :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvim nepovouje pouitie prkazov shellu"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regulrne vrazy nesm by oddelen psmenami"
diff --git a/src/nvim/po/sk.po b/src/nvim/po/sk.po
index d3f954f6d8..66b3d5abb1 100644
--- a/src/nvim/po/sk.po
+++ b/src/nvim/po/sk.po
@@ -1219,10 +1219,6 @@ msgstr "E143: Automatick prkazy neoakvane zmazali nov buffer %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: neseln argument pre :z"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvim nepovouje pouitie prkazov shellu"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regulrne vrazy nesm by oddelen psmenami"
diff --git a/src/nvim/po/sr.po b/src/nvim/po/sr.po
index 88c5d18866..4c157658e5 100644
--- a/src/nvim/po/sr.po
+++ b/src/nvim/po/sr.po
@@ -424,7 +424,7 @@ msgstr "Опција 'dictionary' је празна"
msgid "'thesaurus' option is empty"
msgstr "Опција 'thesaurus' је празна"
-#, c-format
+#, c-format
msgid "Scanning dictionary: %s"
msgstr "Скенирање речника: %s"
@@ -702,7 +702,7 @@ msgstr "E785: complete() може да се користи само у режи
msgid "&Ok"
msgstr "&Ок"
-#, c-format
+#, c-format
msgid "+-%s%3ld line: "
msgid_plural "+-%s%3ld lines: "
msgstr[0] "+-%s%3ld линија: "
@@ -810,7 +810,7 @@ msgstr "E677: Грешка при упису temp датотеке"
msgid "E921: Invalid callback argument"
msgstr "E921: Неисправан callback аргумент"
-#, c-format
+#, c-format
msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
msgstr "<%s>%s%s %d, Хекс %02x, Окт %03o, Дигр %s"
@@ -818,11 +818,11 @@ msgstr "<%s>%s%s %d, Хекс %02x, Окт %03o, Дигр %s"
msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
msgstr "<%s>%s%s %d, Хекс %02x, Октално %03o"
-#, c-format
+#, c-format
msgid "> %d, Hex %04x, Oct %o, Digr %s"
msgstr "> %d, Хекс %04x, Окт %o, Дигр %s"
-#, c-format
+#, c-format
msgid "> %d, Hex %08x, Oct %o, Digr %s"
msgstr "> %d, Хекс %08x, Окт %o, Дигр %s"
@@ -981,9 +981,6 @@ msgstr "E143: Аутокоманде су неочекивано обрисал
msgid "E144: non-numeric argument to :z"
msgstr "E144: ненумерички аргумент за :z"
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Shell команде нису дозвољене у rvim"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Регуларни изрази не могу да се раздвајају словима"
diff --git a/src/nvim/po/sv.po b/src/nvim/po/sv.po
index 4770db15de..db7bada888 100644
--- a/src/nvim/po/sv.po
+++ b/src/nvim/po/sv.po
@@ -2622,10 +2622,6 @@ msgstr "E143: Autokommandon tog ovntat bort ny buffert %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: ickenumeriskt argument till :z"
-#: ../ex_cmds.c:3398
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Skalkommandon inte tilltna i rvim"
-
#: ../ex_cmds.c:3492
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Reguljra uttryck kan inte vara tskilda av bokstver"
diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po
index f2179f4f1b..604e425bd0 100644
--- a/src/nvim/po/uk.po
+++ b/src/nvim/po/uk.po
@@ -1459,10 +1459,6 @@ msgstr "E143: Автокоманди несподівано знищили но
msgid "E144: non-numeric argument to :z"
msgstr "E144: нечисловий аргумент для :z"
-msgid ""
-"E145: Shell commands and some functionality not allowed in restricted mode"
-msgstr "E145: У обмеженому режимі не дозволені команди оболонки і деяка функіональність"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Регулярні вирази не можна розділяти літерами"
diff --git a/src/nvim/po/vi.po b/src/nvim/po/vi.po
index 7dbf19c263..a954ea6e34 100644
--- a/src/nvim/po/vi.po
+++ b/src/nvim/po/vi.po
@@ -1229,10 +1229,6 @@ msgstr "E143: Các lệnh tự động xóa bộ đệm mới ngoài ý muốn %
msgid "E144: non-numeric argument to :z"
msgstr "E144: Tham số của lệnh :z phải là số"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: Không cho phép sử dụng lệnh shell trong rvim."
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Không thể phân cách biểu thức chính quy bằng chữ cái"
diff --git a/src/nvim/po/zh_CN.UTF-8.po b/src/nvim/po/zh_CN.UTF-8.po
index 76204a43a8..542157002a 100644
--- a/src/nvim/po/zh_CN.UTF-8.po
+++ b/src/nvim/po/zh_CN.UTF-8.po
@@ -1222,10 +1222,6 @@ msgstr "E143: 自动命令意外地删除了新缓冲区 %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: :z 不接受非数字的参数"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvim 中禁止使用 shell 命令"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: 正则表达式不能用字母作分界"
diff --git a/src/nvim/po/zh_TW.UTF-8.po b/src/nvim/po/zh_TW.UTF-8.po
index 3c1dd463b7..6a11b5e669 100644
--- a/src/nvim/po/zh_TW.UTF-8.po
+++ b/src/nvim/po/zh_TW.UTF-8.po
@@ -32,8 +32,8 @@
# So please change [行"] to [行 "]
#
# Q. How to use UTF8 mode on Win32?
-# A. A simple configuration:
-# set encoding=utf-8; let $LANG='zh_TW.UTF-8';
+# A. A simple configuration:
+# set encoding=utf-8; let $LANG='zh_TW.UTF-8';
# (set langmenu=none or ..)
# set fileencodings=ucs-bom,utf-8,japan,taiwan,prc
# set fileencoding=taiwan (or utf-8)
@@ -1262,10 +1262,6 @@ msgstr "E143: Autocommands 意外地刪除新緩衝區 %s"
msgid "E144: non-numeric argument to :z"
msgstr "E144: :z 不接受非數字的參數"
-#: ../ex_cmds.c:3404
-msgid "E145: Shell commands not allowed in rvim"
-msgstr "E145: rvim 中禁止使用 shell 命令"
-
#: ../ex_cmds.c:3498
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Regular expression 無法用字母分隔 (?)"
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index d3ca65c53c..3d7d587ed2 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3608,11 +3608,15 @@ static int qf_open_new_cwindow(qf_info_T *qi, int height)
}
if (qf_buf != NULL) {
// Use the existing quickfix buffer
- (void)do_ecmd(qf_buf->b_fnum, NULL, NULL, NULL, ECMD_ONE,
- ECMD_HIDE + ECMD_OLDBUF, oldwin);
+ if (do_ecmd(qf_buf->b_fnum, NULL, NULL, NULL, ECMD_ONE,
+ ECMD_HIDE + ECMD_OLDBUF, oldwin) == FAIL) {
+ return FAIL;
+ }
} else {
// Create a new quickfix buffer
- (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
+ if (do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin) == FAIL) {
+ return FAIL;
+ }
}
// Set the options for the quickfix buffer/window (if not already done)
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 5f09912116..425458f210 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2196,6 +2196,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
if (wp->w_p_spell
+ && foldinfo.fi_lines == 0
&& *wp->w_s->b_p_spl != NUL
&& !GA_EMPTY(&wp->w_s->b_langp)
&& *(char **)(wp->w_s->b_langp.ga_data) != NULL) {
@@ -5205,7 +5206,7 @@ win_redr_custom (
fillchar = ' ';
attr = HL_ATTR(HLF_TPF);
maxwidth = Columns;
- use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
+ use_sandbox = was_set_insecurely(wp, (char_u *)"tabline", 0);
} else {
row = W_ENDROW(wp);
fillchar = fillchar_status(&attr, wp);
@@ -5236,14 +5237,14 @@ win_redr_custom (
attr = HL_ATTR(HLF_MSG);
}
- use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
+ use_sandbox = was_set_insecurely(wp, (char_u *)"rulerformat", 0);
} else {
if (*wp->w_p_stl != NUL)
stl = wp->w_p_stl;
else
stl = p_stl;
- use_sandbox = was_set_insecurely((char_u *)"statusline",
- *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
+ use_sandbox = was_set_insecurely(
+ wp, (char_u *)"statusline", *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
}
col += wp->w_wincol;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index f979889540..90e1e25de2 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1658,6 +1658,48 @@ static bool find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos)
return found;
}
+/// Check matchpairs option for "*initc".
+/// If there is a match set "*initc" to the matching character and "*findc" to
+/// the opposite character. Set "*backwards" to the direction.
+/// When "switchit" is true swap the direction.
+static void find_mps_values(int *initc, int *findc, bool *backwards,
+ bool switchit)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char_u *ptr = curbuf->b_p_mps;
+
+ while (*ptr != NUL) {
+ if (utf_ptr2char(ptr) == *initc) {
+ if (switchit) {
+ *findc = *initc;
+ *initc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1);
+ *backwards = true;
+ } else {
+ *findc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1);
+ *backwards = false;
+ }
+ return;
+ }
+ char_u *prev = ptr;
+ ptr += utfc_ptr2len(ptr) + 1;
+ if (utf_ptr2char(ptr) == *initc) {
+ if (switchit) {
+ *findc = *initc;
+ *initc = utf_ptr2char(prev);
+ *backwards = false;
+ } else {
+ *findc = utf_ptr2char(prev);
+ *backwards = true;
+ }
+ return;
+ }
+ ptr += utfc_ptr2len(ptr);
+ if (*ptr == ',') {
+ ptr++;
+ }
+ }
+}
+
/*
* findmatchlimit -- find the matching paren or brace, if it exists within
* maxtravel lines of the cursor. A maxtravel of 0 means search until falling
@@ -1684,7 +1726,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
static pos_T pos; // current search position
int findc = 0; // matching brace
int count = 0; // cumulative number of braces
- int backwards = false; // init for gcc
+ bool backwards = false; // init for gcc
bool raw_string = false; // search for raw string
bool inquote = false; // true when inside quotes
char_u *ptr;
@@ -1729,9 +1771,10 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
raw_string = (initc == 'R');
initc = NUL;
} else if (initc != '#' && initc != NUL) {
- find_mps_values(&initc, &findc, &backwards, TRUE);
- if (findc == NUL)
+ find_mps_values(&initc, &findc, &backwards, true);
+ if (findc == NUL) {
return NULL;
+ }
} else {
/*
* Either initc is '#', or no initc was given and we need to look
@@ -1759,20 +1802,20 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
else if (linep[pos.col] == '/') {
if (linep[pos.col + 1] == '*') {
comment_dir = FORWARD;
- backwards = FALSE;
+ backwards = false;
pos.col++;
} else if (pos.col > 0 && linep[pos.col - 1] == '*') {
comment_dir = BACKWARD;
- backwards = TRUE;
+ backwards = true;
pos.col--;
}
} else if (linep[pos.col] == '*') {
if (linep[pos.col + 1] == '/') {
comment_dir = BACKWARD;
- backwards = TRUE;
+ backwards = true;
} else if (pos.col > 0 && linep[pos.col - 1] == '/') {
comment_dir = FORWARD;
- backwards = FALSE;
+ backwards = false;
}
}
}
@@ -1794,9 +1837,10 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
if (initc == NUL)
break;
- find_mps_values(&initc, &findc, &backwards, FALSE);
- if (findc)
+ find_mps_values(&initc, &findc, &backwards, false);
+ if (findc) {
break;
+ }
pos.col += utfc_ptr2len(linep + pos.col);
}
if (!findc) {
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index af8482bdbe..ed75bda7a5 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -86,6 +86,8 @@ let s:filename_checks = {
\ 'bzr': ['bzr_log.any'],
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c'],
\ 'cabal': ['file.cabal'],
+ \ 'cabalconfig': ['cabal.config'],
+ \ 'cabalproject': ['cabal.project', 'cabal.project.local'],
\ 'calendar': ['calendar'],
\ 'catalog': ['catalog', 'sgml.catalogfile'],
\ 'cdl': ['file.cdl'],
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index 00e42733a7..a80a73161f 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -516,7 +516,7 @@ func Test_termguicolors()
if !exists('+termguicolors')
return
endif
- if has('vtp') && !has('vcon')
+ if has('vtp') && !has('vcon') && !has('gui_running')
" Win32: 'guicolors' doesn't work without virtual console.
call assert_fails('set termguicolors', 'E954:')
return
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 3e97cd2dd0..9c5f0777c6 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -4423,4 +4423,39 @@ func Test_add_invalid_entry_with_qf_window()
cclose
endfunc
+" Test for very weird problem: autocommand causes a failure, resulting opening
+" the quickfix window to fail. This still splits the window, but otherwise
+" should not mess up buffers.
+func Test_quickfix_window_fails_to_open()
+ CheckScreendump
+
+ let lines =<< trim END
+ anything
+ try
+ anything
+ endtry
+ END
+ call writefile(lines, 'XquickfixFails')
+
+ let lines =<< trim END
+ split XquickfixFails
+ silent vimgrep anything %
+ normal o
+ au BufLeave * ++once source XquickfixFails
+ " This will trigger the autocommand, which causes an error, what follows
+ " is aborted but the window was already split.
+ silent! cwindow
+ END
+ call writefile(lines, 'XtestWinFails')
+ let buf = RunVimInTerminal('-S XtestWinFails', #{rows: 13})
+ call VerifyScreenDump(buf, 'Test_quickfix_window_fails', {})
+
+ " clean up
+ call term_sendkeys(buf, ":bwipe!\<CR>")
+ call term_wait(buf)
+ call StopVimInTerminal(buf)
+ call delete('XtestWinFails')
+ call delete('XquickfixFails')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index 7fe0168356..6214975ef5 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -581,6 +581,27 @@ func Test_read_stdin()
call delete('Xtestout')
endfunc
+func Test_set_shell()
+ let after =<< trim [CODE]
+ call writefile([&shell], "Xtestout")
+ quit!
+ [CODE]
+
+ if has('win32')
+ let $SHELL = 'C:\with space\cmd.exe'
+ let expected = '"C:\with space\cmd.exe"'
+ else
+ let $SHELL = '/bin/with space/sh'
+ let expected = '"/bin/with space/sh"'
+ endif
+
+ if RunVimPiped([], after, '', '')
+ let lines = readfile('Xtestout')
+ call assert_equal(expected, lines[0])
+ endif
+ call delete('Xtestout')
+endfunc
+
func Test_progpath()
" Tests normally run with "./vim" or "../vim", these must have been expanded
" to a full path.
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index d3c0594c03..424cb4abd0 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -1,5 +1,8 @@
" Tests for system() and systemlist()
+source shared.vim
+source check.vim
+
function! Test_System()
if !executable('echo') || !executable('cat') || !executable('wc')
return
@@ -88,3 +91,54 @@ function! Test_system_exmode()
let a = system(v:progpath. cmd)
call assert_notequal(0, v:shell_error)
endfunc
+
+func Test_system_with_shell_quote()
+ throw 'skipped: enable after porting method patches'
+ CheckMSWindows
+
+ call mkdir('Xdir with spaces', 'p')
+ call system('copy "%COMSPEC%" "Xdir with spaces\cmd.exe"')
+
+ let shell_save = &shell
+ let shellxquote_save = &shellxquote
+ try
+ " Set 'shell' always needs noshellslash.
+ let shellslash_save = &shellslash
+ set noshellslash
+ let shell_tests = [
+ \ expand('$COMSPEC'),
+ \ '"' . fnamemodify('Xdir with spaces\cmd.exe', ':p') . '"',
+ \]
+ let &shellslash = shellslash_save
+
+ let sxq_tests = ['', '(', '"']
+
+ " Matrix tests: 'shell' * 'shellxquote'
+ for shell in shell_tests
+ let &shell = shell
+ for sxq in sxq_tests
+ let &shellxquote = sxq
+
+ let msg = printf('shell=%s shellxquote=%s', &shell, &shellxquote)
+
+ try
+ let out = 'echo 123'->system()
+ catch
+ call assert_report(printf('%s: %s', msg, v:exception))
+ continue
+ endtry
+
+ " On Windows we may get a trailing space and CR.
+ if out != "123 \n"
+ call assert_equal("123\n", out, msg)
+ endif
+
+ endfor
+ endfor
+
+ finally
+ let &shell = shell_save
+ let &shellxquote = shellxquote_save
+ call delete('Xdir with spaces', 'rf')
+ endtry
+endfunc
diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua
index 4c1083c386..65dc1b3e03 100644
--- a/test/functional/lua/treesitter_spec.lua
+++ b/test/functional/lua/treesitter_spec.lua
@@ -50,7 +50,7 @@ describe('treesitter API with C parser', function()
exec_lua([[
parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()
+ tree = parser:parse()[1]
root = tree:root()
lang = vim.treesitter.inspect_language('c')
]])
@@ -82,7 +82,7 @@ describe('treesitter API with C parser', function()
feed("2G7|ay")
exec_lua([[
- tree2 = parser:parse()
+ tree2 = parser:parse()[1]
root2 = tree2:root()
descendant2 = root2:descendant_for_range(1,2,1,13)
]])
@@ -106,11 +106,8 @@ describe('treesitter API with C parser', function()
eq(false, exec_lua("return child:id() == nil"))
eq(false, exec_lua("return child:id() == tree"))
- -- orginal tree did not change
- eq({1,2,1,12}, exec_lua("return {descendant:range()}"))
-
-- unchanged buffer: return the same tree
- eq(true, exec_lua("return parser:parse() == tree2"))
+ eq(true, exec_lua("return parser:parse()[1] == tree2"))
end)
local test_text = [[
@@ -142,7 +139,7 @@ void ui_refresh(void)
local res = exec_lua([[
parser = vim.treesitter.get_parser(0, "c")
- func_node = parser:parse():root():child(0)
+ func_node = parser:parse()[1]:root():child(0)
res = {}
for node, field in func_node:iter_children() do
@@ -166,7 +163,7 @@ void ui_refresh(void)
local res = exec_lua([[
parser = vim.treesitter.get_parser(0, "c")
- func_node = parser:parse():root():child(0)
+ func_node = parser:parse()[1]:root():child(0)
local res = {}
for _, node in ipairs(func_node:field("type")) do
@@ -211,7 +208,7 @@ void ui_refresh(void)
local res = exec_lua([[
cquery = vim.treesitter.parse_query("c", ...)
parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()
+ tree = parser:parse()[1]
res = {}
for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do
-- can't transmit node over RPC. just check the name and range
@@ -242,7 +239,7 @@ void ui_refresh(void)
local res = exec_lua([[
cquery = vim.treesitter.parse_query("c", ...)
parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()
+ tree = parser:parse()[1]
res = {}
for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do
-- can't transmit node over RPC. just check the name and range
@@ -275,7 +272,7 @@ void ui_refresh(void)
local res = exec_lua([[
cquery = vim.treesitter.parse_query("c", '((_) @quote (vim-match? @quote "^\\"$")) ((_) @quote (lua-match? @quote "^\\"$"))')
parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()
+ tree = parser:parse()[1]
res = {}
for pattern, match in cquery:iter_matches(tree:root(), 0, 0, 1) do
-- can't transmit node over RPC. just check the name and range
@@ -321,7 +318,7 @@ void ui_refresh(void)
local query = query.parse_query("c", ...)
local nodes = {}
- for _, node in query:iter_captures(parser:parse():root(), 0, 0, 19) do
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
table.insert(nodes, {node:range()})
end
@@ -343,10 +340,7 @@ void ui_refresh(void)
eq({ 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
end)
- it('supports highlighting', function()
- if not check_parser() then return end
-
- local hl_text = [[
+ local hl_text = [[
/// Schedule Lua callback on main loop's event queue
static int nlua_schedule(lua_State *const lstate)
{
@@ -363,7 +357,7 @@ static int nlua_schedule(lua_State *const lstate)
return 0;
}]]
- local hl_query = [[
+local hl_query = [[
(ERROR) @ErrorMsg
"if" @keyword
@@ -398,249 +392,319 @@ static int nlua_schedule(lua_State *const lstate)
(comment) @comment
]]
- local screen = Screen.new(65, 18)
- screen:attach()
- screen:set_default_attr_ids({
- [1] = {bold = true, foreground = Screen.colors.Blue1},
- [2] = {foreground = Screen.colors.Blue1},
- [3] = {bold = true, foreground = Screen.colors.SeaGreen4},
- [4] = {bold = true, foreground = Screen.colors.Brown},
- [5] = {foreground = Screen.colors.Magenta},
- [6] = {foreground = Screen.colors.Red},
- [7] = {bold = true, foreground = Screen.colors.SlateBlue},
- [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
- [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red},
- [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red},
- [11] = {foreground = Screen.colors.Cyan4},
- })
-
- insert(hl_text)
- screen:expect{grid=[[
- /// Schedule Lua callback on main loop's event queue |
- static int nlua_schedule(lua_State *const lstate) |
- { |
- if (lua_type(lstate, 1) != LUA_TFUNCTION |
- || lstate != lstate) { |
- lua_pushliteral(lstate, "vim.schedule: expected function"); |
- return lua_error(lstate); |
+ describe('when highlighting', function()
+ local screen
+
+ before_each(function()
+ screen = Screen.new(65, 18)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {foreground = Screen.colors.Blue1},
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [4] = {bold = true, foreground = Screen.colors.Brown},
+ [5] = {foreground = Screen.colors.Magenta},
+ [6] = {foreground = Screen.colors.Red},
+ [7] = {bold = true, foreground = Screen.colors.SlateBlue},
+ [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red},
+ [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red},
+ [11] = {foreground = Screen.colors.Cyan4},
+ })
+ end)
+
+ it('supports highlighting', function()
+ if not check_parser() then return end
+
+ insert(hl_text)
+ screen:expect{grid=[[
+ /// Schedule Lua callback on main loop's event queue |
+ static int nlua_schedule(lua_State *const lstate) |
+ { |
+ if (lua_type(lstate, 1) != LUA_TFUNCTION |
+ || lstate != lstate) { |
+ lua_pushliteral(lstate, "vim.schedule: expected function"); |
+ return lua_error(lstate); |
+ } |
+ |
+ LuaRef cb = nlua_ref(lstate, 1); |
+ |
+ multiqueue_put(main_loop.events, nlua_schedule_event, |
+ 1, (void *)(ptrdiff_t)cb); |
+ return 0; |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ exec_lua([[
+ local parser = vim.treesitter.get_parser(0, "c")
+ local highlighter = vim.treesitter.highlighter
+ local query = ...
+ test_hl = highlighter.new(parser, {queries = {c = query}})
+ ]], hl_query)
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed("5Goc<esc>dd")
+
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:^lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ } |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed('7Go*/<esc>')
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ {8:*^/} |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ } |
+ {1:~ }|
+ |
+ ]]}
+
+ feed('3Go/*<esc>')
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {2:/^*} |
+ {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {2: || lstate != lstate) {} |
+ {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {2: return lua_error(lstate);} |
+ {2:*/} |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ {8:}} |
+ |
+ ]]}
+
+ feed("gg$")
+ feed("~")
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queu^E} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {2:/*} |
+ {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {2: || lstate != lstate) {} |
+ {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {2: return lua_error(lstate);} |
+ {2:*/} |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ {8:}} |
+ |
+ ]]}
+
+
+ feed("re")
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queu^e} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {2:/*} |
+ {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {2: || lstate != lstate) {} |
+ {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {2: return lua_error(lstate);} |
+ {2:*/} |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ {8:}} |
+ |
+ ]]}
+ end)
+
+ it("supports highlighting with custom parser", function()
+ if not check_parser() then return end
+
+ screen:set_default_attr_ids({ {bold = true, foreground = Screen.colors.SeaGreen4} })
+
+ insert(test_text)
+
+ screen:expect{ grid= [[
+ int width = INT_MAX, height = INT_MAX; |
+ bool ext_widgets[kUIExtCount]; |
+ for (UIExtension i = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
} |
|
- LuaRef cb = nlua_ref(lstate, 1); |
- |
- multiqueue_put(main_loop.events, nlua_schedule_event, |
- 1, (void *)(ptrdiff_t)cb); |
- return 0; |
- ^} |
- {1:~ }|
- {1:~ }|
- |
- ]]}
-
- exec_lua([[
- local parser = vim.treesitter.get_parser(0, "c")
- local highlighter = vim.treesitter.highlighter
- local query = ...
- test_hl = highlighter.new(parser, query)
- ]], hl_query)
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
+ bool inclusive = ui_override(); |
+ for (size_t i = 0; i < ui_count; i++) { |
+ UI *ui = uis[i]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
} |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
^} |
- {1:~ }|
- {1:~ }|
- |
- ]]}
-
- feed("5Goc<esc>dd")
-
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:^lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- } |
- {1:~ }|
- {1:~ }|
- |
- ]]}
-
- feed('7Go*/<esc>')
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
- {8:*^/} |
- } |
|
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- } |
- {1:~ }|
- |
- ]]}
-
- feed('3Go/*<esc>')
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/^*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- {8:}} |
- |
- ]]}
-
- feed("gg$")
- feed("~")
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queu^E} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- {8:}} |
- |
- ]]}
-
-
- feed("re")
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queu^e} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- {8:}} |
- |
- ]]}
- end)
+ ]] }
- it("supports highlighting with custom parser", function()
- if not check_parser() then return end
-
- local screen = Screen.new(65, 18)
- screen:attach()
- screen:set_default_attr_ids({ {bold = true, foreground = Screen.colors.SeaGreen4} })
-
- insert(test_text)
-
- screen:expect{ grid= [[
- int width = INT_MAX, height = INT_MAX; |
- bool ext_widgets[kUIExtCount]; |
- for (UIExtension i = 0; (int)i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- bool inclusive = ui_override(); |
- for (size_t i = 0; i < ui_count; i++) { |
- UI *ui = uis[i]; |
- width = MIN(ui->width, width); |
- height = MIN(ui->height, height); |
- foo = BAR(ui->bazaar, bazaar); |
- for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- |
- ]] }
-
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
- query = vim.treesitter.parse_query("c", "(declaration) @decl")
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+ query = vim.treesitter.parse_query("c", "(declaration) @decl")
- local nodes = {}
- for _, node in query:iter_captures(parser:parse():root(), 0, 0, 19) do
- table.insert(nodes, node)
- end
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
+ table.insert(nodes, node)
+ end
- parser:set_included_ranges(nodes)
+ parser:set_included_regions({nodes})
- local hl = vim.treesitter.highlighter.new(parser, "(identifier) @type")
- ]])
+ local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}})
+ ]])
- screen:expect{ grid = [[
- int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; |
- bool {1:ext_widgets}[{1:kUIExtCount}]; |
- for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- bool {1:inclusive} = {1:ui_override}(); |
- for (size_t {1:i} = 0; i < ui_count; i++) { |
- UI *{1:ui} = {1:uis}[{1:i}]; |
- width = MIN(ui->width, width); |
- height = MIN(ui->height, height); |
- foo = BAR(ui->bazaar, bazaar); |
- for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- |
- ]] }
+ screen:expect{ grid = [[
+ int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; |
+ bool {1:ext_widgets}[{1:kUIExtCount}]; |
+ for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool {1:inclusive} = {1:ui_override}(); |
+ for (size_t {1:i} = 0; i < ui_count; i++) { |
+ UI *{1:ui} = {1:uis}[{1:i}]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]] }
+ end)
+
+ it("supports highlighting injected languages", function()
+ if not check_parser() then return end
+
+ insert([[
+ int x = INT_MAX;
+ #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ #define foo void main() { \
+ return 42; \
+ }
+ ]])
+
+ screen:expect{grid=[[
+ int x = INT_MAX; |
+ #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))|
+ #define foo void main() { \ |
+ return 42; \ |
+ } |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ exec_lua([[
+ local parser = vim.treesitter.get_parser(0, "c", {
+ queries = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}
+ })
+ local highlighter = vim.treesitter.highlighter
+ local query = ...
+ test_hl = highlighter.new(parser, {queries = {c = query}})
+ ]], hl_query)
+
+ screen:expect{grid=[[
+ {3:int} x = {5:INT_MAX}; |
+ #define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))|
+ #define foo {3:void} main() { \ |
+ {4:return} {5:42}; \ |
+ } |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
end)
it('inspects language', function()
@@ -690,7 +754,7 @@ static int nlua_schedule(lua_State *const lstate)
local res = exec_lua [[
parser = vim.treesitter.get_parser(0, "c")
- return { parser:parse():root():range() }
+ return { parser:parse()[1]:root():range() }
]]
eq({0, 0, 19, 0}, res)
@@ -698,38 +762,51 @@ static int nlua_schedule(lua_State *const lstate)
-- The following sets the included ranges for the current parser
-- As stated here, this only includes the function (thus the whole buffer, without the last line)
local res2 = exec_lua [[
- local root = parser:parse():root()
- parser:set_included_ranges({root:child(0)})
- parser.valid = false
- return { parser:parse():root():range() }
+ local root = parser:parse()[1]:root()
+ parser:set_included_regions({{root:child(0)}})
+ parser:invalidate()
+ return { parser:parse()[1]:root():range() }
]]
eq({0, 0, 18, 1}, res2)
local range = exec_lua [[
- return parser:included_ranges()
+ local res = {}
+ for _, region in ipairs(parser:included_regions()) do
+ for _, node in ipairs(region) do
+ table.insert(res, {node:range()})
+ end
+ end
+ return res
]]
eq(range, { { 0, 0, 18, 1 } })
+
+ local range_tbl = exec_lua [[
+ parser:set_included_regions { { { 0, 0, 17, 1 } } }
+ parser:parse()
+ return parser:included_regions()
+ ]]
+
+ eq(range_tbl, { { { 0, 0, 0, 17, 1, 508 } } })
end)
it("allows to set complex ranges", function()
if not check_parser() then return end
insert(test_text)
-
local res = exec_lua [[
parser = vim.treesitter.get_parser(0, "c")
query = vim.treesitter.parse_query("c", "(declaration) @decl")
local nodes = {}
- for _, node in query:iter_captures(parser:parse():root(), 0, 0, 19) do
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
table.insert(nodes, node)
end
- parser:set_included_ranges(nodes)
+ parser:set_included_regions({nodes})
- local root = parser:parse():root()
+ local root = parser:parse()[1]:root()
local res = {}
for i=0,(root:named_child_count() - 1) do
@@ -740,21 +817,18 @@ static int nlua_schedule(lua_State *const lstate)
eq({
{ 2, 2, 2, 40 },
- { 3, 3, 3, 32 },
- { 4, 7, 4, 8 },
- { 4, 8, 4, 25 },
- { 8, 2, 8, 6 },
- { 8, 7, 8, 33 },
- { 9, 8, 9, 20 },
- { 10, 4, 10, 5 },
- { 10, 5, 10, 20 },
+ { 3, 2, 3, 32 },
+ { 4, 7, 4, 25 },
+ { 8, 2, 8, 33 },
+ { 9, 7, 9, 20 },
+ { 10, 4, 10, 20 },
{ 14, 9, 14, 27 } }, res)
end)
it("allows to create string parsers", function()
local ret = exec_lua [[
local parser = vim.treesitter.get_string_parser("int foo = 42;", "c")
- return { parser:parse():root():range() }
+ return { parser:parse()[1]:root():range() }
]]
eq({ 0, 0, 0, 13 }, ret)
@@ -773,7 +847,7 @@ static int nlua_schedule(lua_State *const lstate)
local nodes = {}
local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))')
- for _, node in query:iter_captures(parser:parse():root(), str, 0, 2) do
+ for _, node in query:iter_captures(parser:parse()[1]:root(), str, 0, 2) do
table.insert(nodes, { node:range() })
end
@@ -781,4 +855,68 @@ static int nlua_schedule(lua_State *const lstate)
eq({ {0, 10, 0, 13} }, ret)
end)
+
+ describe("when creating a language tree", function()
+ local function get_ranges()
+ return exec_lua([[
+ local result = {}
+ parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end)
+ return result
+ ]])
+ end
+
+ before_each(function()
+ insert([[
+ int x = INT_MAX;
+ #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ #define READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
+ #define VALUE 0
+ #define VALUE1 1
+ #define VALUE2 2
+ ]])
+ end)
+
+ describe("when parsing regions independently", function()
+ it("should inject a language", function()
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c", {
+ queries = {
+ c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}})
+ ]])
+
+ eq("table", exec_lua("return type(parser:children().c)"))
+ eq(5, exec_lua("return #parser:children().c:trees()"))
+ eq({
+ {0, 2, 7, 0}, -- root tree
+ {3, 16, 3, 17}, -- VALUE 0
+ {4, 17, 4, 18}, -- VALUE1 1
+ {5, 17, 5, 18}, -- VALUE2 2
+ {1, 28, 1, 67}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ {2, 31, 2, 70} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
+ }, get_ranges())
+ end)
+ end)
+
+ describe("when parsing regions combined", function()
+ it("should inject a language", function()
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c", {
+ queries = {
+ c = "(preproc_def (preproc_arg) @c @combined) (preproc_function_def value: (preproc_arg) @c @combined)"}})
+ ]])
+
+ eq("table", exec_lua("return type(parser:children().c)"))
+ eq(2, exec_lua("return #parser:children().c:trees()"))
+ eq({
+ {0, 2, 7, 0}, -- root tree
+ {3, 16, 5, 18}, -- VALUE 0
+ -- VALUE1 1
+ -- VALUE2 2
+ {1, 28, 2, 70} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
+ }, get_ranges())
+ end)
+ end)
+ end)
+
end)
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 669ec5d3ed..018049d2f4 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -117,6 +117,33 @@ describe("folded lines", function()
end
end)
+ it("work with spell", function()
+ command("set spell")
+ insert([[
+ This is a
+ valid English
+ sentence composed by
+ an exhausted developer
+ in his cave.
+ ]])
+
+ feed("gg")
+ feed("zf3j")
+ if not multigrid then
+ -- screen:snapshot_util()
+ screen:expect{grid=[[
+ {5:^+-- 4 lines: This is a······················}|
+ in his cave. |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end
+ end)
+
it("works with multibyte fillchars", function()
insert([[
aa
diff --git a/test/helpers.lua b/test/helpers.lua
index 84148dc1a8..8dbd82cb8c 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -777,11 +777,12 @@ end
function module.isCI(name)
local any = (name == nil)
- assert(any or name == 'appveyor' or name == 'travis' or name == 'sourcehut')
+ assert(any or name == 'appveyor' or name == 'travis' or name == 'sourcehut' or name == 'github')
local av = ((any or name == 'appveyor') and nil ~= os.getenv('APPVEYOR'))
local tr = ((any or name == 'travis') and nil ~= os.getenv('TRAVIS'))
local sh = ((any or name == 'sourcehut') and nil ~= os.getenv('SOURCEHUT'))
- return tr or av or sh
+ local gh = ((any or name == 'github') and nil ~= os.getenv('GITHUB_ACTIONS'))
+ return tr or av or sh or gh
end