version 1.57, 2002/01/17 19:26:34
|
version 1.62, 2002/04/18 17:07:56
|
Line 33
|
Line 33
|
;; Changes by David |
;; Changes by David |
;; Added a syntax-hilighting engine, rewrote auto-indentation engine. |
;; Added a syntax-hilighting engine, rewrote auto-indentation engine. |
;; Added support for block files. |
;; Added support for block files. |
|
;; Tested with Emacs 19.34, 20.5, 21.1 and XEmacs 21.1 |
|
|
;;------------------------------------------------------------------- |
;;------------------------------------------------------------------- |
;; A Forth indentation, documentation search and interaction library |
;; A Forth indentation, documentation search and interaction library |
Line 49
|
Line 50
|
|
|
;;; Code: |
;;; Code: |
|
|
|
;(setq debug-on-error t) |
|
|
;; Code ripped from `version.el' for compatability with Emacs versions |
;; Code ripped from `version.el' for compatability with Emacs versions |
;; prior to 19.23. |
;; prior to 19.23. |
(unless (boundp 'emacs-major-version) |
(if (not (boundp 'emacs-major-version)) |
(defconst emacs-major-version |
(defconst emacs-major-version |
(progn (string-match "^[0-9]+" emacs-version) |
(progn (string-match "^[0-9]+" emacs-version) |
(string-to-int (match-string 0 emacs-version))))) |
(string-to-int (match-string 0 emacs-version))))) |
|
|
|
(defun forth-emacs-older (major minor) |
|
(or (< emacs-major-version major) |
|
(and (= emacs-major-version major) (< emacs-minor-version minor)))) |
|
|
|
;; Code ripped from `subr.el' for compatability with Emacs versions |
|
;; prior to 20.1 |
|
(eval-when-compile |
|
(if (forth-emacs-older 20 1) |
|
(progn |
|
(defmacro when (cond &rest body) |
|
"If COND yields non-nil, do BODY, else return nil." |
|
(list 'if cond (cons 'progn body))) |
|
(defmacro unless (cond &rest body) |
|
"If COND yields nil, do BODY, else return nil." |
|
(cons 'if (cons cond (cons nil body))))))) |
|
|
|
;; `no-error' argument of require not supported in Emacs versions |
|
;; prior to 20.4 :-( |
|
(defun forth-require (feature) |
|
(condition-case err (require feature) (error nil))) |
|
|
|
(require 'font-lock) |
|
|
|
;; define `font-lock-warning-face' in emacs-versions prior to 20.1 |
|
;; (ripped from `font-lock.el') |
|
(unless (boundp 'font-lock-warning-face) |
|
(message "defining font-lock-warning-face") |
|
(make-face 'font-lock-warning-face) |
|
(defvar font-lock-warning-face 'font-lock-warning-face) |
|
(set-face-foreground font-lock-warning-face "red") |
|
(make-face-bold font-lock-warning-face)) |
|
|
|
;; define `font-lock-constant-face' in XEmacs (just copy |
|
;; `font-lock-preprocessor-face') |
|
(unless (boundp 'font-lock-constant-face) |
|
(copy-face font-lock-preprocessor-face 'font-lock-constant-face)) |
|
|
|
|
|
;; define `regexp-opt' in emacs versions prior to 20.1 |
|
;; (this implementation is extremely inefficient, though) |
|
(eval-and-compile (forth-require 'regexp-opt)) |
|
(unless (memq 'regexp-opt features) |
|
(message (concat |
|
"Warning: your Emacs version doesn't support `regexp-opt'. " |
|
"Hilighting will be slow.")) |
|
(defun regexp-opt (STRINGS &optional PAREN) |
|
(let ((open (if PAREN "\\(" "")) (close (if PAREN "\\)" ""))) |
|
(concat open (mapconcat 'regexp-quote STRINGS "\\|") close))) |
|
(defun regexp-opt-depth (re) |
|
(if (string= (substring re 0 2) "\\(") 1 0))) |
|
|
; todo: |
; todo: |
; |
; |
Line 83
|
Line 136
|
; |
; |
; Folding neuschreiben (neue Parser-Informationen benutzen) |
; Folding neuschreiben (neue Parser-Informationen benutzen) |
|
|
;;; Hilighting and indentation engine (dk) |
;;; Motion-hooking (dk) |
;;; |
;;; |
(require 'font-lock) |
(defun forth-idle-function () |
|
"Function that is called when Emacs is idle to detect cursor motion |
|
in forth-block-mode buffers (which is mainly used for screen number |
|
display in). Currently ignores forth-mode buffers but that may change |
|
in the future." |
|
(if (eq major-mode 'forth-block-mode) |
|
(forth-check-motion))) |
|
|
|
(defvar forth-idle-function-timer nil |
|
"Timer that runs `forth-idle-function' or nil if no timer installed.") |
|
|
|
(defun forth-install-motion-hook () |
|
"Install the motion-hooking mechanism. Currently uses idle timers |
|
but might be transparently changed in the future." |
|
(unless forth-idle-function-timer |
|
;; install idle function only once (first time forth-mode is used) |
|
(setq forth-idle-function-timer |
|
(run-with-idle-timer .05 t 'forth-idle-function)))) |
|
|
|
(defvar forth-was-point nil) |
|
|
|
(defun forth-check-motion () |
|
"Run `forth-motion-hooks', if `point' changed since last call. This |
|
used to be called via `post-command-hook' but uses idle timers now as |
|
users complaint about lagging performance." |
|
(when (or (eq forth-was-point nil) (/= forth-was-point (point))) |
|
(setq forth-was-point (point)) |
|
(run-hooks 'forth-motion-hooks))) |
|
|
|
|
|
;;; Hilighting and indentation engine (dk) |
|
;;; |
(defvar forth-disable-parser nil |
(defvar forth-disable-parser nil |
"*Non-nil means to disable on-the-fly parsing of Forth-code. |
"*Non-nil means to disable on-the-fly parsing of Forth-code. |
|
|
Line 182 PARSED-TYPE specifies what kind of text
|
Line 265 PARSED-TYPE specifies what kind of text
|
(("[ifdef]" "[ifundef]") immediate (font-lock-keyword-face . 2) |
(("[ifdef]" "[ifundef]") immediate (font-lock-keyword-face . 2) |
"[ \t\n]" t name (font-lock-function-name-face . 3)) |
"[ \t\n]" t name (font-lock-function-name-face . 3)) |
(("if" "begin" "ahead" "do" "?do" "+do" "u+do" "-do" "u-do" "for" |
(("if" "begin" "ahead" "do" "?do" "+do" "u+do" "-do" "u-do" "for" |
"case" "of" "?dup-if" "?dup-0=-if" "then" "until" "repeat" "again" |
"case" "of" "?dup-if" "?dup-0=-if" "then" "endif" "until" |
|
"repeat" "again" |
"loop" "+loop" "-loop" "next" "endcase" "endof" "else" "while" "try" |
"loop" "+loop" "-loop" "next" "endcase" "endof" "else" "while" "try" |
"recover" "endtry" "assert(" "assert0(" "assert1(" "assert2(" |
"recover" "endtry" "assert(" "assert0(" "assert1(" "assert2(" |
"assert3(" ")" "<interpretation" "<compilation" "interpretation>" |
"assert3(" ")" "<interpretation" "<compilation" "interpretation>" |
Line 332 INDENT1 and INDENT2 are indentation spec
|
Line 416 INDENT1 and INDENT2 are indentation spec
|
(0 . 2) (0 . 2) non-immediate) |
(0 . 2) (0 . 2) non-immediate) |
("\\S-+%$" (0 . 2) (0 . 0) non-immediate) |
("\\S-+%$" (0 . 2) (0 . 0) non-immediate) |
((";" ";m") (-2 . 0) (0 . -2)) |
((";" ";m") (-2 . 0) (0 . -2)) |
(("again" "repeat" "then" "endtry" "endcase" "endof" |
(("again" "repeat" "then" "endif" "endtry" "endcase" "endof" |
"[then]" "[endif]" "[loop]" "[+loop]" "[next]" |
"[then]" "[endif]" "[loop]" "[+loop]" "[next]" |
"[until]" "[repeat]" "[again]" "loop") |
"[until]" "[repeat]" "[again]" "loop") |
(-2 . 0) (0 . -2)) |
(-2 . 0) (0 . -2)) |
Line 388 End:\" construct).")
|
Line 472 End:\" construct).")
|
;; Helper function for `forth-compile-word': translate one entry from |
;; Helper function for `forth-compile-word': translate one entry from |
;; `forth-words' into the form (regexp regexp-depth word-description) |
;; `forth-words' into the form (regexp regexp-depth word-description) |
(defun forth-compile-words-mapper (word) |
(defun forth-compile-words-mapper (word) |
|
;; warning: we cannot rely on regexp-opt's PAREN argument, since |
|
;; XEmacs will use shy parens by default :-( |
(let* ((matcher (car word)) |
(let* ((matcher (car word)) |
(regexp (if (stringp matcher) (concat "\\(" matcher "\\)") |
(regexp |
(if (listp matcher) (regexp-opt matcher t) |
(concat "\\(" (cond ((stringp matcher) matcher) |
(error "Invalid matcher (stringp or listp expected `%s'" |
((listp matcher) (regexp-opt matcher)) |
matcher)))) |
(t (error "Invalid matcher `%s'"))) |
|
"\\)")) |
(depth (regexp-opt-depth regexp)) |
(depth (regexp-opt-depth regexp)) |
(description (cdr word))) |
(description (cdr word))) |
(list regexp depth description))) |
(list regexp depth description))) |
Line 498 End:\" construct).")
|
Line 585 End:\" construct).")
|
;; expression that matched. (used for identifying branches "a\\|b\\|c...") |
;; expression that matched. (used for identifying branches "a\\|b\\|c...") |
(defun forth-get-regexp-branch () |
(defun forth-get-regexp-branch () |
(let ((count 2)) |
(let ((count 2)) |
(while (not (match-beginning count)) |
(while (not (condition-case err (match-beginning count) |
|
(args-out-of-range t))) ; XEmacs requires error handling |
(setq count (1+ count))) |
(setq count (1+ count))) |
count)) |
count)) |
|
|
Line 671 Used for imenu index generation.")
|
Line 759 Used for imenu index generation.")
|
index)) |
index)) |
|
|
;; top-level require is executed at byte-compile and load time |
;; top-level require is executed at byte-compile and load time |
(require 'speedbar nil t) |
(eval-and-compile (forth-require 'speedbar)) |
|
|
;; this code is executed at load-time only |
;; this code is executed at load-time only |
(when (require 'speedbar nil t) |
(when (memq 'speedbar features) |
(speedbar-add-supported-extension ".fs") |
(speedbar-add-supported-extension ".fs") |
(speedbar-add-supported-extension ".fb")) |
(speedbar-add-supported-extension ".fb")) |
|
|
Line 820 Used for imenu index generation.")
|
Line 908 Used for imenu index generation.")
|
(forth-newline-remove-trailing) |
(forth-newline-remove-trailing) |
(indent-according-to-mode)) |
(indent-according-to-mode)) |
|
|
;;; end hilighting/indentation |
|
|
|
;;; Block file encoding/decoding (dk) |
;;; Block file encoding/decoding (dk) |
;;; |
;;; |
Line 979 exceeds 64 characters."
|
Line 1066 exceeds 64 characters."
|
|
|
(add-hook 'forth-motion-hooks 'forth-update-warn-long-lines) |
(add-hook 'forth-motion-hooks 'forth-update-warn-long-lines) |
|
|
(defvar forth-was-point nil) |
|
(defun forth-check-motion () |
|
"Run `forth-motion-hooks', if `point' changed since last call." |
|
(when (or (eq forth-was-point nil) (/= forth-was-point (point))) |
|
(setq forth-was-point (point)) |
|
(run-hooks 'forth-motion-hooks))) |
|
|
|
;;; End block file editing |
;;; End block file editing |
|
|
|
|
Line 1012 exceeds 64 characters."
|
Line 1092 exceeds 64 characters."
|
(define-key forth-mode-map "\M-q" 'forth-fill-paragraph) |
(define-key forth-mode-map "\M-q" 'forth-fill-paragraph) |
(define-key forth-mode-map "\e." 'forth-find-tag) |
(define-key forth-mode-map "\e." 'forth-find-tag) |
|
|
;setup for C-h C-i to work |
;; setup for C-h C-i to work |
(require 'info-look nil t) |
(eval-and-compile (forth-require 'info-look)) |
(when (require 'info-look nil t) |
(when (memq 'info-look features) |
(info-lookup-add-help |
(defvar forth-info-lookup '(symbol (forth-mode "\\S-+" t |
:topic 'symbol |
(("(gforth)Word Index")) |
:mode 'forth-mode |
"\\S-+"))) |
:regexp "[^ |
(unless (memq forth-info-lookup info-lookup-alist) |
]+" |
(setq info-lookup-alist (cons forth-info-lookup info-lookup-alist))) |
:ignore-case t |
;; in X-Emacs C-h C-i is by default bound to Info-query |
:doc-spec '(("(gforth)Name Index" nil "`" "' ")))) |
(define-key forth-mode-map "\C-h\C-i" 'info-lookup-symbol)) |
|
|
|
|
|
;; (info-lookup-add-help |
|
;; :topic 'symbol |
|
;; :mode 'forth-mode |
|
;; :regexp "[^ |
|
;; ]+" |
|
;; :ignore-case t |
|
;; :doc-spec '(("(gforth)Name Index" nil "`" "' ")))) |
|
|
(require 'etags) |
(require 'etags) |
|
|
Line 1052 exceeds 64 characters."
|
Line 1141 exceeds 64 characters."
|
(setq char (1+ char)))) |
(setq char (1+ char)))) |
)) |
)) |
|
|
|
|
(defun forth-mode-variables () |
(defun forth-mode-variables () |
(set-syntax-table forth-mode-syntax-table) |
(set-syntax-table forth-mode-syntax-table) |
(setq local-abbrev-table forth-mode-abbrev-table) |
(setq local-abbrev-table forth-mode-abbrev-table) |
Line 1084 exceeds 64 characters."
|
Line 1172 exceeds 64 characters."
|
(make-local-variable 'forth-compiled-indent-words) |
(make-local-variable 'forth-compiled-indent-words) |
(make-local-variable 'forth-hilight-level) |
(make-local-variable 'forth-hilight-level) |
(make-local-variable 'after-change-functions) |
(make-local-variable 'after-change-functions) |
(make-local-variable 'post-command-hook) |
|
(make-local-variable 'forth-show-screen) |
(make-local-variable 'forth-show-screen) |
(make-local-variable 'forth-screen-marker) |
(make-local-variable 'forth-screen-marker) |
(make-local-variable 'forth-warn-long-lines) |
(make-local-variable 'forth-warn-long-lines) |
Line 1093 exceeds 64 characters."
|
Line 1180 exceeds 64 characters."
|
(make-local-variable 'forth-use-objects) |
(make-local-variable 'forth-use-objects) |
(setq forth-screen-marker (copy-marker 0)) |
(setq forth-screen-marker (copy-marker 0)) |
(add-hook 'after-change-functions 'forth-change-function) |
(add-hook 'after-change-functions 'forth-change-function) |
(add-hook 'post-command-hook 'forth-check-motion) |
(if (and forth-jit-parser (>= emacs-major-version 21)) |
(if (>= emacs-major-version 21) |
|
(add-hook 'fontification-functions 'forth-fontification-function)) |
(add-hook 'fontification-functions 'forth-fontification-function)) |
(setq imenu-create-index-function 'forth-create-index)) |
(setq imenu-create-index-function 'forth-create-index)) |
|
|
Line 1209 Variables controling documentation searc
|
Line 1295 Variables controling documentation searc
|
(use-local-map forth-mode-map) |
(use-local-map forth-mode-map) |
(setq mode-name "Forth") |
(setq mode-name "Forth") |
(setq major-mode 'forth-mode) |
(setq major-mode 'forth-mode) |
|
(forth-install-motion-hook) |
;; convert buffer contents from block file format, if necessary |
;; convert buffer contents from block file format, if necessary |
(when (forth-detect-block-file-p) |
(when (forth-detect-block-file-p) |
(widen) |
(widen) |
Line 1799 The region is sent terminated by a newli
|
Line 1886 The region is sent terminated by a newli
|
;;; Forth menu |
;;; Forth menu |
;;; Mikael Karlsson <qramika@eras70.ericsson.se> |
;;; Mikael Karlsson <qramika@eras70.ericsson.se> |
|
|
(cond ((string-match "XEmacs\\|Lucid" emacs-version) |
;; (dk) code commented out due to complaints of XEmacs users. After |
(require 'func-menu) |
;; all, there's imenu/speedbar, which uses much smarter scanning |
|
;; rules. |
|
|
|
;; (cond ((string-match "XEmacs\\|Lucid" emacs-version) |
|
;; (require 'func-menu) |
|
|
|
;; (defconst fume-function-name-regexp-forth |
|
;; "^\\(:\\)[ \t]+\\([^ \t]*\\)" |
|
;; "Expression to get word definitions in Forth.") |
|
|
|
;; (setq fume-function-name-regexp-alist |
|
;; (append '((forth-mode . fume-function-name-regexp-forth) |
|
;; ) fume-function-name-regexp-alist)) |
|
|
|
;; ;; Find next forth word in the buffer |
|
;; (defun fume-find-next-forth-function-name (buffer) |
|
;; "Searches for the next forth word in BUFFER." |
|
;; (set-buffer buffer) |
|
;; (if (re-search-forward fume-function-name-regexp nil t) |
|
;; (let ((beg (match-beginning 2)) |
|
;; (end (match-end 2))) |
|
;; (cons (buffer-substring beg end) beg)))) |
|
|
(defconst fume-function-name-regexp-forth |
;; (setq fume-find-function-name-method-alist |
"^\\(:\\)[ \t]+\\([^ \t]*\\)" |
;; (append '((forth-mode . fume-find-next-forth-function-name)))) |
"Expression to get word definitions in Forth.") |
|
|
|
(setq fume-function-name-regexp-alist |
|
(append '((forth-mode . fume-function-name-regexp-forth) |
|
) fume-function-name-regexp-alist)) |
|
|
|
;; Find next forth word in the buffer |
|
(defun fume-find-next-forth-function-name (buffer) |
|
"Searches for the next forth word in BUFFER." |
|
(set-buffer buffer) |
|
(if (re-search-forward fume-function-name-regexp nil t) |
|
(let ((beg (match-beginning 2)) |
|
(end (match-end 2))) |
|
(cons (buffer-substring beg end) beg)))) |
|
|
|
(setq fume-find-function-name-method-alist |
;; )) |
(append '((forth-mode . fume-find-next-forth-function-name)))) |
|
|
|
)) |
|
;;; End Forth menu |
;;; End Forth menu |
|
|
;;; File folding of forth-files |
;;; File folding of forth-files |
Line 1833 The region is sent terminated by a newli
|
Line 1924 The region is sent terminated by a newli
|
;;; Works most of the times but loses sync with the cursor occasionally |
;;; Works most of the times but loses sync with the cursor occasionally |
;;; Could be improved by also folding on comments |
;;; Could be improved by also folding on comments |
|
|
(require 'outline) |
;; (dk) This code needs a rewrite; just too ugly and doesn't use the |
|
;; newer and smarter scanning rules of `imenu'. Who needs it anyway?? |
|
|
|
;; (require 'outline) |
|
|
(defun f-outline-level () |
;; (defun f-outline-level () |
(cond ((looking-at "\\`\\\\") |
;; (cond ((looking-at "\\`\\\\") |
0) |
;; 0) |
((looking-at "\\\\ SEC") |
;; ((looking-at "\\\\ SEC") |
0) |
;; 0) |
((looking-at "\\\\ \\\\ .*") |
;; ((looking-at "\\\\ \\\\ .*") |
0) |
;; 0) |
((looking-at "\\\\ DEFS") |
;; ((looking-at "\\\\ DEFS") |
1) |
;; 1) |
((looking-at "\\/\\* ") |
;; ((looking-at "\\/\\* ") |
1) |
;; 1) |
((looking-at ": .*") |
;; ((looking-at ": .*") |
1) |
;; 1) |
((looking-at "\\\\G") |
;; ((looking-at "\\\\G") |
2) |
;; 2) |
((looking-at "[ \t]+\\\\") |
;; ((looking-at "[ \t]+\\\\") |
3))) |
;; 3))) |
|
|
(defun fold-f () |
;; (defun fold-f () |
(interactive) |
;; (interactive) |
(add-hook 'outline-minor-mode-hook 'hide-body) |
;; (add-hook 'outline-minor-mode-hook 'hide-body) |
|
|
; outline mode header start, i.e. find word definitions |
;; ; outline mode header start, i.e. find word definitions |
;;; (setq outline-regexp "^\\(:\\)[ \t]+\\([^ \t]*\\)") |
;; ;;; (setq outline-regexp "^\\(:\\)[ \t]+\\([^ \t]*\\)") |
(setq outline-regexp "\\`\\\\\\|:\\|\\\\ SEC\\|\\\\G\\|[ \t]+\\\\\\|\\\\ DEFS\\|\\/\\*\\|\\\\ \\\\ .*") |
;; (setq outline-regexp "\\`\\\\\\|:\\|\\\\ SEC\\|\\\\G\\|[ \t]+\\\\\\|\\\\ DEFS\\|\\/\\*\\|\\\\ \\\\ .*") |
(setq outline-level 'f-outline-level) |
;; (setq outline-level 'f-outline-level) |
|
|
(outline-minor-mode) |
;; (outline-minor-mode) |
(define-key outline-minor-mode-map '(shift up) 'hide-sublevels) |
;; (define-key outline-minor-mode-map '(shift up) 'hide-sublevels) |
(define-key outline-minor-mode-map '(shift right) 'show-children) |
;; (define-key outline-minor-mode-map '(shift right) 'show-children) |
(define-key outline-minor-mode-map '(shift left) 'hide-subtree) |
;; (define-key outline-minor-mode-map '(shift left) 'hide-subtree) |
(define-key outline-minor-mode-map '(shift down) 'show-subtree)) |
;; (define-key outline-minor-mode-map '(shift down) 'show-subtree)) |
|
|
|
|
;;(define-key global-map '(shift up) 'fold-f) |
;;(define-key global-map '(shift up) 'fold-f) |
|
|
Line 1878 The region is sent terminated by a newli
|
Line 1973 The region is sent terminated by a newli
|
;;; for all of the recognized languages. Scanning the buffer takes some time, |
;;; for all of the recognized languages. Scanning the buffer takes some time, |
;;; but not much. |
;;; but not much. |
;;; |
;;; |
(cond ((string-match "XEmacs\\|Lucid" emacs-version) |
;; (cond ((string-match "XEmacs\\|Lucid" emacs-version) |
(require 'func-menu) |
;; (require 'func-menu) |
;; (define-key global-map 'f8 'function-menu) |
;; ;; (define-key global-map 'f8 'function-menu) |
(add-hook 'find-fible-hooks 'fume-add-menubar-entry) |
;; (add-hook 'find-fible-hooks 'fume-add-menubar-entry) |
; (define-key global-map "\C-cg" 'fume-prompt-function-goto) |
;; ; (define-key global-map "\C-cg" 'fume-prompt-function-goto) |
; (define-key global-map '(shift button3) 'mouse-function-menu) |
;; ; (define-key global-map '(shift button3) 'mouse-function-menu) |
)) |
;; )) |
|
|
(provide 'forth-mode) |
(provide 'forth-mode) |
|
|