;;; tcl.el --- Tcl code editing commands for Emacs
-;; Copyright (C) 1994, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+;; Free Software Foundation, Inc.
-;; Maintainer: Tom Tromey <tromey@busco.lanl.gov>
-;; Author: Tom Tromey <tromey@busco.lanl.gov>
+;; Maintainer: FSF
+;; Author: Tom Tromey <tromey@redhat.com>
;; Chris Lindblad <cjl@lcs.mit.edu>
;; Keywords: languages tcl modes
-;; Version: $Revision: 1.64 $
;; This file is part of GNU Emacs.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;; BEFORE USE:
;;
;; * tcl-typeword-list is similar, but uses font-lock-type-face.
;; * tcl-keyword-list is a list of keywords. I've generally used this
;; for flow-control words. Eg I add "unwind_protect" to this list.
+;; * tcl-builtin-list lists commands to be given font-lock-builtin-face.
;; * tcl-type-alist can be used to minimally customize indentation
;; according to context.
;; Jesper Pedersen <blackie@imada.ou.dk>
;; dfarmer@evolving.com (Doug Farmer)
;; "Chris Alfeld" <calfeld@math.utah.edu>
-;; Ben Wing <wing@666.com>
+;; Ben Wing <ben@xemacs.org>
;; KNOWN BUGS:
-;; * In Tcl "#" is not always a comment character. This can confuse
-;; tcl.el in certain circumstances. For now the only workaround is
-;; to enclose offending hash characters in quotes or precede it with
-;; a backslash. Note that using braces won't work -- quotes change
-;; the syntax class of characters between them, while braces do not.
-;; The electric-# mode helps alleviate this problem somewhat.
+;; * In Tcl "#" is not always a comment character. This can confuse tcl.el
+;; in certain circumstances. For now the only workaround is to use
+;; font-lock which will mark the # chars accordingly or enclose offending
+;; hash characters in quotes or precede them with a backslash. Note that
+;; using braces won't work -- quotes change the syntax class of characters
+;; between them, while braces do not. If you don't use font-lock, the
+;; electric-# mode helps alleviate this problem somewhat.
;; * indent-tcl-exp is untested.
;; TODO:
;; middle of a defun, or between defuns. should notice if point is
;; on first line of defun (or maybe even in comments before defun).
;; * Allow continuation lines to be indented under the first argument
-;; of the preceeding line, like this:
+;; of the preceding line, like this:
;; [list something \
;; something-else]
;; * There is a request that indentation work like this:
;;
(defgroup tcl nil
- "Major mode for editing Tcl source in Emacs"
+ "Major mode for editing Tcl source in Emacs."
:group 'languages)
(defcustom tcl-indent-level 4
"*Indentation of Tcl statements with respect to containing block."
- :group 'tcl
- :type 'integer)
+ :type 'integer
+ :group 'tcl)
(defcustom tcl-continued-indent-level 4
"*Indentation of continuation line relative to first line of command."
- :group 'tcl
- :type 'integer)
+ :type 'integer
+ :group 'tcl)
(defcustom tcl-auto-newline nil
"*Non-nil means automatically newline before and after braces you insert."
- :group 'tcl
- :type 'boolean)
+ :type 'boolean
+ :group 'tcl)
-(defcustom tcl-tab-always-indent t
+(defcustom tcl-tab-always-indent tab-always-indent
"*Control effect of TAB key.
If t (the default), always indent current line.
If nil and point is not in the indentation area at the beginning of
4. Move forward to end of line, indenting if necessary.
5. Create an empty comment.
6. Move backward to start of comment, indenting if necessary."
- :group 'tcl
:type '(choice (const :tag "Always" t)
(const :tag "Beginning only" nil)
- (const :tag "Maybe move or make or delete comment" 'tcl)))
+ (const :tag "Maybe move or make or delete comment" 'tcl))
+ :group 'tcl)
-(defcustom tcl-electric-hash-style 'smart
+(defcustom tcl-electric-hash-style nil ;; 'smart
"*Style of electric hash insertion to use.
Possible values are `backslash', meaning that `\\' quoting should be
done; `quote', meaning that `\"' quoting should be done; `smart',
meaning that the choice between `backslash' and `quote' should be
made depending on the number of hashes inserted; or nil, meaning that
no quoting should be done. Any other value for this variable is
-taken to mean `smart'. The default is `smart'."
- :group 'tcl
- :type '(choice (const backslash) (const quote) (const smart) (const nil)))
+taken to mean `smart'. The default is nil."
+ :type '(choice (const backslash) (const quote) (const smart) (const nil))
+ :group 'tcl)
(defcustom tcl-help-directory-list nil
"*List of topmost directories containing TclX help files."
- :group 'tcl
- :type '(repeat directory))
+ :type '(repeat directory)
+ :group 'tcl)
(defcustom tcl-use-smart-word-finder t
"*If not nil, use smart way to find current word, for Tcl help feature."
- :group 'tcl
- :type 'boolean)
+ :type 'boolean
+ :group 'tcl)
(defcustom tcl-application "wish"
"*Name of Tcl program to run in inferior Tcl mode."
- :group 'tcl
- :type 'string)
+ :type 'string
+ :group 'tcl)
(defcustom tcl-command-switches nil
"*List of switches to supply to the `tcl-application' program."
- :group 'tcl
- :type '(repeat string))
+ :type '(repeat string)
+ :group 'tcl)
(defcustom tcl-prompt-regexp "^\\(% \\|\\)"
"*If not nil, a regexp that will match the prompt in the inferior process.
The default is \"^\\(% \\|\\)\", which will match the default primary
and secondary prompts for tclsh and wish."
- :group 'tcl
- :type 'regexp)
+ :type 'regexp
+ :group 'tcl)
(defcustom inferior-tcl-source-command "source %s\n"
"*Format-string for building a Tcl command to load a file.
and should result in a Tcl expression that will command the
inferior Tcl to load that file. The filename will be appropriately
quoted for Tcl."
+ :type 'string
+ :group 'tcl)
+
+(defface tcl-escaped-newline '((t :inherit font-lock-string-face))
+ "Face used for (non-escaped) backslash at end of a line in Tcl mode."
:group 'tcl
- :type 'string)
+ :version "22.1")
;;
;; Keymaps, abbrevs, syntax tables.
If you do a \\[tcl-eval-defun] command on some Lisp source code, what
process do you send it to?
-- If you're in a process buffer (foo, bar, or *inferior-tcl*),
+- If you're in a process buffer (foo, bar, or *inferior-tcl*),
you send it to that process.
- If you're in some other buffer (e.g., a source file), you
send it to the process attached to buffer `inferior-tcl-buffer'.
Default list includes some TclX keywords.
Call `tcl-set-font-lock-keywords' after changing this list.")
+(defvar tcl-builtin-list
+ '("after" "append" "array" "bgerror" "binary" "catch" "cd" "clock"
+ "close" "concat" "console" "dde" "encoding" "eof" "exec" "expr"
+ "fblocked" "fconfigure" "fcopy" "file" "fileevent" "flush"
+ "format" "gets" "glob" "history" "incr" "info" "interp" "join"
+ "lappend" "lindex" "linsert" "list" "llength" "load" "lrange"
+ "lreplace" "lsort" "namespace" "open" "package" "pid" "puts" "pwd"
+ "read" "regexp" "registry" "regsub" "rename" "scan" "seek" "set"
+ "socket" "source" "split" "string" "subst" "tell" "time" "trace"
+ "unknown" "unset" "vwait")
+ "List of Tcl commands. Used only for highlighting.
+Call `tcl-set-font-lock-keywords' after changing this list.
+This list excludes those commands already found in `tcl-proc-list' and
+`tcl-keyword-list'.")
+
(defvar tcl-font-lock-keywords nil
"Keywords to highlight for Tcl. See variable `font-lock-keywords'.
This variable is generally set from `tcl-proc-regexp',
is a Tcl expression, and the last argument is Tcl commands.")
(defvar tcl-explain-indentation nil
- "If not `nil', debugging message will be printed during indentation.")
+ "If non-nil, debugging message will be printed during indentation.")
\f
-;; Its pretty bogus to have to do this, but there is no easier way to
-;; say "match not syntax-1 and not syntax-2". Too bad you can't put
-;; \s in [...]. This sickness is used in Emacs 19 to match a defun
-;; starter. (It is used for this in v18 as well).
-;;(defconst tcl-omit-ws-regexp
-;; (concat "^\\(\\s"
-;; (mapconcat 'char-to-string "w_.()\"\\$'/" "\\|\\s")
-;; "\\)\\S(*")
-;; "Regular expression that matches everything except space, comment
-;;starter, and comment ender syntax codes.")
-
-;; FIXME? Instead of using the hairy regexp above, we just use a
-;; simple one.
-;;(defconst tcl-omit-ws-regexp "^[^] \t\n#}]\\S(*"
-;; "Regular expression used in locating function definitions.")
-
-;; Here's another stab. I think this one actually works. Now the
-;; problem seems to be that there is a bug in Emacs 19.22 where
-;; end-of-defun doesn't really use the brace matching the one that
-;; trails defun-prompt-regexp.
-;; ?? Is there a bug now ??
-(defconst tcl-omit-ws-regexp "^[^ \t\n#}][^\n}]+}*[ \t]+")
+;; Here's another stab. I think this one actually works.
+;; We have to be careful that the open-brace following this regexp
+;; is indeed the one corresponding to the function's body so
+;; that end-of-defun works correctly. Tricky cases are:
+;; proc foo { {arg1 def} arg2 } {
+;; as well as
+;; proc foo { \n {arg1 def} \n arg2 } {
+;; The current setting handles the first case properly but not the second.
+;; It also fails if `proc' is not in column-0 (e.g. it's in a namespace).
+(defconst tcl-omit-ws-regexp "^[^]\" \t\n#}][^\n\"#]+[ \t]+")
\f
"\\(\\s-\\|$\\)")
2 'font-lock-type-face)
+ (list (concat "\\_<" (regexp-opt tcl-builtin-list t) "\\_>")
+ 1 'font-lock-builtin-face)
+
+ ;; When variable names are enclosed in {} braces, any
+ ;; character can be used. Otherwise just letters, digits,
+ ;; underscores. Variable names can be prefixed with any
+ ;; number of "namespace::" qualifiers. A leading "::" refers
+ ;; to the global namespace.
+ '("\\${\\([^}]+\\)}" 1 font-lock-variable-name-face)
+ '("\\$\\(\\(?:::\\)?\\(?:[[:alnum:]_]+::\\)*[[:alnum:]_]+\\)"
+ 1 font-lock-variable-name-face)
+ '("\\(?:\\s-\\|^\\|\\[\\)set\\s-+{\\([^}]+\\)}"
+ 1 font-lock-variable-name-face keep)
+ '("\\(?:\\s-\\|^\\|\\[\\)set\\s-+\\(\\(?:::\\)?\
+\\(?:[[:alnum:]_]+::\\)*[[:alnum:]_]+\\)"
+ 1 font-lock-variable-name-face keep)
+
+ '("\\(^\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\\\)$" 3 'tcl-escaped-newline)
+
;; Keywords. Only recognized if surrounded by whitespace.
;; FIXME consider using "not word or symbol", not
;; "whitespace".
- (cons (concat "\\(\\s-\\|^\\)"
- ;; FIXME Use regexp-quote?
- (regexp-opt tcl-keyword-list t)
- "\\(\\s-\\|$\\)")
- 2))))
+ (cons (concat "\\_<" (regexp-opt tcl-keyword-list t) "\\_>")
+ 1))))
(if tcl-proc-regexp
()
()
(tcl-set-font-lock-keywords))
+
+(defvar tcl-imenu-generic-expression
+ `((nil ,(concat tcl-proc-regexp "\\([-A-Za-z0-9_:+*]+\\)") 2))
+ "Imenu generic expression for `tcl-mode'. See `imenu-generic-expression'.")
+
\f
;;
`tcl-auto-newline'
Non-nil means automatically newline before and after braces, brackets,
and semicolons inserted in Tcl code.
- `tcl-electric-hash-style'
- Controls action of `#' key.
`tcl-use-smart-word-finder'
If not nil, use a smarter, Tcl-specific way to find the current
word when looking up help on a Tcl command.
-Turning on Tcl mode calls the value of the variable `tcl-mode-hook'
-with no args, if that value is non-nil. Read the documentation for
+Turning on Tcl mode runs `tcl-mode-hook'. Read the documentation for
`tcl-mode-hook' to see what kinds of interesting hook functions
already exist.
Commands:
\\{tcl-mode-map}"
- (set (make-local-variable 'paragraph-start) "$\\|\f")
- (set (make-local-variable 'paragraph-separate) paragraph-start)
-
- (set (make-local-variable 'paragraph-ignore-fill-prefix) t)
- (set (make-local-variable 'fill-paragraph-function) 'tcl-do-fill-paragraph)
+ (unless (and (boundp 'filladapt-mode) filladapt-mode)
+ (set (make-local-variable 'paragraph-ignore-fill-prefix) t))
(set (make-local-variable 'indent-line-function) 'tcl-indent-line)
(set (make-local-variable 'comment-indent-function) 'tcl-comment-indent)
;; (setq require-final-newline t)
(set (make-local-variable 'comment-start) "# ")
- (set (make-local-variable 'comment-start-skip) "#+ *")
- (set (make-local-variable 'comment-column) 40) ;why? -stef
+ (set (make-local-variable 'comment-start-skip)
+ "\\(\\(^\\|[;{[]\\)\\s-*\\)#+ *")
(set (make-local-variable 'comment-end) "")
- (set (make-local-variable 'outline-regexp) "[^\n\^M]")
+ (set (make-local-variable 'outline-regexp) ".")
(set (make-local-variable 'outline-level) 'tcl-outline-level)
(set (make-local-variable 'font-lock-defaults)
'(tcl-font-lock-keywords nil nil nil beginning-of-defun
- (font-lock-syntactic-keywords . tcl-font-lock-syntactic-keywords)
- (parse-sexp-lookup-properties . t)))
+ (font-lock-syntactic-keywords . tcl-font-lock-syntactic-keywords)
+ (parse-sexp-lookup-properties . t)))
+
+ (set (make-local-variable 'imenu-generic-expression)
+ tcl-imenu-generic-expression)
- (set (make-local-variable 'imenu-create-index-function)
- 'tcl-imenu-create-index-function)
-
;; Settings for new dabbrev code.
(set (make-local-variable 'dabbrev-case-fold-search) nil)
(set (make-local-variable 'dabbrev-case-replace) nil)
(beginning-of-line)
(let* ((indent-point (point))
(case-fold-search nil)
- (continued-line
+ (continued-line
(save-excursion
(if (bobp)
nil
(contain-stack (list (point)))
(case-fold-search nil)
outer-loop-done inner-loop-done state ostate
- this-indent last-sexp continued-line
+ this-indent continued-line
(next-depth 0)
last-depth)
(save-excursion
(setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
nil nil state))
(setq next-depth (car state))
- (if (and (car (cdr (cdr state)))
- (>= (car (cdr (cdr state))) 0))
- (setq last-sexp (car (cdr (cdr state)))))
(if (or (nth 4 ostate))
(tcl-indent-line))
(if (or (nth 3 state))
(setq indent-stack (cdr indent-stack)
contain-stack (cdr contain-stack)
last-depth (1- last-depth)))
- (if (/= last-depth next-depth)
- (setq last-sexp nil))
;; Add levels for any parens that were started in this line.
(while (< last-depth next-depth)
(setq indent-stack (cons nil indent-stack)
contain-stack (cons nil contain-stack)
last-depth (1+ last-depth)))
(if (null (car contain-stack))
- (setcar contain-stack
+ (setcar contain-stack
(or (car (cdr state))
(save-excursion
(forward-sexp -1)
(point)))))
(forward-line 1)
- (setq continued-line
+ (setq continued-line
(save-excursion
(backward-char)
(= (preceding-char) ?\\)))
(setq this-indent (- this-indent 1))))
;; Put chosen indentation into effect.
(or (null this-indent)
- (= (current-column)
- (if continued-line
+ (= (current-column)
+ (if continued-line
(+ this-indent tcl-indent-level)
this-indent))
(progn
(delete-region (point) (progn (beginning-of-line) (point)))
- (indent-to
- (if continued-line
+ (indent-to
+ (if continued-line
(+ this-indent tcl-indent-level)
this-indent)))))))))
)
;; Interfaces to other packages.
;;
-(defun tcl-imenu-create-index-function ()
- "Generate alist of indices for imenu."
- (let ((re (concat tcl-proc-regexp "\\([^ \t\n{]+\\)"))
- alist prev-pos)
- (goto-char (point-min))
- (imenu-progress-message prev-pos 0)
- (save-match-data
- (while (re-search-forward re nil t)
- (imenu-progress-message prev-pos)
- ;; Position on start of proc name, not beginning of line.
- (setq alist (cons
- (cons (buffer-substring (match-beginning 2) (match-end 2))
- (match-beginning 2))
- alist))))
- (imenu-progress-message prev-pos 100)
- (nreverse alist)))
-
;; FIXME Definition of function is very ad-hoc. Should use
;; beginning-of-defun. Also has incestuous knowledge about the
;; format of tcl-proc-regexp.
(define-derived-mode inferior-tcl-mode comint-mode "Inferior Tcl"
"Major mode for interacting with Tcl interpreter.
-A Tcl process can be started with M-x inferior-tcl.
+You can start a Tcl process with \\[inferior-tcl].
Entry to this mode runs the normal hooks `comint-mode-hook' and
`inferior-tcl-mode-hook', in that order.
(list (if current-prefix-arg
(read-string "Run Tcl: " tcl-application)
tcl-application)))
- (if (not (comint-check-proc "*inferior-tcl*"))
- (progn
- (set-buffer (apply (function make-comint) "inferior-tcl" cmd nil
- tcl-command-switches))
- (inferior-tcl-mode)))
- (make-local-variable 'tcl-application)
- (setq tcl-application cmd)
+ (unless (comint-check-proc "*inferior-tcl*")
+ (set-buffer (apply (function make-comint) "inferior-tcl" cmd nil
+ tcl-command-switches))
+ (inferior-tcl-mode))
+ (set (make-local-variable 'tcl-application) cmd)
(setq inferior-tcl-buffer "*inferior-tcl*")
- (switch-to-buffer "*inferior-tcl*"))
+ (pop-to-buffer "*inferior-tcl*"))
(defalias 'run-tcl 'inferior-tcl)
"Return t if point is just after the `#' beginning a real comment.
Does not check to see if previous char is actually `#'.
A real comment is either at the beginning of the buffer,
-preceeded only by whitespace on the line, or has a preceeding
+preceded only by whitespace on the line, or has a preceding
semicolon, opening brace, or opening bracket on the same line."
(save-excursion
(backward-char)
(beginning-of-defun)
(car (tcl-hairy-scan-for-comment nil save nil))))
-(defun tcl-do-fill-paragraph (ignore)
- "fill-paragraph function for Tcl mode. Only fills in a comment."
- (let (in-comment col where)
- (save-excursion
- (end-of-line)
- (setq in-comment (tcl-in-comment))
- (if in-comment
- (progn
- (setq where (1+ (point)))
- (setq col (1- (current-column))))))
- (and in-comment
- (save-excursion
- (back-to-indentation)
- (= col (current-column)))
- ;; In a comment. Set the fill prefix, and find the paragraph
- ;; boundaries by searching for lines that look like
- ;; comment-only lines.
- (let ((fill-prefix (buffer-substring (progn
- (beginning-of-line)
- (point))
- where))
- p-start p-end)
- ;; Search backwards.
- (save-excursion
- (while (looking-at "^[ \t]*#")
- (forward-line -1))
- (forward-line)
- (setq p-start (point)))
-
- ;; Search forwards.
- (save-excursion
- (while (looking-at "^[ \t]*#")
- (forward-line))
- (setq p-end (point)))
-
- ;; Narrow and do the fill.
- (save-restriction
- (narrow-to-region p-start p-end)
- (fill-paragraph ignore)))))
- t)
-
-(defun tcl-do-auto-fill ()
- "Auto-fill function for Tcl mode. Only auto-fills in a comment."
- (if (> (current-column) fill-column)
- (let ((fill-prefix "# ")
- in-comment col)
- (save-excursion
- (setq in-comment (tcl-in-comment))
- (if in-comment
- (setq col (1- (current-column)))))
- (if in-comment
- (progn
- (do-auto-fill)
- (save-excursion
- (back-to-indentation)
- (delete-region (point) (line-beginning-position))
- (indent-to-column col)))))))
-
\f
;;
(if and-go (switch-to-tcl t)))))))
(defun tcl-auto-fill-mode (&optional arg)
- "Like `auto-fill-mode', but controls filling of Tcl comments."
+ "Like `auto-fill-mode', but sets `comment-auto-fill-only-comments'."
(interactive "P")
- ;; Following code taken from "auto-fill-mode" (simple.el).
- (prog1
- (setq auto-fill-function
- (if (if (null arg)
- (not auto-fill-function)
- (> (prefix-numeric-value arg) 0))
- 'tcl-do-auto-fill
- nil))
- (force-mode-line-update)))
+ (auto-fill-mode arg)
+ (if auto-fill-function
+ (set (make-local-variable 'comment-auto-fill-only-comments) t)
+ (kill-local-variable 'comment-auto-fill-only-comments)))
(defun tcl-electric-hash (&optional count)
"Insert a `#' and quote if it does not start a real comment.
(unless (or (bolp) (tcl-real-command-p))
(insert ";")
;; Try and erase a non-significant char to keep charpos identical.
- (if (memq (char-after) '(?\t ?\ )) (delete-char 1))))
+ (if (memq (char-after) '(?\t ?\s)) (delete-char 1))))
(funcall (default-value 'comment-indent-function)))
;; The following was inspired by the Tcl editing mode written by
(defun tcl-quote (string)
"Quote STRING according to Tcl rules."
(mapconcat (lambda (char)
- (if (memq char '(?[ ?] ?{ ?} ?\\ ?\" ?$ ? ?\;))
+ (if (memq char '(?[ ?] ?{ ?} ?\\ ?\" ?$ ?\s ?\;))
(concat "\\" (char-to-string char))
(char-to-string char)))
string ""))
(provide 'tcl)
+;; arch-tag: 8a032554-c3ef-422e-b84c-acec0522179d
;;; tcl.el ends here