mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-15 10:30:25 -08:00
Enhancements on forward-sexp movement.
* progmodes/python.el (python-nav-beginning-of-statement) (python-nav-end-of-statement): Return point-marker. (python-nav-forward-sexp): lisp-like forward-sexp behavior. (python-info-current-symbol) (python-info-statement-starts-block-p): Rename from python-info-beginning-of-block-p. (python-info-statement-ends-block-p): Rename from python-info-end-of-block-p. (python-info-beginning-of-statement-p) (python-info-end-of-statement-p) (python-info-beginning-of-block-p, python-info-end-of-block-p): New functions.
This commit is contained in:
parent
5acd2b3ece
commit
8dbce54cc7
2 changed files with 147 additions and 145 deletions
|
|
@ -1,3 +1,19 @@
|
|||
2012-10-08 Fabián Ezequiel Gallina <fgallina@cuca>
|
||||
|
||||
Enhancements on forward-sexp movement.
|
||||
* progmodes/python.el (python-nav-beginning-of-statement)
|
||||
(python-nav-end-of-statement): Return point-marker.
|
||||
(python-nav-forward-sexp): lisp-like forward-sexp behavior.
|
||||
(python-info-current-symbol)
|
||||
(python-info-statement-starts-block-p): Rename from
|
||||
python-info-beginning-of-block-p.
|
||||
(python-info-statement-ends-block-p): Rename from
|
||||
python-info-end-of-block-p.
|
||||
(python-info-beginning-of-statement-p)
|
||||
(python-info-end-of-statement-p)
|
||||
(python-info-beginning-of-block-p, python-info-end-of-block-p):
|
||||
New functions.
|
||||
|
||||
2012-10-08 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||
|
||||
* comint.el (comint-preinput-scroll-to-bottom): Preserve the
|
||||
|
|
|
|||
|
|
@ -1169,7 +1169,8 @@ Returns nil if point is not in a def or class."
|
|||
(python-info-line-ends-backslash-p))
|
||||
(python-syntax-context 'string)
|
||||
(python-syntax-context 'paren))
|
||||
(forward-line -1)))))
|
||||
(forward-line -1))))
|
||||
(point-marker))
|
||||
|
||||
(defun python-nav-end-of-statement ()
|
||||
"Move to end of current statement."
|
||||
|
|
@ -1180,7 +1181,8 @@ Returns nil if point is not in a def or class."
|
|||
(python-info-line-ends-backslash-p)
|
||||
(python-syntax-context 'string)
|
||||
(python-syntax-context 'paren))
|
||||
(forward-line 1)))))
|
||||
(forward-line 1))))
|
||||
(point-marker))
|
||||
|
||||
(defun python-nav-backward-statement (&optional arg)
|
||||
"Move backward to previous statement.
|
||||
|
|
@ -1295,151 +1297,104 @@ When ARG > 0 move forward, else if ARG is < 0."
|
|||
(while (and (funcall search-fn paren-regexp nil t)
|
||||
(python-syntax-context 'paren)))))))
|
||||
|
||||
(defun python-nav--forward-sexp ()
|
||||
"Move to forward sexp."
|
||||
(case (python-syntax-context-type)
|
||||
(string
|
||||
;; Inside of a string, get out of it.
|
||||
(while (and (re-search-forward "[\"']" nil t)
|
||||
(python-syntax-context 'string))))
|
||||
(comment
|
||||
;; Inside of a comment, just move forward.
|
||||
(python-util-forward-comment))
|
||||
(paren
|
||||
(python-nav-lisp-forward-sexp-safe 1))
|
||||
(t
|
||||
(if (and (not (eobp))
|
||||
(= (syntax-class (syntax-after (point))) 4))
|
||||
;; Looking an open-paren
|
||||
(python-nav-lisp-forward-sexp-safe 1)
|
||||
(let ((block-starting-pos
|
||||
(save-excursion (python-nav-beginning-of-block)))
|
||||
(block-ending-pos
|
||||
(save-excursion (python-nav-end-of-block)))
|
||||
(next-block-starting-pos
|
||||
(save-excursion (python-nav-forward-block))))
|
||||
(cond
|
||||
((not block-starting-pos)
|
||||
;; Not inside a block, move to closest one.
|
||||
(and next-block-starting-pos
|
||||
(goto-char next-block-starting-pos)))
|
||||
((= (point) block-starting-pos)
|
||||
;; Point is at beginning of block
|
||||
(if (and next-block-starting-pos
|
||||
(< next-block-starting-pos block-ending-pos))
|
||||
;; Beginning of next block is closer than current's
|
||||
;; end, move to it.
|
||||
(goto-char next-block-starting-pos)
|
||||
(goto-char block-ending-pos)))
|
||||
((= block-ending-pos (point))
|
||||
;; Point is at end of current block
|
||||
(let ((parent-block-end-pos
|
||||
(save-excursion
|
||||
(python-util-forward-comment)
|
||||
(python-nav-beginning-of-block)
|
||||
(python-nav-end-of-block))))
|
||||
(if (and parent-block-end-pos
|
||||
(or (not next-block-starting-pos)
|
||||
(> next-block-starting-pos parent-block-end-pos)))
|
||||
;; If the parent block ends before next block
|
||||
;; starts move to it.
|
||||
(goto-char parent-block-end-pos)
|
||||
(and next-block-starting-pos
|
||||
(goto-char next-block-starting-pos)))))
|
||||
(t (python-nav-end-of-block))))))))
|
||||
(defun python-nav--forward-sexp (&optional dir)
|
||||
"Move to forward sexp.
|
||||
With positive Optional argument DIR direction move forward, else
|
||||
backwards."
|
||||
(setq dir (or dir 1))
|
||||
(unless (= dir 0)
|
||||
(let* ((forward-p (if (> dir 0)
|
||||
(and (setq dir 1) t)
|
||||
(and (setq dir -1) nil)))
|
||||
(re-search-fn (if forward-p
|
||||
're-search-forward
|
||||
're-search-backward))
|
||||
(context-type (python-syntax-context-type)))
|
||||
(cond
|
||||
((eq context-type 'string)
|
||||
;; Inside of a string, get out of it.
|
||||
(while (and (funcall re-search-fn "[\"']" nil t)
|
||||
(python-syntax-context 'string))))
|
||||
((eq context-type 'comment)
|
||||
;; Inside of a comment, just move forward.
|
||||
(python-util-forward-comment dir))
|
||||
((or (eq context-type 'paren)
|
||||
(and forward-p (looking-at (python-rx open-paren)))
|
||||
(and (not forward-p)
|
||||
(eq (syntax-class (syntax-after (1- (point))))
|
||||
(car (string-to-syntax ")")))))
|
||||
;; Inside a paren or looking at it, lisp knows what to do.
|
||||
(python-nav-lisp-forward-sexp-safe dir))
|
||||
(t
|
||||
;; This part handles the lispy feel of
|
||||
;; `python-nav-forward-sexp'. Knowing everything about the
|
||||
;; current context and the context of the next sexp tries to
|
||||
;; follow the lisp sexp motion commands in a symmetric manner.
|
||||
(let* ((context
|
||||
(cond
|
||||
((python-info-beginning-of-block-p) 'block-start)
|
||||
((python-info-end-of-block-p) 'block-end)
|
||||
((python-info-beginning-of-statement-p) 'statement-start)
|
||||
((python-info-end-of-statement-p) 'statement-end)))
|
||||
(next-sexp-pos
|
||||
(save-excursion
|
||||
(python-nav-lisp-forward-sexp-safe dir)
|
||||
(point)))
|
||||
(next-sexp-context
|
||||
(save-excursion
|
||||
(goto-char next-sexp-pos)
|
||||
(cond
|
||||
((python-info-beginning-of-block-p) 'block-start)
|
||||
((python-info-end-of-block-p) 'block-end)
|
||||
((python-info-beginning-of-statement-p) 'statement-start)
|
||||
((python-info-end-of-statement-p) 'statement-end)
|
||||
((python-info-statement-starts-block-p) 'starts-block)
|
||||
((python-info-statement-ends-block-p) 'ends-block)))))
|
||||
(if forward-p
|
||||
(cond ((and (not (eobp))
|
||||
(python-info-current-line-empty-p))
|
||||
(python-util-forward-comment dir)
|
||||
(python-nav--forward-sexp dir))
|
||||
((eq context 'block-start)
|
||||
(python-nav-end-of-block))
|
||||
((eq context 'statement-start)
|
||||
(python-nav-end-of-statement))
|
||||
((and (memq context '(statement-end block-end))
|
||||
(eq next-sexp-context 'ends-block))
|
||||
(goto-char next-sexp-pos)
|
||||
(python-nav-end-of-block))
|
||||
((and (memq context '(statement-end block-end))
|
||||
(eq next-sexp-context 'starts-block))
|
||||
(goto-char next-sexp-pos)
|
||||
(python-nav-end-of-block))
|
||||
((memq context '(statement-end block-end))
|
||||
(goto-char next-sexp-pos)
|
||||
(python-nav-end-of-statement))
|
||||
(t (goto-char next-sexp-pos)))
|
||||
(cond ((and (not (bobp))
|
||||
(python-info-current-line-empty-p))
|
||||
(python-util-forward-comment dir)
|
||||
(python-nav--forward-sexp dir))
|
||||
((eq context 'block-end)
|
||||
(python-nav-beginning-of-block))
|
||||
((eq context 'statement-end)
|
||||
(python-nav-beginning-of-statement))
|
||||
((and (memq context '(statement-start block-start))
|
||||
(eq next-sexp-context 'starts-block))
|
||||
(goto-char next-sexp-pos)
|
||||
(python-nav-beginning-of-block))
|
||||
((and (memq context '(statement-start block-start))
|
||||
(eq next-sexp-context 'ends-block))
|
||||
(goto-char next-sexp-pos)
|
||||
(python-nav-beginning-of-block))
|
||||
((memq context '(statement-start block-start))
|
||||
(goto-char next-sexp-pos)
|
||||
(python-nav-beginning-of-statement))
|
||||
(t (goto-char next-sexp-pos))))))))))
|
||||
|
||||
(defun python-nav--backward-sexp ()
|
||||
"Move to backward sexp."
|
||||
(case (python-syntax-context-type)
|
||||
(string
|
||||
;; Inside of a string, get out of it.
|
||||
(while (and (re-search-backward "[\"']" nil t)
|
||||
(python-syntax-context 'string))))
|
||||
(comment
|
||||
;; Inside of a comment, just move backward.
|
||||
(python-util-forward-comment -1))
|
||||
(paren
|
||||
;; Handle parens like we are lisp.
|
||||
(python-nav-lisp-forward-sexp-safe -1))
|
||||
(t
|
||||
(let* ((block-starting-pos
|
||||
(save-excursion (python-nav-beginning-of-block)))
|
||||
(block-ending-pos
|
||||
(save-excursion (python-nav-end-of-block)))
|
||||
(prev-block-ending-pos
|
||||
(save-excursion (when (python-nav-backward-block)
|
||||
(python-nav-end-of-block))))
|
||||
(prev-block-parent-ending-pos
|
||||
(save-excursion
|
||||
(when prev-block-ending-pos
|
||||
(goto-char prev-block-ending-pos)
|
||||
(python-util-forward-comment)
|
||||
(python-nav-beginning-of-block)
|
||||
(python-nav-end-of-block)))))
|
||||
(if (and (not (bobp))
|
||||
(= (syntax-class (syntax-after (1- (point)))) 5))
|
||||
;; Char before point is a paren closing char, handle it
|
||||
;; like we are lisp.
|
||||
(python-nav-lisp-forward-sexp-safe -1)
|
||||
(cond
|
||||
((not block-ending-pos)
|
||||
;; Not in and ending pos, move to end of previous block.
|
||||
(and (python-nav-backward-block)
|
||||
(python-nav-end-of-block)))
|
||||
((= (point) block-ending-pos)
|
||||
;; In ending pos, we need to search backwards for the
|
||||
;; closest point looking the list of candidates from here.
|
||||
(let ((candidates))
|
||||
(dolist (name
|
||||
'(prev-block-parent-ending-pos
|
||||
prev-block-ending-pos
|
||||
block-ending-pos
|
||||
block-starting-pos))
|
||||
(when (and (symbol-value name)
|
||||
(< (symbol-value name) (point)))
|
||||
(add-to-list 'candidates (symbol-value name))))
|
||||
(goto-char (apply 'max candidates))))
|
||||
((> (point) block-ending-pos)
|
||||
;; After an ending position, move to it.
|
||||
(goto-char block-ending-pos))
|
||||
((= (point) block-starting-pos)
|
||||
;; On a block starting position.
|
||||
(if (not (> (point) (or prev-block-ending-pos (point))))
|
||||
;; Point is after the end position of the block that
|
||||
;; wraps the current one, just move a block backward.
|
||||
(python-nav-backward-block)
|
||||
;; If we got here we are facing a case like this one:
|
||||
;;
|
||||
;; try:
|
||||
;; return here()
|
||||
;; except Exception as e:
|
||||
;;
|
||||
;; Where point is on the "except" and must move to the
|
||||
;; end of "here()".
|
||||
(goto-char prev-block-ending-pos)
|
||||
(let ((parent-block-ending-pos
|
||||
(save-excursion
|
||||
(python-nav-forward-sexp)
|
||||
(and (not (looking-at (python-rx block-start)))
|
||||
(point)))))
|
||||
(when (and parent-block-ending-pos
|
||||
(> parent-block-ending-pos prev-block-ending-pos))
|
||||
;; If we got here we are facing a case like this one:
|
||||
;;
|
||||
;; except ImportError:
|
||||
;; if predicate():
|
||||
;; processing()
|
||||
;; here()
|
||||
;; except AttributeError:
|
||||
;;
|
||||
;; Where point is on the "except" and must move to
|
||||
;; the end of "here()". Without this extra step we'd
|
||||
;; just get to the end of processing().
|
||||
(goto-char parent-block-ending-pos)))))
|
||||
(t
|
||||
(if (and prev-block-ending-pos (< prev-block-ending-pos (point)))
|
||||
(goto-char prev-block-ending-pos)
|
||||
(python-nav-beginning-of-block)))))))))
|
||||
(python-nav--forward-sexp -1))
|
||||
|
||||
(defun python-nav-forward-sexp (&optional arg)
|
||||
"Move forward across one block of code.
|
||||
|
|
@ -2891,12 +2846,43 @@ parent defun name."
|
|||
".") ".")
|
||||
name)))))))
|
||||
|
||||
(defsubst python-info-beginning-of-block-statement-p ()
|
||||
(defun python-info-statement-starts-block-p ()
|
||||
"Return non-nil if current statement opens a block."
|
||||
(save-excursion
|
||||
(python-nav-beginning-of-statement)
|
||||
(looking-at (python-rx block-start))))
|
||||
|
||||
(defun python-info-statement-ends-block-p ()
|
||||
"Return non-nil if point is at end of block."
|
||||
(let ((end-of-block-pos (save-excursion
|
||||
(python-nav-end-of-block)))
|
||||
(end-of-statement-pos (save-excursion
|
||||
(python-nav-end-of-statement))))
|
||||
(and end-of-block-pos end-of-statement-pos
|
||||
(= end-of-block-pos end-of-statement-pos))))
|
||||
|
||||
(defun python-info-beginning-of-statement-p ()
|
||||
"Return non-nil if point is at beginning of statement."
|
||||
(= (point) (save-excursion
|
||||
(python-nav-beginning-of-statement)
|
||||
(point))))
|
||||
|
||||
(defun python-info-end-of-statement-p ()
|
||||
"Return non-nil if point is at end of statement."
|
||||
(= (point) (save-excursion
|
||||
(python-nav-end-of-statement)
|
||||
(point))))
|
||||
|
||||
(defun python-info-beginning-of-block-p ()
|
||||
"Return non-nil if point is at beginning of block."
|
||||
(and (python-info-beginning-of-statement-p)
|
||||
(python-info-statement-starts-block-p)))
|
||||
|
||||
(defun python-info-end-of-block-p ()
|
||||
"Return non-nil if point is at end of block."
|
||||
(and (python-info-end-of-statement-p)
|
||||
(python-info-statement-ends-block-p)))
|
||||
|
||||
(defun python-info-closing-block ()
|
||||
"Return the point of the block the current line closes."
|
||||
(let ((closing-word (save-excursion
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue