;;; python.el --- silly walks for Python
-;; Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
;; Author: Dave Love <fx@gnu.org>
;; Maintainer: FSF
;;; Code:
(eval-when-compile
+ (require 'cl)
(require 'compile)
- (require 'comint))
+ (require 'comint)
+ (require 'hippie-exp))
(autoload 'comint-mode "comint")
"import" "in" "is" "lambda" "not" "or" "pass" "print"
"raise" "return" "try" "while" "yield"
;; Future keywords
- "as" "None")
+ "as" "None"
+ ;; Not real keywords, but close enough to be fontified as such
+ "self" "True" "False")
symbol-end)
;; Definitions
(,(rx symbol-start (group "class") (1+ space) (group (1+ (or word ?_))))
(= (match-beginning 1) (match-end 1))) ; prefix is null
(and (= n 1) ; prefix
(/= (match-beginning 1) (match-end 1)))) ; non-empty
- (unless (eq 'string (syntax-ppss-context (syntax-ppss)))
+ (unless (nth 3 (syntax-ppss))
(eval-when-compile (string-to-syntax "|"))))
;; Otherwise (we're in a non-matching string) the property is
;; nil, which is OK.
;;;; Indentation.
(defcustom python-indent 4
- "*Number of columns for a unit of indentation in Python mode.
+ "Number of columns for a unit of indentation in Python mode.
See also `\\[python-guess-indent]'"
:group 'python
:type 'integer)
+(put 'python-indent 'safe-local-variable 'integerp)
(defcustom python-guess-indent t
- "*Non-nil means Python mode guesses `python-indent' for the buffer."
+ "Non-nil means Python mode guesses `python-indent' for the buffer."
:type 'boolean
:group 'python)
(defcustom python-indent-string-contents t
- "*Non-nil means indent contents of multi-line strings together.
+ "Non-nil means indent contents of multi-line strings together.
This means indent them the same as the preceding non-blank line.
Otherwise preserve their indentation.
:group 'python)
(defcustom python-continuation-offset 4
- "*Number of columns of additional indentation for continuation lines.
+ "Number of columns of additional indentation for continuation lines.
Continuation lines follow a backslash-terminated line starting a
statement."
:group 'python
((looking-at (rx (0+ space) (syntax comment-start)
(not (any " \t\n")))) ; non-indentable comment
(current-indentation))
- (t (let ((point (point)))
- (if python-honour-comment-indentation
- ;; Back over whitespace, newlines, non-indentable comments.
- (catch 'done
- (while t
- (if (cond ((bobp))
- ;; not at comment start
- ((not (forward-comment -1))
- (python-beginning-of-statement)
- t)
- ;; trailing comment
- ((/= (current-column) (current-indentation))
- (python-beginning-of-statement)
- t)
- ;; indentable comment like python-mode.el
- ((and (looking-at (rx (syntax comment-start)
- (or space line-end)))
- (/= 0 (current-column)))))
- (throw 'done t)))))
- (python-indentation-levels)
- ;; Prefer to indent comments with an immediately-following
- ;; statement, e.g.
- ;; ...
- ;; # ...
- ;; def ...
- (when (and (> python-indent-list-length 1)
- (python-comment-line-p))
- (forward-line)
- (unless (python-comment-line-p)
- (let ((elt (assq (current-indentation) python-indent-list)))
- (setq python-indent-list
- (nconc (delete elt python-indent-list)
- (list elt))))))
- (caar (last python-indent-list))))))))
+ (t (if python-honour-comment-indentation
+ ;; Back over whitespace, newlines, non-indentable comments.
+ (catch 'done
+ (while t
+ (if (cond ((bobp))
+ ;; not at comment start
+ ((not (forward-comment -1))
+ (python-beginning-of-statement)
+ t)
+ ;; trailing comment
+ ((/= (current-column) (current-indentation))
+ (python-beginning-of-statement)
+ t)
+ ;; indentable comment like python-mode.el
+ ((and (looking-at (rx (syntax comment-start)
+ (or space line-end)))
+ (/= 0 (current-column)))))
+ (throw 'done t)))))
+ (python-indentation-levels)
+ ;; Prefer to indent comments with an immediately-following
+ ;; statement, e.g.
+ ;; ...
+ ;; # ...
+ ;; def ...
+ (when (and (> python-indent-list-length 1)
+ (python-comment-line-p))
+ (forward-line)
+ (unless (python-comment-line-p)
+ (let ((elt (assq (current-indentation) python-indent-list)))
+ (setq python-indent-list
+ (nconc (delete elt python-indent-list)
+ (list elt))))))
+ (caar (last python-indent-list)))))))
;;;; Cycling through the possible indentations with successive TABs.
(let ((ci (current-indentation))
(def-re (rx line-start (0+ space) (or "def" "class") (1+ space)
(group (1+ (or word (syntax symbol))))))
- found lep def-line)
+ found lep) ;; def-line
(if (python-comment-line-p)
(setq ci most-positive-fixnum))
(while (and (not (bobp)) (not found))
;; Treat bol at beginning of function as outside function so
;; that successive C-M-a makes progress backwards.
- (setq def-line (looking-at def-re))
+ ;;(setq def-line (looking-at def-re))
(unless (bolp) (end-of-line))
(setq lep (line-end-position))
(if (and (re-search-backward def-re nil 'move)
;; Not sure why it was like this -- fails in case of
;; last internal function followed by first
;; non-def statement of the main body.
-;; (and def-line (= in ci))
+ ;;(and def-line (= in ci))
(= in ci)
(< in ci)))
(not (python-in-string/comment)))
(_ (if (python-comment-line-p)
(python-skip-comments/blanks t)))
(ci (current-indentation))
- (open (python-open-block-statement-p)))
+ (open (python-open-block-statement-p))
+ opoint)
(if (and (zerop ci) (not open))
(not (goto-char point))
(catch 'done
- (while (zerop (python-next-statement))
+ (setq opoint (point))
+ (while (and (zerop (python-next-statement))
+ (not (= opoint (point))))
+ (setq opoint (point))
(when (or (and open (<= (current-indentation) ci))
(< (current-indentation) ci))
(python-skip-comments/blanks t)
;;;; pychecker
(defcustom python-check-command "pychecker --stdlib"
- "*Command used to check a Python file."
+ "Command used to check a Python file."
:type 'string
:group 'python)
;; Fixme: Make sure we can work with IPython.
(defcustom python-python-command "python"
- "*Shell command to run Python interpreter.
+ "Shell command to run Python interpreter.
Any arguments can't contain whitespace.
Note that IPython may not work properly; it must at least be used
with the `-cl' flag, i.e. use `ipython -cl'."
:type 'string)
(defcustom python-jython-command "jython"
- "*Shell command to run Jython interpreter.
+ "Shell command to run Jython interpreter.
Any arguments can't contain whitespace."
:group 'python
:type 'string)
is used by `run-python' et al.")
(defvar python-buffer nil
- "*The current python process buffer.
+ "*The current Python process buffer.
Commands that send text from source buffers to Python processes have
to choose a process to send to. This is determined by buffer-local
;; (define-key map "\C-c\C-f" 'python-describe-symbol)
map))
+(defvar inferior-python-mode-syntax-table
+ (let ((st (make-syntax-table python-mode-syntax-table)))
+ ;; Don't get confused by apostrophes in the process's output (e.g. if
+ ;; you execute "help(os)").
+ (modify-syntax-entry ?\' "." st)
+ ;; Maybe we should do the same for double quotes?
+ ;; (modify-syntax-entry ?\" "." st)
+ st))
+
;; Fixme: This should inherit some stuff from `python-mode', but I'm
;; not sure how much: at least some keybindings, like C-c C-f;
;; syntax?; font-locking, e.g. for triple-quoted strings?
\\{inferior-python-mode-map}"
:group 'python
- (set-syntax-table python-mode-syntax-table)
(setq mode-line-process '(":%s"))
(set (make-local-variable 'comint-input-filter) 'python-input-filter)
(add-hook 'comint-preoutput-filter-functions #'python-preoutput-filter
(compilation-shell-minor-mode 1))
(defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'"
- "*Input matching this regexp is not saved on the history list.
+ "Input matching this regexp is not saved on the history list.
Default ignores all inputs of 0, 1, or 2 non-blank characters."
:type 'regexp
:group 'python)
(defvar python-preoutput-result nil
"Data from last `_emacs_out' line seen by the preoutput filter.")
-(defvar python-preoutput-continuation nil
- "If non-nil, funcall this when `python-preoutput-filter' sees `_emacs_ok'.")
-
(defvar python-preoutput-leftover nil)
+(defvar python-preoutput-skip-next-prompt nil)
;; Using this stops us getting lines in the buffer like
;; >>> ... ... >>>
-;; Also look for (and delete) an `_emacs_ok' string and call
-;; `python-preoutput-continuation' if we get it.
(defun python-preoutput-filter (s)
"`comint-preoutput-filter-functions' function: ignore prompts not at bol."
(when python-preoutput-leftover
(setq s (concat python-preoutput-leftover s))
(setq python-preoutput-leftover nil))
- (cond ((and (string-match (rx string-start (repeat 3 (any ".>"))
- " " string-end)
- s)
- (/= (let ((inhibit-field-text-motion t))
- (line-beginning-position))
- (point)))
- ;; The need for this seems to be system-dependent:
- ;; What is this all about, exactly? --Stef
- ;; (if (and (eq ?. (aref s 0)))
- ;; (accept-process-output (get-buffer-process (current-buffer)) 1))
- "")
- ((string= s "_emacs_ok\n")
- (when python-preoutput-continuation
- (funcall python-preoutput-continuation)
- (setq python-preoutput-continuation nil))
- "")
- ((string-match "_emacs_out \\(.*\\)\n" s)
- (setq python-preoutput-result (match-string 1 s))
- "")
- ((string-match ".*\n" s)
- s)
- ((or (eq t (compare-strings s nil nil "_emacs_ok\n" nil (length s)))
- (let ((end (min (length "_emacs_out ") (length s))))
- (eq t (compare-strings s nil end "_emacs_out " nil end))))
- (setq python-preoutput-leftover s)
- "")
- (t s)))
+ (let ((start 0)
+ (res ""))
+ ;; First process whole lines.
+ (while (string-match "\n" s start)
+ (let ((line (substring s start (setq start (match-end 0)))))
+ ;; Skip prompt if needed.
+ (when (and python-preoutput-skip-next-prompt
+ (string-match comint-prompt-regexp line))
+ (setq python-preoutput-skip-next-prompt nil)
+ (setq line (substring line (match-end 0))))
+ ;; Recognize special _emacs_out lines.
+ (if (and (string-match "\\`_emacs_out \\(.*\\)\n\\'" line)
+ (local-variable-p 'python-preoutput-result))
+ (progn
+ (setq python-preoutput-result (match-string 1 line))
+ (set (make-local-variable 'python-preoutput-skip-next-prompt) t))
+ (setq res (concat res line)))))
+ ;; Then process the remaining partial line.
+ (unless (zerop start) (setq s (substring s start)))
+ (cond ((and (string-match comint-prompt-regexp s)
+ ;; Drop this prompt if it follows an _emacs_out...
+ (or python-preoutput-skip-next-prompt
+ ;; ... or if it's not gonna be inserted at BOL.
+ ;; Maybe we could be more selective here.
+ (if (zerop (length res))
+ (not (bolp))
+ (string-match ".\\'" res))))
+ ;; The need for this seems to be system-dependent:
+ ;; What is this all about, exactly? --Stef
+ ;; (if (and (eq ?. (aref s 0)))
+ ;; (accept-process-output (get-buffer-process (current-buffer)) 1))
+ (setq python-preoutput-skip-next-prompt nil)
+ res)
+ ((let ((end (min (length "_emacs_out ") (length s))))
+ (eq t (compare-strings s nil end "_emacs_out " nil end)))
+ ;; The leftover string is a prefix of _emacs_out so we don't know
+ ;; yet whether it's an _emacs_out or something else: wait until we
+ ;; get more output so we can resolve this ambiguity.
+ (set (make-local-variable 'python-preoutput-leftover) s)
+ res)
+ (t (concat res s)))))
(autoload 'comint-check-proc "comint")
;; (not a name) in Python buffers from which `run-python' &c is
;; invoked. Would support multiple processes better.
(when (or new (not (comint-check-proc python-buffer)))
- (save-current-buffer
- (let* ((cmdlist (append (python-args-to-list cmd) '("-i")))
- (path (getenv "PYTHONPATH"))
- (process-environment ; to import emacs.py
- (cons (concat "PYTHONPATH=" data-directory
- (if path (concat ":" path)))
- process-environment)))
- (set-buffer (apply 'make-comint-in-buffer "Python"
- (generate-new-buffer "*Python*")
- (car cmdlist) nil (cdr cmdlist)))
- (setq-default python-buffer (current-buffer))
- (setq python-buffer (current-buffer)))
+ (with-current-buffer
+ (let* ((cmdlist (append (python-args-to-list cmd) '("-i")))
+ (path (getenv "PYTHONPATH"))
+ (process-environment ; to import emacs.py
+ (cons (concat "PYTHONPATH=" data-directory
+ (if path (concat ":" path)))
+ process-environment)))
+ (apply 'make-comint-in-buffer "Python"
+ (if new (generate-new-buffer "*Python*") "*Python*")
+ (car cmdlist) nil (cdr cmdlist)))
+ (setq-default python-buffer (current-buffer))
+ (setq python-buffer (current-buffer))
(accept-process-output (get-buffer-process python-buffer) 5)
- (inferior-python-mode)))
- (if (eq 'python-mode major-mode)
+ (inferior-python-mode)
+ ;; Load function definitions we need.
+ ;; Before the preoutput function was used, this was done via -c in
+ ;; cmdlist, but that loses the banner and doesn't run the startup
+ ;; file. The code might be inline here, but there's enough that it
+ ;; seems worth putting in a separate file, and it's probably cleaner
+ ;; to put it in a module.
+ ;; Ensure we're at a prompt before doing anything else.
+ (python-send-receive "import emacs; print '_emacs_out ()'")))
+ (if (derived-mode-p 'python-mode)
(setq python-buffer (default-value 'python-buffer))) ; buffer-local
- ;; Load function definitions we need.
- ;; Before the preoutput function was used, this was done via -c in
- ;; cmdlist, but that loses the banner and doesn't run the startup
- ;; file. The code might be inline here, but there's enough that it
- ;; seems worth putting in a separate file, and it's probably cleaner
- ;; to put it in a module.
- (python-send-string "import emacs")
- ;; Ensure we're at a prompt before doing anything else.
- (python-send-receive "print '_emacs_out ()'")
;; Without this, help output goes into the inferior python buffer if
;; the process isn't already running.
(sit-for 1 t) ;Should we use accept-process-output instead? --Stef
;; commands having set up such a state.
(defun python-send-command (command)
- "Like `python-send-string' but resets `compilation-shell-minor-mode'."
- (let ((end (marker-position (process-mark (python-proc)))))
- (with-current-buffer python-buffer (goto-char (point-max)))
+ "Like `python-send-string' but resets `compilation-shell-minor-mode'.
+COMMAND should be a single statement."
+ ;; (assert (not (string-match "\n" command)))
+ ;; (let ((end (marker-position (process-mark (python-proc)))))
+ (with-current-buffer (process-buffer (python-proc))
+ (goto-char (point-max))
(compilation-forget-errors)
(python-send-string command)
+ (setq compilation-last-buffer (current-buffer)))
+ ;; No idea what this is for but it breaks the call to
+ ;; compilation-fake-loc in python-send-region. -- Stef
;; Must wait until this has completed before re-setting variables below.
- (python-send-receive "print '_emacs_out ()'")
- (with-current-buffer python-buffer
- (set-marker compilation-parsing-end end)
- (setq compilation-last-buffer (current-buffer)))))
+ ;; (python-send-receive "print '_emacs_out ()'")
+ ;; (with-current-buffer python-buffer
+ ;; (set-marker compilation-parsing-end end))
+ ) ;;)
(defun python-send-region (start end)
"Send the region to the inferior Python process."
"Evaluate STRING in inferior Python process."
(interactive "sPython command: ")
(comint-send-string (python-proc) string)
- (comint-send-string (python-proc) "\n\n"))
+ (unless (string-match "\n\\'" string)
+ ;; Make sure the text is properly LF-terminated.
+ (comint-send-string (python-proc) "\n"))
+ (when (string-match "\n[ \t].*\n?\\'" string)
+ ;; If the string contains a final indented line, add a second newline so
+ ;; as to make sure we terminate the multiline instruction.
+ (comint-send-string (python-proc) "\n")))
(defun python-send-buffer ()
"Send the current buffer to the inferior Python process."
(python-switch-to-python t))
(defcustom python-source-modes '(python-mode jython-mode)
- "*Used to determine if a buffer contains Python source code.
+ "Used to determine if a buffer contains Python source code.
If a file is loaded into a buffer that is in one of these major modes,
it is considered Python source by `python-load-file', which uses the
value to determine defaults."
;; isn't one for `python-buffer'.
(unless (comint-check-proc python-buffer)
(run-python nil t))
- (get-buffer-process (or (if (eq major-mode 'inferior-python-mode)
- (current-buffer)
- python-buffer))))
+ (get-buffer-process (if (derived-mode-p 'inferior-python-mode)
+ (current-buffer)
+ python-buffer)))
(defun python-set-proc ()
"Set the default value of `python-buffer' to correspond to this buffer.
(defun python-send-receive (string)
"Send STRING to inferior Python (if any) and return result.
-The result is what follows `_emacs_out' in the output (or nil)."
+The result is what follows `_emacs_out' in the output."
+ (python-send-string string)
(let ((proc (python-proc)))
- (python-send-string string)
- (setq python-preoutput-result nil)
- (while (progn
- (accept-process-output proc 5)
- python-preoutput-leftover))
- python-preoutput-result))
+ (with-current-buffer (process-buffer proc)
+ (set (make-local-variable 'python-preoutput-result) nil)
+ (while (progn
+ (accept-process-output proc 5)
+ (null python-preoutput-result)))
+ (prog1 python-preoutput-result
+ (kill-local-variable 'python-preoutput-result)))))
;; Fixme: Is there anything reasonable we can do with random methods?
;; (Currently only works with functions.)
instance. Assumes an inferior Python is running."
(let ((symbol (with-syntax-table python-dotty-syntax-table
(current-word))))
- ;; First try the symbol we're on.
- (or (and symbol
- (python-send-receive (format "emacs.eargs(%S, %s)"
- symbol python-imports)))
- ;; Try moving to symbol before enclosing parens.
- (let ((s (syntax-ppss)))
- (unless (zerop (car s))
- (when (eq ?\( (char-after (nth 1 s)))
- (save-excursion
- (goto-char (nth 1 s))
- (skip-syntax-backward "-")
- (let ((point (point)))
- (skip-chars-backward "a-zA-Z._")
- (if (< (point) point)
- (python-send-receive
- (format "emacs.eargs(%S, %s)"
- (buffer-substring-no-properties (point) point)
- python-imports)))))))))))
+ ;; This is run from timers, so inhibit-quit tends to be set.
+ (with-local-quit
+ ;; First try the symbol we're on.
+ (or (and symbol
+ (python-send-receive (format "emacs.eargs(%S, %s)"
+ symbol python-imports)))
+ ;; Try moving to symbol before enclosing parens.
+ (let ((s (syntax-ppss)))
+ (unless (zerop (car s))
+ (when (eq ?\( (char-after (nth 1 s)))
+ (save-excursion
+ (goto-char (nth 1 s))
+ (skip-syntax-backward "-")
+ (let ((point (point)))
+ (skip-chars-backward "a-zA-Z._")
+ (if (< (point) point)
+ (python-send-receive
+ (format "emacs.eargs(%S, %s)"
+ (buffer-substring-no-properties (point) point)
+ python-imports))))))))))))
\f
;;;; Info-look functionality.
(orig (point))
(start (nth 8 syntax))
end)
- (cond ((eq t (nth 3 syntax)) ; in fenced string
- (goto-char (nth 8 syntax)) ; string start
- (condition-case () ; for unbalanced quotes
- (progn (forward-sexp)
- (setq end (point)))
- (error (setq end (point-max)))))
+ (cond ((eq t (nth 3 syntax)) ; in fenced string
+ (goto-char (nth 8 syntax)) ; string start
+ (setq end (condition-case () ; for unbalanced quotes
+ (progn (forward-sexp) (point))
+ (error (point-max)))))
((re-search-backward "\\s|\\s-*\\=" nil t) ; end of fenced
; string
(forward-char)
(condition-case ()
(progn (backward-sexp)
(setq start (point)))
- (error nil))))
+ (error (setq end nil)))))
(when end
(save-restriction
(narrow-to-region start end)
(goto-char orig)
- (fill-paragraph justify))))))
- t)
+ (let ((paragraph-separate
+ ;; Make sure that fenced-string delimiters that stand
+ ;; on their own line stay there.
+ (concat "[ \t]*['\"]+[ \t]*$\\|" paragraph-separate)))
+ (fill-paragraph justify))))))
+ t))
(defun python-shift-left (start end &optional count)
"Shift lines in region COUNT (the prefix arg) columns to the left.
(defun python-try-complete (old)
"Completion function for Python for use with `hippie-expand'."
- (when (eq major-mode 'python-mode) ; though we only add it locally
+ (when (derived-mode-p 'python-mode) ; though we only add it locally
(unless old
(let ((symbol (python-partial-symbol)))
(he-init-string (- (point) (length symbol)) (point))
\f
;;;; Skeletons
+(defcustom python-use-skeletons nil
+ "Non-nil means template skeletons will be automagically inserted.
+This happens when pressing \"if<SPACE>\", for example, to prompt for
+the if condition."
+ :type 'boolean
+ :group 'python)
+
(defvar python-skeletons nil
"Alist of named skeletons for Python mode.
Elements are of the form (NAME . EXPANDER-FUNCTION).")
(function (intern (concat "python-insert-" name))))
`(progn
(add-to-list 'python-skeletons ',(cons name function))
- (define-abbrev python-mode-abbrev-table ,name "" ',function nil t)
+ (if python-use-skeletons
+ (define-abbrev python-mode-abbrev-table ,name "" ',function nil t))
(define-skeleton ,function
,(format "Insert Python \"%s\" template." name)
,@elements)))))
> _ \n)
(defvar python-default-template "if"
- "Default template to expand by `python-insert-template'.
+ "Default template to expand by `python-expand-template'.
Updated on each expansion.")
(defun python-expand-template (name)
(unless (fboundp 'brm-rename)
(pymacs-load "bikeemacs" "brm-") ; first line of normal recipe
(let ((py-mode-map (make-sparse-keymap)) ; it assumes this
- (features (cons 'python-mode features)) ; and requires this
- menu)
- (brm-init) ; second line of normal recipe
- (remove-hook 'python-mode-hook ; undo this from `brm-init'
- '(lambda () (easy-menu-add brm-menu)))
- (easy-menu-define
- python-brm-menu python-mode-map
- "Bicycle Repair Man"
- '("BicycleRepairMan"
- :help "Interface to navigation and refactoring tool"
- "Queries"
- ["Find References" brm-find-references
- :help "Find references to name at point in compilation buffer"]
- ["Find Definition" brm-find-definition
- :help "Find definition of name at point"]
- "-"
- "Refactoring"
- ["Rename" brm-rename
- :help "Replace name at point with a new name everywhere"]
- ["Extract Method" brm-extract-method
- :active (and mark-active (not buffer-read-only))
- :help "Replace statements in region with a method"]
- ["Extract Local Variable" brm-extract-local-variable
- :active (and mark-active (not buffer-read-only))
- :help "Replace expression in region with an assignment"]
- ["Inline Local Variable" brm-inline-local-variable
- :help
- "Substitute uses of variable at point with its definition"]
- ;; Fixme: Should check for anything to revert.
- ["Undo Last Refactoring" brm-undo :help ""]))))
+ (features (cons 'python-mode features))) ; and requires this
+ (brm-init)) ; second line of normal recipe
+ (remove-hook 'python-mode-hook ; undo this from `brm-init'
+ '(lambda () (easy-menu-add brm-menu)))
+ (easy-menu-define
+ python-brm-menu python-mode-map
+ "Bicycle Repair Man"
+ '("BicycleRepairMan"
+ :help "Interface to navigation and refactoring tool"
+ "Queries"
+ ["Find References" brm-find-references
+ :help "Find references to name at point in compilation buffer"]
+ ["Find Definition" brm-find-definition
+ :help "Find definition of name at point"]
+ "-"
+ "Refactoring"
+ ["Rename" brm-rename
+ :help "Replace name at point with a new name everywhere"]
+ ["Extract Method" brm-extract-method
+ :active (and mark-active (not buffer-read-only))
+ :help "Replace statements in region with a method"]
+ ["Extract Local Variable" brm-extract-local-variable
+ :active (and mark-active (not buffer-read-only))
+ :help "Replace expression in region with an assignment"]
+ ["Inline Local Variable" brm-inline-local-variable
+ :help
+ "Substitute uses of variable at point with its definition"]
+ ;; Fixme: Should check for anything to revert.
+ ["Undo Last Refactoring" brm-undo :help ""])))
(error (error "Bicyclerepairman setup failed: %s" data))))
\f
;;;; Modes.
(add-hook 'post-command-hook 'python-abbrev-pc-hook nil t))
(modify-syntax-entry ?/ "w" python-abbrev-syntax-table)
+(defvar python-mode-running) ;Dynamically scoped var.
+
;;;###autoload
(define-derived-mode python-mode fundamental-mode "Python"
"Major mode for editing Python files.
;; . python-font-lock-syntactic-face-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 'indent-line-function) #'python-indent-line)
(set (make-local-variable 'indent-region-function) #'python-indent-region)
(if (featurep 'hippie-exp)
(set (make-local-variable 'hippie-expand-try-functions-list)
(cons 'python-try-complete hippie-expand-try-functions-list)))
+ ;; Python defines TABs as being 8-char wide.
+ (set (make-local-variable 'tab-width) 8)
(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)
+ (setq indent-tabs-mode nil))
(set (make-local-variable 'python-command) python-python-command)
(python-find-imports)
(unless (boundp 'python-mode-running) ; kill the recursion from jython-mode
(custom-add-option 'python-mode-hook 'imenu-add-menubar-index)
(custom-add-option 'python-mode-hook
- '(lambda ()
- "Turn off Indent Tabs mode."
- (set (make-local-variable 'indent-tabs-mode) nil)))
+ (lambda ()
+ "Turn off Indent Tabs mode."
+ (set (make-local-variable 'indent-tabs-mode) nil)))
(custom-add-option 'python-mode-hook 'turn-on-eldoc-mode)
(custom-add-option 'python-mode-hook 'abbrev-mode)
(custom-add-option 'python-mode-hook 'python-setup-brm)