(set (make-local-variable 'add-log-current-defun-function)
'tcl-add-log-defun)
+ (setq-local beginning-of-defun-function #'tcl-beginning-of-defun-function)
+ (setq-local end-of-defun-function #'tcl-end-of-defun-function)
+
(easy-menu-add tcl-mode-menu)
;; Append Tcl menu to popup menu for XEmacs.
(if (boundp 'mode-popup-menu)
;; Interfaces to other packages.
;;
-;; FIXME Definition of function is very ad-hoc. Should use
-;; beginning-of-defun. Also has incestuous knowledge about the
-;; format of tcl-proc-regexp.
+(defun tcl-beginning-of-defun-function (&optional arg)
+ "`beginning-of-defun-function' for Tcl mode."
+ (when (or (not arg) (= arg 0))
+ (setq arg 1))
+ (let* ((search-fn (if (> arg 0)
+ ;; Positive arg means to search backward.
+ #'re-search-backward
+ #'re-search-forward))
+ (arg (abs arg))
+ (result t))
+ (while (and (> arg 0) result)
+ (unless (funcall search-fn tcl-proc-regexp nil t)
+ (setq result nil))
+ (setq arg (1- arg)))
+ result))
+
+(defun tcl-end-of-defun-function ()
+ "`end-of-defun-function' for Tcl mode."
+ ;; Because we let users redefine tcl-proc-list, we don't really know
+ ;; too much about the exact arguments passed to the "proc"-defining
+ ;; command. Instead we just skip words and lists until we see
+ ;; either a ";" or a newline, either of which terminates a command.
+ (skip-syntax-forward "-")
+ (while (and (not (eobp))
+ (not (looking-at-p "[\n;]")))
+ (condition-case nil
+ (forward-sexp)
+ (scan-error
+ (goto-char (point-max))))
+ ;; Note that here we do not want to skip \n.
+ (skip-chars-forward " \t")))
+
(defun tcl-add-log-defun ()
"Return name of Tcl function point is in, or nil."
(save-excursion
- (end-of-line)
- (if (re-search-backward (concat tcl-proc-regexp "\\([^ \t\n{]+\\)") nil t)
- (match-string 2))))
+ (let ((orig-point (point)))
+ (when (beginning-of-defun)
+ ;; Only return the name when in the body of the function.
+ (when (save-excursion
+ (end-of-defun)
+ (>= (point) orig-point))
+ (when (looking-at (concat tcl-proc-regexp "\\([^ \t\n{]+\\)"))
+ (match-string 2)))))))
(defun tcl-outline-level ()
(save-excursion
--- /dev/null
+;;; tcl-tests.el --- Test suite for tcl-mode
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'tcl)
+
+;; From bug#23565
+(ert-deftest tcl-mode-beginning-of-defun-1 ()
+ (with-temp-buffer
+ (tcl-mode)
+ (insert "proc bad {{value \"\"}} {\n # do something\n}")
+ (should (beginning-of-defun))
+ (should (= (point) (point-min)))
+ (end-of-defun)
+ (should (= (point) (point-max)))))
+
+;; From bug#23565
+(ert-deftest tcl-mode-beginning-of-defun-2 ()
+ (with-temp-buffer
+ (tcl-mode)
+ (insert "proc good {{value}} {\n # do something\n}")
+ (should (beginning-of-defun))
+ (should (= (point) (point-min)))
+ (end-of-defun)
+ (should (= (point) (point-max)))))
+
+(ert-deftest tcl-mode-function-name ()
+ (with-temp-buffer
+ (tcl-mode)
+ (insert "proc notinthis {} {\n # nothing\n}\n\n")
+ (should-not (add-log-current-defun))))
+
+(ert-deftest tcl-mode-function-name ()
+ (with-temp-buffer
+ (tcl-mode)
+ (insert "proc simple {} {\n # nothing\n}")
+ (backward-char 3)
+ (should (equal "simple" (add-log-current-defun)))))
+
+(ert-deftest tcl-mode-function-name ()
+ (with-temp-buffer
+ (tcl-mode)
+ (insert "proc inthis {} {\n # nothing\n")
+ (should (equal "inthis" (add-log-current-defun)))))
+
+(provide 'tcl-tests)
+
+;;; tcl-tests.el ends here