patch 9.1.0013: Modula2 filetype support lacking

Problem:  Modula2 filetype support lacking
Solution: Improve the Modula-2 runtime support, add additional modula2
          dialects, add compiler plugin, update syntax highlighting,
          include syntax tests, update Makefiles (Doug Kearns)

closes: #6796
closes: #8115

Signed-off-by: Doug Kearns <dougkearns@gmail.com>
Signed-off-by: Benjamin Kowarsch <trijezdci@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index 2423fd4..9d0f2ee 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -2,8 +2,8 @@
 
 # Vim functions for file type detection
 #
-# Maintainer:	The Vim Project <https://github.com/vim/vim>
-# Last Change:	2023 Aug 10
+# Maintainer:		The Vim Project <https://github.com/vim/vim>
+# Last Change:		2024 Jan 05
 # Former Maintainer:	Bram Moolenaar <Bram@vim.org>
 
 # These functions are moved here from runtime/filetype.vim to make startup
@@ -279,6 +279,19 @@
   endif
 enddef
 
+export def FTdef()
+  if get(g:, "filetype_def", "") == "modula2" || IsModula2()
+    SetFiletypeModula2()
+    return
+  endif
+
+  if exists("g:filetype_def")
+    exe "setf " .. g:filetype_def
+  else
+    setf def
+  endif
+enddef
+
 export def FTe()
   if exists('g:filetype_euphoria')
     exe 'setf ' .. g:filetype_euphoria
@@ -517,16 +530,53 @@
   return getline(lnum) =~ '\<module\s\+\w\+\s*\.\s*\(%\|$\)'
 enddef
 
+def IsModula2(): bool
+  return getline(nextnonblank(1)) =~ '\<MODULE\s\+\w\+\s*;\|^\s*(\*'
+enddef
+
+def SetFiletypeModula2()
+  const KNOWN_DIALECTS = ["iso", "pim", "r10"]
+  const KNOWN_EXTENSIONS = ["gm2"]
+  const LINE_COUNT = 200
+  const TAG = '(\*!m2\(\w\+\)\%(+\(\w\+\)\)\=\*)'
+
+  var dialect = get(g:, "modula2_default_dialect", "pim")
+  var extension = get(g:, "modula2_default_extension", "")
+
+  var matches = []
+
+  # ignore unknown dialects or badly formatted tags
+  for lnum in range(1, min([line("$"), LINE_COUNT]))
+    matches = matchlist(getline(lnum), TAG)
+    if !empty(matches)
+      if index(KNOWN_DIALECTS, matches[1]) >= 0
+         dialect = matches[1]
+      endif
+      if index(KNOWN_EXTENSIONS, matches[2]) >= 0
+         extension = matches[2]
+      endif
+      break
+    endif
+  endfor
+
+  modula2#SetDialect(dialect, extension)
+
+  setf modula2
+enddef
+
 # Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
 export def FTmod()
+  if get(g:, "filetype_mod", "") == "modula2" || IsModula2()
+    SetFiletypeModula2()
+    return
+  endif
+
   if exists("g:filetype_mod")
     exe "setf " .. g:filetype_mod
   elseif expand("<afile>") =~ '\<go.mod$'
     setf gomod
   elseif IsLProlog()
     setf lprolog
-  elseif getline(nextnonblank(1)) =~ '\%(\<MODULE\s\+\w\+\s*;\|^\s*(\*\)'
-    setf modula2
   elseif IsRapid()
     setf rapid
   else
@@ -1243,4 +1293,4 @@
 enddef
 
 # Uncomment this line to check for compilation errors early
-# defcompile
+defcompile
diff --git a/runtime/autoload/modula2.vim b/runtime/autoload/modula2.vim
new file mode 100644
index 0000000..284dc27
--- /dev/null
+++ b/runtime/autoload/modula2.vim
@@ -0,0 +1,31 @@
+" Vim filetype plugin file
+" Language:	Modula-2
+" Maintainer:	Doug Kearns <dougkearns@gmail.com>
+" Last Change:	2024 Jan 04
+
+" Dialect can be one of pim, iso, r10
+function modula2#GetDialect() abort
+
+  if exists("b:modula2.dialect")
+    return b:modula2.dialect
+  endif
+
+  if exists("g:modula2_default_dialect")
+    let dialect = g:modula2_default_dialect
+  else
+    let dialect = "pim"
+  endif
+
+  return dialect
+endfunction
+
+function modula2#SetDialect(dialect, extension = "") abort
+  if exists("b:modula2")
+    unlockvar! b:modula2
+  endif
+
+  let b:modula2 = #{ dialect: a:dialect, extension: a:extension }
+  lockvar! b:modula2
+endfunction
+
+" vim: nowrap sw=2 sts=2 ts=8 noet fdm=marker: