From f21945a5afa22e051d3888b8dcacb2b27900403f Mon Sep 17 00:00:00 2001 From: JSDurand Date: Thu, 24 Dec 2020 16:27:22 +0800 Subject: More progess --- elisp.el | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 elisp.el (limited to 'elisp.el') diff --git a/elisp.el b/elisp.el new file mode 100644 index 0000000..b1f1be4 --- /dev/null +++ b/elisp.el @@ -0,0 +1,237 @@ +;;; -*- lexical-binding: t; -*- + +;;; a simpler mode name + +(add-hook 'emacs-lisp-mode-hook + (lambda () (set 'mode-name "ELisp"))) + +;;; fontification of extra keywords in emacs lisp files + +(require 'advice) + +(font-lock-add-keywords + 'emacs-lisp-mode + `(("^;;;###\\(autoload\\)[ \n]" (1 font-lock-warning-face t)) + (emacs-lisp-highlight-vars-and-faces . emacs-lisp-face) + ("\\(\\(?:#'\\|['`]\\)\\)\\(?:[[:space:]]*\\(\\(?:\\sw\\|\\s_\\)+\\)\\)?" + (1 font-lock-keyword-face) + (2 font-lock-constant-face nil t)))) + +;;;###autoload +(defvar emacs-lisp-face nil + "The face used to highlight extra emacs lisp keywords.") + +;;;###autoload +(defun emacs-lisp-highlight-vars-and-faces (end) + (catch 'matcher + (while (re-search-forward "\\(?:\\sw\\|\\s_\\)+" end t) + (let ((ppss (save-excursion (syntax-ppss)))) + (cond ((nth 3 ppss) ; strings + (search-forward "\"" end t)) + ((nth 4 ppss) ; comments + (forward-line +1)) + ((let ((symbol (intern-soft (match-string-no-properties 0)))) + (and (cond ((null symbol) nil) + ((eq symbol t) nil) + ((keywordp symbol) nil) + ((special-variable-p symbol) + (setq emacs-lisp-face 'font-lock-variable-name-face)) + ((and (fboundp symbol) + (eq (char-before (match-beginning 0)) ?\() + (not (memq (char-before (1- (match-beginning 0))) + (list ?\' ?\`)))) + (let ((unaliased (indirect-function symbol))) + (cond ((or (macrop unaliased) + (special-form-p unaliased)) + (setq emacs-lisp-face 'font-lock-keyword-face)) + (t + (let (unadvised) + (while (not (eq (setq unadvised (ad-get-orig-definition unaliased)) + (setq unaliased (indirect-function unadvised))))) + unaliased) + (setq emacs-lisp-face + (if (subrp unaliased) + 'font-lock-constant-face + 'font-lock-function-name-face))))))) + (throw 'matcher t))))))) + nil)) + +;;; a better indentation + +(advice-add #'calculate-lisp-indent :override #'better-calculate-lisp-indent) + +;;;###autoload +(defun better-calculate-lisp-indent (&optional parse-start) + "Add better indentation for quoted and backquoted lists." + ;; This line because `calculate-lisp-indent-last-sexp` was defined with `defvar` + ;; with it's value ommited, marking it special and only defining it locally. So + ;; if you don't have this, you'll get a void variable error. + (defvar calculate-lisp-indent-last-sexp) + (save-excursion + (beginning-of-line) + (let ((indent-point (point)) + state + ;; setting this to a number inhibits calling hook + (desired-indent nil) + (retry t) + calculate-lisp-indent-last-sexp containing-sexp) + (cond ((or (markerp parse-start) (integerp parse-start)) + (goto-char parse-start)) + ((null parse-start) (beginning-of-defun)) + (t (setq state parse-start))) + (unless state + ;; Find outermost containing sexp + (while (< (point) indent-point) + (setq state (parse-partial-sexp (point) indent-point 0)))) + ;; Find innermost containing sexp + (while (and retry + state + (> (elt state 0) 0)) + (setq retry nil) + (setq calculate-lisp-indent-last-sexp (elt state 2)) + (setq containing-sexp (elt state 1)) + ;; Position following last unclosed open. + (goto-char (1+ containing-sexp)) + ;; Is there a complete sexp since then? + (if (and calculate-lisp-indent-last-sexp + (> calculate-lisp-indent-last-sexp (point))) + ;; Yes, but is there a containing sexp after that? + (let ((peek (parse-partial-sexp calculate-lisp-indent-last-sexp + indent-point 0))) + (if (setq retry (car (cdr peek))) (setq state peek))))) + (if retry + nil + ;; Innermost containing sexp found + (goto-char (1+ containing-sexp)) + (if (not calculate-lisp-indent-last-sexp) + ;; indent-point immediately follows open paren. + ;; Don't call hook. + (setq desired-indent (current-column)) + ;; Find the start of first element of containing sexp. + (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t) + (cond ((looking-at "\\s(") + ;; First element of containing sexp is a list. + ;; Indent under that list. + ) + ((> (save-excursion (forward-line 1) (point)) + calculate-lisp-indent-last-sexp) + ;; This is the first line to start within the containing sexp. + ;; It's almost certainly a function call. + (if (or + ;; Containing sexp has nothing before this line + ;; except the first element. Indent under that element. + (= (point) calculate-lisp-indent-last-sexp) + + ;; First sexp after `containing-sexp' is a keyword. This + ;; condition is more debatable. It's so that I can have + ;; unquoted plists in macros. It assumes that you won't + ;; make a function whose name is a keyword. + ;; (when-let (char-after (char-after (1+ containing-sexp))) + ;; (char-equal char-after ?:)) + + ;; Check for quotes or backquotes around. + (let* ((positions (elt state 9)) + (last (car (last positions))) + (rest (reverse (butlast positions))) + (any-quoted-p nil) + (point nil)) + (or + (when-let (char (char-before last)) + (or (char-equal char ?') + (char-equal char ?`))) + (progn + (while (and rest (not any-quoted-p)) + (setq point (pop rest)) + (setq any-quoted-p + (or + (when-let (char (char-before point)) + (or (char-equal char ?') + (char-equal char ?`))) + (save-excursion + (goto-char (1+ point)) + (looking-at-p + "\\(?:back\\)?quote[\t\n\f\s]+("))))) + any-quoted-p)))) + ;; Containing sexp has nothing before this line + ;; except the first element. Indent under that element. + nil + ;; Skip the first element, find start of second (the first + ;; argument of the function call) and indent under. + (progn (forward-sexp 1) + (parse-partial-sexp (point) + calculate-lisp-indent-last-sexp + 0 t))) + (backward-prefix-chars)) + (t + ;; Indent beneath first sexp on same line as + ;; `calculate-lisp-indent-last-sexp'. Again, it's + ;; almost certainly a function call. + (goto-char calculate-lisp-indent-last-sexp) + (beginning-of-line) + (parse-partial-sexp (point) calculate-lisp-indent-last-sexp + 0 t) + (backward-prefix-chars))))) + ;; Point is at the point to indent under unless we are inside a string. + ;; Call indentation hook except when overridden by lisp-indent-offset + ;; or if the desired indentation has already been computed. + (let ((normal-indent (current-column))) + (cond ((elt state 3) + ;; Inside a string, don't change indentation. + nil) + ((and (integerp lisp-indent-offset) containing-sexp) + ;; Indent by constant offset + (goto-char containing-sexp) + (+ (current-column) lisp-indent-offset)) + ;; in this case calculate-lisp-indent-last-sexp is not nil + (calculate-lisp-indent-last-sexp + (or + ;; try to align the parameters of a known function + (and lisp-indent-function + (not retry) + (funcall lisp-indent-function indent-point state)) + ;; If the function has no special alignment + ;; or it does not apply to this argument, + ;; try to align a constant-symbol under the last + ;; preceding constant symbol, if there is such one of + ;; the last 2 preceding symbols, in the previous + ;; uncommented line. + (and (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (looking-at ":")) + ;; The last sexp may not be at the indentation + ;; where it begins, so find that one, instead. + (save-excursion + (goto-char calculate-lisp-indent-last-sexp) + ;; Handle prefix characters and whitespace + ;; following an open paren. (Bug#1012) + (backward-prefix-chars) + (while (not (or (looking-back "^[ \t]*\\|([ \t]+" + (line-beginning-position)) + (and containing-sexp + (>= (1+ containing-sexp) (point))))) + (forward-sexp -1) + (backward-prefix-chars)) + (setq calculate-lisp-indent-last-sexp (point))) + (> calculate-lisp-indent-last-sexp + (save-excursion + (goto-char (1+ containing-sexp)) + (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t) + (point))) + (let ((parse-sexp-ignore-comments t) + indent) + (goto-char calculate-lisp-indent-last-sexp) + (or (and (looking-at ":") + (setq indent (current-column))) + (and (< (line-beginning-position) + (prog2 (backward-sexp) (point))) + (looking-at ":") + (setq indent (current-column)))) + indent)) + ;; another symbols or constants not preceded by a constant + ;; as defined above. + normal-indent)) + ;; in this case calculate-lisp-indent-last-sexp is nil + (desired-indent) + (t + normal-indent)))))) -- cgit v1.2.3-18-g5258