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.el558
1 files changed, 361 insertions, 197 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index ee752f78352..36dc832347c 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."
@@ -884,8 +899,6 @@ If not at the end of line's indentation, or on a comment line, just call
884(defvar python-saved-check-command nil 899(defvar python-saved-check-command nil
885 "Internal use.") 900 "Internal use.")
886 901
887(autoload 'compilation-start "compile")
888
889;; After `sgml-validate-command'. 902;; After `sgml-validate-command'.
890(defun python-check (command) 903(defun python-check (command)
891 "Check a Python file (default current buffer's file). 904 "Check a Python file (default current buffer's file).
@@ -950,6 +963,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 963do the right thing. If you run multiple processes, you can change
951`python-buffer' to another process buffer with \\[set-variable].") 964`python-buffer' to another process buffer with \\[set-variable].")
952 965
966(defconst python-compilation-regexp-alist
967 `((,(rx (and line-start (1+ (any " \t")) "File \""
968 (group (1+ (not (any "\"<")))) ; avoid `<stdin>' &c
969 "\", line " (group (1+ digit))))
970 1 python-compilation-line-number))
971 "`compilation-error-regexp-alist' for inferior Python.")
972
953(define-derived-mode inferior-python-mode comint-mode "Inferior Python" 973(define-derived-mode inferior-python-mode comint-mode "Inferior Python"
954 "Major mode for interacting with an inferior Python process. 974 "Major mode for interacting with an inferior Python process.
955A Python process can be started with \\[run-python]. 975A Python process can be started with \\[run-python].
@@ -973,7 +993,14 @@ For running multiple processes in multiple buffers, see `python-buffer'.
973 ;; Fixme: Maybe install some python-mode bindings too. 993 ;; Fixme: Maybe install some python-mode bindings too.
974 (define-key inferior-python-mode-map "\C-c\C-l" 'python-load-file) 994 (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) 995 (define-key inferior-python-mode-map "\C-c\C-z" 'python-switch-to-python)
976 (setq comint-input-filter #'python-input-filter)) 996 (add-hook 'comint-input-filter-functions 'python-input-filter nil t)
997 (add-hook 'comint-preoutput-filter-functions #'python-preoutput-filter
998 nil t)
999 ;; Still required by `comint-redirect-send-command', for instance:
1000 (set (make-local-variable 'comint-prompt-regexp) "^\\([>.]\\{3\\} \\)+")
1001 (set (make-local-variable 'compilation-error-regexp-alist)
1002 python-compilation-regexp-alist)
1003 (compilation-shell-minor-mode 1))
977 1004
978(defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'" 1005(defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'"
979 "*Input matching this regexp is not saved on the history list. 1006 "*Input matching this regexp is not saved on the history list.
@@ -989,7 +1016,7 @@ Default ignores all inputs of 0, 1, or 2 non-blank characters."
989 1016
990(defun python-input-filter (str) 1017(defun python-input-filter (str)
991 "`comint-input-filter' function for inferior Python. 1018 "`comint-input-filter' function for inferior Python.
992Don't save anything matching `inferior-python-filter-regexp'. 1019Don't save anything for STR matching `inferior-python-filter-regexp'.
993Also resets variables for adjusting error messages." 1020Also resets variables for adjusting error messages."
994 (setq python-orig-file nil 1021 (setq python-orig-file nil
995 python-orig-start-line 1) 1022 python-orig-start-line 1)
@@ -1005,17 +1032,6 @@ Also resets variables for adjusting error messages."
1005 (t (let ((pos (string-match "[^ \t]" string))) 1032 (t (let ((pos (string-match "[^ \t]" string)))
1006 (if pos (python-args-to-list (substring string pos)))))))) 1033 (if pos (python-args-to-list (substring string pos))))))))
1007 1034
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) 1035(defun python-compilation-line-number (file col)
1020 "Return error descriptor of error found for FILE, column COL. 1036 "Return error descriptor of error found for FILE, column COL.
1021Used as line-number hook function in `python-compilation-regexp-alist'." 1037Used as line-number hook function in `python-compilation-regexp-alist'."
@@ -1028,44 +1044,90 @@ Used as line-number hook function in `python-compilation-regexp-alist'."
1028 (+ line (1- python-orig-start-line)) 1044 (+ line (1- python-orig-start-line))
1029 nil))) 1045 nil)))
1030 1046
1047(defvar python-preoutput-result nil
1048 "Data from output line last `_emacs_out' line seen by the preoutput filter.")
1049
1050(defvar python-preoutput-continuation nil
1051 "If non-nil, funcall this when `python-preoutput-filter' sees `_emacs_ok'.")
1052
1053;; Using this stops us getting lines in the buffer like
1054;; >>> ... ... >>>
1055;; Also look for (and delete) an `_emacs_ok' string and call
1056;; `python-preoutput-continuation' if we get it.
1057(defun python-preoutput-filter (s)
1058 "`comint-preoutput-filter-functions' function: ignore prompts not at bol."
1059 (cond ((and (string-match "\\`[.>]\\{3\\} \\'" s)
1060 (/= (let ((inhibit-field-text-motion t))
1061 (line-beginning-position))
1062 (point)))
1063 "")
1064 ((string= s "_emacs_ok\n")
1065 (when python-preoutput-continuation
1066 (funcall python-preoutput-continuation)
1067 (setq python-preoutput-continuation nil))
1068 "")
1069 ((string-match "_emacs_out \\(.*\\)\n" s)
1070 (setq python-preoutput-result (match-string 1 s))
1071 "")
1072 (t s)))
1073
1031;;;###autoload 1074;;;###autoload
1032(defun run-python (cmd) 1075(defun run-python (&optional cmd noshow)
1033 "Run an inferior Python process, input and output via buffer *Python*. 1076 "Run an inferior Python process, input and output via buffer *Python*.
1034CMD is the Python command to run. 1077CMD is the Python command to run. NOSHOW non-nil means don't show the
1078buffer automatically.
1035If there is a process already running in `*Python*', switch to 1079If there is a process already running in `*Python*', switch to
1036that buffer. With argument, allows you to edit the initial 1080that buffer. Interactively a prefix arg, allows you to edit the initial
1037command line (default is the value of `python-command'); `-i' and 1081command line (default is the value of `python-command'); `-i' etc. args
1038`-c' args will be added to this to support evaluations in the 1082will be added to this as appropriate. Runs the hooks
1039REPL. Runs the hooks `inferior-python-mode-hook' \(after the 1083`inferior-python-mode-hook' (after the `comint-mode-hook' is run).
1040`comint-mode-hook' is run). \(Type \\[describe-mode] in the 1084\(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 1085 (interactive (list (if current-prefix-arg
1043 (read-string "Run Python: " python-command) 1086 (read-string "Run Python: " python-command)
1044 python-command))) 1087 python-command)))
1088 (unless cmd (setq cmd python-python-command))
1089 (setq python-command cmd)
1045 ;; Fixme: Consider making `python-buffer' buffer-local as a buffer 1090 ;; Fixme: Consider making `python-buffer' buffer-local as a buffer
1046 ;; (not a name) in Python buffers from which `run-python' &c is 1091 ;; (not a name) in Python buffers from which `run-python' &c is
1047 ;; invoked. Would support multiple processes better. 1092 ;; invoked. Would support multiple processes better.
1048 (if (not (comint-check-proc "*Python*")) 1093 (unless (comint-check-proc "*Python*")
1049 (let ((cmdlist (append (python-args-to-list cmd) 1094 (let ((cmdlist (append (python-args-to-list cmd) '("-i"))))
1050 '("-i" "-c" "\ 1095 (set-buffer (apply 'make-comint "Python" (car cmdlist) nil
1051from os import remove as _emacs_rem 1096 (cdr cmdlist))))
1052def _emacs_execfile (file): 1097 (inferior-python-mode)
1053 try: 1098 ;; Load function defintions we need.
1054 execfile (file) 1099 ;; Before the preoutput function was used, this was done via -c in
1055 finally: 1100 ;; cmdlist, but that loses the banner and doesn't run the startup
1056 _emacs_rem (file) 1101 ;; file.
1057")))) 1102 (python-send-string "\
1058 (set-buffer (apply 'make-comint "Python" (car cmdlist) nil 1103def _emacs_execfile (file): # execute file and remove it
1059 (cdr cmdlist))) 1104 from os import remove
1060 (inferior-python-mode) 1105 try: execfile (file, globals (), globals ())
1061 (setq comint-output-filter-functions nil))) 1106 finally: remove (file)
1062 (setq python-command cmd) 1107
1063 (setq python-buffer "*Python*") 1108def _emacs_args (name): # get arglist of name for eldoc &c
1064 (pop-to-buffer "*Python*") 1109 import inspect
1065 (set (make-local-variable 'compilation-error-regexp-alist) 1110 parts = name.split ('.')
1066 python-compilation-regexp-alist) 1111 if len (parts) > 1:
1067 (compilation-shell-minor-mode 1) 1112 try: exec 'import ' + parts[0]
1068 (add-hook 'comint-input-filter-functions 'python-input-filter nil t)) 1113 except: return None
1114 try: exec 'func='+name # lose if name is keyword or undefined
1115 except: return None
1116 if inspect.isbuiltin (func):
1117 doc = func.__doc__
1118 if doc.find (' ->') != -1:
1119 print '_emacs_out', doc.split (' ->')[0]
1120 elif doc.find ('\n') != -1:
1121 print '_emacs_out', doc.split ('\n')[0]
1122 return None
1123 if inspect.ismethod (func): func = func.im_func
1124 if not inspect.isfunction (func):
1125 return None
1126 (args, varargs, varkw, defaults) = inspect.getargspec (func)
1127 print '_emacs_out', func.__name__+inspect.formatargspec (args, varargs, varkw, defaults)
1128
1129print '_emacs_ok'"))
1130 (unless noshow (pop-to-buffer (setq python-buffer "*Python*"))))
1069 1131
1070(defun python-mouse-2-command (event) 1132(defun python-mouse-2-command (event)
1071 "Command bound to `mouse-2' in inferior Python buffer. 1133 "Command bound to `mouse-2' in inferior Python buffer.
@@ -1114,7 +1176,7 @@ Selects Comint or Compilation mode command as appropriate."
1114 ;; comint-filter the first two lines of the traceback? 1176 ;; comint-filter the first two lines of the traceback?
1115 (interactive "r") 1177 (interactive "r")
1116 (let* ((f (make-temp-file "py")) 1178 (let* ((f (make-temp-file "py"))
1117 (command (format "_emacs_execfile(%S)\n" f)) 1179 (command (format "_emacs_execfile(%S)" f))
1118 (orig-file (buffer-file-name)) 1180 (orig-file (buffer-file-name))
1119 (orig-line (save-restriction 1181 (orig-line (save-restriction
1120 (widen) 1182 (widen)
@@ -1126,22 +1188,21 @@ Selects Comint or Compilation mode command as appropriate."
1126 (write-region start end f t 'nomsg) 1188 (write-region start end f t 'nomsg)
1127 (when python-buffer 1189 (when python-buffer
1128 (with-current-buffer python-buffer 1190 (with-current-buffer python-buffer
1129 (let ((end (marker-position (process-mark 1191 (let ((end (marker-position (process-mark (python-proc)))))
1130 (get-buffer-process python-buffer)))))
1131 (set (make-local-variable 'python-orig-file) orig-file) 1192 (set (make-local-variable 'python-orig-file) orig-file)
1132 (set (make-local-variable 'python-orig-start-line) orig-line) 1193 (set (make-local-variable 'python-orig-start-line) orig-line)
1133 (set (make-local-variable 'compilation-error-list) nil) 1194 (set (make-local-variable 'compilation-error-list) nil)
1134 ;; (set (make-local-variable 'compilation-old-error-list) nil)
1135 (let ((comint-input-filter-functions 1195 (let ((comint-input-filter-functions
1136 (delete 'python-input-filter comint-input-filter-functions))) 1196 (delete 'python-input-filter comint-input-filter-functions)))
1137 (comint-send-string (python-proc) command)) 1197 (python-send-string command))
1138 (set-marker compilation-parsing-end end) 1198 (set-marker compilation-parsing-end end)
1139 (setq compilation-last-buffer (current-buffer))))))) 1199 (setq compilation-last-buffer (current-buffer)))))))
1140 1200
1141(defun python-send-string (string) 1201(defun python-send-string (string)
1142 "Evaluate STRING in inferior Python process." 1202 "Evaluate STRING in inferior Python process."
1143 (interactive "sPython command: ") 1203 (interactive "sPython command: ")
1144 (comint-send-string (python-proc) string)) 1204 (comint-send-string (python-proc) string)
1205 (comint-send-string (python-proc) "\n\n"))
1145 1206
1146(defun python-send-buffer () 1207(defun python-send-buffer ()
1147 "Send the current buffer to the inferior Python process." 1208 "Send the current buffer to the inferior Python process."
@@ -1198,19 +1259,31 @@ module-qualified names."
1198 (comint-check-source file-name) ; Check to see if buffer needs saved. 1259 (comint-check-source file-name) ; Check to see if buffer needs saved.
1199 (setq python-prev-dir/file (cons (file-name-directory file-name) 1260 (setq python-prev-dir/file (cons (file-name-directory file-name)
1200 (file-name-nondirectory file-name))) 1261 (file-name-nondirectory file-name)))
1201 (comint-send-string 1262 (when python-buffer
1202 (python-proc) 1263 (with-current-buffer python-buffer
1203 (if (string-match "\\.py\\'" file-name) 1264 (let ((end (marker-position (process-mark (python-proc)))))
1204 ;; Fixme: make sure the directory is in the path list 1265 (set (make-local-variable 'compilation-error-list) nil)
1205 (let ((module (file-name-sans-extension 1266 ;; (set (make-local-variable 'compilation-old-error-list) nil)
1206 (file-name-nondirectory file-name)))) 1267 (let ((comint-input-filter-functions
1207 (format "\ 1268 (delete 'python-input-filter comint-input-filter-functions)))
1208if globals().has_key('%s'): 1269 (python-send-string
1209 reload(%s) 1270 (if (string-match "\\.py\\'" file-name)
1210else: 1271 ;; Fixme: make sure the directory is in the path list
1211 import %s 1272 (let ((module (file-name-sans-extension
1273 (file-name-nondirectory file-name))))
1274 (set (make-local-variable 'python-orig-file) nil)
1275 (set (make-local-variable 'python-orig-start-line) nil)
1276 (format "\
1277try:
1278 if globals().has_key(%S): reload(%s)
1279 else: import %s
1280except: None
1212" module module module)) 1281" module module module))
1213 (format "execfile('%s')\n" filename)))) 1282 (set (make-local-variable 'python-orig-file) file-name)
1283 (set (make-local-variable 'python-orig-start-line) 1)
1284 (format "execfile('%s')" file-name))))
1285 (set-marker compilation-parsing-end end)
1286 (setq compilation-last-buffer (current-buffer))))))
1214 1287
1215;; Fixme: Should this start a process if there isn't one? (Unlike cmuscheme.) 1288;; Fixme: Should this start a process if there isn't one? (Unlike cmuscheme.)
1216(defun python-proc () 1289(defun python-proc ()
@@ -1222,74 +1295,114 @@ else:
1222 1295
1223;;;; Context-sensitive help. 1296;;;; Context-sensitive help.
1224 1297
1225;; Fixme: Investigate adapting this to eldoc. 1298(defconst python-dotty-syntax-table
1299 (let ((table (make-syntax-table)))
1300 (set-char-table-parent table python-mode-syntax-table)
1301 (modify-syntax-entry ?. "_" table)
1302 table)
1303 "Syntax table giving `.' symbol syntax.
1304Otherwise inherits from `python-mode-syntax-table'.")
1226 1305
1306;; Fixme: Should this actually be used instead of info-look, i.e. be
1307;; bound to C-h S?
1227(defun python-describe-symbol (symbol) 1308(defun python-describe-symbol (symbol)
1228 "Get help on SYMBOL using `pydoc'. 1309 "Get help on SYMBOL using `pydoc'.
1229Interactively, prompt for symbol." 1310Interactively, prompt for symbol."
1311 ;; Note that we do this in the inferior process, not a separate one to
1312 ;; ensure the environment is appropriate.
1230 (interactive 1313 (interactive
1231 (let ((symbol (current-word)) 1314 (let ((symbol (with-syntax-table python-dotty-syntax-table
1315 (current-word)))
1232 (enable-recursive-minibuffers t) 1316 (enable-recursive-minibuffers t)
1233 val) 1317 val)
1234 (setq val (read-string (if symbol 1318 (setq val (read-string (if symbol
1235 (format "Describe variable (default %s): " 1319 (format "Describe variable (default %s): "
1236 symbol) 1320 symbol)
1237 "Describe variable: ") 1321 "Describe symbol: ")
1238 nil nil symbol)) 1322 nil nil symbol))
1239 (list (or val symbol)))) 1323 (list (or val symbol))))
1240 (if (equal symbol "") (error "No symbol")) 1324 (if (equal symbol "") (error "No symbol"))
1241 (let* ((mod (if (string-match "\\(\\.[^.]+\\)\\'" symbol) 1325 (let* ((func `(lambda ()
1242 (substring symbol 0 (match-beginning 1)))) 1326 (comint-redirect-send-command (format "help(%S)\n" ,symbol)
1243 (import (when mod (concat "import " mod "\n")))) 1327 "*Help*" nil))))
1244 (with-output-to-temp-buffer "*Python Output*" 1328 ;; Ensure we have a suitable help buffer.
1245 (princ (shell-command-to-string 1329 (let (temp-buffer-show-hook) ; avoid xref stuff
1246 (format "%s -c 'import pydoc %s 1330 (with-output-to-temp-buffer "*Help*"
1247try: pydoc.help(%S) 1331 (with-current-buffer standard-output
1248except: print \"No help available on:\", %S'" 1332 (set (make-local-variable 'comint-redirect-subvert-readonly) t))))
1249 ;; Fixme: Is this necessarily right? 1333 (if (and python-buffer (get-buffer python-buffer))
1250 (car (split-string python-command)) 1334 (with-current-buffer python-buffer
1251 (or import "") symbol symbol)))))) 1335 (funcall func))
1336 (setq python-preoutput-continuation func)
1337 (run-python nil t))))
1252 1338
1253(add-to-list 'debug-ignored-errors "^No symbol") 1339(add-to-list 'debug-ignored-errors "^No symbol")
1340
1341;; Fixme: try to make it work with point in the arglist. Also, is
1342;; there anything reasonable we can do with random methods?
1343;; (Currently only works with functions.)
1344(defun python-eldoc-function ()
1345 "`eldoc-print-current-symbol-info' for Python.
1346Only works when point is in a function name, not its arglist, for instance.
1347Assumes an inferior Python is running."
1348 (let ((symbol (with-syntax-table python-dotty-syntax-table
1349 (current-word)))
1350 (proc (and python-buffer (python-proc))))
1351 (when (and proc symbol)
1352 (python-send-string
1353 (format "_emacs_args(%S)" symbol))
1354 (setq python-preoutput-result nil)
1355 (accept-process-output proc 1)
1356 python-preoutput-result)))
1254 1357
1255;;;; Info-look functionality. 1358;;;; Info-look functionality.
1256 1359
1257(require 'info-look) 1360(defun python-after-info-look ()
1258;; We should be able to add info-lookup specs without loading the file first. 1361 "Set up info-look for Python.
1259;; E.g. by setting a buffer-local var or something like that. --Stef 1362Used with `eval-after-load'."
1260(let ((version (let ((s (shell-command-to-string (concat python-command 1363 (let* ((version (let ((s (shell-command-to-string (concat python-command
1261 " -V")))) 1364 " -V"))))
1262 (string-match "^Python \\([0-9]+\\.[0-9]+\\>\\)" s) 1365 (string-match "^Python \\([0-9]+\\.[0-9]+\\>\\)" s)
1263 (match-string 1 s))) 1366 (match-string 1 s)))
1264 ;; Whether info files have a Python version suffix, e.g. in Debian. 1367 ;; Whether info files have a Python version suffix, e.g. in Debian.
1265 (versioned (save-window-excursion 1368 (versioned
1266 (condition-case () 1369 (with-temp-buffer
1267 ;; The call to `info' might create a new frame if 1370 (Info-mode)
1268 ;; pop-up-frames or special-display-buffers are used. 1371 (condition-case ()
1269 ;; So I disabled it until we find a better way 1372 (Info-goto-node (format "(python%s-lib)Miscellaneous Index"
1270 ;; to handle this situation. Maybe Debian should just 1373 version))
1271 ;; fix their install somehow. --Stef 1374 (error nil)))))
1272 ;; (progn (info "(python2.3-lib)Miscellaneous Index") 1375 (info-lookup-maybe-add-help
1273 ;; (Info-last) 1376 :mode 'python-mode
1274 ;; (Info-exit) 1377 :regexp "[[:alnum:]_]+"
1275 ;; t) 1378 :doc-spec
1276 nil 1379 ;; Fixme: Can this reasonably be made specific to indices with
1277 (error nil))))) 1380 ;; different rules? Is the order of indices optimal?
1278 (info-lookup-maybe-add-help 1381 ;; (Miscellaneous in -ref first prefers lookup of keywords, for
1279 :mode 'python-mode 1382 ;; instance.)
1280 :regexp "[[:alnum:]_]+" 1383 (if versioned
1281 :doc-spec 1384 ;; The empty prefix just gets us highlighted terms.
1282 ;; Fixme: Add python-ref? Can this reasonably be made specific 1385 `((,(concat "(python" version "-ref)Miscellaneous Index") nil "")
1283 ;; to indices with different rules? 1386 (,(concat "(python" version "-ref)Module Index" nil ""))
1284 (if versioned 1387 (,(concat "(python" version "-ref)Function-Method-Variable Index"
1285 '((,(concat "(python" version "-lib)Module Index")) 1388 nil ""))
1286 (,(concat "(python" version "-lib)Class-Exception-Object Index")) 1389 (,(concat "(python" version "-ref)Class-Exception-Object Index"
1287 (,(concat "(python" version "-lib)Function-Method-Variable Index")) 1390 nil ""))
1288 (,(concat "(python" version "-lib)Miscellaneous Index"))) 1391 (,(concat "(python" version "-lib)Module Index" nil ""))
1289 '(("(python-lib)Module Index") 1392 (,(concat "(python" version "-lib)Class-Exception-Object Index"
1290 ("(python-lib)Class-Exception-Object Index") 1393 nil ""))
1291 ("(python-lib)Function-Method-Variable Index") 1394 (,(concat "(python" version "-lib)Function-Method-Variable Index"
1292 ("(python-lib)Miscellaneous Index"))))) 1395 nil ""))
1396 (,(concat "(python" version "-lib)Miscellaneous Index" nil "")))
1397 '(("(python-ref)Miscellaneous Index" nil "")
1398 ("(python-ref)Module Index" nil "")
1399 ("(python-ref)Function-Method-Variable Index" nil "")
1400 ("(python-ref)Class-Exception-Object Index" nil "")
1401 ("(python-lib)Module Index" nil "")
1402 ("(python-lib)Class-Exception-Object Index" nil "")
1403 ("(python-lib)Function-Method-Variable Index" nil "")
1404 ("(python-lib)Miscellaneous Index" nil ""))))))
1405(eval-after-load "info-look" '(python-after-info-look))
1293 1406
1294;;;; Miscellancy. 1407;;;; Miscellancy.
1295 1408
@@ -1309,34 +1422,65 @@ The criterion is either a match for `jython-mode' via
1309`python-jython-packages'." 1422`python-jython-packages'."
1310 ;; The logic is taken from python-mode.el. 1423 ;; The logic is taken from python-mode.el.
1311 (save-excursion 1424 (save-excursion
1312 (goto-char (point-min)) 1425 (save-restriction
1313 (let ((interpreter (if (looking-at auto-mode-interpreter-regexp) 1426 (widen)
1314 (match-string 2)))) 1427 (goto-char (point-min))
1315 (if (and interpreter (eq 'jython-mode 1428 (let ((interpreter (if (looking-at auto-mode-interpreter-regexp)
1316 (cdr (assoc (file-name-nondirectory interpreter) 1429 (match-string 2))))
1317 interpreter-mode-alist)))) 1430 (if (and interpreter (eq 'jython-mode
1318 (jython-mode) 1431 (cdr (assoc (file-name-nondirectory
1319 (if (catch 'done 1432 interpreter)
1320 (while (re-search-forward 1433 interpreter-mode-alist))))
1321 (rx (and line-start (or "import" "from") (1+ space) 1434 (jython-mode)
1322 (group (1+ (not (any " \t\n.")))))) 1435 (if (catch 'done
1323 (+ (point) 10000) ; Probably not worth customizing. 1436 (while (re-search-forward
1324 t) 1437 (rx (and line-start (or "import" "from") (1+ space)
1325 (if (member (match-string 1) python-jython-packages) 1438 (group (1+ (not (any " \t\n."))))))
1326 (throw 'done t)))) 1439 10000 ; Probably not worth customizing.
1327 (jython-mode)))))) 1440 t)
1441 (if (member (match-string 1) python-jython-packages)
1442 (throw 'done t))))
1443 (jython-mode)))))))
1328 1444
1329(defun python-fill-paragraph (&optional justify) 1445(defun python-fill-paragraph (&optional justify)
1330 "Like \\[fill-paragraph], but handle comments and multi-line strings. 1446 "`fill-paragraph-function' handling comments and multi-line strings.
1331If any of the current line is a comment, fill the comment or the 1447If any of the current line is a comment, fill the comment or the
1332paragraph of it that point is in, preserving the comment's indentation 1448paragraph of it that point is in, preserving the comment's
1333and initial comment characters." 1449indentation and initial comment characters. Similarly if the end
1450of the current line is in or at the end of a multi-line string.
1451Otherwise, do nothing."
1334 (interactive "P") 1452 (interactive "P")
1335 (or (fill-comment-paragraph justify) 1453 (or (fill-comment-paragraph justify)
1336 (let ((paragraph-start (concat paragraph-start 1454 ;; The `paragraph-start' and `paragraph-separate' variables
1337 "\\|\\s-*\\(:?#\\s\"\\|\\s|\\|#"))) 1455 ;; don't allow us to delimit the last paragraph in a multi-line
1338 (fill-paragraph justify)) 1456 ;; string properly, so narrow to the string and then fill around
1339 t)) 1457 ;; (the end of) the current line.
1458 (save-excursion
1459 (end-of-line)
1460 (let* ((syntax (syntax-ppss))
1461 (orig (point))
1462 (start (nth 8 syntax))
1463 end)
1464 (cond ((eq t (nth 3 syntax)) ; in fenced string
1465 (goto-char (nth 8 syntax)) ; string start
1466 (condition-case () ; for unbalanced quotes
1467 (progn (forward-sexp)
1468 (setq end (point)))
1469 (error (setq end (point-max)))))
1470 ((re-search-backward "\\s|\\s-*\\=" nil t) ; end of fenced
1471 ; string
1472 (forward-char)
1473 (setq end (point))
1474 (condition-case ()
1475 (progn (backward-sexp)
1476 (setq start (point)))
1477 (error nil))))
1478 (when end
1479 (save-restriction
1480 (narrow-to-region start end)
1481 (goto-char orig)
1482 (fill-paragraph justify))))))
1483 t)
1340 1484
1341(defun python-shift-left (start end &optional count) 1485(defun python-shift-left (start end &optional count)
1342 "Shift lines in region COUNT (the prefix arg) columns to the left. 1486 "Shift lines in region COUNT (the prefix arg) columns to the left.
@@ -1377,7 +1521,8 @@ END lie."
1377 1521
1378(defun python-outline-level () 1522(defun python-outline-level ()
1379 "`outline-level' function for Python mode. 1523 "`outline-level' function for Python mode.
1380The level is the number of `python-indent' steps of indentation." 1524The level is the number of `python-indent' steps of indentation
1525of current line."
1381 (/ (current-indentation) python-indent)) 1526 (/ (current-indentation) python-indent))
1382 1527
1383;; Fixme: Consider top-level assignments, imports, &c. 1528;; Fixme: Consider top-level assignments, imports, &c.
@@ -1411,17 +1556,23 @@ Uses `python-beginning-of-block', `python-end-of-block'."
1411 1556
1412;;;; Modes. 1557;;;; Modes.
1413 1558
1559(defvar outline-heading-end-regexp)
1560(defvar eldoc-print-current-symbol-info-function)
1561
1414;;;###autoload 1562;;;###autoload
1415(define-derived-mode python-mode fundamental-mode "Python" 1563(define-derived-mode python-mode fundamental-mode "Python"
1416 "Major mode for editing Python files. 1564 "Major mode for editing Python files.
1417Turns on Font Lock mode unconditionally since it is required for correct 1565Turns on Font Lock mode unconditionally since it is required for correct
1418parsing of the source. 1566parsing of the source.
1419See also `jython-mode', which is actually invoked if the buffer appears to 1567See also `jython-mode', which is actually invoked if the buffer appears to
1420contain Jython code. 1568contain Jython code. See also `run-python' and associated Python mode
1569commands for running Python under Emacs.
1421 1570
1422The Emacs commands which work with `defun's, e.g. \\[beginning-of-defun], deal 1571The Emacs commands which work with `defun's, e.g. \\[beginning-of-defun], deal
1423with nested `def' and `class' blocks. They take the innermost one as 1572with nested `def' and `class' blocks. They take the innermost one as
1424current without distinguishing method and class definitions. 1573current without distinguishing method and class definitions. Used multiple
1574times, they move over others at the same indentation level until they reach
1575the end of definitions at that level, when they move up a level.
1425\\<python-mode-map> 1576\\<python-mode-map>
1426Colon is electric: it outdents the line if appropriate, e.g. for 1577Colon is electric: it outdents the line if appropriate, e.g. for
1427an else statement. \\[python-backspace] at the beginning of an indented statement 1578an else statement. \\[python-backspace] at the beginning of an indented statement
@@ -1430,6 +1581,13 @@ deletes a charcter backward. TAB indents the current line relative to
1430the preceding code. Successive TABs, with no intervening command, cycle 1581the preceding code. Successive TABs, with no intervening command, cycle
1431through the possibilities for indentation on the basis of enclosing blocks. 1582through the possibilities for indentation on the basis of enclosing blocks.
1432 1583
1584\\[fill-paragraph] fills comments and multiline strings appropriately, but has no
1585effect outside them.
1586
1587Supports Eldoc mode (only for functions, using a Python process),
1588Info-Look and Imenu. In Outline minor mode, `class' and `def'
1589lines count as headers.
1590
1433\\{python-mode-map}" 1591\\{python-mode-map}"
1434 :group 'python 1592 :group 'python
1435 (set (make-local-variable 'font-lock-defaults) 1593 (set (make-local-variable 'font-lock-defaults)
@@ -1451,7 +1609,8 @@ through the possibilities for indentation on the basis of enclosing blocks.
1451 (set (make-local-variable 'add-log-current-defun-function) 1609 (set (make-local-variable 'add-log-current-defun-function)
1452 #'python-current-defun) 1610 #'python-current-defun)
1453 ;; Fixme: Generalize to do all blocks? 1611 ;; Fixme: Generalize to do all blocks?
1454 (set (make-local-variable 'outline-regexp) "\\s-+\\(def\\|class\\)\\>") 1612 (set (make-local-variable 'outline-regexp) "\\s-*\\(def\\|class\\)\\>")
1613 (set (make-local-variable 'outline-heading-end-regexp) ":\\s-*\n")
1455 (set (make-local-variable 'outline-level) #'python-outline-level) 1614 (set (make-local-variable 'outline-level) #'python-outline-level)
1456 (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil) 1615 (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil)
1457 (make-local-variable 'python-saved-check-command) 1616 (make-local-variable 'python-saved-check-command)
@@ -1459,6 +1618,10 @@ through the possibilities for indentation on the basis of enclosing blocks.
1459 'python-beginning-of-defun) 1618 'python-beginning-of-defun)
1460 (set (make-local-variable 'end-of-defun-function) 'python-end-of-defun) 1619 (set (make-local-variable 'end-of-defun-function) 'python-end-of-defun)
1461 (setq imenu-create-index-function #'python-imenu-create-index) 1620 (setq imenu-create-index-function #'python-imenu-create-index)
1621 (set (make-local-variable 'eldoc-print-current-symbol-info-function)
1622 #'python-eldoc-function)
1623 (add-hook 'eldoc-mode-hook
1624 '(lambda () (run-python 0 t)) nil t) ; need it running
1462 (unless font-lock-mode (font-lock-mode 1)) 1625 (unless font-lock-mode (font-lock-mode 1))
1463 (when python-guess-indent (python-guess-indent)) 1626 (when python-guess-indent (python-guess-indent))
1464 (set (make-local-variable 'python-command) python-python-command) 1627 (set (make-local-variable 'python-command) python-python-command)
@@ -1471,6 +1634,7 @@ through the possibilities for indentation on the basis of enclosing blocks.
1471 '(lambda () 1634 '(lambda ()
1472 "Turn on Indent Tabs mode." 1635 "Turn on Indent Tabs mode."
1473 (set (make-local-variable 'indent-tabs-mode) t))) 1636 (set (make-local-variable 'indent-tabs-mode) t)))
1637(custom-add-option 'python-mode-hook 'turn-on-eldoc-mode)
1474 1638
1475;;;###autoload 1639;;;###autoload
1476(define-derived-mode jython-mode python-mode "Jython" 1640(define-derived-mode jython-mode python-mode "Jython"