*** dcl-mode-19960212.el Sun Feb 25 18:44:14 1996 --- dcl-mode-19960412.el Sun Apr 14 15:39:24 1996 *************** *** 2,14 **** ;; Author: Odd Gripenstam ;; Maintainer: Odd Gripenstam ! ;; Last modified: 96-02-12 ;; Keywords: DCL editing major-mode languages ;;; Commentary: ;; dcl-mode is a package for editing DCL-command files. It helps you ! ;; indent lines, add leading '$' and trailing '-', move around in the ;; code and insert lexical functions. ;; ;; To use it, make sure dcl-mode.el is in a directory on your --- 2,14 ---- ;; Author: Odd Gripenstam ;; Maintainer: Odd Gripenstam ! ;; Last modified: 96-04-12 ;; Keywords: DCL editing major-mode languages ;;; Commentary: ;; dcl-mode is a package for editing DCL-command files. It helps you ! ;; indent lines, add leading `$' and trailing `-', move around in the ;; code and insert lexical functions. ;; ;; To use it, make sure dcl-mode.el is in a directory on your *************** *** 17,28 **** ;; (autoload 'dcl-mode "dcl-mode" "" t) ;; (setq auto-mode-alist (cons '("\\.com$" . dcl-mode) auto-mode-alist)) ;; ! ;; Type 'C-h m' when you are editing a .COM file to get more ;; information about this mode. ;; ;; If you are installing dcl-mode for everyone to use, you may want ! ;; to include dcl-mode in the 'C-h p' listing by evaluating ! ;; '(finder-compile-keywords)'. This will create finder-inf.el, which ;; should be saved in the Emacs Lisp directory. ;; ;; To use templates you will need a version of tempo.el that is at --- 17,28 ---- ;; (autoload 'dcl-mode "dcl-mode" "" t) ;; (setq auto-mode-alist (cons '("\\.com$" . dcl-mode) auto-mode-alist)) ;; ! ;; Type `C-h m' when you are editing a .COM file to get more ;; information about this mode. ;; ;; If you are installing dcl-mode for everyone to use, you may want ! ;; to include dcl-mode in the `C-h p' listing by evaluating ! ;; `(finder-compile-keywords)'. This will create finder-inf.el, which ;; should be saved in the Emacs Lisp directory. ;; ;; To use templates you will need a version of tempo.el that is at *************** *** 33,38 **** --- 33,43 ---- ;; I recommend setting (setq tempo-interactive t). This will make ;; tempo prompt you for values to put in the blank spots in the templates. ;; + ;; There is limited support for imenu. The limitation is that you need + ;; a version of imenu.el that uses imenu-generic-expression. I found + ;; the version I use in Emacs 19.30. (It was *so* much easier to hook + ;; into that version than the one in 19.27...) + ;; ;; This is my first try at Emacs Lisp programming, and I am also a recent ;; convert from DEC TPU, so there are probably some bugs and bad style ;; in this code. *************** *** 67,73 **** ;; * A delete-indentation function (M-^) that joins continued lines, ;; including lines with end line comments? ;; * Handle DECK/EOD. ! ;; * 'indent list' commands: C-M-q, C-u TAB. What is a list in DCL? One ;; complete command line? A block? A subroutine? ;;; Change Log: --- 72,78 ---- ;; * A delete-indentation function (M-^) that joins continued lines, ;; including lines with end line comments? ;; * Handle DECK/EOD. ! ;; * `indent list' commands: C-M-q, C-u TAB. What is a list in DCL? One ;; complete command line? A block? A subroutine? ;;; Change Log: *************** *** 82,89 **** ;; dcl-calc-cont-indent-relative. Changed default for ;; indentation of continuation lines to use ...indent-relative. ;; Odd Gripenstam 19960128 ! ;; * Added keyword 'languages', which is one of the known keywords in ! ;; 19.27, and the ';;; Change Log:' comment section to make ;; this package work with C-h p. ;; Added dcl-split-line as definition for M-LFD. ;; Added dcl-back-to-indentation as definition for M-m. --- 87,94 ---- ;; dcl-calc-cont-indent-relative. Changed default for ;; indentation of continuation lines to use ...indent-relative. ;; Odd Gripenstam 19960128 ! ;; * Added keyword `languages', which is one of the known keywords in ! ;; 19.27, and the `;;; Change Log:' comment section to make ;; this package work with C-h p. ;; Added dcl-split-line as definition for M-LFD. ;; Added dcl-back-to-indentation as definition for M-m. *************** *** 98,111 **** ;; Added dcl-indent-command as C-M-q. ;; dcl-electric-character now uses ;; dcl-electric-reindent-regexps to decide when to reindent. ! ;; Changed definition of 'first word' in ...indent-relative. ;; Odd Gripenstam 19960212 ;; ;;; Code: ! (defvar dcl-mode-hook nil ! "*Hook called by `dcl-mode'") (defvar dcl-calc-command-indent-function nil "*Function to calculate indentation for a command line. --- 103,169 ---- ;; Added dcl-indent-command as C-M-q. ;; dcl-electric-character now uses ;; dcl-electric-reindent-regexps to decide when to reindent. ! ;; Changed definition of `first word' in ...indent-relative. ;; Odd Gripenstam 19960212 + ;; * Added dcl-set-option with support routines. Added new + ;; movement routines. dcl-end-of-statement now works as documented. + ;; Tidied up the source code. Changed M-a and M-e to be + ;; dcl-forward-command and dcl-backward-command, resp. + ;; Made dcl-back-to-indentation a bit more clever. + ;; Added save-option functions. Made comment-multi-line local. + ;; Added support for imenu. + ;; Odd Gripenstam 19960412 ;; ;;; Code: ! ;;; *** Customization ***************************************************** ! ! ! (defvar dcl-basic-offset 4 ! "*Number of columns to indent a block. ! A block is the commands between THEN-ELSE-ENDIF and between the commands ! dcl-block-begin-regexp and dcl-block-end-regexp. ! ! The meaning of this variable may be changed if ! dcl-calc-command-indent-function is set to a function.") ! ! ! (defvar dcl-continuation-offset 6 ! "*Number of columns to indent a continuation line. ! A continuation line is a line that follows a line ending with `-'. ! ! The meaning of this variable may be changed if ! dcl-calc-cont-indent-function is set to a function.") ! ! ! (defvar dcl-margin-offset 8 ! "*Indentation for the first command line. ! The first command line in a file or after a SUBROUTINE statement is indented ! this much. Other command lines are indented the same number of columns as ! the preceding command line. ! A command line is a line that starts with `$'.") ! ! ! (defvar dcl-margin-label-offset 2 ! "*Number of columns to indent a label that doesn't begin or end a block ! (i.e. doesn't match dcl-block-begin-regexp or dcl-block-end-regexp).") ! ! ! (defvar dcl-comment-line-regexp "^\\$!" ! "*Regexp describing the start of a comment line. ! Comment lines are not indented.") ! ! ! (defvar dcl-block-begin-regexp "loop[0-9]*:" ! "*Regexp describing a command that begins an indented block. ! Set to nil to only indent at THEN-ELSE-ENDIF.") ! ! ! (defvar dcl-block-end-regexp "endloop[0-9]*:" ! "*Regexp describing a command that ends an indented block. ! Set to nil to only indent at THEN-ELSE-ENDIF.") ! (defvar dcl-calc-command-indent-function nil "*Function to calculate indentation for a command line. *************** *** 137,142 **** --- 195,201 ---- dcl-calc-command-indent-hang ") + (defvar dcl-calc-cont-indent-function 'dcl-calc-cont-indent-relative "*Function to calculate indentation for a continuation line. If this variable is non-nil it is called as a function: *************** *** 153,196 **** dcl-calc-cont-indent-relative ") - (defvar dcl-comment-line-regexp "^\\$!" - "*Regexp describing the start of a comment line. - Comment lines are not indented.") - - (defvar dcl-block-begin-regexp "loop[0-9]*:" - "*Regexp describing a command that begins an indented block. - Set to nil to only indent at THEN-ELSE-ENDIF.") - - (defvar dcl-block-end-regexp "endloop[0-9]*:" - "*Regexp describing a command that ends an indented block. - Set to nil to only indent at THEN-ELSE-ENDIF.") - - (defvar dcl-basic-offset 4 - "*Number of columns to indent a block. - A block is the commands between THEN-ELSE-ENDIF and between the commands - dcl-block-begin-regexp and dcl-block-end-regexp. - - The meaning of this variable may be changed if - dcl-calc-command-indent-function is set to a function.") - - (defvar dcl-continuation-offset 6 - "*Number of columns to indent a continuation line. - A continuation line is a line that follows a line ending with `-'. - - The meaning of this variable may be changed if - dcl-calc-cont-indent-function is set to a function.") - - (defvar dcl-margin-label-offset 2 - "*Number of columns to indent a label that doesn't begin or end a block - (i.e. doesn't match dcl-block-begin-regexp or dcl-block-end-regexp).") - - (defvar dcl-margin-offset 8 - "*Indentation for the first command line. - The first command line in a file or after a SUBROUTINE statement is indented - this much. Other command lines are indented the same number of columns as - the preceding command line. - A command line is a line that starts with `$'. - ") (defvar dcl-tab-always-indent t "*Controls the operation of the TAB key. --- 212,217 ---- *************** *** 199,215 **** --- 220,276 ---- Data lines (i.e. lines not part of a command line or continuation line) are never indented.") + (defvar dcl-electric-characters t "*Non-nil causes lines to be re-indented at once when a label, ELSE or ENDIF is typed.") + (defvar dcl-tempo-comma ", " "*Text to insert when a comma is needed in a template") + + (defvar dcl-tempo-left-paren "(" "*Text to insert when a left parenthesis is needed in a template") + + (defvar dcl-tempo-right-paren ")" "*Text to insert when a right parenthesis is needed in a template") + ; I couldn't decide what looked best, so I'll let you decide... + ; Remember, you can also customize this with imenu-submenu-name-format. + (defvar dcl-imenu-label-labels "Labels" + "*Imenu menu title for sub-listing with label names") + (defvar dcl-imenu-label-goto "GOTO" + "*Imenu menu title for sub-listing with GOTO statements") + (defvar dcl-imenu-label-gosub "GOSUB" + "*Imenu menu title for sub-listing with GOSUB statements") + (defvar dcl-imenu-label-call "CALL" + "*Imenu menu title for sub-listing with CALL statements") + + (defvar dcl-imenu-generic-expression + (` + ((nil "^\\$[ \t]*\\([A-Za-z0-9_\$]+\\):[ \t]+SUBROUTINE\\b" 1) + ((, dcl-imenu-label-labels) + "^\\$[ \t]*\\([A-Za-z0-9_\$]+\\):\\([ \t]\\|$\\)" 1) + ((, dcl-imenu-label-goto) "\\s-GOTO[ \t]+\\([A-Za-z0-9_\$]+\\)" 1) + ((, dcl-imenu-label-gosub) "\\s-GOSUB[ \t]+\\([A-Za-z0-9_\$]+\\)" 1) + ((, dcl-imenu-label-call) "\\s-CALL[ \t]+\\([A-Za-z0-9_\$]+\\)" 1))) + "*Default imenu generic expression for DCL. + + The default includes SUBROUTINE labels in the main listing and + sub-listings for other labels, CALL, GOTO and GOSUB statements. + See `imenu-generic-expression' in a recent (e.g. Emacs 19.30) imenu.el + for details.") + + + (defvar dcl-mode-hook nil + "*Hook called by `dcl-mode'") + + + ;;; *** Global variables **************************************************** + + (defvar dcl-mode-syntax-table nil "Syntax table used in DCL-buffers.") (if dcl-mode-syntax-table *************** *** 221,226 **** --- 282,288 ---- (modify-syntax-entry ?> ")<" dcl-mode-syntax-table) ; > is a matching pair ) + (defvar dcl-mode-map () "Keymap used in DCL-mode buffers.") (if dcl-mode-map *************** *** 230,237 **** (define-key dcl-mode-map "\e\t" 'tempo-complete-tag) (define-key dcl-mode-map "\e^" 'dcl-delete-indentation) (define-key dcl-mode-map "\em" 'dcl-back-to-indentation) ! (define-key dcl-mode-map "\ee" 'dcl-end-of-statement) ! (define-key dcl-mode-map "\ea" 'dcl-beginning-of-statement) (define-key dcl-mode-map "\e\C-q" 'dcl-indent-command) (define-key dcl-mode-map "\t" 'dcl-tab) (define-key dcl-mode-map ":" 'dcl-electric-character) --- 292,299 ---- (define-key dcl-mode-map "\e\t" 'tempo-complete-tag) (define-key dcl-mode-map "\e^" 'dcl-delete-indentation) (define-key dcl-mode-map "\em" 'dcl-back-to-indentation) ! (define-key dcl-mode-map "\ee" 'dcl-forward-command) ! (define-key dcl-mode-map "\ea" 'dcl-backward-command) (define-key dcl-mode-map "\e\C-q" 'dcl-indent-command) (define-key dcl-mode-map "\t" 'dcl-tab) (define-key dcl-mode-map ":" 'dcl-electric-character) *************** *** 239,244 **** --- 301,307 ---- (define-key dcl-mode-map "f" 'dcl-electric-character) (define-key dcl-mode-map "E" 'dcl-electric-character) (define-key dcl-mode-map "e" 'dcl-electric-character) + (define-key dcl-mode-map "\C-c\C-o" 'dcl-set-option) (define-key dcl-mode-map "\C-c\C-f" 'tempo-forward-mark) (define-key dcl-mode-map "\C-c\C-b" 'tempo-backward-mark) *************** *** 255,260 **** --- 318,331 ---- '("Complete template tag" . tempo-complete-tag)) (define-key dcl-mode-map [menu-bar dcl dcl-separator-tempo] '("--")) + (define-key dcl-mode-map [menu-bar dcl dcl-save-all-options] + '("Save all options" . dcl-save-all-options)) + (define-key dcl-mode-map [menu-bar dcl dcl-save-nondefault-options] + '("Save changed options" . dcl-save-nondefault-options)) + (define-key dcl-mode-map [menu-bar dcl dcl-set-option] + '("Set option" . dcl-set-option)) + (define-key dcl-mode-map [menu-bar dcl dcl-separator-option] + '("--")) (define-key dcl-mode-map [menu-bar dcl dcl-delete-indentation] '("Delete indentation" . dcl-delete-indentation)) (define-key dcl-mode-map [menu-bar dcl dcl-split-line] *************** *** 265,288 **** '("Indent line/insert tab" . dcl-tab)) (define-key dcl-mode-map [menu-bar dcl dcl-back-to-indentation] '("Back to indentation" . dcl-back-to-indentation)) ! (define-key dcl-mode-map [menu-bar dcl dcl-end-of-statement] ! '("End of statement" . dcl-end-of-statement)) ! (define-key dcl-mode-map [menu-bar dcl dcl-beginning-of-statement] ! '("Beginning of statement" . dcl-beginning-of-statement)) ) (defvar dcl-ws-r "\\([ \t]*-[ \t]*\\(!.*\\)*\n\\)*[ \t]*" "Regular expression describing white space in a DCL command line. White space is any number of continued lines with only space,tab,endcomment followed by space or tab.") (defvar dcl-label-r ! "[a-zA-Z0-9_]*:\\([ \t!]\\|$\\)" "Regular expression describing a label. A label is a name followed by a colon followed by white-space or end-of-line.") ! ;;;--------------------------------------------------------------------------- (defvar dcl-command-regexp "^\\$\\(.*-[ \t]*\\(!.*\\)*\n\\)*.*\\(\".*\\(\"\".*\\)*\"\\)*" "Regular expression describing a DCL command line --- 336,377 ---- '("Indent line/insert tab" . dcl-tab)) (define-key dcl-mode-map [menu-bar dcl dcl-back-to-indentation] '("Back to indentation" . dcl-back-to-indentation)) ! (define-key dcl-mode-map [menu-bar dcl dcl-forward-command] ! '("End of statement" . dcl-forward-command)) ! (define-key dcl-mode-map [menu-bar dcl dcl-backward-command] ! '("Beginning of statement" . dcl-backward-command)) ! ;; imenu is only supported for versions with imenu-generic-expression ! (if (boundp 'imenu-generic-expression) ! (progn ! (define-key dcl-mode-map [menu-bar dcl dcl-separator-movement] ! '("--")) ! (define-key dcl-mode-map [menu-bar dcl imenu] ! '("Buffer index menu" . imenu)))) ) + (defvar dcl-ws-r "\\([ \t]*-[ \t]*\\(!.*\\)*\n\\)*[ \t]*" "Regular expression describing white space in a DCL command line. White space is any number of continued lines with only space,tab,endcomment followed by space or tab.") + (defvar dcl-label-r ! "[a-zA-Z0-9_\$]*:\\([ \t!]\\|$\\)" "Regular expression describing a label. A label is a name followed by a colon followed by white-space or end-of-line.") ! ! (defvar dcl-cmd-r ! "^\\$\\(.*-[ \t]*\\(!.*\\)*\n\\)*[^!\"\n]*\\(\".*\\(\"\".*\\)*\"\\)*[^!\"\n]*" ! "Regular expression describing a DCL command line up to a trailing comment. ! A line starting with $, optionally followed by continuation lines, ! followed by the end of the command line. ! A continuation line is any characters followed by `-', ! optionally followed by a comment, followed by a newline.") ! ! (defvar dcl-command-regexp "^\\$\\(.*-[ \t]*\\(!.*\\)*\n\\)*.*\\(\".*\\(\"\".*\\)*\"\\)*" "Regular expression describing a DCL command line *************** *** 291,307 **** A continuation line is any characters followed by `-', optionally followed by a comment, followed by a newline.") ! ;;;--------------------------------------------------------------------------- (defvar dcl-electric-reindent-regexps (list "endif" "else" dcl-label-r) "*A list of regexps that will trigger a reindent if the last letter is defined as dcl-electric-character. ! E.g.: if this list contains 'endif', the key 'f' is defined as ! dcl-electric-character and the you have just typed the 'f' in ! 'endif', the line will be reindented.") - ;;;--------------------------------------------------------------------------- (defun dcl-mode () "Major mode for editing DCL-files. --- 380,451 ---- A continuation line is any characters followed by `-', optionally followed by a comment, followed by a newline.") ! (defvar dcl-electric-reindent-regexps (list "endif" "else" dcl-label-r) "*A list of regexps that will trigger a reindent if the last letter is defined as dcl-electric-character. ! E.g.: if this list contains `endif', the key `f' is defined as ! dcl-electric-character and the you have just typed the `f' in ! `endif', the line will be reindented.") ! ! ! (defvar dcl-option-alist ! '((dcl-basic-offset dcl-option-value-basic) ! (dcl-continuation-offset curval) ! (dcl-margin-offset dcl-option-value-margin-offset) ! (dcl-margin-label-offset dcl-option-value-offset) ! (dcl-comment-line-regexp dcl-option-value-comment-line) ! (dcl-block-begin-regexp curval) ! (dcl-block-end-regexp curval) ! (dcl-tab-always-indent toggle) ! (dcl-electric-characters toggle) ! (dcl-electric-reindent-regexps curval) ! (dcl-tempo-comma curval) ! (dcl-tempo-left-paren curval) ! (dcl-tempo-right-paren curval) ! (dcl-calc-command-indent-function curval) ! (dcl-calc-cont-indent-function curval) ! (comment-start curval) ! (comment-start-skip curval) ! ) ! "An alist with option variables and functions or keywords to get a ! default value for the option. The keywords are: ! curval the current value ! toggle the opposite of the current value (for t/nil)") ! ! ! (defvar dcl-option-history ! (mapcar (lambda (option-assoc) ! (format "%s" (car option-assoc))) ! dcl-option-alist) ! "The history list for dcl-set-option. Preloaded with all known ! option names from dcl-option-alist") ! ! ! ;; Must be defined after dcl-cmd-r ! ;; This version is more correct but much slower than the one ! ;; above. This version wont find GOTOs in comments or text strings. ! ;(defvar dcl-imenu-generic-expression ! ; (` ! ; ((nil "^\\$[ \t]*\\([A-Za-z0-9_\$]+\\):[ \t]+SUBROUTINE\\b" 1) ! ; ("Labels" "^\\$[ \t]*\\([A-Za-z0-9_\$]+\\):\\([ \t]\\|$\\)" 1) ! ; ("GOTO" (, (concat dcl-cmd-r "GOTO[ \t]+\\([A-Za-z0-9_\$]+\\)")) 5) ! ; ("GOSUB" (, (concat dcl-cmd-r ! ; "GOSUB[ \t]+\\([A-Za-z0-9_\$]+\\)")) 5) ! ; ("CALL" (, (concat dcl-cmd-r "CALL[ \t]+\\([A-Za-z0-9_\$]+\\)")) 5))) ! ; "*Default imenu generic expression for DCL. ! ! ;The default includes SUBROUTINE labels in the main listing and ! ;sub-listings for other labels, CALL, GOTO and GOSUB statements. ! ;See `imenu-generic-expression' in a recent (e.g. Emacs 19.30) imenu.el ! ;for details.") ! ! ! ;;; *** Mode initialization ************************************************* ! (defun dcl-mode () "Major mode for editing DCL-files. *************** *** 315,320 **** --- 459,471 ---- Key bindings: \\{dcl-mode-map} + Commands not usually bound to keys: + + \\[dcl-save-nondefault-options]\t\tSave changed options + \\[dcl-save-all-options]\t\tSave all options + \\[dcl-save-option]\t\t\tSave any option + \\[dcl-save-mode]\t\t\tSave buffer mode + Variables controlling indentation style and extra features: dcl-basic-offset *************** *** 369,374 **** --- 520,536 ---- dcl-tempo-right-paren These variables control the look of expanded templates. + dcl-imenu-generic-expression + Default value for imenu-generic-expression. The default includes + SUBROUTINE labels in the main listing and sub-listings for + other labels, CALL, GOTO and GOSUB statements. + + dcl-imenu-label-labels + dcl-imenu-label-goto + dcl-imenu-label-gosub + dcl-imenu-label-call + Change the text that is used as sub-listing labels in imenu. + Loading this package calls the value of the variable `dcl-mode-load-hook' with no args, if that value is non-nil. Turning on DCL mode calls the value of the variable `dcl-mode-hook' *************** *** 411,416 **** --- 573,581 ---- (make-local-variable 'comment-end) (setq comment-end "") + (make-local-variable 'comment-multi-line) + (setq comment-multi-line nil) + ;; This used to be "^\\$[ \t]*![ \t]*" which looks more correct. ;; The drawback was that you couldn't make empty comment lines by pressing ;; C-M-j repeatedly - only the first line became a comment line. *************** *** 421,426 **** --- 586,598 ---- (make-local-variable 'comment-start-skip) (setq comment-start-skip "\\$[ \t]*![ \t]*") + ;; This variable is made buffer-local by the imenu.el version + ;; included in Emacs 19.30 and does not exist in the version + ;; included in Emacs 19.27 + (if (boundp 'imenu-generic-expression) + (setq imenu-generic-expression dcl-imenu-generic-expression)) + (setq imenu-create-index-function 'dcl-imenu-create-index-function) + (make-local-variable 'dcl-comment-line-regexp) (make-local-variable 'dcl-block-begin-regexp) (make-local-variable 'dcl-block-end-regexp) *************** *** 440,458 **** (tempo-use-tag-list 'dcl-tempo-tags) (run-hooks 'dcl-mode-hook)) ! ;;;--------------------------------------------------------------------------- (defun dcl-beginning-of-statement () "Go to the beginning of the preceding or current command line." (interactive) (re-search-backward dcl-command-regexp nil t)) ! ;;;--------------------------------------------------------------------------- (defun dcl-end-of-statement () "Go to the end of the next or current command line." (interactive) (re-search-forward dcl-command-regexp nil t)) ! ;;;--------------------------------------------------------------------------- (defun dcl-get-line-type () "Determine the type of the current line. Returns: --- 612,844 ---- (tempo-use-tag-list 'dcl-tempo-tags) (run-hooks 'dcl-mode-hook)) ! ! ;;; *** Movement commands *************************************************** ! ! ! ;;;------------------------------------------------------------------------- (defun dcl-beginning-of-statement () "Go to the beginning of the preceding or current command line." (interactive) (re-search-backward dcl-command-regexp nil t)) ! ! ;;;------------------------------------------------------------------------- (defun dcl-end-of-statement () "Go to the end of the next or current command line." (interactive) + (if (or (dcl-end-of-command-p) + (dcl-beginning-of-command-p) + (not (dcl-command-p))) + () + (dcl-beginning-of-statement)) (re-search-forward dcl-command-regexp nil t)) ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-beginning-of-command () ! "Move point to beginning of current command." ! (interactive) ! (let ((type (dcl-get-line-type))) ! (if (and (eq type '$) ! (bolp)) ! () ; already in the correct position ! (dcl-beginning-of-statement)))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-end-of-command () ! "Move point to end of current command or next command if not on a command." ! (interactive) ! (let ((type (dcl-get-line-type)) ! (start (point))) ! (if (or (eq type '$) ! (eq type '-)) ! (progn ! (dcl-beginning-of-command) ! (dcl-end-of-statement)) ! (dcl-end-of-statement)))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-backward-command (&optional incl-comment-commands) ! "Move point to the preceding command line that is not a comment line, ! a command line with only a comment, only contains a `$' or only ! contains a label. ! ! Returns point of the found command line or nil if not able to move." ! (interactive) ! (let ((start (point)) ! done ! retval) ! ;; Find first non-empty command line ! (while (not done) ! ;; back up one statement and look at the command ! (if (dcl-beginning-of-statement) ! (cond ! ((and dcl-block-begin-regexp ; might be nil ! (looking-at (concat "^\\$" dcl-ws-r ! dcl-block-begin-regexp))) ! (setq done t retval (point))) ! ((and dcl-block-end-regexp ; might be nil ! (looking-at (concat "^\\$" dcl-ws-r ! dcl-block-end-regexp))) ! (setq done t retval (point))) ! ((looking-at dcl-comment-line-regexp) ! t) ; comment line, one more loop ! ((and (not incl-comment-commands) ! (looking-at "\\$[ \t]*!")) ! t) ; comment only command, loop... ! ((looking-at "^\\$[ \t]*$") ! t) ; empty line, one more loop ! ((not (looking-at ! (concat "^\\$" dcl-ws-r dcl-label-r dcl-ws-r "$"))) ! (setq done t) ; not a label-only line, exit the loop ! (setq retval (point)))) ! ;; We couldn't go further back, and we haven't found a command yet. ! ;; Return to the start positionn ! (goto-char start) ! (setq done t) ! (setq retval nil))) ! retval)) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-forward-command (&optional incl-comment-commands) ! "Move point to the end of the next command line that is not a comment line, ! a command line with only a comment, only contains a `$' or only ! contains a label. ! ! Returns point of the found command line or nil if not able to move." ! (interactive) ! (let ((start (point)) ! done ! retval) ! ;; Find first non-empty command line ! (while (not done) ! ;; go forward one statement and look at the command ! (if (dcl-end-of-statement) ! (save-excursion ! (dcl-beginning-of-statement) ! (cond ! ((and dcl-block-begin-regexp ; might be nil ! (looking-at (concat "^\\$" dcl-ws-r ! dcl-block-begin-regexp))) ! (setq done t) ! (setq retval (point))) ! ((and dcl-block-end-regexp ; might be nil ! (looking-at (concat "^\\$" dcl-ws-r ! dcl-block-end-regexp))) ! (setq done t) ! (setq retval (point))) ! ((looking-at dcl-comment-line-regexp) ! t) ; comment line, one more loop ! ((and (not incl-comment-commands) ! (looking-at "\\$[ \t]*!")) ! t) ; comment only command, loop... ! ((looking-at "^\\$[ \t]*$") ! t) ; empty line, one more loop ! ((not (looking-at ! (concat "^\\$" dcl-ws-r dcl-label-r dcl-ws-r "$"))) ! (setq done t) ; not a label-only line, exit the loop ! (setq retval (point))))) ! ;; We couldn't go further back, and we haven't found a command yet. ! ;; Return to the start positionn ! (goto-char start) ! (setq done t) ! (setq retval nil))) ! retval)) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-back-to-indentation () ! "Move point to the first non-whitespace character on this line. ! Leading $ and labels counts as whitespace in this case. ! If this is a comment line then move to the first non-whitespace character ! in the comment. ! ! Typing \\[dcl-back-to-indentation] several times in a row will move point to other ! `interesting' points closer to the left margin, and then back to the ! rightmost point again. ! ! E.g. on the following line, point would go to the positions indicated ! by the numbers in order 1-2-3-1-... : ! ! \$ label: command ! 3 2 1" ! (interactive) ! (if (eq last-command 'dcl-back-to-indentation) ! (dcl-back-to-indentation-1 (point)) ! (dcl-back-to-indentation-1))) ! (defun dcl-back-to-indentation-1 (&optional limit) ! "Helper function for dcl-back-to-indentation" ! ! ;; "Indentation points" that we will travel to ! ;; $ l: ! comment ! ;; 4 3 2 1 ! ;; ! ;; $ ! text ! ;; 3 2 1 ! ;; ! ;; $ l: command ! ! ;; 3 2 1 ! ;; ! ;; text ! ;; 1 ! ! (let* ((default-limit (save-excursion (end-of-line) (1+ (point)))) ! (limit (or limit default-limit)) ! (last-good-point (point)) ! (opoint (point))) ! ;; Move over blanks ! (back-to-indentation) ! ! ;; If we already were at the outermost indentation point then we ! ;; start searching for the innermost point again. ! (if (= (point) opoint) ! (setq limit default-limit)) ! ! (if (< (point) limit) ! (setq last-good-point (point))) ! ! (cond ! ;; Special treatment for comment lines. We are trying to allow ! ;; things like "$ !*" as comment lines. ! ((looking-at dcl-comment-line-regexp) ! (re-search-forward (concat dcl-comment-line-regexp "[ \t]*") limit t) ! (if (< (point) limit) ! (setq last-good-point (point)))) ! ! ;; Normal command line ! ((looking-at "^\\$[ \t]*") ! ;; Move over leading "$" and blanks ! (re-search-forward "^\\$[ \t]*" limit t) ! (if (< (point) limit) ! (setq last-good-point (point))) ! ! ;; Move over a label (if it isn't a block begin/end) ! ;; We must treat block begin/end labels as commands because ! ;; dcl-set-option relies on it. ! (if (and (looking-at dcl-label-r) ! (not (or (and dcl-block-begin-regexp ! (looking-at dcl-block-begin-regexp)) ! (and dcl-block-end-regexp ! (looking-at dcl-block-end-regexp))))) ! (re-search-forward (concat dcl-label-r "[ \t]*") limit t)) ! (if (< (point) limit) ! (setq last-good-point (point))) ! ! ;; Move over the beginning of a comment ! (if (looking-at "![ \t]*") ! (re-search-forward "![ \t]*" limit t)) ! (if (< (point) limit) ! (setq last-good-point (point))))) ! (goto-char last-good-point))) ! ! ! ;;; *** Support for indentation ********************************************* ! ! (defun dcl-get-line-type () "Determine the type of the current line. Returns: *************** *** 502,507 **** --- 888,902 ---- (progn 'data) )) + + ;;;------------------------------------------------------------------------- + (defun dcl-indentation-point () + "Return point of first non-`whitespace' on this line." + (save-excursion + (dcl-back-to-indentation) + (point))) + + ;;;--------------------------------------------------------------------------- (defun dcl-show-line-type () " test dcl-get-line-type" *************** *** 526,531 **** --- 921,930 ---- (message "hupp")) ))) + + ;;; *** Perform indentation ************************************************* + + ;;;--------------------------------------------------------------------------- ;; Thanks to Dan Dever for contributing ;; these calculations. They prompted me to add this customization method. *************** *** 582,588 **** (let ((case-fold-search t)) (save-excursion (cond ! ;; No indentation, this word is 'then': +2 ;; last word was endif: -2 ((null indent-type) (or (progn --- 981,987 ---- (let ((case-fold-search t)) (save-excursion (cond ! ;; No indentation, this word is `then': +2 ;; last word was endif: -2 ((null indent-type) (or (progn *************** *** 593,599 **** (goto-char last-point) (if (looking-at "\\bendif\\b") (- (+ cur-indent extra-indent) 2))))) ! ;; Indentation, last word was 'then' or 'else': -2 ((equal indent-type 'indent) (goto-char last-point) (cond --- 992,998 ---- (goto-char last-point) (if (looking-at "\\bendif\\b") (- (+ cur-indent extra-indent) 2))))) ! ;; Indentation, last word was `then' or `else': -2 ((equal indent-type 'indent) (goto-char last-point) (cond *************** *** 601,607 **** (- (+ cur-indent extra-indent) 2)) ((looking-at "\\belse\\b") (- (+ cur-indent extra-indent) 2)))) ! ;; Outdent, this word is 'endif' or 'else': + 2 ((equal indent-type 'outdent) (goto-char this-point) (cond --- 1000,1006 ---- (- (+ cur-indent extra-indent) 2)) ((looking-at "\\belse\\b") (- (+ cur-indent extra-indent) 2)))) ! ;; Outdent, this word is `endif' or `else': + 2 ((equal indent-type 'outdent) (goto-char this-point) (cond *************** *** 609,614 **** --- 1008,1015 ---- (+ cur-indent extra-indent 2)) ((looking-at "\\belse\\b") (+ cur-indent extra-indent 2)))))))) + + ;;;--------------------------------------------------------------------------- (defun dcl-calc-command-indent () "Calculate how much the current line shall be indented. *************** *** 616,622 **** Find the indentation of the preceding line and analyze its contents to see if the current lines should be indented. ! Analyze the current line to see if it should be 'outdented'. Calculate the indentation of the current line, either with the default method or by calling dcl-calc-command-indent-function if it is --- 1017,1023 ---- Find the indentation of the preceding line and analyze its contents to see if the current lines should be indented. ! Analyze the current line to see if it should be `outdented'. Calculate the indentation of the current line, either with the default method or by calling dcl-calc-command-indent-function if it is *************** *** 635,641 **** Find out how much it is indented (cur-indent). Look at the first word on the line to see if the indentation should be adjusted. Skip margin-label, continuations and comments while looking for ! the first word. Save this buffer position as 'last-point'. If the first word after a label is SUBROUTINE, set extra-indent to dcl-margin-offset. --- 1036,1042 ---- Find out how much it is indented (cur-indent). Look at the first word on the line to see if the indentation should be adjusted. Skip margin-label, continuations and comments while looking for ! the first word. Save this buffer position as `last-point'. If the first word after a label is SUBROUTINE, set extra-indent to dcl-margin-offset. *************** *** 646,652 **** Then return to the current line and look at the first word to see if the indentation should be adjusted again. Save this buffer position as ! 'this-point'. First word extra-indent ELSE -dcl-basic-offset --- 1047,1053 ---- Then return to the current line and look at the first word to see if the indentation should be adjusted again. Save this buffer position as ! `this-point'. First word extra-indent ELSE -dcl-basic-offset *************** *** 770,775 **** --- 1171,1177 ---- cur-indent ))) + ;;;--------------------------------------------------------------------------- (defun dcl-calc-cont-indent-relative (cur-indent extra-indent) "Indent continuation lines to a position relative to preceding *************** *** 803,809 **** (if (re-search-forward (concat "^\\$[ \t]*\\(" dcl-label-r "\\)*[ \t]*") end t) (progn ! ;; Move over the first word (might be '@filespec') (if (> (skip-chars-forward "@:[]<>$\\-a-zA-Z0-9_.;" end) 0) (let (was-assignment) (skip-chars-forward " \t" end) --- 1205,1211 ---- (if (re-search-forward (concat "^\\$[ \t]*\\(" dcl-label-r "\\)*[ \t]*") end t) (progn ! ;; Move over the first word (might be `@filespec') (if (> (skip-chars-forward "@:[]<>$\\-a-zA-Z0-9_.;" end) 0) (let (was-assignment) (skip-chars-forward " \t" end) *************** *** 816,822 **** (setq indent (current-column)) ;; Move to the next word unless we have seen an ! ;; assignment. If it starts with '/' it's a ;; qualifier and we will indent to that position (if (and (not was-assignment) (> (skip-chars-forward "a-zA-Z0-9_" end) 0)) --- 1218,1224 ---- (setq indent (current-column)) ;; Move to the next word unless we have seen an ! ;; assignment. If it starts with `/' it's a ;; qualifier and we will indent to that position (if (and (not was-assignment) (> (skip-chars-forward "a-zA-Z0-9_" end) 0)) *************** *** 839,844 **** --- 1241,1247 ---- (1+ (current-column))))))) indent)) + ;;;--------------------------------------------------------------------------- (defun dcl-calc-continuation-indent () "Calculate how much the current line shall be indented. *************** *** 899,904 **** --- 1302,1309 ---- dcl-continuation-offset)) (+ indent dcl-continuation-offset)) )))) + + ;;;--------------------------------------------------------------------------- (defun dcl-indent-command-line () "Indent a line known to be a command line." *************** *** 924,929 **** --- 1329,1336 ---- (if (> (- (point-max) pos) (point)) (goto-char (- (point-max) pos))) )) + + ;;;------------------------------------------------------------------------- (defun dcl-indent-continuation-line () "Indent a line known to be a continuation line. *************** *** 937,948 **** --- 1344,1357 ---- (dcl-indent-to indent)) (skip-chars-forward " \t"))) + ;;;--------------------------------------------------------------------------- (defun dcl-delete-chars (chars) "Delete all characters like chars around point." (skip-chars-backward chars) (delete-region (point) (progn (skip-chars-forward chars) (point)))) + ;;;--------------------------------------------------------------------------- (defun dcl-indent-line () "The DCL version of indent-line-function. *************** *** 981,986 **** --- 1390,1397 ---- (point)) (progn (dcl-end-of-statement) (point)) nil))))) + + ;;;------------------------------------------------------------------------- (defun dcl-tab () "Insert tab in data lines or indent code. *************** *** 1009,1023 **** ((eq dcl-tab-always-indent t) ; t (dcl-indent-line)) ))) ! ;;;------------------------------------------------------------------------- ! (defun dcl-was-looking-at (regexp) ! (save-excursion ! (let ((start (point)) ! (found (re-search-backward regexp 0 t)) ! ) ! (if (not found) ! () ! (equal start (match-end 0)))))) ;;;------------------------------------------------------------------------- (defun dcl-electric-character (arg) --- 1420,1426 ---- ((eq dcl-tab-always-indent t) ; t (dcl-indent-line)) ))) ! ;;;------------------------------------------------------------------------- (defun dcl-electric-character (arg) *************** *** 1041,1046 **** --- 1444,1450 ---- (if (memq t (mapcar 'dcl-was-looking-at dcl-electric-reindent-regexps)) (dcl-indent-line))))) + ;;;------------------------------------------------------------------------- (defun dcl-indent-to (col &optional minimum) "Like indent-to, but only indents if indentation would change" *************** *** 1057,1062 **** --- 1461,1467 ---- (dcl-delete-chars " \t") (indent-to col minimum))))) + ;;;------------------------------------------------------------------------- (defun dcl-split-line () "Break line at point and insert text to keep the syntax valid. *************** *** 1096,1102 **** (t (delete-horizontal-space) (insert " -") ! (reindent-then-newline-and-indent) (setq done t)))) )))) ;; use the normal function for other cases --- 1501,1507 ---- (t (delete-horizontal-space) (insert " -") ! (insert "\n") (indent-according-to-mode) (setq done t)))) )))) ;; use the normal function for other cases *************** *** 1105,1134 **** ;;;------------------------------------------------------------------------- - (defun dcl-back-to-indentation () - "Move point to the first non-whitespace character on this line. - Leading $ and labels counts as whitespace in this case." - (interactive) - (back-to-indentation) - (if (looking-at dcl-command-regexp) ; $-line? - (progn ; yes, skip $ and whitespace - (re-search-forward "^\\$[ \t]*") - (if (and (looking-at dcl-label-r) ; label but not block begin/end? - (not (and dcl-block-begin-regexp ; (might be nil) - (looking-at dcl-block-begin-regexp))) - (not (and dcl-block-end-regexp ; (might be nil) - (looking-at dcl-block-end-regexp)))) - (re-search-forward (concat dcl-label-r "[ \t]*")))))) ; yes - - ;;;------------------------------------------------------------------------- - (defun dcl-indentation-point () - "Return point of first non-'whitespace' on this line." - (save-excursion - (dcl-back-to-indentation) - (point))) - - - ;;;------------------------------------------------------------------------- (defun dcl-delete-indentation (&optional arg) "Join this line to previous like delete-indentation. Also remove the continuation mark if easily detected" --- 1510,1515 ---- *************** *** 1143,1156 **** (progn (delete-backward-char 1) (fixup-whitespace))))) ! ;;;------------------------------------------------------------------------- ! ;;; template stuff ! ;; ;; tempo seems to be the only suitable package among those included in ;; standard Emacs. I would have liked something closer to the functionality ;; of LSE templates... (require 'tempo) (defvar dcl-tempo-tags nil "Tempo tags for DCL mode") --- 1524,1900 ---- (progn (delete-backward-char 1) (fixup-whitespace))))) ! ! ! ;;; *** Set options ********************************************************* ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-option-value-basic (option-assoc) ! "Guess a value for basic-offset" ! (save-excursion ! (dcl-beginning-of-command) ! (let* (;; current lines indentation ! (this-indent (save-excursion ! (dcl-back-to-indentation) ! (current-column))) ! ;; previous lines indentation ! (prev-indent (save-excursion ! (if (dcl-backward-command) ! (progn ! (dcl-back-to-indentation) ! (current-column))))) ! (next-indent (save-excursion ! (dcl-end-of-command) ! (if (dcl-forward-command) ! (progn ! (dcl-beginning-of-command) ! (dcl-back-to-indentation) ! (current-column))))) ! (diff (if prev-indent ! (abs (- this-indent prev-indent))))) ! (cond ! ((and diff ! (/= diff 0)) ! diff) ! ((and next-indent ! (/= (- this-indent next-indent) 0)) ! (abs (- this-indent next-indent))) ! (t ! dcl-basic-offset))))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-option-value-offset (option-assoc) ! "Guess a value for an offset by finding the column of the first ! non-blank character on the line. ! Returns a number as a string" ! (save-excursion ! (beginning-of-line) ! (re-search-forward "^$[ \t]*" nil t) ! (current-column))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-option-value-margin-offset (option-assoc) ! "Guess a value for margin offset by finding the column of the first ! non-blank character on the line, not counting labels. ! Returns a number as a string" ! (save-excursion ! (beginning-of-line) ! (dcl-back-to-indentation) ! (current-column))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-option-value-comment-line (option-assoc) ! "Guess a value for dcl-comment-line-regexp. ! Must return a string." ! ;; Should we set comment-start and comment-start-skip as well? ! ;; If someone wants `$!&' as a comment line, C-M-j won't work well if ! ;; they aren't set. ! ;; This must be done after the user has given the real value in ! ;; dcl-set-option. ! (format ! "%S" ! (save-excursion ! (beginning-of-line) ! ;; We could search for "^\\$.*!+[^ \t]*", but, as noted above, we ! ;; can't handle that case very good, so there is no point in ! ;; suggesting it. ! (if (looking-at "^\\$[^!\n]*!") ! (let ((regexp (buffer-substring (match-beginning 0) (match-end 0)))) ! (concat "^" (regexp-quote regexp))) ! dcl-comment-line-regexp)))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-guess-option-value (option) ! "Guess what value the user would like to give the symbol option" ! (let* ((option-assoc (assoc option dcl-option-alist)) ! (option (car option-assoc)) ! (action (car (cdr option-assoc))) ! (value (cond ! ((fboundp action) ! (funcall action option-assoc)) ! ((eq action 'toggle) ! (not (eval option))) ! ((eq action 'curval) ! (cond ((or (stringp (symbol-value option)) ! (numberp (symbol-value option))) ! (format "%S" (symbol-value option))) ! (t ! (format "'%S" (symbol-value option)))))))) ! ;; format the value as a string if not already done ! (if (stringp value) ! value ! (format "%S" value)))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-guess-option () ! "Guess what option the user wants to set by looking around in the code. ! Returns the name of the option variable as a string." ! (let ((case-fold-search t)) ! (cond ! ;; Continued line ! ((eq (dcl-get-line-type) '-) ! "dcl-calc-cont-indent-function") ! ;; Comment line ! ((save-excursion ! (beginning-of-line) ! (looking-at "^\\$[ \t]*!")) ! "dcl-comment-line-regexp") ! ;; Margin offset ! ;; Test this before label indentation to detect a subroutine ! ((save-excursion ! (beginning-of-line) ! (or (looking-at (concat "^\\$[ \t]*" dcl-label-r dcl-ws-r ! "subroutine")) ! (save-excursion ! (not (dcl-backward-command t))))) ! "dcl-margin-offset") ! ;; Label indentation ! ((save-excursion ! (beginning-of-line) ! (and (looking-at (concat "^\\$[ \t]*" dcl-label-r)) ! (not (and dcl-block-begin-regexp ! (looking-at (concat "^\\$[ \t]*" ! dcl-block-begin-regexp)))) ! (not (and dcl-block-end-regexp ! (looking-at (concat "^\\$[ \t]*" ! dcl-block-end-regexp)))))) ! "dcl-margin-label-offset") ! ;; Basic offset ! ((and (eq (dcl-get-line-type) '$) ; beginning of command ! (save-excursion ! (beginning-of-line) ! (let* ((this-indent (save-excursion ! (dcl-back-to-indentation) ! (current-column))) ! (prev-indent (save-excursion ! (if (dcl-backward-command) ! (progn ! (dcl-back-to-indentation) ! (current-column))))) ! (next-indent (save-excursion ! (dcl-end-of-command) ! (if (dcl-forward-command) ! (progn ! (dcl-beginning-of-command) ! (dcl-back-to-indentation) ! (current-column)))))) ! (or (and prev-indent ; last cmd is indented differently ! (/= (- this-indent prev-indent) 0)) ! (and next-indent ! (/= (- this-indent next-indent) 0)))))) ! "dcl-basic-offset") ! ;; No more guesses. ! (t ! "")))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-set-option (option-sym option-value) ! "Set a value for one of the dcl customization variables. ! The function tries to guess which variable should be set and to what value. ! All variable names are available as completions and in the history list. ! " ! (interactive ! (let* ((option-sym ! (intern (completing-read ! "Set DCL option: " ; prompt ! (mapcar (function ; alist of valid values ! (lambda (option-assoc) ! (cons (format "%s" (car option-assoc)) nil))) ! dcl-option-alist) ! nil ; no predicate ! t ; only value from the list OK ! (dcl-guess-option) ; initial (default) value ! 'dcl-option-history))) ; history list ! (option-value ! (eval-minibuffer ! (format "Set DCL option %s to: " option-sym) ! (dcl-guess-option-value option-sym)))) ! (list option-sym option-value))) ! ;; Should make a sanity check on the symbol/value pair. ! ;; `set' instead of `setq' because we want option-sym to be evaluated. ! (set option-sym option-value)) ! ! ! ;;; *** Save options ******************************************************** ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-save-local-variable (var &optional def-prefix def-suffix) ! "Set or update the value of VAR in the current buffers ! `Local Variables:' list." ! ;; Most code shamelessly stolen from hack-local-variables in files.el ! ;; Thanks to Kai Grossjohann ! ;; for code examples ! ! ;; Look for "Local variables:" line in last page. ! (save-excursion ! (goto-char (point-max)) ! (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move) ! (if (let ((case-fold-search t)) ! (search-forward "Local Variables:" nil t)) ! (let ((continue t) ! prefix prefixlen suffix beg ! prefix-string suffix-string) ! ;; The prefix is what comes before "local variables:" in its line. ! ;; The suffix is what comes after "local variables:" in its line. ! (skip-chars-forward " \t") ! (or (eolp) ! (setq suffix-string (buffer-substring (point) ! (progn (end-of-line) (point))))) ! (goto-char (match-beginning 0)) ! (or (bolp) ! (setq prefix-string ! (buffer-substring (point) ! (progn (beginning-of-line) (point))))) ! ! (if prefix-string (setq prefixlen (length prefix-string) ! prefix (regexp-quote prefix-string))) ! (if suffix-string (setq suffix (concat (regexp-quote suffix-string) ! "$"))) ! (while continue ! ;; Look at next local variable spec. ! (if selective-display (re-search-forward "[\n\C-m]") ! (forward-line 1)) ! ;; Skip the prefix, if any. ! (if prefix ! (if (looking-at prefix) ! (forward-char prefixlen) ! (error "Local variables entry is missing the prefix"))) ! ;; Find the variable name; strip whitespace. ! (skip-chars-forward " \t") ! (setq beg (point)) ! (skip-chars-forward "^:\n") ! (if (eolp) (error "Missing colon in local variables entry")) ! (skip-chars-backward " \t") ! (let* ((str (buffer-substring beg (point))) ! (found-var (read str)) ! val) ! ;; Setting variable named "end" means end of list. ! (if (string-equal (downcase str) "end") ! (progn ! ;; Not found. Insert a new entry before this line ! (setq continue nil) ! (beginning-of-line) ! (insert (concat prefix-string (symbol-name var) ": " ! (prin1-to-string (eval var)) " " ! suffix-string "\n"))) ! ;; Is it the variable we are looking for? ! (if (eq var found-var) ! (progn ! ;; Found it: delete the variable value and insert the ! ;; new value. ! (setq continue nil) ! (skip-chars-forward "^:") ! (forward-char 1) ! (delete-region (point) (progn (read (current-buffer)) ! (point))) ! (insert " ") ! (prin1 (eval var) (current-buffer)) ! (skip-chars-backward "\n") ! (skip-chars-forward " \t") ! (or (if suffix (looking-at suffix) (eolp)) ! (error ! "Local variables entry is terminated incorrectly"))) ! (end-of-line)))))) ! ;; Did not find "Local variables:" ! (goto-char (point-max)) ! (if (not (bolp)) ! (insert "\n")) ! ;; If def- parameter not set, use comment- if set. In that case, make ! ;; sure there is a space in a suitable position ! (let ((def-prefix ! (cond ! (def-prefix ! def-prefix) ! (comment-start ! (if (or (equal comment-start "") ! (string-match "[ \t]$" comment-start)) ! comment-start ! (concat comment-start " "))))) ! (def-suffix ! (cond ! (def-suffix ! def-suffix) ! (comment-end ! (if (or (equal comment-end "") ! (string-match "^[ \t]" comment-end)) ! comment-end ! (concat " " comment-end)))))) ! (insert (concat def-prefix "Local variables:" def-suffix "\n")) ! (insert (concat def-prefix (symbol-name var) ": " ! (prin1-to-string (eval var)) def-suffix "\n")) ! (insert (concat def-prefix "end:" def-suffix))) ! ))) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-save-all-options () ! "Saves or updates all dcl-mode related options in a `Local Variables:' ! section at the end of the current buffer." ! (interactive "*") ! (mapcar (lambda (option-assoc) ! (let* ((option (car option-assoc))) ! (dcl-save-local-variable option "$! "))) ! dcl-option-alist)) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-save-nondefault-options () ! "Saves or updates all dcl-mode related options that don't have their ! default values in a `Local Variables:' section at the end of the ! current buffer. ! ! No entries are removed from the `Local Variables:' section. This means ! that if a variable is given a non-default value in the section and ! later is manually reset to its default value, the variable's entry will ! still be present in the `Local Variables:' section with its old value. ! " ! (interactive "*") ! (mapcar (lambda (option-assoc) ! (let* ((option (car option-assoc)) ! (option-name (symbol-name option))) ! (if (and (string-equal "dcl-" ! (substring option-name 0 4)) ! (not (equal (default-value option) (eval option)))) ! (dcl-save-local-variable option "$! ")))) ! dcl-option-alist)) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-save-option (option) ! "Saves or updates an option in a `Local Variables:' ! section at the end of the current buffer." ! (interactive ! (let ((option (intern (completing-read "Option: " obarray)))) ! (list option))) ! (dcl-save-local-variable option)) ! ! ! ;;;------------------------------------------------------------------------- ! (defun dcl-save-mode () ! "Save the current mode in a `Local Variables:' ! section at the end of the current buffer." ! (interactive) ! (let ((mode (prin1-to-string major-mode))) ! (if (string-match "-mode$" mode) ! (let ((mode (intern (substring mode 0 (match-beginning 0))))) ! (dcl-save-option 'mode)) ! (message "Strange mode: %s" mode)))) ! ! ! ;;; *** Templates *********************************************************** ;; tempo seems to be the only suitable package among those included in ;; standard Emacs. I would have liked something closer to the functionality ;; of LSE templates... + (require 'tempo) (defvar dcl-tempo-tags nil "Tempo tags for DCL mode") *************** *** 1354,1360 **** --- 2098,2161 ---- "f$time" "" 'dcl-tempo-tags) + + ;;; *** Unsorted stuff ***************************************************** + + + ;;;------------------------------------------------------------------------- + (defun dcl-beginning-of-command-p () + "Return t if point is at the beginning of a command. + Otherwise return nil." + (and (bolp) + (eq (dcl-get-line-type) '$))) + + + ;;;------------------------------------------------------------------------- + (defun dcl-end-of-command-p () + "Return t if point is at the end of a command, either the end of an + only line or at the end of the last continuation line. + Otherwise return nil." + ;; Must be at end-of-line on a command line or a continuation line + (let ((type (dcl-get-line-type))) + (if (and (eolp) + (or (eq type '$) + (eq type '-))) + ;; Next line must not be a continuation line + (save-excursion + (forward-line) + (not (eq (dcl-get-line-type) '-)))))) + + ;;;------------------------------------------------------------------------- + (defun dcl-command-p () + "Return t if point is on a command line or a continuation line, + otherwise return nil." + (let ((type (dcl-get-line-type))) + (or (eq type '$) + (eq type '-)))) + + + ;;;------------------------------------------------------------------------- + (defun dcl-was-looking-at (regexp) + (save-excursion + (let ((start (point)) + (found (re-search-backward regexp 0 t))) + (if (not found) + () + (equal start (match-end 0)))))) + + + ;;;------------------------------------------------------------------------- + (defun dcl-imenu-create-index-function () + "Jacket routine to make imenu searches non case sensitive." + (let ((case-fold-search t)) + (imenu-default-create-index-function))) + + + + ;;; *** Epilogue ************************************************************ + + (provide 'dcl-mode) (run-hooks 'dcl-mode-load-hook) ; for your customizations