]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0926: filetype: Business Central files are not recognized v9.2.0926
authorTorben Leth <SShadowS@SShadowS.dk>
Sat, 8 Aug 2026 17:24:06 +0000 (17:24 +0000)
committerChristian Brabandt <cb@256bit.org>
Sat, 8 Aug 2026 17:24:06 +0000 (17:24 +0000)
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 <SShadowS@SShadowS.dk>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/autoload/dist/ft.vim
runtime/doc/filetype.txt
runtime/filetype.vim
src/testdir/test_filetype.vim
src/version.c

index 6a20675f0c4e72f77bb2f6aecbd69918f0ae2970..bf8a0cc36c28969d6c8f5f5040bba53ad0a2786f 100644 (file)
@@ -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 <Bram@vim.org>
 
 # 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()
index f37865ee5fdc2eee0acec0861c3ceeb83da37376..8437531a813e36e33c27cba05d826e49350e6d5e 100644 (file)
@@ -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|
index 01a5130227bc173c99b7f486ea93cc11e905405d..36b052ca365320effeac1e39346a3fb888a8aa14 100644 (file)
@@ -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 <Bram@vim.org>
 
 " 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
index 428f7580bf9f9cfbc3715d266512137e3991e99f..893e3d8d0c47a5f528f895297a82e4cd56f41262 100644 (file)
@@ -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)
index 4e1ff82f62abbdddec37794207e08aa8659d2e31..b0c9b0deb9adf2fd1343646f410e3202316ed48e 100644 (file)
@@ -763,6 +763,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    926,
 /**/
     925,
 /**/