branch: elpa/go-mode
commit 3ba198280bf8d5f2a4079618abfd3db2ebe04f58
Author: Muir Manders <[email protected]>
Commit: Peter Sanford <[email protected]>
Handle indentation for nested dangling operators
The dangling indent level increases for nested dangling expressions:
foo ||
(bar ||
baz)
Previously we only allowed a single extra indent from dangling
operators. Now when indenting the line after a dangling operator we
use the newly added go--dangling-line-opens-indent-p to determine if
the dangling line opened a new indent level.
foo ||
(bar ||
baz)
is now indented properly as
foo ||
(bar ||
baz)
When indenting the statement following the final dangling line we go
back to the first non-dangling line to determine the indent. For
example, in cases like:
if foo ||
(bar ||
baz) {
// now we indent here
// instead of here
}
Closes: #279 [via git-merge-pr]
---
go-mode.el | 85 +++++++++++++++++-----
.../indentation_tests/dangling_operator.go | 5 ++
test/testdata/indentation_tests/multiline_if.go | 53 +++++++++++++-
3 files changed, 119 insertions(+), 24 deletions(-)
diff --git a/go-mode.el b/go-mode.el
index 009f349..f1b467d 100644
--- a/go-mode.el
+++ b/go-mode.el
@@ -591,20 +591,58 @@ current line will be returned."
(current-indentation))
(current-indentation))))
-(defun go--line-opens-paren-p ()
- "Returns whether current line opens a paren that contains point."
+(defun go--dangling-line-opens-indent-p ()
+ "Return non-nil if current dangling line indents the following line."
(save-excursion
- (let ((start-paren-level (go-paren-level))
- (line-beginning (line-beginning-position)))
+ (let ((line-begin (line-beginning-position))
+ (start-paren-level (go-paren-level)))
+
(go-goto-opening-parenthesis)
- (and
- (eq (char-after) ?\() ; opening paren-like character is actually a paren
- (< (go-paren-level) start-paren-level) ; point is before the closing
paren
- (>= (point) line-beginning))))) ; still on starting line
+
+ (let ((in-parens (and
+ ;; opening paren-like character is actually a paren
+ (eq (char-after) ?\()
+ ;; point is before the closing paren
+ (< (go-paren-level) start-paren-level)
+ ;; still on starting line
+ (>= (point) line-begin))))
+
+ (if (not in-parens)
+ ;; if line doesn't open a paren, check if we are a dangling line
under
+ ;; a dangling assignment with nothing on RHS of "="
+ ;;
+ ;; foo :=
+ ;; bar || // check if we are this line (need to open indent)
+ ;; baz ||
+ ;; qux
+ (progn
+ (goto-char line-begin)
+ (let ((prev-line (go-previous-line-has-dangling-op-p)))
+ (when prev-line
+ (goto-char prev-line)
+ (and
+ (not (go-previous-line-has-dangling-op-p))
+ (looking-at ".*=[[:space:]]*$")))))
+ (or
+ ;; previous line is dangling and opens indent
+ (let ((prev-line (go-previous-line-has-dangling-op-p)))
+ (when prev-line
+ (save-excursion
+ (goto-char prev-line)
+ (end-of-line)
+ (go--dangling-line-opens-indent-p))))
+
+ ;; or paren is only preceded by identifier or other parens
+ (string-match-p "^[[:space:]]*[[:word:][:multibyte:]]*(*$"
(buffer-substring line-begin (point)))
+
+ ;; or a preceding paren on this line opens an indent
+ (and
+ (> (point) line-begin)
+ (progn (backward-char) (go--dangling-line-opens-indent-p)))))))))
(defun go-indentation-at-point ()
(save-excursion
- (let (start-nesting)
+ (let (start-nesting dangling-line)
(back-to-indentation)
(setq start-nesting (go-paren-level))
@@ -614,31 +652,38 @@ current line will be returned."
((looking-at "[])}]")
(go-goto-opening-parenthesis)
(if (and
- (not (eq (char-after) ?\()) ; opening parens always indent
+ (not (eq (char-after) ?\())
(go-previous-line-has-dangling-op-p))
- (- (current-indentation) tab-width)
+ (go--non-dangling-indent)
(go--indentation-for-opening-parenthesis)))
- ((progn (go--backward-irrelevant t)
- (looking-back go-dangling-operators-regexp
- (- (point) go--max-dangling-operator-length)))
+ ((setq dangling-line (go-previous-line-has-dangling-op-p))
+ (goto-char dangling-line)
+ (end-of-line)
+
;; only one nesting for all dangling operators in one operation
(if (and
- (not (go--line-opens-paren-p))
+ (not (go--dangling-line-opens-indent-p))
(go-previous-line-has-dangling-op-p))
- (progn
- (current-indentation))
+ (current-indentation)
(+ (current-indentation) tab-width)))
((zerop (go-paren-level))
0)
((progn (go-goto-opening-parenthesis) (< (go-paren-level)
start-nesting))
(if (and
- (not (eq (char-after) ?\()) ; opening parens always indent
+ (not (eq (char-after) ?\())
(go-previous-line-has-dangling-op-p))
- (current-indentation)
- (+ (go--indentation-for-opening-parenthesis) tab-width)))
+ (+ (go--non-dangling-indent) tab-width)
+ (+ (go--indentation-for-opening-parenthesis) tab-width))
+ )
(t
(current-indentation))))))
+(defun go--non-dangling-indent ()
+ (save-excursion
+ (while (go-previous-line-has-dangling-op-p)
+ (forward-line -1))
+ (current-indentation)))
+
(defun go-mode-indent-line ()
(interactive)
(let (indent
diff --git a/test/testdata/indentation_tests/dangling_operator.go
b/test/testdata/indentation_tests/dangling_operator.go
index 6eff406..281ea53 100644
--- a/test/testdata/indentation_tests/dangling_operator.go
+++ b/test/testdata/indentation_tests/dangling_operator.go
@@ -35,5 +35,10 @@ func init() {
3 *
1)
+ i :=
+ "" != "" ||
+ true == false ||
+ false == false
+
return
}
diff --git a/test/testdata/indentation_tests/multiline_if.go
b/test/testdata/indentation_tests/multiline_if.go
index 410704d..d73ae74 100644
--- a/test/testdata/indentation_tests/multiline_if.go
+++ b/test/testdata/indentation_tests/multiline_if.go
@@ -1,5 +1,50 @@
-if realLength == -1 &&
- !chunked(t.TransferEncoding) &&
- bodyAllowedForStatus(t.StatusCode) {
- t.Close = true
+package foo
+
+import (
+ "bytes"
+ "errors"
+)
+
+func _() {
+ if realLength == -1 &&
+ !chunked(t.TransferEncoding) &&
+ bodyAllowedForStatus(t.StatusCode) {
+ t.Close = true
+ }
+
+ if true &&
+ (true ||
+ true && (true ||
+ false) && true) {
+ true
+ }
+
+ if true && (true &&
+ true) {
+ true
+ }
+
+ if true &&
+ (true && (true ||
+ false) && true) {
+ true
+ }
+
+ if true &&
+ foo(true &&
+ true) {
+ true
+ }
+
+ if true &&
+ true && (true ||
+ true) {
+ true
+ }
+
+ if bytes.Contains(out, []byte("-fsanitize")) &&
+ (bytes.Contains(out, []byte("unrecognized")) ||
+ bytes.Contains(out, []byte("unsupported"))) {
+ return true, errors.New(string(out))
+ }
}