emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/gle-mode 9d3c5826dc: Make font-lock highlighting more c


From: Stefan Monnier
Subject: [elpa] externals/gle-mode 9d3c5826dc: Make font-lock highlighting more complete
Date: Mon, 7 Nov 2022 16:15:49 -0500 (EST)

branch: externals/gle-mode
commit 9d3c5826dc6695b47cf8d3fc17b86499cbd34147
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>

    Make font-lock highlighting more complete
    
    This is inspired from Andrey Grozin's font-lock rules,
    tho completely rewritten.
    
    * gle-mode.el (gle-mode-syntax-table): Most non-word-constituent chars
    are punctuation rather than symbol constituents.
    (gle--line-syntax): New var, extracted from Andrey Grozin's font
    lock rules.
    (gle--fontify-next): New function.
    (gle-font-lock-keywords): Use it.
    (gle-mode): GLE keywords are case insensitive.
---
 gle-mode.el | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 175 insertions(+), 16 deletions(-)

diff --git a/gle-mode.el b/gle-mode.el
index dd1c0fa7a6..bf042e1104 100644
--- a/gle-mode.el
+++ b/gle-mode.el
@@ -1,6 +1,6 @@
 ;;; gle-mode.el --- Major mode to edit Graphics Layout Engine files  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 2017  Free Software Foundation, Inc
+;; Copyright (C) 2017-2022  Free Software Foundation, Inc
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Package-Requires: ((cl-lib "0.5"))
@@ -23,11 +23,11 @@
 
 ;; This is a major mode for files using the GLE (Graphics Layout Engine)
 ;; language.  See http://glx.sourceforge.net/
-;; [ Not sure why the site uses "glx", while everything else seems to use
-;;   "gle" instead.  ]
+;; [ Apparently the site uses "glx" while everything else seems to use
+;;   "gle" instead, because "gle" was already occupied in sourceforge.  ]
 
 ;; It provides:
