(require 'font-lock)
(require 'ring)
(require 'fuel-base)
+(require 'factor-smie)
;;; Customization:
: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
(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))))
(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 ()
- (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 ()
+(defsubst factor-end-of-defun-pos ()
(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)
(push (concat (factor-find-in) ".private") usings))
usings)))
-\f
-;;; 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))))))
-
\f
;;; Buffer cycling:
(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.
--- /dev/null
+;;; 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