aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
authorFabián Ezequiel Gallina2012-10-08 02:19:15 -0300
committerFabián Ezequiel Gallina2012-10-08 02:19:15 -0300
commit8dbce54cc73d16375b8d233da7271054eb4cda34 (patch)
tree05b17501a782d7a8af4ad0a8116e7511084b1731 /lisp/progmodes/python.el
parent5acd2b3ece740bbe487e9474f30665317db6f190 (diff)
downloademacs-8dbce54cc73d16375b8d233da7271054eb4cda34.tar.gz
emacs-8dbce54cc73d16375b8d233da7271054eb4cda34.zip
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.
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el276
1 files changed, 131 insertions, 145 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index ffb2e66ca9d..6b0dc954ca7 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -1169,7 +1169,8 @@ Returns nil if point is not in a def or class."
1169 (python-info-line-ends-backslash-p)) 1169 (python-info-line-ends-backslash-p))
1170 (python-syntax-context 'string) 1170 (python-syntax-context 'string)
1171 (python-syntax-context 'paren)) 1171 (python-syntax-context 'paren))
1172 (forward-line -1))))) 1172 (forward-line -1))))
1173 (point-marker))
1173 1174
1174(defun python-nav-end-of-statement () 1175(defun python-nav-end-of-statement ()
1175 "Move to end of current statement." 1176 "Move to end of current statement."
@@ -1180,7 +1181,8 @@ Returns nil if point is not in a def or class."
1180 (python-info-line-ends-backslash-p) 1181 (python-info-line-ends-backslash-p)
1181 (python-syntax-context 'string) 1182 (python-syntax-context 'string)
1182 (python-syntax-context 'paren)) 1183 (python-syntax-context 'paren))
1183 (forward-line 1))))) 1184 (forward-line 1))))
1185 (point-marker))
1184 1186
1185(defun python-nav-backward-statement (&optional arg) 1187(defun python-nav-backward-statement (&optional arg)
1186 "Move backward to previous statement. 1188 "Move backward to previous statement.
@@ -1295,151 +1297,104 @@ When ARG > 0 move forward, else if ARG is < 0."
1295 (while (and (funcall search-fn paren-regexp nil t) 1297 (while (and (funcall search-fn paren-regexp nil t)
1296 (python-syntax-context 'paren))))))) 1298 (python-syntax-context 'paren)))))))
1297 1299
1298(defun python-nav--forward-sexp () 1300(defun python-nav--forward-sexp (&optional dir)
1299 "Move to forward sexp." 1301 "Move to forward sexp.
1300 (case (python-syntax-context-type) 1302With positive Optional argument DIR direction move forward, else
1301 (string 1303backwards."
1302 ;; Inside of a string, get out of it. 1304 (setq dir (or dir 1))
1303 (while (and (re-search-forward "[\"']" nil t) 1305 (unless (= dir 0)
1304 (python-syntax-context 'string)))) 1306 (let* ((forward-p (if (> dir 0)
1305 (comment 1307 (and (setq dir 1) t)
1306 ;; Inside of a comment, just move forward. 1308 (and (setq dir -1) nil)))
1307 (python-util-forward-comment)) 1309 (re-search-fn (if forward-p
1308 (paren 1310 're-search-forward
1309 (python-nav-lisp-forward-sexp-safe 1)) 1311 're-search-backward))
1310 (t 1312 (context-type (python-syntax-context-type)))
1311 (if (and (not (eobp)) 1313 (cond
1312 (= (syntax-class (syntax-after (point))) 4)) 1314 ((eq context-type 'string)
1313 ;; Looking an open-paren 1315 ;; Inside of a string, get out of it.
1314 (python-nav-lisp-forward-sexp-safe 1) 1316 (while (and (funcall re-search-fn "[\"']" nil t)
1315 (let ((block-starting-pos 1317 (python-syntax-context 'string))))
1316 (save-excursion (python-nav-beginning-of-block))) 1318 ((eq context-type 'comment)
1317 (block-ending-pos 1319 ;; Inside of a comment, just move forward.
1318 (save-excursion (python-nav-end-of-block))) 1320 (python-util-forward-comment dir))
1319 (next-block-starting-pos 1321 ((or (eq context-type 'paren)
1320 (save-excursion (python-nav-forward-block)))) 1322 (and forward-p (looking-at (python-rx open-paren)))
1321 (cond 1323 (and (not forward-p)
1322 ((not block-starting-pos) 1324 (eq (syntax-class (syntax-after (1- (point))))
1323 ;; Not inside a block, move to closest one. 1325 (car (string-to-syntax ")")))))
1324 (and next-block-starting-pos 1326 ;; Inside a paren or looking at it, lisp knows what to do.
1325 (goto-char next-block-starting-pos))) 1327 (python-nav-lisp-forward-sexp-safe dir))
1326 ((= (point) block-starting-pos) 1328 (t
1327 ;; Point is at beginning of block 1329 ;; This part handles the lispy feel of
1328 (if (and next-block-starting-pos 1330 ;; `python-nav-forward-sexp'. Knowing everything about the
1329 (< next-block-starting-pos block-ending-pos)) 1331 ;; current context and the context of the next sexp tries to
1330 ;; Beginning of next block is closer than current's 1332 ;; follow the lisp sexp motion commands in a symmetric manner.
1331 ;; end, move to it. 1333 (let* ((context
1332 (goto-char next-block-starting-pos) 1334 (cond
1333 (goto-char block-ending-pos))) 1335 ((python-info-beginning-of-block-p) 'block-start)
1334 ((= block-ending-pos (point)) 1336 ((python-info-end-of-block-p) 'block-end)
1335 ;; Point is at end of current block 1337 ((python-info-beginning-of-statement-p) 'statement-start)
1336 (let ((parent-block-end-pos 1338 ((python-info-end-of-statement-p) 'statement-end)))
1337 (save-excursion 1339 (next-sexp-pos
1338 (python-util-forward-comment) 1340 (save-excursion
1339 (python-nav-beginning-of-block) 1341 (python-nav-lisp-forward-sexp-safe dir)
1340 (python-nav-end-of-block)))) 1342 (point)))
1341 (if (and parent-block-end-pos 1343 (next-sexp-context
1342 (or (not next-block-starting-pos) 1344 (save-excursion
1343 (> next-block-starting-pos parent-block-end-pos))) 1345 (goto-char next-sexp-pos)
1344 ;; If the parent block ends before next block 1346 (cond
1345 ;; starts move to it. 1347 ((python-info-beginning-of-block-p) 'block-start)
1346 (goto-char parent-block-end-pos) 1348 ((python-info-end-of-block-p) 'block-end)
1347 (and next-block-starting-pos 1349 ((python-info-beginning-of-statement-p) 'statement-start)
1348 (goto-char next-block-starting-pos))))) 1350 ((python-info-end-of-statement-p) 'statement-end)
1349 (t (python-nav-end-of-block)))))))) 1351 ((python-info-statement-starts-block-p) 'starts-block)
1352 ((python-info-statement-ends-block-p) 'ends-block)))))
1353 (if forward-p
1354 (cond ((and (not (eobp))
1355 (python-info-current-line-empty-p))
1356 (python-util-forward-comment dir)
1357 (python-nav--forward-sexp dir))
1358 ((eq context 'block-start)
1359 (python-nav-end-of-block))
1360 ((eq context 'statement-start)
1361 (python-nav-end-of-statement))
1362 ((and (memq context '(statement-end block-end))
1363 (eq next-sexp-context 'ends-block))
1364 (goto-char next-sexp-pos)
1365 (python-nav-end-of-block))
1366 ((and (memq context '(statement-end block-end))
1367 (eq next-sexp-context 'starts-block))
1368 (goto-char next-sexp-pos)
1369 (python-nav-end-of-block))
1370 ((memq context '(statement-end block-end))
1371 (goto-char next-sexp-pos)
1372 (python-nav-end-of-statement))
1373 (t (goto-char next-sexp-pos)))
1374 (cond ((and (not (bobp))
1375 (python-info-current-line-empty-p))
1376 (python-util-forward-comment dir)
1377 (python-nav--forward-sexp dir))
1378 ((eq context 'block-end)
1379 (python-nav-beginning-of-block))
1380 ((eq context 'statement-end)
1381 (python-nav-beginning-of-statement))
1382 ((and (memq context '(statement-start block-start))
1383 (eq next-sexp-context 'starts-block))
1384 (goto-char next-sexp-pos)
1385 (python-nav-beginning-of-block))
1386 ((and (memq context '(statement-start block-start))
1387 (eq next-sexp-context 'ends-block))
1388 (goto-char next-sexp-pos)
1389 (python-nav-beginning-of-block))
1390 ((memq context '(statement-start block-start))
1391 (goto-char next-sexp-pos)
1392 (python-nav-beginning-of-statement))
1393 (t (goto-char next-sexp-pos))))))))))
1350 1394
1351(defun python-nav--backward-sexp () 1395(defun python-nav--backward-sexp ()
1352 "Move to backward sexp." 1396 "Move to backward sexp."
1353 (case (python-syntax-context-type) 1397 (python-nav--forward-sexp -1))
1354 (string
1355 ;; Inside of a string, get out of it.
1356 (while (and (re-search-backward "[\"']" nil t)
1357 (python-syntax-context 'string))))
1358 (comment
1359 ;; Inside of a comment, just move backward.
1360 (python-util-forward-comment -1))
1361 (paren
1362 ;; Handle parens like we are lisp.
1363 (python-nav-lisp-forward-sexp-safe -1))
1364 (t
1365 (let* ((block-starting-pos
1366 (save-excursion (python-nav-beginning-of-block)))
1367 (block-ending-pos
1368 (save-excursion (python-nav-end-of-block)))
1369 (prev-block-ending-pos
1370 (save-excursion (when (python-nav-backward-block)
1371 (python-nav-end-of-block))))
1372 (prev-block-parent-ending-pos
1373 (save-excursion
1374 (when prev-block-ending-pos
1375 (goto-char prev-block-ending-pos)
1376 (python-util-forward-comment)
1377 (python-nav-beginning-of-block)
1378 (python-nav-end-of-block)))))
1379 (if (and (not (bobp))
1380 (= (syntax-class (syntax-after (1- (point)))) 5))
1381 ;; Char before point is a paren closing char, handle it
1382 ;; like we are lisp.
1383 (python-nav-lisp-forward-sexp-safe -1)
1384 (cond
1385 ((not block-ending-pos)
1386 ;; Not in and ending pos, move to end of previous block.
1387 (and (python-nav-backward-block)
1388 (python-nav-end-of-block)))
1389 ((= (point) block-ending-pos)
1390 ;; In ending pos, we need to search backwards for the
1391 ;; closest point looking the list of candidates from here.
1392 (let ((candidates))
1393 (dolist (name
1394 '(prev-block-parent-ending-pos
1395 prev-block-ending-pos
1396 block-ending-pos
1397 block-starting-pos))
1398 (when (and (symbol-value name)
1399 (< (symbol-value name) (point)))
1400 (add-to-list 'candidates (symbol-value name))))
1401 (goto-char (apply 'max candidates))))
1402 ((> (point) block-ending-pos)
1403 ;; After an ending position, move to it.
1404 (goto-char block-ending-pos))
1405 ((= (point) block-starting-pos)
1406 ;; On a block starting position.
1407 (if (not (> (point) (or prev-block-ending-pos (point))))
1408 ;; Point is after the end position of the block that
1409 ;; wraps the current one, just move a block backward.
1410 (python-nav-backward-block)
1411 ;; If we got here we are facing a case like this one:
1412 ;;
1413 ;; try:
1414 ;; return here()
1415 ;; except Exception as e:
1416 ;;
1417 ;; Where point is on the "except" and must move to the
1418 ;; end of "here()".
1419 (goto-char prev-block-ending-pos)
1420 (let ((parent-block-ending-pos
1421 (save-excursion
1422 (python-nav-forward-sexp)
1423 (and (not (looking-at (python-rx block-start)))
1424 (point)))))
1425 (when (and parent-block-ending-pos
1426 (> parent-block-ending-pos prev-block-ending-pos))
1427 ;; If we got here we are facing a case like this one:
1428 ;;
1429 ;; except ImportError:
1430 ;; if predicate():
1431 ;; processing()
1432 ;; here()
1433 ;; except AttributeError:
1434 ;;
1435 ;; Where point is on the "except" and must move to
1436 ;; the end of "here()". Without this extra step we'd
1437 ;; just get to the end of processing().
1438 (goto-char parent-block-ending-pos)))))
1439 (t
1440 (if (and prev-block-ending-pos (< prev-block-ending-pos (point)))
1441 (goto-char prev-block-ending-pos)
1442 (python-nav-beginning-of-block)))))))))
1443 1398
1444(defun python-nav-forward-sexp (&optional arg) 1399(defun python-nav-forward-sexp (&optional arg)
1445 "Move forward across one block of code. 1400 "Move forward across one block of code.
@@ -2891,12 +2846,43 @@ parent defun name."
2891 ".") ".") 2846 ".") ".")
2892 name))))))) 2847 name)))))))
2893 2848
2894(defsubst python-info-beginning-of-block-statement-p () 2849(defun python-info-statement-starts-block-p ()
2895 "Return non-nil if current statement opens a block." 2850 "Return non-nil if current statement opens a block."
2896 (save-excursion 2851 (save-excursion
2897 (python-nav-beginning-of-statement) 2852 (python-nav-beginning-of-statement)
2898 (looking-at (python-rx block-start)))) 2853 (looking-at (python-rx block-start))))
2899 2854
2855(defun python-info-statement-ends-block-p ()
2856 "Return non-nil if point is at end of block."
2857 (let ((end-of-block-pos (save-excursion
2858 (python-nav-end-of-block)))
2859 (end-of-statement-pos (save-excursion
2860 (python-nav-end-of-statement))))
2861 (and end-of-block-pos end-of-statement-pos
2862 (= end-of-block-pos end-of-statement-pos))))
2863
2864(defun python-info-beginning-of-statement-p ()
2865 "Return non-nil if point is at beginning of statement."
2866 (= (point) (save-excursion
2867 (python-nav-beginning-of-statement)
2868 (point))))
2869
2870(defun python-info-end-of-statement-p ()
2871 "Return non-nil if point is at end of statement."
2872 (= (point) (save-excursion
2873 (python-nav-end-of-statement)
2874 (point))))
2875
2876(defun python-info-beginning-of-block-p ()
2877 "Return non-nil if point is at beginning of block."
2878 (and (python-info-beginning-of-statement-p)
2879 (python-info-statement-starts-block-p)))
2880
2881(defun python-info-end-of-block-p ()
2882 "Return non-nil if point is at end of block."
2883 (and (python-info-end-of-statement-p)
2884 (python-info-statement-ends-block-p)))
2885
2900(defun python-info-closing-block () 2886(defun python-info-closing-block ()
2901 "Return the point of the block the current line closes." 2887 "Return the point of the block the current line closes."
2902 (let ((closing-word (save-excursion 2888 (let ((closing-word (save-excursion