Skip to content
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
9 changes: 9 additions & 0 deletions cli/lsp/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,13 @@ pub struct WorkspaceSettings {
#[serde(default = "default_document_preload_limit")]
pub document_preload_limit: usize,

/// Disables the server-capability for pull diagnostics to force push-based
/// diagnostics. NOTE: This is read and stored from the initialization
/// options. This value may be updated on configuration change events but
/// the new value will be ignored.
#[serde(default)]
pub force_push_based_diagnostics: bool,

#[serde(default)]
pub suggest: DenoCompletionSettings,

Expand Down Expand Up @@ -626,6 +633,7 @@ impl Default for WorkspaceSettings {
log_file: false,
lint: true,
document_preload_limit: default_document_preload_limit(),
force_push_based_diagnostics: false,
suggest: Default::default(),
testing: Default::default(),
tls_certificate: None,
Expand Down Expand Up @@ -2145,6 +2153,7 @@ mod tests {
log_file: false,
lint: true,
document_preload_limit: 1_000,
force_push_based_diagnostics: false,
suggest: DenoCompletionSettings {
imports: ImportCompletionSettings {
auto_discover: true,
Expand Down
29 changes: 20 additions & 9 deletions cli/lsp/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ pub struct Inner {
project_version: usize,
/// A collection of measurements which instrument that performance of the LSP.
performance: Arc<Performance>,
force_push_based_diagnostics: bool,
registered_semantic_tokens_capabilities: bool,
pub resolver: Arc<LspResolver>,
task_queue: LanguageServerTaskQueue,
Expand Down Expand Up @@ -608,6 +609,7 @@ impl Inner {
npm_search_api,
performance,
registered_semantic_tokens_capabilities: false,
force_push_based_diagnostics: false,
resolver: Default::default(),
ts_fixable_diagnostics: Default::default(),
ts_server,
Expand Down Expand Up @@ -894,6 +896,10 @@ impl Inner {
}));
self.registered_semantic_tokens_capabilities = true;
}

fn is_using_push_based_diagnostics(&self) -> bool {
self.force_push_based_diagnostics || !self.config.diagnostic_capable()
}
}

// lspower::LanguageServer methods. This file's LanguageServer delegates to us.
Expand All @@ -910,8 +916,6 @@ impl Inner {
parent_process_checker::start(parent_pid)
}

let capabilities = capabilities::server_capabilities(&params.capabilities);

let version = format!(
"{} ({}, {})",
DENO_VERSION_INFO.deno,
Expand Down Expand Up @@ -982,15 +986,15 @@ impl Inner {
}
self.config.set_workspace_folders(workspace_folders);
if let Some(options) = params.initialization_options {
self.config.set_workspace_settings(
WorkspaceSettings::from_initialization_options(options),
vec![],
);
let settings = WorkspaceSettings::from_initialization_options(options);
self.force_push_based_diagnostics =
settings.force_push_based_diagnostics;
self.config.set_workspace_settings(settings, vec![]);
}
self.config.set_client_capabilities(params.capabilities);
}

if !self.config.diagnostic_capable() {
if self.is_using_push_based_diagnostics() {
let mut diagnostics_server = DiagnosticsServer::new(
self.client.clone(),
self.performance.clone(),
Expand All @@ -1006,6 +1010,13 @@ impl Inner {
self.update_tracing();
self.update_debug_flag();

let mut capabilities =
capabilities::server_capabilities(&self.config.client_capabilities);

if self.force_push_based_diagnostics {
capabilities.diagnostic_provider = None;
}

if capabilities.semantic_tokens_provider.is_some() {
self.registered_semantic_tokens_capabilities = true;
}
Expand Down Expand Up @@ -1728,7 +1739,7 @@ impl Inner {
);
self.ts_server.cleanup_semantic_cache(self.snapshot()).await;
self.send_diagnostics_update();
if self.config.diagnostic_capable()
if !self.is_using_push_based_diagnostics()
&& self.config.diagnostic_refresh_capable()
{
self.client.refresh_diagnostics();
Expand Down Expand Up @@ -4850,7 +4861,7 @@ impl Inner {
self.project_changed(vec![], ProjectScopesChange::Config);
self.ts_server.cleanup_semantic_cache(self.snapshot()).await;
self.send_diagnostics_update();
if self.config.diagnostic_capable()
if !self.is_using_push_based_diagnostics()
&& self.config.diagnostic_refresh_capable()
{
self.client.refresh_diagnostics();
Expand Down
1 change: 1 addition & 0 deletions cli/lsp/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ pub fn get_repl_workspace_settings() -> WorkspaceSettings {
log_file: false,
lint: false,
document_preload_limit: 0, // don't pre-load any modules as it's expensive and not useful for the repl
force_push_based_diagnostics: false,
tls_certificate: None,
unsafely_ignore_certificate_errors: None,
unstable: Default::default(),
Expand Down
93 changes: 93 additions & 0 deletions tests/integration/lsp_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19810,6 +19810,99 @@ fn lsp_push_diagnostics() {
);
}

#[test(timeout = 300)]
fn lsp_force_push_based_diagnostics_setting() {
let context = TestContextBuilder::new().use_temp_cwd().build();
let mut client = context.new_lsp_command().build();
client.initialize(|builder| {
builder.set_force_push_based_diagnostics(true);
});
client.did_open(json!({
"textDocument": {
"uri": "file:///a/file1.ts",
"languageId": "typescript",
"version": 1,
"text": r#"
const foo: string = 1;
foo;
"#,
},
}));
client.did_open(json!({
"textDocument": {
"uri": "file:///a/file2.ts",
"languageId": "typescript",
"version": 1,
"text": r#"
import "foo";
"#,
},
}));
let diagnostics = client.did_open(json!({
"textDocument": {
"uri": "file:///a/file3.ts",
"languageId": "typescript",
"version": 1,
"text": r#"
// @ts-ignore
"#,
},
}));
assert_eq!(
json!(diagnostics.all_messages()),
json!([
{
"uri": "file:///a/file1.ts",
"diagnostics": [
{
"range": {
"start": { "line": 1, "character": 14 },
"end": { "line": 1, "character": 17 },
},
"severity": 1,
"code": 2322,
"source": "deno-ts",
"message": "Type 'number' is not assignable to type 'string'.",
},
],
"version": 1,
},
{
"uri": "file:///a/file2.ts",
"diagnostics": [
{
"range": {
"start": { "line": 1, "character": 15 },
"end": { "line": 1, "character": 20 },
},
"severity": 1,
"code": "import-prefix-missing",
"source": "deno",
"message": "Import \"foo\" not a dependency\n hint: If you want to use the npm package, try running `deno add npm:foo`",
},
],
"version": 1,
},
{
"uri": "file:///a/file3.ts",
"diagnostics": [
{
"range": {
"start": { "line": 1, "character": 8 },
"end": { "line": 1, "character": 21 },
},
"severity": 2,
"code": "ban-ts-comment",
"source": "deno-lint",
"message": "`@ts-ignore` is not allowed without comment\nAdd an in-line comment explaining the reason for using `@ts-ignore`, like `// @ts-ignore: <reason>`",
},
],
"version": 1,
},
]),
);
}

#[test(timeout = 300)]
fn lsp_isolated_declarations() {
let context = TestContextBuilder::new().use_temp_cwd().build();
Expand Down
27 changes: 21 additions & 6 deletions tests/util/server/src/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,12 @@ impl InitializeParamsBuilder {
self
}

pub fn set_force_push_based_diagnostics(&mut self, value: bool) -> &mut Self {
let options = self.initialization_options_mut();
options.insert("forcePushBasedDiagnostics".to_string(), value.into());
self
}

pub fn add_test_server_suggestions(&mut self) -> &mut Self {
self.set_suggest_imports_hosts(vec![(
"http://localhost:4545/".to_string(),
Expand Down Expand Up @@ -877,12 +883,21 @@ impl LspClient {
Some(workspace) => workspace.configuration == Some(true),
_ => false,
};
self.supports_pull_diagnostics = params
.capabilities
.text_document
.as_ref()
.and_then(|t| t.diagnostic.as_ref())
.is_some();
let force_push_based_diagnostics = (|| {
params
.initialization_options
.as_ref()?
.get("forcePushBasedDiagnostics")?
.as_bool()
})()
.unwrap_or(false);
self.supports_pull_diagnostics = !force_push_based_diagnostics
&& params
.capabilities
.text_document
.as_ref()
.and_then(|t| t.diagnostic.as_ref())
.is_some();

self.write_request("initialize", params);
self.write_notification("initialized", json!({}));
Expand Down
Loading