FUEL: new indentation system based on smie
smie makes writing the indentation code much simpler. It also takes care of some corner cases that led to bad indentation before like stack effects split over multiple lines. See: http://emacs.1067599.n5.nabble.com/SMIE-examples-or-guides-td400784.htmlchar-rename
parent
c646db3ae5
commit
114ced868a
|
@ -21,6 +21,7 @@
|
|||
(require 'font-lock)
|
||||
(require 'ring)
|
||||
(require 'fuel-base)
|
||||
(require 'factor-smie)
|
||||
|
||||
;;; Customization:
|
||||
|
||||
|
@ -40,12 +41,6 @@ source/docs/tests file. When set to false, you'll be asked only once."
|
|||
:type 'boolean
|
||||
:group 'factor)
|
||||
|
||||
(defcustom factor-indent-level 4
|
||||
"Indentation of Factor statements."
|
||||
:type 'integer
|
||||
:safe 'integerp
|
||||
:group 'factor)
|
||||
|
||||
(defcustom factor-comment-column 32
|
||||
"Indentation column of comments."
|
||||
:type 'integer
|
||||
|
@ -335,27 +330,6 @@ these lines in your .emacs:
|
|||
|
||||
(defconst factor-sub-vocab-regex "^<\\([^ \n]+\\) *$")
|
||||
|
||||
(defconst factor-indent-def-starts
|
||||
'("" ":"
|
||||
"AFTER" "BEFORE"
|
||||
"COM-INTERFACE" "CONSULT"
|
||||
"ENUM" "ERROR"
|
||||
"FROM" "FUNCTION:" "FUNCTION-ALIAS:"
|
||||
"INTERSECTION:"
|
||||
"M" "M:" "MACRO" "MACRO:"
|
||||
"MAIN-WINDOW:" "MEMO" "MEMO:" "METHOD"
|
||||
"SYNTAX"
|
||||
"PREDICATE" "PRIMITIVE" "PROTOCOL"
|
||||
"SINGLETONS"
|
||||
"STRUCT" "SYMBOLS" "TAG" "TUPLE"
|
||||
"TYPED" "TYPED:"
|
||||
"UNIFORM-TUPLE"
|
||||
"UNION-STRUCT" "UNION"
|
||||
"VARIANT" "VERTEX-FORMAT"))
|
||||
|
||||
(defconst factor-no-indent-def-starts
|
||||
'("ARTICLE" "HELP" "SPECIALIZED-ARRAYS"))
|
||||
|
||||
(defconst factor-definition-start-regex
|
||||
(format "^\\(%s:\\) " (regexp-opt (append factor-no-indent-def-starts
|
||||
factor-indent-def-starts))))
|
||||
|
@ -567,76 +541,22 @@ these lines in your .emacs:
|
|||
(defsubst factor-brackets-start ()
|
||||
(nth 1 (syntax-ppss)))
|
||||
|
||||
(defun factor-brackets-end ()
|
||||
(save-excursion
|
||||
(goto-char (factor-brackets-start))
|
||||
(condition-case nil
|
||||
(progn (forward-sexp)
|
||||
(1- (point)))
|
||||
(error -1))))
|
||||
|
||||
(defsubst factor-indentation-at (pos)
|
||||
(save-excursion (goto-char pos) (current-indentation)))
|
||||
|
||||
(defsubst factor-at-begin-of-def ()
|
||||
(looking-at factor-begin-of-def-regex))
|
||||
|
||||
(defsubst factor-at-end-of-def ()
|
||||
(looking-at factor-end-of-def-regex))
|
||||
|
||||
(defsubst factor-is-last-char (pos)
|
||||
(save-excursion
|
||||
(goto-char (1+ pos))
|
||||
(looking-at-p "[ ]*$")))
|
||||
|
||||
(defsubst factor-line-offset (pos)
|
||||
(- pos (save-excursion
|
||||
(goto-char pos)
|
||||
(beginning-of-line)
|
||||
(point))))
|
||||
|
||||
(defsubst factor-beginning-of-defun (&optional times)
|
||||
(re-search-backward factor-begin-of-def-regex nil t times))
|
||||
|
||||
(defsubst factor-end-of-defun ()
|
||||
(re-search-forward factor-end-of-def-regex nil t))
|
||||
|
||||
(defun factor-beginning-of-block-pos ()
|
||||
(defsubst factor-end-of-defun-pos ()
|
||||
(save-excursion
|
||||
(if (> (factor-brackets-depth) 0)
|
||||
(factor-brackets-start)
|
||||
(factor-beginning-of-defun)
|
||||
(point))))
|
||||
|
||||
(defun factor-at-setter-line ()
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(when (re-search-forward factor-setter-regex
|
||||
(line-end-position)
|
||||
t)
|
||||
(let* ((to (match-beginning 0))
|
||||
(from (factor-beginning-of-block-pos)))
|
||||
(goto-char from)
|
||||
(let ((depth (factor-brackets-depth)))
|
||||
(and (or (re-search-forward factor-constructor-regex to t)
|
||||
(re-search-forward factor-setter-regex to t))
|
||||
(= depth (factor-brackets-depth))))))))
|
||||
|
||||
(defun factor-at-constructor-line ()
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(re-search-forward factor-constructor-regex (line-end-position) t)))
|
||||
(re-search-forward factor-end-of-def-regex nil t)
|
||||
(point)))
|
||||
|
||||
(defun factor-on-vocab ()
|
||||
"t if point is on a vocab name. We just piggyback on
|
||||
font-lock's pretty accurate information."
|
||||
(eq (get-char-property (point) 'face) 'factor-font-lock-vocabulary-name))
|
||||
|
||||
(defsubst factor-end-of-defun-pos ()
|
||||
(save-excursion
|
||||
(re-search-forward factor-end-of-def-regex nil t)
|
||||
(point)))
|
||||
|
||||
(defun factor-find-end-of-def (&rest foo)
|
||||
(save-excursion
|
||||
(re-search-forward "[ \n];" nil t)
|
||||
|
@ -712,101 +632,6 @@ these lines in your .emacs:
|
|||
(push (concat (factor-find-in) ".private") usings))
|
||||
usings)))
|
||||
|
||||
|
||||
;;; Indentation:
|
||||
|
||||
(defsubst factor-increased-indentation (&optional i)
|
||||
(+ (or i (current-indentation)) factor-indent-level))
|
||||
|
||||
(defsubst factor-decreased-indentation (&optional i)
|
||||
(- (or i (current-indentation)) factor-indent-level))
|
||||
|
||||
(defun factor-indent-in-brackets ()
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(when (> (factor-brackets-depth) 0)
|
||||
(let* ((bs (factor-brackets-start))
|
||||
(be (factor-brackets-end))
|
||||
(ln (line-number-at-pos)))
|
||||
(when (> ln (line-number-at-pos bs))
|
||||
(cond ((and (> be 0)
|
||||
(= (- be (point)) (current-indentation))
|
||||
(= ln (line-number-at-pos be)))
|
||||
(factor-indentation-at bs))
|
||||
((or (factor-is-last-char bs)
|
||||
(not (eq ?\ (char-after (1+ bs)))))
|
||||
(factor-increased-indentation
|
||||
(factor-indentation-at bs)))
|
||||
(t (+ 2 (factor-line-offset bs)))))))))
|
||||
|
||||
(defun factor-indent-definition ()
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(when (factor-at-begin-of-def) 0)))
|
||||
|
||||
(defsubst factor-previous-non-empty ()
|
||||
"Move caret to the beginning of the last non-empty line."
|
||||
(forward-line -1)
|
||||
(while (and (not (bobp))
|
||||
(looking-at "^[ ]*$\\|$"))
|
||||
(forward-line -1)))
|
||||
|
||||
(defun factor-indent-setter-line ()
|
||||
(when (factor-at-setter-line)
|
||||
(or (save-excursion
|
||||
(let ((indent (and (factor-at-constructor-line)
|
||||
(current-indentation))))
|
||||
(while (not (or indent
|
||||
(bobp)
|
||||
(factor-at-begin-of-def)
|
||||
(factor-at-end-of-def)))
|
||||
(if (factor-at-constructor-line)
|
||||
(setq indent (factor-increased-indentation))
|
||||
(forward-line -1)))
|
||||
indent))
|
||||
(save-excursion
|
||||
(factor-previous-non-empty)
|
||||
(current-indentation)))))
|
||||
|
||||
(defconst factor-indent-def-start-regex
|
||||
(format "^\\(%s:\\)\\( \\|\n\\)" (regexp-opt factor-indent-def-starts)))
|
||||
|
||||
(defsubst factor-at-begin-of-indent-def ()
|
||||
(looking-at factor-indent-def-start-regex))
|
||||
|
||||
(defun factor-indent-continuation ()
|
||||
(save-excursion
|
||||
(factor-previous-non-empty)
|
||||
(cond ((or (factor-at-end-of-def)
|
||||
(factor-at-setter-line))
|
||||
(factor-decreased-indentation))
|
||||
((factor-at-begin-of-indent-def)
|
||||
(factor-increased-indentation))
|
||||
(t (current-indentation)))))
|
||||
|
||||
(defun factor-calculate-indentation ()
|
||||
"Calculate Factor indentation for line at point."
|
||||
(or (and (bobp) 0)
|
||||
(factor-indent-definition)
|
||||
(factor-indent-in-brackets)
|
||||
(factor-indent-setter-line)
|
||||
(factor-indent-continuation)
|
||||
0))
|
||||
|
||||
(defun factor-indent-line (&optional ignored)
|
||||
"Indents the current Factor line."
|
||||
(interactive)
|
||||
(let ((target (factor-calculate-indentation))
|
||||
(pos (- (point-max) (point))))
|
||||
(if (= target (current-indentation))
|
||||
(if (< (current-column) (current-indentation))
|
||||
(back-to-indentation))
|
||||
(beginning-of-line)
|
||||
(delete-horizontal-space)
|
||||
(indent-to target)
|
||||
(if (> (- (point-max) pos) (point))
|
||||
(goto-char (- (point-max) pos))))))
|
||||
|
||||
|
||||
;;; Buffer cycling:
|
||||
|
||||
|
@ -946,10 +771,15 @@ With prefix, non-existing files will be created."
|
|||
(setq-local electric-indent-chars
|
||||
(append '(?\] ?\} ?\n) electric-indent-chars))
|
||||
|
||||
(setq-local indent-line-function 'factor-indent-line)
|
||||
;; No tabs for you!!
|
||||
(setq-local indent-tabs-mode nil)
|
||||
|
||||
(add-hook 'smie-indent-functions #'factor-smie-indent nil t)
|
||||
(smie-setup factor-smie-grammar #'factor-smie-rules
|
||||
:forward-token #'factor-smie-forward-token
|
||||
:backward-token #'factor-smie-backward-token)
|
||||
(setq-local smie-indent-basic factor-block-offset)
|
||||
|
||||
(setq-local beginning-of-defun-function 'factor-beginning-of-defun)
|
||||
(setq-local end-of-defun-function 'factor-end-of-defun)
|
||||
;; Load fuel-mode too if factor-mode-use-fuel is t.
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
;;; factor-smie.el --- Helper function for indenting factor code
|
||||
|
||||
;; Copyright (C) 2016 Björn Lindqvist
|
||||
;; See http://factorcode.org/license.txt for BSD license.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Factor indentation using the SMIE framework.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defcustom factor-block-offset 4
|
||||
"Indentation of Factor statements."
|
||||
:type 'integer
|
||||
:safe 'integerp
|
||||
:group 'factor)
|
||||
|
||||
(defconst factor-indent-def-starts
|
||||
'("" ":"
|
||||
"AFTER" "BEFORE"
|
||||
"COM-INTERFACE" "CONSULT"
|
||||
"ENUM" "ERROR"
|
||||
"FROM" "FUNCTION:" "FUNCTION-ALIAS:"
|
||||
"INTERSECTION:"
|
||||
"M" "M:" "MACRO" "MACRO:"
|
||||
"MAIN-WINDOW:" "MEMO" "MEMO:" "METHOD"
|
||||
"SYNTAX"
|
||||
"PREDICATE" "PRIMITIVE" "PROTOCOL"
|
||||
"SINGLETONS"
|
||||
"STRUCT" "SYMBOLS" "TAG" "TUPLE"
|
||||
"TYPED" "TYPED:"
|
||||
"UNIFORM-TUPLE"
|
||||
"UNION-STRUCT" "UNION"
|
||||
"VARIANT" "VERTEX-FORMAT"))
|
||||
|
||||
(defconst factor-no-indent-def-starts
|
||||
'("ARTICLE" "HELP" "SPECIALIZED-ARRAYS"))
|
||||
|
||||
(defconst factor-indent-def-regex
|
||||
(format "^\\(%s:\\)$" (regexp-opt factor-indent-def-starts)))
|
||||
|
||||
(defconst factor-smie-grammar
|
||||
(smie-prec2->grammar
|
||||
(smie-bnf->prec2
|
||||
'(
|
||||
(exp (":" exp ";"))
|
||||
))))
|
||||
|
||||
(defun factor-smie-rules (kind token)
|
||||
(pcase (cons kind token)
|
||||
(`(:before . ";") factor-block-offset)
|
||||
(`(:list-intro . ,_) t)
|
||||
))
|
||||
|
||||
(defun factor-smie-token (dir)
|
||||
(pcase dir
|
||||
('forward (forward-comment (point-max)))
|
||||
('backward (forward-comment (- (point)))))
|
||||
(let ((tok (buffer-substring-no-properties
|
||||
(point)
|
||||
(let ((syntax "w_\\\""))
|
||||
(pcase dir
|
||||
('forward (skip-syntax-forward syntax))
|
||||
('backward (skip-syntax-backward syntax)))
|
||||
(point)))))
|
||||
;; Token normalization. This way we only need one rule in
|
||||
;; factor-smie-grammar.
|
||||
(cond ((string-match factor-indent-def-regex tok) ":")
|
||||
(t tok))))
|
||||
|
||||
(defun factor-smie-forward-token ()
|
||||
(factor-smie-token 'forward))
|
||||
|
||||
(defun factor-smie-backward-token ()
|
||||
(factor-smie-token 'backward))
|
||||
|
||||
(defun factor-smie-indent ()
|
||||
(unless (looking-at ";\\_>")
|
||||
(save-excursion
|
||||
(let ((x nil))
|
||||
(while (progn (setq x (smie-backward-sexp))
|
||||
(null (car-safe x))))
|
||||
(when (string-match factor-indent-def-regex
|
||||
(or (nth 2 x) ""))
|
||||
(goto-char (nth 1 x))
|
||||
(+ factor-block-offset (smie-indent-virtual)))))))
|
||||
|
||||
(provide 'factor-smie)
|
||||
|
||||
;;; factor-smie.el ends here
|
Loading…
Reference in New Issue