mirror of
https://github.com/golang/go
synced 2024-11-22 07:04:40 -07:00
misc/emacs: fix overindentation caused by mis-parsing lines ending with special chars
Fixes #3313 go-mode-backward-skip-comments is probably due for a more ambitious refactoring --- it repeats guard conditions after every nearly every movement of point. R=sameer, r CC=golang-dev https://golang.org/cl/5844063
This commit is contained in:
parent
b485629e47
commit
bf9620ebbd
@ -110,6 +110,7 @@ built-ins, functions, and some types.")
|
|||||||
(let ((m (make-sparse-keymap)))
|
(let ((m (make-sparse-keymap)))
|
||||||
(define-key m "}" #'go-mode-insert-and-indent)
|
(define-key m "}" #'go-mode-insert-and-indent)
|
||||||
(define-key m ")" #'go-mode-insert-and-indent)
|
(define-key m ")" #'go-mode-insert-and-indent)
|
||||||
|
(define-key m "," #'go-mode-insert-and-indent)
|
||||||
(define-key m ":" #'go-mode-delayed-electric)
|
(define-key m ":" #'go-mode-delayed-electric)
|
||||||
;; In case we get : indentation wrong, correct ourselves
|
;; In case we get : indentation wrong, correct ourselves
|
||||||
(define-key m "=" #'go-mode-insert-and-indent)
|
(define-key m "=" #'go-mode-insert-and-indent)
|
||||||
@ -161,6 +162,18 @@ will be marked from the beginning up to this point (that is, up
|
|||||||
to and including character (1- go-mode-mark-cs-end)).")
|
to and including character (1- go-mode-mark-cs-end)).")
|
||||||
(make-variable-buffer-local 'go-mode-mark-cs-end)
|
(make-variable-buffer-local 'go-mode-mark-cs-end)
|
||||||
|
|
||||||
|
(defvar go-mode-mark-string-end 1
|
||||||
|
"The point at which the string cache ends. The buffer
|
||||||
|
will be marked from the beginning up to this point (that is, up
|
||||||
|
to and including character (1- go-mode-mark-string-end)).")
|
||||||
|
(make-variable-buffer-local 'go-mode-mark-string-end)
|
||||||
|
|
||||||
|
(defvar go-mode-mark-comment-end 1
|
||||||
|
"The point at which the comment cache ends. The buffer
|
||||||
|
will be marked from the beginning up to this point (that is, up
|
||||||
|
to and including character (1- go-mode-mark-comment-end)).")
|
||||||
|
(make-variable-buffer-local 'go-mode-mark-comment-end)
|
||||||
|
|
||||||
(defvar go-mode-mark-nesting-end 1
|
(defvar go-mode-mark-nesting-end 1
|
||||||
"The point at which the nesting cache ends. The buffer will be
|
"The point at which the nesting cache ends. The buffer will be
|
||||||
marked from the beginning up to this point.")
|
marked from the beginning up to this point.")
|
||||||
@ -180,6 +193,24 @@ nesting caches from the modified point on."
|
|||||||
(remove-text-properties
|
(remove-text-properties
|
||||||
b (min go-mode-mark-cs-end (point-max)) '(go-mode-cs nil))
|
b (min go-mode-mark-cs-end (point-max)) '(go-mode-cs nil))
|
||||||
(setq go-mode-mark-cs-end b)))
|
(setq go-mode-mark-cs-end b)))
|
||||||
|
|
||||||
|
(when (<= b go-mode-mark-string-end)
|
||||||
|
;; Remove the property adjacent to the change position.
|
||||||
|
;; It may contain positions pointing beyond the new end mark.
|
||||||
|
(let ((b (let ((cs (get-text-property (max 1 (1- b)) 'go-mode-string)))
|
||||||
|
(if cs (car cs) b))))
|
||||||
|
(remove-text-properties
|
||||||
|
b (min go-mode-mark-string-end (point-max)) '(go-mode-string nil))
|
||||||
|
(setq go-mode-mark-string-end b)))
|
||||||
|
(when (<= b go-mode-mark-comment-end)
|
||||||
|
;; Remove the property adjacent to the change position.
|
||||||
|
;; It may contain positions pointing beyond the new end mark.
|
||||||
|
(let ((b (let ((cs (get-text-property (max 1 (1- b)) 'go-mode-comment)))
|
||||||
|
(if cs (car cs) b))))
|
||||||
|
(remove-text-properties
|
||||||
|
b (min go-mode-mark-string-end (point-max)) '(go-mode-comment nil))
|
||||||
|
(setq go-mode-mark-comment-end b)))
|
||||||
|
|
||||||
(when (< b go-mode-mark-nesting-end)
|
(when (< b go-mode-mark-nesting-end)
|
||||||
(remove-text-properties b (min go-mode-mark-nesting-end (point-max)) '(go-mode-nesting nil))
|
(remove-text-properties b (min go-mode-mark-nesting-end (point-max)) '(go-mode-nesting nil))
|
||||||
(setq go-mode-mark-nesting-end b))))
|
(setq go-mode-mark-nesting-end b))))
|
||||||
@ -237,7 +268,7 @@ directly; use `go-mode-cs'."
|
|||||||
(cond
|
(cond
|
||||||
((looking-at "//")
|
((looking-at "//")
|
||||||
(end-of-line)
|
(end-of-line)
|
||||||
(point))
|
(1+ (point)))
|
||||||
((looking-at "/\\*")
|
((looking-at "/\\*")
|
||||||
(goto-char (+ pos 2))
|
(goto-char (+ pos 2))
|
||||||
(if (search-forward "*/" (1+ end) t)
|
(if (search-forward "*/" (1+ end) t)
|
||||||
@ -273,7 +304,114 @@ directly; use `go-mode-cs'."
|
|||||||
(setq pos end)))))
|
(setq pos end)))))
|
||||||
(setq go-mode-mark-cs-end pos)))))
|
(setq go-mode-mark-cs-end pos)))))
|
||||||
|
|
||||||
|
(defun go-mode-in-comment (&optional pos)
|
||||||
|
"Return the comment/string state at point POS. If point is
|
||||||
|
inside a comment (including the delimiters), this
|
||||||
|
returns a pair (START . END) indicating the extents of the
|
||||||
|
comment or string."
|
||||||
|
|
||||||
|
(unless pos
|
||||||
|
(setq pos (point)))
|
||||||
|
(when (> pos go-mode-mark-comment-end)
|
||||||
|
(go-mode-mark-comment pos))
|
||||||
|
(get-text-property pos 'go-mode-comment))
|
||||||
|
|
||||||
|
(defun go-mode-mark-comment (end)
|
||||||
|
"Mark comments up to point END. Don't call this directly; use `go-mode-in-comment'."
|
||||||
|
(setq end (min end (point-max)))
|
||||||
|
(go-mode-parser
|
||||||
|
(save-match-data
|
||||||
|
(let ((pos
|
||||||
|
;; Back up to the last known state.
|
||||||
|
(let ((last-comment
|
||||||
|
(and (> go-mode-mark-comment-end 1)
|
||||||
|
(get-text-property (1- go-mode-mark-comment-end)
|
||||||
|
'go-mode-comment))))
|
||||||
|
(if last-comment
|
||||||
|
(car last-comment)
|
||||||
|
(max 1 (1- go-mode-mark-comment-end))))))
|
||||||
|
(while (< pos end)
|
||||||
|
(goto-char pos)
|
||||||
|
(let ((comment-end ; end of the text property
|
||||||
|
(cond
|
||||||
|
((looking-at "//")
|
||||||
|
(end-of-line)
|
||||||
|
(1+ (point)))
|
||||||
|
((looking-at "/\\*")
|
||||||
|
(goto-char (+ pos 2))
|
||||||
|
(if (search-forward "*/" (1+ end) t)
|
||||||
|
(point)
|
||||||
|
end)))))
|
||||||
|
(cond
|
||||||
|
(comment-end
|
||||||
|
(put-text-property pos comment-end 'go-mode-comment (cons pos comment-end))
|
||||||
|
(setq pos comment-end))
|
||||||
|
((re-search-forward "/[/*]" end t)
|
||||||
|
(setq pos (match-beginning 0)))
|
||||||
|
(t
|
||||||
|
(setq pos end)))))
|
||||||
|
(setq go-mode-mark-comment-end pos)))))
|
||||||
|
|
||||||
|
(defun go-mode-in-string (&optional pos)
|
||||||
|
"Return the string state at point POS. If point is
|
||||||
|
inside a string (including the delimiters), this
|
||||||
|
returns a pair (START . END) indicating the extents of the
|
||||||
|
comment or string."
|
||||||
|
|
||||||
|
(unless pos
|
||||||
|
(setq pos (point)))
|
||||||
|
(when (> pos go-mode-mark-string-end)
|
||||||
|
(go-mode-mark-string pos))
|
||||||
|
(get-text-property pos 'go-mode-string))
|
||||||
|
|
||||||
|
(defun go-mode-mark-string (end)
|
||||||
|
"Mark strings up to point END. Don't call this
|
||||||
|
directly; use `go-mode-in-string'."
|
||||||
|
(setq end (min end (point-max)))
|
||||||
|
(go-mode-parser
|
||||||
|
(save-match-data
|
||||||
|
(let ((pos
|
||||||
|
;; Back up to the last known state.
|
||||||
|
(let ((last-cs
|
||||||
|
(and (> go-mode-mark-string-end 1)
|
||||||
|
(get-text-property (1- go-mode-mark-string-end)
|
||||||
|
'go-mode-string))))
|
||||||
|
(if last-cs
|
||||||
|
(car last-cs)
|
||||||
|
(max 1 (1- go-mode-mark-string-end))))))
|
||||||
|
(while (< pos end)
|
||||||
|
(goto-char pos)
|
||||||
|
(let ((cs-end ; end of the text property
|
||||||
|
(cond
|
||||||
|
((looking-at "\"")
|
||||||
|
(goto-char (1+ pos))
|
||||||
|
(if (looking-at "[^\"\n\\\\]*\\(\\\\.[^\"\n\\\\]*\\)*\"")
|
||||||
|
(match-end 0)
|
||||||
|
(end-of-line)
|
||||||
|
(point)))
|
||||||
|
((looking-at "'")
|
||||||
|
(goto-char (1+ pos))
|
||||||
|
(if (looking-at "[^'\n\\\\]*\\(\\\\.[^'\n\\\\]*\\)*'")
|
||||||
|
(match-end 0)
|
||||||
|
(end-of-line)
|
||||||
|
(point)))
|
||||||
|
((looking-at "`")
|
||||||
|
(goto-char (1+ pos))
|
||||||
|
(while (if (search-forward "`" end t)
|
||||||
|
(if (eq (char-after) ?`)
|
||||||
|
(goto-char (1+ (point))))
|
||||||
|
(goto-char end)
|
||||||
|
nil))
|
||||||
|
(point)))))
|
||||||
|
(cond
|
||||||
|
(cs-end
|
||||||
|
(put-text-property pos cs-end 'go-mode-string (cons pos cs-end))
|
||||||
|
(setq pos cs-end))
|
||||||
|
((re-search-forward "[\"'`]" end t)
|
||||||
|
(setq pos (match-beginning 0)))
|
||||||
|
(t
|
||||||
|
(setq pos end)))))
|
||||||
|
(setq go-mode-mark-string-end pos)))))
|
||||||
|
|
||||||
(defun go-mode-font-lock-cs (limit comment)
|
(defun go-mode-font-lock-cs (limit comment)
|
||||||
"Helper function for highlighting comment/strings. If COMMENT is t,
|
"Helper function for highlighting comment/strings. If COMMENT is t,
|
||||||
@ -406,21 +544,31 @@ token on the line."
|
|||||||
(when (/= (skip-chars-backward "[:word:]_") 0)
|
(when (/= (skip-chars-backward "[:word:]_") 0)
|
||||||
(not (looking-at go-mode-non-terminating-keywords-regexp)))))))
|
(not (looking-at go-mode-non-terminating-keywords-regexp)))))))
|
||||||
|
|
||||||
|
(defun go-mode-whitespace-p (char)
|
||||||
|
"Is char whitespace in the syntax table for go."
|
||||||
|
(eq 32 (char-syntax char)))
|
||||||
|
|
||||||
(defun go-mode-backward-skip-comments ()
|
(defun go-mode-backward-skip-comments ()
|
||||||
"Skip backward over comments and whitespace."
|
"Skip backward over comments and whitespace."
|
||||||
(when (not (bobp))
|
;; only proceed if point is in a comment or white space
|
||||||
(backward-char))
|
(if (or (go-mode-in-comment)
|
||||||
(while (and (not (bobp))
|
(go-mode-whitespace-p (char-after (point))))
|
||||||
(or (eq 32 (char-syntax (char-after (point))))
|
(let ((loop-guard t))
|
||||||
(go-mode-cs)))
|
(while (and
|
||||||
(skip-syntax-backward "-")
|
loop-guard
|
||||||
(when (and (not (bobp)) (eq 32 (char-syntax (char-after (point)))))
|
(not (bobp)))
|
||||||
(backward-char))
|
|
||||||
(when (go-mode-cs)
|
(cond ((go-mode-whitespace-p (char-after (point)))
|
||||||
(let ((pos (previous-single-property-change (point) 'go-mode-cs)))
|
;; moves point back over any whitespace
|
||||||
(if pos (goto-char pos) (goto-char (point-min))))))
|
(re-search-backward "[^[:space:]]"))
|
||||||
(when (and (not (go-mode-cs)) (eq 32 (char-syntax (char-after (1+ (point))))))
|
|
||||||
(forward-char 1)))
|
((go-mode-in-comment)
|
||||||
|
;; move point to char preceeding current comment
|
||||||
|
(goto-char (1- (car (go-mode-in-comment)))))
|
||||||
|
|
||||||
|
;; not in a comment or whitespace? we must be done.
|
||||||
|
(t (setq loop-guard nil)
|
||||||
|
(forward-char 1)))))))
|
||||||
|
|
||||||
(defun go-mode-indentation ()
|
(defun go-mode-indentation ()
|
||||||
"Compute the ideal indentation level of the current line.
|
"Compute the ideal indentation level of the current line.
|
||||||
@ -467,10 +615,10 @@ indented one level."
|
|||||||
(incf indent tab-width))
|
(incf indent tab-width))
|
||||||
((?\()
|
((?\()
|
||||||
(goto-char (car nest))
|
(goto-char (car nest))
|
||||||
(beginning-of-line)
|
|
||||||
(go-mode-backward-skip-comments)
|
(go-mode-backward-skip-comments)
|
||||||
|
(backward-char)
|
||||||
;; Really just want the token before
|
;; Really just want the token before
|
||||||
(when (looking-back "\\<import\\|const\\|var\\|type"
|
(when (looking-back "\\<import\\|const\\|var\\|type\\|package"
|
||||||
(max (- (point) 7) (point-min)))
|
(max (- (point) 7) (point-min)))
|
||||||
(incf indent tab-width)
|
(incf indent tab-width)
|
||||||
(when first
|
(when first
|
||||||
@ -481,9 +629,13 @@ indented one level."
|
|||||||
(when (looking-at "\\<case\\>\\|\\<default\\>\\|\\w+\\s *:\\(\\S.\\|$\\)")
|
(when (looking-at "\\<case\\>\\|\\<default\\>\\|\\w+\\s *:\\(\\S.\\|$\\)")
|
||||||
(decf indent tab-width))
|
(decf indent tab-width))
|
||||||
|
|
||||||
|
(when (looking-at "\\w+\\s *:.+,\\s *$")
|
||||||
|
(incf indent tab-width))
|
||||||
|
|
||||||
;; Continuation lines are indented 1 level
|
;; Continuation lines are indented 1 level
|
||||||
(beginning-of-line)
|
(beginning-of-line) ; back up to end of previous line
|
||||||
(go-mode-backward-skip-comments)
|
(backward-char)
|
||||||
|
(go-mode-backward-skip-comments) ; back up past any comments
|
||||||
(when (case (char-before)
|
(when (case (char-before)
|
||||||
((nil ?\{ ?:)
|
((nil ?\{ ?:)
|
||||||
;; At the beginning of a block or the statement
|
;; At the beginning of a block or the statement
|
||||||
@ -517,12 +669,15 @@ indented one level."
|
|||||||
"Indent the current line according to `go-mode-indentation'."
|
"Indent the current line according to `go-mode-indentation'."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
|
||||||
|
;; turn off case folding to distinguish keywords from identifiers
|
||||||
|
;; e.g. "default" is a keyword; "Default" can be a variable name.
|
||||||
|
(let ((case-fold-search nil))
|
||||||
(let ((col (go-mode-indentation)))
|
(let ((col (go-mode-indentation)))
|
||||||
(when col
|
(when col
|
||||||
(let ((offset (- (current-column) (current-indentation))))
|
(let ((offset (- (current-column) (current-indentation))))
|
||||||
(indent-line-to col)
|
(indent-line-to col)
|
||||||
(when (> offset 0)
|
(when (> offset 0)
|
||||||
(forward-char offset))))))
|
(forward-char offset)))))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Go mode
|
;; Go mode
|
||||||
|
Loading…
Reference in New Issue
Block a user