branch: elpa/j-mode
commit 2f0489a1bfde146b3302c6506bc1209bad0791eb
Author: LdBeth <andp...@foxmail.com>
Commit: LdBeth <andp...@foxmail.com>

    Update for Emacs 29
    
    Update for J9.5, support direct definition, implement indent line,
    various fixes.
---
 j-console.el   |  19 +++++----
 j-font-lock.el |  96 ++++++++++++++++++++++++++++--------------
 j-help.el      |  50 ++++++++--------------
 j-mode.el      | 129 +++++++++++++++++++++++++++++++++++++++++++++------------
 4 files changed, 197 insertions(+), 97 deletions(-)

diff --git a/j-console.el b/j-console.el
index 82833851bb..ff7cc50b21 100644
--- a/j-console.el
+++ b/j-console.el
@@ -1,12 +1,13 @@
-
+;; -*- lexical-binding:t -*-
 ;;; j-mode.el --- Major mode for editing J programs
 
 ;; Copyright (C) 2012 Zachary Elliott
+;; Copyright (C) 2023 LdBeth
 ;;
 ;; Authors: Zachary Elliott <zacharyellio...@gmail.com>
-;; URL: http://github.com/zellio/j-mode
-;; Version: 1.1.1
-;; Keywords: J, Languages
+;; URL: http://github.com/ldbeth/j-mode
+;; Version: 2.0.0
+;; Keywords: J, Langauges
 
 ;; This file is not part of GNU Emacs.
 
@@ -46,7 +47,7 @@
   :group 'j
   :prefix "j-console-")
 
