;;; elisp.el --- My configurations of Emacs Lisp mode -*- lexical-binding: t; -*- ;;; Commentary: ;; Some personal configurations. ;;; Code: ;;; Hide Eldoc in the mode line ;; The original value is eldoc-minor-mode-string (durand-hide-minor-mode eldoc-mode) ;;; fontification of extra keywords in emacs lisp files (require 'advice) (font-lock-add-keywords 'emacs-lisp-mode `(("^;;;###\\(autoload\\)[ \n]" (1 font-lock-preprocessor-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))) 'append) ;;;###autoload (defvar emacs-lisp-face nil "The face used to highlight extra Emacs Lisp keywords.") ;;;###autoload (defun emacs-lisp-highlight-vars-and-faces (end) "Find special things to highlight within the confine of 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))) (paren-starts (nth 9 ppss))) (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)) ((let ((quote-before-p (mapcar (function (lambda (start) (let ((temp-char (char-before start))) (cond ((eq temp-char ?`) 1) ((eq temp-char ?') 2))))) paren-starts))) (and (fboundp symbol) (eq (char-before (match-beginning 0)) ?\() (not (or (memq 2 quote-before-p) (and (memq 1 quote-before-p) (not (or (eq (char-before (max (1- (match-beginning 0)) (point-min))) ?,) (eq (char-before (max (- (match-beginning 0) 2) (point-min))) ?,)))))) ;; (not (memq (char-before (1- (match-beginning 0))) ;; (list ?\' ?\`))) )) (let ((unaliased (indirect-function symbol))) (cond ((special-form-p unaliased) (setq emacs-lisp-face 'font-lock-constant-face)) ((macrop 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-builtin-face 'font-lock-function-name-face))))))) (throw 'matcher t))))))) nil)) ;;; highlight parentheses (require 'paren) (set 'show-paren-style 'parenthesis) (set 'show-paren-highlight-openparen t) (set 'show-paren-when-point-in-periphery nil) (set 'show-paren-when-point-inside-paren nil) (add-hook 'emacs-lisp-mode-hook #'show-paren-mode) ;;; remember cursor position (require 'saveplace) (set 'save-place-file (expand-file-name "saveplace" load-file-directory)) (set 'save-place-forget-unreadable-files t) (save-place-mode 1) ;;; 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. PARSE-START is the starting position of the parse." ;; 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)))))) (provide 'elisp) ;;; elisp.el ends here