diff options
-rw-r--r-- | runtime/autoload/provider/clipboard.vim | 215 | ||||
-rw-r--r-- | runtime/doc/diagnostic.txt | 7 | ||||
-rw-r--r-- | runtime/doc/lua.txt | 6 | ||||
-rw-r--r-- | runtime/doc/news.txt | 4 | ||||
-rw-r--r-- | runtime/doc/provider.txt | 21 | ||||
-rw-r--r-- | runtime/ftplugin/dax.vim | 16 | ||||
-rw-r--r-- | runtime/lua/vim/diagnostic.lua | 6 | ||||
-rw-r--r-- | runtime/lua/vim/filetype.lua | 1 | ||||
-rw-r--r-- | runtime/lua/vim/hl.lua | 57 | ||||
-rw-r--r-- | runtime/syntax/dax.vim | 151 | ||||
-rw-r--r-- | test/functional/lua/hl_spec.lua | 86 | ||||
-rw-r--r-- | test/functional/lua/secure_spec.lua | 164 | ||||
-rw-r--r-- | test/functional/plugin/shada_spec.lua | 4 | ||||
-rw-r--r-- | test/old/testdir/test_filetype.vim | 1 |
14 files changed, 536 insertions, 203 deletions
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 7e7feb50e0..32d8841b72 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -67,6 +67,113 @@ function! s:set_osc52() abort return 'OSC 52' endfunction +function! s:set_pbcopy() abort + let s:copy['+'] = ['pbcopy'] + let s:paste['+'] = ['pbpaste'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + let s:cache_enabled = 0 + return 'pbcopy' +endfunction + +function! s:set_wayland() abort + let s:copy['+'] = ['wl-copy', '--type', 'text/plain'] + let s:paste['+'] = ['wl-paste', '--no-newline'] + let s:copy['*'] = ['wl-copy', '--primary', '--type', 'text/plain'] + let s:paste['*'] = ['wl-paste', '--no-newline', '--primary'] + return 'wl-copy' +endfunction + +function! s:set_wayclip() abort + let s:copy['+'] = ['waycopy', '-t', 'text/plain'] + let s:paste['+'] = ['waypaste', '-t', 'text/plain'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'wayclip' +endfunction + +function! s:set_xsel() abort + let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b'] + let s:paste['+'] = ['xsel', '-o', '-b'] + let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p'] + let s:paste['*'] = ['xsel', '-o', '-p'] + return 'xsel' +endfunction + +function! s:set_xclip() abort + let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard'] + let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard'] + let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary'] + let s:paste['*'] = ['xclip', '-o', '-selection', 'primary'] + return 'xclip' +endfunction + +function! s:set_lemonade() abort + let s:copy['+'] = ['lemonade', 'copy'] + let s:paste['+'] = ['lemonade', 'paste'] + let s:copy['*'] = ['lemonade', 'copy'] + let s:paste['*'] = ['lemonade', 'paste'] + return 'lemonade' +endfunction + +function! s:set_doitclient() abort + let s:copy['+'] = ['doitclient', 'wclip'] + let s:paste['+'] = ['doitclient', 'wclip', '-r'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'doitclient' +endfunction + +function! s:set_win32yank() abort + if has('wsl') && getftype(exepath('win32yank.exe')) == 'link' + let win32yank = resolve(exepath('win32yank.exe')) + else + let win32yank = 'win32yank.exe' + endif + let s:copy['+'] = [win32yank, '-i', '--crlf'] + let s:paste['+'] = [win32yank, '-o', '--lf'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'win32yank' +endfunction + +function! s:set_putclip() abort + let s:copy['+'] = ['putclip'] + let s:paste['+'] = ['getclip'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'putclip' +endfunction + +function! s:set_clip() abort + let s:copy['+'] = ['clip'] + let s:paste['+'] = ['powershell', '-NoProfile', '-NoLogo', '-Command', 'Get-Clipboard'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'clip' +endfunction + +function! s:set_termux() abort + let s:copy['+'] = ['termux-clipboard-set'] + let s:paste['+'] = ['termux-clipboard-get'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'termux-clipboard' +endfunction + +function! s:set_tmux() abort + let tmux_v = v:lua.vim.version.parse(system(['tmux', '-V'])) + if !empty(tmux_v) && !v:lua.vim.version.lt(tmux_v, [3,2,0]) + let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-'] + else + let s:copy['+'] = ['tmux', 'load-buffer', '-'] + endif + let s:paste['+'] = ['tmux', 'save-buffer', '-'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'tmux' +endfunction + let s:cache_enabled = 1 let s:err = '' @@ -78,9 +185,34 @@ function! provider#clipboard#Executable() abort " Setting g:clipboard to v:false explicitly opts-in to using the "builtin" clipboard providers below if exists('g:clipboard') && g:clipboard isnot# v:false if v:t_string ==# type(g:clipboard) + " Handle string form of g:clipboard for all builtin providers if 'osc52' == g:clipboard " User opted-in to OSC 52 by manually setting g:clipboard. return s:set_osc52() + elseif 'pbcopy' == g:clipboard + return s:set_pbcopy() + elseif 'wl-copy' == g:clipboard + return s:set_wayland() + elseif 'wayclip' == g:clipboard + return s:set_wayclip() + elseif 'xsel' == g:clipboard + return s:set_xsel() + elseif 'xclip' == g:clipboard + return s:set_xclip() + elseif 'lemonade' == g:clipboard + return s:set_lemonade() + elseif 'doitclient' == g:clipboard + return s:set_doitclient() + elseif 'win32yank' == g:clipboard + return s:set_win32yank() + elseif 'putclip' == g:clipboard + return s:set_putclip() + elseif 'clip' == g:clipboard + return s:set_clip() + elseif 'termux' == g:clipboard + return s:set_termux() + elseif 'tmux' == g:clipboard + return s:set_tmux() endif endif @@ -102,88 +234,29 @@ function! provider#clipboard#Executable() abort let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0) return get(g:clipboard, 'name', 'g:clipboard') elseif has('mac') - let s:copy['+'] = ['pbcopy'] - let s:paste['+'] = ['pbpaste'] - let s:copy['*'] = s:copy['+'] - let s:paste['*'] = s:paste['+'] - let s:cache_enabled = 0 - return 'pbcopy' + return s:set_pbcopy() elseif !empty($WAYLAND_DISPLAY) && executable('wl-copy') && executable('wl-paste') - let s:copy['+'] = ['wl-copy', '--type', 'text/plain'] - let s:paste['+'] = ['wl-paste', '--no-newline'] - let s:copy['*'] = ['wl-copy', '--primary', '--type', 'text/plain'] - let s:paste['*'] = ['wl-paste', '--no-newline', '--primary'] - return 'wl-copy' + return s:set_wayland() elseif !empty($WAYLAND_DISPLAY) && executable('waycopy') && executable('waypaste') - let s:copy['+'] = ['waycopy', '-t', 'text/plain'] - let s:paste['+'] = ['waypaste', '-t', 'text/plain'] - let s:copy['*'] = s:copy['+'] - let s:paste['*'] = s:paste['+'] - return 'wayclip' + return s:set_wayclip() elseif !empty($DISPLAY) && executable('xsel') && s:cmd_ok('xsel -o -b') - let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b'] - let s:paste['+'] = ['xsel', '-o', '-b'] - let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p'] - let s:paste['*'] = ['xsel', '-o', '-p'] - return 'xsel' + return s:set_xsel() elseif !empty($DISPLAY) && executable('xclip') - let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard'] - let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard'] - let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary'] - let s:paste['*'] = ['xclip', '-o', '-selection', 'primary'] - return 'xclip' + return s:set_xclip() elseif executable('lemonade') - let s:copy['+'] = ['lemonade', 'copy'] - let s:paste['+'] = ['lemonade', 'paste'] - let s:copy['*'] = ['lemonade', 'copy'] - let s:paste['*'] = ['lemonade', 'paste'] - return 'lemonade' + return s:set_lemonade() elseif executable('doitclient') - let s:copy['+'] = ['doitclient', 'wclip'] - let s:paste['+'] = ['doitclient', 'wclip', '-r'] - let s:copy['*'] = s:copy['+'] - let s:paste['*'] = s:paste['+'] - return 'doitclient' + return s:set_doitclient() elseif executable('win32yank.exe') - if has('wsl') && getftype(exepath('win32yank.exe')) == 'link' - let win32yank = resolve(exepath('win32yank.exe')) - else - let win32yank = 'win32yank.exe' - endif - let s:copy['+'] = [win32yank, '-i', '--crlf'] - let s:paste['+'] = [win32yank, '-o', '--lf'] - let s:copy['*'] = s:copy['+'] - let s:paste['*'] = s:paste['+'] - return 'win32yank' + return s:set_win32yank() elseif executable('putclip') && executable('getclip') - let s:copy['+'] = ['putclip'] - let s:paste['+'] = ['getclip'] - let s:copy['*'] = s:copy['+'] - let s:paste['*'] = s:paste['+'] - return 'putclip' + return s:set_putclip() elseif executable('clip') && executable('powershell') - let s:copy['+'] = ['clip'] - let s:paste['+'] = ['powershell', '-NoProfile', '-NoLogo', '-Command', 'Get-Clipboard'] - let s:copy['*'] = s:copy['+'] - let s:paste['*'] = s:paste['+'] - return 'clip' + return s:set_clip() elseif executable('termux-clipboard-set') - let s:copy['+'] = ['termux-clipboard-set'] - let s:paste['+'] = ['termux-clipboard-get'] - let s:copy['*'] = s:copy['+'] - let s:paste['*'] = s:paste['+'] - return 'termux-clipboard' + return s:set_termux() elseif executable('tmux') && (!empty($TMUX) || 0 == jobwait([jobstart(['tmux', 'list-buffers'])], 2000)[0]) - let tmux_v = v:lua.vim.version.parse(system(['tmux', '-V'])) - if !empty(tmux_v) && !v:lua.vim.version.lt(tmux_v, [3,2,0]) - let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-'] - else - let s:copy['+'] = ['tmux', 'load-buffer', '-'] - endif - let s:paste['+'] = ['tmux', 'save-buffer', '-'] - let s:copy['*'] = s:copy['+'] - let s:paste['*'] = s:paste['+'] - return 'tmux' + return s:set_tmux() elseif get(get(g:, 'termfeatures', {}), 'osc52') && &clipboard ==# '' " Don't use OSC 52 when 'clipboard' is set. It can be slow and cause a lot " of user prompts. Users can opt-in to it by setting g:clipboard manually. diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index 2b891bde1b..efdfd2bfc6 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -574,8 +574,8 @@ Lua module: vim.diagnostic *diagnostic-api* *vim.diagnostic.Opts.Signs* Fields: ~ - • {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual text - for diagnostics matching the given severity + • {severity}? (`vim.diagnostic.SeverityFilter`) Only show signs for + diagnostics matching the given severity |diagnostic-severity| • {priority}? (`integer`, default: `10`) Base priority to use for signs. When {severity_sort} is used, the priority of a @@ -607,6 +607,9 @@ Lua module: vim.diagnostic *diagnostic-api* *vim.diagnostic.Opts.VirtualLines* Fields: ~ + • {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual + lines for diagnostics matching the given severity + |diagnostic-severity| • {current_line}? (`boolean`, default: `false`) Only show diagnostics for the current line. • {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index be118cf790..c580c55a5e 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -640,6 +640,12 @@ vim.hl.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts}) • {timeout}? (`integer`, default: -1 no timeout) Time in ms before highlight is cleared + Return (multiple): ~ + (`uv.uv_timer_t?`) range_timer A timer which manages how much time the + highlight has left + (`fun()?`) range_clear A function which allows clearing the highlight + manually. nil is returned if timeout is not specified + ============================================================================== VIM.DIFF *vim.diff* diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index eee39f81f5..72d394dd68 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -104,7 +104,7 @@ The following new features were added. API -• todo +• |vim.hl.range()| now allows multiple timed highlights DEFAULTS @@ -138,6 +138,8 @@ OPTIONS • 'winborder' add bold style. +• |g:clipboard| accepts a string name to force any builtin clipboard tool. + PERFORMANCE • todo diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt index 7a4cc0ee7d..4f7807f721 100644 --- a/runtime/doc/provider.txt +++ b/runtime/doc/provider.txt @@ -240,6 +240,27 @@ The "copy" function stores a list of lines and the register type. The "paste" function returns the clipboard as a `[lines, regtype]` list, where `lines` is a list of lines and `regtype` is a register type conforming to |setreg()|. +Nvim also supports setting g:clipboard to a string to use a builtin clipboard provider: + + - "tmux" - Use tmux clipboard + - "xclip" - Use xclip for X11 clipboard + - "xsel" - Use xsel for X11 clipboard + - "wl-copy" - Use Wayland clipboard with wl-copy/wl-paste + - "wayclip" - Use Wayland clipboard with waycopy/waypaste + - "lemonade" - Use lemonade clipboard (for SSH) + - "doitclient" - Use doitclient clipboard (for SSH) + - "win32yank" - Use win32yank clipboard (for Windows) + - "clip" - Use clip/powershell clipboard (for Windows) + - "putclip" - Use putclip/getclip clipboard (for Windows/Cygwin) + - "termux" - Use Termux clipboard + - "pbcopy" - Use macOS clipboard + - "osc52" - Use OSC 52 sequence + +Example: >vim + let g:clipboard = 'tmux' + +This is equivalent to using the full dictionary configuration for tmux shown above. + *clipboard-wsl* For Windows WSL, try this g:clipboard definition: >vim diff --git a/runtime/ftplugin/dax.vim b/runtime/ftplugin/dax.vim new file mode 100644 index 0000000000..e5783f03a3 --- /dev/null +++ b/runtime/ftplugin/dax.vim @@ -0,0 +1,16 @@ +" Vim filetype plugin +" Language: Data Analysis Expressions (DAX) +" Maintainer: Anarion Dunedain <anarion80@gmail.com> +" Last Change: 2025 Apr 2 + +if exists('b:did_ftplugin') + finish +endif + +let b:did_ftplugin = 1 + +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// + +setlocal commentstring=//\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index c52b42b382..6e91a27512 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -241,6 +241,10 @@ end --- @class vim.diagnostic.Opts.VirtualLines --- +--- Only show virtual lines for diagnostics matching the given +--- severity |diagnostic-severity| +--- @field severity? vim.diagnostic.SeverityFilter +--- --- Only show diagnostics for the current line. --- (default: `false`) --- @field current_line? boolean @@ -252,7 +256,7 @@ end --- @class vim.diagnostic.Opts.Signs --- ---- Only show virtual text for diagnostics matching the given +--- Only show signs for diagnostics matching the given --- severity |diagnostic-severity| --- @field severity? vim.diagnostic.SeverityFilter --- diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index a35a1a32b3..caa937aa83 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -380,6 +380,7 @@ local extension = { dat = detect.dat, Dat = detect.dat, DAT = detect.dat, + dax = 'dax', dcd = 'dcd', decl = detect.decl, dec = detect.decl, diff --git a/runtime/lua/vim/hl.lua b/runtime/lua/vim/hl.lua index a2b06c9727..d15ee1fd10 100644 --- a/runtime/lua/vim/hl.lua +++ b/runtime/lua/vim/hl.lua @@ -17,9 +17,6 @@ M.priorities = { user = 200, } -local range_timer --- @type uv.uv_timer_t? -local range_hl_clear --- @type fun()? - --- @class vim.hl.range.Opts --- @inlinedoc --- @@ -47,6 +44,10 @@ local range_hl_clear --- @type fun()? ---@param start integer[]|string Start of region as a (line, column) tuple or string accepted by |getpos()| ---@param finish integer[]|string End of region as a (line, column) tuple or string accepted by |getpos()| ---@param opts? vim.hl.range.Opts +--- @return uv.uv_timer_t? range_timer A timer which manages how much time the +--- highlight has left +--- @return fun()? range_clear A function which allows clearing the highlight manually. +--- nil is returned if timeout is not specified function M.range(bufnr, ns, higroup, start, finish, opts) opts = opts or {} local regtype = opts.regtype or 'v' @@ -108,38 +109,38 @@ function M.range(bufnr, ns, higroup, start, finish, opts) end end - if range_timer and not range_timer:is_closing() then - range_timer:close() - assert(range_hl_clear) - range_hl_clear() - end - - range_hl_clear = function() - range_timer = nil - range_hl_clear = nil - pcall(vim.api.nvim_buf_clear_namespace, bufnr, ns, 0, -1) - pcall(vim.api.nvim__ns_set, { wins = {} }) - end - + local extmarks = {} --- @type integer[] for _, res in ipairs(region) do local start_row = res[1][2] - 1 local start_col = res[1][3] - 1 local end_row = res[2][2] - 1 local end_col = res[2][3] - api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, { - hl_group = higroup, - end_row = end_row, - end_col = end_col, - priority = priority, - strict = false, - }) + table.insert( + extmarks, + api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, { + hl_group = higroup, + end_row = end_row, + end_col = end_col, + priority = priority, + strict = false, + }) + ) + end + + local range_hl_clear = function() + for _, mark in ipairs(extmarks) do + api.nvim_buf_del_extmark(bufnr, ns, mark) + end end if timeout ~= -1 then - range_timer = vim.defer_fn(range_hl_clear, timeout) + local range_timer = vim.defer_fn(range_hl_clear, timeout) + return range_timer, range_hl_clear end end +local yank_timer --- @type uv.uv_timer_t? +local yank_hl_clear --- @type fun()? local yank_ns = api.nvim_create_namespace('nvim.hlyank') --- Highlight the yanked text during a |TextYankPost| event. @@ -179,8 +180,14 @@ function M.on_yank(opts) local bufnr = vim.api.nvim_get_current_buf() local winid = vim.api.nvim_get_current_win() + if yank_timer and not yank_timer:is_closing() then + yank_timer:close() + assert(yank_hl_clear) + yank_hl_clear() + end + vim.api.nvim__ns_set(yank_ns, { wins = { winid } }) - M.range(bufnr, yank_ns, higroup, "'[", "']", { + yank_timer, yank_hl_clear = M.range(bufnr, yank_ns, higroup, "'[", "']", { regtype = event.regtype, inclusive = true, priority = opts.priority or M.priorities.user, diff --git a/runtime/syntax/dax.vim b/runtime/syntax/dax.vim new file mode 100644 index 0000000000..12e54ee1f5 --- /dev/null +++ b/runtime/syntax/dax.vim @@ -0,0 +1,151 @@ +" Vim syntax file +" Language: Data Analysis Expressions (DAX) +" Maintainer: Anarion Dunedain <anarion80@gmail.com> +" Last Change: +" 2025 Mar 28 First version + +" quit when a syntax file was already loaded +if exists("b:current_syntax") + finish +endif +let s:keepcpo = &cpo +set cpo&vim + +" There are DAX functions with dot in the name (like VARX.S) +setlocal iskeyword+=. +" DAX is case insensitive +syn case ignore + +" DAX statements +syn keyword daxStatement DEFINE EVALUATE MEASURE RETURN VAR +syn match daxStatement "ORDER\ BY" +syn match daxStatement "START\ AT" + +" TODO +syn keyword daxTodo FIXME NOTE TODO OPTIMIZE XXX HACK contained + +" DAX functions +syn keyword daxFunction + \ ABS ACCRINT ACCRINTM ACOS ACOSH ACOT ACOTH + \ ADDCOLUMNS ADDMISSINGITEMS ALL ALLCROSSFILTERED ALLEXCEPT ALLNOBLANKROW ALLSELECTED + \ AMORDEGRC AMORLINC AND APPROXIMATEDISTINCTCOUNT ASIN ASINH ATAN + \ ATANH AVERAGE AVERAGEA AVERAGEX BETA.DIST BETA.INV BITAND + \ BITLSHIFT BITOR BITRSHIFT BITXOR BLANK CALCULATE CALCULATETABLE + \ CALENDAR CALENDARAUTO CEILING CHISQ.DIST CHISQ.DIST.RT CHISQ.INV CHISQ.INV.RT + \ CLOSINGBALANCEMONTH CLOSINGBALANCEQUARTER CLOSINGBALANCEYEAR COALESCE COLUMNSTATISTICS COMBIN COMBINA + \ COMBINEVALUES CONCATENATE CONCATENATEX CONFIDENCE.NORM CONFIDENCE.T CONTAINSROW + \ CONTAINSSTRING CONTAINSSTRINGEXACT CONVERT COS COSH COT COTH + \ COUNT COUNTA COUNTAX COUNTBLANK COUNTROWS COUNTX COUPDAYBS + \ COUPDAYS COUPDAYSNC COUPNCD COUPNUM COUPPCD CROSSFILTER CROSSJOIN + \ CUMIPMT CUMPRINC CURRENCY CURRENTGROUP CUSTOMDATA DATATABLE DATE + \ DATEADD DATEDIFF DATESBETWEEN DATESINPERIOD DATESMTD DATESQTD DATESYTD + \ DATEVALUE DAY DB DDB DEGREES DETAILROWS DISC + \ DISTINCT column DISTINCT table DISTINCTCOUNT DISTINCTCOUNTNOBLANK DIVIDE DOLLARDE DOLLARFR + \ DURATION EARLIER EARLIEST EDATE EFFECT ENDOFMONTH ENDOFQUARTER + \ ENDOFYEAR EOMONTH ERROR EVALUATEANDLOG EVEN EXACT EXCEPT + \ EXP EXPON.DIST FACT FALSE FILTER FILTERS FIND + \ FIRST FIRSTDATE FIXED FLOOR FORMAT FV GCD + \ GENERATE GENERATEALL GENERATESERIES GEOMEAN GEOMEANX GROUPBY HASONEFILTER + \ HASONEVALUE HOUR IF IF.EAGER IFERROR IGNORE INDEX + \ INFO.ALTERNATEOFDEFINITIONS INFO.ANNOTATIONS INFO.ATTRIBUTEHIERARCHIES INFO.ATTRIBUTEHIERARCHYSTORAGES INFO.CALCDEPENDENCY INFO.CALCULATIONGROUPS INFO.CALCULATIONITEMS + \ INFO.CATALOGS INFO.CHANGEDPROPERTIES INFO.COLUMNPARTITIONSTORAGES INFO.COLUMNPERMISSIONS INFO.COLUMNS INFO.COLUMNSTORAGES INFO.CSDLMETADATA + \ INFO.CULTURES INFO.DATACOVERAGEDEFINITIONS INFO.DATASOURCES INFO.DELTATABLEMETADATASTORAGES INFO.DEPENDENCIES INFO.DETAILROWSDEFINITIONS INFO.DICTIONARYSTORAGES + \ INFO.EXCLUDEDARTIFACTS INFO.EXPRESSIONS INFO.EXTENDEDPROPERTIES INFO.FORMATSTRINGDEFINITIONS INFO.FUNCTIONS INFO.GENERALSEGMENTMAPSEGMENTMETADATASTORAGES INFO.GROUPBYCOLUMNS + \ INFO.HIERARCHIES INFO.HIERARCHYSTORAGES INFO.KPIS INFO.LEVELS INFO.LINGUISTICMETADATA INFO.MEASURES INFO.MODEL + \ INFO.OBJECTTRANSLATIONS INFO.PARQUETFILESTORAGES INFO.PARTITIONS INFO.PARTITIONSTORAGES INFO.PERSPECTIVECOLUMNS INFO.PERSPECTIVEHIERARCHIES INFO.PERSPECTIVEMEASURES + \ INFO.PERSPECTIVES INFO.PERSPECTIVETABLES INFO.PROPERTIES INFO.QUERYGROUPS INFO.REFRESHPOLICIES INFO.RELATEDCOLUMNDETAILS INFO.RELATIONSHIPINDEXSTORAGES + \ INFO.RELATIONSHIPS INFO.RELATIONSHIPSTORAGES INFO.ROLEMEMBERSHIPS INFO.ROLES INFO.SEGMENTMAPSTORAGES INFO.SEGMENTSTORAGES INFO.STORAGEFILES + \ INFO.STORAGEFOLDERS INFO.STORAGETABLECOLUMNS INFO.STORAGETABLECOLUMNSEGMENTS INFO.STORAGETABLES INFO.TABLEPERMISSIONS INFO.TABLES INFO.TABLESTORAGES + \ INFO.VARIATIONS INFO.VIEW.COLUMNS INFO.VIEW.MEASURES INFO.VIEW.RELATIONSHIPS INFO.VIEW.TABLES INT INTERSECT + \ INTRATE IPMT ISAFTER ISBLANK ISCROSSFILTERED ISEMPTY ISERROR + \ ISEVEN ISFILTERED ISINSCOPE ISLOGICAL ISNONTEXT ISNUMBER ISO.CEILING + \ ISODD ISONORAFTER ISPMT ISSELECTEDMEASURE ISSUBTOTAL ISTEXT KEEPFILTERS + \ LAST LASTDATE LCM LEFT LEN LINEST LINESTX + \ LN LOG LOG10 LOOKUPVALUE LOWER MATCHBY MAX + \ MAXA MAXX MDURATION MEDIAN MEDIANX MID MIN + \ MINA MINUTE MINX MOD MONTH MOVINGAVERAGE MROUND + \ NATURALINNERJOIN NATURALLEFTOUTERJOIN NETWORKDAYS NEXT NEXTDAY NEXTMONTH NEXTQUARTER + \ NEXTYEAR NOMINAL NONVISUAL NORM.DIST NORM.INV NORM.S.DIST NORM.S.INV + \ NOT NOW NPER ODD ODDFPRICE ODDFYIELD ODDLPRICE + \ ODDLYIELD OFFSET OPENINGBALANCEMONTH OPENINGBALANCEQUARTER OPENINGBALANCEYEAR OR ORDERBY + \ PARALLELPERIOD PARTITIONBY PATH PATHCONTAINS PATHITEM PATHITEMREVERSE PATHLENGTH + \ PDURATION PERCENTILE.EXC PERCENTILE.INC PERCENTILEX.EXC PERCENTILEX.INC PERMUT PI + \ PMT POISSON.DIST POWER PPMT PREVIOUS PREVIOUSDAY PREVIOUSMONTH + \ PREVIOUSQUARTER PREVIOUSYEAR PRICE PRICEDISC PRICEMAT PRODUCT PRODUCTX + \ PV QUARTER QUOTIENT RADIANS RAND RANDBETWEEN RANGE + \ RANK RANK.EQ RANKX RATE RECEIVED RELATED RELATEDTABLE + \ REMOVEFILTERS REPLACE REPT RIGHT ROLLUP ROLLUPADDISSUBTOTAL ROLLUPGROUP + \ ROLLUPISSUBTOTAL ROUND ROUNDDOWN ROUNDUP ROW ROWNUMBER RRI + \ RUNNINGSUM SAMEPERIODLASTYEAR SAMPLE SEARCH SECOND SELECTCOLUMNS SELECTEDMEASURE + \ SELECTEDMEASUREFORMATSTRING SELECTEDMEASURENAME SELECTEDVALUE SIGN SIN SINH SLN + \ SQRT SQRTPI STARTOFMONTH STARTOFQUARTER STARTOFYEAR STDEV.P STDEV.S + \ STDEVX.P STDEVX.S SUBSTITUTE SUBSTITUTEWITHINDEX SUM SUMMARIZE SUMMARIZECOLUMNS + \ SUMX SWITCH SYD T.DIST T.DIST.2T T.DIST.RT T.INV + \ T.INV.2t TAN TANH TBILLEQ TBILLPRICE TBILLYIELD TIME + \ TIMEVALUE TOCSV TODAY TOJSON TOPN TOTALMTD TOTALQTD + \ TOTALYTD TREATAS TRIM TRUE TRUNC Table Constructor UNICHAR + \ UNICODE UNION UPPER USERCULTURE USERELATIONSHIP USERNAME USEROBJECTID + \ USERPRINCIPALNAME UTCNOW UTCTODAY VALUE VALUES VAR.P VAR.S + \ VARX.P VARX.S VDB WEEKDAY WEEKNUM WINDOW XIRR + \ XNPV YEAR YEARFRAC YIELD YIELDDISC YIELDMAT + +" CONTAINS is a vim syntax keyword and can't be a defined keyword +syn match daxFunction "CONTAINS" + +" Numbers +" integer number, or floating point number without a dot. +syn match daxNumber "\<\d\+\>" +" floating point number, with dot +syn match daxNumber "\<\d\+\.\d*\>" + +syn match daxFloat "[-+]\=\<\d\+[eE][\-+]\=\d\+" +syn match daxFloat "[-+]\=\<\d\+\.\d*\([eE][\-+]\=\d\+\)\=" +syn match daxFloat "[-+]\=\<\.\d\+\([eE][\-+]\=\d\+\)\=" + +" String and Character constants +syn region daxString start=+"+ end=+"+ + +" DAX Table and Column names +syn region daxTable start=+'+ms=s+1 end=+'+me=e-1 +syn region daxColumn matchgroup=daxParen start=/\[/ end=/\]/ + +" Operators +syn match daxOperator "+" +syn match daxOperator "-" +syn match daxOperator "*" +syn match daxOperator "/" +syn match daxOperator "\^" +syn match daxOperator "\ NOT(\s\|\\)" +syn match daxOperator "\ IN\ " +syn match daxOperator "&&" +syn match daxOperator "&" +syn match daxOperator "\\|\\|" +syn match daxOperator "[<>]=\=" +syn match daxOperator "<>" +syn match daxOperator "=" +syn match daxOperator ">" +syn match daxOperator "<" + +" Comments +syn region daxComment start="\(^\|\s\)\//" end="$" contains=daxTodo +syn region daxComment start="/\*" end="\*/" contains=daxTodo + +" Define highlighting +hi def link daxComment Comment +hi def link daxNumber Number +hi def link daxFloat Float +hi def link daxString String +hi def link daxStatement Keyword +hi def link daxOperator Operator +hi def link daxFunction Function +hi def link daxTable Number +hi def link daxColumn Statement +hi def link daxParen Delimiter +hi def link daxTodo Todo + +let b:current_syntax = "dax" + +let &cpo = s:keepcpo +unlet! s:keepcpo + +" vim: ts=8 diff --git a/test/functional/lua/hl_spec.lua b/test/functional/lua/hl_spec.lua index 12be01e0a5..f17442912a 100644 --- a/test/functional/lua/hl_spec.lua +++ b/test/functional/lua/hl_spec.lua @@ -139,6 +139,80 @@ describe('vim.hl.range', function() | ]]) end) + + it('shows multiple highlights with different timeouts simultaneously', function() + local timeout1 = 300 + local timeout2 = 600 + exec_lua(function() + local ns = vim.api.nvim_create_namespace('') + vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { timeout = timeout1 }) + vim.hl.range(0, ns, 'Search', { 2, 6 }, { 3, 5 }, { timeout = timeout2 }) + end) + screen:expect({ + grid = [[ + {10:^asdfghjkl}{100:$} | + {10:«口=口»}{100:$} | + {10:qwertyuiop}{100:$} | + {10:口口=口口}{1:$} | + zxcvbnm{1:$} | + | + ]], + timeout = timeout1 / 3, + }) + screen:expect({ + grid = [[ + ^asdfghjkl{1:$} | + «口=口»{1:$} | + qwerty{10:uiop}{100:$} | + {10:口口}=口口{1:$} | + zxcvbnm{1:$} | + | + ]], + timeout = timeout1 + ((timeout2 - timeout1) / 3), + }) + screen:expect([[ + ^asdfghjkl{1:$} | + «口=口»{1:$} | + qwertyuiop{1:$} | + 口口=口口{1:$} | + zxcvbnm{1:$} | + | + ]]) + end) + + it('allows cancelling a highlight that has not timed out', function() + exec_lua(function() + local timeout = 3000 + local range_timer + local range_hl_clear + local ns = vim.api.nvim_create_namespace('') + range_timer, range_hl_clear = vim.hl.range( + 0, + ns, + 'Search', + { 0, 0 }, + { 4, 0 }, + { timeout = timeout } + ) + if range_timer and not range_timer:is_closing() then + range_timer:close() + assert(range_hl_clear) + range_hl_clear() + range_hl_clear() -- Exercise redundant call + end + end) + screen:expect({ + grid = [[ + ^asdfghjkl{1:$} | + «口=口»{1:$} | + qwertyuiop{1:$} | + 口口=口口{1:$} | + zxcvbnm{1:$} | + | + ]], + unchanged = true, + }) + end) end) describe('vim.hl.on_yank', function() @@ -184,9 +258,9 @@ describe('vim.hl.on_yank', function() eq({ win }, api.nvim__ns_get(ns).wins) command('wincmd w') eq({ win }, api.nvim__ns_get(ns).wins) - -- Use a new vim.hl.range() call to cancel the previous timer + -- Use a new vim.hl.on_yank() call to cancel the previous timer exec_lua(function() - vim.hl.range(0, ns, 'Search', { 0, 0 }, { 0, 0 }, { timeout = 0 }) + vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) end) end) @@ -209,9 +283,9 @@ describe('vim.hl.on_yank', function() eq({ win }, api.nvim__ns_get(ns).wins) command('wincmd w') eq({ win }, api.nvim__ns_get(ns).wins) - -- Use a new vim.hl.range() call to cancel the previous timer + -- Use a new vim.hl.on_yank() call to cancel the previous timer exec_lua(function() - vim.hl.range(0, ns, 'Search', { 0, 0 }, { 0, 0 }, { timeout = 0 }) + vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) end) end) @@ -246,5 +320,9 @@ describe('vim.hl.on_yank', function() {1:~ }| | ]]) + -- Use a new vim.hl.on_yank() call to cancel the previous timer + exec_lua(function() + vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) + end) end) end) diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index cd3549fc8a..db83787588 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -38,7 +38,7 @@ describe('vim.secure', function() end) it('works', function() - local screen = Screen.new(80, 8) + local screen = Screen.new(500, 8) screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { bold = true, reverse = true }, @@ -46,129 +46,99 @@ describe('vim.secure', function() [4] = { reverse = true }, }) - --- XXX: screen:expect() may fail if this path is too long. local cwd = fn.getcwd() + if #cwd + 23 > 500 then + pending('path too long') + return + end -- Need to use feed_command instead of exec_lua because of the confirmation prompt feed_command([[lua vim.secure.read('Xfile')]]) - screen:expect { - grid = [[ - | - {1:~ }|*3 - {2: }| - :lua vim.secure.read('Xfile') | - {3:]] - .. cwd - .. pathsep - .. [[Xfile is not trusted.}{MATCH:%s+}| - {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | - ]], - } + screen:expect([[ + {MATCH: +}| + {1:~{MATCH: +}}|*3 + {2:{MATCH: +}}| + :lua vim.secure.read('Xfile'){MATCH: +}| + {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH: +}| + {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^{MATCH: +}| + ]]) feed('d') - screen:expect { - grid = [[ - ^ | - {1:~ }|*6 - | - ]], - } + screen:expect([[ + ^{MATCH: +}| + {1:~{MATCH: +}}|*6 + {MATCH: +}| + ]]) - local trust = read_file(stdpath('state') .. pathsep .. 'trust') + local trust = assert(read_file(stdpath('state') .. pathsep .. 'trust')) eq(string.format('! %s', cwd .. pathsep .. 'Xfile'), vim.trim(trust)) eq(vim.NIL, exec_lua([[return vim.secure.read('Xfile')]])) os.remove(stdpath('state') .. pathsep .. 'trust') feed_command([[lua vim.secure.read('Xfile')]]) - screen:expect { - grid = [[ - | - {1:~ }|*3 - {2: }| - :lua vim.secure.read('Xfile') | - {3:]] - .. cwd - .. pathsep - .. [[Xfile is not trusted.}{MATCH:%s+}| - {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | - ]], - } + screen:expect([[ + {MATCH: +}| + {1:~{MATCH: +}}|*3 + {2:{MATCH: +}}| + :lua vim.secure.read('Xfile'){MATCH: +}| + {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH: +}| + {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^{MATCH: +}| + ]]) feed('a') - screen:expect { - grid = [[ - ^ | - {1:~ }|*6 - | - ]], - } - - local hash = fn.sha256(read_file('Xfile')) - trust = read_file(stdpath('state') .. pathsep .. 'trust') + screen:expect([[ + ^{MATCH: +}| + {1:~{MATCH: +}}|*6 + {MATCH: +}| + ]]) + + local hash = fn.sha256(assert(read_file('Xfile'))) + trust = assert(read_file(stdpath('state') .. pathsep .. 'trust')) eq(string.format('%s %s', hash, cwd .. pathsep .. 'Xfile'), vim.trim(trust)) eq(vim.NIL, exec_lua([[vim.secure.read('Xfile')]])) os.remove(stdpath('state') .. pathsep .. 'trust') feed_command([[lua vim.secure.read('Xfile')]]) - screen:expect { - grid = [[ - | - {1:~ }|*3 - {2: }| - :lua vim.secure.read('Xfile') | - {3:]] - .. cwd - .. pathsep - .. [[Xfile is not trusted.}{MATCH:%s+}| - {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | - ]], - } + screen:expect([[ + {MATCH: +}| + {1:~{MATCH: +}}|*3 + {2:{MATCH: +}}| + :lua vim.secure.read('Xfile'){MATCH: +}| + {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH: +}| + {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^{MATCH: +}| + ]]) feed('i') - screen:expect { - grid = [[ - ^ | - {1:~ }|*6 - | - ]], - } + screen:expect([[ + ^{MATCH: +}| + {1:~{MATCH: +}}|*6 + {MATCH: +}| + ]]) -- Trust database is not updated - trust = read_file(stdpath('state') .. pathsep .. 'trust') - eq(nil, trust) + eq(nil, read_file(stdpath('state') .. pathsep .. 'trust')) feed_command([[lua vim.secure.read('Xfile')]]) - screen:expect { - grid = [[ - | - {1:~ }|*3 - {2: }| - :lua vim.secure.read('Xfile') | - {3:]] - .. cwd - .. pathsep - .. [[Xfile is not trusted.}{MATCH:%s+}| - {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | - ]], - } + screen:expect([[ + {MATCH: +}| + {1:~{MATCH: +}}|*3 + {2:{MATCH: +}}| + :lua vim.secure.read('Xfile'){MATCH: +}| + {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH: +}| + {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^{MATCH: +}| + ]]) feed('v') - screen:expect { - grid = [[ - ^let g:foobar = 42 | - {1:~ }|*2 - {2:]] - .. fn.fnamemodify(cwd, ':~') - .. pathsep - .. [[Xfile [RO]{MATCH:%s+}}| - | - {1:~ }| - {4:[No Name] }| - | - ]], - } + screen:expect([[ + ^let g:foobar = 42{MATCH: +}| + {1:~{MATCH: +}}|*2 + {2:]] .. fn.fnamemodify(cwd, ':~') .. pathsep .. [[Xfile [RO]{MATCH: +}}| + {MATCH: +}| + {1:~{MATCH: +}}| + {4:[No Name]{MATCH: +}}| + {MATCH: +}| + ]]) -- Trust database is not updated - trust = read_file(stdpath('state') .. pathsep .. 'trust') - eq(nil, trust) + eq(nil, read_file(stdpath('state') .. pathsep .. 'trust')) -- Cannot write file pcall_err(command, 'write') diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua index f33819f364..ca005d9f12 100644 --- a/test/functional/plugin/shada_spec.lua +++ b/test/functional/plugin/shada_spec.lua @@ -3170,8 +3170,8 @@ describe('syntax/shada.vim', function() month = htsnum(os.date('%m', 0)), day = htsnum(os.date('%d', 0)), hour = htsnum(os.date('!%H', 0)), - minute = htsnum(os.date('%M', 0)), - second = htsnum(os.date('%S', 0)), + minute = htsnum(os.date('!%M', 0)), + second = htsnum(os.date('!%S', 0)), } local msh = function(s) return { diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index 4e54ff598f..8347178f79 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -213,6 +213,7 @@ func s:GetFilenameChecks() abort \ 'dafny': ['file.dfy'], \ 'dart': ['file.dart', 'file.drt'], \ 'datascript': ['file.ds'], + \ 'dax': ['file.dax'], \ 'dcd': ['file.dcd'], \ 'deb822sources': ['/etc/apt/sources.list.d/file.sources', 'any/etc/apt/sources.list.d/file.sources'], \ 'debchangelog': ['changelog.Debian', 'changelog.dch', 'NEWS.Debian', 'NEWS.dch', '/debian/changelog'], |