diff options
| author | Kenichi Handa | 2012-10-11 20:29:47 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2012-10-11 20:29:47 +0900 |
| commit | d3e4228575e9ba9e99dc4a7dae788280ffcc4566 (patch) | |
| tree | 97d35f3c0766372c166a31f3c0f7aba791a38dde /lisp/progmodes/python.el | |
| parent | cde44a7728488ca6bc6a46c18d9c5e647b160547 (diff) | |
| parent | fd2f90cf5c6a15610aa1e17e73d6d8a5f8cb1999 (diff) | |
| download | emacs-d3e4228575e9ba9e99dc4a7dae788280ffcc4566.tar.gz emacs-d3e4228575e9ba9e99dc4a7dae788280ffcc4566.zip | |
merge trunk
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 475 |
1 files changed, 281 insertions, 194 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 726c0b2d542..5bf64c18f99 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -235,6 +235,9 @@ | |||
| 235 | (substitute-key-definition 'forward-sentence | 235 | (substitute-key-definition 'forward-sentence |
| 236 | 'python-nav-forward-block | 236 | 'python-nav-forward-block |
| 237 | map global-map) | 237 | map global-map) |
| 238 | (substitute-key-definition 'backward-up-list | ||
| 239 | 'python-nav-backward-up-list | ||
| 240 | map global-map) | ||
| 238 | (define-key map "\C-c\C-j" 'imenu) | 241 | (define-key map "\C-c\C-j" 'imenu) |
| 239 | ;; Indent specific | 242 | ;; Indent specific |
| 240 | (define-key map "\177" 'python-indent-dedent-line-backspace) | 243 | (define-key map "\177" 'python-indent-dedent-line-backspace) |
| @@ -337,19 +340,28 @@ | |||
| 337 | "==" ">=" "is" "not"))) | 340 | "==" ">=" "is" "not"))) |
| 338 | ;; FIXME: Use regexp-opt. | 341 | ;; FIXME: Use regexp-opt. |
| 339 | (assignment-operator . ,(rx (or "=" "+=" "-=" "*=" "/=" "//=" "%=" "**=" | 342 | (assignment-operator . ,(rx (or "=" "+=" "-=" "*=" "/=" "//=" "%=" "**=" |
| 340 | ">>=" "<<=" "&=" "^=" "|=")))) | 343 | ">>=" "<<=" "&=" "^=" "|="))) |
| 341 | "Additional Python specific sexps for `python-rx'")) | 344 | (string-delimiter . ,(rx (and |
| 342 | 345 | ;; Match even number of backslashes. | |
| 343 | (defmacro python-rx (&rest regexps) | 346 | (or (not (any ?\\ ?\' ?\")) point |
| 344 | "Python mode specialized rx macro. | 347 | ;; Quotes might be preceded by a escaped quote. |
| 348 | (and (or (not (any ?\\)) point) ?\\ | ||
| 349 | (* ?\\ ?\\) (any ?\' ?\"))) | ||
| 350 | (* ?\\ ?\\) | ||
| 351 | ;; Match single or triple quotes of any kind. | ||
| 352 | (group (or "\"" "\"\"\"" "'" "'''")))))) | ||
| 353 | "Additional Python specific sexps for `python-rx'") | ||
| 354 | |||
| 355 | (defmacro python-rx (&rest regexps) | ||
| 356 | "Python mode specialized rx macro. | ||
| 345 | This variant of `rx' supports common python named REGEXPS." | 357 | This variant of `rx' supports common python named REGEXPS." |
| 346 | (let ((rx-constituents (append python-rx-constituents rx-constituents))) | 358 | (let ((rx-constituents (append python-rx-constituents rx-constituents))) |
| 347 | (cond ((null regexps) | 359 | (cond ((null regexps) |
| 348 | (error "No regexp")) | 360 | (error "No regexp")) |
| 349 | ((cdr regexps) | 361 | ((cdr regexps) |
| 350 | (rx-to-string `(and ,@regexps) t)) | 362 | (rx-to-string `(and ,@regexps) t)) |
| 351 | (t | 363 | (t |
| 352 | (rx-to-string (car regexps) t))))) | 364 | (rx-to-string (car regexps) t)))))) |
| 353 | 365 | ||
| 354 | 366 | ||
| 355 | ;;; Font-lock and syntax | 367 | ;;; Font-lock and syntax |
| @@ -498,16 +510,7 @@ The type returned can be `comment', `string' or `paren'." | |||
| 498 | 510 | ||
| 499 | (defconst python-syntax-propertize-function | 511 | (defconst python-syntax-propertize-function |
| 500 | (syntax-propertize-rules | 512 | (syntax-propertize-rules |
| 501 | ((rx | 513 | ((python-rx string-delimiter) |
| 502 | (and | ||
| 503 | ;; Match even number of backslashes. | ||
| 504 | (or (not (any ?\\ ?\' ?\")) point | ||
| 505 | ;; Quotes might be preceded by a escaped quote. | ||
| 506 | (and (or (not (any ?\\)) point) ?\\ | ||
| 507 | (* ?\\ ?\\) (any ?\' ?\"))) | ||
| 508 | (* ?\\ ?\\) | ||
| 509 | ;; Match single or triple quotes of any kind. | ||
| 510 | (group (or "\"" "\"\"\"" "'" "'''")))) | ||
| 511 | (0 (ignore (python-syntax-stringify)))))) | 514 | (0 (ignore (python-syntax-stringify)))))) |
| 512 | 515 | ||
| 513 | (defsubst python-syntax-count-quotes (quote-char &optional point limit) | 516 | (defsubst python-syntax-count-quotes (quote-char &optional point limit) |
| @@ -676,12 +679,12 @@ START is the buffer position where the sexp starts." | |||
| 676 | (goto-char (line-beginning-position)) | 679 | (goto-char (line-beginning-position)) |
| 677 | (bobp)) | 680 | (bobp)) |
| 678 | 'no-indent) | 681 | 'no-indent) |
| 679 | ;; Inside a paren | ||
| 680 | ((setq start (python-syntax-context 'paren ppss)) | ||
| 681 | 'inside-paren) | ||
| 682 | ;; Inside string | 682 | ;; Inside string |
| 683 | ((setq start (python-syntax-context 'string ppss)) | 683 | ((setq start (python-syntax-context 'string ppss)) |
| 684 | 'inside-string) | 684 | 'inside-string) |
| 685 | ;; Inside a paren | ||
| 686 | ((setq start (python-syntax-context 'paren ppss)) | ||
| 687 | 'inside-paren) | ||
| 685 | ;; After backslash | 688 | ;; After backslash |
| 686 | ((setq start (when (not (or (python-syntax-context 'string ppss) | 689 | ((setq start (when (not (or (python-syntax-context 'string ppss) |
| 687 | (python-syntax-context 'comment ppss))) | 690 | (python-syntax-context 'comment ppss))) |
| @@ -710,7 +713,7 @@ START is the buffer position where the sexp starts." | |||
| 710 | ;; After normal line | 713 | ;; After normal line |
| 711 | ((setq start (save-excursion | 714 | ((setq start (save-excursion |
| 712 | (back-to-indentation) | 715 | (back-to-indentation) |
| 713 | (python-util-forward-comment -1) | 716 | (skip-chars-backward (rx (or whitespace ?\n))) |
| 714 | (python-nav-beginning-of-statement) | 717 | (python-nav-beginning-of-statement) |
| 715 | (point-marker))) | 718 | (point-marker))) |
| 716 | 'after-line) | 719 | 'after-line) |
| @@ -973,7 +976,16 @@ Called from a program, START and END specify the region to indent." | |||
| 973 | (back-to-indentation) | 976 | (back-to-indentation) |
| 974 | (setq word (current-word)) | 977 | (setq word (current-word)) |
| 975 | (forward-line 1) | 978 | (forward-line 1) |
| 976 | (when word | 979 | (when (and word |
| 980 | ;; Don't mess with strings, unless it's the | ||
| 981 | ;; enclosing set of quotes. | ||
| 982 | (or (not (python-syntax-context 'string)) | ||
| 983 | (eq | ||
| 984 | (syntax-after | ||
| 985 | (+ (1- (point)) | ||
| 986 | (current-indentation) | ||
| 987 | (python-syntax-count-quotes (char-after) (point)))) | ||
| 988 | (string-to-syntax "|")))) | ||
| 977 | (beginning-of-line) | 989 | (beginning-of-line) |
| 978 | (delete-horizontal-space) | 990 | (delete-horizontal-space) |
| 979 | (indent-to (python-indent-calculate-indentation))))) | 991 | (indent-to (python-indent-calculate-indentation))))) |
| @@ -1160,7 +1172,8 @@ Returns nil if point is not in a def or class." | |||
| 1160 | (python-info-line-ends-backslash-p)) | 1172 | (python-info-line-ends-backslash-p)) |
| 1161 | (python-syntax-context 'string) | 1173 | (python-syntax-context 'string) |
| 1162 | (python-syntax-context 'paren)) | 1174 | (python-syntax-context 'paren)) |
| 1163 | (forward-line -1))))) | 1175 | (forward-line -1)))) |
| 1176 | (point-marker)) | ||
| 1164 | 1177 | ||
| 1165 | (defun python-nav-end-of-statement () | 1178 | (defun python-nav-end-of-statement () |
| 1166 | "Move to end of current statement." | 1179 | "Move to end of current statement." |
| @@ -1171,7 +1184,8 @@ Returns nil if point is not in a def or class." | |||
| 1171 | (python-info-line-ends-backslash-p) | 1184 | (python-info-line-ends-backslash-p) |
| 1172 | (python-syntax-context 'string) | 1185 | (python-syntax-context 'string) |
| 1173 | (python-syntax-context 'paren)) | 1186 | (python-syntax-context 'paren)) |
| 1174 | (forward-line 1))))) | 1187 | (forward-line 1)))) |
| 1188 | (point-marker)) | ||
| 1175 | 1189 | ||
| 1176 | (defun python-nav-backward-statement (&optional arg) | 1190 | (defun python-nav-backward-statement (&optional arg) |
| 1177 | "Move backward to previous statement. | 1191 | "Move backward to previous statement. |
| @@ -1286,151 +1300,104 @@ When ARG > 0 move forward, else if ARG is < 0." | |||
| 1286 | (while (and (funcall search-fn paren-regexp nil t) | 1300 | (while (and (funcall search-fn paren-regexp nil t) |
| 1287 | (python-syntax-context 'paren))))))) | 1301 | (python-syntax-context 'paren))))))) |
| 1288 | 1302 | ||
| 1289 | (defun python-nav--forward-sexp () | 1303 | (defun python-nav--forward-sexp (&optional dir) |
| 1290 | "Move to forward sexp." | 1304 | "Move to forward sexp. |
| 1291 | (case (python-syntax-context-type) | 1305 | With positive Optional argument DIR direction move forward, else |
| 1292 | (string | 1306 | backwards." |
| 1293 | ;; Inside of a string, get out of it. | 1307 | (setq dir (or dir 1)) |
| 1294 | (while (and (re-search-forward "[\"']" nil t) | 1308 | (unless (= dir 0) |
| 1295 | (python-syntax-context 'string)))) | 1309 | (let* ((forward-p (if (> dir 0) |
| 1296 | (comment | 1310 | (and (setq dir 1) t) |
| 1297 | ;; Inside of a comment, just move forward. | 1311 | (and (setq dir -1) nil))) |
| 1298 | (python-util-forward-comment)) | 1312 | (re-search-fn (if forward-p |
| 1299 | (paren | 1313 | 're-search-forward |
| 1300 | (python-nav-lisp-forward-sexp-safe 1)) | 1314 | 're-search-backward)) |
| 1301 | (t | 1315 | (context-type (python-syntax-context-type))) |
| 1302 | (if (and (not (eobp)) | 1316 | (cond |
| 1303 | (= (syntax-class (syntax-after (point))) 4)) | 1317 | ((eq context-type 'string) |
| 1304 | ;; Looking an open-paren | 1318 | ;; Inside of a string, get out of it. |
| 1305 | (python-nav-lisp-forward-sexp-safe 1) | 1319 | (while (and (funcall re-search-fn "[\"']" nil t) |
| 1306 | (let ((block-starting-pos | 1320 | (python-syntax-context 'string)))) |
| 1307 | (save-excursion (python-nav-beginning-of-block))) | 1321 | ((eq context-type 'comment) |
| 1308 | (block-ending-pos | 1322 | ;; Inside of a comment, just move forward. |
| 1309 | (save-excursion (python-nav-end-of-block))) | 1323 | (python-util-forward-comment dir)) |
| 1310 | (next-block-starting-pos | 1324 | ((or (eq context-type 'paren) |
| 1311 | (save-excursion (python-nav-forward-block)))) | 1325 | (and forward-p (looking-at (python-rx open-paren))) |
| 1312 | (cond | 1326 | (and (not forward-p) |
| 1313 | ((not block-starting-pos) | 1327 | (eq (syntax-class (syntax-after (1- (point)))) |
| 1314 | ;; Not inside a block, move to closest one. | 1328 | (car (string-to-syntax ")"))))) |
| 1315 | (and next-block-starting-pos | 1329 | ;; Inside a paren or looking at it, lisp knows what to do. |
| 1316 | (goto-char next-block-starting-pos))) | 1330 | (python-nav-lisp-forward-sexp-safe dir)) |
| 1317 | ((= (point) block-starting-pos) | 1331 | (t |
| 1318 | ;; Point is at beginning of block | 1332 | ;; This part handles the lispy feel of |
| 1319 | (if (and next-block-starting-pos | 1333 | ;; `python-nav-forward-sexp'. Knowing everything about the |
| 1320 | (< next-block-starting-pos block-ending-pos)) | 1334 | ;; current context and the context of the next sexp tries to |
| 1321 | ;; Beginning of next block is closer than current's | 1335 | ;; follow the lisp sexp motion commands in a symmetric manner. |
| 1322 | ;; end, move to it. | 1336 | (let* ((context |
| 1323 | (goto-char next-block-starting-pos) | 1337 | (cond |
| 1324 | (goto-char block-ending-pos))) | 1338 | ((python-info-beginning-of-block-p) 'block-start) |
| 1325 | ((= block-ending-pos (point)) | 1339 | ((python-info-end-of-block-p) 'block-end) |
| 1326 | ;; Point is at end of current block | 1340 | ((python-info-beginning-of-statement-p) 'statement-start) |
| 1327 | (let ((parent-block-end-pos | 1341 | ((python-info-end-of-statement-p) 'statement-end))) |
| 1328 | (save-excursion | 1342 | (next-sexp-pos |
| 1329 | (python-util-forward-comment) | 1343 | (save-excursion |
| 1330 | (python-nav-beginning-of-block) | 1344 | (python-nav-lisp-forward-sexp-safe dir) |
| 1331 | (python-nav-end-of-block)))) | 1345 | (point))) |
| 1332 | (if (and parent-block-end-pos | 1346 | (next-sexp-context |
| 1333 | (or (not next-block-starting-pos) | 1347 | (save-excursion |
| 1334 | (> next-block-starting-pos parent-block-end-pos))) | 1348 | (goto-char next-sexp-pos) |
| 1335 | ;; If the parent block ends before next block | 1349 | (cond |
| 1336 | ;; starts move to it. | 1350 | ((python-info-beginning-of-block-p) 'block-start) |
| 1337 | (goto-char parent-block-end-pos) | 1351 | ((python-info-end-of-block-p) 'block-end) |
| 1338 | (and next-block-starting-pos | 1352 | ((python-info-beginning-of-statement-p) 'statement-start) |
| 1339 | (goto-char next-block-starting-pos))))) | 1353 | ((python-info-end-of-statement-p) 'statement-end) |
| 1340 | (t (python-nav-end-of-block)))))))) | 1354 | ((python-info-statement-starts-block-p) 'starts-block) |
| 1355 | ((python-info-statement-ends-block-p) 'ends-block))))) | ||
| 1356 | (if forward-p | ||
| 1357 | (cond ((and (not (eobp)) | ||
| 1358 | (python-info-current-line-empty-p)) | ||
| 1359 | (python-util-forward-comment dir) | ||
| 1360 | (python-nav--forward-sexp dir)) | ||
| 1361 | ((eq context 'block-start) | ||
| 1362 | (python-nav-end-of-block)) | ||
| 1363 | ((eq context 'statement-start) | ||
| 1364 | (python-nav-end-of-statement)) | ||
| 1365 | ((and (memq context '(statement-end block-end)) | ||
| 1366 | (eq next-sexp-context 'ends-block)) | ||
| 1367 | (goto-char next-sexp-pos) | ||
| 1368 | (python-nav-end-of-block)) | ||
| 1369 | ((and (memq context '(statement-end block-end)) | ||
| 1370 | (eq next-sexp-context 'starts-block)) | ||
| 1371 | (goto-char next-sexp-pos) | ||
| 1372 | (python-nav-end-of-block)) | ||
| 1373 | ((memq context '(statement-end block-end)) | ||
| 1374 | (goto-char next-sexp-pos) | ||
| 1375 | (python-nav-end-of-statement)) | ||
| 1376 | (t (goto-char next-sexp-pos))) | ||
| 1377 | (cond ((and (not (bobp)) | ||
| 1378 | (python-info-current-line-empty-p)) | ||
| 1379 | (python-util-forward-comment dir) | ||
| 1380 | (python-nav--forward-sexp dir)) | ||
| 1381 | ((eq context 'block-end) | ||
| 1382 | (python-nav-beginning-of-block)) | ||
| 1383 | ((eq context 'statement-end) | ||
| 1384 | (python-nav-beginning-of-statement)) | ||
| 1385 | ((and (memq context '(statement-start block-start)) | ||
| 1386 | (eq next-sexp-context 'starts-block)) | ||
| 1387 | (goto-char next-sexp-pos) | ||
| 1388 | (python-nav-beginning-of-block)) | ||
| 1389 | ((and (memq context '(statement-start block-start)) | ||
| 1390 | (eq next-sexp-context 'ends-block)) | ||
| 1391 | (goto-char next-sexp-pos) | ||
| 1392 | (python-nav-beginning-of-block)) | ||
| 1393 | ((memq context '(statement-start block-start)) | ||
| 1394 | (goto-char next-sexp-pos) | ||
| 1395 | (python-nav-beginning-of-statement)) | ||
| 1396 | (t (goto-char next-sexp-pos)))))))))) | ||
| 1341 | 1397 | ||
| 1342 | (defun python-nav--backward-sexp () | 1398 | (defun python-nav--backward-sexp () |
| 1343 | "Move to backward sexp." | 1399 | "Move to backward sexp." |
| 1344 | (case (python-syntax-context-type) | 1400 | (python-nav--forward-sexp -1)) |
| 1345 | (string | ||
| 1346 | ;; Inside of a string, get out of it. | ||
| 1347 | (while (and (re-search-backward "[\"']" nil t) | ||
| 1348 | (python-syntax-context 'string)))) | ||
| 1349 | (comment | ||
| 1350 | ;; Inside of a comment, just move backward. | ||
| 1351 | (python-util-forward-comment -1)) | ||
| 1352 | (paren | ||
| 1353 | ;; Handle parens like we are lisp. | ||
| 1354 | (python-nav-lisp-forward-sexp-safe -1)) | ||
| 1355 | (t | ||
| 1356 | (let* ((block-starting-pos | ||
| 1357 | (save-excursion (python-nav-beginning-of-block))) | ||
| 1358 | (block-ending-pos | ||
| 1359 | (save-excursion (python-nav-end-of-block))) | ||
| 1360 | (prev-block-ending-pos | ||
| 1361 | (save-excursion (when (python-nav-backward-block) | ||
| 1362 | (python-nav-end-of-block)))) | ||
| 1363 | (prev-block-parent-ending-pos | ||
| 1364 | (save-excursion | ||
| 1365 | (when prev-block-ending-pos | ||
| 1366 | (goto-char prev-block-ending-pos) | ||
| 1367 | (python-util-forward-comment) | ||
| 1368 | (python-nav-beginning-of-block) | ||
| 1369 | (python-nav-end-of-block))))) | ||
| 1370 | (if (and (not (bobp)) | ||
| 1371 | (= (syntax-class (syntax-after (1- (point)))) 5)) | ||
| 1372 | ;; Char before point is a paren closing char, handle it | ||
| 1373 | ;; like we are lisp. | ||
| 1374 | (python-nav-lisp-forward-sexp-safe -1) | ||
| 1375 | (cond | ||
| 1376 | ((not block-ending-pos) | ||
| 1377 | ;; Not in and ending pos, move to end of previous block. | ||
| 1378 | (and (python-nav-backward-block) | ||
| 1379 | (python-nav-end-of-block))) | ||
| 1380 | ((= (point) block-ending-pos) | ||
| 1381 | ;; In ending pos, we need to search backwards for the | ||
| 1382 | ;; closest point looking the list of candidates from here. | ||
| 1383 | (let ((candidates)) | ||
| 1384 | (dolist (name | ||
| 1385 | '(prev-block-parent-ending-pos | ||
| 1386 | prev-block-ending-pos | ||
| 1387 | block-ending-pos | ||
| 1388 | block-starting-pos)) | ||
| 1389 | (when (and (symbol-value name) | ||
| 1390 | (< (symbol-value name) (point))) | ||
| 1391 | (add-to-list 'candidates (symbol-value name)))) | ||
| 1392 | (goto-char (apply 'max candidates)))) | ||
| 1393 | ((> (point) block-ending-pos) | ||
| 1394 | ;; After an ending position, move to it. | ||
| 1395 | (goto-char block-ending-pos)) | ||
| 1396 | ((= (point) block-starting-pos) | ||
| 1397 | ;; On a block starting position. | ||
| 1398 | (if (not (> (point) (or prev-block-ending-pos (point)))) | ||
| 1399 | ;; Point is after the end position of the block that | ||
| 1400 | ;; wraps the current one, just move a block backward. | ||
| 1401 | (python-nav-backward-block) | ||
| 1402 | ;; If we got here we are facing a case like this one: | ||
| 1403 | ;; | ||
| 1404 | ;; try: | ||
| 1405 | ;; return here() | ||
| 1406 | ;; except Exception as e: | ||
| 1407 | ;; | ||
| 1408 | ;; Where point is on the "except" and must move to the | ||
| 1409 | ;; end of "here()". | ||
| 1410 | (goto-char prev-block-ending-pos) | ||
| 1411 | (let ((parent-block-ending-pos | ||
| 1412 | (save-excursion | ||
| 1413 | (python-nav-forward-sexp) | ||
| 1414 | (and (not (looking-at (python-rx block-start))) | ||
| 1415 | (point))))) | ||
| 1416 | (when (and parent-block-ending-pos | ||
| 1417 | (> parent-block-ending-pos prev-block-ending-pos)) | ||
| 1418 | ;; If we got here we are facing a case like this one: | ||
| 1419 | ;; | ||
| 1420 | ;; except ImportError: | ||
| 1421 | ;; if predicate(): | ||
| 1422 | ;; processing() | ||
| 1423 | ;; here() | ||
| 1424 | ;; except AttributeError: | ||
| 1425 | ;; | ||
| 1426 | ;; Where point is on the "except" and must move to | ||
| 1427 | ;; the end of "here()". Without this extra step we'd | ||
| 1428 | ;; just get to the end of processing(). | ||
| 1429 | (goto-char parent-block-ending-pos))))) | ||
| 1430 | (t | ||
| 1431 | (if (and prev-block-ending-pos (< prev-block-ending-pos (point))) | ||
| 1432 | (goto-char prev-block-ending-pos) | ||
| 1433 | (python-nav-beginning-of-block))))))))) | ||
| 1434 | 1401 | ||
| 1435 | (defun python-nav-forward-sexp (&optional arg) | 1402 | (defun python-nav-forward-sexp (&optional arg) |
| 1436 | "Move forward across one block of code. | 1403 | "Move forward across one block of code. |
| @@ -1445,6 +1412,67 @@ move backward N times." | |||
| 1445 | (python-nav--backward-sexp) | 1412 | (python-nav--backward-sexp) |
| 1446 | (setq arg (1+ arg)))) | 1413 | (setq arg (1+ arg)))) |
| 1447 | 1414 | ||
| 1415 | (defun python-nav--up-list (&optional dir) | ||
| 1416 | "Internal implementation of `python-nav-up-list'. | ||
| 1417 | DIR is always 1 or -1 and comes sanitized from | ||
| 1418 | `python-nav-up-list' calls." | ||
| 1419 | (let ((context (python-syntax-context-type)) | ||
| 1420 | (forward-p (> dir 0))) | ||
| 1421 | (cond | ||
| 1422 | ((memq context '(string comment))) | ||
| 1423 | ((eq context 'paren) | ||
| 1424 | (let ((forward-sexp-function)) | ||
| 1425 | (up-list dir))) | ||
| 1426 | ((and forward-p (python-info-end-of-block-p)) | ||
| 1427 | (let ((parent-end-pos | ||
| 1428 | (save-excursion | ||
| 1429 | (let ((indentation (and | ||
| 1430 | (python-nav-beginning-of-block) | ||
| 1431 | (current-indentation)))) | ||
| 1432 | (while (and indentation | ||
| 1433 | (> indentation 0) | ||
| 1434 | (>= (current-indentation) indentation) | ||
| 1435 | (python-nav-backward-block))) | ||
| 1436 | (python-nav-end-of-block))))) | ||
| 1437 | (and (> (or parent-end-pos (point)) (point)) | ||
| 1438 | (goto-char parent-end-pos)))) | ||
| 1439 | (forward-p (python-nav-end-of-block)) | ||
| 1440 | ((and (not forward-p) | ||
| 1441 | (> (current-indentation) 0) | ||
| 1442 | (python-info-beginning-of-block-p)) | ||
| 1443 | (let ((prev-block-pos | ||
| 1444 | (save-excursion | ||
| 1445 | (let ((indentation (current-indentation))) | ||
| 1446 | (while (and (python-nav-backward-block) | ||
| 1447 | (> (current-indentation) indentation)))) | ||
| 1448 | (point)))) | ||
| 1449 | (and (> (point) prev-block-pos) | ||
| 1450 | (goto-char prev-block-pos)))) | ||
| 1451 | ((not forward-p) (python-nav-beginning-of-block))))) | ||
| 1452 | |||
| 1453 | (defun python-nav-up-list (&optional arg) | ||
| 1454 | "Move forward out of one level of parentheses (or blocks). | ||
| 1455 | With ARG, do this that many times. | ||
| 1456 | A negative argument means move backward but still to a less deep spot. | ||
| 1457 | This command assumes point is not in a string or comment." | ||
| 1458 | (interactive "^p") | ||
| 1459 | (or arg (setq arg 1)) | ||
| 1460 | (while (> arg 0) | ||
| 1461 | (python-nav--up-list 1) | ||
| 1462 | (setq arg (1- arg))) | ||
| 1463 | (while (< arg 0) | ||
| 1464 | (python-nav--up-list -1) | ||
| 1465 | (setq arg (1+ arg)))) | ||
| 1466 | |||
| 1467 | (defun python-nav-backward-up-list (&optional arg) | ||
| 1468 | "Move backward out of one level of parentheses (or blocks). | ||
| 1469 | With ARG, do this that many times. | ||
| 1470 | A negative argument means move backward but still to a less deep spot. | ||
| 1471 | This command assumes point is not in a string or comment." | ||
| 1472 | (interactive "^p") | ||
| 1473 | (or arg (setq arg 1)) | ||
| 1474 | (python-nav-up-list (- arg))) | ||
| 1475 | |||
| 1448 | 1476 | ||
| 1449 | ;;; Shell integration | 1477 | ;;; Shell integration |
| 1450 | 1478 | ||
| @@ -1643,6 +1671,22 @@ uniqueness for different types of configurations." | |||
| 1643 | OUTPUT is a string with the contents of the buffer." | 1671 | OUTPUT is a string with the contents of the buffer." |
| 1644 | (ansi-color-filter-apply output)) | 1672 | (ansi-color-filter-apply output)) |
| 1645 | 1673 | ||
| 1674 | (defvar python-shell--parent-buffer nil) | ||
| 1675 | |||
| 1676 | (defvar python-shell-output-syntax-table | ||
| 1677 | (let ((table (make-syntax-table python-dotty-syntax-table))) | ||
| 1678 | (modify-syntax-entry ?\' "." table) | ||
| 1679 | (modify-syntax-entry ?\" "." table) | ||
| 1680 | (modify-syntax-entry ?\( "." table) | ||
| 1681 | (modify-syntax-entry ?\[ "." table) | ||
| 1682 | (modify-syntax-entry ?\{ "." table) | ||
| 1683 | (modify-syntax-entry ?\) "." table) | ||
| 1684 | (modify-syntax-entry ?\] "." table) | ||
| 1685 | (modify-syntax-entry ?\} "." table) | ||
| 1686 | table) | ||
| 1687 | "Syntax table for shell output. | ||
| 1688 | It makes parens and quotes be treated as punctuation chars.") | ||
| 1689 | |||
| 1646 | (define-derived-mode inferior-python-mode comint-mode "Inferior Python" | 1690 | (define-derived-mode inferior-python-mode comint-mode "Inferior Python" |
| 1647 | "Major mode for Python inferior process. | 1691 | "Major mode for Python inferior process. |
| 1648 | Runs a Python interpreter as a subprocess of Emacs, with Python | 1692 | Runs a Python interpreter as a subprocess of Emacs, with Python |
| @@ -1665,7 +1709,12 @@ initialization of the interpreter via `python-shell-setup-codes' | |||
| 1665 | variable. | 1709 | variable. |
| 1666 | 1710 | ||
| 1667 | \(Type \\[describe-mode] in the process buffer for a list of commands.)" | 1711 | \(Type \\[describe-mode] in the process buffer for a list of commands.)" |
| 1668 | (set-syntax-table python-mode-syntax-table) | 1712 | (and python-shell--parent-buffer |
| 1713 | (python-util-clone-local-variables python-shell--parent-buffer)) | ||
| 1714 | (setq comint-prompt-regexp (format "^\\(?:%s\\|%s\\|%s\\)" | ||
| 1715 | python-shell-prompt-regexp | ||
| 1716 | python-shell-prompt-block-regexp | ||
| 1717 | python-shell-prompt-pdb-regexp)) | ||
| 1669 | (setq mode-line-process '(":%s")) | 1718 | (setq mode-line-process '(":%s")) |
| 1670 | (make-local-variable 'comint-output-filter-functions) | 1719 | (make-local-variable 'comint-output-filter-functions) |
| 1671 | (add-hook 'comint-output-filter-functions | 1720 | (add-hook 'comint-output-filter-functions |
| @@ -1686,10 +1735,21 @@ variable. | |||
| 1686 | (make-local-variable 'python-pdbtrack-tracked-buffer) | 1735 | (make-local-variable 'python-pdbtrack-tracked-buffer) |
| 1687 | (make-local-variable 'python-shell-internal-last-output) | 1736 | (make-local-variable 'python-shell-internal-last-output) |
| 1688 | (when python-shell-enable-font-lock | 1737 | (when python-shell-enable-font-lock |
| 1738 | (set-syntax-table python-mode-syntax-table) | ||
| 1689 | (set (make-local-variable 'font-lock-defaults) | 1739 | (set (make-local-variable 'font-lock-defaults) |
| 1690 | '(python-font-lock-keywords nil nil nil nil)) | 1740 | '(python-font-lock-keywords nil nil nil nil)) |
| 1691 | (set (make-local-variable 'syntax-propertize-function) | 1741 | (set (make-local-variable 'syntax-propertize-function) |
| 1692 | python-syntax-propertize-function)) | 1742 | (syntax-propertize-rules |
| 1743 | (comint-prompt-regexp | ||
| 1744 | (0 (ignore | ||
| 1745 | (put-text-property | ||
| 1746 | comint-last-input-start end 'syntax-table | ||
| 1747 | python-shell-output-syntax-table) | ||
| 1748 | (font-lock-unfontify-region comint-last-input-start end)))) | ||
| 1749 | ((python-rx string-delimiter) | ||
| 1750 | (0 (ignore | ||
| 1751 | (and (not (eq (get-text-property start 'field) 'output)) | ||
| 1752 | (python-syntax-stringify)))))))) | ||
| 1693 | (compilation-shell-minor-mode 1)) | 1753 | (compilation-shell-minor-mode 1)) |
| 1694 | 1754 | ||
| 1695 | (defun python-shell-make-comint (cmd proc-name &optional pop internal) | 1755 | (defun python-shell-make-comint (cmd proc-name &optional pop internal) |
| @@ -1712,15 +1772,10 @@ killed." | |||
| 1712 | (let* ((cmdlist (split-string-and-unquote cmd)) | 1772 | (let* ((cmdlist (split-string-and-unquote cmd)) |
| 1713 | (buffer (apply #'make-comint-in-buffer proc-name proc-buffer-name | 1773 | (buffer (apply #'make-comint-in-buffer proc-name proc-buffer-name |
| 1714 | (car cmdlist) nil (cdr cmdlist))) | 1774 | (car cmdlist) nil (cdr cmdlist))) |
| 1715 | (current-buffer (current-buffer)) | 1775 | (python-shell--parent-buffer (current-buffer)) |
| 1716 | (process (get-buffer-process buffer))) | 1776 | (process (get-buffer-process buffer))) |
| 1717 | (with-current-buffer buffer | 1777 | (with-current-buffer buffer |
| 1718 | (inferior-python-mode) | 1778 | (inferior-python-mode)) |
| 1719 | (python-util-clone-local-variables current-buffer) | ||
| 1720 | (setq comint-prompt-regexp (format "^\\(?:%s\\|%s\\|%s\\)" | ||
| 1721 | python-shell-prompt-regexp | ||
| 1722 | python-shell-prompt-block-regexp | ||
| 1723 | python-shell-prompt-pdb-regexp))) | ||
| 1724 | (accept-process-output process) | 1779 | (accept-process-output process) |
| 1725 | (and pop (pop-to-buffer buffer t)) | 1780 | (and pop (pop-to-buffer buffer t)) |
| 1726 | (and internal (set-process-query-on-exit-flag process nil)))) | 1781 | (and internal (set-process-query-on-exit-flag process nil)))) |
| @@ -1875,7 +1930,9 @@ detecting a prompt at the end of the buffer." | |||
| 1875 | python-shell-output-filter-buffer | 1930 | python-shell-output-filter-buffer |
| 1876 | (concat python-shell-output-filter-buffer string)) | 1931 | (concat python-shell-output-filter-buffer string)) |
| 1877 | (when (string-match | 1932 | (when (string-match |
| 1878 | (format "\n\\(?:%s\\|%s\\|%s\\)$" | 1933 | ;; XXX: It seems on OSX an extra carriage return is attached |
| 1934 | ;; at the end of output, this handles that too. | ||
| 1935 | (format "\r?\n\\(?:%s\\|%s\\|%s\\)$" | ||
| 1879 | python-shell-prompt-regexp | 1936 | python-shell-prompt-regexp |
| 1880 | python-shell-prompt-block-regexp | 1937 | python-shell-prompt-block-regexp |
| 1881 | python-shell-prompt-pdb-regexp) | 1938 | python-shell-prompt-pdb-regexp) |
| @@ -2279,28 +2336,28 @@ inferior python process is updated properly." | |||
| 2279 | 2336 | ||
| 2280 | (defcustom python-fill-comment-function 'python-fill-comment | 2337 | (defcustom python-fill-comment-function 'python-fill-comment |
| 2281 | "Function to fill comments. | 2338 | "Function to fill comments. |
| 2282 | This is the function used by `python-fill-paragraph-function' to | 2339 | This is the function used by `python-fill-paragraph' to |
| 2283 | fill comments." | 2340 | fill comments." |
| 2284 | :type 'symbol | 2341 | :type 'symbol |
| 2285 | :group 'python) | 2342 | :group 'python) |
| 2286 | 2343 | ||
| 2287 | (defcustom python-fill-string-function 'python-fill-string | 2344 | (defcustom python-fill-string-function 'python-fill-string |
| 2288 | "Function to fill strings. | 2345 | "Function to fill strings. |
| 2289 | This is the function used by `python-fill-paragraph-function' to | 2346 | This is the function used by `python-fill-paragraph' to |
| 2290 | fill strings." | 2347 | fill strings." |
| 2291 | :type 'symbol | 2348 | :type 'symbol |
| 2292 | :group 'python) | 2349 | :group 'python) |
| 2293 | 2350 | ||
| 2294 | (defcustom python-fill-decorator-function 'python-fill-decorator | 2351 | (defcustom python-fill-decorator-function 'python-fill-decorator |
| 2295 | "Function to fill decorators. | 2352 | "Function to fill decorators. |
| 2296 | This is the function used by `python-fill-paragraph-function' to | 2353 | This is the function used by `python-fill-paragraph' to |
| 2297 | fill decorators." | 2354 | fill decorators." |
| 2298 | :type 'symbol | 2355 | :type 'symbol |
| 2299 | :group 'python) | 2356 | :group 'python) |
| 2300 | 2357 | ||
| 2301 | (defcustom python-fill-paren-function 'python-fill-paren | 2358 | (defcustom python-fill-paren-function 'python-fill-paren |
| 2302 | "Function to fill parens. | 2359 | "Function to fill parens. |
| 2303 | This is the function used by `python-fill-paragraph-function' to | 2360 | This is the function used by `python-fill-paragraph' to |
| 2304 | fill parens." | 2361 | fill parens." |
| 2305 | :type 'symbol | 2362 | :type 'symbol |
| 2306 | :group 'python) | 2363 | :group 'python) |
| @@ -2377,7 +2434,7 @@ SYMMETRIC: | |||
| 2377 | :safe (lambda (val) | 2434 | :safe (lambda (val) |
| 2378 | (memq val '(django onetwo pep-257 pep-257-nn symmetric nil)))) | 2435 | (memq val '(django onetwo pep-257 pep-257-nn symmetric nil)))) |
| 2379 | 2436 | ||
| 2380 | (defun python-fill-paragraph-function (&optional justify) | 2437 | (defun python-fill-paragraph (&optional justify) |
| 2381 | "`fill-paragraph-function' handling multi-line strings and possibly comments. | 2438 | "`fill-paragraph-function' handling multi-line strings and possibly comments. |
| 2382 | If any of the current line is in or at the end of a multi-line string, | 2439 | If any of the current line is in or at the end of a multi-line string, |
| 2383 | fill the string or the paragraph of it that point is in, preserving | 2440 | fill the string or the paragraph of it that point is in, preserving |
| @@ -2396,8 +2453,7 @@ Optional argument JUSTIFY defines if the paragraph should be justified." | |||
| 2396 | (funcall python-fill-string-function justify)) | 2453 | (funcall python-fill-string-function justify)) |
| 2397 | ;; Decorators | 2454 | ;; Decorators |
| 2398 | ((equal (char-after (save-excursion | 2455 | ((equal (char-after (save-excursion |
| 2399 | (back-to-indentation) | 2456 | (python-nav-beginning-of-statement))) ?@) |
| 2400 | (point))) ?@) | ||
| 2401 | (funcall python-fill-decorator-function justify)) | 2457 | (funcall python-fill-decorator-function justify)) |
| 2402 | ;; Parens | 2458 | ;; Parens |
| 2403 | ((or (python-syntax-context 'paren) | 2459 | ((or (python-syntax-context 'paren) |
| @@ -2409,12 +2465,12 @@ Optional argument JUSTIFY defines if the paragraph should be justified." | |||
| 2409 | (t t)))) | 2465 | (t t)))) |
| 2410 | 2466 | ||
| 2411 | (defun python-fill-comment (&optional justify) | 2467 | (defun python-fill-comment (&optional justify) |
| 2412 | "Comment fill function for `python-fill-paragraph-function'. | 2468 | "Comment fill function for `python-fill-paragraph'. |
| 2413 | JUSTIFY should be used (if applicable) as in `fill-paragraph'." | 2469 | JUSTIFY should be used (if applicable) as in `fill-paragraph'." |
| 2414 | (fill-comment-paragraph justify)) | 2470 | (fill-comment-paragraph justify)) |
| 2415 | 2471 | ||
| 2416 | (defun python-fill-string (&optional justify) | 2472 | (defun python-fill-string (&optional justify) |
| 2417 | "String fill function for `python-fill-paragraph-function'. | 2473 | "String fill function for `python-fill-paragraph'. |
| 2418 | JUSTIFY should be used (if applicable) as in `fill-paragraph'." | 2474 | JUSTIFY should be used (if applicable) as in `fill-paragraph'." |
| 2419 | (let* ((marker (point-marker)) | 2475 | (let* ((marker (point-marker)) |
| 2420 | (str-start-pos | 2476 | (str-start-pos |
| @@ -2484,12 +2540,12 @@ JUSTIFY should be used (if applicable) as in `fill-paragraph'." | |||
| 2484 | (indent-according-to-mode))))) t) | 2540 | (indent-according-to-mode))))) t) |
| 2485 | 2541 | ||
| 2486 | (defun python-fill-decorator (&optional justify) | 2542 | (defun python-fill-decorator (&optional justify) |
| 2487 | "Decorator fill function for `python-fill-paragraph-function'. | 2543 | "Decorator fill function for `python-fill-paragraph'. |
| 2488 | JUSTIFY should be used (if applicable) as in `fill-paragraph'." | 2544 | JUSTIFY should be used (if applicable) as in `fill-paragraph'." |
| 2489 | t) | 2545 | t) |
| 2490 | 2546 | ||
| 2491 | (defun python-fill-paren (&optional justify) | 2547 | (defun python-fill-paren (&optional justify) |
| 2492 | "Paren fill function for `python-fill-paragraph-function'. | 2548 | "Paren fill function for `python-fill-paragraph'. |
| 2493 | JUSTIFY should be used (if applicable) as in `fill-paragraph'." | 2549 | JUSTIFY should be used (if applicable) as in `fill-paragraph'." |
| 2494 | (save-restriction | 2550 | (save-restriction |
| 2495 | (narrow-to-region (progn | 2551 | (narrow-to-region (progn |
| @@ -2879,12 +2935,43 @@ parent defun name." | |||
| 2879 | ".") ".") | 2935 | ".") ".") |
| 2880 | name))))))) | 2936 | name))))))) |
| 2881 | 2937 | ||
| 2882 | (defsubst python-info-beginning-of-block-statement-p () | 2938 | (defun python-info-statement-starts-block-p () |
| 2883 | "Return non-nil if current statement opens a block." | 2939 | "Return non-nil if current statement opens a block." |
| 2884 | (save-excursion | 2940 | (save-excursion |
| 2885 | (python-nav-beginning-of-statement) | 2941 | (python-nav-beginning-of-statement) |
| 2886 | (looking-at (python-rx block-start)))) | 2942 | (looking-at (python-rx block-start)))) |
| 2887 | 2943 | ||
| 2944 | (defun python-info-statement-ends-block-p () | ||
| 2945 | "Return non-nil if point is at end of block." | ||
| 2946 | (let ((end-of-block-pos (save-excursion | ||
| 2947 | (python-nav-end-of-block))) | ||
| 2948 | (end-of-statement-pos (save-excursion | ||
| 2949 | (python-nav-end-of-statement)))) | ||
| 2950 | (and end-of-block-pos end-of-statement-pos | ||
| 2951 | (= end-of-block-pos end-of-statement-pos)))) | ||
| 2952 | |||
| 2953 | (defun python-info-beginning-of-statement-p () | ||
| 2954 | "Return non-nil if point is at beginning of statement." | ||
| 2955 | (= (point) (save-excursion | ||
| 2956 | (python-nav-beginning-of-statement) | ||
| 2957 | (point)))) | ||
| 2958 | |||
| 2959 | (defun python-info-end-of-statement-p () | ||
| 2960 | "Return non-nil if point is at end of statement." | ||
| 2961 | (= (point) (save-excursion | ||
| 2962 | (python-nav-end-of-statement) | ||
| 2963 | (point)))) | ||
| 2964 | |||
| 2965 | (defun python-info-beginning-of-block-p () | ||
| 2966 | "Return non-nil if point is at beginning of block." | ||
| 2967 | (and (python-info-beginning-of-statement-p) | ||
| 2968 | (python-info-statement-starts-block-p))) | ||
| 2969 | |||
| 2970 | (defun python-info-end-of-block-p () | ||
| 2971 | "Return non-nil if point is at end of block." | ||
| 2972 | (and (python-info-end-of-statement-p) | ||
| 2973 | (python-info-statement-ends-block-p))) | ||
| 2974 | |||
| 2888 | (defun python-info-closing-block () | 2975 | (defun python-info-closing-block () |
| 2889 | "Return the point of the block the current line closes." | 2976 | "Return the point of the block the current line closes." |
| 2890 | (let ((closing-word (save-excursion | 2977 | (let ((closing-word (save-excursion |
| @@ -3109,7 +3196,7 @@ if that value is non-nil." | |||
| 3109 | 3196 | ||
| 3110 | (set (make-local-variable 'paragraph-start) "\\s-*$") | 3197 | (set (make-local-variable 'paragraph-start) "\\s-*$") |
| 3111 | (set (make-local-variable 'fill-paragraph-function) | 3198 | (set (make-local-variable 'fill-paragraph-function) |
| 3112 | 'python-fill-paragraph-function) | 3199 | 'python-fill-paragraph) |
| 3113 | 3200 | ||
| 3114 | (set (make-local-variable 'beginning-of-defun-function) | 3201 | (set (make-local-variable 'beginning-of-defun-function) |
| 3115 | #'python-beginning-of-defun-function) | 3202 | #'python-beginning-of-defun-function) |