1
0
forked from aniani/vim

patch 9.1.1307: make syntax does not reliably detect different flavors

Problem:  GNU extensions, such as `ifeq` and `wildcard` function, are
          highlighted in BSDmakefile
Solution: detect BSD, GNU, or Microsoft implementation according to
	  filename, user-defined global variables, or file contents

closes: #17089

Co-authored-by: Roland Hieber <rohieb@users.noreply.github.com>
Signed-off-by: Eisuke Kawashima <e-kwsm@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Eisuke Kawashima 2025-04-15 19:20:06 +02:00 committed by Christian Brabandt
parent 32f2bb6e1e
commit f35bd76b31
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
7 changed files with 126 additions and 28 deletions

View File

@ -557,17 +557,47 @@ export def FTm()
enddef
export def FTmake()
# Check if it is a Microsoft Makefile
unlet! b:make_microsoft
# Check if it is a BSD, GNU, or Microsoft Makefile
unlet! b:make_flavor
# 1. filename
if expand('%:t') == 'BSDmakefile'
b:make_flavor = 'bsd'
setf make
return
elseif expand('%:t') == 'GNUmakefile'
b:make_flavor = 'gnu'
setf make
return
endif
# 2. user's setting
if exists('g:make_flavor')
b:make_flavor = g:make_flavor
setf make
return
elseif get(g:, 'make_microsoft')
echom "make_microsoft is deprecated; try g:make_flavor = 'microsoft' instead"
b:make_flavor = 'microsoft'
setf make
return
endif
# 3. try to detect a flavor from file content
var n = 1
while n < 1000 && n <= line('$')
var line = getline(n)
if line =~? '^\s*!\s*\(ifn\=\(def\)\=\|include\|message\|error\)\>'
b:make_microsoft = 1
b:make_flavor = 'microsoft'
break
elseif line =~ '^ *ifn\=\(eq\|def\)\>' || line =~ '^ *[-s]\=include\s'
elseif line =~ '^\.\%(export\|error\|for\|if\%(n\=\%(def\|make\)\)\=\|info\|warning\)\>'
b:make_flavor = 'bsd'
break
elseif line =~ '^ *\w\+\s*[!?:+]='
elseif line =~ '^ *\%(ifn\=\%(eq\|def\)\|define\|override\)\>'
b:make_flavor = 'gnu'
break
elseif line =~ '\$[({][a-z-]\+\s\+\S\+' # a function call, e.g. $(shell pwd)
b:make_flavor = 'gnu'
break
endif
n += 1

View File

@ -1,4 +1,4 @@
*filetype.txt* For Vim version 9.1. Last change: 2025 Mar 15
*filetype.txt* For Vim version 9.1. Last change: 2025 Apr 15
VIM REFERENCE MANUAL by Bram Moolenaar
@ -158,6 +158,8 @@ variables can be used to overrule the filetype used for certain extensions:
*.inc g:filetype_inc
*.lsl g:filetype_lsl
*.m g:filetype_m |ft-mathematica-syntax|
*[mM]makefile,*.mk,*.mak,[mM]akefile*
g:make_flavor |ft-make-syntax|
*.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md
g:filetype_md |ft-pandoc-syntax|
*.mod g:filetype_mod

View File

@ -1,4 +1,4 @@
*syntax.txt* For Vim version 9.1. Last change: 2025 Apr 13
*syntax.txt* For Vim version 9.1. Last change: 2025 Apr 15
VIM REFERENCE MANUAL by Bram Moolenaar
@ -2393,11 +2393,16 @@ Comments are also highlighted by default. You can turn this off by using: >
:let make_no_comments = 1
Microsoft Makefile handles variable expansion and comments differently
(backslashes are not used for escape). If you see any wrong highlights
because of this, you can try this: >
There are various Make implementations, which add extensions other than the
POSIX specification and thus are mutually incompatible. If the filename is
BSDmakefile or GNUmakefile, the corresponding implementation is automatically
determined; otherwise vim tries to detect it by the file contents. If you see
any wrong highlights because of this, you can enforce a flavor by setting one
of the following: >
:let make_microsoft = 1
:let g:make_flavor = 'bsd' " or
:let g:make_flavor = 'gnu' " or
:let g:make_flavor = 'microsoft'
MAPLE *maple.vim* *ft-maple-syntax*

View File

@ -3186,7 +3186,7 @@ au BufNewFile,BufRead */etc/sensors.d/[^.]* call s:StarSetf('sensors')
au BufNewFile,BufRead */etc/logcheck/*.d*/* call s:StarSetf('logcheck')
" Makefile
au BufNewFile,BufRead [mM]akefile* call s:StarSetf('make')
au BufNewFile,BufRead [mM]akefile* if expand('<afile>:t') !~ g:ft_ignore_pat | call dist#ft#FTmake() | endif
" Ruby Makefile
au BufNewFile,BufRead [rR]akefile* call s:StarSetf('ruby')

View File

