aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
authorFabián Ezequiel Gallina2012-08-09 00:30:37 -0300
committerFabián Ezequiel Gallina2012-08-09 00:30:37 -0300
commit489af14fa55c1774367460c3279c0897f0ea9f2c (patch)
treea9efd774007b5a6a2e1ca48b0a4df051f33cb775 /lisp/progmodes/python.el
parentb5e94c8e466ea583b3518cda8d5219baad2ac427 (diff)
downloademacs-489af14fa55c1774367460c3279c0897f0ea9f2c.tar.gz
emacs-489af14fa55c1774367460c3279c0897f0ea9f2c.zip
* 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.
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el239
1 files changed, 167 insertions, 72 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 58d984f8d4d..c65f2a2d595 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -54,7 +54,7 @@
54;; `python-nav-beginning-of-statement', `python-nav-end-of-statement', 54;; `python-nav-beginning-of-statement', `python-nav-end-of-statement',
55;; `python-nav-beginning-of-block' and `python-nav-end-of-block' are 55;; `python-nav-beginning-of-block' and `python-nav-end-of-block' are
56;; included but no bound to any key. At last but not least the 56;; included but no bound to any key. At last but not least the
57;; specialized `python-nav-forward-sexp-function' allows easy 57;; specialized `python-nav-forward-sexp' allows easy
58;; navigation between code blocks. 58;; navigation between code blocks.
59 59
60;; Shell interaction: is provided and allows you to execute easily any 60;; Shell interaction: is provided and allows you to execute easily any
@@ -1249,83 +1249,178 @@ backward to previous block."
1249 (and (goto-char starting-pos) nil) 1249 (and (goto-char starting-pos) nil)
1250 (and (not (= (point) starting-pos)) (point-marker))))) 1250 (and (not (= (point) starting-pos)) (point-marker)))))
1251 1251
1252(defun python-nav-forward-sexp-function (&optional arg) 1252(defun python-nav-lisp-forward-sexp-safe (&optional arg)
1253 "Safe version of standard `forward-sexp'.
1254When ARG > 0 move forward, else if ARG is < 0."
1255 (or arg (setq arg 1))
1256 (let ((forward-sexp-function nil)
1257 (paren-regexp
1258 (if (> arg 0) (python-rx close-paren) (python-rx open-paren)))
1259 (search-fn
1260 (if (> arg 0) #'re-search-forward #'re-search-backward)))
1261 (condition-case nil
1262 (forward-sexp arg)
1263 (error
1264 (while (and (funcall search-fn paren-regexp nil t)
1265 (python-syntax-context 'paren)))))))
1266
1267(defun python-nav--forward-sexp ()
1268 "Move to forward sexp."
1269 (case (python-syntax-context-type)
1270 (string
1271 ;; Inside of a string, get out of it.
1272 (while (and (re-search-forward "[\"']" nil t)
1273 (python-syntax-context 'string))))
1274 (comment
1275 ;; Inside of a comment, just move forward.
1276 (python-util-forward-comment))
1277 (paren
1278 (python-nav-lisp-forward-sexp-safe 1))
1279 (t
1280 (if (and (not (eobp))
1281 (= (syntax-class (syntax-after (point))) 4))
1282 ;; Looking an open-paren
1283 (python-nav-lisp-forward-sexp-safe 1)
1284 (let ((block-starting-pos
1285 (save-excursion (python-nav-beginning-of-block)))
1286 (block-ending-pos
1287 (save-excursion (python-nav-end-of-block)))
1288 (next-block-starting-pos
1289 (save-excursion (python-nav-forward-block))))
1290 (cond
1291 ((not block-starting-pos)
1292 ;; Not inside a block, move to closest one.
1293 (and next-block-starting-pos
1294 (goto-char next-block-starting-pos)))
1295 ((= (point) block-starting-pos)
1296 ;; Point is at beginning of block
1297 (if (and next-block-starting-pos
1298 (< next-block-starting-pos block-ending-pos))
1299 ;; Beginning of next block is closer than current's
1300 ;; end, move to it.
1301 (goto-char next-block-starting-pos)
1302 (goto-char block-ending-pos)))
1303 ((= block-ending-pos (point))
1304 ;; Point is at end of current block
1305 (let ((parent-block-end-pos
1306 (save-excursion
1307 (python-util-forward-comment)
1308 (python-nav-beginning-of-block)
1309 (python-nav-end-of-block))))
1310 (if (and parent-block-end-pos
1311 (or (not next-block-starting-pos)
1312 (> next-block-starting-pos parent-block-end-pos)))
1313 ;; If the parent block ends before next block
1314 ;; starts move to it.
1315 (goto-char parent-block-end-pos)
1316 (and next-block-starting-pos
1317 (goto-char next-block-starting-pos)))))
1318 (t (python-nav-end-of-block))))))))
1319
1320(defun python-nav--backward-sexp ()
1321 "Move to backward sexp."
1322 (case (python-syntax-context-type)
1323 (string
1324 ;; Inside of a string, get out of it.
1325 (while (and (re-search-backward "[\"']" nil t)
1326 (python-syntax-context 'string))))
1327 (comment
1328 ;; Inside of a comment, just move backward.
1329 (python-util-forward-comment -1))
1330 (paren
1331 ;; Handle parens like we are lisp.
1332 (python-nav-lisp-forward-sexp-safe -1))
1333 (t
1334 (let* ((block-starting-pos
1335 (save-excursion (python-nav-beginning-of-block)))
1336 (block-ending-pos
1337 (save-excursion (python-nav-end-of-block)))
1338 (prev-block-ending-pos
1339 (save-excursion (when (python-nav-backward-block)
1340 (python-nav-end-of-block))))
1341 (prev-block-parent-ending-pos
1342 (save-excursion
1343 (when prev-block-ending-pos
1344 (goto-char prev-block-ending-pos)
1345 (python-util-forward-comment)
1346 (python-nav-beginning-of-block)
1347 (python-nav-end-of-block)))))
1348 (if (and (not (bobp))
1349 (= (syntax-class (syntax-after (1- (point)))) 5))
1350 ;; Char before point is a paren closing char, handle it
1351 ;; like we are lisp.
1352 (python-nav-lisp-forward-sexp-safe -1)
1353 (cond
1354 ((not block-ending-pos)
1355 ;; Not in and ending pos, move to end of previous block.
1356 (and (python-nav-backward-block)
1357 (python-nav-end-of-block)))
1358 ((= (point) block-ending-pos)
1359 ;; In ending pos, we need to search backwards for the
1360 ;; closest point looking the list of candidates from here.
1361 (let ((candidates))
1362 (dolist (name
1363 '(prev-block-parent-ending-pos
1364 prev-block-ending-pos
1365 block-ending-pos
1366 block-starting-pos))
1367 (when (and (symbol-value name)
1368 (< (symbol-value name) (point)))
1369 (add-to-list 'candidates (symbol-value name))))
1370 (goto-char (apply 'max candidates))))
1371 ((> (point) block-ending-pos)
1372 ;; After an ending position, move to it.
1373 (goto-char block-ending-pos))
1374 ((= (point) block-starting-pos)
1375 ;; On a block starting position.
1376 (if (not (> (point) (or prev-block-ending-pos (point))))
1377 ;; Point is after the end position of the block that
1378 ;; wraps the current one, just move a block backward.
1379 (python-nav-backward-block)
1380 ;; If we got here we are facing a case like this one:
1381 ;;
1382 ;; try:
1383 ;; return here()
1384 ;; except Exception as e:
1385 ;;
1386 ;; Where point is on the "except" and must move to the
1387 ;; end of "here()".
1388 (goto-char prev-block-ending-pos)
1389 (let ((parent-block-ending-pos
1390 (save-excursion
1391 (python-nav-forward-sexp)
1392 (and (not (looking-at (python-rx block-start)))
1393 (point)))))
1394 (when (and parent-block-ending-pos
1395 (> parent-block-ending-pos prev-block-ending-pos))
1396 ;; If we got here we are facing a case like this one:
1397 ;;
1398 ;; except ImportError:
1399 ;; if predicate():
1400 ;; processing()
1401 ;; here()
1402 ;; except AttributeError:
1403 ;;
1404 ;; Where point is on the "except" and must move to
1405 ;; the end of "here()". Without this extra step we'd
1406 ;; just get to the end of processing().
1407 (goto-char parent-block-ending-pos)))))
1408 (t
1409 (if (and prev-block-ending-pos (< prev-block-ending-pos (point)))
1410 (goto-char prev-block-ending-pos)
1411 (python-nav-beginning-of-block)))))))))
1412
1413(defun python-nav-forward-sexp (&optional arg)
1253 "Move forward across one block of code. 1414 "Move forward across one block of code.
1254With ARG, do it that many times. Negative arg -N means 1415With ARG, do it that many times. Negative arg -N means
1255move backward N times." 1416move backward N times."
1256 (interactive "^p") 1417 (interactive "^p")
1257 (or arg (setq arg 1)) 1418 (or arg (setq arg 1))
1258 (while (> arg 0) 1419 (while (> arg 0)
1259 (let ((block-starting-pos 1420 (python-nav--forward-sexp)
1260 (save-excursion (python-nav-beginning-of-block))) 1421 (setq arg (1- arg)))
1261 (block-ending-pos
1262 (save-excursion (python-nav-end-of-block)))
1263 (next-block-starting-pos
1264 (save-excursion (python-nav-forward-block))))
1265 (cond ((not block-starting-pos)
1266 (python-nav-forward-block))
1267 ((= (point) block-starting-pos)
1268 (if (or (not next-block-starting-pos)
1269 (< block-ending-pos next-block-starting-pos))
1270 (python-nav-end-of-block)
1271 (python-nav-forward-block)))
1272 ((= block-ending-pos (point))
1273 (let ((parent-block-end-pos
1274 (save-excursion
1275 (python-util-forward-comment)
1276 (python-nav-beginning-of-block)
1277 (python-nav-end-of-block))))
1278 (if (and parent-block-end-pos
1279 (or (not next-block-starting-pos)
1280 (> next-block-starting-pos parent-block-end-pos)))
1281 (goto-char parent-block-end-pos)
1282 (python-nav-forward-block))))
1283 (t (python-nav-end-of-block))))
1284 (setq arg (1- arg)))
1285 (while (< arg 0) 1422 (while (< arg 0)
1286 (let* ((block-starting-pos 1423 (python-nav--backward-sexp)
1287 (save-excursion (python-nav-beginning-of-block)))
1288 (block-ending-pos
1289 (save-excursion (python-nav-end-of-block)))
1290 (prev-block-ending-pos
1291 (save-excursion (when (python-nav-backward-block)
1292 (python-nav-end-of-block))))
1293 (prev-block-parent-ending-pos
1294 (save-excursion
1295 (when prev-block-ending-pos
1296 (goto-char prev-block-ending-pos)
1297 (python-util-forward-comment)
1298 (python-nav-beginning-of-block)
1299 (python-nav-end-of-block)))))
1300 (cond ((not block-ending-pos)
1301 (and (python-nav-backward-block)
1302 (python-nav-end-of-block)))
1303 ((= (point) block-ending-pos)
1304 (let ((candidates))
1305 (dolist (name
1306 '(prev-block-parent-ending-pos
1307 prev-block-ending-pos
1308 block-ending-pos
1309 block-starting-pos))
1310 (when (and (symbol-value name)
1311 (< (symbol-value name) (point)))
1312 (add-to-list 'candidates (symbol-value name))))
1313 (goto-char (apply 'max candidates))))
1314 ((> (point) block-ending-pos)
1315 (python-nav-end-of-block))
1316 ((= (point) block-starting-pos)
1317 (if (not (> (point) (or prev-block-ending-pos (point))))
1318 (python-nav-backward-block)
1319 (goto-char prev-block-ending-pos)
1320 (let ((parent-block-ending-pos
1321 (save-excursion
1322 (python-nav-forward-sexp-function)
1323 (and (not (looking-at (python-rx block-start)))
1324 (point)))))
1325 (when (and parent-block-ending-pos
1326 (> parent-block-ending-pos prev-block-ending-pos))
1327 (goto-char parent-block-ending-pos)))))
1328 (t (python-nav-beginning-of-block))))
1329 (setq arg (1+ arg)))) 1424 (setq arg (1+ arg))))
1330 1425
1331 1426
@@ -2848,7 +2943,7 @@ if that value is non-nil."
2848 (set (make-local-variable 'parse-sexp-ignore-comments) t) 2943 (set (make-local-variable 'parse-sexp-ignore-comments) t)
2849 2944
2850 (set (make-local-variable 'forward-sexp-function) 2945 (set (make-local-variable 'forward-sexp-function)
2851 'python-nav-forward-sexp-function) 2946 'python-nav-forward-sexp)
2852 2947
2853 (set (make-local-variable 'font-lock-defaults) 2948 (set (make-local-variable 'font-lock-defaults)
2854 '(python-font-lock-keywords nil nil nil nil)) 2949 '(python-font-lock-keywords nil nil nil nil))