1 ;;; factor-mode.el --- Major mode for editing Factor programs. -*- lexical-binding: t -*-
3 ;; Copyright (C) 2013 Erik Charlebois
4 ;; Copyright (C) 2008, 2009, 2010 Jose Antonio Ortega Ruiz
5 ;; See http://factorcode.org/license.txt for BSD license.
7 ;; Maintainer: Erik Charlebois <erikcharlebois@gmail.com>
8 ;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
9 ;; Keywords: languages, factor
10 ;; Start date: Tue Dec 02, 2008 21:32
14 ;; A major mode for editing Factor programs. It provides indenting and
24 (require 'factor-smie)
30 "Major mode for Factor source code."
33 (defcustom factor-cycling-no-ask nil
34 "Whether to never create source/doc/tests file when cycling."
38 (defcustom factor-cycle-always-ask-p t
39 "Whether to always ask for file creation when cycling to a
40 source/docs/tests file. When set to false, you'll be asked only once."
44 (defcustom factor-comment-column 32
45 "Indentation column of comments."
50 (defcustom factor-mode-use-fuel t
51 "Whether to use the full FUEL facilities in factor mode.
53 Set this variable to nil if you just want to use Emacs as the
54 external editor of your Factor environment, e.g., by putting
55 these lines in your .emacs:
57 (add-to-list 'load-path \"/path/to/factor/misc/fuel\")
58 (setq factor-mode-use-fuel nil)
59 (require 'factor-mode)
68 (defgroup factor-faces nil
69 "Faces used by factor-mode."
73 (defface factor-font-lock-constructor '((t (:inherit font-lock-type-face)))
74 "Factor for constructor words."
78 (defface factor-font-lock-constant '((t (:inherit font-lock-constant-face)))
79 "Face for constant and literal values."
83 (defface factor-font-lock-number '((t (:inherit font-lock-constant-face)))
84 "Face for integer and floating-point constants."
88 (defface factor-font-lock-ratio '((t (:inherit font-lock-constant-face)))
89 "Face for ratio constants."
93 (defface factor-font-lock-parsing-word '((t (:inherit font-lock-keyword-face)))
98 (defface factor-font-lock-setter-word
99 '((t (:inherit font-lock-function-name-face)))
100 "setter words (>>foo)"
104 (defface factor-font-lock-getter-word
105 '((t (:inherit font-lock-function-name-face)))
106 "getter words (foo>>)"
110 (defface factor-font-lock-string '((t (:inherit font-lock-string-face)))
115 (defface factor-font-lock-symbol '((t (:inherit font-lock-variable-name-face)))
116 "name of symbol being defined"
120 (defface factor-font-lock-type-name '((t (:inherit font-lock-type-face)))
125 (defface factor-font-lock-vocabulary-name
126 '((t (:inherit font-lock-constant-face)))
131 (defface factor-font-lock-word
132 '((t (:inherit font-lock-function-name-face)))
133 "Face for the word, generic or method being defined."
137 (defface factor-font-lock-invalid-syntax
138 '((t (:inherit font-lock-warning-face)))
139 "syntactically invalid constructs"
143 (defface factor-font-lock-comment '((t (:inherit font-lock-comment-face)))
144 "Face for Factor comments."
148 (defface factor-font-lock-stack-effect '((t :inherit font-lock-comment-face))
149 "Face for Factor stack effect declarations."
153 (defface factor-font-lock-type-in-stack-effect '((t :inherit font-lock-comment-face
155 "Face for Factor types in stack effect declarations."
162 (defun factor-beginning-of-symbol ()
163 "Move point to the beginning of the current symbol."
164 (skip-syntax-backward "w_()\""))
166 (defun factor-end-of-symbol ()
167 "Move point to the end of the current symbol."
168 (skip-syntax-forward "w_()\""))
170 (put 'factor-symbol 'end-op 'factor-end-of-symbol)
171 (put 'factor-symbol 'beginning-op 'factor-beginning-of-symbol)
173 (defun factor-symbol-at-point ()
174 (let ((thing (thing-at-point 'factor-symbol t)))
175 (and (> (length thing) 0) thing)))
180 ;; Utility regexp used by other regexps to match a Factor symbol name
181 (setq-local symbol-nc "\\(?:\\sw\\|\\s_\\|\"\\|\\s(\\|\\s)\\|\\s\\\\)+")
182 (setq-local symbol (format "\\(%s\\)" symbol-nc))
183 (setq-local c-symbol-nc "\\(?:\\sw\\|\\s_\\|\\[\\|\\]\\)+")
184 (setq-local c-symbol (format "\\(%s\\)" c-symbol-nc))
185 (setq-local ws+ "[ \n\t]+")
186 (setq-local symbols-to-semicolon "\\([^;\t]*\\)\\(;\\)")
188 (defun one-symbol (content)
189 (concat "\\_<\\(" content "\\)\\_>"))
191 (defun syntax-begin (content)
192 (one-symbol (concat (regexp-opt content) ":")))
194 (defun syntax-and-1-symbol (prefixes)
195 (concat (syntax-begin prefixes) ws+ symbol))
197 (defun syntax-and-2-symbols (prefixes)
198 (concat (syntax-and-1-symbol prefixes) ws+ symbol))
200 ;; Used to font-lock stack effect declarations with may be nested.
201 (defun factor-match-brackets (limit)
202 (let ((start (point)))
203 (when (re-search-forward "[ \n]([ \n]" limit t)
205 (let ((bracket-start (point)))
206 (when (condition-case nil
207 (progn (forward-sexp) 't)
209 (let ((bracket-stop (point)))
210 (goto-char bracket-start)
211 (re-search-forward "\\(.\\|\n\\)+" bracket-stop 'mv)))))))
213 ;; Excludes parsing words that are handled by other regexps
214 (defconst factor-parsing-words
215 '(":" "::" ";" ":>" "&:" "<<" "<PRIVATE" ">>"
218 "CONSULT:" "call-next-method"
219 "FOREIGN-ATOMIC-TYPE:" "FOREIGN-ENUM-TYPE:" "FOREIGN-RECORD-TYPE:" "FUNCTION-ALIAS:"
222 "initial:" "IMPLEMENT-STRUCTS:"
225 "PRIVATE>" "PROTOCOL:"
230 (defconst factor-parsing-words-regex
231 (format "\\(?:^\\| \\)%s" (regexp-opt factor-parsing-words 'symbols)))
233 (defconst factor-constant-words
236 (defconst factor-constant-words-regex
237 (regexp-opt factor-constant-words 'symbols))
239 (defconst factor-bracer-words
240 '("B" "BV" "C" "CS" "HEX" "H" "HS" "S" "T" "V" "W" "flags"))
242 (defconst factor-brace-words-regex
243 (format "%s{" (regexp-opt factor-bracer-words t)))
245 (defconst factor-declaration-words
255 (defconst factor-declaration-words-regex
256 (regexp-opt factor-declaration-words 'symbols))
258 (defconst factor-integer-regex
259 (one-symbol "-?\\(?:0[xob][0-9a-fA-F][0-9a-fA-F,]*\\|[0-9][0-9,]*\\)"))
261 (defconst factor-raw-float-regex
262 "[0-9]*\\.[0-9]*\\([eEpP][+-]?[0-9]+\\)?")
264 (defconst factor-float-regex
265 (format "\\_<-?%s\\_>" factor-raw-float-regex))
267 (defconst factor-number-regex
268 (format "\\([0-9]+\\|%s\\)" factor-raw-float-regex))
270 (defconst factor-ratio-regex
271 (format "\\_<[+-]?%s/-?%s\\_>" factor-number-regex factor-number-regex))
273 (defconst factor-bad-string-regex
274 "\\_<\"[^>]\\([^\"\n]\\|\\\\\"\\)*\n")
276 (defconst factor-word-definition-regex
278 (one-symbol (regexp-opt
279 '(":" "::" "GENERIC:" "GENERIC#:" "DEFER:" "HOOK:"
280 "IDENTITY-MEMO:" "MACRO:" "MACRO::" "MATH:" "MEMO:" "MEMO::"
281 "POSTPONE:" "PRIMITIVE:" "SYNTAX:" "TYPED:" "TYPED::")))
284 (defconst factor-method-definition-regex
285 (syntax-and-2-symbols '("M" "M:" "BEFORE" "AFTER")))
287 ;; [parsing-word] [vocab-word]
288 (defconst factor-vocab-ref-regex
289 (syntax-and-1-symbol '("IN" "USE" "QUALIFIED")))
291 (defconst factor-using-lines-regex
292 (concat (syntax-begin '("USING")) ws+ symbols-to-semicolon))
294 ;; [parsing-word] [symbol-word]
295 (defconst factor-symbol-definition-regex
297 '("&" "CONSTANT" "DESTRUCTOR" "EBNF" "FORGET" "FUNCTOR"
298 "GAME" "GLSL-PROGRAM" "GLSL-SHADER"
299 "HELP" "LIBRARY" "MAIN" "MAIN-WINDOW" "SLOT" "STRING"
302 ;; [parsing-word] [symbol-word]* ;
303 (defconst factor-symbols-lines-regex
304 (concat (syntax-begin '("SYMBOLS")) ws+ symbols-to-semicolon))
306 (defconst factor-types-lines-regex
308 (syntax-begin '("INTERSECTION" "SINGLETONS" "SPECIALIZED-ARRAYS"))
309 ws+ symbols-to-semicolon))
311 ;; [parsing-word] [type-word]
312 (defconst factor-type-definition-regex
314 '("COM-INTERFACE" "C-TYPE" "MIXIN"
316 "SINGLETON" "SPECIALIZED-ARRAY" "SPECIALIZED-VECTOR"
319 (defconst factor-constructor-regex
320 (one-symbol "<[^ >]+>"))
322 (defconst factor-getter-regex
323 (one-symbol (concat symbol-nc ">>")))
325 (defconst factor-setter-regex
326 (one-symbol (format ">>%s\\|%s<<" symbol-nc symbol-nc)))
328 (defconst factor-stack-effect-regex
329 "\\( ( [^)]* )\\)\\|\\( (( [^)]* ))\\)")
331 (defconst factor-use-line-regex "^USE: +\\(.*\\)$")
333 (defconst factor-current-vocab-regex "^IN: +\\([^ \r\n\f]+\\)")
335 (defconst factor-sub-vocab-regex "^<\\([^ \n]+\\) *$")
337 (defconst factor-definition-start-regex
338 (format "^\\(%s:\\) " (regexp-opt (append factor-no-indent-def-starts
339 factor-indent-def-starts))))
341 (defconst factor-single-liner-regex
342 (regexp-opt '("ABOUT:"
344 "CONSTANT:" "C-GLOBAL:" "C-TYPE:"
345 "DEFER:" "DESTRUCTOR:"
347 "GAME:" "GENERIC:" "GENERIC#:"
351 "MAIN:" "MATH:" "MIXIN:"
353 "POSTPONE:" "PRIVATE>" "<PRIVATE"
354 "QUALIFIED-WITH:" "QUALIFIED:"
356 "SINGLETON:" "SLOT:" "SPECIALIZED-ARRAY:"
360 (defconst factor-begin-of-def-regex
361 (format "^USING: \\|\\(%s\\)\\|\\(^%s .*\\)"
362 factor-definition-start-regex
363 factor-single-liner-regex))
365 (defconst factor-definition-end-regex
366 (format "\\(^\\| +\\);\\( *%s\\)*\\($\\| +\\)"
367 factor-declaration-words-regex))
369 (defconst factor-end-of-def-regex
370 (format "^.*%s\\|^%s .*"
371 factor-definition-end-regex
372 factor-single-liner-regex))
374 (defconst factor-word-signature-regex
375 (format ":[^ ]* \\([^ ]+\\)\\(%s\\)*" factor-stack-effect-regex))
377 (defconst factor-defun-signature-regex
378 (format "\\(%s\\|%s\\)"
379 factor-word-signature-regex
380 "M[^:]*: [^ ]+ [^ ]+"))
382 (defconst factor-typedef-regex
383 (syntax-and-2-symbols '("TYPEDEF" "INSTANCE")))
385 (defconst factor-rename-regex
386 (concat (syntax-and-2-symbols '("RENAME")) ws+ "\\(=>\\)" ws+ symbol))
388 (defconst factor-from/exclude-regex
389 (concat (syntax-begin '("FROM" "EXCLUDE")) ws+
391 "\\(=>\\)" ws+ symbols-to-semicolon))
393 (defconst factor-predicate-regex
394 (concat (syntax-begin '("PREDICATE")) ws+ symbol ws+ "\\(<\\)" ws+ symbol))
396 (defconst factor-alien-function-regex
397 (concat (syntax-begin '("CALLBACK"
405 ;; Regexp from hell that puts every type name in the first group,
406 ;; names and brackets in the second and third.
407 (defconst factor-function-params-regex
408 (format "\\(?:%s%s\\(%s,?\\(?:%s)\\)?\\)\\|\\([()]\\)\\)" c-symbol ws+ c-symbol-nc ws+))
410 (defconst factor-function-alias-regex
411 (concat (syntax-begin '("FUNCTION-ALIAS"))
416 (defconst factor-group-name-to-face
417 #s(hash-table test equal data
418 ("C" 'factor-font-lock-comment
419 "CO" 'factor-font-lock-constructor
420 "CT" 'factor-font-lock-constant
421 "P" 'factor-font-lock-parsing-word
422 "V" 'factor-font-lock-vocabulary-name
423 "T" 'factor-font-lock-type-name
424 "N" 'factor-font-lock-number
425 "W" 'factor-font-lock-word)))
427 (defun factor-group-name-to-face (group-name)
428 (gethash group-name factor-group-name-to-face))
430 (defun factor-groups-to-font-lock (groups)
434 (list i (factor-group-name-to-face x)))
437 (defun factor-syntax (regex groups)
438 (append (list regex) (factor-groups-to-font-lock groups)))
443 (defconst factor-font-lock-keywords
445 ,(factor-syntax factor-brace-words-regex '("P"))
446 ,(factor-syntax factor-vocab-ref-regex '("P" "V"))
447 ,(factor-syntax factor-using-lines-regex '("P" "V" "P"))
448 ,(factor-syntax factor-symbols-lines-regex '("P" "W" "P"))
449 ,(factor-syntax factor-from/exclude-regex '("P" "V" "P" "W" "P"))
450 ,(factor-syntax (syntax-and-2-symbols '("C")) '("P" "W" "T"))
451 ,(factor-syntax factor-symbol-definition-regex '("P" "W"))
452 ,(factor-syntax factor-typedef-regex '("P" "T" "T"))
453 ,(factor-syntax (syntax-and-2-symbols '("C-GLOBAL")) '("P" "T" "W"))
454 ,(factor-syntax (syntax-and-2-symbols '("QUALIFIED-WITH")) '("P" "V" "W"))
455 ,(factor-syntax factor-rename-regex '("P" "W" "V" "P" "W"))
456 ,(factor-syntax factor-declaration-words-regex '("C"))
457 ,(factor-syntax factor-word-definition-regex '("P" "W"))
458 ,(factor-syntax (syntax-and-2-symbols '("ALIAS")) '("P" "W" "W"))
459 ,(factor-syntax (syntax-and-2-symbols '("HINTS" "LOG")) '("P" "W" ""))
460 ,(factor-syntax (syntax-and-1-symbol '("ALIEN" "CHAR" "COLOR" "NAN" "HEXCOLOR")) '("P" "CT"))
461 ,(factor-syntax factor-types-lines-regex '("P" "T"))
463 (,factor-float-regex . 'factor-font-lock-number)
464 (,factor-ratio-regex . 'factor-font-lock-ratio)
465 ,(factor-syntax factor-type-definition-regex '("P" "T"))
466 ,(factor-syntax factor-method-definition-regex '("P" "T" "W"))
468 ;; Highlights tuple and struct definitions. The TUPLE/STRUCT
469 ;; parsing word, class name and optional parent classes are
470 ;; matched in three groups. Then the text up until the end of the
471 ;; definition that is terminated with ";" is searched for words
472 ;; that are slot names which are highlighted with the face
473 ;; factor-font-lock-symbol.
475 "\\(%s:\\)[ \n]+%s\\(?:[ \n]+\\(<\\)[ \n]+%s\\)?"
476 (regexp-opt '("BUILTIN"
488 (1 'factor-font-lock-parsing-word)
489 (2 'factor-font-lock-type-name)
490 (3 'factor-font-lock-parsing-word nil t)
491 (4 'factor-font-lock-type-name nil t)
492 ;; This allows three different slot styles:
493 ;; 1) foo 2) { foo initial: 123 } 3) { foo initial: { 123 } }
495 "{%s%s[^}]+}%s}\\|{%s%s[^}]+}\\|%s"
499 (factor-find-end-of-def)
501 (1 'factor-font-lock-symbol nil t)
502 (2 'factor-font-lock-symbol nil t)
503 (3 'factor-font-lock-symbol nil t)))
504 ,(factor-syntax factor-predicate-regex '("P" "T" "P" "T"))
505 ;; Highlights alien function definitions. Types in stack effect
506 ;; declarations are given a bold face.
507 (,factor-alien-function-regex
508 (1 'factor-font-lock-parsing-word)
509 (2 'factor-font-lock-type-name)
510 (3 'factor-font-lock-word)
511 (,factor-function-params-regex
512 (factor-find-ending-bracket)
514 (1 'factor-font-lock-type-in-stack-effect nil t)
515 (2 'factor-font-lock-stack-effect nil t)
516 (3 'factor-font-lock-stack-effect nil t)))
518 ;; Almost identical to the previous one, but for function aliases.
519 (,factor-function-alias-regex
520 (1 'factor-font-lock-parsing-word)
521 (2 'factor-font-lock-word)
522 (3 'factor-font-lock-type-name)
523 (4 'factor-font-lock-word)
524 (,factor-function-params-regex
525 (factor-find-ending-bracket)
527 (1 'factor-font-lock-type-in-stack-effect nil t)
528 (2 'factor-font-lock-stack-effect nil t)
529 (3 'factor-font-lock-stack-effect nil t)))
530 ,(factor-syntax factor-integer-regex '("N"))
531 (factor-match-brackets . 'factor-font-lock-stack-effect)
532 ,(factor-syntax factor-constructor-regex '("CO"))
533 (,factor-setter-regex . 'factor-font-lock-setter-word)
534 (,factor-getter-regex . 'factor-font-lock-getter-word)
535 (,factor-bad-string-regex . 'factor-font-lock-invalid-syntax)
536 ("\\_<\\(P\\|SBUF\\|DLL\\)\"" 1 'factor-font-lock-parsing-word)
537 (,factor-constant-words-regex . 'factor-font-lock-constant)
538 ,(factor-syntax factor-parsing-words-regex '("P"))
539 (,"\t" . 'whitespace-highlight-face)))
541 ;; Handling of multi-line constructs
542 (defun factor-font-lock-extend-region ()
543 (eval-when-compile (defvar font-lock-beg) (defvar font-lock-end))
545 (goto-char font-lock-beg)
546 (let ((found (or (re-search-backward "\n\n" nil t) (point-min))))
547 (goto-char font-lock-end)
548 (when (re-search-forward "\n\n" nil t)
550 (setq font-lock-end (point)))
551 (setq font-lock-beg found))))
553 ;;; Source code analysis:
555 (defsubst factor-brackets-depth ()
556 (nth 0 (syntax-ppss)))
558 (defsubst factor-brackets-start ()
559 (nth 1 (syntax-ppss)))
561 (defsubst factor-beginning-of-defun (&optional times)
562 (re-search-backward factor-begin-of-def-regex nil t times))
564 (defsubst factor-end-of-defun ()
565 (re-search-forward factor-end-of-def-regex nil t))
567 (defsubst factor-end-of-defun-pos ()
569 (re-search-forward factor-end-of-def-regex nil t)
572 (defun factor-on-vocab ()
573 "t if point is on a vocab name. We just piggyback on
574 font-lock's pretty accurate information."
575 (eq (get-char-property (point) 'face) 'factor-font-lock-vocabulary-name))
577 (defun factor-find-end-of-def (&rest foo)
579 (re-search-forward "[ \n];" nil t)
582 (defun factor-find-ending-bracket (&rest foo)
584 (re-search-forward "[ \n]\)" nil t)
587 (defun factor-beginning-of-body ()
589 (and (factor-beginning-of-defun)
590 (re-search-forward factor-defun-signature-regex p t)
591 (not (re-search-forward factor-end-of-def-regex p t)))))
593 (defun factor-beginning-of-sexp ()
594 (if (> (factor-brackets-depth) 0)
595 (goto-char (factor-brackets-start))
596 (factor-beginning-of-body)))
598 (defsubst factor-beginning-of-sexp-pos ()
599 (save-excursion (factor-beginning-of-sexp) (point)))
604 (defvar-local factor-current-vocab-function 'factor-find-vocab-name)
606 (defsubst factor-current-vocab ()
607 (funcall factor-current-vocab-function))
609 (defun factor-find-in ()
612 (if (re-search-backward factor-current-vocab-regex nil t)
613 (match-string-no-properties 1)
614 (when (re-search-forward factor-current-vocab-regex nil t)
615 (match-string-no-properties 1)))))
617 (defun factor-in-private? ()
618 "t if point is withing a PRIVATE-block, nil otherwise."
620 (when (re-search-backward "\\_<<?PRIVATE>?\\_>" nil t)
621 (string= (match-string-no-properties 0) "<PRIVATE"))))
623 (defun factor-find-vocab-name ()
624 "Name of the vocab with possible .private suffix"
625 (concat (factor-find-in) (if (factor-in-private?) ".private" "")))
628 (defvar-local factor-usings-function 'factor-find-usings)
630 (defsubst factor-usings ()
631 (funcall factor-usings-function))
633 (defun factor-file-has-private ()
635 (goto-char (point-min))
636 (and (re-search-forward "\\_<<PRIVATE\\_>" nil t)
637 (re-search-forward "\\_<PRIVATE>\\_>" nil t))))
639 (defun factor-find-usings (&optional no-private)
640 "Lists all vocabs used by the vocab."
643 (goto-char (point-max))
644 (while (re-search-backward factor-using-lines-regex nil t)
645 (dolist (u (split-string (match-string-no-properties 2) nil t))
647 (when (and (not no-private) (factor-file-has-private))
648 (goto-char (point-max))
649 (push (concat (factor-find-in) ".private") usings))
655 (defconst factor-cycle-endings
656 '(".factor" "-tests.factor" "-docs.factor"))
658 (defvar factor-cycle-ring
659 (let ((ring (make-ring (length factor-cycle-endings))))
660 (dolist (e factor-cycle-endings ring)
661 (ring-insert ring e))
664 (defconst factor-cycle-basename-regex
665 (format "\\(.+?\\)\\(%s\\)$" (regexp-opt factor-cycle-endings)))
667 (defun factor-cycle-split (basename)
668 (when (string-match factor-cycle-basename-regex basename)
669 (cons (match-string 1 basename) (match-string 2 basename))))
671 (defun factor-cycle-next (file skip)
672 (let* ((dir (file-name-directory file))
673 (basename (file-name-nondirectory file))
674 (p/s (factor-cycle-split basename))
676 (ring factor-cycle-ring)
677 (idx (or (ring-member ring (cdr p/s)) 0))
678 (len (ring-size ring))
681 (while (and (< i len) (not result))
682 (let* ((suffix (ring-ref ring (+ i idx)))
683 (path (expand-file-name (concat prefix suffix) dir)))
684 (when (or (file-exists-p path)
686 (not (member suffix factor-cycling-no-ask))
687 (y-or-n-p (format "Create %s? " path))))
689 (when (and (not factor-cycle-always-ask-p)
690 (not (member suffix factor-cycling-no-ask)))
691 (setq factor-cycling-no-ask
692 (cons name factor-cycling-no-ask))))
696 (defun factor-visit-other-file (&optional create)
697 "Cycle between code, tests and docs factor files.
698 With prefix, non-existing files will be created."
700 (let ((file (factor-cycle-next (buffer-file-name) (not create))))
701 (unless file (error "No other file found"))
703 (unless (file-exists-p file)
704 (set-buffer-modified-p t)
710 ;; TODO Handle the plural words (SINGLETONS:, SYMBOLS:, etc)
711 (defvar factor-imenu-generic-expression
714 (regexp-opt '(":" "::" "ALIAS:" "BUILTIN:" "C:" "CONSTANT:" "ERROR:"
715 "GENERIC:" "GENERIC#:" "HOOK:" "INTERSECTION:" "MATH:"
716 "MIXIN:" "PREDICATE:" "PRIMITIVE:" "SINGLETON:" "SLOT:"
717 "SYMBOL:" "SYNTAX:" "TUPLE:" "UNION:" "LOG:" "C-TYPE:" "ENUM:"
718 "STRUCT:" "FUNCTION-ALIAS:"))
719 "\\s-+\\(\\(?:\\s_\\|\\sw\\|\\s\\\\)+\\)")
723 (regexp-opt '("M:" "M::"))
724 "\\s-+\\(\\(?:\\s_\\|\\sw|\\s\\\\)+\\s-+\\(?:\\s_\\|\\sw|\\s\\\\)+\\)")
728 (regexp-opt '("FUNCTION:" "TYPEDEF:"))
729 "\\s-+\\(?:\\(?:\\s_\\|\\sw\\|\\s\\\\)+\\s-+\\)\\(\\(?:\\s_\\|\\sw\\|\\s\\\\)+\\)")
731 "Imenu generic expression for factor-mode. See `imenu-generic-expression'.")
736 (defvar factor-mode-syntax-table (fuel-syntax-table))
738 (defun factor-setup-buffer-font-lock ()
739 (setq-local comment-start "! ")
740 (setq-local comment-end "")
741 (setq-local comment-column factor-comment-column)
742 (setq-local comment-start-skip "!+ *")
743 (setq-local parse-sexp-ignore-comments t)
744 (setq-local parse-sexp-lookup-properties t)
745 (setq-local font-lock-defaults '(factor-font-lock-keywords))
746 ;; Some syntactic constructs are often split over multiple lines so
747 ;; we need to setup multiline font-lock.
748 (setq-local font-lock-multiline t)
749 (add-hook 'font-lock-extend-region-functions 'factor-font-lock-extend-region)
750 (setq-local syntax-propertize-function 'factor-syntax-propertize))
752 (defun factor-font-lock-string (str)
753 "Fontify STR as if it was Factor code."
755 (set-syntax-table factor-mode-syntax-table)
756 (factor-setup-buffer-font-lock)
758 (let ((font-lock-verbose nil))
759 (font-lock-fontify-buffer))
762 (defun factor-syntax-propertize (start end)
764 (syntax-propertize-rules
765 ("\\(^\\| \\|\t\\)\\(!\\|#!\\)\\($\\| \\|\t\\)" (2 "< ")))
769 (define-derived-mode factor-mode prog-mode "Factor"
770 "A mode for editing programs written in the Factor programming language.
772 (factor-setup-buffer-font-lock)
773 (define-key factor-mode-map [remap ff-get-other-file]
774 'factor-visit-other-file)
776 (setq-local electric-indent-chars
777 (append '(?\] ?\} ?\n) electric-indent-chars))
780 (setq-local indent-tabs-mode nil)
782 (add-hook 'smie-indent-functions #'factor-smie-indent nil t)
783 (smie-setup factor-smie-grammar #'factor-smie-rules
784 :forward-token #'factor-smie-forward-token
785 :backward-token #'factor-smie-backward-token)
786 (setq-local smie-indent-basic factor-block-offset)
787 (setq-local imenu-generic-expression factor-imenu-generic-expression)
789 (setq-local beginning-of-defun-function 'factor-beginning-of-defun)
790 (setq-local end-of-defun-function 'factor-end-of-defun)
791 ;; Load fuel-mode too if factor-mode-use-fuel is t.
792 (when factor-mode-use-fuel (require 'fuel-mode) (fuel-mode)))
795 (add-to-list 'auto-mode-alist '("\\.factor\\'" . factor-mode))
798 (add-to-list 'interpreter-mode-alist '("factor" . factor-mode))
801 (provide 'factor-mode)
803 ;;; factor-mode.el ends here