Commit bf9620eb authored by Ben Fried's avatar Ben Fried Committed by Russ Cox

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
parent b485629e
...@@ -110,6 +110,7 @@ built-ins, functions, and some types.") ...@@ -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 ...@@ -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." ...@@ -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'." ...@@ -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'." ...@@ -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." ...@@ -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." ...@@ -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." ...@@ -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." ...@@ -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)
(let ((col (go-mode-indentation))) ;; turn off case folding to distinguish keywords from identifiers
(when col ;; e.g. "default" is a keyword; "Default" can be a variable name.
(let ((offset (- (current-column) (current-indentation)))) (let ((case-fold-search nil))
(indent-line-to col) (let ((col (go-mode-indentation)))
(when (> offset 0) (when col
(forward-char offset)))))) (let ((offset (- (current-column) (current-indentation))))
(indent-line-to col)
(when (> offset 0)
(forward-char offset)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Go mode ;; Go mode
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment