branch: elpa/j-mode commit 65753691027760178f60efa2dec850d372ae931b Author: LdBeth <andp...@foxmail.com> Commit: LdBeth <andp...@foxmail.com>
Version 2.0.1 Added definition block navigation (C-M-a, C-M-e). Fixed highlighting. --- j-console.el | 2 +- j-font-lock.el | 90 ++++++++++++++++++++++++++++++++-------------------------- j-help.el | 4 +-- j-mode.el | 82 +++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 124 insertions(+), 54 deletions(-) diff --git a/j-console.el b/j-console.el index ff8418a14e..7998205e37 100644 --- a/j-console.el +++ b/j-console.el @@ -6,7 +6,7 @@ ;; ;; Authors: Zachary Elliott <zacharyellio...@gmail.com> ;; URL: http://github.com/ldbeth/j-mode -;; Version: 2.0.0 +;; Version: 2.0.1 ;; Keywords: J, Langauges ;; This file is not part of GNU Emacs. diff --git a/j-font-lock.el b/j-font-lock.el index 1606204108..18bee08b70 100644 --- a/j-font-lock.el +++ b/j-font-lock.el @@ -2,11 +2,11 @@ ;;; j-font-lock.el --- font-lock extension for j-mode ;; Copyright (C) 2012 Zachary Elliott -;; Copyright (C) 2023 LdBeth +;; Copyright (C) 2023, 2024 LdBeth ;; ;; Authors: Zachary Elliott <zacharyellio...@gmail.com> ;; URL: http://github.com/ldbeth/j-mode -;; Version: 2.0.0 +;; Version: 2.0.1 ;; Keywords: J, Langauges ;; This file is not part of GNU Emacs. @@ -55,29 +55,25 @@ :group 'j :group 'j-font-lock) -(defvar j-verb-face - (defface j-verb-face - `((t (:foreground "Red"))) +(defface j-verb-face + `((t (:foreground "Red"))) "Font Lock mode face used to higlight vrebs" - :group 'j-faces)) + :group 'j-faces) -(defvar j-adverb-face - (defface j-adverb-face - `((t (:foreground "Green"))) +(defface j-adverb-face + `((t (:foreground "Green"))) "Font Lock mode face used to higlight adverbs" - :group 'j-faces)) + :group 'j-faces) -(defvar j-conjunction-face - (defface j-conjunction-face - `((t (:foreground "Blue"))) +(defface j-conjunction-face + `((t (:foreground "Blue"))) "Font Lock mode face used to higlight conjunctions" - :group 'j-faces)) + :group 'j-faces) -(defvar j-other-face - (defface j-other-face - `((t (:foreground "Black"))) +(defface j-other-face + `((t (:foreground "Black"))) "Font Lock mode face used to higlight others" - :group 'j-faces)) + :group 'j-faces) (defvar j-font-lock-syntax-table (let ((table (make-syntax-table))) @@ -103,7 +99,8 @@ (defalias 'j-mode-syntax-propertize (syntax-propertize-rules ("^\\()\\)" (1 ".")) - ("{{\\()\\)\s" (1 ".")))) + ("{{\\()\\)" (1 ".")) + ("\\('\\)`?[0-9A-Z_a-z ]*\\('\\)\s*=[.:]" (1 ".") (2 ".")))) (defvar j-font-lock-constants '( @@ -147,8 +144,9 @@ (defvar j-font-lock-len-3-verbs '("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." "T." "?." "\":" "\"." "}:" "}." "{:" "{." "[:" "/:" "\\:" "#:" "#." ";:" ",:" + '("u:" "u." "v." "s:" "r." "q:" "p:" "p." "o." "L." "j." "I." + "i:" "i." "E." "e." "x:" "Z:" + "C." "c." "A." "T." "?." "\":" "\"." "}:" "}." "{:" "{." "[:" "/:" "\\:" "#:" "#." ";:" ",:" ",." "|:" "|." "~:" "~." "$:" "$." "^." "%:" "%." "-:" "-." "*:" "*." "+:" "+." ">:" ">." "<:" "<.")) (defvar j-font-lock-len-1-verbs @@ -157,7 +155,7 @@ (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 '("]:" "M." "f." "b." "/." "\\.")) (defvar j-font-lock-len-1-adverbs @@ -179,7 +177,7 @@ '("&.:" "F.." "F.:" "F:." "F::" " ::" " :.")) (defvar j-font-lock-len-2-conjunctions '("t." "S:" "L:" "H." "D:" "D." "d." "F." "F:" "m." - "&:" "&." "@:" "@." "`:" "!:" "!." ";." + "&:" "&." "@:" "@." "`:" "!:" "!." ";." "[." "]." "^:" " ." " :")) (defvar j-font-lock-len-1-conjunctions '("&" "@" "`" "\"")) @@ -188,13 +186,25 @@ j-font-lock-len-2-conjunctions j-font-lock-len-1-conjunctions)) +(defconst j-font-lock-multiassign-regexp + (rx (group "'") (? "`") (* (any "_a-zA-Z0-9 ")) (group "'") + (* "\s") "=" (or "." ":"))) + +(defun j-font-lock-prematch-variable () + (goto-char (match-end 1)) + (match-beginning 2)) (defvar j-font-lock-keywords `( - (,(rx (seq (group (* (any "_a-zA-Z0-9"))) - (* "\s") - (group "=" (or "." ":")))) - (1 font-lock-variable-name-face) (2 j-other-face)) + (,(rx (group (+ (any "_a-zA-Z0-9"))) + (* "\s") "=" (or "." ":")) + (1 font-lock-variable-name-face)) + (,j-font-lock-multiassign-regexp + (1 font-lock-keyword-face) + (2 font-lock-keyword-face) + ("[_a-zA-Z0-9]+" + (j-font-lock-prematch-variable) nil + (0 font-lock-variable-name-face))) (,(rx bow (any "a-zA-Z") (* (any "_a-zA-Z0-9")) "_:") ;; Self-Effacing References @@ -213,26 +223,26 @@ eow) . font-lock-constant-face) (,(regexp-opt j-font-lock-len-3-verbs) - . 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) + . '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) . ) (,(rx (or (regexp (regexp-opt j-font-lock-len-2-verbs)) (seq symbol-start (opt "_") (regexp "[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) . 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-others) . j-other-face) + . '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) . '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-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 + "Function for detection of string vs. Comment. Note: J comments are three chars longs, there is no easy / evident way to handle this in emacs and it poses problems" (if (nth 3 state) font-lock-string-face diff --git a/j-help.el b/j-help.el index 08f9ba1fe6..77898f0eda 100644 --- a/j-help.el +++ b/j-help.el @@ -6,7 +6,7 @@ ;; ;; Authors: Zachary Elliott <zacharyellio...@gmail.com> ;; URL: http://github.com/ldbeth/j-mode -;; Version: 2.0.0 +;; Version: 2.0.1 ;; Keywords: J, Languages ;; This file is not part of GNU Emacs. @@ -121,7 +121,7 @@ It groups the objects in LIST according to the predicate FN" (defconst j-help-dictionary-data-block (mapcar (lambda (l) (list (length (caar l)) - (regexp-opt (mapcar 'car l)) + (regexp-opt (mapcar #'car l)) l)) (delq nil (group-by j-help-voc-alist (lambda (x) (length (car x)))))) "(int * string * (string * string) alist) list") diff --git a/j-mode.el b/j-mode.el index f5ea9489a1..1cc0ea7de5 100644 --- a/j-mode.el +++ b/j-mode.el @@ -2,11 +2,11 @@ ;;; j-mode.el --- Major mode for editing J programs ;; Copyright (C) 2012 Zachary Elliott -;; Copyright (C) 2023 LdBeth +;; Copyright (C) 2023, 2024 LdBeth ;; ;; Authors: Zachary Elliott <zacharyellio...@gmail.com> ;; URL: http://github.com/ldbeth/j-mode -;; Version: 2.0.0 +;; Version: 2.0.1 ;; Keywords: J, Langauges ;; This file is not part of GNU Emacs. @@ -77,28 +77,31 @@ "if." "else." "elseif." "select." "case." "fcase." "throw." - "try." "except." "catch." "catcht." + "try." "except." "catch." "catcht." "catchd." "while." "whilst." "for."))) (seq (or "for" "goto" "label") (regexp "_[a-zA-Z]+\\.")))) - (seq (regexp "[_a-zA-Z0-9]+") + (seq (regexp "[_a-zA-Z0-9]+") (? "'") (* "\s") "=" (or "." ":") (* "\s") (or "{{" - (seq "0" (+ "\s") ":" (* "\s") - (regexp + (seq (regexp (regexp-opt '("dyad" "monad" "adverb" "verb" "conjunction" "1" "2" "3" "4"))) - eol)))))) + (+ "\s") + (or (seq ":" (* "\s") "0") + "define"))))))) + (defconst j-dedenting-keywords-regexp (rx (or "}}" - (seq bol ")" eol) + (seq ")" eol) (seq bow (regexp (regexp-opt '("end." "else." "elseif." "case." "fcase." - "catch." "catcht." "except."))))))) + "catch." "catcht." "catchd." + "except."))))))) (defun j-thing-outside-string (thing-regexp) "Look for REGEXP from `point' til `point-at-eol' outside strings and @@ -109,8 +112,10 @@ found, else beginning and end of the match." nil (let* ((thing-begin (match-beginning 0)) (thing-end (match-end 0)) + (eol (pos-eol)) (parse (save-excursion - (parse-partial-sexp (pos-eol) thing-end)))) + (parse-partial-sexp eol + (max eol thing-end))))) (if (or (nth 3 parse) (nth 4 parse)) nil (list thing-begin thing-end)))))) @@ -147,7 +152,7 @@ contents of current line." (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) + (max 0 (- tentative-indent j-indent-offset)) tentative-indent)) (delta (- indent (current-indentation)))) ;; (message "###DEBUGi:%d t:%d" indent tentative-indent) @@ -156,6 +161,59 @@ contents of current line." (goto-char (max (point) (+ old-point delta)))) ))) +(defun j-which-explict-definition () + "Return nil, `:one-liner' or `:multi-liner' depending on what + kind of explicit definition we are `looking-at'. Modifies `match-data'!" + ;; XXX we could dump the check for NB. if we prepending '^' to the others + (cond ((j-thing-outside-string (rx (or (seq bow "define") + (seq ":" (* "\s") "0")) + (* "\s") + eol)) + :multi-liner) + ((j-thing-outside-string (rx (or (seq bow "def") + " :") + (+ "\s"))) + (pcase (char-after (match-end 0)) + ('nil (error "XXX Illegal definition?")) + (?\' :one-liner) + (_ :multi-liner))) + ((j-thing-outside-string "{{") :direct) + (t nil))) + +(defun j-end-of-explicit-definition () + "Goto the end of the next explicit definition below point." + (interactive) + (if (not (= (point) (pos-eol))) + (beginning-of-line) + (forward-line 1)) + (beginning-of-line) + (save-match-data + (pcase (j-which-explict-definition) + ('nil (forward-line 1)) + (:one-liner (beginning-of-line 2) t) + (:multi-liner (search-forward-regexp "^)") t) + (:direct (search-forward-regexp + (rx "}}" (or eol (not (any ".:"))))) + t)))) + +(defun j-beginning-of-explicit-definition () + "Got the start of the next explicit definition above point." + (interactive) + (let ((cur (point)) beg end) + (save-excursion + (if (not (= (point) (pos-bol))) + (beginning-of-line) + (forward-line -1)) + (save-match-data + (while (not (or (j-which-explict-definition) + (= (pos-bol) (point-min)))) + (forward-line -1))) + (setq beg (point)) + (j-end-of-explicit-definition) + (setq end (point))) + (if (> end cur) (goto-char beg) + (beginning-of-line)))) + (defvar j-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c !") 'j-console) @@ -195,6 +253,8 @@ contents of current line." syntax-propertize-function #'j-mode-syntax-propertize indent-tabs-mode nil indent-line-function #'j-indent-line + beginning-of-defun-function #'j-beginning-of-explicit-definition + end-of-defun-function #'j-end-of-explicit-definition font-lock-comment-start-skip "NB. *" font-lock-defaults