fix(lsp): handle mbc properly when formatting (#9273)

This commit is contained in:
Kitson Kelly 2021-01-27 07:50:13 +11:00 committed by GitHub
parent 43f4a23f89
commit ada43cc56a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 157 additions and 7 deletions

View file

@ -669,7 +669,7 @@ impl Inner {
)
})?
.unwrap();
let line_index = self.documents.line_index(&specifier);
let file_path =
if let Ok(file_path) = params.text_document.uri.to_file_path() {
file_path
@ -685,7 +685,9 @@ impl Inner {
// TODO(@kitsonk) this could be handled better in `cli/tools/fmt.rs` in the
// future.
match dprint::format_text(&file_path, &file_text, &config) {
Ok(new_text) => Some(text::get_edits(&file_text, &new_text)),
Ok(new_text) => {
Some(text::get_edits(&file_text, &new_text, line_index))
}
Err(err) => {
warn!("Format error: {}", err);
None
@ -702,6 +704,7 @@ impl Inner {
Ok(Some(text_edits))
}
} else {
self.client.show_message(MessageType::Warning, format!("Unable to format \"{}\". Likely due to unrecoverable syntax errors in the file.", specifier)).await;
Ok(None)
}
}
@ -1524,6 +1527,81 @@ mod tests {
harness.run().await;
}
#[tokio::test]
async fn test_format_mbc() {
let mut harness = LspTestHarness::new(vec![
("initialize_request.json", LspResponse::RequestAny),
("initialized_notification.json", LspResponse::None),
("did_open_notification_mbc_fmt.json", LspResponse::None),
(
"formatting_request_mbc_fmt.json",
LspResponse::Request(
2,
json!([
{
"range": {
"start": {
"line": 0,
"character": 12
},
"end": {
"line": 0,
"character": 13,
}
},
"newText": "\""
},
{
"range": {
"start": {
"line": 0,
"character": 21
},
"end": {
"line": 0,
"character": 22
}
},
"newText": "\";"
},
{
"range": {
"start": {
"line": 1,
"character": 12,
},
"end": {
"line": 1,
"character": 13,
}
},
"newText": "\""
},
{
"range": {
"start": {
"line": 1,
"character": 23,
},
"end": {
"line": 1,
"character": 25,
}
},
"newText": "\");"
}
]),
),
),
(
"shutdown_request.json",
LspResponse::Request(3, json!(null)),
),
("exit_notification.json", LspResponse::None),
]);
harness.run().await;
}
#[tokio::test]
async fn test_large_doc_change() {
let mut harness = LspTestHarness::new(vec![

View file

@ -181,8 +181,8 @@ impl LineIndex {
/// Returns a u16 position based on a u8 offset.
pub fn position_utf16(&self, offset: TextSize) -> lsp_types::Position {
let line = partition_point(&self.utf8_offsets, |&it| it <= offset) - 1;
let line_start_offset = self.utf8_offsets[line];
let line = partition_point(&self.utf16_offsets, |&it| it <= offset) - 1;
let line_start_offset = self.utf16_offsets[line];
let col = offset - line_start_offset;
lsp_types::Position {
@ -208,13 +208,21 @@ impl LineIndex {
/// Compare two strings and return a vector of text edit records which are
/// supported by the Language Server Protocol.
pub fn get_edits(a: &str, b: &str) -> Vec<TextEdit> {
pub fn get_edits(
a: &str,
b: &str,
maybe_line_index: Option<LineIndex>,
) -> Vec<TextEdit> {
if a == b {
return vec![];
}
let chunks = diff(a, b);
let mut text_edits = Vec::<TextEdit>::new();
let line_index = LineIndex::new(a);
let line_index = if let Some(line_index) = maybe_line_index {
line_index
} else {
LineIndex::new(a)
};
let mut iter = chunks.iter().peekable();
let mut a_pos = TextSize::from(0);
loop {
@ -565,7 +573,7 @@ const C: char = \"メ メ\";
fn test_get_edits() {
let a = "abcdefg";
let b = "a\nb\nchije\nfg\n";
let actual = get_edits(a, b);
let actual = get_edits(a, b, None);
assert_eq!(
actual,
vec![
@ -599,6 +607,44 @@ const C: char = \"メ メ\";
);
}
#[test]
fn test_get_edits_mbc() {
let a = "const bar = \"👍🇺🇸😃\";\nconsole.log('hello deno')\n";
let b = "const bar = \"👍🇺🇸😃\";\nconsole.log(\"hello deno\");\n";
let actual = get_edits(a, b, None);
assert_eq!(
actual,
vec![
TextEdit {
range: lsp_types::Range {
start: lsp_types::Position {
line: 1,
character: 12
},
end: lsp_types::Position {
line: 1,
character: 13
}
},
new_text: "\"".to_string()
},
TextEdit {
range: lsp_types::Range {
start: lsp_types::Position {
line: 1,
character: 23
},
end: lsp_types::Position {
line: 1,
character: 25
}
},
new_text: "\");".to_string()
},
]
)
}
#[test]
fn test_get_range_change() {
let a = "abcdefg";

View file

@ -0,0 +1,12 @@
{
"jsonrpc": "2.0",
"method": "textDocument/didOpen",
"params": {
"textDocument": {
"uri": "file:///a/file.ts",
"languageId": "typescript",
"version": 1,
"text": "const bar = '👍🇺🇸😃'\nconsole.log('hello deno')\n"
}
}
}

View file

@ -0,0 +1,14 @@
{
"jsonrpc": "2.0",
"id": 2,
"method": "textDocument/formatting",
"params": {
"textDocument": {
"uri": "file:///a/file.ts"
},
"options": {
"tabSize": 2,
"insertSpaces": true
}
}
}