summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog38
-rw-r--r--lisp/faces.el7
-rw-r--r--lisp/progmodes/python.el204
-rw-r--r--lisp/vc/log-edit.el78
-rw-r--r--lisp/vc/vc-dispatcher.el2
5 files changed, 202 insertions, 127 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index faa5a3dffff..db1f0481d62 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,41 @@
+2014-07-12 Paul Eggert <eggert@cs.ucla.edu>
+
+ Fix bug: C-x v v discarded existing log message (Bug#17884).
+ * vc/vc-dispatcher.el (vc-log-edit):
+ Don't clobber an already-existing log message.
+
+2014-07-12 Glenn Morris <rgm@gnu.org>
+
+ * vc/log-edit.el (log-edit-changelog-entries):
+ Check for a visited-but-never-saved ChangeLog.
+
+2014-07-12 Stefan Monnier <monnier@iro.umontreal.ca>
+
+ * vc/log-edit.el (log-edit-changelog-entries): Don't both visiting
+ a non-existing file (bug#17970).
+
+ * faces.el (face-name): Undo last change.
+ (x-resolve-font-name): Don't call face-name (bug#17956).
+
+2014-07-12 Fabián Ezequiel Gallina <fgallina@gnu.org>
+
+ Fix dedenters and electric colon handling. (Bug#15163)
+ * progmodes/python.el
+ (python-rx-constituents): Add dedenter and block-ender.
+ (python-indent-dedenters, python-indent-block-enders): Delete.
+ (python-indent-context): Return new case for dedenter-statement.
+ (python-indent-calculate-indentation): Handle new case.
+ (python-indent-calculate-levels): Fix levels calculation for
+ dedenter statements.
+ (python-indent-post-self-insert-function): Fix colon handling.
+ (python-info-dedenter-opening-block-message): New function.
+ (python-indent-line): Use it.
+ (python-info-closing-block)
+ (python-info-closing-block-message): Remove.
+ (python-info-dedenter-opening-block-position)
+ (python-info-dedenter-opening-block-positions)
+ (python-info-dedenter-statement-p): New functions.
+
2014-07-11 Dmitry Antipov <dmantipov@yandex.ru>
* files.el (out-of-memory-warning-percentage): New defcustom.
diff --git a/lisp/faces.el b/lisp/faces.el
index bb77af0425e..d9239d9e1eb 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -370,10 +370,7 @@ If `inhibit-x-resources' is non-nil, this function does nothing."
(defun face-name (face)
"Return the name of face FACE."
- (check-face face)
- (if (symbolp face)
- (symbol-name face)
- face))
+ (symbol-name (check-face face)))
(defun face-all-attributes (face &optional frame)
@@ -2749,8 +2746,6 @@ If PATTERN is nil, return the name of the frame's base font, which never
contains wildcards.
Given optional arguments FACE and FRAME, return a font which is
also the same size as FACE on FRAME, or fail."
- (when face
- (setq face (face-name face)))
(and (eq frame t)
(setq frame nil))
(if pattern
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 065a182904f..1187636c663 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -321,6 +321,13 @@
(or "def" "class" "if" "elif" "else" "try"
"except" "finally" "for" "while" "with")
symbol-end))
+ (dedenter . ,(rx symbol-start
+ (or "elif" "else" "except" "finally")
+ symbol-end))
+ (block-ender . ,(rx symbol-start
+ (or
+ "break" "continue" "pass" "raise" "return")
+ symbol-end))
(decorator . ,(rx line-start (* space) ?@ (any letter ?_)
(* (any word ?_))))
(defun . ,(rx symbol-start (or "def" "class") symbol-end))
@@ -630,18 +637,6 @@ It makes underscores and dots word constituent chars.")
(defvar python-indent-levels '(0)
"Levels of indentation available for `python-indent-line-function'.")
-(defvar python-indent-dedenters '("else" "elif" "except" "finally")
- "List of words that should be dedented.
-These make `python-indent-calculate-indentation' subtract the value of
-`python-indent-offset'.")
-
-(defvar python-indent-block-enders
- '("break" "continue" "pass" "raise" "return")
- "List of words that mark the end of a block.
-These make `python-indent-calculate-indentation' subtract the
-value of `python-indent-offset' when `python-indent-context' is
-AFTER-LINE.")
-
(defun python-indent-guess-indent-offset ()
"Guess and set `python-indent-offset' for the current buffer."
(interactive)
@@ -692,6 +687,7 @@ Where status can be any of the following symbols:
* after-backslash: Previous line ends in a backslash
* after-beginning-of-block: Point is after beginning of block
* after-line: Point is after normal line
+ * dedenter-statement: Point is on a dedenter statement.
* no-indent: Point is at beginning of buffer or other special case
START is the buffer position where the sexp starts."
(save-restriction
@@ -746,6 +742,8 @@ START is the buffer position where the sexp starts."
(when (looking-at (python-rx block-start))
(point-marker)))))
'after-beginning-of-block)
+ ((when (setq start (python-info-dedenter-statement-p))
+ 'dedenter-statement))
;; After normal line
((setq start (save-excursion
(back-to-indentation)
@@ -776,8 +774,7 @@ START is the buffer position where the sexp starts."
(goto-char context-start)
(+ (current-indentation) python-indent-offset))
;; When after a simple line just use previous line
- ;; indentation, in the case current line starts with a
- ;; `python-indent-dedenters' de-indent one level.
+ ;; indentation.
(`after-line
(let* ((pair (save-excursion
(goto-char context-start)
@@ -785,25 +782,27 @@ START is the buffer position where the sexp starts."
(current-indentation)
(python-info-beginning-of-block-p))))
(context-indentation (car pair))
- (after-block-start-p (cdr pair))
+ ;; TODO: Separate block enders into its own case.
(adjustment
- (if (or (save-excursion
- (back-to-indentation)
- (and
- ;; De-indent only when dedenters are not
- ;; next to a block start. This allows
- ;; one-liner constructs such as:
- ;; if condition: print "yay"
- ;; else: print "wry"
- (not after-block-start-p)
- (looking-at (regexp-opt python-indent-dedenters))))
- (save-excursion
- (python-util-forward-comment -1)
- (python-nav-beginning-of-statement)
- (looking-at (regexp-opt python-indent-block-enders))))
+ (if (save-excursion
+ (python-util-forward-comment -1)
+ (python-nav-beginning-of-statement)
+ (looking-at (python-rx block-ender)))
python-indent-offset
0)))
(- context-indentation adjustment)))
+ ;; When point is on a dedenter statement, search for the
+ ;; opening block that corresponds to it and use its
+ ;; indentation. If no opening block is found just remove
+ ;; indentation as this is an invalid python file.
+ (`dedenter-statement
+ (let ((block-start-point
+ (python-info-dedenter-opening-block-position)))
+ (save-excursion
+ (if (not block-start-point)
+ 0
+ (goto-char block-start-point)
+ (current-indentation)))))
;; When inside of a string, do nothing. just use the current
;; indentation. XXX: perhaps it would be a good idea to
;; invoke standard text indentation here
@@ -930,16 +929,25 @@ START is the buffer position where the sexp starts."
(defun python-indent-calculate-levels ()
"Calculate `python-indent-levels' and reset `python-indent-current-level'."
- (let* ((indentation (python-indent-calculate-indentation))
- (remainder (% indentation python-indent-offset))
- (steps (/ (- indentation remainder) python-indent-offset)))
- (setq python-indent-levels (list 0))
- (dotimes (step steps)
- (push (* python-indent-offset (1+ step)) python-indent-levels))
- (when (not (eq 0 remainder))
- (push (+ (* python-indent-offset steps) remainder) python-indent-levels))
- (setq python-indent-levels (nreverse python-indent-levels))
- (setq python-indent-current-level (1- (length python-indent-levels)))))
+ (if (not (python-info-dedenter-statement-p))
+ (let* ((indentation (python-indent-calculate-indentation))
+ (remainder (% indentation python-indent-offset))
+ (steps (/ (- indentation remainder) python-indent-offset)))
+ (setq python-indent-levels (list 0))
+ (dotimes (step steps)
+ (push (* python-indent-offset (1+ step)) python-indent-levels))
+ (when (not (eq 0 remainder))
+ (push (+ (* python-indent-offset steps) remainder) python-indent-levels)))
+ (setq python-indent-levels
+ (or
+ (mapcar (lambda (pos)
+ (save-excursion
+ (goto-char pos)
+ (current-indentation)))
+ (python-info-dedenter-opening-block-positions))
+ (list 0))))
+ (setq python-indent-current-level (1- (length python-indent-levels))
+ python-indent-levels (nreverse python-indent-levels)))
(defun python-indent-toggle-levels ()
"Toggle `python-indent-current-level' over `python-indent-levels'."
@@ -988,7 +996,7 @@ equal to
(indent-to next-indent)
(goto-char starting-pos))
(and follow-indentation-p (back-to-indentation)))
- (python-info-closing-block-message))
+ (python-info-dedenter-opening-block-message))
(defun python-indent-line-function ()
"`indent-line-function' for Python mode.
@@ -1124,14 +1132,7 @@ the line will be re-indented automatically if needed."
(eolp)
(not (equal ?: (char-before (1- (point)))))
(not (python-syntax-comment-or-string-p)))
- (let ((indentation (current-indentation))
- (calculated-indentation (python-indent-calculate-indentation)))
- (python-info-closing-block-message)
- (when (> indentation calculated-indentation)
- (save-excursion
- (indent-line-to calculated-indentation)
- (when (not (python-info-closing-block-message))
- (indent-line-to indentation)))))))))
+ (python-indent-line)))))
;;; Navigation
@@ -3454,49 +3455,88 @@ parent defun name."
(and (python-info-end-of-statement-p)
(python-info-statement-ends-block-p)))
-(defun python-info-closing-block ()
- "Return the point of the block the current line closes."
- (let ((closing-word (save-excursion
- (back-to-indentation)
- (current-word)))
- (indentation (current-indentation)))
- (when (member closing-word python-indent-dedenters)
+(define-obsolete-function-alias
+ 'python-info-closing-block
+ 'python-info-dedenter-opening-block-position "24.4")
+
+(defun python-info-dedenter-opening-block-position ()
+ "Return the point of the closest block the current line closes.
+Returns nil if point is not on a dedenter statement or no opening
+block can be detected. The latter case meaning current file is
+likely an invalid python file."
+ (let ((positions (python-info-dedenter-opening-block-positions))
+ (indentation (current-indentation))
+ (position))
+ (while (and (not position)
+ positions)
(save-excursion
- (forward-line -1)
- (while (and (> (current-indentation) indentation)
- (not (bobp))
- (not (back-to-indentation))
- (forward-line -1)))
- (back-to-indentation)
- (cond
- ((not (equal indentation (current-indentation))) nil)
- ((string= closing-word "elif")
- (when (member (current-word) '("if" "elif"))
- (point-marker)))
- ((string= closing-word "else")
- (when (member (current-word) '("if" "elif" "except" "for" "while"))
- (point-marker)))
- ((string= closing-word "except")
- (when (member (current-word) '("try"))
- (point-marker)))
- ((string= closing-word "finally")
- (when (member (current-word) '("except" "else"))
- (point-marker))))))))
-
-(defun python-info-closing-block-message (&optional closing-block-point)
- "Message the contents of the block the current line closes.
-With optional argument CLOSING-BLOCK-POINT use that instead of
-recalculating it calling `python-info-closing-block'."
- (let ((point (or closing-block-point (python-info-closing-block))))
+ (goto-char (car positions))
+ (if (<= (current-indentation) indentation)
+ (setq position (car positions))
+ (setq positions (cdr positions)))))
+ position))
+
+(defun python-info-dedenter-opening-block-positions ()
+ "Return points of blocks the current line may close sorted by closer.
+Returns nil if point is not on a dedenter statement or no opening
+block can be detected. The latter case meaning current file is
+likely an invalid python file."
+ (save-excursion
+ (let ((dedenter-pos (python-info-dedenter-statement-p)))
+ (when dedenter-pos
+ (goto-char dedenter-pos)
+ (let* ((pairs '(("elif" "elif" "if")
+ ("else" "if" "elif" "except" "for" "while")
+ ("except" "except" "try")
+ ("finally" "else" "except" "try")))
+ (dedenter (match-string-no-properties 0))
+ (possible-opening-blocks (cdr (assoc-string dedenter pairs)))
+ (collected-indentations)
+ (opening-blocks))
+ (catch 'exit
+ (while (python-nav--syntactically
+ (lambda ()
+ (re-search-backward (python-rx block-start) nil t))
+ #'<)
+ (let ((indentation (current-indentation)))
+ (when (and (not (memq indentation collected-indentations))
+ (or (not collected-indentations)
+ (< indentation (apply #'min collected-indentations))))
+ (setq collected-indentations
+ (cons indentation collected-indentations))
+ (when (member (match-string-no-properties 0)
+ possible-opening-blocks)
+ (setq opening-blocks (cons (point) opening-blocks))))
+ (when (zerop indentation)
+ (throw 'exit nil)))))
+ ;; sort by closer
+ (nreverse opening-blocks))))))
+
+(define-obsolete-function-alias
+ 'python-info-closing-block-message
+ 'python-info-dedenter-opening-block-message "24.4")
+
+(defun python-info-dedenter-opening-block-message ()
+ "Message the first line of the block the current statement closes."
+ (let ((point (python-info-dedenter-opening-block-position)))
(when point
(save-restriction
(widen)
(message "Closes %s" (save-excursion
(goto-char point)
- (back-to-indentation)
(buffer-substring
(point) (line-end-position))))))))
+(defun python-info-dedenter-statement-p ()
+ "Return point if current statement is a dedenter.
+Sets `match-data' to the keyword that starts the dedenter
+statement."
+ (save-excursion
+ (python-nav-beginning-of-statement)
+ (when (and (not (python-syntax-context-type))
+ (looking-at (python-rx dedenter)))
+ (point))))
+
(defun python-info-line-ends-backslash-p (&optional line-number)
"Return non-nil if current line ends with backslash.
With optional argument LINE-NUMBER, check that line instead."
diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el
index 1d75411ec1f..3b03ee14c0b 100644
--- a/lisp/vc/log-edit.el
+++ b/lisp/vc/log-edit.el
@@ -905,44 +905,46 @@ where LOGBUFFER is the name of the ChangeLog buffer, and each
;; that memoizing which is undesired here.
(setq change-log-default-name nil)
(find-change-log)))))
- (with-current-buffer (find-file-noselect changelog-file-name)
- (unless (eq major-mode 'change-log-mode) (change-log-mode))
- (goto-char (point-min))
- (if (looking-at "\\s-*\n") (goto-char (match-end 0)))
- (if (not (log-edit-changelog-ours-p))
- (list (current-buffer))
- (save-restriction
- (log-edit-narrow-changelog)
- (goto-char (point-min))
-
- ;; Search for the name of FILE relative to the ChangeLog. If that
- ;; doesn't occur anywhere, they're not using full relative
- ;; filenames in the ChangeLog, so just look for FILE; we'll accept
- ;; some false positives.
- (let ((pattern (file-relative-name
- file (file-name-directory changelog-file-name))))
- (if (or (string= pattern "")
- (not (save-excursion
- (search-forward pattern nil t))))
- (setq pattern (file-name-nondirectory file)))
-
- (setq pattern (concat "\\(^\\|[^[:alnum:]]\\)"
- (regexp-quote pattern)
- "\\($\\|[^[:alnum:]]\\)"))
-
- (let (texts
- (pos (point)))
- (while (and (not (eobp)) (re-search-forward pattern nil t))
- (let ((entry (log-edit-changelog-entry)))
- (if (< (elt entry 1) (max (1+ pos) (point)))
- ;; This is not relevant, actually.
- nil
- (push entry texts))
- ;; Make sure we make progress.
- (setq pos (max (1+ pos) (elt entry 1)))
- (goto-char pos)))
-
- (cons (current-buffer) texts))))))))
+ (when (or (find-buffer-visiting changelog-file-name)
+ (file-exists-p changelog-file-name))
+ (with-current-buffer (find-file-noselect changelog-file-name)
+ (unless (eq major-mode 'change-log-mode) (change-log-mode))
+ (goto-char (point-min))
+ (if (looking-at "\\s-*\n") (goto-char (match-end 0)))
+ (if (not (log-edit-changelog-ours-p))
+ (list (current-buffer))
+ (save-restriction
+ (log-edit-narrow-changelog)
+ (goto-char (point-min))
+
+ ;; Search for the name of FILE relative to the ChangeLog. If that
+ ;; doesn't occur anywhere, they're not using full relative
+ ;; filenames in the ChangeLog, so just look for FILE; we'll accept
+ ;; some false positives.
+ (let ((pattern (file-relative-name
+ file (file-name-directory changelog-file-name))))
+ (if (or (string= pattern "")
+ (not (save-excursion
+ (search-forward pattern nil t))))
+ (setq pattern (file-name-nondirectory file)))
+
+ (setq pattern (concat "\\(^\\|[^[:alnum:]]\\)"
+ (regexp-quote pattern)
+ "\\($\\|[^[:alnum:]]\\)"))
+
+ (let (texts
+ (pos (point)))
+ (while (and (not (eobp)) (re-search-forward pattern nil t))
+ (let ((entry (log-edit-changelog-entry)))
+ (if (< (elt entry 1) (max (1+ pos) (point)))
+ ;; This is not relevant, actually.
+ nil
+ (push entry texts))
+ ;; Make sure we make progress.
+ (setq pos (max (1+ pos) (elt entry 1)))
+ (goto-char pos)))
+
+ (cons (current-buffer) texts)))))))))
(defun log-edit-changelog-insert-entries (buffer beg end &rest files)
"Insert the text from BUFFER between BEG and END.
diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el
index a0efe023a1d..0445891ed55 100644
--- a/lisp/vc/vc-dispatcher.el
+++ b/lisp/vc/vc-dispatcher.el
@@ -596,7 +596,7 @@ NOT-URGENT means it is ok to continue if the user says not to save."
(setq default-directory
(buffer-local-value 'default-directory vc-parent-buffer))
(log-edit 'vc-finish-logentry
- t
+ (= (point-min) (point-max))
`((log-edit-listfun . (lambda ()
;; FIXME: Should expand the list
;; for directories.