feat: migrate LSP to opt-in native language servers
This commit is contained in:
Executable → Regular
+102
-9
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
path::PathBuf,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
@@ -17,7 +17,7 @@ use vamp::{
|
||||
|
||||
static NEXT_FIXTURE: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
// A real subprocess speaking framed LSP, not a plugin echoing generic effects.
|
||||
// A real subprocess speaking framed LSP to the native client.
|
||||
// Files are explicit test-controlled gates; no wall-clock ordering assumptions.
|
||||
const SERVER: &str = r#"
|
||||
require 'json'
|
||||
@@ -213,13 +213,14 @@ impl Fixture {
|
||||
self.alternate
|
||||
])
|
||||
};
|
||||
let options = json!({"servers": [{
|
||||
"language_id": "rust", "extensions": ["rs"], "command": command,
|
||||
}]});
|
||||
let plugin = Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/plugins/lsp.rb");
|
||||
let options = json!({
|
||||
"extensions": if mode == "irrelevant" { vec!["myl"] } else { vec!["rs"] },
|
||||
"command": command,
|
||||
"initialization_options": {"fixture": true},
|
||||
"settings": {"rust-analyzer": {"cargo": {"allFeatures": true}}},
|
||||
});
|
||||
let config = format!(
|
||||
"Vamp.configure do |config|\n config.clipboard_mode = 'separate'\n config.plugin {}, options: JSON.parse({})\nend\n",
|
||||
serde_json::to_string(&plugin).unwrap(),
|
||||
"Vamp.configure do |config|\n config.clipboard_mode = 'separate'\n config.lsp['fixture-language'] = JSON.parse({})\nend\n",
|
||||
serde_json::to_string(&options.to_string()).unwrap(),
|
||||
);
|
||||
let config_path = self.root.join("config.rb");
|
||||
@@ -323,6 +324,10 @@ fn lsp_framing_lifecycle_diagnostics_and_unicode_dirty_definition() {
|
||||
initialize["params"]["capabilities"]["general"]["positionEncodings"],
|
||||
json!(["utf-16"])
|
||||
);
|
||||
assert_eq!(
|
||||
initialize["params"]["initializationOptions"],
|
||||
json!({"fixture": true})
|
||||
);
|
||||
assert_eq!(
|
||||
initialize["params"]["capabilities"]["textDocument"]["publishDiagnostics"]["versionSupport"],
|
||||
true
|
||||
@@ -340,6 +345,10 @@ fn lsp_framing_lifecycle_diagnostics_and_unicode_dirty_definition() {
|
||||
.position(|frame| frame["method"] == "initialized")
|
||||
.unwrap();
|
||||
assert!(initialized_index < open_index);
|
||||
assert_eq!(
|
||||
frames[open_index]["params"]["textDocument"]["languageId"],
|
||||
"fixture-language"
|
||||
);
|
||||
assert_eq!(
|
||||
frames[open_index]["params"]["textDocument"]["text"],
|
||||
"A😀e\u{301}Z\n"
|
||||
@@ -368,7 +377,7 @@ fn lsp_framing_lifecycle_diagnostics_and_unicode_dirty_definition() {
|
||||
.iter()
|
||||
.find(|frame| frame["id"] == "settings")
|
||||
.unwrap()["result"],
|
||||
json!([null, null])
|
||||
json!([{"cargo": {"allFeatures": true}}, null])
|
||||
);
|
||||
assert_eq!(
|
||||
frames.iter().find(|frame| frame["id"] == 0).unwrap()["error"]["code"],
|
||||
@@ -698,3 +707,87 @@ fn lsp_optional_configuration_numeric_sync_and_unversioned_diagnostics() {
|
||||
assert_eq!(fixture.method_count("textDocument/didChange"), 0);
|
||||
assert_eq!(fixture.method_count("textDocument/didSave"), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_definition_reuses_dirty_targets_without_an_enabled_target_language() {
|
||||
let mut fixture = Fixture::new();
|
||||
let target = fixture.target.with_extension("txt");
|
||||
fs::rename(&fixture.target, &target).unwrap();
|
||||
fixture.target = target;
|
||||
let mut session = fixture.open("basic");
|
||||
until(&mut session, &fixture, |session| {
|
||||
session.editor().diagnostics().count() == 2
|
||||
});
|
||||
let target_id = edit_target(&mut session, &fixture);
|
||||
session.execute("lsp_definition");
|
||||
until(&mut session, &fixture, |session| {
|
||||
session.editor().buffer_id() == target_id
|
||||
});
|
||||
assert_eq!(session.editor().cursor(), Cursor { row: 0, column: 1 });
|
||||
assert_eq!(session.editor().lines(), &["😀e\u{301}disk", ""]);
|
||||
assert!(session.editor().dirty());
|
||||
assert_eq!(fs::read_to_string(&fixture.target).unwrap(), "disk\n");
|
||||
assert_eq!(fixture.method_count("textDocument/didOpen"), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_definition_does_not_move_a_caret_that_has_moved_since_the_request() {
|
||||
let fixture = Fixture::new();
|
||||
let mut session = fixture.open("stale");
|
||||
until(&mut session, &fixture, |session| {
|
||||
session.editor().diagnostics().count() == 2
|
||||
});
|
||||
session.execute("lsp_definition");
|
||||
until(&mut session, &fixture, |_| {
|
||||
fixture.method_count("textDocument/definition") == 1
|
||||
});
|
||||
session.handle(Input::Right);
|
||||
fixture.release();
|
||||
until(&mut session, &fixture, |session| {
|
||||
session
|
||||
.editor()
|
||||
.message()
|
||||
.contains("stale response complete")
|
||||
});
|
||||
assert_eq!(session.editor().buffer_id(), 1);
|
||||
assert_eq!(session.editor().buffer_count(), 1);
|
||||
assert_eq!(session.editor().cursor(), Cursor { row: 0, column: 1 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_only_starts_an_explicitly_configured_server_when_a_matching_buffer_opens() {
|
||||
let fixture = Fixture::new();
|
||||
let mut session = fixture.open("irrelevant");
|
||||
session.execute("lsp_diagnostics");
|
||||
until(&mut session, &fixture, |session| {
|
||||
session.editor().message().contains("no running server")
|
||||
});
|
||||
assert!(!fixture.log.exists());
|
||||
let custom = fixture.root.join("custom.myl");
|
||||
fs::write(&custom, "custom language\n").unwrap();
|
||||
session.execute(&format!("edit {}", custom.display()));
|
||||
until(&mut session, &fixture, |_| {
|
||||
fixture.method_count("textDocument/didOpen") == 1
|
||||
});
|
||||
let frames = fixture.frames();
|
||||
let open = frames
|
||||
.iter()
|
||||
.find(|frame| frame["method"] == "textDocument/didOpen")
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
open["params"]["textDocument"]["languageId"],
|
||||
"fixture-language"
|
||||
);
|
||||
assert_eq!(open["params"]["textDocument"]["text"], "custom language\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_session_shutdown_finishes_the_server_protocol_before_returning() {
|
||||
let fixture = Fixture::new();
|
||||
let mut session = fixture.open("basic");
|
||||
until(&mut session, &fixture, |session| {
|
||||
session.editor().diagnostics().count() == 2
|
||||
});
|
||||
drop(session);
|
||||
assert_eq!(fixture.method_count("shutdown"), 1);
|
||||
}
|
||||
Reference in New Issue
Block a user