diff --git a/runtime/autoload/README.txt b/runtime/autoload/README.txt index bca86a2a4c..8cb69f36e8 100644 --- a/runtime/autoload/README.txt +++ b/runtime/autoload/README.txt @@ -17,6 +17,7 @@ htmlcomplete.vim HTML javascriptcomplete.vim Javascript phpcomplete.vim PHP pythoncomplete.vim Python +python3complete.vim Python rubycomplete.vim Ruby syntaxcomplete.vim from syntax highlighting xmlcomplete.vim XML (uses files in the xml directory) diff --git a/runtime/autoload/python3complete.vim b/runtime/autoload/python3complete.vim index ca5707d31f..1f074305f1 100644 --- a/runtime/autoload/python3complete.vim +++ b/runtime/autoload/python3complete.vim @@ -14,6 +14,10 @@ " i.e. "import url" " Continue parsing on invalid line?? " +" v 0.10 by Vim project +" * disables importing local modules, unless the global Vim variable +" g:pythoncomplete_allow_import is set to non-zero +" " v 0.9 " * Fixed docstring parsing for classes and functions " * Fixed parsing of *args and **kwargs type arguments @@ -132,11 +136,20 @@ class Completer(object): def evalsource(self,text,line=0): sc = self.parser.parse(text,line) + try: allow_imports = int( + vim.eval("get(g:, 'pythoncomplete_allow_import', 0)")) + except Exception: + allow_imports = 0 src = sc.get_code() dbg("source: %s" % src) try: exec(src,self.compldict) except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1])) for l in sc.locals: + # Executing import/from statements harvested from the buffer runs + # arbitrary package code; only do so when the user opted in. + if not allow_imports and (l.startswith('import') + or l.startswith('from ')): + continue try: exec(l,self.compldict) except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l)) @@ -300,13 +313,11 @@ class Scope(object): def get_code(self): str = "" if len(self.docstr) > 0: str += '"""'+self.docstr+'"""\n' - for l in self.locals: - if l.startswith('import'): str += l+'\n' str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n' for sub in self.subscopes: str += sub.get_code() for l in self.locals: - if not l.startswith('import'): str += l+'\n' + if not l.startswith('import') and not l.startswith('from '): str += l+'\n' return str diff --git a/runtime/autoload/pythoncomplete.vim b/runtime/autoload/pythoncomplete.vim index e9233e1d49..e9fd9dc490 100644 --- a/runtime/autoload/pythoncomplete.vim +++ b/runtime/autoload/pythoncomplete.vim @@ -12,6 +12,10 @@ " i.e. "import url" " Continue parsing on invalid line?? " +" v 0.10 by Vim project +" * disables importing local modules, unless the global Vim variable +" g:pythoncomplete_allow_import is set to non-zero +" " v 0.9 " * Fixed docstring parsing for classes and functions " * Fixed parsing of *args and **kwargs type arguments @@ -146,11 +150,20 @@ class Completer(object): def evalsource(self,text,line=0): sc = self.parser.parse(text,line) + try: allow_imports = int( + vim.eval("get(g:, 'pythoncomplete_allow_import', 0)")) + except Exception: + allow_imports = 0 src = sc.get_code() dbg("source: %s" % src) try: exec(src) in self.compldict except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1])) for l in sc.locals: + # Executing import/from statements harvested from the buffer runs + # arbitrary package code; only do so when the user opted in. + if not allow_imports and (l.startswith('import') + or l.startswith('from ')): + continue try: exec(l) in self.compldict except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l)) @@ -315,13 +328,11 @@ class Scope(object): def get_code(self): str = "" if len(self.docstr) > 0: str += '"""'+self.docstr+'"""\n' - for l in self.locals: - if l.startswith('import'): str += l+'\n' str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n' for sub in self.subscopes: str += sub.get_code() for l in self.locals: - if not l.startswith('import'): str += l+'\n' + if not l.startswith('import') and not l.startswith('from '): str += l+'\n' return str diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index ca40c76ce4..2954de8e2b 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -137,6 +137,7 @@ variables can be used to overrule the filetype used for certain extensions: file name variable ~ `*.app` g:filetype_app + `*.as` g:filetype_as `*.asa` g:filetype_asa |ft-aspperl-syntax| |ft-aspvbs-syntax| `*.asm` g:asmsyntax |ft-asm-syntax| @@ -910,6 +911,20 @@ By default the following options are set, in accordance with PEP8: > To disable this behavior, set the following variable in your vimrc: > let g:python_recommended_style = 0 +< +Python omni-completion |compl-omni| is provided by python3complete.vim (or +pythoncomplete.vim) for Nvim with the |python3| provider. +By default it does not inspect the import / from statements found in the +buffer. This means completion of names defined in the buffer itself (classes, +functions, variables) works, but completion of members of imported modules is +not offered. + +To enable completion of imported module members, set: > + let g:pythoncomplete_allow_import = 1 +< +WARNING: enabling this causes omni-completion to execute the import statements +found in the buffer through Python's import machinery, which runs the imported +modules' top-level code. Only enable this for code you trust. POWERSHELL diff --git a/runtime/indent/karel.vim b/runtime/indent/karel.vim new file mode 100644 index 0000000000..9913607570 --- /dev/null +++ b/runtime/indent/karel.vim @@ -0,0 +1,121 @@ +" Vim indent file +" Language: Fanuc Karel +" Maintainer: Patrick Meiser-Knosowski +" Version: 1.0.0 +" Last Change: 28. May 2026 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal nolisp +setlocal nocindent +setlocal nosmartindent +setlocal autoindent +setlocal indentexpr=GetKarelIndent() +setlocal indentkeys=!^F,o,O,=~end,0=~else,0=~case,0=~until,0=~const,0=~type,0=~var,0=~begin +let b:undo_indent = "setlocal lisp< cindent< smartindent< autoindent< indentexpr< indentkeys<" + +if get(g:,'karelSpaceIndent',1) + " Use spaces, not tabs, for indention, 2 is enough. + " More or even tabs would waste valuable space on the teach pendant. + setlocal softtabstop=2 + setlocal shiftwidth=2 + setlocal expandtab + setlocal shiftround + let b:undo_indent = b:undo_indent." softtabstop< shiftwidth< expandtab< shiftround<" +endif + +" Only define the function once. +if exists("*GetKarelIndent") + finish +endif +let s:keepcpo = &cpo +set cpo&vim + +function GetKarelIndent() abort + + let currentLine = getline(v:lnum) + if currentLine =~? '\v^--' && !get(g:, 'karelCommentIndent', 0) + " If current line has a -- in column 1, keep zero indent. + " This may be useful if code is commented out at the first column. + return 0 + endif + + " Find a non-blank line above the current line. + let preNoneBlankLineNum = s:karelPreNoneBlank(v:lnum - 1) + if preNoneBlankLineNum == 0 + " At the start of the file use zero indent. + return 0 + endif + + let preNoneBlankLine = getline(preNoneBlankLineNum) + let ind = indent(preNoneBlankLineNum) + + " Define add 'shiftwidth' pattern + let addShiftwidthPattern = '\v^\s*(' + let addShiftwidthPattern ..= 'if>|while>|for>|using>|condition>|.*' + let addShiftwidthPattern ..= '|else>' + let addShiftwidthPattern ..= '|case>' + let addShiftwidthPattern ..= '|repeat>' + let addShiftwidthPattern ..= '|const>' + let addShiftwidthPattern ..= '|type>' + let addShiftwidthPattern ..= '|var>' + let addShiftwidthPattern ..= '|begin>' + let addShiftwidthPattern ..= '|routine>' + if get(g:, 'karelIndentBetweenPrg', 1) + let addShiftwidthPattern ..= '|program>' + endif + let addShiftwidthPattern ..= ')' + + " Define Subtract 'shiftwidth' pattern + let subtractShiftwidthPattern = '\v^\s*(' + let subtractShiftwidthPattern ..= 'end(if|while|for|using|condition|structure)?>' + let subtractShiftwidthPattern ..= '|else>' + let subtractShiftwidthPattern ..= '|case>|endselect>' + let subtractShiftwidthPattern ..= '|until>' + let subtractShiftwidthPattern ..= '|const>' + let subtractShiftwidthPattern ..= '|type>' + let subtractShiftwidthPattern ..= '|var>' + let subtractShiftwidthPattern ..= '|begin>' + let subtractShiftwidthPattern ..= ')' + + " Add shiftwidth + if preNoneBlankLine =~? addShiftwidthPattern + let ind += &sw + endif + + " Subtract shiftwidth + if currentLine =~? subtractShiftwidthPattern + let ind = ind - &sw + endif + + " First case after a select gets the indent of the select. + if currentLine =~? '\v^\s*case>' + \&& preNoneBlankLine =~? '\v^\s*select>' + let ind = ind + &sw + endif + + return ind +endfunction + +" This function works almost like prevnonblank() but handles &-headers, +" comments and continue instructions like blank lines +function s:karelPreNoneBlank(lnum) abort + + let nPreNoneBlank = prevnonblank(a:lnum) + + while nPreNoneBlank > 0 && getline(nPreNoneBlank) =~? '\v^\s*(\&\w\+|--)' + " Previous none blank line irrelevant. Look further aback. + let nPreNoneBlank = prevnonblank(nPreNoneBlank - 1) + endwhile + + return nPreNoneBlank +endfunction + +let &cpo = s:keepcpo +unlet s:keepcpo + +" vim:sw=2 sts=2 et diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index af27e53fec..92ed432e22 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -275,7 +275,7 @@ local extension = { astro = 'astro', asy = 'asy', atl = 'atlas', - as = 'atlas', + as = detect.as, zed = 'authzed', ahk = 'autohotkey', au3 = 'autoit', @@ -730,6 +730,7 @@ local extension = { JUST = 'just', kl = 'karel', KL = 'karel', + pg = 'kawasaki_as', kdl = 'kdl', kerml = 'kerml', kv = 'kivy', @@ -1190,6 +1191,7 @@ local extension = { sdl = 'sdl', sed = 'sed', sexp = 'sexplib', + sgf = 'sgf', bash = detect.bash, bats = detect.bash, cygport = detect.bash, @@ -1456,6 +1458,7 @@ local extension = { xlc = 'xml', xba = 'xml', slnx = 'xml', + reanim = 'xml', xpm = detect_line1('XPM2', 'xpm2', 'xpm'), xpm2 = 'xpm2', xqy = 'xquery', @@ -1474,6 +1477,7 @@ local extension = { yaml = 'yaml', eyaml = 'yaml', mplstyle = 'yaml', + ksy = 'yaml', kyaml = 'yaml', kyml = 'yaml', grc = detect_line1('<%?xml', 'xml', 'yaml'), diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 49739dba4f..064c23e9ec 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -63,6 +63,20 @@ function M.app(path, bufnr) end end +-- This function checks for Kawasaki robots AS file or atlas file type. +--- @type vim.filetype.mapfn +function M.as(_, bufnr) + if vim.g.filetype_as then + return vim.g.filetype_as + end + for _, line in ipairs(getlines(bufnr, 1, 30)) do + if line:find('^%.NETCONF') then + return 'kawasaki_as' + end + end + return 'atlas' +end + --- @param bufnr integer --- @return boolean local function is_objectscript_routime(bufnr) @@ -2143,6 +2157,8 @@ local function match_from_hashbang(contents, path, dispatch_extension) name = fn.substitute(first_line, [[^#!.*\\s\+\(\i\+\).*]], '\\1', '') elseif matchregex(first_line, [[^#!\s*[^/\\ ]*\>\([^/\\]\|$\)]]) then name = fn.substitute(first_line, [[^#!\s*\([^/\\ ]*\>\).*]], '\\1', '') + elseif matchregex(first_line, [[^#!.*\]]) then + name = fn.substitute(first_line, [[^#!.*\\s\+\(\i\+\).*]], '\\1', '') else name = fn.substitute(first_line, [[^#!\s*\S*[/\\]\(\f\+\).*]], '\\1', '') end @@ -2153,7 +2169,7 @@ local function match_from_hashbang(contents, path, dispatch_extension) name = 'wish' end - if matchregex(name, [[^\(bash\d*\|dash\|ksh\d*\|sh\)\>]]) then + if matchregex(name, [[^\(bash\d*\|d\?ash\|ksh\d*\|sh\)\>]]) then -- Bourne-like shell scripts: bash bash2 dash ksh ksh93 sh return sh(path, contents, first_line) elseif matchregex(name, [[^csh\>]]) then diff --git a/runtime/syntax/karel.vim b/runtime/syntax/karel.vim index 85c78529e6..a9cdc8277d 100644 --- a/runtime/syntax/karel.vim +++ b/runtime/syntax/karel.vim @@ -1,6 +1,6 @@ " Vim syntax file " Language: KAREL -" Last Change: 2024-11-17 +" Last Change: 2026-05-28 " Maintainer: Kirill Morozov " Credits: Jay Strybis for the initial implementation and Patrick Knosowski " for a couple of fixes. @@ -61,10 +61,10 @@ hi def link karelFunction Function syn keyword karelClause EVAL FROM IN WHEN WITH hi def link karelClause Keyword -syn keyword karelConditional IF THEN ELSE ENDIF SELECT ENDSELECT CASE +syn keyword karelConditional IF THEN ELSE ENDIF SELECT ENDSELECT CASE OF hi def link karelConditional Conditional -syn keyword karelRepeat WHILE DO ENDWHILE FOR +syn keyword karelRepeat WHILE DO ENDWHILE FOR TO DOWNTO hi def link karelRepeat Repeat syn keyword karelProcedure ABORT_TASK ACT_SCREEN ACT_TBL ADD_BYNAMEPC ADD_DICT ADD_INTPC ADD_REALPC ADD_STRINGPC APPEND_NODE APPEND_QUEUE diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index eb9e38c917..9268802d8f 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -433,6 +433,7 @@ func s:GetFilenameChecks() abort \ 'julia': ['file.jl'], \ 'just': ['justfile', 'Justfile', '.justfile', 'config.just'], \ 'karel': ['file.kl', 'file.KL'], + \ 'kawasaki_as': ['file.pg'], \ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file', 'Config.in', 'Config.in.host'], \ 'kdl': ['file.kdl'], \ 'kerml': ['file.kerml'], @@ -739,6 +740,7 @@ func s:GetFilenameChecks() abort \ 'services': ['/etc/services', 'any/etc/services'], \ 'setserial': ['/etc/serial.conf', 'any/etc/serial.conf'], \ 'sexplib': ['file.sexp'], + \ 'sgf': ['file.sgf'], \ 'sh': ['.bashrc', '.bash_profile', '.bash-profile', '.bash_logout', '.bash-logout', '.bash_aliases', '.bash-aliases', '.bash_history', '.bash-history', \ '/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh', \ '/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf', 'file.bats', '.ash_history', 'any/etc/neofetch/config.conf', '.xprofile', @@ -984,7 +986,7 @@ func s:GetFilenameChecks() abort \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', \ 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', \ 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd', 'fonts.conf', 'file.xcu', 'file.xlb', 'file.xlc', 'file.xba', 'file.xpr', - \ 'file.xpfm', 'file.spfm', 'file.bxml', 'file.mmi', 'file.slnx', 'Directory.Packages.props', 'Directory.Build.targets', 'Directory.Build.props'], + \ 'file.xpfm', 'file.spfm', 'file.bxml', 'file.mmi', 'file.slnx', 'Directory.Packages.props', 'Directory.Build.targets', 'Directory.Build.props', 'file.reanim'], \ 'xmodmap': ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'], \ 'xpm': ['file.xpm'], \ 'xpm2': ['file.xpm2'], @@ -994,7 +996,7 @@ func s:GetFilenameChecks() abort \ 'xslt': ['file.xsl', 'file.xslt'], \ 'yacc': ['file.yy', 'file.yxx', 'file.y++'], \ 'yaml': ['file.yaml', 'file.yml', 'file.eyaml', 'file.kyaml', 'file.kyml', 'any/.bundle/config', '.clangd', '.clang-format', '.clang-tidy', 'file.mplstyle', 'matplotlibrc', 'yarn.lock', - \ '/home/user/.kube/config', '/home/user/.kube/kuberc', '.condarc', 'condarc', '.mambarc', 'mambarc', 'pixi.lock', 'buf.lock'], + \ '/home/user/.kube/config', '/home/user/.kube/kuberc', '.condarc', 'condarc', '.mambarc', 'mambarc', 'pixi.lock', 'buf.lock', 'file.ksy'], \ 'yang': ['file.yang'], \ 'yara': ['file.yara', 'file.yar'], \ 'yuck': ['file.yuck'], @@ -1086,7 +1088,10 @@ func s:GetScriptChecks() abort \ ['#!/path/bash2'], \ ['#!/path/dash'], \ ['#!/path/ksh'], - \ ['#!/path/ksh93']], + \ ['#!/path/ksh93'], + \ ['#!/path/ash'], + \ ['#!/path/busybox ash'], + \ ['#!/path/busybox sh']], \ 'csh': [['#!/path/csh']], \ 'tcsh': [['#!/path/tcsh']], \ 'zsh': [['#!/path/zsh']], @@ -3526,4 +3531,19 @@ func Test_cucumber_code_injection() filetype plugin off endfunc +func Test_as_file() + filetype on + + call writefile([], 'Xfile.as', 'D') + split Xfile.as + call assert_equal('atlas', &filetype) + bwipe! + call writefile(['', '.NETCONF'], 'Xfile.as', 'D') + split Xfile.as + call assert_equal('kawasaki_as', &filetype) + bwipe! + + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab