From 24183950e183a6908f21142905ecbcf424b7f0f5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Aug 2026 08:47:30 +0800 Subject: [PATCH] vim-patch:5d41506: runtime(sh): Selectively suppress matching syntax errors (#41302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a refinement upon "g:sh_no_error", support not matching particular classes of syntax errors. Look up syntax rule names and list them with: ‐----------------------------------------------------------- let g:sh_no_error_rules = ["shCurlyError", "shParenError"] ‐----------------------------------------------------------- closes: vim/vim#20935 https://github.com/vim/vim/commit/5d41506eb4895fbf0b6ccf4067c7f6e3c8ac568b Co-authored-by: Aliaksei Budavei <0x000c70@gmail.com> --- runtime/doc/syntax.txt | 13 ++-- runtime/syntax/sh.vim | 138 ++++++++++++++++++++++------------------- 2 files changed, 83 insertions(+), 68 deletions(-) diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index bbd5c11971..7c43f14096 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -3218,12 +3218,15 @@ reduce this, the "sh_maxlines" internal variable can be set. Example: > The default is to use the twice sh_minlines. Set it to a smaller number to speed up displaying. The disadvantage is that highlight errors may appear. -syntax/sh.vim tries to flag certain problems as errors; usually things like -unmatched "]", "done", "fi", etc. If you find the error handling problematic -for your purposes, you may suppress such error highlighting by putting -the following line in your .vimrc: > +Unmatched "]", "done", "fi", etc., are highlighted as errors by default. If +you find this error handling problematic, you may suppress it with: > - let g:sh_no_error= 1 + let g:sh_no_error = 1 +< +As a refinement, you may suppress particular classes of errors by looking up +their syntax rule names and listing them with: > + + let g:sh_no_error_rules = ["shCurlyError", "shParenError"] < *sh-embed* *sh-awk* diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim index 901923b0d3..162a7750c9 100644 --- a/runtime/syntax/sh.vim +++ b/runtime/syntax/sh.vim @@ -3,7 +3,7 @@ " Maintainer: This runtime file is looking for a new maintainer. " Previous Maintainers: Charles E. Campbell " Lennart Schultz -" Last Change: 2026 Aug 06 by Vim Project +" Last Change: 2026 Aug 13 by Vim Project " Version: 208 " Former URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH " For options and settings, please use: :help ft-sh-syntax @@ -189,6 +189,30 @@ else com! -nargs=* ShFoldIfDoFor endif +" Set up syntax error commands for shell {{{1 +" ====================================== +if exists("g:sh_no_error_rules") && type(g:sh_no_error_rules) == type([]) + fun! s:ScanAndCondExecSynErrCmd(idx, cmd) abort + let parts = matchlist(a:cmd, '\(\(\S\+\)\s\+\(\S\+\)\s*\)\{2}') + " Do nothing for matchable names listed in "g:sh_no_error_rules". + if len(parts) < a:idx || index(g:sh_no_error_rules, parts[a:idx]) < 0 + exec a:cmd + endif + endfun +elseif exists("g:sh_no_error") + fun! s:ScanAndCondExecSynErrCmd(_, __) abort + endfun +else + fun! s:ScanAndCondExecSynErrCmd(_, cmd) abort + exec a:cmd + endfun +endif + +" Read shFooError from "syn match shFooError ''" etc. +com! -nargs=+ ShDefSynErrRule call s:ScanAndCondExecSynErrCmd(2, ) +" Read shFooError from "hi def link shFooError Error". +com! -nargs=+ ShLinkSynErrGroup call s:ScanAndCondExecSynErrCmd(3, ) + " Generate bracket expression items {{{1 " ================================= " Note that the following function can be invoked as many times as necessary @@ -323,20 +347,18 @@ endif " Error Codes: {{{1 " ============ -if !exists("g:sh_no_error") - syn match shDoError "\" - syn match shIfError "\" - syn match shInError "\" - syn match shCaseError ";;" - syn match shEsacError "\" - syn match shCurlyError "}" - syn match shParenError ")" - syn match shOK '\.\(done\|fi\|in\|esac\)' - if exists("b:is_kornshell") || exists("b:is_bash") - syn match shDTestError "]]" - endif - syn match shTestError "]" +ShDefSynErrRule syn match shDoError "\" +ShDefSynErrRule syn match shIfError "\" +ShDefSynErrRule syn match shInError "\" +ShDefSynErrRule syn match shCaseError ";;" +ShDefSynErrRule syn match shEsacError "\" +ShDefSynErrRule syn match shCurlyError "}" +ShDefSynErrRule syn match shParenError ")" +ShDefSynErrRule syn match shOK '\.\%(done\|fi\|in\|esac\)' +if exists("b:is_kornshell") || exists("b:is_bash") + ShDefSynErrRule syn match shDTestError "]]" endif +ShDefSynErrRule syn match shTestError "]" " Options: {{{1 " ==================== @@ -427,8 +449,8 @@ ShFoldIfDoFor syn region shCaseEsac matchgroup=shConditional start="\" en syn keyword shCaseIn contained skipwhite skipnl in nextgroup=shCase,shCaseStart,shCaseBar,shComment,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote if exists("b:is_bash") || (exists("b:is_kornshell") && !exists("b:is_ksh88")) syn region shCaseExSingleQuote matchgroup=shQuote start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial,shSpecial skipwhite skipnl nextgroup=shCaseBar contained -elseif !exists("g:sh_no_error") - syn region shCaseExSingleQuote matchgroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial skipwhite skipnl nextgroup=shCaseBar contained +else + ShDefSynErrRule syn region shCaseExSingleQuote matchgroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial skipwhite skipnl nextgroup=shCaseBar contained endif syn region shCaseSingleQuote matchgroup=shQuote start=+'+ end=+'+ contains=shStringSpecial skipwhite skipnl nextgroup=shCaseBar contained syn region shCaseDoubleQuote matchgroup=shQuote start=+"+ skip=+\\\\\|\\.+ end=+"+ contains=@shDblQuoteList,shStringSpecial skipwhite skipnl nextgroup=shCaseBar contained @@ -472,8 +494,8 @@ if exists("b:is_kornshell") || exists("b:is_bash") || exists("b:is_posix") syn region shArithmetic matchgroup=shArithRegion start="\$\[" skip='\\\\\|\\.' end="\]" contains=@shArithList syn match shSkipInitWS contained "^\s\+" syn region shArithParen matchgroup=shArithRegion contained start="(" end=")" contains=@shArithParenList -elseif !exists("g:sh_no_error") - syn region shCommandSub matchgroup=Error start="\$(" end=")" contains=@shCommandSubList +else + ShDefSynErrRule syn region shCommandSub matchgroup=Error start="\$(" end=")" contains=@shCommandSubList endif syn region shCmdParenRegion matchgroup=shCmdSubRegion start="((\@!" skip='\\\\\|\\.' end=")" contains=@shCommandSubList @@ -534,9 +556,9 @@ if exists("b:is_bash") || exists("b:is_kornshell") syn match shSpecial "^\(\\\\\)*\zs\\\o\o\o\|\\x\x\x\|\\c[^"]\|\\[abefnrtv]" contained syn region shExSingleQuote matchgroup=shQuote start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial,shSpecial nextgroup=shSpecialNxt syn region shExDoubleQuote matchgroup=shQuote start=+\$"+ skip=+\\\\\|\\.\|\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,shSpecial nextgroup=shSpecialNxt -elseif !exists("g:sh_no_error") - syn region shExSingleQuote matchGroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial - syn region shExDoubleQuote matchGroup=Error start=+\$"+ skip=+\\\\\|\\.+ end=+"+ contains=shStringSpecial +else + ShDefSynErrRule syn region shExSingleQuote matchgroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial + ShDefSynErrRule syn region shExDoubleQuote matchgroup=Error start=+\$"+ skip=+\\\\\|\\.+ end=+"+ contains=shStringSpecial endif syn region shSingleQuote matchgroup=shQuote start=+'+ end=+'+ contains=@Spell nextgroup=shSpecialStart,shSpecialSQ syn region shDoubleQuote matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@()" transparent nextgroup=shVariable " Claim commented out function declaration headers. syn match shFunctionComment "^\s*\zs\ze#" transparent nextgroup=shComment - - if !exists("g:sh_no_error") - syn match shFunctionNameAssignError "\%#=1\%(\%(\<\h\w*\)\@>=\)\%(\%(\w\+\)\@>=\=\)\+()" skipwhite skipnl nextgroup=shExpr,shSubSh - syn match shFunctionNameCommentError "#" contained - endif + ShDefSynErrRule syn match shFunctionNameAssignError "\%#=1\%(\%(\<\h\w*\)\@>=\)\%(\%(\w\+\)\@>=\=\)\+()" skipwhite skipnl nextgroup=shExpr,shSubSh + ShDefSynErrRule syn match shFunctionNameCommentError "#" contained elseif exists("b:is_ksh88") " AT&T ksh88 syn match shFunctionCmdOne "^\s*\zs\h\w*\s*()\ze\_s*\%(\%(for\|case\|select\|if\|while\|until\)\>\|\[\[\s\|((\)" skipwhite skipnl nextgroup=@shFunctionCmds contains=shFunctionParens @@ -695,17 +714,13 @@ else syn match shFunctionFour "\<\h\w*\>\s*()\ze\_s*(" contained skipwhite skipnl nextgroup=shFunctionSubSh contains=shFunctionParens endif -if !exists("g:sh_no_error") - syn match shDoError "\