Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit 317c2b5

Browse files
authored
Merge pull request #1455 from jrobsonchase/fix_clobbered_lines
Fix TextEdit calculation.
2 parents 5b8e99b + c0f4f99 commit 317c2b5

File tree

4 files changed

+33
-29
lines changed

4 files changed

+33
-29
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ rls-vfs = "0.8"
3131

3232
cargo = { git = "https://github.com/rust-lang/cargo", rev = "beb8fcb5248dc2e6aa488af9613216d5ccb31c6a" }
3333
cargo_metadata = "0.7"
34-
clippy_lints = { git = "https://github.com/rust-lang/rust-clippy", rev = "86f73473c8de4598f8ade982dbb9d44f89777c54", optional = true }
34+
clippy_lints = { git = "https://github.com/rust-lang/rust-clippy", rev = "fc96aa036884183ddc68d2659f4633e6f138b4e0", optional = true }
3535
env_logger = "0.6"
3636
failure = "0.1.1"
3737
home = "0.3"

rls/src/actions/format.rs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,6 @@ impl Rustfmt {
7878
NewlineStyle::Native => native,
7979
};
8080

81-
let lsp_line_length = |line: &str| line.chars().map(char::len_utf16).sum();
82-
let line_cols: Vec<usize> = input.lines().map(lsp_line_length).collect();
83-
8481
let output = self.format(input, cfg)?;
8582
let ModifiedLines { chunks } = output.parse().map_err(|_| Error::Failed)?;
8683

@@ -89,23 +86,29 @@ impl Rustfmt {
8986
.map(|item| {
9087
// Rustfmt's line indices are 1-based
9188
let start_line = u64::from(item.line_number_orig) - 1;
92-
let end_line = {
93-
// Could underflow if we don't remove lines and there's only one
94-
let removed = u64::from(item.lines_removed).saturating_sub(1);
95-
start_line + removed
96-
};
97-
let end_col: Option<usize> = line_cols.get(end_line as usize).copied();
98-
let end_col: u64 = end_col.map(|col| col as u64).unwrap_or_else(u64::max_value);
89+
let end_line = start_line + u64::from(item.lines_removed);
90+
91+
let mut new_text = item.lines.join(newline);
92+
93+
// Rustfmt represents an added line as start_line == end_line, new_text == "",
94+
// which is a no-op, so we need to add a terminating newline.
95+
if start_line == end_line && new_text.len() == 0 {
96+
new_text.push_str(newline);
97+
}
98+
99+
// Line deletions are represented as start_line != end_line, new_text == "".
100+
// If we're not deleting a line, there should always be a terminating newline.
101+
let delete_only = start_line != end_line && new_text.len() == 0;
102+
if !delete_only && !new_text.ends_with(newline) {
103+
new_text.push_str(newline);
104+
}
99105

100106
TextEdit {
101107
range: Range {
102108
start: Position::new(start_line, 0),
103-
// We don't extend the range past the last line because
104-
// sometimes it may not exist, skewing the diff and
105-
// making us add an invalid additional trailing newline.
106-
end: Position::new(end_line, end_col),
109+
end: Position::new(end_line, 0),
107110
},
108-
new_text: item.lines.join(newline),
111+
new_text,
109112
}
110113
})
111114
.collect())
@@ -232,13 +235,13 @@ mod tests {
232235
)
233236
}
234237
// Handle single-line text wrt. added/removed trailing newline
235-
test_case("fn main() {} ", vec![(0, 0, 0, 13, "fn main() {}\n")]);
236-
test_case("fn main() {} \n", vec![(0, 0, 0, 13, "fn main() {}")]);
237-
test_case("\nfn main() {} \n", vec![(0, 0, 1, 13, "fn main() {}")]);
238+
test_case("fn main() {} ", vec![(0, 0, 1, 0, "fn main() {}\n")]);
239+
test_case("fn main() {} \n", vec![(0, 0, 1, 0, "fn main() {}\n")]);
240+
test_case("\nfn main() {} \n", vec![(0, 0, 2, 0, "fn main() {}\n")]);
238241
// Check that we send two separate edits
239242
test_case(
240243
" struct Upper ;\n\nstruct Lower ;",
241-
vec![(0, 0, 0, 16, "struct Upper;"), (2, 0, 2, 14, "struct Lower;\n")],
244+
vec![(0, 0, 1, 0, "struct Upper;\n"), (2, 0, 3, 0, "struct Lower;\n")],
242245
);
243246
}
244247
}

tests/client.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,9 +1765,9 @@ fn client_reformat() {
17651765
assert_eq!(result.unwrap()[0], TextEdit {
17661766
range: Range {
17671767
start: Position { line: 0, character: 0 },
1768-
end: Position { line: 1, character: 69 },
1768+
end: Position { line: 2, character: 0 },
17691769
},
1770-
new_text: "pub mod foo;\npub fn main() {\n let world = \"world\";\n println!(\"Hello, {}!\", world);\n}".to_string(),
1770+
new_text: "pub mod foo;\npub fn main() {\n let world = \"world\";\n println!(\"Hello, {}!\", world);\n}\n".to_string(),
17711771
});
17721772
}
17731773

@@ -1804,14 +1804,15 @@ fn client_reformat_with_range() {
18041804
let newline = if cfg!(windows) { "\r\n" } else { "\n" };
18051805
let formatted = r#"pub fn main() {
18061806
let world1 = "world";
1807-
println!("Hello, {}!", world1);"#
1808-
.replace("\r", "")
1809-
.replace("\n", newline);
1807+
println!("Hello, {}!", world1);
1808+
"#
1809+
.replace("\r", "")
1810+
.replace("\n", newline);
18101811

18111812
let edits = result.unwrap();
18121813
assert_eq!(edits.len(), 2);
18131814
assert_eq!(edits[0].new_text, formatted);
1814-
assert_eq!(edits[1].new_text, "");
1815+
assert_eq!(edits[1].new_text, newline);
18151816
}
18161817

18171818
#[test]

0 commit comments

Comments
 (0)