Commit: patch 9.2.0926: filetype: Business Central files are not recognized

Christian Brabandt <[email protected]> Sat, 8 Aug 2026 19:45:04 +0200
Newsgroups gmane.editors.vim.devel
Message-ID <[email protected]>
patch 9.2.0926: filetype: Business Central files are not recognized

Commit: https://github.com/vim/vim/commit/9b41cf6386bc0afd1bf5eca396adfdd488e617d0
Author: Torben Leth <[email protected]>
Date:   Sat Aug 8 17:24:06 2026 +0000

    patch 9.2.0926: filetype: Business Central files are not recognized
    
    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: #20975
    
    Supported by AI.
    
    Signed-off-by: Torben Leth <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index 6a20675f0..bf8a0cc36 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -3,7 +3,7 @@ vim9script
 # Vim functions for file type detection
 #
 # Maintainer:		The Vim Project <https://github.com/vim/vim>
-# Last Change:		2026 Aug 06
+# Last Change:		2026 Aug 08
 # Former Maintainer:	Bram Moolenaar <[email protected]>
 
 # These functions are moved here from runtime/filetype.vim to make startup
@@ -41,6 +41,34 @@ export def Check_inp()
   endif
 enddef
 
+# AL (Microsoft Dynamics 365 Business Central) or Perl AutoLoader
+export def FTal()
+  if exists("g:filetype_al")
+    exe "setf " .. g:filetype_al
+    return
+  endif
+
+  # 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 lnum in range(1, min([line("$"), 200]))
+    var line = getline(lnum)
+    if line =~# '^\s*\%(codeunit\|page\|pageextension\|pagecustomization\|table\|tableextension\|' ..
+      'report\|reportextension\|xmlport\|query\|enum\|enumextension\|profile\|profileextension\|' ..
+      'controladdin\|interface\|permissionset\|permissionsetextension\|entitlement\)\>\s\+\%(\d\|"\|\u\)'
+      || line =~# '^\s*dotnet\s*$'
+      || line =~# '^\s*\%(namespace\|using\)\s\+[[:alnum:]._]\+\s*;'
+      setf al
+      return
+    endif
+  endfor
+
+  setf perl
+enddef
+
 # Erlang Application Resource Files (*.app.src is matched by extension)
 # See: https://erlang.org/doc/system/applications
 export def FTapp()
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index f37865ee5..8437531a8 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -1,4 +1,4 @@
-*filetype.txt*	For Vim version 9.2.  Last change: 2026 Jul 01
+*filetype.txt*	For Vim version 9.2.  Last change: 2026 Aug 08
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -138,6 +138,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|
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 01a513022..36b052ca3 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -1,7 +1,7 @@
 " Vim support file to detect file types
 "
 " Maintainer:		The Vim Project <https://github.com/vim/vim>
-" Last Change:		2026 Jul 18
+" Last Change:		2026 Aug 08
 " Former Maintainer:	Bram Moolenaar <[email protected]>
 
 " If the filetype can be detected from extension or file name(the final path component),
@@ -862,7 +862,10 @@ if has("fname_case")
 else
   au BufNewFile,BufRead *.pl				call dist#ft#FTpl()
 endif
-au BufNewFile,BufRead *.plx,*.al,*.psgi			setf perl
+au BufNewFile,BufRead *.plx,*.psgi			setf perl
+
+" Perl AutoLoader or AL (Dynamics 365 Business Central)
+au BufNewFile,BufRead *.al				call dist#ft#FTal()
 
 " Perl, XPM or XPM2
 au BufNewFile,BufRead *.pm
diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim
index 428f7580b..893e3d8d0 100644
--- a/src/testdir/test_filetype.vim
+++ b/src/testdir/test_filetype.vim
@@ -635,7 +635,7 @@ def s:GetFilenameChecks(): dict<list<string>>
     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'],
@@ -1268,6 +1268,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)
diff --git a/src/version.c b/src/version.c
index 4e1ff82f6..b0c9b0deb 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    926,
 /**/
     925,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wsl6W-002I2S-98%40256bit.org.