summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChong Yidong <cyd@stupidchicken.com>2006-12-17 22:56:39 +0000
committerChong Yidong <cyd@stupidchicken.com>2006-12-17 22:56:39 +0000
commit4df5698c017b846ad326cbe83b09a2859476ba96 (patch)
tree17c01421053f1c0aaa7b530134795ec768cea61d
parent76f38b63b7c4f9b4fadfc5a12eab402804c962a2 (diff)
downloademacs-4df5698c017b846ad326cbe83b09a2859476ba96.tar.gz
(beginning-of-defun-raw): Optimise (for speed) the case when
open-paren-in-column-0-is-defun-start is nil. Based on code by Martin Rudalics.
-rw-r--r--lisp/emacs-lisp/lisp.el103
1 files changed, 61 insertions, 42 deletions
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 6e06e4a067b..895bec256d4 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -185,13 +185,18 @@ With ARG, do it that many times. Negative arg -N
means move forward to Nth following beginning of defun.
Returns t unless search stops due to beginning or end of buffer.
-Normally a defun starts when there is a char with open-parenthesis
-syntax at the beginning of a line. If `defun-prompt-regexp' is
-non-nil, then a string which matches that regexp may precede the
-open-parenthesis, and point ends up at the beginning of the line.
-
If variable `beginning-of-defun-function' is non-nil, its value
-is called as a function to find the defun's beginning."
+is called as a function to find the defun's beginning.
+
+Normally a defun is assumed to start where there is a char with
+open-parenthesis syntax at the beginning of a line. If
+`defun-prompt-regexp' is non-nil, then a string which matches
+that regexp may precede the open-parenthesis, and point ends up
+at the beginning of the line.
+
+If `defun-prompt-regexp' and `open-paren-in-column-0-is-defun-start'
+are both nil, the function instead finds an open-paren at the
+outermost level."
(interactive "p")
(or (not (eq this-command 'beginning-of-defun))
(eq last-command 'beginning-of-defun)
@@ -208,9 +213,9 @@ is non-nil.
If variable `beginning-of-defun-function' is non-nil, its value
is called as a function to find the defun's beginning."
- (interactive "p") ; change this to "P", maybe, if we ever come to pass ARG
- ; to beginning-of-defun-function.
- (unless arg (setq arg 1)) ; The call might not be interactive.
+ (interactive "p") ; change this to "P", maybe, if we ever come to pass ARG
+ ; to beginning-of-defun-function.
+ (unless arg (setq arg 1))
(cond
(beginning-of-defun-function
(if (> arg 0)
@@ -230,42 +235,56 @@ is called as a function to find the defun's beginning."
nil 'move arg)
(progn (goto-char (1- (match-end 0)))) t))
+ ;; If open-paren-in-column-0-is-defun-start and defun-prompt-regexp
+ ;; are both nil, column 0 has no significance - so scan forward
+ ;; from BOB to see how nested point is, then carry on from there.
+ ;;
+ ;; It is generally not a good idea to land up here, because the
+ ;; call to scan-lists below can be extremely slow. This is because
+ ;; back_comment in syntax.c may have to scan from bob to find the
+ ;; beginning of each comment. Fixing this is not trivial -- cyd.
+
+ ((eq arg 0))
(t
- ;; Column 0 has no significance - so scan forward from BOB to see how
- ;; nested point is, then carry on from there.
- (let* ((floor (point-min))
- (ceiling (point-max))
- (pps-state (let (syntax-begin-function
- font-lock-beginning-of-syntax-function)
- (syntax-ppss)))
- (nesting-depth (nth 0 pps-state)))
+ (let ((floor (point-min))
+ (ceiling (point-max))
+ (arg-+ve (> arg 0)))
(save-restriction
(widen)
- ;; Get outside of any string or comment.
- (if (nth 8 pps-state)
- (goto-char (nth 8 pps-state)))
-
- (cond
- ((> arg 0)
- (when (> nesting-depth 0)
- (up-list (- nesting-depth))
- (setq arg (1- arg)))
- ;; We're now outside of any defun.
- (backward-list arg)
- (if (< (point) floor) (goto-char floor)))
-
- ((< arg 0)
- (cond
- ((> nesting-depth 0)
- (up-list nesting-depth)
- (setq arg (1+ arg)))
- ((not (looking-at "\\s("))
- ;; We're between defuns, and not at the start of one.
- (setq arg (1+ arg))))
- (forward-list (- arg))
- (down-list)
- (backward-char)
- (if (> (point) ceiling) (goto-char ceiling)))))))))
+ (let ((ppss (let (syntax-begin-function
+ font-lock-beginning-of-syntax-function)
+ (syntax-ppss)))
+ ;; position of least enclosing paren, or nil.
+ encl-pos)
+ ;; Back out of any comment/string, so that encl-pos will always
+ ;; become nil if we're at top-level.
+ (when (nth 8 ppss)
+ (goto-char (nth 8 ppss))
+ (setq ppss (syntax-ppss))) ; should be fast, due to cache.
+ (setq encl-pos (syntax-ppss-toplevel-pos ppss))
+ (if encl-pos (goto-char encl-pos))
+
+ (and encl-pos arg-+ve (setq arg (1- arg)))
+ (and (not encl-pos) (not arg-+ve) (not (looking-at "\\s("))
+ (setq arg (1+ arg)))
+
+ (condition-case nil ; to catch crazy parens.
+ (progn
+ (goto-char (scan-lists (point) (- arg) 0))
+ (if arg-+ve
+ (if (>= (point) floor)
+ t
+ (goto-char floor)
+ nil)
+ ;; forward to next (, or trigger the c-c
+ (goto-char (1- (scan-lists (point) 1 -1)))
+ (if (<= (point) ceiling)
+ t
+ (goto-char ceiling)
+ nil)))
+ (error
+ (goto-char (if arg-+ve floor ceiling))
+ nil))))))))
(defvar end-of-defun-function nil
"If non-nil, function for function `end-of-defun' to call.