;; `python-nav-beginning-of-statement', `python-nav-end-of-statement',
;; `python-nav-beginning-of-block' and `python-nav-end-of-block' are
;; included but no bound to any key. At last but not least the
-;; specialized `python-nav-forward-sexp-function' allows easy
+;; specialized `python-nav-forward-sexp' allows easy
;; navigation between code blocks.
;; Shell interaction: is provided and allows you to execute easily any
\f
;;; Font-lock and syntax
+
+(defun python-syntax-context (type &optional syntax-ppss)
+ "Return non-nil if point is on TYPE using SYNTAX-PPSS.
+TYPE can be `comment', `string' or `paren'. It returns the start
+character address of the specified TYPE."
+ (let ((ppss (or syntax-ppss (syntax-ppss))))
+ (case type
+ (comment (and (nth 4 ppss) (nth 8 ppss)))
+ (string (and (not (nth 4 ppss)) (nth 8 ppss)))
+ (paren (nth 1 ppss))
+ (t nil))))
+
+(defun python-syntax-context-type (&optional syntax-ppss)
+ "Return the context type using SYNTAX-PPSS.
+The type returned can be `comment', `string' or `paren'."
+ (let ((ppss (or syntax-ppss (syntax-ppss))))
+ (cond
+ ((nth 8 ppss) (if (nth 4 ppss) 'comment 'string))
+ ((nth 1 ppss) 'paren))))
+
+(defsubst python-syntax-comment-or-string-p ()
+ "Return non-nil if point is inside 'comment or 'string."
+ (nth 8 (syntax-ppss)))
+
+(define-obsolete-function-alias
+ 'python-info-ppss-context #'python-syntax-context "24.3")
+
+(define-obsolete-function-alias
+ 'python-info-ppss-context-type #'python-syntax-context-type "24.3")
+
+(define-obsolete-function-alias
+ 'python-info-ppss-comment-or-string-p
+ #'python-syntax-comment-or-string-p "24.3")
+
(defvar python-font-lock-keywords
;; Keywords
`(,(rx symbol-start
(? ?\[ (+ (not (any ?\]))) ?\]) (* space)
assignment-operator)))
(when (re-search-forward re limit t)
- (while (and (python-info-ppss-context 'paren)
+ (while (and (python-syntax-context 'paren)
(re-search-forward re limit t)))
- (if (and (not (python-info-ppss-context 'paren))
+ (if (and (not (python-syntax-context 'paren))
(not (equal (char-after (point-marker)) ?=)))
t
(set-match-data nil)))))
assignment-operator)))
(when (and (re-search-forward re limit t)
(goto-char (nth 3 (match-data))))
- (while (and (python-info-ppss-context 'paren)
+ (while (and (python-syntax-context 'paren)
(re-search-forward re limit t))
(goto-char (nth 3 (match-data))))
- (if (not (python-info-ppss-context 'paren))
+ (if (not (python-syntax-context 'paren))
t
(set-match-data nil)))))
(1 font-lock-variable-name-face nil nil))))
(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.
(syntax-propertize-rules
- (;; ¡Backrefs don't work in syntax-propertize-rules!
- (concat "\\(?:\\([RUru]\\)[Rr]?\\|^\\|[^\\]\\(?:\\\\.\\)*\\)" ;Prefix.
- "\\(?:\\('\\)'\\('\\)\\|\\(?2:\"\\)\"\\(?3:\"\\)\\)")
- (3 (ignore (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
- ;; whether this is an opening or closing triple or whether it's
- ;; quoted anyhow, and should be ignored. (For that we need to do
- ;; the same job as `syntax-ppss' to be correct and it seems to be OK
- ;; to use it here despite initial worries.) We also have to sort
- ;; out a possible prefix -- well, we don't _have_ to, but I think it
- ;; should be treated as part of the string.
-
- ;; Test cases:
- ;; ur"""ar""" x='"' # """
- ;; x = ''' """ ' a
- ;; '''
- ;; x '"""' x """ \"""" x
- (save-excursion
- (goto-char (match-beginning 0))
- (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 "|"))))
- )))
+ ((rx
+ (and
+ ;; Match even number of backslashes.
+ (or (not (any ?\\ ?\' ?\")) point
+ ;; Quotes might be preceded by a escaped quote.
+ (and (or (not (any ?\\)) point) ?\\
+ (* ?\\ ?\\) (any ?\' ?\")))
+ (* ?\\ ?\\)
+ ;; Match single or triple quotes of any kind.
+ (group (or "\"" "\"\"\"" "'" "'''"))))
+ (0 (ignore (python-syntax-stringify))))))
+
+(defsubst python-syntax-count-quotes (quote-char &optional point limit)
+ "Count number of quotes around point (max is 3).
+QUOTE-CHAR is the quote char to count. Optional argument POINT is
+the point where scan starts (defaults to current point) and LIMIT
+is used to limit the scan."
+ (let ((i 0))
+ (while (and (< i 3)
+ (or (not limit) (< (+ point i) limit))
+ (eq (char-after (+ point i)) quote-char))
+ (incf i))
+ i))
+
+(defun python-syntax-stringify ()
+ "Put `syntax-table' property correctly on single/triple quotes."
+ (let* ((num-quotes (length (match-string-no-properties 1)))
+ (ppss (prog2
+ (backward-char num-quotes)
+ (syntax-ppss)
+ (forward-char num-quotes)))
+ (string-start (and (not (nth 4 ppss)) (nth 8 ppss)))
+ (quote-starting-pos (- (point) num-quotes))
+ (quote-ending-pos (point))
+ (num-closing-quotes
+ (and string-start
+ (python-syntax-count-quotes
+ (char-before) string-start quote-starting-pos))))
+ (cond ((and string-start (= num-closing-quotes 0))
+ ;; This set of quotes doesn't match the string starting
+ ;; kind. Do nothing.
+ nil)
+ ((not string-start)
+ ;; This set of quotes delimit the start of a string.
+ (put-text-property quote-starting-pos (1+ quote-starting-pos)
+ 'syntax-table (string-to-syntax "|")))
+ ((= num-quotes num-closing-quotes)
+ ;; This set of quotes delimit the end of a string.
+ (put-text-property (1- quote-ending-pos) quote-ending-pos
+ 'syntax-table (string-to-syntax "|")))
+ ((> num-quotes num-closing-quotes)
+ ;; This may only happen whenever a triple quote is closing
+ ;; a single quoted string. Add string delimiter syntax to
+ ;; all three quotes.
+ (put-text-property quote-starting-pos quote-ending-pos
+ 'syntax-table (string-to-syntax "|"))))))
(defvar python-mode-syntax-table
(let ((table (make-syntax-table)))
:safe 'booleanp)
(define-obsolete-variable-alias
- 'python-indent 'python-indent-offset "24.2")
+ 'python-indent 'python-indent-offset "24.3")
(define-obsolete-variable-alias
- 'python-guess-indent 'python-indent-guess-indent-offset "24.2")
+ 'python-guess-indent 'python-indent-guess-indent-offset "24.3")
(defvar python-indent-current-level 0
"Current indentation level `python-indent-line-function' is using.")
(re-search-forward
(python-rx line-start block-start) nil t))
(when (and
- (not (python-info-ppss-context-type))
+ (not (python-syntax-context-type))
(progn
(goto-char (line-end-position))
(python-util-forward-comment -1)
(bobp))
'no-indent)
;; Inside a paren
- ((setq start (python-info-ppss-context 'paren ppss))
+ ((setq start (python-syntax-context 'paren ppss))
'inside-paren)
;; Inside string
- ((setq start (python-info-ppss-context 'string ppss))
+ ((setq start (python-syntax-context 'string ppss))
'inside-string)
;; After backslash
- ((setq start (when (not (or (python-info-ppss-context 'string ppss)
- (python-info-ppss-context 'comment ppss)))
+ ((setq start (when (not (or (python-syntax-context 'string ppss)
+ (python-syntax-context 'comment ppss)))
(let ((line-beg-pos (line-beginning-position)))
(when (python-info-line-ends-backslash-p
(1- line-beg-pos))
(while (and (re-search-backward
(python-rx block-start) nil t)
(or
- (python-info-ppss-context-type)
+ (python-syntax-context-type)
(python-info-continuation-line-p))))
(when (looking-at (python-rx block-start))
(point-marker)))))
(while (prog2
(forward-line -1)
(and (not (bobp))
- (python-info-ppss-context 'paren))))
+ (python-syntax-context 'paren))))
(goto-char (line-end-position))
(while (and (re-search-backward
"\\." (line-beginning-position) t)
- (python-info-ppss-context-type)))
+ (python-syntax-context-type)))
(if (and (looking-at "\\.")
- (not (python-info-ppss-context-type)))
+ (not (python-syntax-context-type)))
;; The indentation is the same column of the
;; first matching dot that's not inside a
;; comment, a string or a paren
(when (and (looking-at (regexp-opt '(")" "]" "}")))
(progn
(forward-char 1)
- (not (python-info-ppss-context 'paren))))
+ (not (python-syntax-context 'paren))))
(goto-char context-start)
(current-indentation))))
;; If open paren is contained on a line by itself add another
`python-indent-levels'. Afterwards it sets the variable
`python-indent-current-level' correctly so offset is equal
to (`nth' `python-indent-current-level' `python-indent-levels')"
- (if (or (and (eq this-command 'indent-for-tab-command)
- (eq last-command this-command))
- force-toggle)
- (if (not (equal python-indent-levels '(0)))
- (python-indent-toggle-levels)
- (python-indent-calculate-levels))
- (python-indent-calculate-levels))
- (beginning-of-line)
- (delete-horizontal-space)
- (indent-to (nth python-indent-current-level python-indent-levels))
+ (or
+ (and (or (and (eq this-command 'indent-for-tab-command)
+ (eq last-command this-command))
+ force-toggle)
+ (not (equal python-indent-levels '(0)))
+ (or (python-indent-toggle-levels) t))
+ (python-indent-calculate-levels))
+ (let* ((starting-pos (point-marker))
+ (indent-ending-position
+ (+ (line-beginning-position) (current-indentation)))
+ (follow-indentation-p
+ (or (bolp)
+ (and (<= (line-beginning-position) starting-pos)
+ (>= indent-ending-position starting-pos))))
+ (next-indent (nth python-indent-current-level python-indent-levels)))
+ (unless (= next-indent (current-indentation))
+ (beginning-of-line)
+ (delete-horizontal-space)
+ (indent-to next-indent)
+ (goto-char starting-pos))
+ (and follow-indentation-p (back-to-indentation)))
(python-info-closing-block-message))
(defun python-indent-line-function ()
(defun python-indent-dedent-line ()
"De-indent current line."
(interactive "*")
- (when (and (not (python-info-ppss-comment-or-string-p))
+ (when (and (not (python-syntax-comment-or-string-p))
(<= (point-marker) (save-excursion
(back-to-indentation)
(point-marker)))
(when (and (not arg)
(eolp)
(not (equal ?: (char-after (- (point-marker) 2))))
- (not (python-info-ppss-comment-or-string-p)))
+ (not (python-syntax-comment-or-string-p)))
(let ((indentation (current-indentation))
(calculated-indentation (python-indent-calculate-indentation)))
(python-info-closing-block-message)
(goto-char (line-beginning-position))
;; If after going to the beginning of line the point
;; is still inside a paren it's ok to do the trick
- (when (python-info-ppss-context 'paren)
+ (when (python-syntax-context 'paren)
(let ((indentation (python-indent-calculate-indentation)))
(when (< (current-indentation) indentation)
(indent-line-to indentation)))))))
(end-of-line 1))
(while (and (funcall re-search-fn
python-nav-beginning-of-defun-regexp nil t)
- (python-info-ppss-context-type)))
+ (python-syntax-context-type)))
(and (python-info-looking-at-beginning-of-defun)
(or (not (= (line-number-at-pos pos)
(line-number-at-pos)))
(equal (char-after (+ (point) (current-indentation))) ?#)
(<= (current-indentation) beg-defun-indent)
(looking-at (python-rx decorator))
- (python-info-ppss-context-type))))
+ (python-syntax-context-type))))
(forward-line 1)
;; If point falls inside a paren or string context the point is
;; forwarded at the end of it (or end of buffer if its not closed)
- (let ((context-type (python-info-ppss-context-type)))
+ (let ((context-type (python-syntax-context-type)))
(when (memq context-type '(paren string))
;; Slow but safe.
(while (and (not (eobp))
- (python-info-ppss-context-type))
+ (python-syntax-context-type))
(forward-line 1)))))))
(defun python-nav-beginning-of-statement ()
(save-excursion
(forward-line -1)
(python-info-line-ends-backslash-p))
- (python-info-ppss-context 'string)
- (python-info-ppss-context 'paren))
+ (python-syntax-context 'string)
+ (python-syntax-context 'paren))
(forward-line -1)))))
(defun python-nav-end-of-statement ()
(not (eobp))
(when (or
(python-info-line-ends-backslash-p)
- (python-info-ppss-context 'string)
- (python-info-ppss-context 'paren))
+ (python-syntax-context 'string)
+ (python-syntax-context 'paren))
(forward-line 1)))))
(defun python-nav-backward-statement (&optional arg)
(python-nav-end-of-statement)
(while (and
(re-search-forward block-start-regexp nil t)
- (python-info-ppss-context-type)))
+ (python-syntax-context-type)))
(setq arg (1- arg)))
(while (< arg 0)
(python-nav-beginning-of-statement)
(while (and
(re-search-backward block-start-regexp nil t)
- (python-info-ppss-context-type)))
+ (python-syntax-context-type)))
(setq arg (1+ arg)))
(python-nav-beginning-of-statement)
(if (not (looking-at (python-rx block-start)))
(and (goto-char starting-pos) nil)
(and (not (= (point) starting-pos)) (point-marker)))))
-(defun python-nav-forward-sexp-function (&optional arg)
+(defun python-nav-lisp-forward-sexp-safe (&optional arg)
+ "Safe version of standard `forward-sexp'.
+When ARG > 0 move forward, else if ARG is < 0."
+ (or arg (setq arg 1))
+ (let ((forward-sexp-function nil)
+ (paren-regexp
+ (if (> arg 0) (python-rx close-paren) (python-rx open-paren)))
+ (search-fn
+ (if (> arg 0) #'re-search-forward #'re-search-backward)))
+ (condition-case nil
+ (forward-sexp arg)
+ (error
+ (while (and (funcall search-fn paren-regexp nil t)
+ (python-syntax-context 'paren)))))))
+
+(defun python-nav--forward-sexp ()
+ "Move to forward sexp."
+ (case (python-syntax-context-type)
+ (string
+ ;; Inside of a string, get out of it.
+ (while (and (re-search-forward "[\"']" nil t)
+ (python-syntax-context 'string))))
+ (comment
+ ;; Inside of a comment, just move forward.
+ (python-util-forward-comment))
+ (paren
+ (python-nav-lisp-forward-sexp-safe 1))
+ (t
+ (if (and (not (eobp))
+ (= (syntax-class (syntax-after (point))) 4))
+ ;; Looking an open-paren
+ (python-nav-lisp-forward-sexp-safe 1)
+ (let ((block-starting-pos
+ (save-excursion (python-nav-beginning-of-block)))
+ (block-ending-pos
+ (save-excursion (python-nav-end-of-block)))
+ (next-block-starting-pos
+ (save-excursion (python-nav-forward-block))))
+ (cond
+ ((not block-starting-pos)
+ ;; Not inside a block, move to closest one.
+ (and next-block-starting-pos
+ (goto-char next-block-starting-pos)))
+ ((= (point) block-starting-pos)
+ ;; Point is at beginning of block
+ (if (and next-block-starting-pos
+ (< next-block-starting-pos block-ending-pos))
+ ;; Beginning of next block is closer than current's
+ ;; end, move to it.
+ (goto-char next-block-starting-pos)
+ (goto-char block-ending-pos)))
+ ((= block-ending-pos (point))
+ ;; Point is at end of current block
+ (let ((parent-block-end-pos
+ (save-excursion
+ (python-util-forward-comment)
+ (python-nav-beginning-of-block)
+ (python-nav-end-of-block))))
+ (if (and parent-block-end-pos
+ (or (not next-block-starting-pos)
+ (> next-block-starting-pos parent-block-end-pos)))
+ ;; If the parent block ends before next block
+ ;; starts move to it.
+ (goto-char parent-block-end-pos)
+ (and next-block-starting-pos
+ (goto-char next-block-starting-pos)))))
+ (t (python-nav-end-of-block))))))))
+
+(defun python-nav--backward-sexp ()
+ "Move to backward sexp."
+ (case (python-syntax-context-type)
+ (string
+ ;; Inside of a string, get out of it.
+ (while (and (re-search-backward "[\"']" nil t)
+ (python-syntax-context 'string))))
+ (comment
+ ;; Inside of a comment, just move backward.
+ (python-util-forward-comment -1))
+ (paren
+ ;; Handle parens like we are lisp.
+ (python-nav-lisp-forward-sexp-safe -1))
+ (t
+ (let* ((block-starting-pos
+ (save-excursion (python-nav-beginning-of-block)))
+ (block-ending-pos
+ (save-excursion (python-nav-end-of-block)))
+ (prev-block-ending-pos
+ (save-excursion (when (python-nav-backward-block)
+ (python-nav-end-of-block))))
+ (prev-block-parent-ending-pos
+ (save-excursion
+ (when prev-block-ending-pos
+ (goto-char prev-block-ending-pos)
+ (python-util-forward-comment)
+ (python-nav-beginning-of-block)
+ (python-nav-end-of-block)))))
+ (if (and (not (bobp))
+ (= (syntax-class (syntax-after (1- (point)))) 5))
+ ;; Char before point is a paren closing char, handle it
+ ;; like we are lisp.
+ (python-nav-lisp-forward-sexp-safe -1)
+ (cond
+ ((not block-ending-pos)
+ ;; Not in and ending pos, move to end of previous block.
+ (and (python-nav-backward-block)
+ (python-nav-end-of-block)))
+ ((= (point) block-ending-pos)
+ ;; In ending pos, we need to search backwards for the
+ ;; closest point looking the list of candidates from here.
+ (let ((candidates))
+ (dolist (name
+ '(prev-block-parent-ending-pos
+ prev-block-ending-pos
+ block-ending-pos
+ block-starting-pos))
+ (when (and (symbol-value name)
+ (< (symbol-value name) (point)))
+ (add-to-list 'candidates (symbol-value name))))
+ (goto-char (apply 'max candidates))))
+ ((> (point) block-ending-pos)
+ ;; After an ending position, move to it.
+ (goto-char block-ending-pos))
+ ((= (point) block-starting-pos)
+ ;; On a block starting position.
+ (if (not (> (point) (or prev-block-ending-pos (point))))
+ ;; Point is after the end position of the block that
+ ;; wraps the current one, just move a block backward.
+ (python-nav-backward-block)
+ ;; If we got here we are facing a case like this one:
+ ;;
+ ;; try:
+ ;; return here()
+ ;; except Exception as e:
+ ;;
+ ;; Where point is on the "except" and must move to the
+ ;; end of "here()".
+ (goto-char prev-block-ending-pos)
+ (let ((parent-block-ending-pos
+ (save-excursion
+ (python-nav-forward-sexp)
+ (and (not (looking-at (python-rx block-start)))
+ (point)))))
+ (when (and parent-block-ending-pos
+ (> parent-block-ending-pos prev-block-ending-pos))
+ ;; If we got here we are facing a case like this one:
+ ;;
+ ;; except ImportError:
+ ;; if predicate():
+ ;; processing()
+ ;; here()
+ ;; except AttributeError:
+ ;;
+ ;; Where point is on the "except" and must move to
+ ;; the end of "here()". Without this extra step we'd
+ ;; just get to the end of processing().
+ (goto-char parent-block-ending-pos)))))
+ (t
+ (if (and prev-block-ending-pos (< prev-block-ending-pos (point)))
+ (goto-char prev-block-ending-pos)
+ (python-nav-beginning-of-block)))))))))
+
+(defun python-nav-forward-sexp (&optional arg)
"Move forward across one block of code.
With ARG, do it that many times. Negative arg -N means
move backward N times."
(interactive "^p")
(or arg (setq arg 1))
(while (> arg 0)
- (let ((block-starting-pos
- (save-excursion (python-nav-beginning-of-block)))
- (block-ending-pos
- (save-excursion (python-nav-end-of-block)))
- (next-block-starting-pos
- (save-excursion (python-nav-forward-block))))
- (cond ((not block-starting-pos)
- (python-nav-forward-block))
- ((= (point) block-starting-pos)
- (if (or (not next-block-starting-pos)
- (< block-ending-pos next-block-starting-pos))
- (python-nav-end-of-block)
- (python-nav-forward-block)))
- ((= block-ending-pos (point))
- (let ((parent-block-end-pos
- (save-excursion
- (python-util-forward-comment)
- (python-nav-beginning-of-block)
- (python-nav-end-of-block))))
- (if (and parent-block-end-pos
- (or (not next-block-starting-pos)
- (> next-block-starting-pos parent-block-end-pos)))
- (goto-char parent-block-end-pos)
- (python-nav-forward-block))))
- (t (python-nav-end-of-block))))
- (setq arg (1- arg)))
+ (python-nav--forward-sexp)
+ (setq arg (1- arg)))
(while (< arg 0)
- (let* ((block-starting-pos
- (save-excursion (python-nav-beginning-of-block)))
- (block-ending-pos
- (save-excursion (python-nav-end-of-block)))
- (prev-block-ending-pos
- (save-excursion (when (python-nav-backward-block)
- (python-nav-end-of-block))))
- (prev-block-parent-ending-pos
- (save-excursion
- (when prev-block-ending-pos
- (goto-char prev-block-ending-pos)
- (python-util-forward-comment)
- (python-nav-beginning-of-block)
- (python-nav-end-of-block)))))
- (cond ((not block-ending-pos)
- (and (python-nav-backward-block)
- (python-nav-end-of-block)))
- ((= (point) block-ending-pos)
- (let ((candidates))
- (dolist (name
- '(prev-block-parent-ending-pos
- prev-block-ending-pos
- block-ending-pos
- block-starting-pos))
- (when (and (symbol-value name)
- (< (symbol-value name) (point)))
- (add-to-list 'candidates (symbol-value name))))
- (goto-char (apply 'max candidates))))
- ((> (point) block-ending-pos)
- (python-nav-end-of-block))
- ((= (point) block-starting-pos)
- (if (not (> (point) (or prev-block-ending-pos (point))))
- (python-nav-backward-block)
- (goto-char prev-block-ending-pos)
- (let ((parent-block-ending-pos
- (save-excursion
- (python-nav-forward-sexp-function)
- (and (not (looking-at (python-rx block-start)))
- (point)))))
- (when (and parent-block-ending-pos
- (> parent-block-ending-pos prev-block-ending-pos))
- (goto-char parent-block-ending-pos)))))
- (t (python-nav-beginning-of-block))))
+ (python-nav--backward-sexp)
(setq arg (1+ arg))))
\f
:group 'python
:safe 'booleanp)
-(defcustom python-shell-send-setup-max-wait 5
- "Seconds to wait for process output before code setup.
-If output is received before the specified time then control is
-returned in that moment and not after waiting."
- :type 'integer
- :group 'python
- :safe 'integerp)
-
(defcustom python-shell-process-environment nil
"List of environment variables for Python shell.
This variable follows the same rules as `process-environment'
If DEDICATED is t and the variable `buffer-file-name' is non-nil
returns a string with the form
`python-shell-buffer-name'[variable `buffer-file-name'] else
-returns the value of `python-shell-buffer-name'. After
-calculating the process name adds the buffer name for the process
-in the `same-window-buffer-names' list."
+returns the value of `python-shell-buffer-name'."
(let ((process-name
(if (and dedicated
buffer-file-name)
(format "%s[%s]" python-shell-buffer-name buffer-file-name)
(format "%s" python-shell-buffer-name))))
- (add-to-list 'same-window-buffer-names (purecopy
- (format "*%s*" process-name)))
process-name))
(defun python-shell-internal-get-process-name ()
'python-shell-completion-complete-at-point)
(define-key inferior-python-mode-map "\t"
'python-shell-completion-complete-or-indent)
+ (make-local-variable 'python-pdbtrack-buffers-to-kill)
+ (make-local-variable 'python-pdbtrack-tracked-buffer)
+ (make-local-variable 'python-shell-internal-last-output)
(when python-shell-enable-font-lock
(set (make-local-variable 'font-lock-defaults)
'(python-font-lock-keywords nil nil nil nil))
python-syntax-propertize-function))
(compilation-shell-minor-mode 1))
-(defun python-shell-make-comint (cmd proc-name &optional pop)
+(defun python-shell-make-comint (cmd proc-name &optional pop internal)
"Create a python shell comint buffer.
CMD is the python command to be executed and PROC-NAME is the
process name the comint buffer will get. After the comint buffer
-is created the `inferior-python-mode' is activated. If POP is
-non-nil the buffer is shown."
+is created the `inferior-python-mode' is activated. When
+optional argument POP is non-nil the buffer is shown. When
+optional argument INTERNAL is non-nil this process is run on a
+buffer with a name that starts with a space, following the Emacs
+convention for temporary/internal buffers, and also makes sure
+the user is not queried for confirmation when the process is
+killed."
(save-excursion
- (let* ((proc-buffer-name (format "*%s*" proc-name))
+ (let* ((proc-buffer-name
+ (format (if (not internal) "*%s*" " *%s*") proc-name))
(process-environment (python-shell-calculate-process-environment))
(exec-path (python-shell-calculate-exec-path)))
(when (not (comint-check-proc proc-buffer-name))
(let* ((cmdlist (split-string-and-unquote cmd))
- (buffer (apply 'make-comint proc-name (car cmdlist) nil
- (cdr cmdlist)))
- (current-buffer (current-buffer)))
+ (buffer (apply #'make-comint-in-buffer proc-name proc-buffer-name
+ (car cmdlist) nil (cdr cmdlist)))
+ (current-buffer (current-buffer))
+ (process (get-buffer-process buffer)))
(with-current-buffer buffer
(inferior-python-mode)
- (python-util-clone-local-variables current-buffer))))
- (and pop (pop-to-buffer proc-buffer-name t))
+ (python-util-clone-local-variables current-buffer))
+ (accept-process-output process)
+ (and pop (pop-to-buffer buffer t))
+ (and internal (set-process-query-on-exit-flag process nil))))
proc-buffer-name)))
;;;###autoload
"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.)"
- (set-process-query-on-exit-flag
- (get-buffer-process
- (python-shell-make-comint
- (python-shell-parse-command)
- (python-shell-internal-get-process-name))) nil))
+`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. Note that
+`python-shell-enable-font-lock' and `inferior-python-mode-hook'
+are set to nil for these shells, so setup codes are not sent at
+startup."
+ (let ((python-shell-enable-font-lock nil)
+ (inferior-python-mode-hook nil))
+ (get-buffer-process
+ (python-shell-make-comint
+ (python-shell-parse-command)
+ (python-shell-internal-get-process-name) nil t))))
(defun python-shell-get-process ()
"Get inferior Python process for current buffer and return it."
"Current internal shell buffer for the current buffer.
This is really not necessary at all for the code to work but it's
there for compatibility with CEDET.")
-(make-variable-buffer-local 'python-shell-internal-buffer)
+
+(defvar python-shell-internal-last-output nil
+ "Last output captured by the internal shell.
+This is really not necessary at all for the code to work but it's
+there for compatibility with CEDET.")
(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)
- (setq python-shell-internal-buffer proc-buffer-name)
+ (proc-buffer-name (format " *%s*" proc-name)))
+ (when (not (process-live-p proc-name))
+ (run-python-internal)
+ (setq python-shell-internal-buffer proc-buffer-name)
+ ;; XXX: Why is this `sit-for' needed?
+ ;; `python-shell-make-comint' calls `accept-process-output'
+ ;; already but it is not helping to get proper output on
+ ;; 'gnu/linux when the internal shell process is not running and
+ ;; a call to `python-shell-internal-send-string' is issued.
+ (sit-for 0.1 t))
(get-buffer-process proc-buffer-name)))
(define-obsolete-function-alias
- 'python-proc 'python-shell-internal-get-or-create-process "24.2")
+ 'python-proc 'python-shell-internal-get-or-create-process "24.3")
(define-obsolete-variable-alias
- 'python-buffer 'python-shell-internal-buffer "24.2")
+ 'python-buffer 'python-shell-internal-buffer "24.3")
+
+(define-obsolete-variable-alias
+ 'python-preoutput-result 'python-shell-internal-last-output "24.3")
(defun python-shell-send-string (string &optional process msg)
"Send STRING to inferior Python PROCESS.
(interactive "sPython command: ")
(let ((process (or process (python-shell-get-or-create-process)))
(lines (split-string string "\n" t)))
- (when msg
- (message (format "Sent: %s..." (nth 0 lines))))
+ (and msg (message "Sent: %s..." (nth 0 lines)))
(if (> (length lines) 1)
- (let* ((temp-file-name (make-temp-file "py"))
+ (let* ((temporary-file-directory
+ (if (file-remote-p default-directory)
+ (concat (file-remote-p default-directory) "/tmp")
+ temporary-file-directory))
+ (temp-file-name (make-temp-file "py"))
(file-name (or (buffer-file-name) temp-file-name)))
(with-temp-file temp-file-name
(insert string)
(string-match "\n[ \t].*\n?$" string))
(comint-send-string process "\n")))))
+;; Shell output catching stolen from gud-gdb
+(defvar python-shell-fetch-lines-in-progress nil)
+(defvar python-shell-fetch-lines-string nil)
+(defvar python-shell-fetched-lines nil)
+
+(defun python-shell-fetch-lines-filter (string)
+ "Filter used to read the list of lines output by a command.
+STRING is the output to filter."
+ (setq string (concat python-shell-fetch-lines-string string))
+ (while (string-match "\n" string)
+ (push (substring string 0 (match-beginning 0))
+ python-shell-fetched-lines)
+ (setq string (substring string (match-end 0))))
+ (if (equal (string-match comint-prompt-regexp string) 0)
+ (progn
+ (setq python-shell-fetch-lines-in-progress nil)
+ string)
+ (progn
+ (setq python-shell-fetch-lines-string string)
+ "")))
+
(defun python-shell-send-string-no-output (string &optional process msg)
"Send STRING to PROCESS and inhibit output.
When MSG is non-nil messages the first line of STRING. Return
the output."
- (let* ((output-buffer "")
- (process (or process (python-shell-get-or-create-process)))
- (comint-preoutput-filter-functions
- (append comint-preoutput-filter-functions
- '(ansi-color-filter-apply
- (lambda (string)
- (setq output-buffer (concat output-buffer string))
- ""))))
- (inhibit-quit t))
+ (let ((process (or process (python-shell-get-or-create-process)))
+ (comint-preoutput-filter-functions
+ '(python-shell-fetch-lines-filter))
+ (python-shell-fetch-lines-in-progress t)
+ (inhibit-quit t))
(or
(with-local-quit
(python-shell-send-string string process msg)
- (accept-process-output process)
- (replace-regexp-in-string
- (if (> (length python-shell-prompt-output-regexp) 0)
- (format "\n*%s$\\|^%s\\|\n$"
- python-shell-prompt-regexp
- (or python-shell-prompt-output-regexp ""))
- (format "\n*$\\|^%s\\|\n$"
- python-shell-prompt-regexp))
- "" output-buffer))
+ (while python-shell-fetch-lines-in-progress
+ (accept-process-output process))
+ (prog1
+ (mapconcat #'identity
+ (reverse python-shell-fetched-lines) "\n")
+ (setq python-shell-fetched-lines nil)))
(with-current-buffer (process-buffer process)
(comint-interrupt-subjob)))))
(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))
+ ;; XXX Remove `python-shell-internal-last-output' once CEDET is
+ ;; updated to support this new mode.
+ (setq python-shell-internal-last-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 "24.2")
+ 'python-send-receive 'python-shell-internal-send-string "24.3")
(define-obsolete-function-alias
- 'python-send-string 'python-shell-internal-send-string "24.2")
+ 'python-send-string 'python-shell-internal-send-string "24.3")
(defun python-shell-send-region (start end)
"Send the region delimited by START and END to inferior Python process."
(defun python-shell-send-buffer (&optional arg)
"Send the entire buffer to inferior Python process.
-
-With prefix ARG include lines surrounded by \"if __name__ == '__main__':\""
+With prefix ARG allow execution of code inside blocks delimited
+by \"if __name__== '__main__':\""
(interactive "P")
(save-restriction
(widen)
- (python-shell-send-region
- (point-min)
- (or (and
- (not arg)
- (save-excursion
- (re-search-forward (python-rx if-name-main) nil t))
- (match-beginning 0))
- (point-max)))))
+ (let ((str (buffer-substring (point-min) (point-max))))
+ (and
+ (not arg)
+ (setq str (replace-regexp-in-string
+ (python-rx if-name-main)
+ "if __name__ == '__main__ ':" str)))
+ (python-shell-send-string str))))
(defun python-shell-send-defun (arg)
"Send the current defun to inferior Python process.
(interactive "fFile to send: ")
(let* ((process (or process (python-shell-get-or-create-process)))
(temp-file-name (when temp-file-name
- (expand-file-name temp-file-name)))
- (file-name (or (expand-file-name file-name) temp-file-name)))
+ (expand-file-name
+ (or (file-remote-p temp-file-name 'localname)
+ temp-file-name))))
+ (file-name (or (when file-name
+ (expand-file-name
+ (or (file-remote-p file-name 'localname)
+ file-name)))
+ temp-file-name)))
(when (not file-name)
(error "If FILE-NAME is nil then TEMP-FILE-NAME must be non-nil"))
(python-shell-send-string
"Send all setup code for shell.
This function takes the list of setup code to send from the
`python-shell-setup-codes' list."
- (let ((msg "Sent %s")
- (process (get-buffer-process (current-buffer))))
- (accept-process-output process python-shell-send-setup-max-wait)
+ (let ((process (get-buffer-process (current-buffer))))
(dolist (code python-shell-setup-codes)
(when code
- (message (format msg code))
+ (message "Sent %s" code)
(python-shell-send-string
(symbol-value code) process)))))
:type 'string
:group 'python)
-(defun python-shell-completion--get-completions (input process completion-code)
- "Retrieve available completions for INPUT using PROCESS.
-Argument COMPLETION-CODE is the python code used to get
-completions on the current context."
- (with-current-buffer (process-buffer process)
- (let ((completions (python-shell-send-string-no-output
- (format completion-code input) process)))
- (when (> (length completions) 2)
- (split-string completions "^'\\|^\"\\|;\\|'$\\|\"$" t)))))
-
-(defun python-shell-completion--do-completion-at-point (process)
- "Do completion at point for PROCESS."
- (with-syntax-table python-dotty-syntax-table
- (let* ((beg
- (save-excursion
+(defun python-shell-completion-get-completions (process line input)
+ "Do completion at point for PROCESS.
+LINE is used to detect the context on how to complete given
+INPUT."
+ (let* ((prompt
+ ;; Get the last prompt for the inferior process
+ ;; buffer. This is used for the completion code selection
+ ;; heuristic.
+ (with-current-buffer (process-buffer process)
+ (buffer-substring-no-properties
+ (overlay-start comint-last-prompt-overlay)
+ (overlay-end comint-last-prompt-overlay))))
+ (completion-context
+ ;; Check whether a prompt matches a pdb string, an import
+ ;; statement or just the standard prompt and use the
+ ;; correct python-shell-completion-*-code string
+ (cond ((and (> (length python-shell-completion-pdb-string-code) 0)
+ (string-match
+ (concat "^" python-shell-prompt-pdb-regexp) prompt))
+ 'pdb)
+ ((and (>
+ (length python-shell-completion-module-string-code) 0)
+ (string-match
+ (concat "^" python-shell-prompt-regexp) prompt)
+ (string-match "^[ \t]*\\(from\\|import\\)[ \t]" line))
+ 'import)
+ ((string-match
+ (concat "^" python-shell-prompt-regexp) prompt)
+ 'default)
+ (t nil)))
+ (completion-code
+ (case completion-context
+ (pdb python-shell-completion-pdb-string-code)
+ (import python-shell-completion-module-string-code)
+ (default python-shell-completion-string-code)
+ (t nil)))
+ (input
+ (if (eq completion-context 'import)
+ (replace-regexp-in-string "^[ \t]+" "" line)
+ input)))
+ (and completion-code
+ (> (length input) 0)
+ (with-current-buffer (process-buffer process)
+ (let ((completions (python-shell-send-string-no-output
+ (format completion-code input) process)))
+ (and (> (length completions) 2)
+ (split-string completions
+ "^'\\|^\"\\|;\\|'$\\|\"$" t)))))))
+
+(defun python-shell-completion-complete-at-point (&optional process)
+ "Perform completion at point in inferior Python.
+Optional argument PROCESS forces completions to be retrieved
+using that one instead of current buffer's process."
+ (setq process (or process (get-buffer-process (current-buffer))))
+ (let* ((start
+ (save-excursion
+ (with-syntax-table python-dotty-syntax-table
(let* ((paren-depth (car (syntax-ppss)))
(syntax-string "w_")
(syntax-list (string-to-syntax syntax-string)))
- ;; Stop scanning for the beginning of the completion subject
- ;; after the char before point matches a delimiter
- (while (member (car (syntax-after (1- (point)))) syntax-list)
+ ;; Stop scanning for the beginning of the completion
+ ;; subject after the char before point matches a
+ ;; delimiter
+ (while (member
+ (car (syntax-after (1- (point)))) syntax-list)
(skip-syntax-backward syntax-string)
(when (or (equal (char-before) ?\))
(equal (char-before) ?\"))
(while (or
;; honor initial paren depth
(> (car (syntax-ppss)) paren-depth)
- (python-info-ppss-context 'string))
- (forward-char -1))))
- (point)))
- (end (point))
- (line (buffer-substring-no-properties (point-at-bol) end))
- (input (buffer-substring-no-properties beg end))
- ;; Get the last prompt for the inferior process buffer. This is
- ;; used for the completion code selection heuristic.
- (prompt
- (with-current-buffer (process-buffer process)
- (buffer-substring-no-properties
- (overlay-start comint-last-prompt-overlay)
- (overlay-end comint-last-prompt-overlay))))
- (completion-context
- ;; Check whether a prompt matches a pdb string, an import statement
- ;; or just the standard prompt and use the correct
- ;; python-shell-completion-*-code string
- (cond ((and (> (length python-shell-completion-pdb-string-code) 0)
- (string-match
- (concat "^" python-shell-prompt-pdb-regexp) prompt))
- 'pdb)
- ((and (>
- (length python-shell-completion-module-string-code) 0)
- (string-match
- (concat "^" python-shell-prompt-regexp) prompt)
- (string-match "^[ \t]*\\(from\\|import\\)[ \t]" line))
- 'import)
- ((string-match
- (concat "^" python-shell-prompt-regexp) prompt)
- 'default)
- (t nil)))
- (completion-code
- (case completion-context
- ('pdb python-shell-completion-pdb-string-code)
- ('import python-shell-completion-module-string-code)
- ('default python-shell-completion-string-code)
- (t nil)))
- (input
- (if (eq completion-context 'import)
- (replace-regexp-in-string "^[ \t]+" "" line)
- input))
- (completions
- (and completion-code (> (length input) 0)
- (python-shell-completion--get-completions
- input process completion-code))))
- (list beg end completions))))
-
-(defun python-shell-completion-complete-at-point ()
- "Perform completion at point in inferior Python process."
- (and comint-last-prompt-overlay
- (> (point-marker) (overlay-end comint-last-prompt-overlay))
- (python-shell-completion--do-completion-at-point
- (get-buffer-process (current-buffer)))))
+ (python-syntax-context 'string))
+ (forward-char -1)))
+ (point)))))
+ (end (point)))
+ (list start end
+ (completion-table-dynamic
+ (apply-partially
+ #'python-shell-completion-get-completions
+ process (buffer-substring-no-properties
+ (line-beginning-position) end))))))
(defun python-shell-completion-complete-or-indent ()
"Complete or indent depending on the context.
"Variable containing the value of the current tracked buffer.
Never set this variable directly, use
`python-pdbtrack-set-tracked-buffer' instead.")
-(make-variable-buffer-local 'python-pdbtrack-tracked-buffer)
(defvar python-pdbtrack-buffers-to-kill nil
"List of buffers to be deleted after tracking finishes.")
-(make-variable-buffer-local 'python-pdbtrack-buffers-to-kill)
(defun python-pdbtrack-set-tracked-buffer (file-name)
"Set the buffer for FILE-NAME as the tracked buffer.
(let ((process (python-shell-get-process)))
(if (not process)
(error "Completion needs an inferior Python process running")
- (python-shell-completion--do-completion-at-point process))))
+ (python-shell-completion-complete-at-point process))))
(add-to-list 'debug-ignored-errors
"^Completion needs an inferior Python process running.")
This is the function used by `python-fill-paragraph-function' to
fill comments."
:type 'symbol
- :group 'python
- :safe 'symbolp)
+ :group 'python)
(defcustom python-fill-string-function 'python-fill-string
"Function to fill strings.
This is the function used by `python-fill-paragraph-function' to
fill strings."
:type 'symbol
- :group 'python
- :safe 'symbolp)
+ :group 'python)
(defcustom python-fill-decorator-function 'python-fill-decorator
"Function to fill decorators.
This is the function used by `python-fill-paragraph-function' to
fill decorators."
:type 'symbol
- :group 'python
- :safe 'symbolp)
+ :group 'python)
(defcustom python-fill-paren-function 'python-fill-paren
"Function to fill parens.
This is the function used by `python-fill-paragraph-function' to
fill parens."
:type 'symbol
+ :group 'python)
+
+(defcustom python-fill-string-style 'pep-257
+ "Style used to fill docstrings.
+This affects `python-fill-string' behavior with regards to
+triple quotes positioning.
+
+Possible values are DJANGO, PEP-257, PEP-257-NN, SYMMETRIC and
+NIL. A value of NIL won't care about quotes position, will do
+what `fill-paragraph' does, any other value may result in one of
+the following docstring styles:
+
+DJANGO:
+
+ \"\"\"
+ Process foo, return bar.
+ \"\"\"
+
+ \"\"\"
+ Process foo, return bar.
+
+ If processing fails throw ProcessingError.
+ \"\"\"
+
+PEP-257:
+
+ \"\"\"Process foo, return bar.\"\"\"
+
+ \"\"\"Process foo, return bar.
+
+ If processing fails throw ProcessingError.
+
+ \"\"\"
+
+PEP-257-NN:
+
+ \"\"\"Process foo, return bar.\"\"\"
+
+ \"\"\"Process foo, return bar.
+
+ If processing fails throw ProcessingError.
+ \"\"\"
+
+SYMMETRIC:
+
+ \"\"\"Process foo, return bar.\"\"\"
+
+ \"\"\"
+ Process foo, return bar.
+
+ If processing fails throw ProcessingError.
+ \"\"\""
+ :type 'symbol
:group 'python
- :safe 'symbolp)
+ :safe (lambda (val) (memq val '(django pep-257 pep-257-nn symmetric nil))))
(defun python-fill-paragraph-function (&optional justify)
"`fill-paragraph-function' handling multi-line strings and possibly comments.
Optional argument JUSTIFY defines if the paragraph should be justified."
(interactive "P")
(save-excursion
- (back-to-indentation)
(cond
;; Comments
- ((funcall python-fill-comment-function justify))
+ ((python-syntax-context 'comment)
+ (funcall python-fill-comment-function justify))
;; Strings/Docstrings
- ((save-excursion (skip-chars-forward "\"'uUrR")
- (python-info-ppss-context 'string))
+ ((save-excursion (or (python-syntax-context 'string)
+ (equal (string-to-syntax "|")
+ (syntax-after (point)))))
(funcall python-fill-string-function justify))
;; Decorators
((equal (char-after (save-excursion
(back-to-indentation)
- (point-marker))) ?@)
+ (point))) ?@)
(funcall python-fill-decorator-function justify))
;; Parens
- ((or (python-info-ppss-context 'paren)
+ ((or (python-syntax-context 'paren)
(looking-at (python-rx open-paren))
(save-excursion
(skip-syntax-forward "^(" (line-end-position))
(defun python-fill-string (&optional justify)
"String fill function for `python-fill-paragraph-function'.
JUSTIFY should be used (if applicable) as in `fill-paragraph'."
- (let ((marker (point-marker))
- (string-start-marker
- (progn
- (skip-chars-forward "\"'uUrR")
- (goto-char (python-info-ppss-context 'string))
- (skip-chars-forward "\"'uUrR")
- (point-marker)))
- (reg-start (line-beginning-position))
- (string-end-marker
- (progn
- (while (python-info-ppss-context 'string)
- (goto-char (1+ (point-marker))))
- (skip-chars-backward "\"'")
- (point-marker)))
- (reg-end (line-end-position))
- (fill-paragraph-function))
+ (let* ((marker (point-marker))
+ (str-start-pos
+ (let ((m (make-marker)))
+ (setf (marker-position m)
+ (or (python-syntax-context 'string)
+ (and (equal (string-to-syntax "|")
+ (syntax-after (point)))
+ (point)))) m))
+ (num-quotes (python-syntax-count-quotes
+ (char-after str-start-pos) str-start-pos))
+ (str-end-pos
+ (save-excursion
+ (goto-char (+ str-start-pos num-quotes))
+ (or (re-search-forward (rx (syntax string-delimiter)) nil t)
+ (goto-char (point-max)))
+ (point-marker)))
+ (multi-line-p
+ ;; Docstring styles may vary for oneliners and multi-liners.
+ (> (count-matches "\n" str-start-pos str-end-pos) 0))
+ (delimiters-style
+ (case python-fill-string-style
+ ;; delimiters-style is a cons cell with the form
+ ;; (START-NEWLINES . END-NEWLINES). When any of the sexps
+ ;; is NIL means to not add any newlines for start or end
+ ;; of docstring. See `python-fill-string-style' for a
+ ;; graphic idea of each style.
+ (pep-257 (and multi-line-p (cons nil 2)))
+ (pep-257-nn (and multi-line-p (cons nil 1)))
+ (django (cons 1 1))
+ (symmetric (and multi-line-p (cons 1 1)))))
+ (docstring-p (save-excursion
+ ;; Consider docstrings those strings which
+ ;; start on a line by themselves.
+ (goto-char str-start-pos)
+ (skip-chars-backward (rx whitespace))
+ (= (point) (line-beginning-position))))
+ (fill-paragraph-function))
(save-restriction
- (narrow-to-region reg-start reg-end)
- (save-excursion
- (goto-char string-start-marker)
- (delete-region (point-marker) (progn
- (skip-syntax-forward "> ")
- (point-marker)))
- (goto-char string-end-marker)
- (delete-region (point-marker) (progn
- (skip-syntax-backward "> ")
- (point-marker)))
- (save-excursion
- (goto-char marker)
- (fill-paragraph justify))
- ;; If there is a newline in the docstring lets put triple
- ;; quote in it's own line to follow pep 8
- (when (save-excursion
- (re-search-backward "\n" string-start-marker t))
- (newline)
- (newline-and-indent))
- (fill-paragraph justify)))) t)
+ (narrow-to-region str-start-pos str-end-pos)
+ (fill-paragraph justify))
+ (save-excursion
+ (when (and docstring-p python-fill-string-style)
+ ;; Add the number of newlines indicated by the selected style
+ ;; at the start of the docstring.
+ (goto-char (+ str-start-pos num-quotes))
+ (delete-region (point) (progn
+ (skip-syntax-forward "> ")
+ (point)))
+ (and (car delimiters-style)
+ (or (newline (car delimiters-style)) t)
+ ;; Indent only if a newline is added.
+ (indent-according-to-mode))
+ ;; Add the number of newlines indicated by the selected style
+ ;; at the end of the docstring.
+ (goto-char (if (not (= str-end-pos (point-max)))
+ (- str-end-pos num-quotes)
+ str-end-pos))
+ (delete-region (point) (progn
+ (skip-syntax-backward "> ")
+ (point)))
+ (and (cdr delimiters-style)
+ ;; Add newlines only if string ends.
+ (not (= str-end-pos (point-max)))
+ (or (newline (cdr delimiters-style)) t)
+ ;; Again indent only if a newline is added.
+ (indent-according-to-mode))))) t)
(defun python-fill-decorator (&optional justify)
"Decorator fill function for `python-fill-paragraph-function'.
JUSTIFY should be used (if applicable) as in `fill-paragraph'."
(save-restriction
(narrow-to-region (progn
- (while (python-info-ppss-context 'paren)
+ (while (python-syntax-context 'paren)
(goto-char (1- (point-marker))))
(point-marker)
(line-beginning-position))
(progn
- (when (not (python-info-ppss-context 'paren))
+ (when (not (python-syntax-context 'paren))
(end-of-line)
- (when (not (python-info-ppss-context 'paren))
+ (when (not (python-syntax-context 'paren))
(skip-syntax-backward "^)")))
- (while (python-info-ppss-context 'paren)
+ (while (python-syntax-context 'paren)
(goto-char (1+ (point-marker))))
(point-marker)))
(let ((paragraph-start "\f\\|[ \t]*$")
:safe 'booleanp)
(define-obsolete-variable-alias
- 'python-use-skeletons 'python-skeleton-autoinsert "24.2")
+ 'python-use-skeletons 'python-skeleton-autoinsert "24.3")
(defvar python-skeleton-available '()
"Internal list of available skeletons.")
;; Only expand in code.
:enable-function (lambda ()
(and
- (not (python-info-ppss-comment-or-string-p))
+ (not (python-syntax-comment-or-string-p))
python-skeleton-autoinsert)))
(defmacro python-skeleton-define (name doc &rest skel)
With optional argument REPLACE-SELF convert \"self\" to current
parent defun name."
(let ((name
- (and (not (python-info-ppss-comment-or-string-p))
+ (and (not (python-syntax-comment-or-string-p))
(with-syntax-table python-dotty-syntax-table
(let ((sym (symbol-at-point)))
(and sym
(goto-char line-number))
(while (and (not (eobp))
(goto-char (line-end-position))
- (python-info-ppss-context 'paren)
+ (python-syntax-context 'paren)
(not (equal (char-before (point)) ?\\)))
(forward-line 1))
(when (equal (char-before) ?\\)
(when (python-info-line-ends-backslash-p)
(while (save-excursion
(goto-char (line-beginning-position))
- (python-info-ppss-context 'paren))
+ (python-syntax-context 'paren))
(forward-line -1))
(back-to-indentation)
(point-marker)))))
(widen)
(let* ((context-type (progn
(back-to-indentation)
- (python-info-ppss-context-type)))
+ (python-syntax-context-type)))
(line-start (line-number-at-pos))
(context-start (when context-type
- (python-info-ppss-context context-type))))
+ (python-syntax-context context-type))))
(cond ((equal context-type 'paren)
;; Lines inside a paren are always a continuation line
;; (except the first one).
assignment-operator
not-simple-operator)
(line-end-position) t)
- (not (python-info-ppss-context-type))))
+ (not (python-syntax-context-type))))
(skip-syntax-forward "\s")
(point-marker)))))
-(defun python-info-ppss-context (type &optional syntax-ppss)
- "Return non-nil if point is on TYPE using SYNTAX-PPSS.
-TYPE can be `comment', `string' or `paren'. It returns the start
-character address of the specified TYPE."
- (let ((ppss (or syntax-ppss (syntax-ppss))))
- (case type
- (comment
- (and (nth 4 ppss)
- (nth 8 ppss)))
- (string
- (and (not (nth 4 ppss))
- (nth 8 ppss)))
- (paren
- (nth 1 ppss))
- (t nil))))
-
-(defun python-info-ppss-context-type (&optional syntax-ppss)
- "Return the context type using SYNTAX-PPSS.
-The type returned can be `comment', `string' or `paren'."
- (let ((ppss (or syntax-ppss (syntax-ppss))))
- (cond
- ((nth 8 ppss) (if (nth 4 ppss) 'comment 'string))
- ((nth 1 ppss) 'paren))))
-
-(defsubst python-info-ppss-comment-or-string-p ()
- "Return non-nil if point is inside 'comment or 'string."
- (nth 8 (syntax-ppss)))
-
(defun python-info-looking-at-beginning-of-defun (&optional syntax-ppss)
"Check if point is at `beginning-of-defun' using SYNTAX-PPSS."
- (and (not (python-info-ppss-context-type (or syntax-ppss (syntax-ppss))))
+ (and (not (python-syntax-context-type (or syntax-ppss (syntax-ppss))))
(save-excursion
(beginning-of-line 1)
(looking-at python-nav-beginning-of-defun-regexp))))
(defun python-util-forward-comment (&optional direction)
"Python mode specific version of `forward-comment'.
Optional argument DIRECTION defines the direction to move to."
- (let ((comment-start (python-info-ppss-context 'comment))
+ (let ((comment-start (python-syntax-context 'comment))
(factor (if (< (or direction 0) 0)
-99999
99999)))
(set (make-local-variable 'parse-sexp-ignore-comments) t)
(set (make-local-variable 'forward-sexp-function)
- 'python-nav-forward-sexp-function)
+ 'python-nav-forward-sexp)
(set (make-local-variable 'font-lock-defaults)
'(python-font-lock-keywords nil nil nil nil))
(python-skeleton-add-menu-items)
+ (make-local-variable 'python-shell-internal-buffer)
+
(when python-indent-guess-indent-offset
(python-indent-guess-indent-offset)))