]> gitweb.factorcode.org Git - factor.git/commitdiff
FUEL 0.0 : all factor.el functionality in place, plus evaluation.
authorJose A. Ortega Ruiz <jao@gnu.org>
Sat, 6 Dec 2008 03:34:25 +0000 (04:34 +0100)
committerJose A. Ortega Ruiz <jao@gnu.org>
Sat, 6 Dec 2008 03:34:25 +0000 (04:34 +0100)
13 files changed:
extra/fuel/authors.txt [new file with mode: 0644]
extra/fuel/fuel-tests.factor [new file with mode: 0644]
extra/fuel/fuel.factor [new file with mode: 0644]
misc/fuel/README [new file with mode: 0644]
misc/fuel/factor-mode.el [new file with mode: 0644]
misc/fuel/fu.el [new file with mode: 0644]
misc/fuel/fuel-base.el [new file with mode: 0644]
misc/fuel/fuel-eval.el [new file with mode: 0644]
misc/fuel/fuel-font-lock.el [new file with mode: 0644]
misc/fuel/fuel-help.el [new file with mode: 0644]
misc/fuel/fuel-listener.el [new file with mode: 0644]
misc/fuel/fuel-mode.el [new file with mode: 0644]
misc/fuel/fuel-syntax.el [new file with mode: 0644]

diff --git a/extra/fuel/authors.txt b/extra/fuel/authors.txt
new file mode 100644 (file)
index 0000000..6acd9d5
--- /dev/null
@@ -0,0 +1,2 @@
+Jose Antonio Ortega Ruiz <jao@gnu.org>
+Eduardo Cavazos <wayo.cavazos@gmail.com>
diff --git a/extra/fuel/fuel-tests.factor b/extra/fuel/fuel-tests.factor
new file mode 100644 (file)
index 0000000..74bc5d4
--- /dev/null
@@ -0,0 +1,4 @@
+! Copyright (C) 2008 Your name.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test fuel ;
+IN: fuel.tests
diff --git a/extra/fuel/fuel.factor b/extra/fuel/fuel.factor
new file mode 100644 (file)
index 0000000..9203f0f
--- /dev/null
@@ -0,0 +1,119 @@
+! Copyright (C) 2008 Jose Antonio Ortega Ruiz.
+! See http://factorcode.org/license.txt for BSD license.
+
+USING: accessors arrays classes.tuple compiler.units continuations debugger
+eval io io.streams.string kernel listener listener.private
+make math namespaces parser prettyprint quotations sequences strings
+vectors vocabs.loader ;
+
+IN: fuel
+
+! <PRIVATE
+
+TUPLE: fuel-status in use ds? ;
+
+SYMBOL: fuel-status-stack
+V{ } clone fuel-status-stack set-global
+
+: push-fuel-status ( -- )
+    in get use get clone display-stacks? get
+    fuel-status boa
+    fuel-status-stack get push ;
+
+: pop-fuel-status ( -- )
+    fuel-status-stack get empty? [
+        fuel-status-stack get pop
+        [ in>> in set ]
+        [ use>> clone use set ]
+        [ ds?>> display-stacks? swap [ on ] [ off ] if ] tri
+    ] unless ;
+
+SYMBOL: fuel-eval-result
+f clone fuel-eval-result set-global
+
+SYMBOL: fuel-eval-output
+f clone fuel-eval-result set-global
+
+! PRIVATE>
+
+GENERIC: fuel-pprint ( obj -- )
+
+M: object fuel-pprint pprint ;
+
+M: f fuel-pprint drop "nil" write ;
+
+M: integer fuel-pprint pprint ;
+
+M: string fuel-pprint pprint ;
+
+M: sequence fuel-pprint
+    dup empty? [ drop f fuel-pprint ] [
+        "(" write
+        [ " " write ] [ fuel-pprint ] interleave
+        ")" write
+    ] if ;
+
+M: tuple fuel-pprint tuple>array fuel-pprint ;
+
+M: continuation fuel-pprint drop "~continuation~" write ;
+
+: fuel-eval-set-result ( obj -- )
+    clone fuel-eval-result set-global ;
+
+: fuel-retort ( -- )
+    error get
+    fuel-eval-result get-global
+    fuel-eval-output get-global
+    3array fuel-pprint ;
+
+: fuel-forget-error ( -- )
+    f error set-global ;
+
+: (fuel-begin-eval) ( -- )
+    push-fuel-status
+    display-stacks? off
+    fuel-forget-error
+    f fuel-eval-result set-global
+    f fuel-eval-output set-global ;
+
+: (fuel-end-eval) ( quot -- )
+    with-string-writer fuel-eval-output set-global
+    fuel-retort
+    pop-fuel-status ;
+
+: (fuel-eval) ( lines -- )
+    [ [ parse-lines ] with-compilation-unit call ] curry [ drop ] recover ;
+
+: (fuel-eval-each) ( lines -- )
+    [ 1vector (fuel-eval) ] each ;
+
+: (fuel-eval-usings) ( usings -- )
+    [ "USING: " prepend " ;" append ] map
+    (fuel-eval-each) fuel-forget-error ;
+
+: (fuel-eval-in) ( in -- )
+    [ dup "IN: " prepend 1vector (fuel-eval) in set ] when* ;
+
+: fuel-eval-in-context ( lines in usings -- )
+    (fuel-begin-eval) [
+        (fuel-eval-usings)
+        (fuel-eval-in)
+        (fuel-eval)
+    ] (fuel-end-eval) ;
+
+: fuel-begin-eval ( in -- )
+    (fuel-begin-eval)
+    (fuel-eval-in)
+    fuel-retort ;
+
+: fuel-eval ( lines -- )
+    (fuel-begin-eval) [ (fuel-eval) ] (fuel-end-eval) ;
+
+: fuel-end-eval ( -- )
+    [ ] (fuel-end-eval) ;
+
+
+: fuel-startup ( -- )
+    "listener" run ;
+
+MAIN: fuel-startup
diff --git a/misc/fuel/README b/misc/fuel/README
new file mode 100644 (file)
index 0000000..b98a23e
--- /dev/null
@@ -0,0 +1,60 @@
+FUEL, Factor's Ultimate Emacs Library
+-------------------------------------
+
+FUEL provides a complete environment for your Factor coding pleasure
+inside Emacs, including source code edition and interaction with a
+Factor listener instance running within Emacs.
+
+FUEL was started by Jose A Ortega as an extension to Ed Cavazos'
+original factor.el code.
+
+Installation
+------------
+
+FUEL comes bundled with Factor's distribution. The folder misc/fuel
+contains Elisp code, and there's a fuel vocabulary in extras/fuel.
+
+To install FUEL, either add this line to your Emacs initialisation:
+
+  (load-file "<path/to/factor/installation>/misc/fuel/fu.el")
+
+or
+
+  (add-to-list load-path "<path/to/factor/installation>/fuel")
+  (require 'fuel)
+
+If all you want is a major mode for editing Factor code with pretty
+font colors and indentation, without running the factor listener
+inside Emacs, you can use instead:
+
+  (add-to-list load-path "<path/to/factor/installation>/fuel")
+  (setq factor-mode-use-fuel nil)
+  (require 'factor-mode)
+
+Basic usage
+-----------
+
+If you're using the default factor binary and images locations inside
+the Factor's source tree, that should be enough to start using FUEL.
+Editing any file with the extension .factor will put you in
+factor-mode; try C-hm for a summary of available commands.
+
+To start the listener, try M-x run-factor.
+
+Many aspects of the environment can be customized:
+M-x customize-group fuel will show you how many.
+
+Quick key reference
+-------------------
+
+ - C-cz : switch to listener
+ - C-co : cycle between code, tests and docs factor files
+
+ - C-M-x, C-cC-ed : eval definition around point
+
+ - C-cC-da : toggle autodoc mode
+ - C-cC-dd : help for word at point
+ - C-cC-ds : short help word at point
+
+Chords ending in a single letter <x> accept also C-<x> (e.g. C-cC-z is
+the same as C-cz).
diff --git a/misc/fuel/factor-mode.el b/misc/fuel/factor-mode.el
new file mode 100644 (file)
index 0000000..d79930b
--- /dev/null
@@ -0,0 +1,239 @@
+;;; factor-mode.el -- mode for editing Factor source
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Tue Dec 02, 2008 21:32
+
+;;; Comentary:
+
+;; Definition of factor-mode, a major Emacs for editing Factor source
+;; code.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-syntax)
+(require 'fuel-font-lock)
+
+(require 'ring)
+
+\f
+;;; Customization:
+
+(defgroup factor-mode nil
+  "Major mode for Factor source code"
+  :group 'fuel)
+
+(defcustom factor-mode-use-fuel t
+  "Whether to use the full FUEL facilities in factor mode.
+
+Set this variable to nil if you just want to use Emacs as the
+external editor of your Factor environment, e.g., by putting
+these lines in your .emacs:
+
+  (add-to-list 'load-path \"/path/to/factor/misc/fuel\")
+  (setq factor-mode-use-fuel nil)
+  (require 'factor-mode)
+"
+  :type 'boolean
+  :group 'factor-mode)
+
+(defcustom factor-mode-default-indent-width 4
+  "Default indentation width for factor-mode.
+
+This value will be used for the local variable
+`factor-mode-indent-width' in new factor buffers. For existing
+code, we first check if `factor-mode-indent-width' is set
+explicitly in a local variable section or line (e.g.
+'! -*- factor-mode-indent-witdth: 2 -*-'). If that's not the case,
+`factor-mode' tries to infer its correct value from the existing
+code in the buffer."
+  :type 'integer
+  :group 'fuel)
+
+(defcustom factor-mode-hook nil
+  "Hook run when entering Factor mode."
+  :type 'hook
+  :group 'factor-mode)
+
+\f
+;;; Syntax table:
+
+(defun factor-mode--syntax-setup ()
+  (set-syntax-table fuel-syntax--syntax-table)
+  (set (make-local-variable 'beginning-of-defun-function)
+       'fuel-syntax--beginning-of-defun)
+  (set (make-local-variable 'end-of-defun-function) 'fuel-syntax--end-of-defun)
+  (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil)
+  (fuel-syntax--enable-usings))
+
+\f
+;;; Indentation:
+
+(make-variable-buffer-local
+ (defvar factor-mode-indent-width factor-mode-default-indent-width
+   "Indentation width in factor buffers. A local variable."))
+
+(defun factor-mode--guess-indent-width ()
+  "Chooses an indentation value from existing code."
+  (let ((word-cont "^ +[^ ]")
+        (iw))
+    (save-excursion
+      (beginning-of-buffer)
+      (while (not iw)
+        (if (not (re-search-forward fuel-syntax--definition-start-regex nil t))
+            (setq iw factor-mode-default-indent-width)
+          (forward-line)
+          (when (looking-at word-cont)
+            (setq iw (current-indentation))))))
+    iw))
+
+(defun factor-mode--indent-in-brackets ()
+  (save-excursion
+    (beginning-of-line)
+    (when (> (fuel-syntax--brackets-depth) 0)
+      (let ((op (fuel-syntax--brackets-start))
+            (cl (fuel-syntax--brackets-end))
+            (ln (line-number-at-pos)))
+        (when (> ln (line-number-at-pos op))
+          (if (and (> cl 0) (= ln (line-number-at-pos cl)))
+              (fuel-syntax--indentation-at op)
+            (fuel-syntax--increased-indentation (fuel-syntax--indentation-at op))))))))
+
+(defun factor-mode--indent-definition ()
+  (save-excursion
+    (beginning-of-line)
+    (when (fuel-syntax--at-begin-of-def) 0)))
+
+(defun factor-mode--indent-setter-line ()
+  (when (fuel-syntax--at-setter-line)
+    (save-excursion
+      (let ((indent (and (fuel-syntax--at-constructor-line) (current-indentation))))
+        (while (not (or indent
+                        (bobp)
+                        (fuel-syntax--at-begin-of-def)
+                        (fuel-syntax--at-end-of-def)))
+          (if (fuel-syntax--at-constructor-line)
+              (setq indent (fuel-syntax--increased-indentation))
+            (forward-line -1)))
+        indent))))
+
+(defun factor-mode--indent-continuation ()
+  (save-excursion
+    (forward-line -1)
+    (while (and (not (bobp))
+                (fuel-syntax--looking-at-emptiness))
+      (forward-line -1))
+    (cond ((or (fuel-syntax--at-end-of-def)
+               (fuel-syntax--at-setter-line))
+           (fuel-syntax--decreased-indentation))
+          ((and (fuel-syntax--at-begin-of-def)
+                (not (fuel-syntax--at-using)))
+           (fuel-syntax--increased-indentation))
+          (t (current-indentation)))))
+
+(defun factor-mode--calculate-indentation ()
+  "Calculate Factor indentation for line at point."
+  (or (and (bobp) 0)
+      (factor-mode--indent-definition)
+      (factor-mode--indent-in-brackets)
+      (factor-mode--indent-setter-line)
+      (factor-mode--indent-continuation)
+      0))
+
+(defun factor-mode--indent-line ()
+  "Indent current line as Factor code"
+  (let ((target (factor-mode--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))))))
+
+(defun factor-mode--indentation-setup ()
+  (set (make-local-variable 'indent-line-function) 'factor-mode--indent-line)
+  (setq factor-indent-width (factor-mode--guess-indent-width))
+  (setq indent-tabs-mode nil))
+
+\f
+;;; Buffer cycling:
+
+(defconst factor-mode--cycle-endings
+  '(".factor" "-tests.factor" "-docs.factor"))
+
+(defconst factor-mode--regex-cycle-endings
+  (format "\\(.*?\\)\\(%s\\)$"
+          (regexp-opt factor-mode--cycle-endings)))
+
+(defconst factor-mode--cycle-endings-ring
+  (let ((ring (make-ring (length factor-mode--cycle-endings))))
+    (dolist (e factor-mode--cycle-endings ring)
+      (ring-insert ring e))))
+
+(defun factor-mode--cycle-next (file)
+  (let* ((match (string-match factor-mode--regex-cycle-endings file))
+         (base (and match (match-string-no-properties 1 file)))
+         (ending (and match (match-string-no-properties 2 file)))
+         (idx (and ending (ring-member factor-mode--cycle-endings-ring ending)))
+         (gfl (lambda (i) (concat base (ring-ref factor-mode--cycle-endings-ring i)))))
+    (if (not idx) file
+      (let ((l (length factor-mode--cycle-endings)) (i 1) next)
+        (while (and (not next) (< i l))
+          (when (file-exists-p (funcall gfl (+ idx i)))
+            (setq next (+ idx i)))
+          (setq i (1+ i)))
+        (funcall gfl (or next idx))))))
+
+(defun factor-mode-visit-other-file (&optional file)
+  "Cycle between code, tests and docs factor files."
+  (interactive)
+  (find-file (factor-mode--cycle-next (or file (buffer-file-name)))))
+
+\f
+;;; Keymap:
+
+(defun factor-mode-insert-and-indent (n)
+  (interactive "p")
+  (self-insert-command n)
+  (indent-for-tab-command))
+
+(defvar factor-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [?\]] 'factor-mode-insert-and-indent)
+    (define-key map [?}] 'factor-mode-insert-and-indent)
+    (define-key map "\C-m" 'newline-and-indent)
+    (define-key map "\C-co" 'factor-mode-visit-other-file)
+    (define-key map "\C-c\C-o" 'factor-mode-visit-other-file)
+    map))
+
+(defun factor-mode--keymap-setup ()
+  (use-local-map factor-mode-map))
+
+\f
+;;; Factor mode:
+
+;;;###autoload
+(defun factor-mode ()
+  "A mode for editing programs written in the Factor programming language.
+\\{factor-mode-map}"
+  (interactive)
+  (kill-all-local-variables)
+  (setq major-mode 'factor-mode)
+  (setq mode-name "Factor")
+  (fuel-font-lock--font-lock-setup)
+  (factor-mode--keymap-setup)
+  (factor-mode--indentation-setup)
+  (factor-mode--syntax-setup)
+  (when factor-mode-use-fuel (require 'fuel-mode) (fuel-mode))
+  (run-hooks 'factor-mode-hook))
+
+\f
+(provide 'factor-mode)
+;;; factor-mode.el ends here
diff --git a/misc/fuel/fu.el b/misc/fuel/fu.el
new file mode 100644 (file)
index 0000000..508d7ef
--- /dev/null
@@ -0,0 +1,26 @@
+;;; fu.el --- Startup file for FUEL
+
+;; Copyright (C) 2008  Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+
+;;; Code:
+
+(add-to-list 'load-path (file-name-directory load-file-name))
+
+(add-to-list 'auto-mode-alist '("\\.factor\\'" . factor-mode))
+(autoload 'factor-mode "factor-mode.el"
+  "Major mode for editing Factor source." t)
+
+(autoload 'run-factor "fuel-listener.el"
+  "Start a Factor listener, or switch to a running one." t)
+
+(autoload 'fuel-autodoc-mode "fuel-help.el"
+  "Minor mode showing in the minibuffer a synopsis of Factor word at point."
+  t)
+
+
+\f
+;;; fu.el ends here
diff --git a/misc/fuel/fuel-base.el b/misc/fuel/fuel-base.el
new file mode 100644 (file)
index 0000000..a62d16c
--- /dev/null
@@ -0,0 +1,63 @@
+;;; fuel-base.el --- Basic FUEL support code
+
+;; Copyright (C) 2008  Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+
+;;; Commentary:
+
+;; Basic definitions likely to be used by all FUEL modules.
+
+;;; Code:
+
+(defconst fuel-version "1.0")
+
+;;;###autoload
+(defsubst fuel-version ()
+  "Echoes FUEL's version."
+  (interactive)
+  (message "FUEL %s" fuel-version))
+
+\f
+;;; Customization:
+
+;;;###autoload
+(defgroup fuel nil
+  "Factor's Ultimate Emacs Library"
+  :group 'language)
+
+\f
+;;; Emacs compatibility:
+
+(eval-after-load "ring"
+  '(when (not (fboundp 'ring-member))
+     (defun ring-member (ring item)
+       (catch 'found
+         (dotimes (ind (ring-length ring) nil)
+           (when (equal item (ring-ref ring ind))
+             (throw 'found ind)))))))
+
+\f
+;;; Utilities
+
+(defun fuel--shorten-str (str len)
+  (let ((sl (length str)))
+    (if (<= sl len) str
+      (let* ((sep " ... ")
+             (sepl (length sep))
+             (segl (/ (- len sepl) 2)))
+        (format "%s%s%s"
+                (substring str 0 segl)
+                sep
+                (substring str (- sl segl)))))))
+
+(defun fuel--shorten-region (begin end len)
+  (fuel--shorten-str (mapconcat 'identity
+                                (split-string (buffer-substring begin end) nil t)
+                                " ")
+                     len))
+
+(provide 'fuel-base)
+;;; fuel-base.el ends here
diff --git a/misc/fuel/fuel-eval.el b/misc/fuel/fuel-eval.el
new file mode 100644 (file)
index 0000000..c92d8a8
--- /dev/null
@@ -0,0 +1,112 @@
+;;; fuel-eval.el --- utilities for communication with fuel-listener
+
+;; Copyright (C) 2008  Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+;; Start date: Tue Dec 02, 2008
+
+;;; Commentary:
+
+;; Protocols for handling communications via a comint buffer running a
+;; factor listener.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-syntax)
+
+\f
+;;; Syncronous string sending:
+
+(defvar fuel-eval-log-max-length 16000)
+
+(defvar fuel-eval--default-proc-function nil)
+(defsubst fuel-eval--default-proc ()
+  (and fuel-eval--default-proc-function
+       (funcall fuel-eval--default-proc-function)))
+
+(defvar fuel-eval--proc nil)
+(defvar fuel-eval--log t)
+
+(defun fuel-eval--send-string (str)
+  (let ((proc (or fuel-eval--proc (fuel-eval--default-proc))))
+    (when proc
+      (with-current-buffer (get-buffer-create "*factor messages*")
+        (goto-char (point-max))
+        (when (and (> fuel-eval-log-max-length 0)
+                   (> (point) fuel-eval-log-max-length))
+          (erase-buffer))
+        (when fuel-eval--log (insert "\n>> " (fuel--shorten-str str 75) "\n"))
+        (let ((beg (point)))
+          (comint-redirect-send-command-to-process str (current-buffer) proc nil t)
+          (with-current-buffer (process-buffer proc)
+            (while (not comint-redirect-completed) (sleep-for 0 1)))
+          (goto-char beg)
+          (current-buffer))))))
+
+\f
+;;; Evaluation protocol
+
+(defsubst fuel-eval--retort-make (err result &optional output)
+  (list err result output))
+
+(defsubst fuel-eval--retort-error (ret) (nth 0 ret))
+(defsubst fuel-eval--retort-result (ret) (nth 1 ret))
+(defsubst fuel-eval--retort-output (ret) (nth 2 ret))
+
+(defsubst fuel-eval--retort-p (ret) (listp ret))
+
+(defsubst fuel-eval--error-name (err) (car err))
+
+(defsubst fuel-eval--make-parse-error-retort (str)
+  (fuel-eval--retort-make 'parse-retort-error nil str))
+
+(defun fuel-eval--parse-retort (buffer)
+  (save-current-buffer
+    (set-buffer buffer)
+    (condition-case nil
+        (read (current-buffer))
+      (error (fuel-eval--make-parse-error-retort
+              (buffer-substring-no-properties (point) (point-max)))))))
+
+(defsubst fuel-eval--send/retort (str)
+  (fuel-eval--parse-retort (fuel-eval--send-string str)))
+
+(defsubst fuel-eval--eval-begin ()
+  (fuel-eval--send/retort "fuel-begin-eval"))
+
+(defsubst fuel-eval--eval-end ()
+  (fuel-eval--send/retort "fuel-begin-eval"))
+
+(defsubst fuel-eval--factor-array (strs)
+  (format "V{ %S }" (mapconcat 'identity strs " ")))
+
+(defsubst fuel-eval--eval-strings (strs)
+  (let ((str (format "%s fuel-eval" (fuel-eval--factor-array strs))))
+    (fuel-eval--send/retort str)))
+
+(defsubst fuel-eval--eval-string (str)
+  (fuel-eval--eval-strings (list str)))
+
+(defun fuel-eval--eval-strings/context (strs)
+  (let ((usings (fuel-syntax--usings-update)))
+    (fuel-eval--send/retort
+     (format "%s %S %s fuel-eval-in-context"
+             (fuel-eval--factor-array strs)
+             (or fuel-syntax--current-vocab "f")
+             (if usings (fuel-eval--factor-array usings) "f")))))
+
+(defsubst fuel-eval--eval-string/context (str)
+  (fuel-eval--eval-strings/context (list str)))
+
+(defun fuel-eval--eval-region/context (begin end)
+  (let ((lines (split-string (buffer-substring-no-properties begin end)
+                             "[\f\n\r\v]+" t)))
+    (when (> (length lines) 0)
+      (fuel-eval--eval-strings/context lines))))
+
+\f
+(provide 'fuel-eval)
+;;; fuel-eval.el ends here
diff --git a/misc/fuel/fuel-font-lock.el b/misc/fuel/fuel-font-lock.el
new file mode 100644 (file)
index 0000000..c8673f7
--- /dev/null
@@ -0,0 +1,88 @@
+;;; fuel-font-lock.el -- font lock for factor code
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Wed Dec 03, 2008 21:40
+
+;;; Comentary:
+
+;; Font lock setup for highlighting Factor code.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-syntax)
+
+(require 'font-lock)
+
+\f
+;;; Faces:
+
+(defmacro fuel-font-lock--face (face def doc)
+  (let ((face (intern (format "factor-font-lock-%s" (symbol-name face))))
+        (def (intern (format "font-lock-%s-face" (symbol-name def)))))
+    `(defface ,face (face-default-spec ,def)
+       ,(format "Face for %s." doc)
+       :group 'factor-mode
+       :group 'faces)))
+
+(defmacro fuel-font-lock--faces-setup ()
+  (cons 'progn
+        (mapcar (lambda (f) (cons 'fuel-font-lock--face f))
+                '((comment comment "comments")
+                  (constructor type  "constructors (<foo>)")
+                  (declaration keyword "declaration words")
+                  (parsing-word keyword  "parsing words")
+                  (setter-word function-name "setter words (>>foo)")
+                  (stack-effect comment "stack effect specifications")
+                  (string string "strings")
+                  (symbol variable-name "name of symbol being defined")
+                  (type-name type "type names")
+                  (vocabulary-name constant "vocabulary names")
+                  (word function-name "word, generic or method being defined")))))
+
+(fuel-font-lock--faces-setup)
+
+\f
+;;; Font lock:
+
+(defconst fuel-font-lock--parsing-lock-keywords
+  (cons '("\\(P\\|SBUF\\)\"" 1 'factor-font-lock-parsing-word)
+        (mapcar (lambda (w) `(,(format "\\(^\\| \\)\\(%s\\)\\($\\| \\)" w)
+                         2 'factor-font-lock-parsing-word))
+                fuel-syntax--parsing-words)))
+
+(defconst fuel-font-lock--font-lock-keywords
+  `(,@fuel-font-lock--parsing-lock-keywords
+    (,fuel-syntax--stack-effect-regex . 'factor-font-lock-stack-effect)
+    (,fuel-syntax--parsing-words-ext-regex . 'factor-font-lock-parsing-word)
+    (,fuel-syntax--declaration-words-regex 1 'factor-font-lock-declaration)
+    (,fuel-syntax--word-definition-regex 2 'factor-font-lock-word)
+    (,fuel-syntax--type-definition-regex 2 'factor-font-lock-type-name)
+    (,fuel-syntax--method-definition-regex (1 'factor-font-lock-type-name)
+                                           (2 'factor-font-lock-word))
+    (,fuel-syntax--parent-type-regex 1 'factor-font-lock-type)
+    (,fuel-syntax--constructor-regex . 'factor-font-lock-constructor)
+    (,fuel-syntax--setter-regex . 'factor-font-lock-setter-word)
+    (,fuel-syntax--symbol-definition-regex 2 'factor-font-lock-symbol)
+    (,fuel-syntax--use-line-regex 1 'factor-font-lock-vocabulary-name))
+  "Font lock keywords definition for Factor mode.")
+
+(defun fuel-font-lock--font-lock-setup (&optional keywords no-syntax)
+  (set (make-local-variable 'comment-start) "! ")
+  (set (make-local-variable 'parse-sexp-lookup-properties) t)
+  (set (make-local-variable 'font-lock-comment-face) 'factor-font-lock-comment)
+  (set (make-local-variable 'font-lock-string-face) 'factor-font-lock-string)
+  (set (make-local-variable 'font-lock-defaults)
+       `(,(or keywords 'fuel-font-lock--font-lock-keywords)
+         nil nil nil nil
+         ,@(if no-syntax nil
+             (list (cons 'font-lock-syntactic-keywords
+                         fuel-syntax--syntactic-keywords))))))
+
+\f
+(provide 'fuel-font-lock)
+;;; fuel-font-lock.el ends here
diff --git a/misc/fuel/fuel-help.el b/misc/fuel/fuel-help.el
new file mode 100644 (file)
index 0000000..dcf17d2
--- /dev/null
@@ -0,0 +1,208 @@
+;;; fuel-help.el -- accessing Factor's help system
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Wed Dec 03, 2008 21:41
+
+;;; Comentary:
+
+;; Modes and functions interfacing Factor's 'see' and 'help'
+;; utilities, as well as an ElDoc-based autodoc mode.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-font-lock)
+(require 'fuel-eval)
+
+\f
+;;; Customization:
+
+(defgroup fuel-help nil
+  "Options controlling FUEL's help system"
+  :group 'fuel)
+
+(defcustom fuel-help-minibuffer-font-lock t
+  "Whether to use font lock for info messages in the minibuffer."
+  :group 'fuel-help
+  :type 'boolean)
+
+(defcustom fuel-help-always-ask t
+  "When enabled, always ask for confirmation in help prompts."
+  :type 'boolean
+  :group 'fuel-help)
+
+(defcustom fuel-help-use-minibuffer t
+  "When enabled, use the minibuffer for short help messages."
+  :type 'boolean
+  :group 'fuel-help)
+
+(defcustom fuel-help-mode-hook nil
+  "Hook run by `factor-help-mode'."
+  :type 'hook
+  :group 'fuel-help)
+
+(defface fuel-help-font-lock-headlines '((t (:bold t :weight bold)))
+  "Face for headlines in help buffers."
+  :group 'fuel-help
+  :group 'faces)
+
+\f
+;;; Autodoc mode:
+
+(defvar fuel-help--font-lock-buffer
+  (let ((buffer (get-buffer-create " *fuel help minibuffer messages*")))
+    (set-buffer buffer)
+    (fuel-font-lock--font-lock-setup)
+    buffer))
+
+(defun fuel-help--font-lock-str (str)
+  (set-buffer fuel-help--font-lock-buffer)
+  (erase-buffer)
+  (insert str)
+  (let ((font-lock-verbose nil)) (font-lock-fontify-buffer))
+  (buffer-string))
+
+(defun fuel-help--word-synopsis (&optional word)
+  (let ((word (or word (fuel-syntax-symbol-at-point)))
+        (fuel-eval--log nil))
+    (when word
+      (let ((ret (fuel-eval--eval-string/context
+                  (format "\\ %s synopsis fuel-eval-set-result" word))))
+        (when (not (fuel-eval--retort-error ret))
+          (if fuel-help-minibuffer-font-lock
+              (fuel-help--font-lock-str (fuel-eval--retort-result ret))
+            (fuel-eval--retort-result ret)))))))
+
+(make-variable-buffer-local
+ (defvar fuel-autodoc-mode-string " A"
+   "Modeline indicator for fuel-autodoc-mode"))
+
+(define-minor-mode fuel-autodoc-mode
+  "Toggle Fuel's Autodoc mode.
+With no argument, this command toggles the mode.
+Non-null prefix argument turns on the mode.
+Null prefix argument turns off the mode.
+
+When Autodoc mode is enabled, a synopsis of the word at point is
+displayed in the minibuffer."
+  :init-value nil
+  :lighter fuel-autodoc-mode-string
+  :group 'fuel
+
+  (set (make-local-variable 'eldoc-documentation-function)
+       (when fuel-autodoc-mode 'fuel-help--word-synopsis))
+  (set (make-local-variable 'eldoc-minor-mode-string) nil)
+  (eldoc-mode fuel-autodoc-mode)
+  (message "Fuel Autodoc %s" (if fuel-autodoc-mode "enabled" "disabled")))
+
+\f
+;;;; Factor help mode:
+
+(defvar fuel-help-mode-map (make-sparse-keymap)
+  "Keymap for Factor help mode.")
+
+(define-key fuel-help-mode-map [(return)] 'fuel-help)
+
+(defconst fuel-help--headlines
+  (regexp-opt '("Class description"
+                "Definition"
+                "Examples"
+                "Generic word contract"
+                "Inputs and outputs"
+                "Methods"
+                "Notes"
+                "Parent topics:"
+                "See also"
+                "Syntax"
+                "Vocabulary"
+                "Warning"
+                "Word description")
+              t))
+
+(defconst fuel-help--headlines-regexp (format "^%s" fuel-help--headlines))
+
+(defconst fuel-help--font-lock-keywords
+  `(,@fuel-font-lock--font-lock-keywords
+    (,fuel-help--headlines-regexp . 'fuel-help-font-lock-headlines)))
+
+(defun fuel-help-mode ()
+  "Major mode for displaying Factor documentation.
+\\{fuel-help-mode-map}"
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map fuel-help-mode-map)
+  (setq mode-name "Factor Help")
+  (setq major-mode 'fuel-help-mode)
+
+  (fuel-font-lock--font-lock-setup fuel-help--font-lock-keywords t)
+
+  (set (make-local-variable 'view-no-disable-on-exit) t)
+  (view-mode)
+  (setq view-exit-action
+        (lambda (buffer)
+          ;; Use `with-current-buffer' to make sure that `bury-buffer'
+          ;; also removes BUFFER from the selected window.
+          (with-current-buffer buffer
+            (bury-buffer))))
+
+  (setq fuel-autodoc-mode-string "")
+  (fuel-autodoc-mode)
+  (run-mode-hooks 'fuel-help-mode-hook))
+
+(defun fuel-help--help-buffer ()
+  (with-current-buffer (get-buffer-create "*fuel-help*")
+    (fuel-help-mode)
+    (current-buffer)))
+
+(defvar fuel-help--history nil)
+
+(defun fuel-help--show-help (&optional see)
+  (let* ((def (fuel-syntax-symbol-at-point))
+         (prompt (format "See%s help on%s: " (if see " short" "")
+                         (if def (format " (%s)" def) "")))
+         (ask (or (not (memq major-mode '(factor-mode fuel-help-mode)))
+                  (not def)
+                  fuel-help-always-ask))
+         (def (if ask (read-string prompt nil 'fuel-help--history def) def))
+         (cmd (format "\\ %s %s" def (if see "see" "help")))
+         (fuel-eval--log nil)
+         (ret (fuel-eval--eval-string/context cmd))
+         (out (fuel-eval--retort-output ret)))
+    (if (or (fuel-eval--retort-error ret) (empty-string-p out))
+        (message "No help for '%s'" def)
+      (let ((hb (fuel-help--help-buffer))
+            (inhibit-read-only t)
+            (font-lock-verbose nil))
+        (set-buffer hb)
+        (erase-buffer)
+        (insert out)
+        (set-buffer-modified-p nil)
+        (pop-to-buffer hb)
+        (goto-char (point-min))))))
+
+\f
+;;; Interface: see/help commands
+
+(defun fuel-help-short (&optional arg)
+  "See a help summary of symbol at point.
+By default, the information is shown in the minibuffer. When
+called with a prefix argument, the information is displayed in a
+separate help buffer."
+  (interactive "P")
+  (if (if fuel-help-use-minibuffer (not arg) arg)
+      (fuel-help--word-synopsis)
+    (fuel-help--show-help t)))
+
+(defun fuel-help ()
+  "Show extended help about the symbol at point, using a help
+buffer."
+  (interactive)
+  (fuel-help--show-help))
+
+\f
+(provide 'fuel-help)
+;;; fuel-help.el ends here
diff --git a/misc/fuel/fuel-listener.el b/misc/fuel/fuel-listener.el
new file mode 100644 (file)
index 0000000..958c589
--- /dev/null
@@ -0,0 +1,120 @@
+;;; fuel-listener.el --- starting the fuel listener
+
+;; Copyright (C) 2008  Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+
+;;; Commentary:
+
+;; Utilities to maintain and switch to a factor listener comint
+;; buffer, with an accompanying major fuel-listener-mode.
+
+;;; Code:
+
+(require 'fuel-eval)
+(require 'fuel-base)
+(require 'comint)
+
+\f
+;;; Customization:
+
+(defgroup fuel-listener nil
+  "Interacting with a Factor listener inside Emacs"
+  :group 'fuel)
+
+(defcustom fuel-listener-factor-binary "~/factor/factor"
+  "Full path to the factor executable to use when starting a listener."
+  :type '(file :must-match t)
+  :group 'fuel-listener)
+
+(defcustom fuel-listener-factor-image "~/factor/factor.image"
+  "Full path to the factor image to use when starting a listener."
+  :type '(file :must-match t)
+  :group 'fuel-listener)
+
+(defcustom fuel-listener-use-other-window t
+  "Use a window other than the current buffer's when switching to
+the factor-listener buffer."
+  :type 'boolean
+  :group 'fuel-listener)
+
+(defcustom fuel-listener-window-allow-split t
+  "Allow window splitting when switching to the fuel listener
+buffer."
+  :type 'boolean
+  :group 'fuel-listener)
+
+\f
+;;; Fuel listener buffer/process:
+
+(defvar fuel-listener-buffer nil
+  "The buffer in which the Factor listener is running.")
+
+(defun fuel-listener--start-process ()
+  (let ((factor (expand-file-name fuel-listener-factor-binary))
+        (image (expand-file-name fuel-listener-factor-image)))
+    (unless (file-executable-p factor)
+      (error "Could not run factor: %s is not executable" factor))
+    (unless (file-readable-p image)
+      (error "Could not run factor: image file %s not readable" image))
+    (setq fuel-listener-buffer
+          (make-comint "fuel listener" factor nil "-run=fuel" (format "-i=%s" image)))
+    (with-current-buffer fuel-listener-buffer
+      (fuel-listener-mode))))
+
+(defun fuel-listener--process (&optional start)
+  (or (and (buffer-live-p fuel-listener-buffer)
+           (get-buffer-process fuel-listener-buffer))
+      (if (not start)
+          (error "No running factor listener (try M-x run-factor)")
+        (fuel-listener--start-process)
+        (fuel-listener--process))))
+
+(setq fuel-eval--default-proc-function 'fuel-listener--process)
+
+\f
+;;; Interface: starting fuel listener
+
+(defalias 'switch-to-factor 'run-factor)
+(defalias 'switch-to-fuel-listener 'run-factor)
+;;;###autoload
+(defun run-factor (&optional arg)
+  "Show the fuel-listener buffer, starting the process if needed."
+  (interactive)
+  (let ((buf (process-buffer (fuel-listener--process t)))
+        (pop-up-windows fuel-listener-window-allow-split))
+    (if fuel-listener-use-other-window
+        (pop-to-buffer buf)
+      (switch-to-buffer buf))))
+
+\f
+;;; Fuel listener mode:
+
+(defconst fuel-listener--prompt-regex "( [^)]* ) ")
+
+(defun fuel-listener--wait-for-prompt (&optional timeout)
+  (let ((proc (fuel-listener--process)))
+    (with-current-buffer fuel-listener-buffer
+      (goto-char comint-last-input-end)
+      (while (not (or (re-search-forward comint-prompt-regexp nil t)
+                      (not (accept-process-output proc timeout))))
+        (goto-char comint-last-input-end))
+      (goto-char (point-max)))))
+
+(defun fuel-listener--startup ()
+  (fuel-listener--wait-for-prompt)
+  (fuel-eval--send-string "USE: fuel")
+  (message "FUEL listener up and running!"))
+
+(define-derived-mode fuel-listener-mode comint-mode "Fuel Listener"
+  "Major mode for interacting with an inferior Factor listener process.
+\\{fuel-listener-mode-map}"
+  (set (make-local-variable 'comint-prompt-regexp)
+       fuel-listener--prompt-regex)
+  (fuel-listener--startup))
+
+\f
+(provide 'fuel-listener)
+;;; fuel-listener.el ends here
diff --git a/misc/fuel/fuel-mode.el b/misc/fuel/fuel-mode.el
new file mode 100644 (file)
index 0000000..5a32066
--- /dev/null
@@ -0,0 +1,106 @@
+;;; fuel-mode.el -- Minor mode enabling FUEL niceties
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Sat Dec 06, 2008 00:52
+
+;;; Comentary:
+
+;; Enhancements to vanilla factor-mode (notably, listener interaction)
+;; enabled by means of a minor mode.
+
+;;; Code:
+
+(require 'factor-mode)
+(require 'fuel-base)
+(require 'fuel-syntax)
+(require 'fuel-font-lock)
+(require 'fuel-help)
+(require 'fuel-eval)
+(require 'fuel-listener)
+
+\f
+;;; Customization:
+
+(defgroup fuel-mode nil
+  "Mode enabling FUEL's ultimate abilities."
+  :group 'fuel)
+
+(defcustom fuel-mode-autodoc-p t
+  "Whether `fuel-autodoc-mode' gets enable by default in fuel buffers."
+  :group 'fuel-mode
+  :type 'boolean)
+
+\f
+;;; User commands
+
+(defun fuel-eval-definition (&optional arg)
+  "Sends definition around point to Fuel's listener for evaluation.
+With prefix, switchs the the listener's buffer."
+  (interactive "P")
+  (save-excursion
+    (mark-defun)
+    (let* ((begin (point))
+           (end (mark)))
+      (unless (< begin end) (error "No evaluable definition around point"))
+      (let* ((msg (match-string 0))
+             (ret (fuel-eval--eval-region/context begin end))
+             (err (fuel-eval--retort-error ret)))
+        (when err (error "%s" err))
+        (message "%s" (fuel--shorten-region begin end 70)))))
+  (when arg (pop-to-buffer fuel-listener-buffer)))
+
+\f
+;;; Minor mode definition:
+
+(make-variable-buffer-local
+ (defvar fuel-mode-string " F"
+   "Modeline indicator for fuel-mode"))
+
+(defvar fuel-mode-map (make-sparse-keymap)
+  "Key map for fuel-mode")
+
+(define-minor-mode fuel-mode
+  "Toggle Fuel's mode.
+With no argument, this command toggles the mode.
+Non-null prefix argument turns on the mode.
+Null prefix argument turns off the mode.
+
+When Fuel mode is enabled, a host of nice utilities for
+interacting with a factor listener is at your disposal.
+\\{fuel-mode-map}"
+  :init-value nil
+  :lighter fuel-mode-string
+  :group 'fuel
+  :keymap fuel-mode-map
+
+  (setq fuel-autodoc-mode-string "/A")
+  (when fuel-mode-autodoc-p (fuel-autodoc-mode fuel-mode)))
+
+\f
+;;; Keys:
+
+(defun fuel-mode--key-1 (k c)
+  (define-key fuel-mode-map (vector '(control ?c) k) c)
+  (define-key fuel-mode-map (vector '(control ?c) `(control ,k))  c))
+
+(defun fuel-mode--key (p k c)
+  (define-key fuel-mode-map (vector '(control ?c) `(control ,p) k) c)
+  (define-key fuel-mode-map (vector '(control ?c) `(control ,p) `(control ,k)) c))
+
+(fuel-mode--key-1 ?z 'run-factor)
+
+(define-key fuel-mode-map "\C-\M-x" 'fuel-eval-definition)
+
+(fuel-mode--key ?e ?d 'fuel-eval-definition)
+
+(fuel-mode--key ?d ?a 'fuel-autodoc-mode)
+(fuel-mode--key ?d ?d 'fuel-help)
+(fuel-mode--key ?d ?s 'fuel-help-short)
+
+\f
+(provide 'fuel-mode)
+;;; fuel-mode.el ends here
diff --git a/misc/fuel/fuel-syntax.el b/misc/fuel/fuel-syntax.el
new file mode 100644 (file)
index 0000000..a0485f9
--- /dev/null
@@ -0,0 +1,281 @@
+;;; fuel-syntax.el --- auxiliar definitions for factor code navigation.
+
+;; Copyright (C) 2008  Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+
+;;; Commentary:
+
+;; Auxiliar constants and functions to parse factor code.
+
+;;; Code:
+
+(require 'thingatpt)
+
+\f
+;;; Thing-at-point support for factor symbols:
+
+(defun fuel-syntax--beginning-of-symbol ()
+  "Move point to the beginning of the current symbol."
+  (while (eq (char-before) ?:) (backward-char))
+  (skip-syntax-backward "w_"))
+
+(defun fuel-syntax--end-of-symbol ()
+  "Move point to the end of the current symbol."
+  (skip-syntax-forward "w_")
+  (while (looking-at ":") (forward-char)))
+
+(put 'factor-symbol 'end-op 'fuel-syntax--end-of-symbol)
+(put 'factor-symbol 'beginning-op 'fuel-syntax--beginning-of-symbol)
+
+(defsubst fuel-syntax-symbol-at-point ()
+  (let ((s (substring-no-properties (thing-at-point 'factor-symbol))))
+    (and (> (length s) 0) s)))
+
+\f
+;;; Regexps galore:
+
+(defconst fuel-syntax--parsing-words
+  '("{" "}" "^:" "^::" ";" "<<" "<PRIVATE" ">>"
+    "BIN:" "BV{" "B{" "C:" "C-STRUCT:" "C-UNION:" "CHAR:" "CS{" "C{"
+    "DEFER:" "ERROR:" "EXCLUDE:" "FORGET:"
+    "GENERIC#" "GENERIC:" "HEX:" "HOOK:" "H{"
+    "IN:" "INSTANCE:" "INTERSECTION:"
+    "M:" "MACRO:" "MACRO::" "MAIN:" "MATH:" "METHOD:" "MIXIN:"
+    "OCT:" "POSTPONE:" "PREDICATE:" "PRIMITIVE:" "PRIVATE>" "PROVIDE:"
+    "REQUIRE:"  "REQUIRES:" "SINGLETON:" "SLOT:" "SYMBOL:" "SYMBOLS:"
+    "TUPLE:" "T{" "t\\??" "TYPEDEF:"
+    "UNION:" "USE:" "USING:" "V{" "VARS:" "W{"))
+
+(defconst fuel-syntax--parsing-words-ext-regex
+  (regexp-opt '("B" "call-next-method" "delimiter" "f" "initial:" "read-only")
+              'words))
+
+(defconst fuel-syntax--declaration-words
+  '("flushable" "foldable" "inline" "parsing" "recursive"))
+
+(defconst fuel-syntax--declaration-words-regex
+  (regexp-opt fuel-syntax--declaration-words 'words))
+
+(defsubst fuel-syntax--second-word-regex (prefixes)
+  (format "^%s +\\([^ \r\n]+\\)" (regexp-opt prefixes t)))
+
+(defconst fuel-syntax--method-definition-regex
+  "^M: +\\([^ ]+\\) +\\([^ ]+\\)")
+
+(defconst fuel-syntax--word-definition-regex
+  (fuel-syntax--second-word-regex '(":" "::" "GENERIC:")))
+
+(defconst fuel-syntax--type-definition-regex
+  (fuel-syntax--second-word-regex '("TUPLE:" "SINGLETON:")))
+
+(defconst fuel-syntax--parent-type-regex "^TUPLE: +[^ ]+ +< +\\([^ ]+\\)")
+
+(defconst fuel-syntax--constructor-regex "<[^ >]+>")
+
+(defconst fuel-syntax--setter-regex "\\W>>[^ ]+\\b")
+
+(defconst fuel-syntax--symbol-definition-regex
+  (fuel-syntax--second-word-regex '("SYMBOL:" "VAR:")))
+
+(defconst fuel-syntax--stack-effect-regex " ( .* )")
+
+(defconst fuel-syntax--using-lines-regex "^USING: +\\([^;]+\\);")
+
+(defconst fuel-syntax--use-line-regex "^USE: +\\(.*\\)$")
+
+(defconst fuel-syntax--current-vocab-regex "^IN: +\\([^ \r\n\f]+\\)")
+
+(defconst fuel-syntax--sub-vocab-regex "^<\\([^ \n]+\\) *$")
+
+(defconst fuel-syntax--definition-starters-regex
+  (regexp-opt '("VARS" "TUPLE" "MACRO" "MACRO:" "M" ":" "")))
+
+(defconst fuel-syntax--definition-start-regex
+  (format "^\\(%s:\\) " fuel-syntax--definition-starters-regex))
+
+(defconst fuel-syntax--definition-end-regex
+  (format "\\(\\(^\\| +\\);\\( +%s\\)*\\($\\| +\\)\\)"
+          fuel-syntax--declaration-words-regex))
+
+(defconst fuel-syntax--single-liner-regex
+  (format "^%s" (regexp-opt '("DEFER:" "GENERIC:" "IN:"
+                              "PRIVATE>" "<PRIVATE"
+                              "SINGLETON:" "SYMBOL:" "USE:" "VAR:"))))
+
+(defconst fuel-syntax--begin-of-def-regex
+  (format "^USING: \\|\\(%s\\)\\|\\(%s .*\\)"
+          fuel-syntax--definition-start-regex
+          fuel-syntax--single-liner-regex))
+
+(defconst fuel-syntax--end-of-def-line-regex
+  (format "^.*%s" fuel-syntax--definition-end-regex))
+
+(defconst fuel-syntax--end-of-def-regex
+  (format "\\(%s\\)\\|\\(%s .*\\)"
+          fuel-syntax--end-of-def-line-regex
+          fuel-syntax--single-liner-regex))
+\f
+;;; Factor syntax table
+
+(defvar fuel-syntax--syntax-table
+  (let ((i 0)
+        (table (make-syntax-table)))
+    ;; Default is atom-constituent
+    (while (< i 256)
+      (modify-syntax-entry i "_   " table)
+      (setq i (1+ i)))
+
+    ;; Word components.
+    (setq i ?0)
+    (while (<= i ?9)
+      (modify-syntax-entry i "w   " table)
+      (setq i (1+ i)))
+    (setq i ?A)
+    (while (<= i ?Z)
+      (modify-syntax-entry i "w   " table)
+      (setq i (1+ i)))
+    (setq i ?a)
+    (while (<= i ?z)
+      (modify-syntax-entry i "w   " table)
+      (setq i (1+ i)))
+
+    ;; Whitespace
+    (modify-syntax-entry ?\t " " table)
+    (modify-syntax-entry ?\f " " table)
+    (modify-syntax-entry ?\r " " table)
+    (modify-syntax-entry ?  " " table)
+
+    ;; (end of) Comments
+    (modify-syntax-entry ?\n ">" table)
+
+    ;; Parenthesis
+    (modify-syntax-entry ?\[ "(]  " table)
+    (modify-syntax-entry ?\] ")[  " table)
+    (modify-syntax-entry ?{ "(}  " table)
+    (modify-syntax-entry ?} "){  " table)
+
+    (modify-syntax-entry ?\( "()" table)
+    (modify-syntax-entry ?\) ")(" table)
+
+    ;; Strings
+    (modify-syntax-entry ?\" "\"" table)
+    (modify-syntax-entry ?\\ "/" table)
+    table)
+  "Syntax table used while in Factor mode.")
+
+(defconst fuel-syntax--syntactic-keywords
+  `(("\\(#!\\)" (1 "<"))
+    (" \\(!\\)" (1 "<"))
+    ("^\\(!\\)" (1 "<"))
+    ("\\(!(\\) .* \\()\\)" (1 "<") (2 ">"))
+    ("\\([[({]\\)\\([^ \"\n]\\)" (1 "_") (2 "_"))
+    ("\\([^ \"\n]\\)\\([])}]\\)" (1 "_") (2 "_"))))
+
+\f
+;;; Source code analysis:
+
+(defsubst fuel-syntax--brackets-depth ()
+  (nth 0 (syntax-ppss)))
+
+(defsubst fuel-syntax--brackets-start ()
+  (nth 1 (syntax-ppss)))
+
+(defun fuel-syntax--brackets-end ()
+  (save-excursion
+    (goto-char (fuel-syntax--brackets-start))
+    (condition-case nil
+        (progn (forward-sexp)
+               (1- (point)))
+      (error -1))))
+
+(defsubst fuel-syntax--indentation-at (pos)
+  (save-excursion (goto-char pos) (current-indentation)))
+
+(defsubst fuel-syntax--increased-indentation (&optional i)
+  (+ (or i (current-indentation)) factor-indent-width))
+(defsubst fuel-syntax--decreased-indentation (&optional i)
+  (- (or i (current-indentation)) factor-indent-width))
+
+(defsubst fuel-syntax--at-begin-of-def ()
+  (looking-at fuel-syntax--begin-of-def-regex))
+
+(defsubst fuel-syntax--at-end-of-def ()
+  (looking-at fuel-syntax--end-of-def-regex))
+
+(defsubst fuel-syntax--looking-at-emptiness ()
+  (looking-at "^[ \t]*$"))
+
+(defun fuel-syntax--at-setter-line ()
+  (save-excursion
+    (beginning-of-line)
+    (if (not (fuel-syntax--looking-at-emptiness))
+        (re-search-forward fuel-syntax--setter-regex (line-end-position) t)
+      (forward-line -1)
+      (or (fuel-syntax--at-constructor-line)
+          (fuel-syntax--at-setter-line)))))
+
+(defun fuel-syntax--at-constructor-line ()
+  (save-excursion
+    (beginning-of-line)
+    (re-search-forward fuel-syntax--constructor-regex (line-end-position) t)))
+
+(defsubst fuel-syntax--at-using ()
+  (looking-at fuel-syntax--using-lines-regex))
+
+(defsubst fuel-syntax--beginning-of-defun (&optional times)
+  (re-search-backward fuel-syntax--begin-of-def-regex nil t times))
+
+(defsubst fuel-syntax--end-of-defun ()
+  (re-search-forward fuel-syntax--end-of-def-regex nil t))
+
+\f
+;;; USING/IN:
+
+(make-variable-buffer-local
+ (defvar fuel-syntax--current-vocab nil))
+
+(make-variable-buffer-local
+ (defvar fuel-syntax--usings nil))
+
+(defun fuel-syntax--current-vocab ()
+  (let ((ip
+         (save-excursion
+           (when (re-search-backward fuel-syntax--current-vocab-regex nil t)
+             (setq fuel-syntax--current-vocab (match-string-no-properties 1))
+             (point)))))
+    (when ip
+      (let ((pp (save-excursion
+                  (when (re-search-backward fuel-syntax--sub-vocab-regex ip t)
+                    (point)))))
+        (when (and pp (> pp ip))
+          (let ((sub (match-string-no-properties 1)))
+            (unless (save-excursion (search-backward (format "%s>" sub) pp t))
+              (setq fuel-syntax--current-vocab
+                    (format "%s.%s" fuel-syntax--current-vocab (downcase sub)))))))))
+  fuel-syntax--current-vocab)
+
+(defun fuel-syntax--usings-update ()
+  (save-excursion
+    (setq fuel-syntax--usings (list (fuel-syntax--current-vocab)))
+    (while (re-search-backward fuel-syntax--using-lines-regex nil t)
+      (dolist (u (split-string (match-string-no-properties 1) nil t))
+        (push u fuel-syntax--usings)))
+    fuel-syntax--usings))
+
+(defsubst fuel-syntax--usings-update-hook ()
+  (fuel-syntax--usings-update)
+  nil)
+
+(defun fuel-syntax--enable-usings ()
+  (add-hook 'before-save-hook 'fuel-syntax--usings-update-hook nil t)
+  (fuel-syntax--usings-update))
+
+(defsubst fuel-syntax--usings ()
+  (or fuel-syntax--usings (fuel-syntax--usings-update)))
+
+\f
+(provide 'fuel-syntax)
+;;; fuel-syntax.el ends here