From aea78a92c443e334a87e801a6286f46efeae46d2 Mon Sep 17 00:00:00 2001 From: shadowwa Date: Sun, 22 Sep 2024 14:26:55 +0200 Subject: [PATCH 1/2] subtype detection from native (n)vim method Detection and filetype setting are done in ftdetect scripts filetype is set to subtype.epuppet so ftplugin and syntax file loading is done by (n)vim owns scripts (ftplugin.vim and syntax/synload.vim) Added more test to detect if g:epuppet_default_subtype is defined in .vimrc --- ftdetect/puppet.lua | 31 ++++++++++++----- ftdetect/puppet.vim | 41 ++++++++++++++++++----- ftplugin/epuppet.vim | 49 ++++----------------------- syntax/epuppet.vim | 40 ++-------------------- test/filetype/epuppet.vader | 66 ++++++++++++++++++++++++++++--------- test/syntax/epuppet.vader | 2 +- 6 files changed, 116 insertions(+), 113 deletions(-) diff --git a/ftdetect/puppet.lua b/ftdetect/puppet.lua index 11b51a5..7074a4f 100644 --- a/ftdetect/puppet.lua +++ b/ftdetect/puppet.lua @@ -1,16 +1,31 @@ --- Some epp files may get marked as "mason" type before this script is reached. --- Vim's own scripts.vim forces the type if it detects a `<%` at the start of --- the file. All files ending in .epp should be epuppet +-- nvim older than 0.7.0 vim.filetype is null, and detection fallback to vimscript +if vim.filetype == nil then + return nil +end vim.filetype.add({ extension = { epp = function(path, bufnr) - local path_wo_epp = path:sub(1,-5) - local matched = vim.filetype.match({ buf = bufnr, filename = path_wo_epp }) - if matched ~= nil and matched ~= 'mason' then - vim.b.epuppet_subtype = matched + local root = vim.fn.fnamemodify(path, ':r') + local matched = vim.filetype.match({ buf = bufnr, filename = root }) + -- subtype not detected in lua file, return nil so detection fallback + -- on ftdetect/*.vim + if matched == nil then + return nil + -- don't loop + elseif string.match(matched, 'epuppet') then + return matched + -- Some epp files may get marked as "mason" type before this script is reached. + -- NVim's own detect.lua forces the type if it detects a `<%` at the start of + -- the file. All files ending in .epp should be epuppet + elseif matched ~= 'mason' then + return matched .. '.epuppet' + end + if vim.g.epuppet_default_subtype ~= nil then + return vim.g.epuppet_default_subtype .. '.epuppet' + else + return 'epuppet' end - return 'epuppet' end, } }) diff --git a/ftdetect/puppet.vim b/ftdetect/puppet.vim index 6c608a0..70397e8 100644 --- a/ftdetect/puppet.vim +++ b/ftdetect/puppet.vim @@ -12,12 +12,35 @@ if !has('patch-8.2.2334') && !has('nvim-0.5.0') " for .pp files. au! BufRead,BufNewFile *.pp setfiletype puppet endif -" Vim now has autodetection for epuppet and Puppetfile. We only need to add -" autocommands for older versions of vim / neovim -if !has('patch-8.2.2402') && !has('nvim-0.5.0') - " Some epp files may get marked as "mason" type before this script is reached. - " Vim's own scripts.vim forces the type if it detects a `<%` at the start of - " the file. All files ending in .epp should be epuppet - au! BufRead,BufNewFile *.epp setf epuppet - au BufRead,BufNewFile Puppetfile setfiletype ruby -endif +au BufRead,BufNewFile Puppetfile setfiletype ruby + +" au! is needed because epuppet already declared in filetype.vim +au! BufNewFile,BufRead *.epp call DetectSubepuppetNativeType() +function! DetectSubepuppetNativeType() + if !exists('g:epuppet_default_subtype') + let g:epuppet_default_subtype = 'sh' + endif + if exists('*fnameescape') + execute 'doautocmd filetypedetect BufRead ' .fnameescape(expand(':r')) + " don't loop + if &filetype =~# 'epuppet' + return + endif + " Some epp files may get marked as "mason" type before this script is reached. + " Vim's own script.vim forces the type if it detects a `<%` at the start of + " the file. All files ending in .epp should be epuppet + if &filetype !=# '' && !( &filetype ==# 'mason' && expand('') !~# 'mason') + let b:epuppet_subtype = &filetype + let &filetype = b:epuppet_subtype . '.epuppet' + else + if exists('g:epuppet_default_subtype') && g:epuppet_default_subtype !=# '' + let &filetype = g:epuppet_default_subtype . '.epuppet' + else + let &filetype = 'epuppet' + endif + endif + elseif &verbose > 0 + echomsg 'Warning: epuppet subtype will not be recognized because this version of Vim does not have fnameescape()' + setf epuppet + endif +endfunction diff --git a/ftplugin/epuppet.vim b/ftplugin/epuppet.vim index 6bbb49c..b672872 100644 --- a/ftplugin/epuppet.vim +++ b/ftplugin/epuppet.vim @@ -4,8 +4,8 @@ " URL: https://github.com/rodjek/vim-puppet " Last Change: 2019-09-01 -" Only do this when not done yet for this buffer -if exists('b:did_ftplugin') +" since this filetype can be loaded along a subtype, don't test with b:did_ftplugin +if (exists('b:did_ftplugin_epuppet')) finish endif @@ -17,48 +17,10 @@ let s:undo_ftplugin = '' if has('win32') let s:browsefilter = "All Files (*.*)\t*.*\n" else - let s:browsefilter = "All Files (*)\t*\n" + let s:browsefilter = "All Files (*)\t*\n" endif let s:match_words = '' -if !exists('g:epuppet_default_subtype') - let g:epuppet_default_subtype = 'sh' -endif - -if &filetype =~# '^epuppet\.' - let b:epuppet_subtype = matchstr(&filetype,'^epuppet\.\zs\w\+') -elseif !exists('b:epuppet_subtype') - let b:epuppet_subtype = matchstr(substitute(expand('%:t'),'\c\%(\.epp\)\+$','',''),'\.\zs\w\+\%(\ze+\w\+\)\=$') - " TODO instead of listing exceptions like this, can we instead recognize - " extension -> type mapping? - if b:epuppet_subtype ==? 'rhtml' - let b:epuppet_subtype = 'html' - elseif b:epuppet_subtype ==? 'rb' - let b:epuppet_subtype = 'ruby' - elseif b:epuppet_subtype ==? 'yml' - let b:epuppet_subtype = 'yaml' - elseif b:epuppet_subtype ==? 'js' - let b:epuppet_subtype = 'javascript' - elseif b:epuppet_subtype ==? 'txt' - " Conventional; not a real file type - let b:epuppet_subtype = 'text' - elseif b:epuppet_subtype ==? 'py' - let b:epuppet_subtype = 'python' - elseif b:epuppet_subtype ==? 'rs' - let b:epuppet_subtype = 'rust' - elseif b:epuppet_subtype ==?'' - let b:epuppet_subtype = g:epuppet_default_subtype - endif -endif - -if exists('b:epuppet_subtype') && b:epuppet_subtype != '' && b:epuppet_subtype !=? 'epuppet' - exe 'runtime! ftplugin/'.b:epuppet_subtype.'.vim ftplugin/'.b:epuppet_subtype.'_*.vim ftplugin/'.b:epuppet_subtype.'/*.vim' -endif -unlet! b:did_ftplugin - -runtime! ftplugin/sh.vim -unlet! b:did_ftplugin - " Override our defaults if these were set by an included ftplugin. if exists('b:undo_ftplugin') let s:undo_ftplugin = b:undo_ftplugin @@ -77,8 +39,11 @@ let s:include = &l:include let s:path = &l:path let s:suffixesadd = &l:suffixesadd +if (exists('b:did_ftplugin')) + unlet b:did_ftplugin +endif runtime! ftplugin/puppet.vim -let b:did_ftplugin = 1 +let b:did_ftplugin_epuppet = 1 " Combine the new set of values with those previously included. if exists('b:undo_ftplugin') diff --git a/syntax/epuppet.vim b/syntax/epuppet.vim index 23ceedf..2d1be63 100644 --- a/syntax/epuppet.vim +++ b/syntax/epuppet.vim @@ -4,46 +4,12 @@ " URL: https://github.com/rodjek/vim-puppet " Last Change: 2019-09-01 -" quit when a syntax file was already loaded {{{1 -if exists('b:current_syntax') +" since this filetype can be loaded along a subtype, don't test with b:current_syntax +if (exists('b:current_syntax') && b:current_syntax ==# 'epuppet') finish endif -if !exists('g:epuppet_default_subtype') - let g:epuppet_default_subtype = 'sh' -endif - -if &filetype =~# '^epuppet\.' - let b:epuppet_subtype = matchstr(&filetype,'^epuppet\.\zs\w\+') -elseif !exists('b:epuppet_subtype') - let b:epuppet_subtype = matchstr(substitute(expand('%:t'),'\c\%(\.epp\)\+$','',''),'\.\zs\w\+\%(\ze+\w\+\)\=$') - " TODO instead of listing exceptions like this, can we instead recognize - " extension -> type mapping? - if b:epuppet_subtype ==? 'rhtml' - let b:epuppet_subtype = 'html' - elseif b:epuppet_subtype ==? 'rb' - let b:epuppet_subtype = 'ruby' - elseif b:epuppet_subtype ==? 'yml' - let b:epuppet_subtype = 'yaml' - elseif b:epuppet_subtype ==? 'js' - let b:epuppet_subtype = 'javascript' - elseif b:epuppet_subtype ==? 'txt' - " Conventional; not a real file type - let b:epuppet_subtype = 'text' - elseif b:epuppet_subtype ==? 'py' - let b:epuppet_subtype = 'python' - elseif b:epuppet_subtype ==? 'rs' - let b:epuppet_subtype = 'rust' - elseif b:epuppet_subtype ==? '' - let b:epuppet_subtype = g:epuppet_default_subtype - endif -endif - -if exists('b:epuppet_subtype') && b:epuppet_subtype != '' && b:epuppet_subtype !=? 'epuppet' - exe 'runtime! syntax/'.b:epuppet_subtype.'.vim' - unlet! b:current_syntax -endif - +unlet! b:current_syntax syn include @puppetTop syntax/puppet.vim syn cluster ePuppetRegions contains=ePuppetBlock,ePuppetExpression,ePuppetComment diff --git a/test/filetype/epuppet.vader b/test/filetype/epuppet.vader index 87a5d56..261c317 100644 --- a/test/filetype/epuppet.vader +++ b/test/filetype/epuppet.vader @@ -1,33 +1,67 @@ -Execute (Filetype detection on a new empty file): +Execute (Setup default subtype to Undefined): + Save g:epuppet_default_subtype + if exists('g:epuppet_default_subtype') + unlet g:epuppet_default_subtype + end + +Execute (Filetype detection on a new empty file without g:epuppet_default_subtype defined by user): + edit foo.epp + AssertEqual &filetype, 'sh.epuppet' + " new is needed before bedelete https://github.com/junegunn/vader.vim/issues/134 + new + " bdelete is needed otherwise g:epuppet_default_subtype is not reseted for the next tests + bdelete foo.epp + +Execute (epuppet test_with_leading_tag without g:epuppet_default_subtype defined by user): + edit test/test-files/test_with_leading_tag.epp + AssertEqual &filetype, 'sh.epuppet' + new + bdelete test/test-files/test_with_leading_tag.epp + +Execute (Setting default subtype to 'conf'): + let g:epuppet_default_subtype = 'conf' + +Execute (Filetype detection on a new empty file with g:epuppet_default_subtype defined by user at 'conf'): edit foo.epp - AssertEqual &filetype, 'epuppet' + AssertEqual &filetype, 'conf.epuppet' -Execute (epuppet test_with_leading_tag): +Execute (epuppet test_with_leading_tag with g:epuppet_default_subtype defined by user at 'conf'): edit test/test-files/test_with_leading_tag.epp - AssertEqual &filetype, 'epuppet' + AssertEqual &filetype, 'conf.epuppet' + +Execute (Restore default subtype): + Restore g:epuppet_default_subtype -Execute (TODO: epuppet perl with shebang): +Execute (epuppet perl with shebang): edit test/test-files/test_perl_with_shebang.epp - AssertEqual &filetype, 'epuppet' - AssertEqual b:epuppet_subtype, 'perl' + AssertEqual &filetype, 'perl.epuppet' # We don't need to parse the shebang for shell since sh is the default subtype Execute (epuppet default to shell): edit test/test-files/test_shell_with_shebang.epp - AssertEqual &filetype, 'epuppet' - AssertEqual b:epuppet_subtype, 'sh' + AssertEqual &filetype, 'sh.epuppet' Execute (epuppet shell with extension): edit test/test-files/test_shell_with_extension.sh.epp - AssertEqual &filetype, 'epuppet' - AssertEqual b:epuppet_subtype, 'sh' + AssertEqual &filetype, 'sh.epuppet' Execute (epuppet php with extension): edit test/test-files/test_php_with_extension.php.epp - AssertEqual &filetype, 'epuppet' - AssertEqual b:epuppet_subtype, 'php' + AssertEqual &filetype, 'php.epuppet' -Execute (TODO: epuppet apache conf with path and extension): +Execute (epuppet apache conf with path and extension): edit test/test-files/etc/apache2/test.conf.epp - AssertEqual &filetype, 'epuppet' - AssertEqual b:epuppet_subtype, 'apache' + AssertEqual &filetype, 'apache.epuppet' + +# non sensical type to test corner caser +Execute (epuppet php with double subtype extension): + edit test/test-files/test.php.php.epp + AssertEqual &filetype, 'php.epuppet' + +Execute (epuppet php with double epuppet extension): + edit test/test-files/test.php.epp.epp + AssertEqual &filetype, 'php.epuppet' + +Execute (epuppet php with reversed extension): + edit test/test-files/test.epp.php + AssertEqual &filetype, 'php' diff --git a/test/syntax/epuppet.vader b/test/syntax/epuppet.vader index 9b6216f..438b442 100644 --- a/test/syntax/epuppet.vader +++ b/test/syntax/epuppet.vader @@ -1,4 +1,4 @@ -Given epuppet (template with litteral content puppet tags): +Given sh.epuppet (template with litteral content puppet tags): # Short litteral comment <% if $variable == '<%%somevalue%%>' { -%> MYVAR=<%= $variable %> From 16b4abcfb92da05a75d99754e218f29fe540edd7 Mon Sep 17 00:00:00 2001 From: shadowwa Date: Sun, 22 Sep 2024 18:03:38 +0200 Subject: [PATCH 2/2] Add mention for on-demand loading with vim-plug If using ``` 'for': ['puppet', 'epuppet'] ``` vim-plug load ftdetect/puppet.vim, that set filetype to 'subtype.epuppet' then as this does not strictly match 'epuppet' vim-plug remove vim-puppet from &rtp and syntax and ftplugin file could not be loaded. The solution is to add a wildcard ``` 'for': ['puppet', '*epuppet'] ``` --- README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 64f4502..adb7850 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,19 @@ With [Plug](https://github.com/junegunn/vim-plug) In your ~/.vimrc (or stdpath('config') . '/init.vim' for Neovim) - call plug#begin() - rodjek/vim-puppet - call plug#end() +```vim + call plug#begin() + Plug 'rodjek/vim-puppet' + call plug#end() +``` + +if you want to load only for puppet type use (pay attention to the * for epupet type) + +```vim + call plug#begin() + Plug 'rodjek/vim-puppet', { 'for': ['puppet', '*epuppet'] } + call plug#end() +``` Testing -------