;;; python.el --- silly walks for Python -*- coding: iso-8859-1 -*-
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
;; Free Software Foundation, Inc.
;; Author: Dave Love <fx@gnu.org>
(,(rx symbol-start (group "def") (1+ space) (group (1+ (or word ?_))))
(1 font-lock-keyword-face) (2 font-lock-function-name-face))
;; Top-level assignments are worth highlighting.
- (,(rx line-start (group (1+ (or word ?_))) (0+ space) "=")
+ (,(rx line-start (group (1+ (or word ?_))) (0+ space)
+ (opt (or "+" "-" "*" "**" "/" "//" "&" "%" "|" "^" "<<" ">>")) "=")
(1 font-lock-variable-name-face))
;; Decorators.
(,(rx line-start (* (any " \t")) (group "@" (1+ (or word ?_))
symbol-end)
. font-lock-builtin-face)))
-(defconst python-font-lock-syntactic-keywords
+(defconst python-syntax-propertize-function
;; 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)))
- ;; This doesn't really help.
-;;; (,(rx (and ?\\ (group ?\n))) (1 " "))
- ))
-
-(defun python-quote-syntax (n)
+ (syntax-propertize-rules
+ (;; ¡Backrefs don't work in syntax-propertize-rules!
+ (concat "\\(?:\\([RUru]\\)[Rr]?\\|^\\|[^\\]\\(?:\\\\.\\)*\\)" ;Prefix.
+ "\\(?:\\('\\)'\\('\\)\\|\\(?2:\"\\)\"\\(?3:\"\\)\\)")
+ (3 (ignore (python-quote-syntax))))
+ ;; This doesn't really help.
+ ;;((rx (and ?\\ (group ?\n))) (1 " "))
+ ))
+
+(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 "|"))))
+ )))
;; This isn't currently in `font-lock-defaults' as probably not worth
;; it -- we basically only mess with a few normally-symbol characters.
'(("else" "if" "elif" "while" "for" "try" "except")
("elif" "if" "elif")
("except" "try" "except")
- ("finally" "try" "except"))
+ ("finally" "else" "try" "except"))
"Alist of keyword matches.
The car of an element is a keyword introducing a statement which
can close a block opened by a keyword in the cdr.")
(let ((name (buffer-file-name)))
(if name
(file-name-nondirectory name))))))))
- (setq python-saved-check-command command)
+ (set (make-local-variable 'python-saved-check-command) command)
(require 'compile) ;To define compilation-* variables.
(save-some-buffers (not compilation-ask-about-save) nil)
(let ((compilation-error-regexp-alist
:type 'regexp
:group 'python)
+(defcustom python-remove-cwd-from-path t
+ "Whether to allow loading of Python modules from the current directory.
+If this is non-nil, Emacs removes '' from sys.path when starting
+an inferior Python process. This is the default, for security
+reasons, as it is easy for the Python process to be started
+without the user's realization (e.g. to perform completion)."
+ :type 'boolean
+ :group 'python
+ :version "23.3")
+
(defun python-input-filter (str)
"`comint-input-filter' function for inferior Python.
Don't save anything for STR matching `inferior-python-filter-regexp'."
;;;###autoload
(defun run-python (&optional cmd noshow new)
"Run an inferior Python process, input and output via buffer *Python*.
-CMD is the Python command to run. NOSHOW non-nil means don't show the
-buffer automatically.
-
-Normally, if there is a process already running in `python-buffer',
-switch to that buffer. Interactively, a prefix arg allows you to edit
-the initial command line (default is `python-command'); `-i' etc. args
-will be added to this as appropriate. A new process is started if:
-one isn't running attached to `python-buffer', or interactively the
-default `python-command', or argument NEW is non-nil. See also the
-documentation for `python-buffer'.
-
-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.)"
+CMD is the Python command to run. NOSHOW non-nil means don't
+show the buffer automatically.
+
+Interactively, a prefix arg means to prompt for the initial
+Python command line (default is `python-command').
+
+A new process is started if one isn't running attached to
+`python-buffer', or if called from Lisp with non-nil arg NEW.
+Otherwise, if a process is already running in `python-buffer',
+switch to that buffer.
+
+This command runs the hook `inferior-python-mode-hook' after
+running `comint-mode-hook'. Type \\[describe-mode] in the
+process buffer for a list of commands.
+
+By default, Emacs inhibits the loading of Python modules from the
+current working directory, for security reasons. To disable this
+behavior, change `python-remove-cwd-from-path' to nil."
(interactive (if current-prefix-arg
(list (read-string "Run Python: " python-command) nil t)
(list python-command)))
(when (or new (not (comint-check-proc python-buffer)))
(with-current-buffer
(let* ((cmdlist
- (append (python-args-to-list cmd)
- '("-i" "-c" "import sys; sys.path.remove('')")))
+ (append (python-args-to-list cmd) '("-i")
+ (if python-remove-cwd-from-path
+ '("-c" "import sys; sys.path.remove('')"))))
(path (getenv "PYTHONPATH"))
(process-environment ; to import emacs.py
(cons (concat "PYTHONPATH="
(eval-when-compile
;; Define a user-level skeleton and add it to the abbrev table.
(defmacro def-python-skeleton (name &rest elements)
+ (declare (indent 2))
(let* ((name (symbol-name name))
(function (intern (concat "python-insert-" name))))
`(progn
(define-skeleton ,function
,(format "Insert Python \"%s\" template." name)
,@elements)))))
-(put 'def-python-skeleton 'lisp-indent-function 2)
;; From `skeleton-further-elements' set below:
;; `<': outdent a level;
:group 'python
(set (make-local-variable 'font-lock-defaults)
'(python-font-lock-keywords nil nil nil nil
- (font-lock-syntactic-keywords
- . python-font-lock-syntactic-keywords)
- ;; This probably isn't worth it.
- ;; (font-lock-syntactic-face-function
- ;; . python-font-lock-syntactic-face-function)
- ))
+ ;; This probably isn't worth it.
+ ;; (font-lock-syntactic-face-function
+ ;; . python-font-lock-syntactic-face-function)
+ ))
+ (set (make-local-variable 'syntax-propertize-function)
+ python-syntax-propertize-function)
(set (make-local-variable 'parse-sexp-lookup-properties) t)
(set (make-local-variable 'parse-sexp-ignore-comments) t)
(set (make-local-variable 'comment-start) "# ")
(set (make-local-variable 'outline-heading-end-regexp) ":\\s-*\n")
(set (make-local-variable 'outline-level) #'python-outline-level)
(set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil)
- (make-local-variable 'python-saved-check-command)
(set (make-local-variable 'beginning-of-defun-function)
'python-beginning-of-defun)
(set (make-local-variable 'end-of-defun-function) 'python-end-of-defun)
(^ '(- (1+ (current-indentation))))))
;; Python defines TABs as being 8-char wide.
(set (make-local-variable 'tab-width) 8)
- (unless font-lock-mode (font-lock-mode 1))
(when python-guess-indent (python-guess-indent))
;; Let's make it harder for the user to shoot himself in the foot.
(unless (= tab-width python-indent)
overlay-arrow-string "=>"
python-pdbtrack-is-tracking-p t)
(set-marker overlay-arrow-position
- (save-excursion (beginning-of-line) (point))
+ (line-beginning-position)
(current-buffer)))
(setq overlay-arrow-position nil
python-pdbtrack-is-tracking-p nil)))
process is started. If you use this, you will probably want to ensure
that the current arguments are retained (they will be included in the
prompt). This argument is ignored when this function is called
-programmatically, or when running in Emacs 19.34 or older.
+programmatically.
Note: You can toggle between using the CPython interpreter and the
JPython interpreter by hitting \\[python-toggle-shells]. This toggles
(provide 'python)
(provide 'python-21)
-;; arch-tag: 6fce1d99-a704-4de9-ba19-c6e4912b0554
;;; python.el ends here