commit 2c76a50e20ded88b1767562455d2999fd2faa0de
parent 8151fc59cf28d8a4ba1693379d06726015b61aa9
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sat, 4 Oct 2025 06:01:16 +0800
vim-patch:9.1.1821: filetype: Not all PKL files are recognized (#36008)
Problem: filetype: Not all PKL files are recognized
Solution: Detect *.pcf as pkl filetype, detect using the pkl-lsp://
protocol as pkl filetype, include PKL syntax script
(Jan Claußen)
This adds basic syntax support for the new PKL language by Apple.
What works:
- Shebang support
- Comment support
- Integers (decimal, hex, octal and binary) support
- Floating point support including exponentials
- Basic datatype support
- Unicode escape delimiters
- Escape code support
- String interpolation
- Support up to five pounds for custom delimiters
- Folding of multi-line comments and blocks
What doesn't work:
The language heavily uses parameterized type declarations, which can get
very complex. It is very hard to highlight this properly. There is
official Tree-sitter support for this. Since it is hard to pull this off
in a vim syntax file, I opted for basic support of the data types.
References:
https://github.com/apple/pkl-pantry
fixes: vim/vim#18271
closes: vim/vim#18274
https://github.com/vim/vim/commit/67a8f2945e54def2a9a94aad919e4f489595acb7
Co-authored-by: Jan Claußen <jan.claussen10@web.de>
Diffstat:
4 files changed, 176 insertions(+), 3 deletions(-)
diff --git a/runtime/ftplugin/pkl.vim b/runtime/ftplugin/pkl.vim
@@ -2,13 +2,15 @@
" Language: Pkl
" Maintainer: Riley Bruins <ribru17@gmail.com>
" Last Change: 2025 Jul 14
+" 2025 Oct 03 by Vim Project Add foldmethod #18274
if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1
-setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
+setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,://
setlocal commentstring=//\ %s
+setlocal foldmethod=syntax
-let b:undo_ftplugin = 'setl com< cms<'
+let b:undo_ftplugin = 'setl com< cms< fdm<'
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
@@ -949,6 +949,7 @@ local extension = {
pmod = 'pike',
rcp = 'pilrc',
pkl = 'pkl',
+ pcf = 'pkl',
PL = detect.pl,
pli = 'pli',
pl1 = 'pli',
@@ -2683,6 +2684,7 @@ local pattern = {
['^pacman%.log'] = starsetf(function(path, _bufnr)
return vim.uv.fs_stat(path) and 'pacmanlog' or nil
end),
+ ['^pkl%-lsp://'] = 'pkl',
['printcap'] = starsetf(function(_path, _bufnr)
return require('vim.filetype.detect').printcap('print')
end),
diff --git a/runtime/syntax/pkl.vim b/runtime/syntax/pkl.vim
@@ -0,0 +1,169 @@
+" Vim syntax file
+" Language: PKL
+" Maintainer: Jan Claußen <jan DOT claussen10 AT web DOT de>
+" Last Change: 2025 Sep 24
+
+if exists("b:current_syntax")
+ finish
+endif
+
+" We use line-continuation here
+let s:cpo_save = &cpo
+set cpo&vim
+
+" Needed to properly highlight multiline strings
+syn sync fromstart
+
+" PKL supports non-Unicode identifiers. So we modify the keyword character
+" class to include them
+syn iskeyword @,48-57,192-255,$,_
+
+" Declare a variable for identifiers
+let s:id = '\%(\K\+\d*[_$]*\K*\d*[_$]*\)'
+
+" --- Decorator ---
+exe $'syn match pklDecorator "@{s:id}\{{1,}}"'
+
+" --- Comments ---
+syn match pklComment "\/\{2}.*"
+syn match pklDocComment "\/\{3}.*"
+syn region pklMultiComment start="\/\*" end="\*\/" keepend fold
+
+" --- Strings ---
+syn region pklString start=+"+ end=+"+ contains=pklEscape,pklUnicodeEscape,pklStringInterpolation oneline
+syn region pklMultiString start=+"""+ skip=+\\."+ end=+"""+ contains=pklEscape,pklUnicodeEscape keepend fold
+syn match pklEscape "\\[\\nt0rbaeuf"']" contained containedin=pklString,pklMultiString
+syn match pklUnicode "[0-9A-Fa-f]\+" contained
+
+" --- String interpolation ---
+" Standard interpolation
+syn region pklStringInterpolation matchgroup=pklDelimiter
+ \ start=+\\(+ end=+)+ contains=pklNumbers,pklOperator,pklIdentifier,pklFunction,pklParen,pklString
+ \ contained containedin=pklString,pklMultiString oneline
+" Unicode escape sequences
+syn region pklUnicodeEscape matchgroup=pklDelimiter
+ \ start=+\\u{+ end=+}+ contains=pklUnicode
+ \ contained containedin=pklString,pklMultiString
+
+" --- Basic data types ---
+syn keyword pklType
+ \ UInt UInt8 UInt16 UInt32 UInt64 UInt128
+ \ Int Int8 Int16 Int32 Int64 Int128
+ \ Float
+ \ Number
+ \ String
+ \ Boolean
+ \ Null
+ \ Any
+
+syn keyword pklCollections
+ \ Map Mapping
+ \ List Listing
+ \ Set
+
+" --- Custom string delimiters ---
+function! s:DefineCustomStringDelimiters(n)
+ for x in range(1, a:n)
+ exe $'syn region pklString{x}Pound start=+{repeat("#", x)}"+ end=+"{repeat("#", x)}+ contains=pklStringInterpolation{x}Pound,pklEscape{x}Pound oneline'
+ exe $'hi def link pklString{x}Pound String'
+
+ exe $'syn region pklMultiString{x}Pound start=+{repeat("#", x)}"""+ end=+"""{repeat("#", x)}+ contains=pklStringInterpolation{x}Pound,pklEscape{x}Pound keepend fold'
+ exe $'hi def link pklMultiString{x}Pound String'
+
+ exe $'syn match pklEscape{x}Pound "\\{repeat("#", x) }[\\nt0rbaeuf"'']" contained containedin=pklString{x}Pound,pklMultiString{x}Pound'
+ exe $'hi def link pklEscape{x}Pound SpecialChar'
+
+ exe $'syn region pklStringInterpolation{x}Pound matchgroup=pklDelimiter start=+\\{repeat("#", x)}(+ end=+)+ contains=pklNumbers,pklOperator,pklIdentifier,pklFunction,pklParen,pklString contained containedin=pklString{x}Pound,pklMultiString{x}Pound oneline'
+
+ exe $'syn region pklUnicodeEscape{x}Pound matchgroup=pklDelimiter start=+\\{repeat("#", x)}u{{+ end=+}}+ contains=pklUnicode contained containedin=pklString{x}Pound,pklMultiString{x}Pound'
+ exe $'hi def link pklUnicodeEscape{x}Pound SpecialChar'
+ endfor
+endfunction
+
+call s:DefineCustomStringDelimiters(5)
+
+" --- Keywords ---
+syn keyword pklBoolean false true
+syn keyword pklClass outer super this module new
+syn keyword pklConditional if else when
+syn keyword pklConstant null NaN Infinity
+syn keyword pklException throw
+syn keyword pklInclude amends import extends as
+syn keyword pklKeyword function let out is
+syn keyword pklModifier abstract const external fixed hidden local open
+syn keyword pklReserved case delete override protected record switch vararg
+syn keyword pklRepeat for in
+syn keyword pklSpecial nothing unknown
+syn keyword pklStatement trace read
+syn keyword pklStruct typealias class
+
+" Include all unicode letters
+exe $'syn match pklIdentifier "{s:id}"'
+
+" Explicitely make keywords identifiers with backticks
+syn region pklIdentifierExplicit start=+`+ end=+`+
+
+syn match pklOperator ",\||\|+\|*\|->\|?\|-\|==\|=\|!=\|!" contained containedin=pklType
+
+" --- Numbers ---
+" decimal numbers
+syn match pklNumbers display transparent "\<\d\|\.\d" contains=pklNumber,pklFloat,pklOctal
+syn match pklNumber display contained "\d\%(\d\+\)*\>"
+" hex numbers
+syn match pklNumber display contained "0x\x\%('\=\x\+\)\>"
+" binary numbers
+syn match pklNumber display contained "0b[01]\%('\=[01]\+\)\>"
+" octal numbers
+syn match pklOctal display contained "0o\o\+\>"
+
+"floating point number, with dot, optional exponent
+syn match pklFloat display contained "\d\+\.\d\+\%(e[-+]\=\d\+\)\="
+"floating point number, starting with a dot, optional exponent
+syn match pklFloat display contained "\.\d\+\%(e[-+]\=\d\+\)\=\>"
+"floating point number, without dot, with exponent
+syn match pklFloat display contained "\d\+e[-+]\=\d\+\>"
+
+" --- Brackets, operators, functions ---
+syn region pklParen matchgroup=pklBrackets start='(' end=')' contains=ALLBUT,pklUnicode transparent
+syn region pklBracket matchgroup=pklBrackets start='\[\|<::\@!' end=']\|:>' contains=ALLBUT,pklUnicode transparent
+syn region pklBlock matchgroup=pklBrackets start="{" end="}" contains=ALLBUT,pklUnicode fold transparent
+
+exe $'syn match pklFunction "\<\h{s:id}*\>\ze\_s*[?|\*]\?(" contains=pklType'
+
+" --- Highlight links ---
+hi def link pklBoolean Boolean
+hi def link pklBrackets Delimiter
+hi def link pklClass Statement
+hi def link pklCollections Type
+hi def link pklComment Comment
+hi def link pklConditional Conditional
+hi def link pklConstant Constant
+hi def link pklDecorator Special
+hi def link pklDelimiter Delimiter
+hi def link pklDocComment Comment
+hi def link pklEscape SpecialChar
+hi def link pklException Exception
+hi def link pklFloat Number
+hi def link pklFunction Function
+hi def link pklInclude Include
+hi def link pklKeyword Keyword
+hi def link pklModifier StorageClass
+hi def link pklMultiComment Comment
+hi def link pklMultiString String
+hi def link pklNumber Number
+hi def link pklNumbers Number
+hi def link pklOctal Number
+hi def link pklRepeat Repeat
+hi def link pklReserved Error
+hi def link pklShebang Comment
+hi def link pklSpecial Special
+hi def link pklStatement Statement
+hi def link pklString String
+hi def link pklStruct Structure
+hi def link pklType Type
+hi def link pklUnicodeEscape SpecialChar
+
+let b:current_syntax = "pkl"
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
@@ -612,7 +612,7 @@ func s:GetFilenameChecks() abort
\ 'pilrc': ['file.rcp'],
\ 'pine': ['.pinerc', 'pinerc', '.pinercex', 'pinercex'],
\ 'pinfo': ['/etc/pinforc', '/.pinforc', 'any/.pinforc', 'any/etc/pinforc'],
- \ 'pkl': ['file.pkl'],
+ \ 'pkl': ['file.pkl', 'file.pcf'],
\ 'pli': ['file.pli', 'file.pl1'],
\ 'plm': ['file.plm', 'file.p36', 'file.pac'],
\ 'plp': ['file.plp'],