branch: externals/matlab-mode
commit 7d0d26a0312cf3a7b0cb07ff982f1b5274f96424
Author: John Ciolfi <john.ciolfi...@gmail.com>
Commit: John Ciolfi <john.ciolfi...@gmail.com>

    Setup imenu for *.tlc files
---
 tests/metest-imenu-tlc-files/timestwo.tlc          | 23 ++++++
 tests/metest-imenu-tlc-files/timestwo_expected.txt |  2 +
 tests/metest-imenu-tlc.el                          | 86 ++++++++++++++++++++++
 tests/metest.el                                    |  2 +
 tlc.el                                             | 22 +++---
 5 files changed, 125 insertions(+), 10 deletions(-)

diff --git a/tests/metest-imenu-tlc-files/timestwo.tlc 
b/tests/metest-imenu-tlc-files/timestwo.tlc
new file mode 100644
index 0000000000..4816d067aa
--- /dev/null
+++ b/tests/metest-imenu-tlc-files/timestwo.tlc
@@ -0,0 +1,23 @@
+%implements "timestwo" "C"
+
+%% Function: BlockTypeSetup ==================================
+%%
+%function BlockTypeSetup(block, system) void
+    %% Add function prototype to model's header file
+    %<LibCacheFunctionPrototype...
+       ("extern void mytimestwo(real_T* in,real_T* out,int_T els);")>
+    %% Add file that contains "myfile" to list of files to be compiled
+    %<LibAddToModelSources("myfile")>
+%endfunction
+
+%% Function: Outputs ==========================================
+%%
+%function Outputs(block, system) Output
+    /* %<Type> Block: %<Name> */
+    %assign outPtr = LibBlockOutputSignalAddr(0, "", "", 0)
+    %assign inPtr = LibBlockInputSignalAddr(0, "", "",0)
+    %assign numEls = LibBlockOutputSignalWidth(0)
+    /* Multiply input by two */
+    mytimestwo(%<inPtr>,%<outPtr>,%<numEls>);
+
+%endfunction
diff --git a/tests/metest-imenu-tlc-files/timestwo_expected.txt 
b/tests/metest-imenu-tlc-files/timestwo_expected.txt
new file mode 100644
index 0000000000..93b35ee0c2
--- /dev/null
+++ b/tests/metest-imenu-tlc-files/timestwo_expected.txt
@@ -0,0 +1,2 @@
+BlockTypeSetup
+Outputs
diff --git a/tests/metest-imenu-tlc.el b/tests/metest-imenu-tlc.el
new file mode 100644
index 0000000000..0cef57b69c
--- /dev/null
+++ b/tests/metest-imenu-tlc.el
@@ -0,0 +1,86 @@
+;;; metest-imenu-tlc.el --- Testing suite for MATLAB Emacs -*- 
lexical-binding: t -*-
+;;
+;; Copyright 2025 Free Software Foundation, Inc.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;;
+
+;;; Commentary:
+;;
+;; Tests to exercise the tlc--imenu-generic-expression regexp
+;;
+
+;;; Code:
+
+(require 'tlc)
+
+(defun metest-imenu-tlc-files ()
+  "Return list of full paths to each metest-imenu-tlc-files/*.tlc."
+  (directory-files "metest-imenu-tlc-files" t "\\.tlc$"))
+
+(defvar metest-imenu-tlc (cons "metest-imenu-tlc" (metest-imenu-tlc-files)))
+
+(defun metest-imenu-tlc (&optional tlc-file)
+  "Test MATLAB imenu support using ./metest-imenu-tlc-files/TLC-FILE.
+Compare ./metest-imenu-tlc-files/TLC-FILE against
+./metest-imenu-tlc-files/NAME_expected.txt, where NAME_expected.txt
+contains the matched functions of the tlc--imenu-generic-expression
+regexp, one per line.
+
+If TLC-FILE is not provided, loop comparing all
+  ./metest-imenu-tlc-files/*.tlc
+
+For debugging, you can run with a specified TLC-FILE,
+  M-: (metest-imenu-tlc \"metest-imenu-tlc-files/TLC-FILE\")"
+  (let* ((tlc-files (if tlc-file
+                      (progn
+                        (setq tlc-file (file-truename tlc-file))
+                        (when (not (file-exists-p tlc-file))
+                          (error "File %s does not exist" tlc-file))
+                        (list tlc-file))
+                    (metest-imenu-tlc-files))))
+    (dolist (tlc-file tlc-files)
+      (save-excursion
+        (message "START: (metest-imenu-tlc \"%s\")" tlc-file)
+
+        (find-file tlc-file)
+        (goto-char (point-min))
+
+        (let* ((imenu-re (cadar tlc--imenu-generic-expression))
+               (got "")
+               (expected-file (replace-regexp-in-string "\\.tlc$" 
"_expected.txt" tlc-file))
+               (got-file (concat expected-file "~"))
+               (expected (when (file-exists-p expected-file)
+                           (with-temp-buffer
+                             (insert-file-contents-literally expected-file)
+                             (buffer-string))))
+               (case-fold-search nil))
+          (while (re-search-forward imenu-re nil t)
+            (setq got (concat got (match-string 1) "\n")))
+
+          (when (not (string= got expected))
+            (let ((coding-system-for-write 'raw-text-unix))
+              (write-region got nil got-file))
+            (when (not expected)
+              (error "Baseline for %s does not exists.  See %s and if it looks 
good rename it to %s"
+                     tlc-file got-file expected-file))
+            (error "Baseline for %s does not match, got: %s, expected: %s"
+                   tlc-file got-file expected-file))
+          (kill-buffer)))
+      (message "PASS: (metest-imenu-tlc \"%s\")" tlc-file)))
+  "success")
+
+(provide 'metest-imenu-tlc)
+;;; metest-imenu-tlc.el ends here
diff --git a/tests/metest.el b/tests/metest.el
index 04b42f71a3..87e223b840 100644
--- a/tests/metest.el
+++ b/tests/metest.el
@@ -39,6 +39,7 @@
 (require 'metest-font-lock-test2)
 (require 'metest-indent-test2)
 (require 'metest-imenu)
+(require 'metest-imenu-tlc)
 
 (defun metest-all-syntax-tests ()
   "Run all the syntax test cases in this file."
@@ -66,6 +67,7 @@
   (metest-run 'metest-indents-test)
 
   (metest-imenu)
+  (metest-imenu-tlc)
 
   ;; Parsing and completion are high level tools
   (metest-run 'metest-complete-test)
diff --git a/tlc.el b/tlc.el
index eecd7d5be8..4ce364fc07 100644
--- a/tlc.el
+++ b/tlc.el
@@ -137,6 +137,10 @@
   :group 'tlc
   :type 'hook)
 
+(defvar tlc--imenu-generic-expression
+  '((nil "^[[:blank:]]*%function[[:blank:]]+\\([a-zA-Z0-9_]+\\)" 1))
+  "Regexp to find function names in *.tlc files for `imenu'.")
+
 (defvar tlc-syntax-table nil
   "Syntax table used in an TLC file.")
 
@@ -233,21 +237,19 @@
   (setq mode-name "TLC")
   (use-local-map tlc-mode-map)
   (set-syntax-table tlc-syntax-table)
-  (make-local-variable 'comment-start)
-  (make-local-variable 'comment-end)
-  (make-local-variable 'comment-start-skip)
-  (setq comment-start "%% "
-        comment-end   "")
-  (setq comment-start-skip "%%\\|/%")
-  (make-local-variable 'indent-line-function)
-  (setq indent-line-function 'tlc-indent)
-  (make-local-variable 'font-lock-defaults)
-  (setq font-lock-defaults '((tlc-font-lock-keywords)
+  (setq-local comment-start "%% ")
+  (setq-local comment-end   "")
+  (setq-local comment-start-skip "%%\\|/%")
+  (setq-local indent-line-function 'tlc-indent)
+  (setq-local font-lock-defaults '((tlc-font-lock-keywords)
                              nil ; do not do string/comment highlighting
                              nil ; keywords are case sensitive.
                              ;; This puts _ as a word constituent,
                              ;; simplifying our keywords significantly
                              ((?_ . "w"))))
+
+  (setq-local imenu-generic-expression tlc--imenu-generic-expression)
+
   (tlc-version)
   (save-excursion
     (goto-char (point-min))

Reply via email to