-;; - Rudimentary code highlighting
+;; - Code highlighting
 ;; - Automatic indentation
 ;; - Flymake support (requires Emacs-26's fymake)
 ;; - Imenu support
@@ -35,8 +35,27 @@
 ;; - Completion of bloc names
 ;; - Skeletons/templates to insert or close blocs
 
+;; If you have misspelled a keyword or a command (etc.),
+;; it should jump into your eyes because it is not highlighted.
+
+;;;; Known defects:
+
+;; - `print' is not highlighted in:
+;;
+;;     if a==0 then print 0
+;;     else if a==1 then print 1
+;;     else print 2
+;;
+;; - The `gle--line-syntax' description of the GLE language was extracted
+;;   by hand from the doc and it is probably incomplete, and it is hard
+;;   to update.
+
+;;;; Contributors:
+;; Andrey Grozin <A.G.Grozin@inp.nsk.su> (2022-11-07)
+;; provided the data to build the syntax description from which
+;; the highlighting works.
+
 ;;;; TODO
-;; - Fix highlighting of function calls?
 ;; - provide more completion
 
 ;;; Code:
@@ -52,6 +71,13 @@
 
 (defvar gle-mode-syntax-table
   (let ((st (make-syntax-table)))
+    ;; Turn all symbol-constituent syntax into punctuation.
+    (map-char-table (lambda (c v)
+                      (and (equal v '(3))
+                           (set-char-table-range st c '(1))))
+                    st)
+    ;; Make `_' into a symbol-constituent again.
+    (modify-syntax-entry ?_ "_" st)
     (modify-syntax-entry ?! "<" st)
     (modify-syntax-entry ?\n ">" st)
     (modify-syntax-entry ?\" "\"" st)
@@ -225,25 +251,157 @@
 
 ;;;; Font-lock
 
+(defvar gle--line-syntax
+  (let ((blocnames
+         ;; Extracted with:
+         ;;     sed -ne 's/\(^\|.*\\sf \)begin \([[:alnum:]]*\).*/\2/p' \
+         ;;         **/*.tex | sort -u
+         '(font-lock-builtin-face
+           ("box" any ("fill") ("add") ("nobox") ("name") ("round"))
+           ("path" any ("fill") ("stroke") ("clip"))
+           ("clip") ("config") ("contour") ("fitz") ("graph") ("key")
+           ("length") ("letz") ("name") ("object") ("origin")
+           ("rotate") ("scale") ("surface") ("table") ("tex") ("texpreamble")
+           ("text" ("width")) ("translate")))
+        (bitmaps '(font-lock-constant-face ("png") ("jpeg") ("gif") ("tiff")))
+        (arcends '(font-lock-constant-face ("start") ("end") ("both"))))
+    `(font-lock-keyword-face
+      ("begin" ,@blocnames)
+      ("end" ("if") ("sub")
+             ,@(mapcar (lambda (x) (if (consp x) (list (car x)) x)) blocnames))
+      ("if" any ("then"))               ;FIXME: What can come after `then'?
+      ("else" ("if" any ("then")))      ;FIXME: What can come after `else'?
+      ("for" any ("to") ("step"))
+      ("next")
+      ("sub") ;; font-lock-function-name-face ("[[:alpha:]][[:alnum:]_]*")
+      ("next")
+      ("local")
+      ("return")
+      font-lock-preprocessor-face
+      ("include") ;; Arg is a string, so we don't highlight it specially
+      font-lock-builtin-face
+      ("define" ("marker"))
+      ("bitmap"      any ("type" ,@bitmaps))
+      ("bitmap_info" any ("type" ,@bitmaps))
+      ("orientation" font-lock-constant-face ("portrait") ("landscape"))
+      ("papersize" font-lock-constant-face
+                   ("a0paper") ("a1paper") ("a2paper") ("a3paper") ("a4paper")
+                   ("letterpaper"))
+      ("tex"  any ("name") ("add"))
+      ("draw" any ("name"))
+      ("box"  any ("name") ("fill") ("justify") ("nobox") ("round"))
+      ("circle"  any ("fill"))
+      ("ellipse" any ("fill"))
+      ("aline"          any ("arrow") ("curve") ,@arcends)
+      ("rline"          any ("arrow") ("curve") ,@arcends)
+      ("arc"            any ("arrow") ,@arcends)
+      ("elliptical_arc" any ("arrow") ,@arcends)
+      ("join" any ("curve"))
+      ("colormap" any ("color") ("palette"))
+      ("abound") ("amove") ("rmove") ("arcto")   ("bezier") ("rbezier") 
("curve")
+      ("closepath") ("gsave") ("grestore") ("defmarker") ("margins") ("marker")
+      ("postscript") ("print") ("psbbtweak") ("pscomment") ("reverse") ("save")
+      ("size") ("text") ("write")
+      ("set" ("alabeldist") ("alabelscale") ("arrowangle") ("arrowsize")
+       ("arrowstyle" font-lock-constant-face
+                     ("simple") ("filled") ("empty"))
+       ("atitledist") ("atitlescale") ("background ")
+       ("cap" font-lock-constant-face ("butt") ("round") ("square"))
+       ("color") ("dashlen") ("fill") ("font") ("fontlwidth") ("hei")
+       ("join" font-lock-constant-face ("mitre") ("round") ("bevel"))
+       ("just" font-lock-constant-face
+               ("center") ("left") ("right") ("tl") ("tc") ("tr") ("lc") ("cc")
+               ("rc") ("bl") ("bc") ("br"))
+       ("lstyle") ("lwidth") ("pattern")
+       ("texscale" font-lock-constant-face
+                   ("scale") ("fixed") ("none"))
+       ("titlescale")
+       ("ticksscale"))
+      )))
+
+(defun gle--fontify-next (desc face &optional top)
+  (let ((entries '())
+        (rules '())
+        (any (eq (car desc) 'any)))
+    (if any (pop desc))
+    (dolist (x desc)
+      (cond
+       ((consp x)
+        (push (cons (car x) (gle--fontify-next (cdr x) face))
+              entries))
+       ((null entries) (setq face x))
+       (t
+        (push (cons face entries) rules)
+        (setq entries nil)
+        (setq face x))))
+    (when entries
+      (push (cons face entries) rules))
+    (when rules
+      (cl-assert (not (and any top)))
+      (let ((arules
+             ;; List of (MORE FACE . ENTRIES) where MORE is non-nil if
+             ;; one of the ENTRIES needs further processing.
+             (mapcar (lambda (x)
+                       (cons (cl-some #'cdr (cdr x)) x))
+                     rules))
+            (regexp
+             (concat (cond (any ".*") (top "^[ \t]*") (t "[ \t]*"))
+                     "\\_<\\("
+                     (mapconcat (lambda (x)
+                                  (concat (regexp-opt (mapcar #'car (cdr x)))
+                                          "\\_>\\(\\)"))
+                                rules
+                                "\\|")
+                     "\\)")))
+        (lambda (limit)
+          (if any
+              (while (looking-at regexp)
+                (goto-char (match-end 0))
+                (let ((i 2))
+                  (while (not (match-beginning i)) (setq i (1+ i)))
+                  (let ((arule (nth (- i 2) arules)))
+                    (put-text-property (match-beginning 1) (match-end 1)
+                                       'face (cadr arule))
+                    (cl-assert (not (car arule))))))
+            (when (if top (re-search-forward regexp limit t)
+                    (looking-at regexp))
+              (goto-char (match-end 0))
+              (let ((i 2))
+                (while (not (match-beginning i)) (setq i (1+ i)))
+                (let ((arule (nth (- i 2) arules)))
+                  (put-text-property (match-beginning 1) (match-end 1)
+                                     'face (cadr arule))
+                  (when (car arule)
+                    (let* ((kw (match-string-no-properties 1))
+                           (entry (assoc kw (cddr arule))))
+                      (cl-assert entry)
+                      (when (cdr entry)
+                        (funcall (cdr entry) limit))))))
+              ;; Try again (if at top).
+              t)))))))
+
 (defvar gle-font-lock-keywords
   `(("^[ \t]*\\(\\(?:\\sw\\|\\s_\\)+\\)[ \t]*="
-     (1 font-lock-variable-name-face))
+     (1 'font-lock-variable-name-face))
     ("^[ \t]*if[ \t][^!\n;]*[ \t]\\(then\\)\\_>"
-     (1 font-lock-keyword-face))
+     (1 'font-lock-keyword-face))
     ("^[ \t]*for[ \t][^!\n;]*[ \t]\\(to\\)\\_>\\(?:[^!\n;]*[ 
\t]\\(step\\)\\_>\\)?"
-     (1 font-lock-keyword-face) (2 font-lock-keyword-face nil t))
+     (1 'font-lock-keyword-face) (2 'font-lock-keyword-face nil t))
     ("^[ \t]*else[ \t]+\\(if\\)[ \t][^!\n;]*[ \t]\\(then\\)\\_>"
-     (1 font-lock-keyword-face) (2 font-lock-keyword-face))
+     (1 'font-lock-keyword-face) (2 'font-lock-keyword-face))
     (,(concat "^[ \t]*end[ \t]+\\("
               (regexp-opt `("if" "sub" ,@gle--bloc-names))
               "\\_>\\)")
-     (1 font-lock-keyword-face))
+     (1 'font-lock-keyword-face))
     (,(concat "^[ \t]*begin[ \t]+\\(" (regexp-opt gle--bloc-names) "\\_>\\)")
-     (1 font-lock-keyword-face))
+     (1 'font-lock-keyword-face))
     ("^[ \t]*sub[ \t]*\\(\\(?:\\sw\\|\\s_\\)+\\)"
-     (1 font-lock-function-name-face))
+     (1 'font-lock-function-name-face))
+    ("^[ \t]*\\(@[[:alpha:]][[:alnum:]_]*\\)" (1 
'font-lock-function-name-face))
+    (,(gle--fontify-next gle--line-syntax nil 'top))
     ;; FIXME: Actually, this can also be a function call!
-    ("^[ \t]*\\(\\(?:\\sw\\|\\s_\\)+\\)" (1 font-lock-keyword-face))))
+    ;; ("^[ \t]*\\([[:alpha:]][[:alnum:]_]*\\)" (1 'font-lock-keyword-face))
+    ("\\_<\\([[:alpha:]][[:alnum:]_]*\\)(" (1 'font-lock-function-name-face))))
 
 ;;;; Flymake
 
@@ -323,6 +481,7 @@ See `flymake-diagnostic-functions' for documentation of 
REPORT-FN."
 ;;;; Completion
 
 (defun gle--capf-data ()
+  ;; FIXME: Use `gle--line-syntax'!
   (save-excursion
     (skip-chars-backward "a-z")
     (when (looking-back "^[ \t]*\\(?:begin\\|end\\)[ \t]+"
@@ -469,8 +628,8 @@ NAME is the kind of bloc to insert."
 
 (defvar gle-mode-map
   (let ((map (make-sparse-keymap)))
-    (define-key map [?\C-c ?\C-e] 'gle-insert-close)
-    (define-key map [?\C-c ?\C-o] 'gle-insert-bloc)
+    (define-key map [?\C-c ?\C-e] #'gle-insert-close)
+    (define-key map [?\C-c ?\C-o] #'gle-insert-bloc)
     map))
 
 ;;;###autoload
@@ -485,7 +644,7 @@ NAME is the kind of bloc to insert."
               :forward-token #'gle-smie-forward-token
               :backward-token #'gle-smie-backward-token)
   (setq-local font-lock-defaults
-              '(gle-font-lock-keywords))
+              '(gle-font-lock-keywords nil t))
   (setq-local imenu-generic-expression gle-imenu-generic-expression)
   (add-hook 'flymake-diagnostic-functions #'gle--flymake nil 'local)
   (add-hook 'completion-at-point-functions #'gle--capf-data nil 'local)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]