diff options
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 110 |
1 files changed, 85 insertions, 25 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 632659c28bb..02d0cbef262 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -386,7 +386,18 @@ | |||
| 386 | (* ?\\ ?\\) (any ?\' ?\"))) | 386 | (* ?\\ ?\\) (any ?\' ?\"))) |
| 387 | (* ?\\ ?\\) | 387 | (* ?\\ ?\\) |
| 388 | ;; Match single or triple quotes of any kind. | 388 | ;; Match single or triple quotes of any kind. |
| 389 | (group (or "\"" "\"\"\"" "'" "'''")))))) | 389 | (group (or "\"" "\"\"\"" "'" "'''"))))) |
| 390 | (coding-cookie . ,(rx line-start ?# (* space) | ||
| 391 | (or | ||
| 392 | ;; # coding=<encoding name> | ||
| 393 | (: "coding" (or ?: ?=) (* space) (group-n 1 (+ (or word ?-)))) | ||
| 394 | ;; # -*- coding: <encoding name> -*- | ||
| 395 | (: "-*-" (* space) "coding:" (* space) | ||
| 396 | (group-n 1 (+ (or word ?-))) (* space) "-*-") | ||
| 397 | ;; # vim: set fileencoding=<encoding name> : | ||
| 398 | (: "vim:" (* space) "set" (+ space) | ||
| 399 | "fileencoding" (* space) ?= (* space) | ||
| 400 | (group-n 1 (+ (or word ?-))) (* space) ":"))))) | ||
| 390 | "Additional Python specific sexps for `python-rx'") | 401 | "Additional Python specific sexps for `python-rx'") |
| 391 | 402 | ||
| 392 | (defmacro python-rx (&rest regexps) | 403 | (defmacro python-rx (&rest regexps) |
| @@ -2400,11 +2411,7 @@ there for compatibility with CEDET.") | |||
| 2400 | (concat (file-remote-p default-directory) "/tmp") | 2411 | (concat (file-remote-p default-directory) "/tmp") |
| 2401 | temporary-file-directory)) | 2412 | temporary-file-directory)) |
| 2402 | (temp-file-name (make-temp-file "py")) | 2413 | (temp-file-name (make-temp-file "py")) |
| 2403 | ;; XXX: Python's built-in compile function accepts utf-8 as | 2414 | (coding-system-for-write (python-info-encoding))) |
| 2404 | ;; input so there's no need to enforce a coding cookie. In | ||
| 2405 | ;; the future making `coding-system-for-write' match the | ||
| 2406 | ;; current buffer's coding may be a good idea. | ||
| 2407 | (coding-system-for-write 'utf-8)) | ||
| 2408 | (with-temp-file temp-file-name | 2415 | (with-temp-file temp-file-name |
| 2409 | (insert string) | 2416 | (insert string) |
| 2410 | (delete-trailing-whitespace)) | 2417 | (delete-trailing-whitespace)) |
| @@ -2511,16 +2518,28 @@ the python shell: | |||
| 2511 | \"if __name__ == '__main__'\" block will be removed. | 2518 | \"if __name__ == '__main__'\" block will be removed. |
| 2512 | 2. When a subregion of the buffer is sent, it takes care of | 2519 | 2. When a subregion of the buffer is sent, it takes care of |
| 2513 | appending extra empty lines so tracebacks are correct. | 2520 | appending extra empty lines so tracebacks are correct. |
| 2514 | 3. Wraps indented regions under an \"if True:\" block so the | 2521 | 3. When the region sent is a substring of the current buffer, a |
| 2522 | coding cookie is added. | ||
| 2523 | 4. Wraps indented regions under an \"if True:\" block so the | ||
| 2515 | interpreter evaluates them correctly." | 2524 | interpreter evaluates them correctly." |
| 2516 | (let ((substring (buffer-substring-no-properties start end)) | 2525 | (let* ((substring (buffer-substring-no-properties start end)) |
| 2517 | (fillstr (make-string (1- (line-number-at-pos start)) ?\n)) | 2526 | (buffer-substring-p (save-restriction |
| 2518 | (toplevel-block-p (save-excursion | 2527 | (widen) |
| 2519 | (goto-char start) | 2528 | (not (equal (list (point-min) (point-max)) |
| 2520 | (or (zerop (line-number-at-pos start)) | 2529 | (list start end))))) |
| 2521 | (progn | 2530 | (encoding (python-info-encoding)) |
| 2522 | (python-util-forward-comment 1) | 2531 | (fillstr (concat |
| 2523 | (zerop (current-indentation))))))) | 2532 | (when buffer-substring-p |
| 2533 | (format "# -*- coding: %s -*-\n" encoding)) | ||
| 2534 | (make-string | ||
| 2535 | (- (line-number-at-pos start) | ||
| 2536 | (if buffer-substring-p 2 1)) ?\n))) | ||
| 2537 | (toplevel-block-p (save-excursion | ||
| 2538 | (goto-char start) | ||
| 2539 | (or (zerop (line-number-at-pos start)) | ||
| 2540 | (progn | ||
| 2541 | (python-util-forward-comment 1) | ||
| 2542 | (zerop (current-indentation))))))) | ||
| 2524 | (with-temp-buffer | 2543 | (with-temp-buffer |
| 2525 | (python-mode) | 2544 | (python-mode) |
| 2526 | (if fillstr (insert fillstr)) | 2545 | (if fillstr (insert fillstr)) |
| @@ -2536,17 +2555,26 @@ the python shell: | |||
| 2536 | (when (python-nav-if-name-main) | 2555 | (when (python-nav-if-name-main) |
| 2537 | (cons (point) | 2556 | (cons (point) |
| 2538 | (progn (python-nav-forward-sexp-safe) | 2557 | (progn (python-nav-forward-sexp-safe) |
| 2558 | ;; Include ending newline | ||
| 2559 | (forward-line 1) | ||
| 2539 | (point))))))) | 2560 | (point))))))) |
| 2540 | ;; Oh destructuring bind, how I miss you. | 2561 | ;; Oh destructuring bind, how I miss you. |
| 2541 | (if-name-main-start (car if-name-main-start-end)) | 2562 | (if-name-main-start (car if-name-main-start-end)) |
| 2542 | (if-name-main-end (cdr if-name-main-start-end))) | 2563 | (if-name-main-end (cdr if-name-main-start-end)) |
| 2564 | (fillstr (make-string | ||
| 2565 | (- (line-number-at-pos if-name-main-end) | ||
| 2566 | (line-number-at-pos if-name-main-start)) ?\n))) | ||
| 2543 | (when if-name-main-start-end | 2567 | (when if-name-main-start-end |
| 2544 | (goto-char if-name-main-start) | 2568 | (goto-char if-name-main-start) |
| 2545 | (delete-region if-name-main-start if-name-main-end) | 2569 | (delete-region if-name-main-start if-name-main-end) |
| 2546 | (insert | 2570 | (insert fillstr)))) |
| 2547 | (make-string | 2571 | ;; Ensure there's only one coding cookie in the generated string. |
| 2548 | (- (line-number-at-pos if-name-main-end) | 2572 | (goto-char (point-min)) |
| 2549 | (line-number-at-pos if-name-main-start)) ?\n))))) | 2573 | (when (looking-at-p (python-rx coding-cookie)) |
| 2574 | (forward-line 1) | ||
| 2575 | (when (looking-at-p (python-rx coding-cookie)) | ||
| 2576 | (delete-region | ||
| 2577 | (line-beginning-position) (line-end-position)))) | ||
| 2550 | (buffer-substring-no-properties (point-min) (point-max))))) | 2578 | (buffer-substring-no-properties (point-min) (point-max))))) |
| 2551 | 2579 | ||
| 2552 | (defun python-shell-send-region (start end &optional nomain) | 2580 | (defun python-shell-send-region (start end &optional nomain) |
| @@ -2604,15 +2632,21 @@ If DELETE is non-nil, delete the file afterwards." | |||
| 2604 | (expand-file-name | 2632 | (expand-file-name |
| 2605 | (or (file-remote-p file-name 'localname) | 2633 | (or (file-remote-p file-name 'localname) |
| 2606 | file-name))) | 2634 | file-name))) |
| 2607 | temp-file-name))) | 2635 | temp-file-name)) |
| 2636 | (encoding | ||
| 2637 | (with-temp-buffer | ||
| 2638 | (insert-file-contents | ||
| 2639 | (or temp-file-name file-name)) | ||
| 2640 | (python-info-encoding)))) | ||
| 2608 | (when (not file-name) | 2641 | (when (not file-name) |
| 2609 | (error "If FILE-NAME is nil then TEMP-FILE-NAME must be non-nil")) | 2642 | (error "If FILE-NAME is nil then TEMP-FILE-NAME must be non-nil")) |
| 2610 | (python-shell-send-string | 2643 | (python-shell-send-string |
| 2611 | (format | 2644 | (format |
| 2612 | (concat "__pyfile = open('''%s''');" | 2645 | (concat |
| 2613 | "exec(compile(__pyfile.read(), '''%s''', 'exec'));" | 2646 | "import codecs; __pyfile = codecs.open('''%s''', encoding='''%s''');" |
| 2614 | "__pyfile.close()%s") | 2647 | "exec(compile(__pyfile.read().encode('''%s'''), '''%s''', 'exec'));" |
| 2615 | (or temp-file-name file-name) file-name | 2648 | "__pyfile.close()%s") |
| 2649 | (or temp-file-name file-name) encoding encoding file-name | ||
| 2616 | (if delete (format "; import os; os.remove('''%s''')" | 2650 | (if delete (format "; import os; os.remove('''%s''')" |
| 2617 | (or temp-file-name file-name)) | 2651 | (or temp-file-name file-name)) |
| 2618 | "")) | 2652 | "")) |
| @@ -3912,6 +3946,32 @@ operator." | |||
| 3912 | (* whitespace) line-end)) | 3946 | (* whitespace) line-end)) |
| 3913 | (string-equal "" (match-string-no-properties 1)))) | 3947 | (string-equal "" (match-string-no-properties 1)))) |
| 3914 | 3948 | ||
| 3949 | (defun python-info-encoding-from-cookie () | ||
| 3950 | "Detect current buffer's encoding from its coding cookie. | ||
| 3951 | Returns the enconding as a symbol." | ||
| 3952 | (let ((first-two-lines | ||
| 3953 | (save-excursion | ||
| 3954 | (save-restriction | ||
| 3955 | (widen) | ||
| 3956 | (goto-char (point-min)) | ||
| 3957 | (forward-line 2) | ||
| 3958 | (buffer-substring-no-properties | ||
| 3959 | (point) | ||
| 3960 | (point-min)))))) | ||
| 3961 | (when (string-match (python-rx coding-cookie) first-two-lines) | ||
| 3962 | (intern (match-string-no-properties 1 first-two-lines))))) | ||
| 3963 | |||
| 3964 | (defun python-info-encoding () | ||
| 3965 | "Return encoding for file. | ||
| 3966 | Try `python-info-encoding-from-cookie', if none is found then | ||
| 3967 | default to utf-8." | ||
| 3968 | ;; If no enconding is defined, then it's safe to use UTF-8: Python 2 | ||
| 3969 | ;; uses ASCII as default while Python 3 uses UTF-8. This means that | ||
| 3970 | ;; in the worst case escenario python.el will make things work for | ||
| 3971 | ;; Python 2 files with unicode data and no encoding defined. | ||
| 3972 | (or (python-info-encoding-from-cookie) | ||
| 3973 | 'utf-8)) | ||
| 3974 | |||
| 3915 | 3975 | ||
| 3916 | ;;; Utility functions | 3976 | ;;; Utility functions |
| 3917 | 3977 | ||