vim-patch:9.2.0926: filetype: Business Central files are not recognized (#41230)

Problem:  filetype: Business Central files are not recognized
Solution: Add filetype detection logic for *.al files to detect perl or
          use either perl or al filetype (Torben Leth).

Reference:
https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-dev-overview

closes: vim/vim#20975

Supported by AI.

9b41cf6386
This commit is contained in:
Torben Leth
2026-08-09 02:49:20 +02:00
committed by GitHub
parent a45d3dccf1
commit f538a4f16f
4 changed files with 85 additions and 2 deletions

View File

@@ -136,6 +136,7 @@ what kind of file it is. This doesn't always work. A number of global
variables can be used to overrule the filetype used for certain extensions:
file name variable ~
`*.al` g:filetype_al
`*.app` g:filetype_app
`*.as` g:filetype_as
`*.asa` g:filetype_asa |ft-aspperl-syntax|

View File

@@ -245,6 +245,7 @@ local extension = {
adb = 'ada',
tdf = 'ahdl',
aidl = 'aidl',
al = detect.al,
a68 = 'algol68',
aml = 'aml',
run = 'ampl',
@@ -1006,7 +1007,6 @@ local extension = {
plx = 'perl',
prisma = 'prisma',
psgi = 'perl',
al = 'perl',
ctp = 'php',
php = 'php',
phpt = 'php',

View File

@@ -31,6 +31,37 @@ local matchregex = vim.filetype._matchregex
-- luacheck: push no unused args
-- luacheck: push ignore 122
-- AL (Microsoft Dynamics 365 Business Central) or Perl AutoLoader
--- @type vim.filetype.mapfn
function M.al(_, bufnr)
if vim.g.filetype_al then
return vim.g.filetype_al
end
-- AL sources declare an object as "<kind> <id> <name>" at the start of a
-- line, optionally preceded by namespace and using declarations. Perl
-- AutoLoader chunks match neither. Matching a bare keyword anywhere would
-- be wrong: table, page and report are ordinary English words, so the object
-- name must follow. The match is case sensitive because AL tooling emits
-- lowercase keywords, while prose in Perl comments is usually capitalised.
for _, line in ipairs(getlines(bufnr, 1, 200)) do
if
matchregex(
line,
[[^\s*\%(codeunit\|page\|pageextension\|pagecustomization\|table\|tableextension\|]]
.. [[report\|reportextension\|xmlport\|query\|enum\|enumextension\|profile\|profileextension\|]]
.. [[controladdin\|interface\|permissionset\|permissionsetextension\|entitlement\)\>\s\+\%(\d\|"\|\u\)]]
)
or findany(
line,
{ '^%s*dotnet%s*$', '^%s*namespace%s+[%w._]+%s*;', '^%s*using%s+[%w._]+%s*;' }
)
then
return 'al'
end
end
return 'perl'
end
-- Erlang Application Resource Files (*.app.src is matched by extension)
-- See: https://erlang.org/doc/system/applications
--- @type vim.filetype.mapfn

View File

@@ -634,7 +634,7 @@ func s:GetFilenameChecks() abort
\ 'pcmk': ['file.pcmk'],
\ 'pdf': ['file.pdf'],
\ 'pem': ['file.pem', 'file.cer', 'file.crt', 'file.csr'],
\ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc', '.latexmkrc', 'latexmkrc'],
\ 'perl': ['file.plx', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc', '.latexmkrc', 'latexmkrc'],
\ 'pf': ['pf.conf'],
\ 'pfmain': ['main.cf', 'main.cf.proto'],
\ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt', 'file.theme'],
@@ -1264,6 +1264,57 @@ endfunc
" Keep sorted.
"""""""""""""""""""""""""""""""""""""""""""""""""
func Test_al_file()
filetype on
" AL object declaration
call writefile(['codeunit 50100 "My Codeunit"', '{', '}'], 'Xfile.al', 'D')
split Xfile.al
call assert_equal('al', &filetype)
bwipe!
" AL namespace and using declarations before the object
call writefile(['namespace Microsoft.Sales;', '', 'using Microsoft.Foundation;'], 'Xfile.al')
split Xfile.al
call assert_equal('al', &filetype)
bwipe!
" Perl AutoLoader chunk
call writefile(['# NOTE: Derived from blib/lib/Net/SSLeay.pm.', 'package Net::SSLeay;', 'sub do_https {'], 'Xfile.al')
split Xfile.al
call assert_equal('perl', &filetype)
bwipe!
" AL DotNet alias object, which is a bare keyword on its own line
call writefile(['dotnet', '{', ' assembly("mscorlib")', '}'], 'Xfile.al')
split Xfile.al
call assert_equal('al', &filetype)
bwipe!
" Perl code containing AL object kinds as ordinary words
call writefile(['sub value {', ' my $table = shift;', ' # report page interface', '}'], 'Xfile.al')
split Xfile.al
call assert_equal('perl', &filetype)
bwipe!
" Perl documentation containing AL object kinds at the start of a line
call writefile(['package Foo;', '=pod', 'Table of contents', 'using the -x option', 'table of contents follows'], 'Xfile.al')
split Xfile.al
call assert_equal('perl', &filetype)
bwipe!
" Test dist#ft#FTal()
let g:filetype_al = 'perl'
call writefile(['codeunit 50100 "My Codeunit"'], 'Xfile.al')
split Xfile.al
call assert_equal('perl', &filetype)
bwipe!
unlet g:filetype_al
filetype off
endfunc
" Since dist#ft#FTm4() looks around for configure.ac
" the test needs to isolate itself in a fresh temporary project tree,
" so that no configure.ac from another test (or from the repo root)