aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
authorFabián Ezequiel Gallina2014-12-27 01:30:21 -0300
committerFabián Ezequiel Gallina2014-12-27 01:30:21 -0300
commit2dd5163d764f395eb31a2306dba385d123af4aba (patch)
tree27b1ade1b6af5e984040a8acc840f81ee4f5adaa /lisp/progmodes/python.el
parent7aa506eed8881788485a9774165454404bac2623 (diff)
downloademacs-2dd5163d764f395eb31a2306dba385d123af4aba.tar.gz
emacs-2dd5163d764f395eb31a2306dba385d123af4aba.zip
python.el: Handle file encoding for shell.
* lisp/progmodes/python.el (python-rx-constituents): Add coding-cookie. (python-shell--save-temp-file): Write file with proper encoding. (python-shell-buffer-substring): Add coding cookie for detected encoding to generated content. Fix blank lines when removing if-name-main block. (python-shell-send-file): Handle file encoding. (python-info-encoding-from-cookie) (python-info-encoding): New functions. * test/automated/python-tests.el (python-shell-buffer-substring-1) (python-shell-buffer-substring-2, python-shell-buffer-substring-3) (python-shell-buffer-substring-4, python-shell-buffer-substring-5) (python-shell-buffer-substring-6, python-shell-buffer-substring-7) (python-shell-buffer-substring-8) (python-info-encoding-from-cookie-1) (python-info-encoding-from-cookie-2) (python-info-encoding-from-cookie-3) (python-info-encoding-from-cookie-4) (python-info-encoding-from-cookie-5) (python-info-encoding-from-cookie-6) (python-info-encoding-from-cookie-7, python-info-encoding-1) (python-info-encoding-2): New tests.
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el110
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.
3951Returns 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.
3966Try `python-info-encoding-from-cookie', if none is found then
3967default 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