@ -4,6 +4,7 @@
" Previous Maintainer: Claudio Fleiner <claudio@fleiner.com>
" URL: https://github.com/vim/vim/blob/master/runtime/syntax/make.vim
" Last Change: 2022 Nov 06
" 2025 Apr 15 by Vim project: rework Make flavor detection (#17089)
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@ -13,6 +14,9 @@ endif
let s:cpo_save = &cpo
set cpo&vim
" enable GNU extension when b:make_flavor is not set—detection failed or Makefile is POSIX-compliant
let s:make_flavor = 'gnu'
" some special characters
syn match makeSpecial "^\s*[@+-]\+"
syn match makeNextLine "\\\n\s*"
@ -21,14 +25,16 @@ syn match makeNextLine "\\\n\s*"
syn region makeDefine start="^\s*define\s" end="^\s*endef\s*\(#.*\)\?$"
\ contains=makeStatement,makeIdent,makePreCondit,makeDefine
" Microsoft Makefile specials
syn case ignore
syn match makeInclude "^!\s*include\s.*$"
syn match makePreCondit "^!\s*\(cmdswitches\|error\|message\|include\|if\|ifdef\|ifndef\|else\|else\s*if\|else\s*ifdef\|else\s*ifndef\|endif\|undef\)\>"
syn case match
if get(b:, 'make_flavor', s:make_flavor) == 'microsoft'
" Microsoft Makefile specials
syn case ignore
syn match makeInclude "^!\s*include\s.*$"
syn match makePreCondit "^!\s*\(cmdswitches\|error\|message\|include\|if\|ifdef\|ifndef\|else\|else\s*if\|else\s*ifdef\|else\s*ifndef\|endif\|undef\)\>"
syn case match
endif
" identifiers
if exists("b:make_microsoft") || exists("make_microsoft")
if get(b:, 'make_flavor', s:make_flavor) == 'microsoft'
syn region makeIdent start="\$(" end=")" contains=makeStatement,makeIdent
syn region makeIdent start="\${" end="}" contains=makeStatement,makeIdent
else
@ -59,13 +65,31 @@ syn match makeTarget "^[~A-Za-z0-9_./$(){}%*@-][A-Za-z0-9_./\t $(){}%*
\ skipnl nextgroup=makeCommands,makeCommandError
syn region makeSpecTarget transparent matchgroup=makeSpecTarget
\ start="^\.\(SUFFIXES\|PHONY\|DEFAULT\|PRECIOUS\|IGNORE\|SILENT\|EXPORT_ALL_VARIABLES\|KEEP_STATE\|LIBPATTERNS\|NOTPARALLEL\|DELETE_ON_ERROR\|INTERMEDIATE\|POSIX\|SECONDARY\|ONESHELL\)\>\s*:\{1,2}[^:=]"rs=e-1
\ start="^\.\(SUFFIXES\|PHONY\|DEFAULT\|PRECIOUS\|IGNORE\|SILENT\|NOTPARALLEL\|POSIX\)\>\s*:\{1,2}[^:=]"rs=e-1
\ end="[^\\]$" keepend
\ contains=makeIdent,makeSpecTarget,makeNextLine,makeComment skipnl nextGroup=makeCommands
syn match makeSpecTarget "^\.\(SUFFIXES\|PHONY\|DEFAULT\|PRECIOUS\|IGNORE\|SILENT\|EXPORT_ALL_VARIABLES\|KEEP_STATE\|LIBPATTERNS\|NOTPARALLEL\|DELETE_ON_ERROR\|INTERMEDIATE\|POSIX\|SECONDARY\|ONESHELL\)\>\s*::\=\s*$"
syn match makeSpecTarget "^\.\(SUFFIXES\|PHONY\|DEFAULT\|PRECIOUS\|IGNORE\|SILENT\|NOTPARALLEL\|POSIX\)\>\s*::\=\s*$"
\ contains=makeIdent,makeComment
\ skipnl nextgroup=makeCommands,makeCommandError
if get(b:, 'make_flavor', s:make_flavor) == 'bsd'
syn region makeSpecTarget transparent matchgroup=makeSpecTarget
\ start="^\.DELETE_ON_ERROR\>\s*:\{1,2}[^:=]"rs=e-1
\ end="[^\\]$" keepend
\ contains=makeIdent,makeSpecTarget,makeNextLine,makeComment skipnl nextGroup=makeCommands
syn match makeSpecTarget "^\.DELETE_ON_ERROR\>\s*::\=\s*$"
\ contains=makeIdent,makeComment
\ skipnl nextgroup=makeCommands,makeCommandError
elseif get(b:, 'make_flavor', s:make_flavor) == 'gnu'
syn region makeSpecTarget transparent matchgroup=makeSpecTarget
\ start="^\.\(EXPORT_ALL_VARIABLES\|DELETE_ON_ERROR\|INTERMEDIATE\|KEEP_STATE\|LIBPATTERNS\|ONESHELL\|SECONDARY\)\>\s*:\{1,2}[^:=]"rs=e-1
\ end="[^\\]$" keepend
\ contains=makeIdent,makeSpecTarget,makeNextLine,makeComment skipnl nextGroup=makeCommands
syn match makeSpecTarget "^\.\(EXPORT_ALL_VARIABLES\|DELETE_ON_ERROR\|INTERMEDIATE\|KEEP_STATE\|LIBPATTERNS\|ONESHELL\|SECONDARY\)\>\s*::\=\s*$"
\ contains=makeIdent,makeComment
\ skipnl nextgroup=makeCommands,makeCommandError
endif
syn match makeCommandError "^\s\+\S.*" contained
syn region makeCommands contained start=";"hs=s+1 start="^\t"
\ end="^[^\t#]"me=e-1,re=e-1 end="^$"
@ -74,17 +98,19 @@ syn region makeCommands contained start=";"hs=s+1 start="^\t"
syn match makeCmdNextLine "\\\n."he=e-1 contained
" some directives
syn match makePreCondit "^ *\(ifn\=\(eq\|def\)\>\|else\(\s\+ifn\=\(eq\|def\)\)\=\>\|endif\>\)"
syn match makeInclude "^ *[-s]\=include\s.*$"
syn match makeStatement "^ *vpath"
syn match makeExport "^ *\(export\|unexport\)\>"
syn match makeOverride "^ *override\>"
" Statements / Functions (GNU make)
syn match makeStatement contained "(\(abspath\|addprefix\|addsuffix\|and\|basename\|call\|dir\|error\|eval\|file\|filter-out\|filter\|findstring\|firstword\|flavor\|foreach\|guile\|if\|info\|join\|lastword\|notdir\|or\|origin\|patsubst\|realpath\|shell\|sort\|strip\|subst\|suffix\|value\|warning\|wildcard\|word\|wordlist\|words\)\>"ms=s+1
if get(b:, 'make_flavor', s:make_flavor) == 'gnu'
" Statements / Functions (GNU make)
syn match makePreCondit "^ *\(ifn\=\(eq\|def\)\>\|else\(\s\+ifn\=\(eq\|def\)\)\=\>\|endif\>\)"
syn match makeStatement "^ *vpath\>"
syn match makeOverride "^ *override\>"
syn match makeStatement contained "[({]\(abspath\|addprefix\|addsuffix\|and\|basename\|call\|dir\|error\|eval\|file\|filter-out\|filter\|findstring\|firstword\|flavor\|foreach\|guile\|if\|info\|intcmp\|join\|lastword\|let\|notdir\|or\|origin\|patsubst\|realpath\|shell\|sort\|strip\|subst\|suffix\|value\|warning\|wildcard\|word\|wordlist\|words\)\>"ms=s+1
endif
" Comment
if !exists("make_no_comments")
if exists("b:make_microsoft") || exists("make_microsoft")
if get(b:, 'make_flavor', s:make_flavor) == 'microsoft'
syn match makeComment "#.*" contains=@Spell,makeTodo
else
syn region makeComment start="#" end="^$" end="[^\\]$" keepend contains=@Spell,makeTodo

