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