aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el643
1 files changed, 379 insertions, 264 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 1028e937924..bfa507b851a 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -38,7 +38,7 @@
38 38
39;; This doesn't implement all the facilities of python-mode.el. Some 39;; This doesn't implement all the facilities of python-mode.el. Some
40;; just need doing, e.g. catching exceptions in the inferior Python 40;; just need doing, e.g. catching exceptions in the inferior Python
41;; buffer (but see M-x pdb for debugging). [Atually, the use of 41;; buffer (but see M-x pdb for debugging). [Actually, the use of
42;; `compilation-minor-mode' now is probably enough for that.] Others 42;; `compilation-minor-mode' now is probably enough for that.] Others
43;; don't seem appropriate. For instance, `forward-into-nomenclature' 43;; don't seem appropriate. For instance, `forward-into-nomenclature'
44;; should be done separately, since it's not specific to Python, and 44;; should be done separately, since it's not specific to Python, and
@@ -56,16 +56,25 @@
56;; bindings are changed to obey Emacs conventions, and things like 56;; bindings are changed to obey Emacs conventions, and things like
57;; marking blocks and `beginning-of-defun' behave differently. 57;; marking blocks and `beginning-of-defun' behave differently.
58 58
59;; TODO: See various Fixmes below. It should be possible to arrange
60;; some sort of completion using the inferior interpreter.
61
59;;; Code: 62;;; Code:
60 63
61(require 'syntax) ; ensure appropriate version
62;; It's messy to autoload the relevant comint functions so that comint 64;; It's messy to autoload the relevant comint functions so that comint
63;; is only required when inferior Python is used. 65;; is only required when inferior Python is used.
64(require 'comint) 66(require 'comint)
67(eval-when-compile
68 (require 'compile)
69 (autoload 'Info-last "info")
70 (autoload 'Info-exit "info")
71 (autoload 'info-lookup-maybe-add-help "info-look"))
72(autoload 'compilation-start "compile") ; spurious compiler warning anyway
65 73
66(defgroup python nil 74(defgroup python nil
67 "Silly walks in the Python language" 75 "Silly walks in the Python language"
68 :group 'languages 76 :group 'languages
77 :version "21.4"
69 :link '(emacs-commentary-link "python")) 78 :link '(emacs-commentary-link "python"))
70 79
71;;;###autoload 80;;;###autoload
@@ -101,7 +110,8 @@
101 (group (syntax string-quote)) ; maybe gets property 110 (group (syntax string-quote)) ; maybe gets property
102 (backref 2) ; per first quote 111 (backref 2) ; per first quote
103 (group (backref 2)))) ; maybe gets property 112 (group (backref 2)))) ; maybe gets property
104 (1 (python-quote-syntax 1)) (2 (python-quote-syntax 2)) 113 (1 (python-quote-syntax 1))
114 (2 (python-quote-syntax 2))
105 (3 (python-quote-syntax 3))) 115 (3 (python-quote-syntax 3)))
106 ;; This doesn't really help. 116 ;; This doesn't really help.
107;;; (,(rx (and ?\\ (group ?\n))) (1 " ")) 117;;; (,(rx (and ?\\ (group ?\n))) (1 " "))
@@ -110,40 +120,43 @@
110(defun python-quote-syntax (n) 120(defun python-quote-syntax (n)
111 "Put `syntax-table' property correctly on triple quote. 121 "Put `syntax-table' property correctly on triple quote.
112Used for syntactic keywords. N is the match number (1, 2 or 3)." 122Used for syntactic keywords. N is the match number (1, 2 or 3)."
113 ;; Given a triple quote, we have to look backwards for a previous 123 ;; Given a triple quote, we have to check the context to know
114 ;; occurrence of the sequence to know whether this is an opening or 124 ;; whether this is an opening or closing triple or whether it's
115 ;; closing triple. We also have to sort out a possible prefix -- 125 ;; quoted anyhow, and should be ignored. (For that we need to do
116 ;; well, we don't _have_ to, but I think it should be treated as 126 ;; the same job as `syntax-ppss' to be correct and it seems to be OK
117 ;; part of the string. 127 ;; to use it here despite initial worries.) We also have to sort
118 (let ((tag (save-excursion 128 ;; out a possible prefix -- well, we don't _have_ to, but I think it
119 (goto-char (match-beginning 0)) 129 ;; should be treated as part of the string.
120 (unless (eq ?\\ (char-before)) 130
121 (cond 131 ;; Test cases:
122 ;; Look for a previous string fence. 132 ;; ur"""ar""" x='"' # """
123 ((or (zerop (skip-syntax-backward "^|")) 133 ;; x = ''' """ ' a
124 (bobp)) 134 ;; '''
125 'start) ; no previous string fence 135 ;; x '"""' x
126 ;; Check fence on a matching quote. 136 (save-excursion
127 ((eq (char-before) (char-after (match-beginning 2))) 137 (goto-char (match-beginning 0))
128 (if (eq (char-before) (char-after)) 138 (unless (eq ?\\ (char-before))
129 'end ; fence ended string 139 (cond
130 'start)) ; began string 140 ;; Consider property for the last char if in a fenced string.
131 ;; Check for matching prefixed string. 141 ((= n 3)
132 ((and (memq (char-before) '(?u ?U ?r ?R)) 142 (let ((syntax (syntax-ppss)))
133 (skip-chars-forward "rR")) 143 (when (eq t (nth 3 syntax)) ; after unclosed fence
134 (if (eq (char-after) (char-after (match-beginning 2))) 144 (goto-char (nth 8 syntax)) ; fence position
135 'end)) ; else non-matching: return nil 145 ;; Skip any prefix.
136 ;; For non-matching quote, start new string. 146 (if (memq (char-after) '(?u ?U ?R ?r))
137 ((/= (char-before) (char-after)) 147 (skip-chars-forward "uUrR"))
138 'start)))))) 148 ;; Is it a matching sequence?
139 (if (if (eq tag 'start) ; Maybe starts a new string. 149 (if (eq (char-after) (char-after (match-beginning 2)))
140 ;; Initial property if this is the prefix (empty or not) or 150 (eval-when-compile (string-to-syntax "|"))))))
141 ;; isn't the prefix and the prefix is empty. 151 ;; Consider property for initial char, accounting for prefixes.
142 (or (= n 1) (and (= n 2) (= (match-beginning 1) (match-end 1)))) 152 ((or (and (= n 2) ; not prefix
143 (and (eq tag 'end) ; Maybe ends existing string. 153 (= (match-beginning 1) (match-end 1))) ; prefix is null
144 (= n 3))) ; Match is at end. 154 (and (= n 1) ; prefix
145 (eval-when-compile (string-to-syntax "|")) 155 (/= (match-beginning 1) (match-end 1)))) ; non-empty
146 ;; Otherwise the property is nil, which is OK. 156 (unless (eq 'string (syntax-ppss-context (syntax-ppss)))
157 (eval-when-compile (string-to-syntax "|")))))
158 ;; Otherwise (we're in a non-matching string) the property is
159 ;; nil, which is OK.
147 ))) 160 )))
148 161
149;; This isn't currently in `font-lock-defaults' as probably not worth 162;; This isn't currently in `font-lock-defaults' as probably not worth
@@ -386,27 +399,29 @@ Continuation lines follow a backslash-terminated line starting a statement."
386Set `python-indent' locally to the value guessed." 399Set `python-indent' locally to the value guessed."
387 (interactive) 400 (interactive)
388 (save-excursion 401 (save-excursion
389 (goto-char (point-min)) 402 (save-restriction
390 (let (done indent) 403 (widen)
391 (while (and (not done) (not (eobp))) 404 (goto-char (point-min))
392 (when (and (re-search-forward (rx (and ?: (0+ space) 405 (let (done indent)
393 (or (syntax comment-start) 406 (while (and (not done) (not (eobp)))
394 line-end))) 407 (when (and (re-search-forward (rx (and ?: (0+ space)
395 nil 'move) 408 (or (syntax comment-start)
396 (python-open-block-statement-p)) 409 line-end)))
397 (save-excursion 410 nil 'move)
398 (python-beginning-of-statement) 411 (python-open-block-statement-p))
399 (let ((initial (current-indentation))) 412 (save-excursion
400 (if (zerop (python-next-statement)) 413 (python-beginning-of-statement)
401 (setq indent (- (current-indentation) initial))) 414 (let ((initial (current-indentation)))
402 (if (and (>= indent 2) (<= indent 8)) ; sanity check 415 (if (zerop (python-next-statement))
403 (setq done t)))))) 416 (setq indent (- (current-indentation) initial)))
404 (when done 417 (if (and (>= indent 2) (<= indent 8)) ; sanity check
405 (when (/= indent (default-value 'python-indent)) 418 (setq done t))))))
406 (set (make-local-variable 'python-indent) indent) 419 (when done
407 (unless (= tab-width python-indent) 420 (when (/= indent (default-value 'python-indent))
408 (setq indent-tabs-mode nil))) 421 (set (make-local-variable 'python-indent) indent)
409 indent)))) 422 (unless (= tab-width python-indent)
423 (setq indent-tabs-mode nil)))
424 indent)))))
410 425
411(defun python-calculate-indentation () 426(defun python-calculate-indentation ()
412 "Calculate Python indentation for line at point." 427 "Calculate Python indentation for line at point."
@@ -590,7 +605,7 @@ start of buffer."
590 (def-re (rx (and line-start (0+ space) (or "def" "class") 605 (def-re (rx (and line-start (0+ space) (or "def" "class")
591 (1+ space) 606 (1+ space)
592 (group (1+ (or word (syntax symbol))))))) 607 (group (1+ (or word (syntax symbol)))))))
593 point found lep def-line) 608 found lep def-line)
594 (if (python-comment-line-p) 609 (if (python-comment-line-p)
595 (setq ci most-positive-fixnum)) 610 (setq ci most-positive-fixnum))
596 (while (and (not (bobp)) (not found)) 611 (while (and (not (bobp)) (not found))
@@ -807,6 +822,7 @@ move and return nil. Otherwise return t."
807 822
808;;;; Imenu. 823;;;; Imenu.
809 824
825(defvar python-recursing)
810(defun python-imenu-create-index () 826(defun python-imenu-create-index ()
811 "`imenu-create-index-function' for Python. 827 "`imenu-create-index-function' for Python.
812 828
@@ -814,10 +830,10 @@ Makes nested Imenu menus from nested `class' and `def' statements.
814The nested menus are headed by an item referencing the outer 830The nested menus are headed by an item referencing the outer
815definition; it has a space prepended to the name so that it sorts 831definition; it has a space prepended to the name so that it sorts
816first with `imenu--sort-by-name'." 832first with `imenu--sort-by-name'."
817 (unless (boundp 'recursing) ; dynamically bound below 833 (unless (boundp 'python-recursing) ; dynamically bound below
818 (goto-char (point-min))) ; normal call from Imenu 834 (goto-char (point-min))) ; normal call from Imenu
819 (let (index-alist ; accumulated value to return 835 (let (index-alist ; accumulated value to return
820 name is-class pos) 836 name)
821 (while (re-search-forward 837 (while (re-search-forward
822 (rx (and line-start (0+ space) ; leading space 838 (rx (and line-start (0+ space) ; leading space
823 (or (group "def") (group "class")) ; type 839 (or (group "def") (group "class")) ; type
@@ -830,7 +846,7 @@ first with `imenu--sort-by-name'."
830 (setq name (concat "class " name))) 846 (setq name (concat "class " name)))
831 (save-restriction 847 (save-restriction
832 (narrow-to-defun) 848 (narrow-to-defun)
833 (let* ((recursing t) 849 (let* ((python-recursing t)
834 (sublist (python-imenu-create-index))) 850 (sublist (python-imenu-create-index)))
835 (if sublist 851 (if sublist
836 (progn (push (cons (concat " " name) pos) sublist) 852 (progn (push (cons (concat " " name) pos) sublist)
@@ -884,8 +900,6 @@ If not at the end of line's indentation, or on a comment line, just call
884(defvar python-saved-check-command nil 900(defvar python-saved-check-command nil
885 "Internal use.") 901 "Internal use.")
886 902
887(autoload 'compilation-start "compile")
888
889;; After `sgml-validate-command'. 903;; After `sgml-validate-command'.
890(defun python-check (command) 904(defun python-check (command)
891 "Check a Python file (default current buffer's file). 905 "Check a Python file (default current buffer's file).
@@ -950,6 +964,13 @@ to be the new process's buffer. If you only run one process, this will
950do the right thing. If you run multiple processes, you can change 964do the right thing. If you run multiple processes, you can change
951`python-buffer' to another process buffer with \\[set-variable].") 965`python-buffer' to another process buffer with \\[set-variable].")
952 966
967(defconst python-compilation-regexp-alist
968 `((,(rx (and line-start (1+ (any " \t")) "File \""
969 (group (1+ (not (any "\"<")))) ; avoid `<stdin>' &c
970 "\", line " (group (1+ digit))))
971 1 python-compilation-line-number))
972 "`compilation-error-regexp-alist' for inferior Python.")
973
953(define-derived-mode inferior-python-mode comint-mode "Inferior Python" 974(define-derived-mode inferior-python-mode comint-mode "Inferior Python"
954 "Major mode for interacting with an inferior Python process. 975 "Major mode for interacting with an inferior Python process.
955A Python process can be started with \\[run-python]. 976A Python process can be started with \\[run-python].
@@ -973,7 +994,14 @@ For running multiple processes in multiple buffers, see `python-buffer'.
973 ;; Fixme: Maybe install some python-mode bindings too. 994 ;; Fixme: Maybe install some python-mode bindings too.
974 (define-key inferior-python-mode-map "\C-c\C-l" 'python-load-file) 995 (define-key inferior-python-mode-map "\C-c\C-l" 'python-load-file)
975 (define-key inferior-python-mode-map "\C-c\C-z" 'python-switch-to-python) 996 (define-key inferior-python-mode-map "\C-c\C-z" 'python-switch-to-python)
976 (setq comint-input-filter #'python-input-filter)) 997 (add-hook 'comint-input-filter-functions 'python-input-filter nil t)
998 (add-hook 'comint-preoutput-filter-functions #'python-preoutput-filter
999 nil t)
1000 ;; Still required by `comint-redirect-send-command', for instance:
1001 (set (make-local-variable 'comint-prompt-regexp) "^\\([>.]\\{3\\} \\)+")
1002 (set (make-local-variable 'compilation-error-regexp-alist)
1003 python-compilation-regexp-alist)
1004 (compilation-shell-minor-mode 1))
977 1005
978(defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'" 1006(defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'"
979 "*Input matching this regexp is not saved on the history list. 1007 "*Input matching this regexp is not saved on the history list.
@@ -981,18 +1009,15 @@ Default ignores all inputs of 0, 1, or 2 non-blank characters."
981 :type 'regexp 1009 :type 'regexp
982 :group 'python) 1010 :group 'python)
983 1011
984(defvar python-orig-start-line nil 1012(defvar python-orig-start nil
985 "Line number at start of region sent to inferior Python.") 1013 "Marker to the start of the region passed to the inferior Python.
986 1014It can also be a filename.")
987(defvar python-orig-file nil
988 "File name to associate with errors found in inferior Python.")
989 1015
990(defun python-input-filter (str) 1016(defun python-input-filter (str)
991 "`comint-input-filter' function for inferior Python. 1017 "`comint-input-filter' function for inferior Python.
992Don't save anything matching `inferior-python-filter-regexp'. 1018Don't save anything for STR matching `inferior-python-filter-regexp'.
993Also resets variables for adjusting error messages." 1019Also resets variables for adjusting error messages."
994 (setq python-orig-file nil 1020 (setq python-orig-start nil)
995 python-orig-start-line 1)
996 (not (string-match inferior-python-filter-regexp str))) 1021 (not (string-match inferior-python-filter-regexp str)))
997 1022
998;; Fixme: Loses with quoted whitespace. 1023;; Fixme: Loses with quoted whitespace.
@@ -1005,108 +1030,103 @@ Also resets variables for adjusting error messages."
1005 (t (let ((pos (string-match "[^ \t]" string))) 1030 (t (let ((pos (string-match "[^ \t]" string)))
1006 (if pos (python-args-to-list (substring string pos)))))))) 1031 (if pos (python-args-to-list (substring string pos))))))))
1007 1032
1008(defvar compilation-minor-mode-map)
1009(defvar compilation-error-list)
1010(defvar compilation-parsing-end)
1011
1012(defconst python-compilation-regexp-alist
1013 `((,(rx (and line-start (1+ (any " \t")) "File \""
1014 (group (1+ (not (any "\"<")))) ; avoid `<stdin>' &c
1015 "\", line " (group (1+ digit))))
1016 1 python-compilation-line-number))
1017 "`compilation-error-regexp-alist' for inferior Python.")
1018
1019(defun python-compilation-line-number (file col) 1033(defun python-compilation-line-number (file col)
1020 "Return error descriptor of error found for FILE, column COL. 1034 "Return error descriptor of error found for FILE, column COL.
1021Used as line-number hook function in `python-compilation-regexp-alist'." 1035Used as line-number hook function in `python-compilation-regexp-alist'."
1022 (let ((line (save-excursion 1036 (let ((line (string-to-number (match-string 2))))
1023 (goto-char (match-beginning 2)) 1037 (cons (point-marker)
1024 (read (current-buffer))))) 1038 (if (and (markerp python-orig-start)
1025 (list (point-marker) (if python-orig-file 1039 (marker-buffer python-orig-start))
1026 (list python-orig-file default-directory) 1040 (with-current-buffer (marker-buffer python-orig-start)
1027 file) 1041 (goto-char python-orig-start)
1028 (+ line (1- python-orig-start-line)) 1042 (forward-line (1- line)))
1029 nil))) 1043 (list (if (stringp python-orig-start) python-orig-start file)
1044 line nil)))))
1045
1046(defvar python-preoutput-result nil
1047 "Data from output line last `_emacs_out' line seen by the preoutput filter.")
1048
1049(defvar python-preoutput-continuation nil
1050 "If non-nil, funcall this when `python-preoutput-filter' sees `_emacs_ok'.")
1051
1052;; Using this stops us getting lines in the buffer like
1053;; >>> ... ... >>>
1054;; Also look for (and delete) an `_emacs_ok' string and call
1055;; `python-preoutput-continuation' if we get it.
1056(defun python-preoutput-filter (s)
1057 "`comint-preoutput-filter-functions' function: ignore prompts not at bol."
1058 (cond ((and (string-match "\\`[.>]\\{3\\} \\'" s)
1059 (/= (let ((inhibit-field-text-motion t))
1060 (line-beginning-position))
1061 (point)))
1062 "")
1063 ((string= s "_emacs_ok\n")
1064 (when python-preoutput-continuation
1065 (funcall python-preoutput-continuation)
1066 (setq python-preoutput-continuation nil))
1067 "")
1068 ((string-match "_emacs_out \\(.*\\)\n" s)
1069 (setq python-preoutput-result (match-string 1 s))
1070 "")
1071 (t s)))
1030 1072
1031;;;###autoload 1073;;;###autoload
1032(defun run-python (cmd) 1074(defun run-python (&optional cmd noshow)
1033 "Run an inferior Python process, input and output via buffer *Python*. 1075 "Run an inferior Python process, input and output via buffer *Python*.
1034CMD is the Python command to run. 1076CMD is the Python command to run. NOSHOW non-nil means don't show the
1077buffer automatically.
1035If there is a process already running in `*Python*', switch to 1078If there is a process already running in `*Python*', switch to
1036that buffer. With argument, allows you to edit the initial 1079that buffer. Interactively a prefix arg, allows you to edit the initial
1037command line (default is the value of `python-command'); `-i' and 1080command line (default is the value of `python-command'); `-i' etc. args
1038`-c' args will be added to this to support evaluations in the 1081will be added to this as appropriate. Runs the hooks
1039REPL. Runs the hooks `inferior-python-mode-hook' \(after the 1082`inferior-python-mode-hook' (after the `comint-mode-hook' is run).
1040`comint-mode-hook' is run). \(Type \\[describe-mode] in the 1083\(Type \\[describe-mode] in the process buffer for a list of commands.)"
1041process buffer for a list of commands.)"
1042 (interactive (list (if current-prefix-arg 1084 (interactive (list (if current-prefix-arg
1043 (read-string "Run Python: " python-command) 1085 (read-string "Run Python: " python-command)
1044 python-command))) 1086 python-command)))
1087 (unless cmd (setq cmd python-python-command))
1088 (setq python-command cmd)
1045 ;; Fixme: Consider making `python-buffer' buffer-local as a buffer 1089 ;; Fixme: Consider making `python-buffer' buffer-local as a buffer
1046 ;; (not a name) in Python buffers from which `run-python' &c is 1090 ;; (not a name) in Python buffers from which `run-python' &c is
1047 ;; invoked. Would support multiple processes better. 1091 ;; invoked. Would support multiple processes better.
1048 (if (not (comint-check-proc "*Python*")) 1092 (unless (comint-check-proc "*Python*")
1049 (let ((cmdlist (append (python-args-to-list cmd) 1093 (let ((cmdlist (append (python-args-to-list cmd) '("-i"))))
1050 '("-i" "-c" "\ 1094 (set-buffer (apply 'make-comint "Python" (car cmdlist) nil
1051from os import remove as _emacs_rem 1095 (cdr cmdlist))))
1052def _emacs_execfile (file): 1096 (inferior-python-mode)
1053 try: 1097 ;; Load function defintions we need.
1054 execfile (file) 1098 ;; Before the preoutput function was used, this was done via -c in
1055 finally: 1099 ;; cmdlist, but that loses the banner and doesn't run the startup
1056 _emacs_rem (file) 1100 ;; file.
1057")))) 1101 (python-send-string "\
1058 (set-buffer (apply 'make-comint "Python" (car cmdlist) nil 1102def _emacs_execfile (file): # execute file and remove it
1059 (cdr cmdlist))) 1103 from os import remove
1060 (inferior-python-mode) 1104 try: execfile (file, globals (), globals ())
1061 (setq comint-output-filter-functions nil))) 1105 finally: remove (file)
1062 (setq python-command cmd) 1106
1063 (setq python-buffer "*Python*") 1107def _emacs_args (name): # get arglist of name for eldoc &c
1064 (pop-to-buffer "*Python*") 1108 import inspect
1065 (compilation-minor-mode 1) 1109 parts = name.split ('.')
1066 (add-hook 'comint-input-filter-functions 'python-input-filter nil t) 1110 if len (parts) > 1:
1067 ;; Avoid clobbering comint bindings. 1111 try: exec 'import ' + parts[0]
1068 (set (make-local-variable 'minor-mode-overriding-map-alist) 1112 except: return None
1069 `((compilation-minor-mode 1113 try: exec 'func='+name # lose if name is keyword or undefined
1070 . ,(let ((map (make-sparse-keymap))) 1114 except: return None
1071 ;; It would be useful to put keymap properties on the 1115 if inspect.isbuiltin (func):
1072 ;; error lines so that we could use RET and mouse-2 on 1116 doc = func.__doc__
1073 ;; them directly. These bindings will only DTRT with 1117 if doc.find (' ->') != -1:
1074 ;; the font-lock-style compilation mode. 1118 print '_emacs_out', doc.split (' ->')[0]
1075 (define-key map [mouse-2] #'python-mouse-2-command) 1119 elif doc.find ('\\n') != -1:
1076 (define-key map "\C-m" #'python-RET-command) 1120 print '_emacs_out', doc.split ('\\n')[0]
1077 (if (boundp 'compilation-menu-map) 1121 return None
1078 (define-key map [menu-bar compilation] 1122 if inspect.ismethod (func): func = func.im_func
1079 (cons "Errors" compilation-menu-map))) 1123 if not inspect.isfunction (func):
1080 map)))) 1124 return None
1081 (set (make-local-variable 'compilation-error-regexp-alist) 1125 (args, varargs, varkw, defaults) = inspect.getargspec (func)
1082 python-compilation-regexp-alist)) 1126 print '_emacs_out', func.__name__+inspect.formatargspec (args, varargs, varkw, defaults)
1083 1127
1084(defun python-mouse-2-command (event) 1128print '_emacs_ok'"))
1085 "Command bound to `mouse-2' in inferior Python buffer. 1129 (unless noshow (pop-to-buffer (setq python-buffer "*Python*"))))
1086Selects Comint or Compilation mode command as appropriate."
1087 (interactive "e")
1088 ;; This only works with the font-lock-based compilation mode.
1089 (call-interactively
1090 (lookup-key (if (save-window-excursion
1091 (save-excursion
1092 (mouse-set-point event)
1093 (consp (get-text-property (line-beginning-position)
1094 'message))))
1095 compilation-mode-map
1096 comint-mode-map)
1097 [mouse-2])))
1098
1099(defun python-RET-command ()
1100 "Command bound to `RET' in inferior Python buffer.
1101Selects Comint or Compilation mode command as appropriate."
1102 (interactive)
1103 ;; This only works with the font-lock-based compilation mode.
1104 (call-interactively
1105 (lookup-key (if (consp (get-text-property (line-beginning-position)
1106 'message))
1107 compilation-mode-map
1108 comint-mode-map)
1109 "\C-m")))
1110 1130
1111(defun python-send-region (start end) 1131(defun python-send-region (start end)
1112 "Send the region to the inferior Python process." 1132 "Send the region to the inferior Python process."
@@ -1128,11 +1148,8 @@ Selects Comint or Compilation mode command as appropriate."
1128 ;; comint-filter the first two lines of the traceback? 1148 ;; comint-filter the first two lines of the traceback?
1129 (interactive "r") 1149 (interactive "r")
1130 (let* ((f (make-temp-file "py")) 1150 (let* ((f (make-temp-file "py"))
1131 (command (format "_emacs_execfile(%S)\n" f)) 1151 (command (format "_emacs_execfile(%S)" f))
1132 (orig-file (buffer-file-name)) 1152 (orig-start (copy-marker start)))
1133 (orig-line (save-restriction
1134 (widen)
1135 (line-number-at-pos start))))
1136 (if (save-excursion 1153 (if (save-excursion
1137 (goto-char start) 1154 (goto-char start)
1138 (/= 0 (current-indentation))) ; need dummy block 1155 (/= 0 (current-indentation))) ; need dummy block
@@ -1140,22 +1157,20 @@ Selects Comint or Compilation mode command as appropriate."
1140 (write-region start end f t 'nomsg) 1157 (write-region start end f t 'nomsg)
1141 (when python-buffer 1158 (when python-buffer
1142 (with-current-buffer python-buffer 1159 (with-current-buffer python-buffer
1143 (let ((end (marker-position (process-mark 1160 (let ((end (marker-position (process-mark (python-proc)))))
1144 (get-buffer-process python-buffer))))) 1161 (set (make-local-variable 'python-orig-start) orig-start)
1145 (set (make-local-variable 'python-orig-file) orig-file)
1146 (set (make-local-variable 'python-orig-start-line) orig-line)
1147 (set (make-local-variable 'compilation-error-list) nil) 1162 (set (make-local-variable 'compilation-error-list) nil)
1148 ;; (set (make-local-variable 'compilation-old-error-list) nil)
1149 (let ((comint-input-filter-functions 1163 (let ((comint-input-filter-functions
1150 (delete 'python-input-filter comint-input-filter-functions))) 1164 (delete 'python-input-filter comint-input-filter-functions)))
1151 (comint-send-string (python-proc) command)) 1165 (python-send-string command))
1152 (set-marker compilation-parsing-end end) 1166 (set-marker compilation-parsing-end end)
1153 (setq compilation-last-buffer (current-buffer))))))) 1167 (setq compilation-last-buffer (current-buffer)))))))
1154 1168
1155(defun python-send-string (string) 1169(defun python-send-string (string)
1156 "Evaluate STRING in inferior Python process." 1170 "Evaluate STRING in inferior Python process."
1157 (interactive "sPython command: ") 1171 (interactive "sPython command: ")
1158 (comint-send-string (python-proc) string)) 1172 (comint-send-string (python-proc) string)
1173 (comint-send-string (python-proc) "\n\n"))
1159 1174
1160(defun python-send-buffer () 1175(defun python-send-buffer ()
1161 "Send the current buffer to the inferior Python process." 1176 "Send the current buffer to the inferior Python process."
@@ -1212,19 +1227,27 @@ module-qualified names."
1212 (comint-check-source file-name) ; Check to see if buffer needs saved. 1227 (comint-check-source file-name) ; Check to see if buffer needs saved.
1213 (setq python-prev-dir/file (cons (file-name-directory file-name) 1228 (setq python-prev-dir/file (cons (file-name-directory file-name)
1214 (file-name-nondirectory file-name))) 1229 (file-name-nondirectory file-name)))
1215 (comint-send-string 1230 (when python-buffer
1216 (python-proc) 1231 (with-current-buffer python-buffer
1217 (if (string-match "\\.py\\'" file-name) 1232 (let ((end (marker-position (process-mark (python-proc)))))
1218 ;; Fixme: make sure the directory is in the path list 1233 (set (make-local-variable 'compilation-error-list) nil)
1219 (let ((module (file-name-sans-extension 1234 ;; (set (make-local-variable 'compilation-old-error-list) nil)
1220 (file-name-nondirectory file-name)))) 1235 (let ((comint-input-filter-functions
1221 (format "\ 1236 (delete 'python-input-filter comint-input-filter-functions)))
1222if globals().has_key('%s'): 1237 (python-send-string
1223 reload(%s) 1238 (if (string-match "\\.py\\'" file-name)
1224else: 1239 ;; Fixme: make sure the directory is in the path list
1225 import %s 1240 (let ((module (file-name-sans-extension
1241 (file-name-nondirectory file-name))))
1242 (set (make-local-variable 'python-orig-start) nil)
1243 (format "\
1244if globals().has_key(%S): reload(%s)
1245else: import %s
1226" module module module)) 1246" module module module))
1227 (format "execfile('%s')\n" filename)))) 1247 (set (make-local-variable 'python-orig-start) file-name)
1248 (format "execfile('%s')" file-name))))
1249 (set-marker compilation-parsing-end end)
1250 (setq compilation-last-buffer (current-buffer))))))
1228 1251
1229;; Fixme: Should this start a process if there isn't one? (Unlike cmuscheme.) 1252;; Fixme: Should this start a process if there isn't one? (Unlike cmuscheme.)
1230(defun python-proc () 1253(defun python-proc ()
@@ -1236,74 +1259,115 @@ else:
1236 1259
1237;;;; Context-sensitive help. 1260;;;; Context-sensitive help.
1238 1261
1239;; Fixme: Investigate adapting this to eldoc. 1262(defconst python-dotty-syntax-table
1263 (let ((table (make-syntax-table)))
1264 (set-char-table-parent table python-mode-syntax-table)
1265 (modify-syntax-entry ?. "_" table)
1266 table)
1267 "Syntax table giving `.' symbol syntax.
1268Otherwise inherits from `python-mode-syntax-table'.")
1240 1269
1270;; Fixme: Should this actually be used instead of info-look, i.e. be
1271;; bound to C-h S?
1241(defun python-describe-symbol (symbol) 1272(defun python-describe-symbol (symbol)
1242 "Get help on SYMBOL using `pydoc'. 1273 "Get help on SYMBOL using `pydoc'.
1243Interactively, prompt for symbol." 1274Interactively, prompt for symbol."
1275 ;; Note that we do this in the inferior process, not a separate one to
1276 ;; ensure the environment is appropriate.
1244 (interactive 1277 (interactive
1245 (let ((symbol (current-word)) 1278 (let ((symbol (with-syntax-table python-dotty-syntax-table
1279 (current-word)))
1246 (enable-recursive-minibuffers t) 1280 (enable-recursive-minibuffers t)
1247 val) 1281 val)
1248 (setq val (read-string (if symbol 1282 (setq val (read-string (if symbol
1249 (format "Describe variable (default %s): " 1283 (format "Describe symbol (default %s): "
1250 symbol) 1284 symbol)
1251 "Describe variable: ") 1285 "Describe symbol: ")
1252 nil nil symbol)) 1286 nil nil symbol))
1253 (list (or val symbol)))) 1287 (list (or val symbol))))
1254 (if (equal symbol "") (error "No symbol")) 1288 (if (equal symbol "") (error "No symbol"))
1255 (let* ((mod (if (string-match "\\(\\.[^.]+\\)\\'" symbol) 1289 (let* ((func `(lambda ()
1256 (substring symbol 0 (match-beginning 1)))) 1290 (comint-redirect-send-command (format "help(%S)\n" ,symbol)
1257 (import (when mod (concat "import " mod "\n")))) 1291 "*Help*" nil))))
1258 (with-output-to-temp-buffer "*Python Output*" 1292 ;; Ensure we have a suitable help buffer.
1259 (princ (shell-command-to-string 1293 (let (temp-buffer-show-hook) ; avoid xref stuff
1260 (format "%s -c 'import pydoc %s 1294 (with-output-to-temp-buffer "*Help*"
1261try: pydoc.help(%S) 1295 (with-current-buffer standard-output
1262except: print \"No help available on:\", %S'" 1296 (set (make-local-variable 'comint-redirect-subvert-readonly) t))))
1263 ;; Fixme: Is this necessarily right? 1297 (if (and python-buffer (get-buffer python-buffer))
1264 (car (split-string python-command)) 1298 (with-current-buffer python-buffer
1265 (or import "") symbol symbol)))))) 1299 (funcall func))
1300 (setq python-preoutput-continuation func)
1301 (run-python nil t))))
1266 1302
1267(add-to-list 'debug-ignored-errors "^No symbol") 1303(add-to-list 'debug-ignored-errors "^No symbol")
1304
1305;; Fixme: try to make it work with point in the arglist. Also, is
1306;; there anything reasonable we can do with random methods?
1307;; (Currently only works with functions.)
1308(defun python-eldoc-function ()
1309 "`eldoc-print-current-symbol-info' for Python.
1310Only works when point is in a function name, not its arglist, for instance.
1311Assumes an inferior Python is running."
1312 (let ((symbol (with-syntax-table python-dotty-syntax-table
1313 (current-word)))
1314 (proc (and python-buffer (python-proc))))
1315 (when (and proc symbol)
1316 (python-send-string
1317 (format "_emacs_args(%S)" symbol))
1318 (setq python-preoutput-result nil)
1319 (accept-process-output proc 1)
1320 python-preoutput-result)))
1268 1321
1269;;;; Info-look functionality. 1322;;;; Info-look functionality.
1270 1323
1271(require 'info-look) 1324(defun python-after-info-look ()
1272;; We should be able to add info-lookup specs without loading the file first. 1325 "Set up info-look for Python.
1273;; E.g. by setting a buffer-local var or something like that. --Stef 1326Used with `eval-after-load'."
1274(let ((version (let ((s (shell-command-to-string (concat python-command 1327 (let* ((version (let ((s (shell-command-to-string (concat python-command
1275 " -V")))) 1328 " -V"))))
1276 (string-match "^Python \\([0-9]+\\.[0-9]+\\>\\)" s) 1329 (string-match "^Python \\([0-9]+\\.[0-9]+\\>\\)" s)
1277 (match-string 1 s))) 1330 (match-string 1 s)))
1278 ;; Whether info files have a Python version suffix, e.g. in Debian. 1331 ;; Whether info files have a Python version suffix, e.g. in Debian.
1279 (versioned (save-window-excursion 1332 (versioned
1280 (condition-case () 1333 (with-temp-buffer
1281 ;; The call to `info' might create a new frame if 1334 (Info-mode)
1282 ;; pop-up-frames or special-display-buffers are used. 1335 (condition-case ()
1283 ;; So I disabled it until we find a better way 1336 ;; Don't use `info' because it would pop-up a *info* buffer.
1284 ;; to handle this situation. Maybe Debian should just 1337 (Info-goto-node (format "(python%s-lib)Miscellaneous Index"
1285 ;; fix their install somehow. --Stef 1338 version))
1286 ;; (progn (info "(python2.3-lib)Miscellaneous Index") 1339 (error nil)))))
1287 ;; (Info-last) 1340 (info-lookup-maybe-add-help
1288 ;; (Info-exit) 1341 :mode 'python-mode
1289 ;; t) 1342 :regexp "[[:alnum:]_]+"
1290 nil 1343 :doc-spec
1291 (error nil))))) 1344 ;; Fixme: Can this reasonably be made specific to indices with
1292 (info-lookup-maybe-add-help 1345 ;; different rules? Is the order of indices optimal?
1293 :mode 'python-mode 1346 ;; (Miscellaneous in -ref first prefers lookup of keywords, for
1294 :regexp "[[:alnum:]_]+" 1347 ;; instance.)
1295 :doc-spec 1348 (if versioned
1296 ;; Fixme: Add python-ref? Can this reasonably be made specific 1349 ;; The empty prefix just gets us highlighted terms.
1297 ;; to indices with different rules? 1350 `((,(concat "(python" version "-ref)Miscellaneous Index") nil "")
1298 (if versioned 1351 (,(concat "(python" version "-ref)Module Index" nil ""))
1299 '((,(concat "(python" version "-lib)Module Index")) 1352 (,(concat "(python" version "-ref)Function-Method-Variable Index"
1300 (,(concat "(python" version "-lib)Class-Exception-Object Index")) 1353 nil ""))
1301 (,(concat "(python" version "-lib)Function-Method-Variable Index")) 1354 (,(concat "(python" version "-ref)Class-Exception-Object Index"
1302 (,(concat "(python" version "-lib)Miscellaneous Index"))) 1355 nil ""))
1303 '(("(python-lib)Module Index") 1356 (,(concat "(python" version "-lib)Module Index" nil ""))
1304 ("(python-lib)Class-Exception-Object Index") 1357 (,(concat "(python" version "-lib)Class-Exception-Object Index"
1305 ("(python-lib)Function-Method-Variable Index") 1358 nil ""))
1306 ("(python-lib)Miscellaneous Index"))))) 1359 (,(concat "(python" version "-lib)Function-Method-Variable Index"
1360 nil ""))
1361 (,(concat "(python" version "-lib)Miscellaneous Index" nil "")))
1362 '(("(python-ref)Miscellaneous Index" nil "")
1363 ("(python-ref)Module Index" nil "")
1364 ("(python-ref)Function-Method-Variable Index" nil "")
1365 ("(python-ref)Class-Exception-Object Index" nil "")
1366 ("(python-lib)Module Index" nil "")
1367 ("(python-lib)Class-Exception-Object Index" nil "")
1368 ("(python-lib)Function-Method-Variable Index" nil "")
1369 ("(python-lib)Miscellaneous Index" nil ""))))))
1370(eval-after-load "info-look" '(python-after-info-look))
1307 1371
1308;;;; Miscellancy. 1372;;;; Miscellancy.
1309 1373
@@ -1323,34 +1387,65 @@ The criterion is either a match for `jython-mode' via
1323`python-jython-packages'." 1387`python-jython-packages'."
1324 ;; The logic is taken from python-mode.el. 1388 ;; The logic is taken from python-mode.el.
1325 (save-excursion 1389 (save-excursion
1326 (goto-char (point-min)) 1390 (save-restriction
1327 (let ((interpreter (if (looking-at auto-mode-interpreter-regexp) 1391 (widen)
1328 (match-string 2)))) 1392 (goto-char (point-min))
1329 (if (and interpreter (eq 'jython-mode 1393 (let ((interpreter (if (looking-at auto-mode-interpreter-regexp)
1330 (cdr (assoc (file-name-nondirectory interpreter) 1394 (match-string 2))))
1331 interpreter-mode-alist)))) 1395 (if (and interpreter (eq 'jython-mode
1332 (jython-mode) 1396 (cdr (assoc (file-name-nondirectory
1333 (if (catch 'done 1397 interpreter)
1334 (while (re-search-forward 1398 interpreter-mode-alist))))
1335 (rx (and line-start (or "import" "from") (1+ space) 1399 (jython-mode)
1336 (group (1+ (not (any " \t\n.")))))) 1400 (if (catch 'done
1337 (+ (point) 10000) ; Probably not worth customizing. 1401 (while (re-search-forward
1338 t) 1402 (rx (and line-start (or "import" "from") (1+ space)
1339 (if (member (match-string 1) python-jython-packages) 1403 (group (1+ (not (any " \t\n."))))))
1340 (throw 'done t)))) 1404 10000 ; Probably not worth customizing.
1341 (jython-mode)))))) 1405 t)
1406 (if (member (match-string 1) python-jython-packages)
1407 (throw 'done t))))
1408 (jython-mode)))))))
1342 1409
1343(defun python-fill-paragraph (&optional justify) 1410(defun python-fill-paragraph (&optional justify)
1344 "Like \\[fill-paragraph], but handle comments and multi-line strings. 1411 "`fill-paragraph-function' handling comments and multi-line strings.
1345If any of the current line is a comment, fill the comment or the 1412If any of the current line is a comment, fill the comment or the
1346paragraph of it that point is in, preserving the comment's indentation 1413paragraph of it that point is in, preserving the comment's
1347and initial comment characters." 1414indentation and initial comment characters. Similarly if the end
1415of the current line is in or at the end of a multi-line string.
1416Otherwise, do nothing."
1348 (interactive "P") 1417 (interactive "P")
1349 (or (fill-comment-paragraph justify) 1418 (or (fill-comment-paragraph justify)
1350 (let ((paragraph-start (concat paragraph-start 1419 ;; The `paragraph-start' and `paragraph-separate' variables
1351 "\\|\\s-*\\(:?#\\s\"\\|\\s|\\|#"))) 1420 ;; don't allow us to delimit the last paragraph in a multi-line
1352 (fill-paragraph justify)) 1421 ;; string properly, so narrow to the string and then fill around
1353 t)) 1422 ;; (the end of) the current line.
1423 (save-excursion
1424 (end-of-line)
1425 (let* ((syntax (syntax-ppss))
1426 (orig (point))
1427 (start (nth 8 syntax))
1428 end)
1429 (cond ((eq t (nth 3 syntax)) ; in fenced string
1430 (goto-char (nth 8 syntax)) ; string start
1431 (condition-case () ; for unbalanced quotes
1432 (progn (forward-sexp)
1433 (setq end (point)))
1434 (error (setq end (point-max)))))
1435 ((re-search-backward "\\s|\\s-*\\=" nil t) ; end of fenced
1436 ; string
1437 (forward-char)
1438 (setq end (point))
1439 (condition-case ()
1440 (progn (backward-sexp)
1441 (setq start (point)))
1442 (error nil))))
1443 (when end
1444 (save-restriction
1445 (narrow-to-region start end)
1446 (goto-char orig)
1447 (fill-paragraph justify))))))
1448 t)
1354 1449
1355(defun python-shift-left (start end &optional count) 1450(defun python-shift-left (start end &optional count)
1356 "Shift lines in region COUNT (the prefix arg) columns to the left. 1451 "Shift lines in region COUNT (the prefix arg) columns to the left.
@@ -1391,7 +1486,8 @@ END lie."
1391 1486
1392(defun python-outline-level () 1487(defun python-outline-level ()
1393 "`outline-level' function for Python mode. 1488 "`outline-level' function for Python mode.
1394The level is the number of `python-indent' steps of indentation." 1489The level is the number of `python-indent' steps of indentation
1490of current line."
1395 (/ (current-indentation) python-indent)) 1491 (/ (current-indentation) python-indent))
1396 1492
1397;; Fixme: Consider top-level assignments, imports, &c. 1493;; Fixme: Consider top-level assignments, imports, &c.
@@ -1425,17 +1521,23 @@ Uses `python-beginning-of-block', `python-end-of-block'."
1425 1521
1426;;;; Modes. 1522;;;; Modes.
1427 1523
1524(defvar outline-heading-end-regexp)
1525(defvar eldoc-print-current-symbol-info-function)
1526(defvar python-mode-running)
1428;;;###autoload 1527;;;###autoload
1429(define-derived-mode python-mode fundamental-mode "Python" 1528(define-derived-mode python-mode fundamental-mode "Python"
1430 "Major mode for editing Python files. 1529 "Major mode for editing Python files.
1431Turns on Font Lock mode unconditionally since it is required for correct 1530Turns on Font Lock mode unconditionally since it is required for correct
1432parsing of the source. 1531parsing of the source.
1433See also `jython-mode', which is actually invoked if the buffer appears to 1532See also `jython-mode', which is actually invoked if the buffer appears to
1434contain Jython code. 1533contain Jython code. See also `run-python' and associated Python mode
1534commands for running Python under Emacs.
1435 1535
1436The Emacs commands which work with `defun's, e.g. \\[beginning-of-defun], deal 1536The Emacs commands which work with `defun's, e.g. \\[beginning-of-defun], deal
1437with nested `def' and `class' blocks. They take the innermost one as 1537with nested `def' and `class' blocks. They take the innermost one as
1438current without distinguishing method and class definitions. 1538current without distinguishing method and class definitions. Used multiple
1539times, they move over others at the same indentation level until they reach
1540the end of definitions at that level, when they move up a level.
1439\\<python-mode-map> 1541\\<python-mode-map>
1440Colon is electric: it outdents the line if appropriate, e.g. for 1542Colon is electric: it outdents the line if appropriate, e.g. for
1441an else statement. \\[python-backspace] at the beginning of an indented statement 1543an else statement. \\[python-backspace] at the beginning of an indented statement
@@ -1444,6 +1546,13 @@ deletes a charcter backward. TAB indents the current line relative to
1444the preceding code. Successive TABs, with no intervening command, cycle 1546the preceding code. Successive TABs, with no intervening command, cycle
1445through the possibilities for indentation on the basis of enclosing blocks. 1547through the possibilities for indentation on the basis of enclosing blocks.
1446 1548
1549\\[fill-paragraph] fills comments and multiline strings appropriately, but has no
1550effect outside them.
1551
1552Supports Eldoc mode (only for functions, using a Python process),
1553Info-Look and Imenu. In Outline minor mode, `class' and `def'
1554lines count as headers.
1555
1447\\{python-mode-map}" 1556\\{python-mode-map}"
1448 :group 'python 1557 :group 'python
1449 (set (make-local-variable 'font-lock-defaults) 1558 (set (make-local-variable 'font-lock-defaults)
@@ -1465,7 +1574,8 @@ through the possibilities for indentation on the basis of enclosing blocks.
1465 (set (make-local-variable 'add-log-current-defun-function) 1574 (set (make-local-variable 'add-log-current-defun-function)
1466 #'python-current-defun) 1575 #'python-current-defun)
1467 ;; Fixme: Generalize to do all blocks? 1576 ;; Fixme: Generalize to do all blocks?
1468 (set (make-local-variable 'outline-regexp) "\\s-+\\(def\\|class\\)\\>") 1577 (set (make-local-variable 'outline-regexp) "\\s-*\\(def\\|class\\)\\>")
1578 (set (make-local-variable 'outline-heading-end-regexp) ":\\s-*\n")
1469 (set (make-local-variable 'outline-level) #'python-outline-level) 1579 (set (make-local-variable 'outline-level) #'python-outline-level)
1470 (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil) 1580 (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil)
1471 (make-local-variable 'python-saved-check-command) 1581 (make-local-variable 'python-saved-check-command)
@@ -1473,6 +1583,10 @@ through the possibilities for indentation on the basis of enclosing blocks.
1473 'python-beginning-of-defun) 1583 'python-beginning-of-defun)
1474 (set (make-local-variable 'end-of-defun-function) 'python-end-of-defun) 1584 (set (make-local-variable 'end-of-defun-function) 'python-end-of-defun)
1475 (setq imenu-create-index-function #'python-imenu-create-index) 1585 (setq imenu-create-index-function #'python-imenu-create-index)
1586 (set (make-local-variable 'eldoc-print-current-symbol-info-function)
1587 #'python-eldoc-function)
1588 (add-hook 'eldoc-mode-hook
1589 '(lambda () (run-python 0 t)) nil t) ; need it running
1476 (unless font-lock-mode (font-lock-mode 1)) 1590 (unless font-lock-mode (font-lock-mode 1))
1477 (when python-guess-indent (python-guess-indent)) 1591 (when python-guess-indent (python-guess-indent))
1478 (set (make-local-variable 'python-command) python-python-command) 1592 (set (make-local-variable 'python-command) python-python-command)
@@ -1485,6 +1599,7 @@ through the possibilities for indentation on the basis of enclosing blocks.
1485 '(lambda () 1599 '(lambda ()
1486 "Turn on Indent Tabs mode." 1600 "Turn on Indent Tabs mode."
1487 (set (make-local-variable 'indent-tabs-mode) t))) 1601 (set (make-local-variable 'indent-tabs-mode) t)))
1602(custom-add-option 'python-mode-hook 'turn-on-eldoc-mode)
1488 1603
1489;;;###autoload 1604;;;###autoload
1490(define-derived-mode jython-mode python-mode "Jython" 1605(define-derived-mode jython-mode python-mode "Jython"