summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2021-01-27 07:50:13 +1100
committerGitHub <noreply@github.com>2021-01-27 07:50:13 +1100
commitada43cc56ac2e337cc034f8052d7e5da61268c34 (patch)
treeb8b5f95704695163db359f3d42c1da95cbed91d2
parent43f4a23f89be19549f2e798c2eb0c59925861590 (diff)
fix(lsp): handle mbc properly when formatting (#9273)
-rw-r--r--cli/lsp/language_server.rs82
-rw-r--r--cli/lsp/text.rs56
-rw-r--r--cli/tests/lsp/did_open_notification_mbc_fmt.json12
-rw-r--r--cli/tests/lsp/formatting_request_mbc_fmt.json14
4 files changed, 157 insertions, 7 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 55ae92c00..b322438fa 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -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)
}
}
@@ -1525,6 +1528,81 @@ mod tests {
}
#[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![
("initialize_request.json", LspResponse::RequestAny),
diff --git a/cli/lsp/text.rs b/cli/lsp/text.rs
index 1d350c12f..f444d639e 100644
--- a/cli/lsp/text.rs
+++ b/cli/lsp/text.rs
@@ -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![
@@ -600,6 +608,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";
let b = "abcdefg";
diff --git a/cli/tests/lsp/did_open_notification_mbc_fmt.json b/cli/tests/lsp/did_open_notification_mbc_fmt.json
new file mode 100644
index 000000000..528dad25d
--- /dev/null
+++ b/cli/tests/lsp/did_open_notification_mbc_fmt.json
@@ -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"
+ }
+ }
+}
diff --git a/cli/tests/lsp/formatting_request_mbc_fmt.json b/cli/tests/lsp/formatting_request_mbc_fmt.json
new file mode 100644
index 000000000..f20cc18e6
--- /dev/null
+++ b/cli/tests/lsp/formatting_request_mbc_fmt.json
@@ -0,0 +1,14 @@
+{
+ "jsonrpc": "2.0",
+ "id": 2,
+ "method": "textDocument/formatting",
+ "params": {
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "options": {
+ "tabSize": 2,
+ "insertSpaces": true
+ }
+ }
+}