Skip to content

Indent inside strings after line-ending backslash #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 121 additions & 2 deletions rust-mode-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ very very very long string
*/"
))

(defun test-indent (indented)
(let ((deindented (replace-regexp-in-string "^[[:blank:]]*" " " indented)))
(defun test-indent (indented &optional deindented)
(let ((deindented (or deindented (replace-regexp-in-string "^[[:blank:]]*" " " indented))))
(rust-test-manip-code
deindented
1
Expand Down Expand Up @@ -1207,3 +1207,122 @@ impl Foo for Bar {
}
"
))

(ert-deftest test-indent-string-with-eol-backslash ()
(test-indent
"
pub fn foo() {
format!(\"abc \\
def\")
}
"
))

(ert-deftest test-indent-string-with-eol-backslash-at-start ()
(test-indent
"
pub fn foo() {
format!(\"\\
abc \\
def\")
}
"
))

(ert-deftest test-indent-string-without-eol-backslash-indent-is-not-touched ()
(test-indent
"
pub fn foo() {
format!(\"
abc
def\");
}

pub fn foo() {
format!(\"la la la
la
la la\");
}
"
;; Should still indent the code parts but leave the string internals alone:
"
pub fn foo() {
format!(\"
abc
def\");
}

pub fn foo() {
format!(\"la la la
la
la la\");
}
"
))

(ert-deftest test-indent-string-eol-backslash-mixed-with-literal-eol ()
(test-indent
"
fn foo() {
println!(\"
Here is the beginning of the string
and here is a line that is arbitrarily indented \\
and a continuation of that indented line
and another arbitrary indentation
still another
yet another \\
with a line continuing it
And another line not indented
\")
}
"
"
fn foo() {
println!(\"
Here is the beginning of the string
and here is a line that is arbitrarily indented \\
and a continuation of that indented line
and another arbitrary indentation
still another
yet another \\
with a line continuing it
And another line not indented
\")
}
"))

(ert-deftest test-indent-string-eol-backslash-dont-touch-raw-strings ()
(test-indent
"
pub fn foo() {
format!(r\"\
abc\
def\");
}

pub fn foo() {
format!(r\"la la la
la\
la la\");
}
"
;; Should still indent the code parts but leave the string internals alone:
"
pub fn foo() {
format!(r\"\
abc\
def\");
}

pub fn foo() {
format!(r\"la la la
la\
la la\");
}
"
))

(ert-deftest indent-inside-string-first-line ()
(test-indent
;; Needs to leave 1 space before "world"
"\"hello \\\n world\""))
65 changes: 57 additions & 8 deletions rust-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
;; be undone via tab.

(when (looking-at (concat "\s*\." rust-re-ident))
(previous-logical-line)
(forward-line -1)
(end-of-line)

(let
Expand Down Expand Up @@ -164,10 +164,58 @@
(when rust-indent-method-chain
(rust-align-to-method-chain))
(save-excursion
(rust-rewind-irrelevant)
(backward-up-list)
(rust-rewind-to-beginning-of-current-level-expr)
(+ (current-column) rust-indent-offset))))))
(cond
;; Indent inside a non-raw string only if the the previous line
;; ends with a backslash that is is inside the same string
((nth 3 (syntax-ppss))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how "well known and unchangable" are these indices? it feels like it'd be more obvious what's happening here if we at least used symbolic names.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I see, it's returning into some crazy tuple...ok.

(let*
((string-begin-pos (nth 8 (syntax-ppss)))
(end-of-prev-line-pos (when (> (line-number-at-pos) 1)
(save-excursion
(forward-line -1)
(end-of-line)
(point)))))
(when
(and
;; If the string begins with an "r" it's a raw string and
;; we should not change the indentation
(/= ?r (char-after string-begin-pos))

;; If we're on the first line this will be nil and the
;; rest does not apply
end-of-prev-line-pos

;; The end of the previous line needs to be inside the
;; current string...
(> end-of-prev-line-pos string-begin-pos)

;; ...and end with a backslash
(= ?\\ (char-before end-of-prev-line-pos)))

;; Indent to the same level as the previous line, or the
;; start of the string if the previous line starts the string
(if (= (line-number-at-pos end-of-prev-line-pos) (line-number-at-pos string-begin-pos))
;; The previous line is the start of the string.
;; If the backslash is the only character after the
;; string beginning, indent to the next indent
;; level. Otherwise align with the start of the string.
(if (> (- end-of-prev-line-pos string-begin-pos) 2)
(save-excursion
(goto-char (+ 1 string-begin-pos))
(current-column))
baseline)

;; The previous line is not the start of the string, so
;; match its indentation.
(save-excursion
(goto-char end-of-prev-line-pos)
(back-to-indentation)
(current-column))))))

;; A function return type is indented to the corresponding function arguments
((looking-at "->")
(save-excursion
Expand Down Expand Up @@ -223,13 +271,14 @@
;; so add one additional indent level
(+ baseline rust-indent-offset))))))))))

;; If we're at the beginning of the line (before or at the current
;; indentation), jump with the indentation change. Otherwise, save the
;; excursion so that adding the indentations will leave us at the
;; equivalent position within the line to where we were before.
(if (<= (current-column) (current-indentation))
(indent-line-to indent)
(save-excursion (indent-line-to indent)))))
(when indent
;; If we're at the beginning of the line (before or at the current
;; indentation), jump with the indentation change. Otherwise, save the
;; excursion so that adding the indentations will leave us at the
;; equivalent position within the line to where we were before.
(if (<= (current-column) (current-indentation))
(indent-line-to indent)
(save-excursion (indent-line-to indent))))))


;; Font-locking definitions and helpers
Expand Down