;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
"import" "in" "is" "lambda" "not" "or" "pass" "print"
"raise" "return" "try" "while" "yield"
;; Future keywords
- "as" "None"
+ "as" "None" "with"
;; Not real keywords, but close enough to be fontified as such
"self" "True" "False")
symbol-end)
(= (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.
(error nil))))))))
(defun python-comment-line-p ()
- "Return non-nil iff current line has only a comment."
+ "Return non-nil if current line has only a comment."
(save-excursion
(end-of-line)
(when (eq 'comment (syntax-ppss-context (syntax-ppss)))
(looking-at (rx (or (syntax comment-start) line-end))))))
(defun python-blank-line-p ()
- "Return non-nil iff current line is blank."
+ "Return non-nil if current line is blank."
(save-excursion
(beginning-of-line)
(looking-at "\\s-*$")))
(save-excursion
(unless bos (python-beginning-of-statement))
(looking-at (rx (and (or "if" "else" "elif" "while" "for" "def"
- "class" "try" "except" "finally")
+ "class" "try" "except" "finally" "with")
symbol-end)))))
(defun python-close-block-statement-p (&optional bos)
(let ((initial (current-indentation)))
(if (zerop (python-next-statement))
(setq indent (- (current-indentation) initial)))
- (if (and (>= indent 2) (<= indent 8)) ; sanity check
+ (if (and indent (>= indent 2) (<= indent 8)) ; sanity check
(setq done t))))))
(when done
(when (/= indent (default-value 'python-indent))
"Skip out of any nested brackets.
Skip forward if FORWARD is non-nil, else backward.
If SYNTAX is non-nil it is the state returned by `syntax-ppss' at point.
-Return non-nil iff skipping was done."
+Return non-nil if skipping was done."
(let ((depth (syntax-ppss-depth (or syntax (syntax-ppss))))
(forward (if forward -1 1)))
(unless (zerop depth)
nil)
((eq 'string (syntax-ppss-context s))
;; Go to start of string and skip it.
- (goto-char (nth 8 s))
- (condition-case () ; beware invalid syntax
- (progn (forward-sexp) t)
- (error (end-of-line))))
+ (let ((pos (point)))
+ (goto-char (nth 8 s))
+ (condition-case () ; beware invalid syntax
+ (progn (forward-sexp) t)
+ ;; If there's a mismatched string, make sure
+ ;; we still overall move *forward*.
+ (error (goto-char pos) (end-of-line)))))
((python-skip-out t s))))
(end-of-line))
(unless comment
(if (and (zerop ci) (not open))
(not (goto-char point))
(catch 'done
- (while (zerop (python-next-statement))
+ (while (zerop (python-next-statement))
(when (or (and open (<= (current-indentation) ci))
(< (current-indentation) ci))
(python-skip-comments/blanks t)
(throw 'done t)))))))
(setq arg (1- arg)))
(zerop arg)))
-\f
+
+(defvar python-which-func-length-limit 40
+ "Non-strict length limit for `python-which-func' output.")
+
+(defun python-which-func ()
+ (let ((function-name (python-current-defun python-which-func-length-limit)))
+ (set-text-properties 0 (length function-name) nil function-name)
+ function-name))
+
+
;;;; Imenu.
(defvar python-recursing)
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-l" 'python-load-file)
(define-key map "\C-c\C-v" 'python-check)
;; Note that we _can_ still use these commands which send to the
- ;; Python process even at the prompt iff we have a normal prompt,
+ ;; Python process even at the prompt provided we have a normal prompt,
;; i.e. '>>> ' and not '... '. See the comment before
;; python-send-region. Fixme: uncomment these if we address that.
(path (getenv "PYTHONPATH"))
(process-environment ; to import emacs.py
(cons (concat "PYTHONPATH=" data-directory
- (if path (concat ":" path)))
+ (if path (concat path-separator path)))
process-environment)))
(apply 'make-comint-in-buffer "Python"
(if new (generate-new-buffer "*Python*") "*Python*")
COMMAND should be a single statement."
;; (assert (not (string-match "\n" command)))
;; (let ((end (marker-position (process-mark (python-proc)))))
- (with-current-buffer python-buffer (goto-char (point-max)))
+ (with-current-buffer (process-buffer (python-proc))
+ (goto-char (point-max))
(compilation-forget-errors)
(python-send-string command)
- (with-current-buffer python-buffer
- (setq compilation-last-buffer (current-buffer)))
+ (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.
;; isn't one for `python-buffer'.
(unless (comint-check-proc python-buffer)
(run-python nil t))
- (get-buffer-process (or (if (derived-mode-p '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.
(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.
(1+ (/ (current-indentation) python-indent)))
;; Fixme: Consider top-level assignments, imports, &c.
-(defun python-current-defun ()
+(defun python-current-defun (&optional length-limit)
"`add-log-current-defun-function' for Python."
(save-excursion
;; Move up the tree of nested `class' and `def' blocks until we
;; get to zero indentation, accumulating the defined names.
- (let ((start t)
- accum)
- (while (or start (> (current-indentation) 0))
- (setq start nil)
- (python-beginning-of-block)
- (end-of-line)
- (beginning-of-defun)
- (if (looking-at (rx (0+ space) (or "def" "class") (1+ space)
- (group (1+ (or word (syntax symbol))))))
- (push (match-string 1) accum)))
- (if accum (mapconcat 'identity accum ".")))))
+ (let ((accum)
+ (length -1))
+ (catch 'done
+ (while (or (null length-limit)
+ (null (cdr accum))
+ (< length length-limit))
+ (setq start nil)
+ (let ((started-from (point)))
+ (python-beginning-of-block)
+ (end-of-line)
+ (beginning-of-defun)
+ (when (= (point) started-from)
+ (throw 'done nil)))
+ (when (looking-at (rx (0+ space) (or "def" "class") (1+ space)
+ (group (1+ (or word (syntax symbol))))))
+ (push (match-string 1) accum)
+ (setq length (+ length 1 (length (car accum)))))
+ (when (= (current-indentation) 0)
+ (throw 'done nil))))
+ (when accum
+ (when (and length-limit (> length length-limit))
+ (setcar accum ".."))
+ (mapconcat 'identity accum ".")))))
(defun python-mark-block ()
"Mark the block around point.
(interactive)
(let ((window (get-buffer-window "*Completions*")))
(if (and (eq last-command this-command)
- window (window-live-p window) (window-buffer window)
+ (window-live-p window) (window-buffer window)
(buffer-name (window-buffer window)))
(with-current-buffer (window-buffer window)
(if (pos-visible-in-window-p (point-max) window)
> _ \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)
;; . 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)
#'python-current-defun)
(set (make-local-variable 'outline-regexp)
(rx (* space) (or "class" "def" "elif" "else" "except" "finally"
- "for" "if" "try" "while")
+ "for" "if" "try" "while" "with")
symbol-end))
(set (make-local-variable 'outline-heading-end-regexp) ":\\s-*\n")
(set (make-local-variable 'outline-level) #'python-outline-level)
(set (make-local-variable 'beginning-of-defun-function)
'python-beginning-of-defun)
(set (make-local-variable 'end-of-defun-function) 'python-end-of-defun)
+ (add-hook 'which-func-functions 'python-which-func nil t)
(setq imenu-create-index-function #'python-imenu-create-index)
(set (make-local-variable 'eldoc-documentation-function)
#'python-eldoc-function)