]> git.eshelyaron.com Git - emacs.git/commitdiff
* progmodes/python.el: Enhancements to forward-sexp.
authorFabián Ezequiel Gallina <fgallina@gnu.org>
Thu, 9 Aug 2012 03:30:37 +0000 (00:30 -0300)
committerFabián Ezequiel Gallina <fgallina@gnu.org>
Thu, 9 Aug 2012 03:30:37 +0000 (00:30 -0300)
(python-nav-forward-sexp): Rename from
python-nav-forward-sexp-function.
(python-nav--forward-sexp, python-nav--backward-sexp): New
functions.

lisp/ChangeLog
lisp/progmodes/python.el

index 5ccb2b66734d8a96ae897de228d315f575dc0c89..1a30da26fc6a136ac08531d9836e232155c6ec40 100644 (file)
@@ -1,3 +1,11 @@
+2012-08-09  Fabián Ezequiel Gallina  <fgallina@cuca>
+
+       * progmodes/python.el: Enhancements to forward-sexp.
+       (python-nav-forward-sexp): Rename from
+       python-nav-forward-sexp-function.
+       (python-nav--forward-sexp, python-nav--backward-sexp): New
+       functions.
+
 2012-08-09  Jay Belanger  <jay.p.belanger@gmail.com>
 
        * calc/calc-menu.el (calc-modes-menu): Add entries for matrix
index 58d984f8d4d03c320e17736074908fcbff015d55..c65f2a2d5953a17e0608496c78761abeb1ffd77a 100644 (file)
@@ -54,7 +54,7 @@
 ;; `python-nav-beginning-of-statement', `python-nav-end-of-statement',
 ;; `python-nav-beginning-of-block' and `python-nav-end-of-block' are
 ;; included but no bound to any key.  At last but not least the
-;; specialized `python-nav-forward-sexp-function' allows easy
+;; specialized `python-nav-forward-sexp' allows easy
 ;; navigation between code blocks.
 
 ;; Shell interaction: is provided and allows you to execute easily any
@@ -1249,83 +1249,178 @@ backward to previous block."
         (and (goto-char starting-pos) nil)
       (and (not (= (point) starting-pos)) (point-marker)))))
 
-(defun python-nav-forward-sexp-function (&optional arg)
+(defun python-nav-lisp-forward-sexp-safe (&optional arg)
+  "Safe version of standard `forward-sexp'.
+When ARG > 0 move forward, else if ARG is < 0."
+  (or arg (setq arg 1))
+  (let ((forward-sexp-function nil)
+        (paren-regexp
+         (if (> arg 0) (python-rx close-paren) (python-rx open-paren)))
+        (search-fn
+         (if (> arg 0) #'re-search-forward #'re-search-backward)))
+    (condition-case nil
+        (forward-sexp arg)
+      (error
+       (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--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)))))))))
+
+(defun python-nav-forward-sexp (&optional arg)
   "Move forward across one block of code.
 With ARG, do it that many times.  Negative arg -N means
 move backward N times."
   (interactive "^p")
   (or arg (setq arg 1))
   (while (> arg 0)
-    (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)
-             (python-nav-forward-block))
-            ((= (point) block-starting-pos)
-             (if (or (not next-block-starting-pos)
-                     (< block-ending-pos next-block-starting-pos))
-                 (python-nav-end-of-block)
-               (python-nav-forward-block)))
-            ((= block-ending-pos (point))
-             (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)))
-                   (goto-char parent-block-end-pos)
-                 (python-nav-forward-block))))
-            (t (python-nav-end-of-block))))
-      (setq arg (1- arg)))
+    (python-nav--forward-sexp)
+    (setq arg (1- arg)))
   (while (< arg 0)
-    (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)))))
-      (cond ((not block-ending-pos)
-             (and (python-nav-backward-block)
-                  (python-nav-end-of-block)))
-            ((= (point) block-ending-pos)
-             (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)
-             (python-nav-end-of-block))
-            ((= (point) block-starting-pos)
-             (if (not (> (point) (or prev-block-ending-pos (point))))
-                 (python-nav-backward-block)
-               (goto-char prev-block-ending-pos)
-               (let ((parent-block-ending-pos
-                      (save-excursion
-                        (python-nav-forward-sexp-function)
-                        (and (not (looking-at (python-rx block-start)))
-                             (point)))))
-                 (when (and parent-block-ending-pos
-                            (> parent-block-ending-pos prev-block-ending-pos))
-                   (goto-char parent-block-ending-pos)))))
-            (t (python-nav-beginning-of-block))))
+    (python-nav--backward-sexp)
     (setq arg (1+ arg))))
 
 \f
@@ -2848,7 +2943,7 @@ if that value is non-nil."
   (set (make-local-variable 'parse-sexp-ignore-comments) t)
 
   (set (make-local-variable 'forward-sexp-function)
-       'python-nav-forward-sexp-function)
+       'python-nav-forward-sexp)
 
   (set (make-local-variable 'font-lock-defaults)
        '(python-font-lock-keywords nil nil nil nil))