-;;; python.el -- Python's flying circus support for Emacs
+;;; python.el --- Python's flying circus support for Emacs
;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
;; Ordered by priority:
-;; Better decorator support for beginning of defun
-
-;; Review code and cleanup
+;; Give a better interface for virtualenv support in interactive
+;; shells
;;; Code:
(,(rx symbol-start "class" (1+ space) (group (1+ (or word ?_))))
(1 font-lock-type-face))
;; Constants
- (,(rx symbol-start (group "None" symbol-end))
- (1 font-lock-constant-face))
+ (,(rx symbol-start
+ ;; copyright, license, credits, quit, exit are added by the
+ ;; site module and since they are not intended to be used in
+ ;; programs they are not added here either.
+ (or "None" "True" "False" "Ellipsis" "__debug__" "NotImplemented")
+ symbol-end) . font-lock-constant-face)
;; Decorators.
(,(rx line-start (* (any " \t")) (group "@" (1+ (or word ?_))
(0+ "." (1+ (or word ?_)))))
"FutureWarning" "GeneratorExit" "IOError" "ImportError"
"ImportWarning" "IndentationError" "IndexError" "KeyError"
"KeyboardInterrupt" "LookupError" "MemoryError" "NameError"
- "NotImplemented" "NotImplementedError" "OSError" "OverflowError"
+ "NotImplementedError" "OSError" "OverflowError"
"PendingDeprecationWarning" "ReferenceError" "RuntimeError"
"RuntimeWarning" "StandardError" "StopIteration" "SyntaxError"
"SyntaxWarning" "SystemError" "SystemExit" "TabError" "TypeError"
"UserWarning" "ValueError" "Warning" "ZeroDivisionError")
symbol-end) . font-lock-type-face)
;; Builtins
- (,(rx (or line-start (not (any ". \t"))) (* (any " \t")) symbol-start
- (group
- (or "_" "__debug__" "__doc__" "__import__" "__name__" "__package__"
- "abs" "all" "any" "apply" "basestring" "bin" "bool" "buffer"
- "bytearray" "bytes" "callable" "chr" "classmethod" "cmp" "coerce"
- "compile" "complex" "copyright" "credits" "delattr" "dict" "dir"
- "divmod" "enumerate" "eval" "execfile" "exit" "file" "filter"
- "float" "format" "frozenset" "getattr" "globals" "hasattr" "hash"
- "help" "hex" "id" "input" "int" "intern" "isinstance" "issubclass"
- "iter" "len" "license" "list" "locals" "long" "map" "max" "min"
- "next" "object" "oct" "open" "ord" "pow" "print" "property" "quit"
- "range" "raw_input" "reduce" "reload" "repr" "reversed" "round"
- "set" "setattr" "slice" "sorted" "staticmethod" "str" "sum"
- "super" "tuple" "type" "unichr" "unicode" "vars" "xrange" "zip"
- "True" "False" "Ellipsis")) symbol-end)
- (1 font-lock-builtin-face))
+ (,(rx symbol-start
+ (or "_" "__doc__" "__import__" "__name__" "__package__" "abs" "all"
+ "any" "apply" "basestring" "bin" "bool" "buffer" "bytearray"
+ "bytes" "callable" "chr" "classmethod" "cmp" "coerce" "compile"
+ "complex" "delattr" "dict" "dir" "divmod" "enumerate" "eval"
+ "execfile" "file" "filter" "float" "format" "frozenset"
+ "getattr" "globals" "hasattr" "hash" "help" "hex" "id" "input"
+ "int" "intern" "isinstance" "issubclass" "iter" "len" "list"
+ "locals" "long" "map" "max" "min" "next" "object" "oct" "open"
+ "ord" "pow" "print" "property" "range" "raw_input" "reduce"
+ "reload" "repr" "reversed" "round" "set" "setattr" "slice"
+ "sorted" "staticmethod" "str" "sum" "super" "tuple" "type"
+ "unichr" "unicode" "vars" "xrange" "zip")
+ symbol-end) . font-lock-builtin-face)
;; asignations
;; support for a = b = c = 5
(,(lambda (limit)
(set-match-data nil)))))
(1 font-lock-variable-name-face nil nil))))
-;; Fixme: Is there a better way?
(defconst python-font-lock-syntactic-keywords
+ ;; Make outer chars of matching triple-quote sequences into generic
+ ;; string delimiters. Fixme: Is there a better way?
;; First avoid a sequence preceded by an odd number of backslashes.
- `((,(rx (not (any ?\\))
- ?\\ (* (and ?\\ ?\\))
- (group (syntax string-quote))
- (backref 1)
- (group (backref 1)))
- (2 ,(string-to-syntax "\""))) ; dummy
- (,(rx (group (optional (any "uUrR"))) ; prefix gets syntax property
- (optional (any "rR")) ; possible second prefix
- (group (syntax string-quote)) ; maybe gets property
- (backref 2) ; per first quote
- (group (backref 2))) ; maybe gets property
- (1 (python-quote-syntax 1))
- (2 (python-quote-syntax 2))
- (3 (python-quote-syntax 3))))
- "Make outer chars of triple-quote strings into generic string delimiters.")
-
-(defun python-quote-syntax (n)
+ `((,(concat "\\(?:\\([RUru]\\)[Rr]?\\|^\\|[^\\]\\(?:\\\\.\\)*\\)" ;Prefix.
+ "\\(?:\\('\\)'\\('\\)\\|\\(?2:\"\\)\"\\(?3:\"\\)\\)")
+ (3 (python-quote-syntax)))))
+
+(defun python-quote-syntax ()
"Put `syntax-table' property correctly on triple quote.
Used for syntactic keywords. N is the match number (1, 2 or 3)."
;; Given a triple quote, we have to check the context to know
;; x '"""' x """ \"""" x
(save-excursion
(goto-char (match-beginning 0))
- (cond
- ;; Consider property for the last char if in a fenced string.
- ((= n 3)
- (let* ((font-lock-syntactic-keywords nil)
- (syntax (syntax-ppss)))
- (when (eq t (nth 3 syntax)) ; after unclosed fence
- (goto-char (nth 8 syntax)) ; fence position
- (skip-chars-forward "uUrR") ; skip any prefix
- ;; Is it a matching sequence?
- (if (eq (char-after) (char-after (match-beginning 2)))
- (eval-when-compile (string-to-syntax "|"))))))
- ;; Consider property for initial char, accounting for prefixes.
- ((or (and (= n 2) ; leading quote (not prefix)
- (= (match-beginning 1) (match-end 1))) ; prefix is null
- (and (= n 1) ; prefix
- (/= (match-beginning 1) (match-end 1)))) ; non-empty
- (let ((font-lock-syntactic-keywords nil))
- (unless (eq 'string (syntax-ppss-context (syntax-ppss)))
- (eval-when-compile (string-to-syntax "|")))))
- ;; Otherwise (we're in a non-matching string) the property is
- ;; nil, which is OK.
- )))
+ (let ((syntax (save-match-data (syntax-ppss))))
+ (cond
+ ((eq t (nth 3 syntax)) ; after unclosed fence
+ ;; Consider property for the last char if in a fenced string.
+ (goto-char (nth 8 syntax)) ; fence position
+ (skip-chars-forward "uUrR") ; skip any prefix
+ ;; Is it a matching sequence?
+ (if (eq (char-after) (char-after (match-beginning 2)))
+ (put-text-property (match-beginning 3) (match-end 3)
+ 'syntax-table (string-to-syntax "|"))))
+ ((match-end 1)
+ ;; Consider property for initial char, accounting for prefixes.
+ (put-text-property (match-beginning 1) (match-end 1)
+ 'syntax-table (string-to-syntax "|")))
+ (t
+ ;; Consider property for initial char, accounting for prefixes.
+ (put-text-property (match-beginning 2) (match-end 2)
+ 'syntax-table (string-to-syntax "|"))))
+ )))
(defvar python-mode-syntax-table
(let ((table (make-syntax-table)))
:group 'python
:safe 'stringp)
+(defvar python-shell-internal-buffer-name "Python Internal"
+ "Default buffer name for the Internal Python interpreter.")
+
(defcustom python-shell-interpreter-args "-i"
"Default arguments for the Python interpreter."
:type 'string
(format "*%s*" process-name)))
process-name))
+(defun python-shell-internal-get-process-name ()
+ "Calculate the appropiate process name for Internal Python process.
+The name is calculated from `python-shell-global-buffer-name' and
+a hash of all relevant global shell settings in order to ensure
+uniqueness for different types of configurations."
+ (format "%s [%s]"
+ python-shell-internal-buffer-name
+ (md5
+ (concat
+ (python-shell-parse-command)
+ (mapconcat #'symbol-value python-shell-setup-codes "")
+ (mapconcat #'indentity python-shell-process-environment "")
+ (mapconcat #'indentity python-shell-exec-path "")))))
+
(defun python-shell-parse-command ()
"Calculate the string used to execute the inferior Python process."
(format "%s %s" python-shell-interpreter python-shell-interpreter-args))
(pop-to-buffer proc-buffer-name))
dedicated)
+(defun run-python-internal ()
+ "Run an inferior Internal Python process.
+Input and output via buffer named after
+`python-shell-internal-buffer-name' and what
+`python-shell-internal-get-process-name' returns. This new kind
+of shell is intended to be used for generic communication related
+to defined configurations. The main difference with global or
+dedicated shells is that these ones are attached to a
+configuration, not a buffer. This means that can be used for
+example to retrieve the sys.path and other stuff, without messing
+with user shells. Runs the hook
+`inferior-python-mode-hook' (after the `comint-mode-hook' is
+run). \(Type \\[describe-mode] in the process buffer for a list
+of commands.)"
+ (interactive)
+ (save-excursion
+ (let* ((cmd (python-shell-parse-command))
+ (proc-name (python-shell-internal-get-process-name))
+ (proc-buffer-name (format "*%s*" proc-name))
+ (process-environment
+ (if python-shell-process-environment
+ (python-util-merge 'list python-shell-process-environment
+ process-environment 'string=)
+ process-environment))
+ (exec-path
+ (if python-shell-exec-path
+ (python-util-merge 'list python-shell-exec-path
+ exec-path 'string=)
+ exec-path)))
+ (when (not (comint-check-proc proc-buffer-name))
+ (let ((cmdlist (split-string-and-unquote cmd)))
+ (set-buffer
+ (apply 'make-comint proc-name (car cmdlist) nil
+ (cdr cmdlist)))
+ (inferior-python-mode))))))
+
(defun python-shell-get-process ()
"Get inferior Python process for current buffer and return it."
(let* ((dedicated-proc-name (python-shell-get-process-name t))
dedicated-proc-buffer-name
global-proc-buffer-name))))
+(defun python-shell-internal-get-or-create-process ()
+ "Get or create an inferior Internal Python process."
+ (let* ((proc-name (python-shell-internal-get-process-name))
+ (proc-buffer-name (format "*%s*" proc-name)))
+ (run-python-internal)
+ (get-buffer-process proc-buffer-name)))
+
(defun python-shell-send-string (string &optional process msg)
"Send STRING to inferior Python PROCESS.
When MSG is non-nil messages the first line of STRING."
(lambda (string) string)
(butlast (split-string output-buffer "\n")) "\n")))
+(defun python-shell-internal-send-string (string)
+ "Send STRING to the Internal Python interpreter.
+Returns the output. See `python-shell-send-string-no-output'."
+ (python-shell-send-string-no-output
+ ;; Makes this function compatible with the old
+ ;; python-send-receive. (At least for CEDET).
+ (replace-regexp-in-string "_emacs_out +" "" string)
+ (python-shell-internal-get-or-create-process) nil))
+
+(define-obsolete-function-alias
+ 'python-send-receive 'python-shell-internal-send-string "23.3"
+ "Send STRING to inferior Python (if any) and return result.
+The result is what follows `_emacs_out' in the output.
+This is a no-op if `python-check-comint-prompt' returns nil.")
+
(defun python-shell-send-region (start end)
"Send the region delimited by START and END to inferior Python process."
(interactive "r")
`add-log-current-defun-function' since it returns nil if point is
not inside a defun."
(let ((names '())
- (min-indent))
+ (min-indent)
+ (first-run t))
(save-restriction
(widen)
(save-excursion
(forward-comment -9999)
(setq min-indent (current-indentation))
(while (python-beginning-of-defun-function 1 t)
- (when (< (current-indentation) min-indent)
+ (when (or (< (current-indentation) min-indent)
+ first-run)
+ (setq first-run nil)
(setq min-indent (current-indentation))
(looking-at python-nav-beginning-of-defun-regexp)
(setq names (cons
,(lambda (arg)
(python-end-of-defun-function)) nil))
+ (set (make-local-variable 'mode-require-final-newline) t)
+
(set (make-local-variable 'outline-regexp)
(python-rx (* space) block-start))
(set (make-local-variable 'outline-heading-end-regexp) ":\\s-*\n")