-(defcustom j-console-cmd "ijconsole"
+(defcustom j-console-cmd "jc"
   "Name of the executable used for the J REPL session"
   :type 'string
   :group 'j-console)
@@ -86,7 +87,8 @@ Should be NIL if there is no file not the empty string"
 
 (defun j-console-create-session ()
   "Starts a comint session wrapped around the j-console-cmd"
-  (setq comint-process-echoes t)
+  (setq comint-process-echoes nil
+        comint-use-prompt-regexp t)
   (apply 'make-comint j-console-cmd-buffer-name
          j-console-cmd j-console-cmd-init-file j-console-cmd-args)
   (mapc
@@ -110,7 +112,8 @@ Should be NIL if there is no file not the empty string"
         (get-process j-console-cmd-buffer-name))))
 
 (define-derived-mode inferior-j-mode comint-mode "Inferior J"
-  "Major mode for J inferior process.")
+  "Major mode for J inferior process."
+  (setq comint-prompt-regexp "\s+"))
 
 ;;;###autoload
 (defun j-console ()
@@ -135,7 +138,7 @@ the containing buffer"
 (defun j-console-execute-line ()
   "Sends current line to the j-console-cmd session and exectues it"
   (interactive)
-  (j-console-execute-region (point-at-bol) (point-at-eol)))
+  (j-console-execute-region (pos-bol) (pos-eol)))
 
 (defun j-console-execute-buffer ()
   "Sends current buffer to the j-console-cmd session and exectues it"
diff --git a/j-font-lock.el b/j-font-lock.el
index 46511069f2..d7649f2fef 100644
--- a/j-font-lock.el
+++ b/j-font-lock.el
@@ -1,12 +1,13 @@
-
+;; -*- lexical-binding:t -*-
 ;;; j-font-lock.el --- font-lock extension for j-mode
 
 ;; Copyright (C) 2012 Zachary Elliott
+;; Copyright (C) 2023 LdBeth
 ;;
 ;; Authors: Zachary Elliott <zacharyellio...@gmail.com>
-;; URL: http://github.com/zellio/j-mode
-;; Version: 1.1.1
-;; Keywords: J, Languages
+;; URL: http://github.com/ldbeth/j-mode
+;; Version: 2.0.0
+;; Keywords: J, Langauges
 
 ;; This file is not part of GNU Emacs.
 
@@ -43,9 +44,6 @@
 ;;; Code:
 
 
-;; (defconst j-font-lock-version "1.1.1"
-;;   "`j-font-lock' version")
-
 (defgroup j-font-lock nil
   "font-lock extension for j-mode"
   :group 'j
@@ -94,14 +92,37 @@
     (modify-syntax-entry ?\( "()"  table)
     (modify-syntax-entry ?\) ")("  table)
     (modify-syntax-entry ?\' "\""  table)
-    (modify-syntax-entry ?N "w 1" table)
-    (modify-syntax-entry ?\B "w 2" table)
+    (modify-syntax-entry ?N "w 1"  table)
+    (modify-syntax-entry ?B "w 2"  table)
     (modify-syntax-entry ?\n ">"   table)
     (modify-syntax-entry ?\r ">"   table)
     table)
   "Syntax table for j-mode")
 
-(defvar j-font-lock-constants '())
+(defvar j-font-lock-constants
+  '(
+    ;; char codes
+    "CR" "CRLF" "LF" "TAB"
+    ;; grammar codes
+    ;;0     1          2            3      3       4
+    "noun" "adverb"  "conjunction" "verb" "monad" "dyad"
+    ))
+
+(defvar j-font-lock-builtins
+  `(;; modules
+    "require" "load" "loadd" "script" "scriptd"
+    "jpath" "jcwdpath" "jhostpath" "jsystemdefs"
+    ;; OO
+    "coclass" "cocreate" "cocurrent" "codestroy" "coerase"
+    "coextend" "cofullname" "coinsert" "coname" "conames" "conew"
+    "conl" "copath" "coreset"
+    ;; environment
+    "type" "names" "nameclass" "nc" "namelist" "nl" "erase"
+    ;; system
+    "assert"
+    "getenv" "setenv" "exit" "stdin" "stdout" "stderr"
+    ;; :   :0
+    "def" "define" ))
 
 (defvar j-font-lock-control-structures
   '("assert."  "break."  "continue."  "while."  "whilst."  "for."  "do."  
"end."
@@ -110,45 +131,52 @@
     ;; "for_[a-zA-Z]+\\."  "goto_[a-zA-Z]+\\."  "label_[a-zA-Z]+\\."
     ))
 
+(defvar j-font-lock-direct-definition
+  '("{{" "}}"))
+
 (defvar j-font-lock-foreign-conjunctions
-  '("0!:" "1!:" "2!:" "3!:" "4!:" "5!:" "6!:" "7!:" "8!:" "9!:" "11!:" "13!:"
+  '("0!:" "1!:" "2!:" "3!:" "4!:" "5!:" "6!:" "7!:" "8!:" "9!:" "13!:"
     "15!:" "18!:" "128!:" ))
 
 (defvar j-font-lock-len-3-verbs
-  '("_9:" "p.." "{::"))
+  '("p.." "{::" "__:"))
 (defvar j-font-lock-len-2-verbs
   '("x:" "u:" "s:" "r." "q:" "p:" "p." "o." "L." "j." "I." "i:" "i." "E." "e."
     "C." "A." "?." "\":" "\"." "}:" "}." "{:" "{." "[:" "/:" "\\:" "#:" "#." 
";:" ",:"
     ",." "|:" "|." "~:" "~." "$:" "$." "^." "%:" "%." "-:" "-." "*:" "*."  "+:"
     "+." "_:" ">:" ">." "<:" "<."))
 (defvar j-font-lock-len-1-verbs
-  '("?" "{" "]" "[" ":" "!" "#" ";" "," "|" "$" "^" "%" "-" "*" "+" ">" "<" 
"="))
+  '("?" "{" "]" "[" "!" "#" ";" "," "|" "$" "^" "%" "-" "*" "+" ">" "<" "="))
 (defvar j-font-lock-verbs
   (append j-font-lock-len-3-verbs j-font-lock-len-2-verbs 
j-font-lock-len-1-verbs))
 
+(defvar j-font-lock-len-3-adverbs
+  '("\\.."))
 (defvar j-font-lock-len-2-adverbs
-  '("t:" "t." "M." "f." "b." "/."))
+  '("]:" "M." "f." "b." "/." "\\."))
 (defvar j-font-lock-len-1-adverbs
-  '("}" "." "\\" "/" "~"))
+  '("}" "\\" "/" "~"))
 (defvar j-font-lock-adverbs
-  (append j-font-lock-len-2-adverbs j-font-lock-len-1-adverbs))
+  (append j-font-lock-len-3-adverbs j-font-lock-len-2-adverbs 
j-font-lock-len-1-adverbs))
 
 (defvar j-font-lock-len-3-others
   '("NB."))
 (defvar j-font-lock-len-2-others
-  '("=." "=:" "_." "a." "a:"))
+  '("=." "=:" "a." "a:" ;; "__" "_."
+    ))
 (defvar j-font-lock-len-1-others
   '("_" ))
 (defvar j-font-lock-others
   (append j-font-lock-len-3-others j-font-lock-len-2-others 
j-font-lock-len-1-others))
 
 (defvar j-font-lock-len-3-conjunctions
-  '("&.:"))
+  '("&.:" "F.." "F.:" "F:." "F::"))
 (defvar j-font-lock-len-2-conjunctions
-  '("T." "S:" "L:" "H." "D:" "D." "d." "&:" "&." "@:" "@." "`:" "!:" "!." ";."
-    "::" ":." ".:" ".." "^:"))
+  '("T." "t." "S:" "L:" "H." "D:" "D." "d." "F." "F:" "m."
+    "&:" "&." "@:" "@." "`:" "!:" "!." ";."
+    "::" ":." ".:" ".." "^:" " ."))
 (defvar j-font-lock-len-1-conjunctions
-  '("&" "@" "`" "\"" ":" "."))
+  '("&" "@" "`" "\"" ":"))
 (defvar j-font-lock-conjunctions
   (append j-font-lock-len-3-conjunctions
           j-font-lock-len-2-conjunctions
@@ -159,24 +187,31 @@
   `(
     ("\\([_a-zA-Z0-9]+\\)\s*\\(=[.:]\\)"
      (1 font-lock-variable-name-face) (2 j-other-face))
-
     (,(regexp-opt j-font-lock-foreign-conjunctions) . font-lock-warning-face)
-    (,(concat (regexp-opt j-font-lock-control-structures)
-              "\\|\\(?:\\(?:for\\|goto\\|label\\)_[a-zA-Z]+\\.\\)")
+    (,(concat "\\<" (regexp-opt j-font-lock-control-structures)
+              "\\|\\(?:\\(for\\|goto\\|label\\)_[a-zA-Z]+\\.\\)")
      . font-lock-keyword-face)
+    (,(concat "\\<" (regexp-opt j-font-lock-builtins)) . 
font-lock-builtin-face)
     (,(regexp-opt j-font-lock-constants) . font-lock-constant-face)
-    (,(regexp-opt j-font-lock-len-3-verbs) . j-verb-face)
+    (,(concat (regexp-opt j-font-lock-len-3-verbs)
+              "\\|\\(?:_[0-9]:\\)")
+     . j-verb-face)
+    (,(regexp-opt j-font-lock-len-3-adverbs) . j-adverb-face)
     (,(regexp-opt j-font-lock-len-3-conjunctions) . j-conjunction-face)
     ;;(,(regexp-opt j-font-lock-len-3-others) . )
-    (,(regexp-opt j-font-lock-len-2-verbs) . j-verb-face)
+    (,(concat (regexp-opt j-font-lock-len-2-verbs)
+              "\\|\\(?:[0-9]:\\)")
+     . j-verb-face)
     (,(regexp-opt j-font-lock-len-2-adverbs) . j-adverb-face)
     (,(regexp-opt j-font-lock-len-2-conjunctions) . j-conjunction-face)
-    ;;(,(regexp-opt j-font-lock-len-2-others) . )
+    (,(regexp-opt j-font-lock-len-2-others) . j-other-face)
+    (,(regexp-opt j-font-lock-direct-definition) . font-lock-keyword-face)
     (,(regexp-opt j-font-lock-len-1-verbs) . j-verb-face)
     (,(regexp-opt j-font-lock-len-1-adverbs) . j-adverb-face)
     (,(regexp-opt j-font-lock-len-1-conjunctions) . j-conjunction-face)
-    ;;(,(regexp-opt j-font-lock-len-1-other) . )
-    ) "J Mode font lock keys words")
+    ;;(,(regexp-opt j-font-lock-len-1-others) . j-other-face)
+    )
+  "J Mode font lock keys words")
 
 (defun j-font-lock-syntactic-face-function (state)
   "Function for detection of string vs. Comment Note: J comments
@@ -187,7 +222,8 @@ this in emacs and it poses problems"
       (and (<= (+ start-pos 3) (point-max))
            (eq (char-after start-pos) ?N)
            (string= (buffer-substring-no-properties
-                     start-pos (+ start-pos 3)) "NB.")
+                     start-pos (+ start-pos 3))
+                    "NB.")
            font-lock-comment-face))))
 
 (provide 'j-font-lock)
diff --git a/j-help.el b/j-help.el
index cf0845686e..d28c930809 100644
--- a/j-help.el
+++ b/j-help.el
@@ -1,10 +1,12 @@
-;;; j-help.el --- Documentation extention for j-mode -*- lexical-binding: t; 
-*-
+;; -*- lexical-binding:t -*-
+;;; j-help.el --- Documentation extention for j-mode
 
 ;; Copyright (C) 2012 Zachary Elliott
+;; Copyright (C) 2023 LdBeth
 ;;
 ;; Authors: Zachary Elliott <zacharyellio...@gmail.com>
-;; URL: http://github.com/zellio/j-mode
-;; Version: 1.1.1
+;; URL: http://github.com/ldbeth/j-mode
+;; Version: 2.0.0
 ;; Keywords: J, Languages
 
 ;; This file is not part of GNU Emacs.
@@ -41,19 +43,6 @@
 
 ;;; Code:
 
-(defmacro if-let ( binding then &optional else )
-  "Bind value according to BINDING and check for truthy-ness
-If the test passes then eval THEN with the BINDING varlist bound
-If no, eval ELSE with no binding"
-  (let* ((sym (caar binding))
-         (tst (cdar binding))
-         (gts (gensym)))
-    `(let ((,gts ,@tst))
-       (if ,gts
-         (let ((,sym ,gts))
-           ,then)
-         ,else))))
-
 (defun group-by* ( list fn prev coll agr )
   "Helper method for the group-by function. Should not be called directly."
   (if list
@@ -70,15 +59,12 @@ It groups the objects in LIST according to the predicate FN"
   (let ((sl (sort list (lambda (x y) (< (funcall fn x) (funcall fn y))))))
     (group-by* sl fn '() '() '())))
 
-(unless (fboundp 'some)
-  (defun some ( fn list )
-    (when list
-      (let ((val (funcall fn (car list))))
-       (if val val (some fn (cdr list)))))))
-
-(unless (fboundp 'caddr)
-  (defun caddr ( list )
-    (car (cdr (cdr list)))))
+(defun j-some ( fn list )
+  (let (val)
+    (while (and list (not val))
+      (setq val (funcall fn (car list))
+            list (cdr list)))
+    val))
 
 (defgroup j-help nil
   "Documentation extention for j-mode"
@@ -154,7 +140,7 @@ It groups the objects in LIST according to the predicate FN"
   (let ((dic (j-help-valid-dictionary)))
     (if (or (not alist-data) (string= dic ""))
         (error "%s" "No dictionary found. Please specify a dictionary.")
-      (let ((name (car alist-data))
+      (let ((_name (car alist-data))
             (doc-name (cdr alist-data)))
         (format "%s/%s.%s" dic doc-name "htm")))))
 
@@ -167,7 +153,7 @@ It groups the objects in LIST according to the predicate FN"
 
 string * int -> (string * string) list"
   (unless (or (< point 0) (< (length s) point))
-    (some
+    (j-some
      (lambda (x)
        (let* ((check-size (car x)))
          (if (and
@@ -182,8 +168,8 @@ string * int -> (string * string) list"
   "int -> (string * string) list"
   (save-excursion
     (goto-char point)
-    (let* ((bol (point-at-bol))
-           (eol (point-at-eol))
+    (let* ((bol (pos-bol))
+           (eol (pos-eol))
            (s (buffer-substring-no-properties bol eol)))
       (j-help-determine-symbol s (- point bol)))))
 
@@ -203,9 +189,9 @@ string * int -> (string * string) list"
   (save-excursion
     (goto-char point)
     (j-help-branch-determine-symbol-at-point*
-     (buffer-substring-no-properties (point-at-bol) (point-at-eol))
-     (- (max (- point j-help-symbol-search-branch-limit) (point-at-bol)) 
(point-at-bol))
-     (- point (point-at-bol))
+     (buffer-substring-no-properties (pos-bol) (pos-eol))
+     (- (max (- point j-help-symbol-search-branch-limit) (pos-bol)) (pos-bol))
+     (- point (pos-bol))
      nil)))
 
 ;;;###autoload
diff --git a/j-mode.el b/j-mode.el
index 5cadb58213..2cff9e11d6 100644
--- a/j-mode.el
+++ b/j-mode.el
@@ -1,12 +1,13 @@
-
+;; -*- lexical-binding:t -*-
 ;;; j-mode.el --- Major mode for editing J programs
 
 ;; Copyright (C) 2012 Zachary Elliott
+;; Copyright (C) 2023 LdBeth
 ;;
 ;; Authors: Zachary Elliott <zacharyellio...@gmail.com>
-;; URL: http://github.com/zellio/j-mode
-;; Version: 1.1.1
-;; Keywords: J, Languages
+;; URL: http://github.com/ldbeth/j-mode
+;; Version: 2.0.0
+;; Keywords: J, Langauges
 
 ;; This file is not part of GNU Emacs.
 
@@ -47,8 +48,7 @@
 ;;; Code:
 
 ;; Required eval depth for older systems
-(setq max-lisp-eval-depth (max 500 max-lisp-eval-depth))
-
+;; (setq max-lisp-eval-depth (max 500 max-lisp-eval-depth))
 (require 'j-font-lock)
 (require 'j-console)
 (require 'j-help)
@@ -57,7 +57,7 @@
 (defconst j-mode-version "1.1.1"
   "`j-mode' version")
 
-(defgroup j-mode nil
+(defgroup j nil
   "A mode for J"
   :group 'languages
   :prefix "j-")
@@ -67,6 +67,83 @@
   :type 'hook
   :group 'j)
 
+(defcustom j-indent-offset 2
+  "Amount of offset per level of indentation."
+  :type 'natnum
+  :group 'j)
+
+(defconst j-indenting-keywords-regexp
+  (concat "\\<"
+          (regexp-opt '(;;"do\\."
+                        "if." "else." "elseif."
+                        "select." "case." "fcase."
+                        "throw."
+                        "try." "except." "catch." "catcht."
+                        "while." "whilst."
+                        "for." "for_"
+                        "label_"))
+          "\\|\\([_a-zA-Z0-9]+\\)\s*\\(=[.:]\\)\s*{{"))
+(defconst j-dedenting-keywords-regexp
+  (concat "}}\\|\\(\\<"
+          (regexp-opt '("end."
+                        "else." "elseif."
+                        "case." "fcase."
+                        "catch." "catcht." "except."))
+          "\\)"))
+
+(defun j-thing-outside-string (thing-regexp)
+  "Look for REGEXP from `point' til `point-at-eol' outside strings and
+comments. Match-data is set for THING-REGEXP. Returns nil if no match was
+found, else beginning and end of the match."
+  (save-excursion
+    (if (not (search-forward-regexp thing-regexp (pos-eol) t))
+        nil
+        (let* ((thing-begin (match-beginning 0))
+               (thing-end (match-end 0))
+               (parse (save-excursion
+                        (parse-partial-sexp (pos-eol) thing-end))))
+          (if (or (nth 3 parse) (nth 4 parse))
+              nil
+              (list thing-begin thing-end))))))
+
+(defun j-compute-indentation ()
+  "Return what indentation should be in effect, disregarding
+contents of current line."
+  (let ((indent 0))
+    (save-excursion
+      ;; skip empty/comment lines, if that leaves us in the first line, return 0
+      (while (and (= (forward-line -1) 0)
+                  (if (looking-at "\\s *\\\\?$")
+                      t
+                    (setq indent (save-match-data
+                                   (back-to-indentation)
+                                   (if (and (looking-at 
j-indenting-keywords-regexp)
+                                            (progn
+                                              (goto-char (match-end 0))
+                                              (not (j-thing-outside-string 
"\\<end\\."))))
+                                       (+ (current-indentation) 
j-indent-offset)
+                                     (current-indentation))))
+                    nil))))
+    indent))
+
+(defun j-indent-line ()
+  "Indent current line correctly."
+  (interactive)
+  (let ((old-point (point)))
+    (save-match-data
+      (back-to-indentation)
+      (let* ((tentative-indent (j-compute-indentation))
+             ;;FIXME doesn't handle comments correctly
+             (indent (if (looking-at j-dedenting-keywords-regexp)
+                         (- tentative-indent j-indent-offset)
+                         tentative-indent))
+             (delta (- indent (current-indentation))))
+;;         (message "###DEBUGi:%d t:%d" indent tentative-indent)
+        (indent-line-to indent)
+        (back-to-indentation)
+        (goto-char (max (point) (+ old-point delta))))
+      )))
+
 (defvar j-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "C-c !")   'j-console)
@@ -91,27 +168,25 @@
     ["Help on J-mode" describe-mode t]))
 
 ;;;###autoload
-(defun j-mode ()
+(define-derived-mode j-mode prog-mode "J"
   "Major mode for editing J"
-  (interactive)
-  (kill-all-local-variables)
-  (use-local-map j-mode-map)
-  (setq mode-name "J"
-        major-mode 'j-mode)
-  (set-syntax-table j-font-lock-syntax-table)
-  (set (make-local-variable 'comment-start)
-       "NB. ")
-  (set (make-local-variable 'comment-start-skip)
-       "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)NB. *")
-  (set (make-local-variable 'font-lock-comment-start-skip)
-       "NB. *")
-  (set (make-local-variable 'font-lock-defaults)
-       '(j-font-lock-keywords
-         nil nil nil nil
-         ;;(font-lock-mark-block-function . mark-defun)
-         (font-lock-syntactic-face-function
-          . j-font-lock-syntactic-face-function)))
-  (run-mode-hooks 'j-mode-hook))
+  :group 'j
+  :syntax-table j-font-lock-syntax-table
+  (setq-local comment-start
+              "NB. "
+              comment-start-skip
+              "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)NB. *"
+              comment-column 40
+              indent-tabs-mode nil
+              indent-line-function #'j-indent-line
+              font-lock-comment-start-skip
+              "NB. *"
+              font-lock-defaults
+              '(j-font-lock-keywords
+                nil nil nil nil
+                ;;(font-lock-mark-block-function . mark-defun)
+                (font-lock-syntactic-face-function
+                 . j-font-lock-syntactic-face-function))))
 
 
 ;;;###autoload

Reply via email to