View File

@ -2857,15 +2857,48 @@ endfunc
func Test_make_file()
filetype on
" BSD Makefile
call writefile([''], 'BSDmakefile', 'D')
split BSDmakefile
call assert_equal('bsd', get(b:, 'make_flavor', ''))
bwipe!
call writefile(['.ifmake all', '.endif'], 'XMakefile.mak', 'D')
split XMakefile.mak
call assert_equal('bsd', get(b:, 'make_flavor', ''))
bwipe!
" GNU Makefile
call writefile([''], 'GNUmakefile', 'D')
split GNUmakefile
call assert_equal('gnu', get(b:, 'make_flavor', ''))
bwipe!
call writefile(['ifeq ($(foo),foo)', 'endif'], 'XMakefile.mak', 'D')
split XMakefile.mak
call assert_equal('gnu', get(b:, 'make_flavor', ''))
bwipe!
call writefile(['define foo', 'endef'], 'XMakefile.mak', 'D')
split XMakefile.mak
call assert_equal('gnu', get(b:, 'make_flavor', ''))
bwipe!
call writefile(['vim := $(wildcard *.vim)'], 'XMakefile.mak', 'D')
split XMakefile.mak
call assert_equal('gnu', get(b:, 'make_flavor', ''))
bwipe!
" Microsoft Makefile
call writefile(['# Makefile for Windows', '!if "$(VIMDLL)" == "yes"'], 'XMakefile.mak', 'D')
split XMakefile.mak
call assert_equal(1, get(b:, 'make_microsoft', 0))
call assert_equal('microsoft', get(b:, 'make_flavor', ''))
bwipe!
" BSD or GNU
call writefile(['# get the list of tests', 'include testdir/Make_all.mak'], 'XMakefile.mak', 'D')
split XMakefile.mak
call assert_equal(0, get(b:, 'make_microsoft', 0))
call assert_notequal('microsoft', get(b:, 'make_flavor', ''))
bwipe!
filetype off

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1307,
/**/
1306,
/**/