1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod lsp_ext_command;
15pub mod rust_analyzer_ext;
16
17use crate::{
18 CodeAction, ColorPresentation, Completion, CompletionResponse, CompletionSource,
19 CoreCompletion, DocumentColor, Hover, InlayHint, LocationLink, LspAction, LspPullDiagnostics,
20 ManifestProvidersStore, ProjectItem, ProjectPath, ProjectTransaction, PulledDiagnostics,
21 ResolveState, Symbol,
22 buffer_store::{BufferStore, BufferStoreEvent},
23 environment::ProjectEnvironment,
24 lsp_command::{self, *},
25 lsp_store,
26 manifest_tree::{
27 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
28 ManifestTree,
29 },
30 prettier_store::{self, PrettierStore, PrettierStoreEvent},
31 project_settings::{LspSettings, ProjectSettings},
32 relativize_path, resolve_path,
33 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
34 worktree_store::{WorktreeStore, WorktreeStoreEvent},
35 yarn::YarnPathStore,
36};
37use anyhow::{Context as _, Result, anyhow};
38use async_trait::async_trait;
39use client::{TypedEnvelope, proto};
40use clock::Global;
41use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
42use futures::{
43 AsyncWriteExt, Future, FutureExt, StreamExt,
44 future::{Either, Shared, join_all, pending, select},
45 select, select_biased,
46 stream::FuturesUnordered,
47};
48use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
49use gpui::{
50 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
51 WeakEntity,
52};
53use http_client::HttpClient;
54use itertools::Itertools as _;
55use language::{
56 Bias, BinaryStatus, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
57 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
58 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, ManifestDelegate, ManifestName,
59 Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain, Transaction,
60 Unclipped,
61 language_settings::{
62 FormatOnSave, Formatter, LanguageSettings, SelectedFormatter, language_settings,
63 },
64 point_to_lsp,
65 proto::{
66 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
67 serialize_lsp_edit, serialize_version,
68 },
69 range_from_lsp, range_to_lsp,
70};
71use lsp::{
72 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticSeverity,
73 DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter,
74 FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
75 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
76 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
77 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, WillRenameFiles,
78 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
79};
80use node_runtime::read_package_installed_version;
81use parking_lot::Mutex;
82use postage::{mpsc, sink::Sink, stream::Stream, watch};
83use rand::prelude::*;
84
85use rpc::{
86 AnyProtoClient,
87 proto::{FromProto, ToProto},
88};
89use serde::Serialize;
90use settings::{Settings, SettingsLocation, SettingsStore};
91use sha2::{Digest, Sha256};
92use smol::channel::Sender;
93use snippet::Snippet;
94use std::{
95 any::Any,
96 borrow::Cow,
97 cell::RefCell,
98 cmp::{Ordering, Reverse},
99 convert::TryInto,
100 ffi::OsStr,
101 future::ready,
102 iter, mem,
103 ops::{ControlFlow, Range},
104 path::{self, Path, PathBuf},
105 pin::pin,
106 rc::Rc,
107 sync::Arc,
108 time::{Duration, Instant},
109};
110use sum_tree::Dimensions;
111use text::{Anchor, BufferId, LineEnding, OffsetRangeExt};
112use url::Url;
113use util::{
114 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
115 paths::{PathExt, SanitizedPath},
116 post_inc,
117};
118
119pub use fs::*;
120pub use language::Location;
121#[cfg(any(test, feature = "test-support"))]
122pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
123pub use worktree::{
124 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
125 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
126};
127
128const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
129pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub enum FormatTrigger {
133 Save,
134 Manual,
135}
136
137pub enum LspFormatTarget {
138 Buffers,
139 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
140}
141
142pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
143
144impl FormatTrigger {
145 fn from_proto(value: i32) -> FormatTrigger {
146 match value {
147 0 => FormatTrigger::Save,
148 1 => FormatTrigger::Manual,
149 _ => FormatTrigger::Save,
150 }
151 }
152}
153
154#[derive(Clone)]
155struct UnifiedLanguageServer {
156 id: LanguageServerId,
157 project_roots: HashSet<Arc<Path>>,
158}
159
160#[derive(Clone, Hash, PartialEq, Eq)]
161struct LanguageServerSeed {
162 worktree_id: WorktreeId,
163 name: LanguageServerName,
164 toolchain: Option<Toolchain>,
165 settings: Arc<LspSettings>,
166}
167
168#[derive(Debug)]
169pub struct DocumentDiagnosticsUpdate<'a, D> {
170 pub diagnostics: D,
171 pub result_id: Option<String>,
172 pub server_id: LanguageServerId,
173 pub disk_based_sources: Cow<'a, [String]>,
174}
175
176pub struct DocumentDiagnostics {
177 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
178 document_abs_path: PathBuf,
179 version: Option<i32>,
180}
181
182pub struct LocalLspStore {
183 weak: WeakEntity<LspStore>,
184 worktree_store: Entity<WorktreeStore>,
185 toolchain_store: Entity<LocalToolchainStore>,
186 http_client: Arc<dyn HttpClient>,
187 environment: Entity<ProjectEnvironment>,
188 fs: Arc<dyn Fs>,
189 languages: Arc<LanguageRegistry>,
190 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
191 yarn: Entity<YarnPathStore>,
192 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
193 buffers_being_formatted: HashSet<BufferId>,
194 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
195 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
196 watched_manifest_filenames: HashSet<ManifestName>,
197 language_server_paths_watched_for_rename:
198 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
199 language_server_watcher_registrations:
200 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
201 supplementary_language_servers:
202 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
203 prettier_store: Entity<PrettierStore>,
204 next_diagnostic_group_id: usize,
205 diagnostics: HashMap<
206 WorktreeId,
207 HashMap<
208 Arc<Path>,
209 Vec<(
210 LanguageServerId,
211 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
212 )>,
213 >,
214 >,
215 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
216 _subscription: gpui::Subscription,
217 lsp_tree: LanguageServerTree,
218 registered_buffers: HashMap<BufferId, usize>,
219 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
220 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
221}
222
223impl LocalLspStore {
224 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
225 pub fn running_language_server_for_id(
226 &self,
227 id: LanguageServerId,
228 ) -> Option<&Arc<LanguageServer>> {
229 let language_server_state = self.language_servers.get(&id)?;
230
231 match language_server_state {
232 LanguageServerState::Running { server, .. } => Some(server),
233 LanguageServerState::Starting { .. } => None,
234 }
235 }
236
237 fn get_or_insert_language_server(
238 &mut self,
239 worktree_handle: &Entity<Worktree>,
240 delegate: Arc<LocalLspAdapterDelegate>,
241 disposition: &Arc<LaunchDisposition>,
242 language_name: &LanguageName,
243 cx: &mut App,
244 ) -> LanguageServerId {
245 let key = LanguageServerSeed {
246 worktree_id: worktree_handle.read(cx).id(),
247 name: disposition.server_name.clone(),
248 settings: disposition.settings.clone(),
249 toolchain: disposition.toolchain.clone(),
250 };
251 if let Some(state) = self.language_server_ids.get_mut(&key) {
252 state.project_roots.insert(disposition.path.path.clone());
253 state.id
254 } else {
255 let adapter = self
256 .languages
257 .lsp_adapters(language_name)
258 .into_iter()
259 .find(|adapter| adapter.name() == disposition.server_name)
260 .expect("To find LSP adapter");
261 let new_language_server_id = self.start_language_server(
262 worktree_handle,
263 delegate,
264 adapter,
265 disposition.settings.clone(),
266 key.clone(),
267 cx,
268 );
269 if let Some(state) = self.language_server_ids.get_mut(&key) {
270 state.project_roots.insert(disposition.path.path.clone());
271 } else {
272 debug_assert!(
273 false,
274 "Expected `start_language_server` to ensure that `key` exists in a map"
275 );
276 }
277 new_language_server_id
278 }
279 }
280
281 fn start_language_server(
282 &mut self,
283 worktree_handle: &Entity<Worktree>,
284 delegate: Arc<LocalLspAdapterDelegate>,
285 adapter: Arc<CachedLspAdapter>,
286 settings: Arc<LspSettings>,
287 key: LanguageServerSeed,
288 cx: &mut App,
289 ) -> LanguageServerId {
290 let worktree = worktree_handle.read(cx);
291
292 let root_path = worktree.abs_path();
293 let toolchain = key.toolchain.clone();
294 let override_options = settings.initialization_options.clone();
295
296 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
297
298 let server_id = self.languages.next_language_server_id();
299 log::trace!(
300 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
301 adapter.name.0
302 );
303
304 let binary = self.get_language_server_binary(
305 adapter.clone(),
306 settings,
307 toolchain.clone(),
308 delegate.clone(),
309 true,
310 cx,
311 );
312 let pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
313
314 let pending_server = cx.spawn({
315 let adapter = adapter.clone();
316 let server_name = adapter.name.clone();
317 let stderr_capture = stderr_capture.clone();
318 #[cfg(any(test, feature = "test-support"))]
319 let lsp_store = self.weak.clone();
320 let pending_workspace_folders = pending_workspace_folders.clone();
321 async move |cx| {
322 let binary = binary.await?;
323 #[cfg(any(test, feature = "test-support"))]
324 if let Some(server) = lsp_store
325 .update(&mut cx.clone(), |this, cx| {
326 this.languages.create_fake_language_server(
327 server_id,
328 &server_name,
329 binary.clone(),
330 &mut cx.to_async(),
331 )
332 })
333 .ok()
334 .flatten()
335 {
336 return Ok(server);
337 }
338
339 let code_action_kinds = adapter.code_action_kinds();
340 lsp::LanguageServer::new(
341 stderr_capture,
342 server_id,
343 server_name,
344 binary,
345 &root_path,
346 code_action_kinds,
347 Some(pending_workspace_folders),
348 cx,
349 )
350 }
351 });
352
353 let startup = {
354 let server_name = adapter.name.0.clone();
355 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
356 let key = key.clone();
357 let adapter = adapter.clone();
358 let lsp_store = self.weak.clone();
359 let pending_workspace_folders = pending_workspace_folders.clone();
360 let fs = self.fs.clone();
361 let pull_diagnostics = ProjectSettings::get_global(cx)
362 .diagnostics
363 .lsp_pull_diagnostics
364 .enabled;
365 cx.spawn(async move |cx| {
366 let result = async {
367 let language_server = pending_server.await?;
368
369 let workspace_config = Self::workspace_configuration_for_adapter(
370 adapter.adapter.clone(),
371 fs.as_ref(),
372 &delegate,
373 toolchain,
374 cx,
375 )
376 .await?;
377
378 let mut initialization_options = Self::initialization_options_for_adapter(
379 adapter.adapter.clone(),
380 fs.as_ref(),
381 &delegate,
382 )
383 .await?;
384
385 match (&mut initialization_options, override_options) {
386 (Some(initialization_options), Some(override_options)) => {
387 merge_json_value_into(override_options, initialization_options);
388 }
389 (None, override_options) => initialization_options = override_options,
390 _ => {}
391 }
392
393 let initialization_params = cx.update(|cx| {
394 let mut params =
395 language_server.default_initialize_params(pull_diagnostics, cx);
396 params.initialization_options = initialization_options;
397 adapter.adapter.prepare_initialize_params(params, cx)
398 })??;
399
400 Self::setup_lsp_messages(
401 lsp_store.clone(),
402 fs,
403 &language_server,
404 delegate.clone(),
405 adapter.clone(),
406 );
407
408 let did_change_configuration_params =
409 Arc::new(lsp::DidChangeConfigurationParams {
410 settings: workspace_config,
411 });
412 let language_server = cx
413 .update(|cx| {
414 language_server.initialize(
415 initialization_params,
416 did_change_configuration_params.clone(),
417 cx,
418 )
419 })?
420 .await
421 .inspect_err(|_| {
422 if let Some(lsp_store) = lsp_store.upgrade() {
423 lsp_store
424 .update(cx, |lsp_store, cx| {
425 lsp_store.cleanup_lsp_data(server_id);
426 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
427 })
428 .ok();
429 }
430 })?;
431
432 language_server
433 .notify::<lsp::notification::DidChangeConfiguration>(
434 &did_change_configuration_params,
435 )
436 .ok();
437
438 anyhow::Ok(language_server)
439 }
440 .await;
441
442 match result {
443 Ok(server) => {
444 lsp_store
445 .update(cx, |lsp_store, cx| {
446 lsp_store.insert_newly_running_language_server(
447 adapter,
448 server.clone(),
449 server_id,
450 key,
451 pending_workspace_folders,
452 cx,
453 );
454 })
455 .ok();
456 stderr_capture.lock().take();
457 Some(server)
458 }
459
460 Err(err) => {
461 let log = stderr_capture.lock().take().unwrap_or_default();
462 delegate.update_status(
463 adapter.name(),
464 BinaryStatus::Failed {
465 error: if log.is_empty() {
466 format!("{err:#}")
467 } else {
468 format!("{err:#}\n-- stderr --\n{log}")
469 },
470 },
471 );
472 log::error!("Failed to start language server {server_name:?}: {err:?}");
473 if !log.is_empty() {
474 log::error!("server stderr: {log}");
475 }
476 None
477 }
478 }
479 })
480 };
481 let state = LanguageServerState::Starting {
482 startup,
483 pending_workspace_folders,
484 };
485
486 self.languages
487 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
488
489 self.language_servers.insert(server_id, state);
490 self.language_server_ids
491 .entry(key)
492 .or_insert(UnifiedLanguageServer {
493 id: server_id,
494 project_roots: Default::default(),
495 });
496 server_id
497 }
498
499 fn get_language_server_binary(
500 &self,
501 adapter: Arc<CachedLspAdapter>,
502 settings: Arc<LspSettings>,
503 toolchain: Option<Toolchain>,
504 delegate: Arc<dyn LspAdapterDelegate>,
505 allow_binary_download: bool,
506 cx: &mut App,
507 ) -> Task<Result<LanguageServerBinary>> {
508 if let Some(settings) = settings.binary.as_ref()
509 && settings.path.is_some()
510 {
511 let settings = settings.clone();
512
513 return cx.background_spawn(async move {
514 let mut env = delegate.shell_env().await;
515 env.extend(settings.env.unwrap_or_default());
516
517 Ok(LanguageServerBinary {
518 path: PathBuf::from(&settings.path.unwrap()),
519 env: Some(env),
520 arguments: settings
521 .arguments
522 .unwrap_or_default()
523 .iter()
524 .map(Into::into)
525 .collect(),
526 })
527 });
528 }
529 let lsp_binary_options = LanguageServerBinaryOptions {
530 allow_path_lookup: !settings
531 .binary
532 .as_ref()
533 .and_then(|b| b.ignore_system_version)
534 .unwrap_or_default(),
535 allow_binary_download,
536 };
537
538 cx.spawn(async move |cx| {
539 let binary_result = adapter
540 .clone()
541 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
542 .await;
543
544 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
545
546 let mut binary = binary_result?;
547 let mut shell_env = delegate.shell_env().await;
548
549 shell_env.extend(binary.env.unwrap_or_default());
550
551 if let Some(settings) = settings.binary.as_ref() {
552 if let Some(arguments) = &settings.arguments {
553 binary.arguments = arguments.iter().map(Into::into).collect();
554 }
555 if let Some(env) = &settings.env {
556 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
557 }
558 }
559
560 binary.env = Some(shell_env);
561 Ok(binary)
562 })
563 }
564
565 fn setup_lsp_messages(
566 this: WeakEntity<LspStore>,
567 fs: Arc<dyn Fs>,
568 language_server: &LanguageServer,
569 delegate: Arc<dyn LspAdapterDelegate>,
570 adapter: Arc<CachedLspAdapter>,
571 ) {
572 let name = language_server.name();
573 let server_id = language_server.server_id();
574 language_server
575 .on_notification::<lsp::notification::PublishDiagnostics, _>({
576 let adapter = adapter.clone();
577 let this = this.clone();
578 move |mut params, cx| {
579 let adapter = adapter.clone();
580 if let Some(this) = this.upgrade() {
581 this.update(cx, |this, cx| {
582 {
583 let buffer = params
584 .uri
585 .to_file_path()
586 .map(|file_path| this.get_buffer(&file_path, cx))
587 .ok()
588 .flatten();
589 adapter.process_diagnostics(&mut params, server_id, buffer);
590 }
591
592 this.merge_lsp_diagnostics(
593 DiagnosticSourceKind::Pushed,
594 vec![DocumentDiagnosticsUpdate {
595 server_id,
596 diagnostics: params,
597 result_id: None,
598 disk_based_sources: Cow::Borrowed(
599 &adapter.disk_based_diagnostic_sources,
600 ),
601 }],
602 |_, diagnostic, cx| match diagnostic.source_kind {
603 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
604 adapter.retain_old_diagnostic(diagnostic, cx)
605 }
606 DiagnosticSourceKind::Pulled => true,
607 },
608 cx,
609 )
610 .log_err();
611 })
612 .ok();
613 }
614 }
615 })
616 .detach();
617 language_server
618 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
619 let adapter = adapter.adapter.clone();
620 let delegate = delegate.clone();
621 let this = this.clone();
622 let fs = fs.clone();
623 move |params, cx| {
624 let adapter = adapter.clone();
625 let delegate = delegate.clone();
626 let this = this.clone();
627 let fs = fs.clone();
628 let mut cx = cx.clone();
629 async move {
630 let toolchain_for_id = this
631 .update(&mut cx, |this, _| {
632 this.as_local()?.language_server_ids.iter().find_map(
633 |(seed, value)| {
634 (value.id == server_id).then(|| seed.toolchain.clone())
635 },
636 )
637 })?
638 .context("Expected the LSP store to be in a local mode")?;
639 let workspace_config = Self::workspace_configuration_for_adapter(
640 adapter.clone(),
641 fs.as_ref(),
642 &delegate,
643 toolchain_for_id,
644 &mut cx,
645 )
646 .await?;
647
648 Ok(params
649 .items
650 .into_iter()
651 .map(|item| {
652 if let Some(section) = &item.section {
653 workspace_config
654 .get(section)
655 .cloned()
656 .unwrap_or(serde_json::Value::Null)
657 } else {
658 workspace_config.clone()
659 }
660 })
661 .collect())
662 }
663 }
664 })
665 .detach();
666
667 language_server
668 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
669 let this = this.clone();
670 move |_, cx| {
671 let this = this.clone();
672 let cx = cx.clone();
673 async move {
674 let Some(server) =
675 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
676 else {
677 return Ok(None);
678 };
679 let root = server.workspace_folders();
680 Ok(Some(
681 root.into_iter()
682 .map(|uri| WorkspaceFolder {
683 uri,
684 name: Default::default(),
685 })
686 .collect(),
687 ))
688 }
689 }
690 })
691 .detach();
692 // Even though we don't have handling for these requests, respond to them to
693 // avoid stalling any language server like `gopls` which waits for a response
694 // to these requests when initializing.
695 language_server
696 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
697 let this = this.clone();
698 move |params, cx| {
699 let this = this.clone();
700 let mut cx = cx.clone();
701 async move {
702 this.update(&mut cx, |this, _| {
703 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
704 && let lsp::NumberOrString::String(token) = params.token
705 {
706 status.progress_tokens.insert(token);
707 }
708 })?;
709
710 Ok(())
711 }
712 }
713 })
714 .detach();
715
716 language_server
717 .on_request::<lsp::request::RegisterCapability, _, _>({
718 let lsp_store = this.clone();
719 move |params, cx| {
720 let lsp_store = lsp_store.clone();
721 let mut cx = cx.clone();
722 async move {
723 lsp_store
724 .update(&mut cx, |lsp_store, cx| {
725 if lsp_store.as_local().is_some() {
726 match lsp_store
727 .register_server_capabilities(server_id, params, cx)
728 {
729 Ok(()) => {}
730 Err(e) => {
731 log::error!(
732 "Failed to register server capabilities: {e:#}"
733 );
734 }
735 };
736 }
737 })
738 .ok();
739 Ok(())
740 }
741 }
742 })
743 .detach();
744
745 language_server
746 .on_request::<lsp::request::UnregisterCapability, _, _>({
747 let lsp_store = this.clone();
748 move |params, cx| {
749 let lsp_store = lsp_store.clone();
750 let mut cx = cx.clone();
751 async move {
752 lsp_store
753 .update(&mut cx, |lsp_store, cx| {
754 if lsp_store.as_local().is_some() {
755 match lsp_store
756 .unregister_server_capabilities(server_id, params, cx)
757 {
758 Ok(()) => {}
759 Err(e) => {
760 log::error!(
761 "Failed to unregister server capabilities: {e:#}"
762 );
763 }
764 }
765 }
766 })
767 .ok();
768 Ok(())
769 }
770 }
771 })
772 .detach();
773
774 language_server
775 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
776 let this = this.clone();
777 move |params, cx| {
778 let mut cx = cx.clone();
779 let this = this.clone();
780 async move {
781 LocalLspStore::on_lsp_workspace_edit(
782 this.clone(),
783 params,
784 server_id,
785 &mut cx,
786 )
787 .await
788 }
789 }
790 })
791 .detach();
792
793 language_server
794 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
795 let this = this.clone();
796 move |(), cx| {
797 let this = this.clone();
798 let mut cx = cx.clone();
799 async move {
800 this.update(&mut cx, |this, cx| {
801 cx.emit(LspStoreEvent::RefreshInlayHints);
802 this.downstream_client.as_ref().map(|(client, project_id)| {
803 client.send(proto::RefreshInlayHints {
804 project_id: *project_id,
805 })
806 })
807 })?
808 .transpose()?;
809 Ok(())
810 }
811 }
812 })
813 .detach();
814
815 language_server
816 .on_request::<lsp::request::CodeLensRefresh, _, _>({
817 let this = this.clone();
818 move |(), cx| {
819 let this = this.clone();
820 let mut cx = cx.clone();
821 async move {
822 this.update(&mut cx, |this, cx| {
823 cx.emit(LspStoreEvent::RefreshCodeLens);
824 this.downstream_client.as_ref().map(|(client, project_id)| {
825 client.send(proto::RefreshCodeLens {
826 project_id: *project_id,
827 })
828 })
829 })?
830 .transpose()?;
831 Ok(())
832 }
833 }
834 })
835 .detach();
836
837 language_server
838 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
839 let this = this.clone();
840 move |(), cx| {
841 let this = this.clone();
842 let mut cx = cx.clone();
843 async move {
844 this.update(&mut cx, |lsp_store, _| {
845 lsp_store.pull_workspace_diagnostics(server_id);
846 lsp_store
847 .downstream_client
848 .as_ref()
849 .map(|(client, project_id)| {
850 client.send(proto::PullWorkspaceDiagnostics {
851 project_id: *project_id,
852 server_id: server_id.to_proto(),
853 })
854 })
855 })?
856 .transpose()?;
857 Ok(())
858 }
859 }
860 })
861 .detach();
862
863 language_server
864 .on_request::<lsp::request::ShowMessageRequest, _, _>({
865 let this = this.clone();
866 let name = name.to_string();
867 move |params, cx| {
868 let this = this.clone();
869 let name = name.to_string();
870 let mut cx = cx.clone();
871 async move {
872 let actions = params.actions.unwrap_or_default();
873 let (tx, rx) = smol::channel::bounded(1);
874 let request = LanguageServerPromptRequest {
875 level: match params.typ {
876 lsp::MessageType::ERROR => PromptLevel::Critical,
877 lsp::MessageType::WARNING => PromptLevel::Warning,
878 _ => PromptLevel::Info,
879 },
880 message: params.message,
881 actions,
882 response_channel: tx,
883 lsp_name: name.clone(),
884 };
885
886 let did_update = this
887 .update(&mut cx, |_, cx| {
888 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
889 })
890 .is_ok();
891 if did_update {
892 let response = rx.recv().await.ok();
893 Ok(response)
894 } else {
895 Ok(None)
896 }
897 }
898 }
899 })
900 .detach();
901 language_server
902 .on_notification::<lsp::notification::ShowMessage, _>({
903 let this = this.clone();
904 let name = name.to_string();
905 move |params, cx| {
906 let this = this.clone();
907 let name = name.to_string();
908 let mut cx = cx.clone();
909
910 let (tx, _) = smol::channel::bounded(1);
911 let request = LanguageServerPromptRequest {
912 level: match params.typ {
913 lsp::MessageType::ERROR => PromptLevel::Critical,
914 lsp::MessageType::WARNING => PromptLevel::Warning,
915 _ => PromptLevel::Info,
916 },
917 message: params.message,
918 actions: vec![],
919 response_channel: tx,
920 lsp_name: name,
921 };
922
923 let _ = this.update(&mut cx, |_, cx| {
924 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
925 });
926 }
927 })
928 .detach();
929
930 let disk_based_diagnostics_progress_token =
931 adapter.disk_based_diagnostics_progress_token.clone();
932
933 language_server
934 .on_notification::<lsp::notification::Progress, _>({
935 let this = this.clone();
936 move |params, cx| {
937 if let Some(this) = this.upgrade() {
938 this.update(cx, |this, cx| {
939 this.on_lsp_progress(
940 params,
941 server_id,
942 disk_based_diagnostics_progress_token.clone(),
943 cx,
944 );
945 })
946 .ok();
947 }
948 }
949 })
950 .detach();
951
952 language_server
953 .on_notification::<lsp::notification::LogMessage, _>({
954 let this = this.clone();
955 move |params, cx| {
956 if let Some(this) = this.upgrade() {
957 this.update(cx, |_, cx| {
958 cx.emit(LspStoreEvent::LanguageServerLog(
959 server_id,
960 LanguageServerLogType::Log(params.typ),
961 params.message,
962 ));
963 })
964 .ok();
965 }
966 }
967 })
968 .detach();
969
970 language_server
971 .on_notification::<lsp::notification::LogTrace, _>({
972 let this = this.clone();
973 move |params, cx| {
974 let mut cx = cx.clone();
975 if let Some(this) = this.upgrade() {
976 this.update(&mut cx, |_, cx| {
977 cx.emit(LspStoreEvent::LanguageServerLog(
978 server_id,
979 LanguageServerLogType::Trace(params.verbose),
980 params.message,
981 ));
982 })
983 .ok();
984 }
985 }
986 })
987 .detach();
988
989 json_language_server_ext::register_requests(this.clone(), language_server);
990 rust_analyzer_ext::register_notifications(this.clone(), language_server);
991 clangd_ext::register_notifications(this, language_server, adapter);
992 }
993
994 fn shutdown_language_servers_on_quit(
995 &mut self,
996 _: &mut Context<LspStore>,
997 ) -> impl Future<Output = ()> + use<> {
998 let shutdown_futures = self
999 .language_servers
1000 .drain()
1001 .map(|(_, server_state)| Self::shutdown_server(server_state))
1002 .collect::<Vec<_>>();
1003
1004 async move {
1005 join_all(shutdown_futures).await;
1006 }
1007 }
1008
1009 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1010 match server_state {
1011 LanguageServerState::Running { server, .. } => {
1012 if let Some(shutdown) = server.shutdown() {
1013 shutdown.await;
1014 }
1015 }
1016 LanguageServerState::Starting { startup, .. } => {
1017 if let Some(server) = startup.await
1018 && let Some(shutdown) = server.shutdown()
1019 {
1020 shutdown.await;
1021 }
1022 }
1023 }
1024 Ok(())
1025 }
1026
1027 fn language_servers_for_worktree(
1028 &self,
1029 worktree_id: WorktreeId,
1030 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1031 self.language_server_ids
1032 .iter()
1033 .filter_map(move |(seed, state)| {
1034 if seed.worktree_id != worktree_id {
1035 return None;
1036 }
1037
1038 if let Some(LanguageServerState::Running { server, .. }) =
1039 self.language_servers.get(&state.id)
1040 {
1041 Some(server)
1042 } else {
1043 None
1044 }
1045 })
1046 }
1047
1048 fn language_server_ids_for_project_path(
1049 &self,
1050 project_path: ProjectPath,
1051 language: &Language,
1052 cx: &mut App,
1053 ) -> Vec<LanguageServerId> {
1054 let Some(worktree) = self
1055 .worktree_store
1056 .read(cx)
1057 .worktree_for_id(project_path.worktree_id, cx)
1058 else {
1059 return Vec::new();
1060 };
1061 let delegate: Arc<dyn ManifestDelegate> =
1062 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1063
1064 self.lsp_tree
1065 .get(
1066 project_path,
1067 language.name(),
1068 language.manifest(),
1069 &delegate,
1070 cx,
1071 )
1072 .collect::<Vec<_>>()
1073 }
1074
1075 fn language_server_ids_for_buffer(
1076 &self,
1077 buffer: &Buffer,
1078 cx: &mut App,
1079 ) -> Vec<LanguageServerId> {
1080 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1081 let worktree_id = file.worktree_id(cx);
1082
1083 let path: Arc<Path> = file
1084 .path()
1085 .parent()
1086 .map(Arc::from)
1087 .unwrap_or_else(|| file.path().clone());
1088 let worktree_path = ProjectPath { worktree_id, path };
1089 self.language_server_ids_for_project_path(worktree_path, language, cx)
1090 } else {
1091 Vec::new()
1092 }
1093 }
1094
1095 fn language_servers_for_buffer<'a>(
1096 &'a self,
1097 buffer: &'a Buffer,
1098 cx: &'a mut App,
1099 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1100 self.language_server_ids_for_buffer(buffer, cx)
1101 .into_iter()
1102 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1103 LanguageServerState::Running {
1104 adapter, server, ..
1105 } => Some((adapter, server)),
1106 _ => None,
1107 })
1108 }
1109
1110 async fn execute_code_action_kind_locally(
1111 lsp_store: WeakEntity<LspStore>,
1112 mut buffers: Vec<Entity<Buffer>>,
1113 kind: CodeActionKind,
1114 push_to_history: bool,
1115 cx: &mut AsyncApp,
1116 ) -> anyhow::Result<ProjectTransaction> {
1117 // Do not allow multiple concurrent code actions requests for the
1118 // same buffer.
1119 lsp_store.update(cx, |this, cx| {
1120 let this = this.as_local_mut().unwrap();
1121 buffers.retain(|buffer| {
1122 this.buffers_being_formatted
1123 .insert(buffer.read(cx).remote_id())
1124 });
1125 })?;
1126 let _cleanup = defer({
1127 let this = lsp_store.clone();
1128 let mut cx = cx.clone();
1129 let buffers = &buffers;
1130 move || {
1131 this.update(&mut cx, |this, cx| {
1132 let this = this.as_local_mut().unwrap();
1133 for buffer in buffers {
1134 this.buffers_being_formatted
1135 .remove(&buffer.read(cx).remote_id());
1136 }
1137 })
1138 .ok();
1139 }
1140 });
1141 let mut project_transaction = ProjectTransaction::default();
1142
1143 for buffer in &buffers {
1144 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1145 buffer.update(cx, |buffer, cx| {
1146 lsp_store
1147 .as_local()
1148 .unwrap()
1149 .language_servers_for_buffer(buffer, cx)
1150 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1151 .collect::<Vec<_>>()
1152 })
1153 })?;
1154 for (_, language_server) in adapters_and_servers.iter() {
1155 let actions = Self::get_server_code_actions_from_action_kinds(
1156 &lsp_store,
1157 language_server.server_id(),
1158 vec![kind.clone()],
1159 buffer,
1160 cx,
1161 )
1162 .await?;
1163 Self::execute_code_actions_on_server(
1164 &lsp_store,
1165 language_server,
1166 actions,
1167 push_to_history,
1168 &mut project_transaction,
1169 cx,
1170 )
1171 .await?;
1172 }
1173 }
1174 Ok(project_transaction)
1175 }
1176
1177 async fn format_locally(
1178 lsp_store: WeakEntity<LspStore>,
1179 mut buffers: Vec<FormattableBuffer>,
1180 push_to_history: bool,
1181 trigger: FormatTrigger,
1182 logger: zlog::Logger,
1183 cx: &mut AsyncApp,
1184 ) -> anyhow::Result<ProjectTransaction> {
1185 // Do not allow multiple concurrent formatting requests for the
1186 // same buffer.
1187 lsp_store.update(cx, |this, cx| {
1188 let this = this.as_local_mut().unwrap();
1189 buffers.retain(|buffer| {
1190 this.buffers_being_formatted
1191 .insert(buffer.handle.read(cx).remote_id())
1192 });
1193 })?;
1194
1195 let _cleanup = defer({
1196 let this = lsp_store.clone();
1197 let mut cx = cx.clone();
1198 let buffers = &buffers;
1199 move || {
1200 this.update(&mut cx, |this, cx| {
1201 let this = this.as_local_mut().unwrap();
1202 for buffer in buffers {
1203 this.buffers_being_formatted
1204 .remove(&buffer.handle.read(cx).remote_id());
1205 }
1206 })
1207 .ok();
1208 }
1209 });
1210
1211 let mut project_transaction = ProjectTransaction::default();
1212
1213 for buffer in &buffers {
1214 zlog::debug!(
1215 logger =>
1216 "formatting buffer '{:?}'",
1217 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1218 );
1219 // Create an empty transaction to hold all of the formatting edits.
1220 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1221 // ensure no transactions created while formatting are
1222 // grouped with the previous transaction in the history
1223 // based on the transaction group interval
1224 buffer.finalize_last_transaction();
1225 buffer
1226 .start_transaction()
1227 .context("transaction already open")?;
1228 buffer.end_transaction(cx);
1229 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1230 buffer.finalize_last_transaction();
1231 anyhow::Ok(transaction_id)
1232 })??;
1233
1234 let result = Self::format_buffer_locally(
1235 lsp_store.clone(),
1236 buffer,
1237 formatting_transaction_id,
1238 trigger,
1239 logger,
1240 cx,
1241 )
1242 .await;
1243
1244 buffer.handle.update(cx, |buffer, cx| {
1245 let Some(formatting_transaction) =
1246 buffer.get_transaction(formatting_transaction_id).cloned()
1247 else {
1248 zlog::warn!(logger => "no formatting transaction");
1249 return;
1250 };
1251 if formatting_transaction.edit_ids.is_empty() {
1252 zlog::debug!(logger => "no changes made while formatting");
1253 buffer.forget_transaction(formatting_transaction_id);
1254 return;
1255 }
1256 if !push_to_history {
1257 zlog::trace!(logger => "forgetting format transaction");
1258 buffer.forget_transaction(formatting_transaction.id);
1259 }
1260 project_transaction
1261 .0
1262 .insert(cx.entity(), formatting_transaction);
1263 })?;
1264
1265 result?;
1266 }
1267
1268 Ok(project_transaction)
1269 }
1270
1271 async fn format_buffer_locally(
1272 lsp_store: WeakEntity<LspStore>,
1273 buffer: &FormattableBuffer,
1274 formatting_transaction_id: clock::Lamport,
1275 trigger: FormatTrigger,
1276 logger: zlog::Logger,
1277 cx: &mut AsyncApp,
1278 ) -> Result<()> {
1279 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1280 buffer.handle.update(cx, |buffer, cx| {
1281 let adapters_and_servers = lsp_store
1282 .as_local()
1283 .unwrap()
1284 .language_servers_for_buffer(buffer, cx)
1285 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1286 .collect::<Vec<_>>();
1287 let settings =
1288 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1289 .into_owned();
1290 (adapters_and_servers, settings)
1291 })
1292 })?;
1293
1294 /// Apply edits to the buffer that will become part of the formatting transaction.
1295 /// Fails if the buffer has been edited since the start of that transaction.
1296 fn extend_formatting_transaction(
1297 buffer: &FormattableBuffer,
1298 formatting_transaction_id: text::TransactionId,
1299 cx: &mut AsyncApp,
1300 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1301 ) -> anyhow::Result<()> {
1302 buffer.handle.update(cx, |buffer, cx| {
1303 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1304 if last_transaction_id != Some(formatting_transaction_id) {
1305 anyhow::bail!("Buffer edited while formatting. Aborting")
1306 }
1307 buffer.start_transaction();
1308 operation(buffer, cx);
1309 if let Some(transaction_id) = buffer.end_transaction(cx) {
1310 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1311 }
1312 Ok(())
1313 })?
1314 }
1315
1316 // handle whitespace formatting
1317 if settings.remove_trailing_whitespace_on_save {
1318 zlog::trace!(logger => "removing trailing whitespace");
1319 let diff = buffer
1320 .handle
1321 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1322 .await;
1323 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1324 buffer.apply_diff(diff, cx);
1325 })?;
1326 }
1327
1328 if settings.ensure_final_newline_on_save {
1329 zlog::trace!(logger => "ensuring final newline");
1330 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1331 buffer.ensure_final_newline(cx);
1332 })?;
1333 }
1334
1335 // Formatter for `code_actions_on_format` that runs before
1336 // the rest of the formatters
1337 let mut code_actions_on_format_formatter = None;
1338 let should_run_code_actions_on_format = !matches!(
1339 (trigger, &settings.format_on_save),
1340 (FormatTrigger::Save, &FormatOnSave::Off)
1341 );
1342 if should_run_code_actions_on_format {
1343 let have_code_actions_to_run_on_format = settings
1344 .code_actions_on_format
1345 .values()
1346 .any(|enabled| *enabled);
1347 if have_code_actions_to_run_on_format {
1348 zlog::trace!(logger => "going to run code actions on format");
1349 code_actions_on_format_formatter = Some(Formatter::CodeActions(
1350 settings.code_actions_on_format.clone(),
1351 ));
1352 }
1353 }
1354
1355 let formatters = match (trigger, &settings.format_on_save) {
1356 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1357 (FormatTrigger::Save, FormatOnSave::List(formatters)) => formatters.as_ref(),
1358 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1359 match &settings.formatter {
1360 SelectedFormatter::Auto => {
1361 if settings.prettier.allowed {
1362 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1363 std::slice::from_ref(&Formatter::Prettier)
1364 } else {
1365 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1366 std::slice::from_ref(&Formatter::LanguageServer { name: None })
1367 }
1368 }
1369 SelectedFormatter::List(formatter_list) => formatter_list.as_ref(),
1370 }
1371 }
1372 };
1373
1374 let formatters = code_actions_on_format_formatter.iter().chain(formatters);
1375
1376 for formatter in formatters {
1377 match formatter {
1378 Formatter::Prettier => {
1379 let logger = zlog::scoped!(logger => "prettier");
1380 zlog::trace!(logger => "formatting");
1381 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1382
1383 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1384 lsp_store.prettier_store().unwrap().downgrade()
1385 })?;
1386 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1387 .await
1388 .transpose()?;
1389 let Some(diff) = diff else {
1390 zlog::trace!(logger => "No changes");
1391 continue;
1392 };
1393
1394 extend_formatting_transaction(
1395 buffer,
1396 formatting_transaction_id,
1397 cx,
1398 |buffer, cx| {
1399 buffer.apply_diff(diff, cx);
1400 },
1401 )?;
1402 }
1403 Formatter::External { command, arguments } => {
1404 let logger = zlog::scoped!(logger => "command");
1405 zlog::trace!(logger => "formatting");
1406 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1407
1408 let diff = Self::format_via_external_command(
1409 buffer,
1410 command.as_ref(),
1411 arguments.as_deref(),
1412 cx,
1413 )
1414 .await
1415 .with_context(|| {
1416 format!("Failed to format buffer via external command: {}", command)
1417 })?;
1418 let Some(diff) = diff else {
1419 zlog::trace!(logger => "No changes");
1420 continue;
1421 };
1422
1423 extend_formatting_transaction(
1424 buffer,
1425 formatting_transaction_id,
1426 cx,
1427 |buffer, cx| {
1428 buffer.apply_diff(diff, cx);
1429 },
1430 )?;
1431 }
1432 Formatter::LanguageServer { name } => {
1433 let logger = zlog::scoped!(logger => "language-server");
1434 zlog::trace!(logger => "formatting");
1435 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1436
1437 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1438 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1439 continue;
1440 };
1441
1442 let language_server = if let Some(name) = name.as_deref() {
1443 adapters_and_servers.iter().find_map(|(adapter, server)| {
1444 if adapter.name.0.as_ref() == name {
1445 Some(server.clone())
1446 } else {
1447 None
1448 }
1449 })
1450 } else {
1451 adapters_and_servers.first().map(|e| e.1.clone())
1452 };
1453
1454 let Some(language_server) = language_server else {
1455 log::debug!(
1456 "No language server found to format buffer '{:?}'. Skipping",
1457 buffer_path_abs.as_path().to_string_lossy()
1458 );
1459 continue;
1460 };
1461
1462 zlog::trace!(
1463 logger =>
1464 "Formatting buffer '{:?}' using language server '{:?}'",
1465 buffer_path_abs.as_path().to_string_lossy(),
1466 language_server.name()
1467 );
1468
1469 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1470 zlog::trace!(logger => "formatting ranges");
1471 Self::format_ranges_via_lsp(
1472 &lsp_store,
1473 &buffer.handle,
1474 ranges,
1475 buffer_path_abs,
1476 &language_server,
1477 &settings,
1478 cx,
1479 )
1480 .await
1481 .context("Failed to format ranges via language server")?
1482 } else {
1483 zlog::trace!(logger => "formatting full");
1484 Self::format_via_lsp(
1485 &lsp_store,
1486 &buffer.handle,
1487 buffer_path_abs,
1488 &language_server,
1489 &settings,
1490 cx,
1491 )
1492 .await
1493 .context("failed to format via language server")?
1494 };
1495
1496 if edits.is_empty() {
1497 zlog::trace!(logger => "No changes");
1498 continue;
1499 }
1500 extend_formatting_transaction(
1501 buffer,
1502 formatting_transaction_id,
1503 cx,
1504 |buffer, cx| {
1505 buffer.edit(edits, None, cx);
1506 },
1507 )?;
1508 }
1509 Formatter::CodeActions(code_actions) => {
1510 let logger = zlog::scoped!(logger => "code-actions");
1511 zlog::trace!(logger => "formatting");
1512 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1513
1514 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1515 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1516 continue;
1517 };
1518 let code_action_kinds = code_actions
1519 .iter()
1520 .filter_map(|(action_kind, enabled)| {
1521 enabled.then_some(action_kind.clone().into())
1522 })
1523 .collect::<Vec<_>>();
1524 if code_action_kinds.is_empty() {
1525 zlog::trace!(logger => "No code action kinds enabled, skipping");
1526 continue;
1527 }
1528 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kinds);
1529
1530 let mut actions_and_servers = Vec::new();
1531
1532 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1533 let actions_result = Self::get_server_code_actions_from_action_kinds(
1534 &lsp_store,
1535 language_server.server_id(),
1536 code_action_kinds.clone(),
1537 &buffer.handle,
1538 cx,
1539 )
1540 .await
1541 .with_context(
1542 || format!("Failed to resolve code actions with kinds {:?} for language server {}",
1543 code_action_kinds.iter().map(|kind| kind.as_str()).join(", "),
1544 language_server.name())
1545 );
1546 let Ok(actions) = actions_result else {
1547 // note: it may be better to set result to the error and break formatters here
1548 // but for now we try to execute the actions that we can resolve and skip the rest
1549 zlog::error!(
1550 logger =>
1551 "Failed to resolve code actions with kinds {:?} with language server {}",
1552 code_action_kinds.iter().map(|kind| kind.as_str()).join(", "),
1553 language_server.name()
1554 );
1555 continue;
1556 };
1557 for action in actions {
1558 actions_and_servers.push((action, index));
1559 }
1560 }
1561
1562 if actions_and_servers.is_empty() {
1563 zlog::warn!(logger => "No code actions were resolved, continuing");
1564 continue;
1565 }
1566
1567 'actions: for (mut action, server_index) in actions_and_servers {
1568 let server = &adapters_and_servers[server_index].1;
1569
1570 let describe_code_action = |action: &CodeAction| {
1571 format!(
1572 "code action '{}' with title \"{}\" on server {}",
1573 action
1574 .lsp_action
1575 .action_kind()
1576 .unwrap_or("unknown".into())
1577 .as_str(),
1578 action.lsp_action.title(),
1579 server.name(),
1580 )
1581 };
1582
1583 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1584
1585 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1586 zlog::error!(
1587 logger =>
1588 "Failed to resolve {}. Error: {}",
1589 describe_code_action(&action),
1590 err
1591 );
1592 continue;
1593 }
1594
1595 if let Some(edit) = action.lsp_action.edit().cloned() {
1596 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1597 // but filters out and logs warnings for code actions that cause unreasonably
1598 // difficult handling on our part, such as:
1599 // - applying edits that call commands
1600 // which can result in arbitrary workspace edits being sent from the server that
1601 // have no way of being tied back to the command that initiated them (i.e. we
1602 // can't know which edits are part of the format request, or if the server is done sending
1603 // actions in response to the command)
1604 // - actions that create/delete/modify/rename files other than the one we are formatting
1605 // as we then would need to handle such changes correctly in the local history as well
1606 // as the remote history through the ProjectTransaction
1607 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1608 // Supporting these actions is not impossible, but not supported as of yet.
1609 if edit.changes.is_none() && edit.document_changes.is_none() {
1610 zlog::trace!(
1611 logger =>
1612 "No changes for code action. Skipping {}",
1613 describe_code_action(&action),
1614 );
1615 continue;
1616 }
1617
1618 let mut operations = Vec::new();
1619 if let Some(document_changes) = edit.document_changes {
1620 match document_changes {
1621 lsp::DocumentChanges::Edits(edits) => operations.extend(
1622 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1623 ),
1624 lsp::DocumentChanges::Operations(ops) => operations = ops,
1625 }
1626 } else if let Some(changes) = edit.changes {
1627 operations.extend(changes.into_iter().map(|(uri, edits)| {
1628 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1629 text_document:
1630 lsp::OptionalVersionedTextDocumentIdentifier {
1631 uri,
1632 version: None,
1633 },
1634 edits: edits.into_iter().map(Edit::Plain).collect(),
1635 })
1636 }));
1637 }
1638
1639 let mut edits = Vec::with_capacity(operations.len());
1640
1641 if operations.is_empty() {
1642 zlog::trace!(
1643 logger =>
1644 "No changes for code action. Skipping {}",
1645 describe_code_action(&action),
1646 );
1647 continue;
1648 }
1649 for operation in operations {
1650 let op = match operation {
1651 lsp::DocumentChangeOperation::Edit(op) => op,
1652 lsp::DocumentChangeOperation::Op(_) => {
1653 zlog::warn!(
1654 logger =>
1655 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1656 describe_code_action(&action),
1657 );
1658 continue 'actions;
1659 }
1660 };
1661 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1662 zlog::warn!(
1663 logger =>
1664 "Failed to convert URI '{:?}' to file path. Skipping {}",
1665 &op.text_document.uri,
1666 describe_code_action(&action),
1667 );
1668 continue 'actions;
1669 };
1670 if &file_path != buffer_path_abs {
1671 zlog::warn!(
1672 logger =>
1673 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1674 file_path,
1675 buffer_path_abs,
1676 describe_code_action(&action),
1677 );
1678 continue 'actions;
1679 }
1680
1681 let mut lsp_edits = Vec::new();
1682 for edit in op.edits {
1683 match edit {
1684 Edit::Plain(edit) => {
1685 if !lsp_edits.contains(&edit) {
1686 lsp_edits.push(edit);
1687 }
1688 }
1689 Edit::Annotated(edit) => {
1690 if !lsp_edits.contains(&edit.text_edit) {
1691 lsp_edits.push(edit.text_edit);
1692 }
1693 }
1694 Edit::Snippet(_) => {
1695 zlog::warn!(
1696 logger =>
1697 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1698 describe_code_action(&action),
1699 );
1700 continue 'actions;
1701 }
1702 }
1703 }
1704 let edits_result = lsp_store
1705 .update(cx, |lsp_store, cx| {
1706 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1707 &buffer.handle,
1708 lsp_edits,
1709 server.server_id(),
1710 op.text_document.version,
1711 cx,
1712 )
1713 })?
1714 .await;
1715 let Ok(resolved_edits) = edits_result else {
1716 zlog::warn!(
1717 logger =>
1718 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1719 buffer_path_abs.as_path(),
1720 describe_code_action(&action),
1721 );
1722 continue 'actions;
1723 };
1724 edits.extend(resolved_edits);
1725 }
1726
1727 if edits.is_empty() {
1728 zlog::warn!(logger => "No edits resolved from LSP");
1729 continue;
1730 }
1731
1732 extend_formatting_transaction(
1733 buffer,
1734 formatting_transaction_id,
1735 cx,
1736 |buffer, cx| {
1737 buffer.edit(edits, None, cx);
1738 },
1739 )?;
1740 }
1741
1742 if let Some(command) = action.lsp_action.command() {
1743 zlog::warn!(
1744 logger =>
1745 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1746 &command.command,
1747 );
1748
1749 // bail early if command is invalid
1750 let server_capabilities = server.capabilities();
1751 let available_commands = server_capabilities
1752 .execute_command_provider
1753 .as_ref()
1754 .map(|options| options.commands.as_slice())
1755 .unwrap_or_default();
1756 if !available_commands.contains(&command.command) {
1757 zlog::warn!(
1758 logger =>
1759 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1760 command.command,
1761 server.name(),
1762 );
1763 continue;
1764 }
1765
1766 // noop so we just ensure buffer hasn't been edited since resolving code actions
1767 extend_formatting_transaction(
1768 buffer,
1769 formatting_transaction_id,
1770 cx,
1771 |_, _| {},
1772 )?;
1773 zlog::info!(logger => "Executing command {}", &command.command);
1774
1775 lsp_store.update(cx, |this, _| {
1776 this.as_local_mut()
1777 .unwrap()
1778 .last_workspace_edits_by_language_server
1779 .remove(&server.server_id());
1780 })?;
1781
1782 let execute_command_result = server
1783 .request::<lsp::request::ExecuteCommand>(
1784 lsp::ExecuteCommandParams {
1785 command: command.command.clone(),
1786 arguments: command.arguments.clone().unwrap_or_default(),
1787 ..Default::default()
1788 },
1789 )
1790 .await
1791 .into_response();
1792
1793 if execute_command_result.is_err() {
1794 zlog::error!(
1795 logger =>
1796 "Failed to execute command '{}' as part of {}",
1797 &command.command,
1798 describe_code_action(&action),
1799 );
1800 continue 'actions;
1801 }
1802
1803 let mut project_transaction_command =
1804 lsp_store.update(cx, |this, _| {
1805 this.as_local_mut()
1806 .unwrap()
1807 .last_workspace_edits_by_language_server
1808 .remove(&server.server_id())
1809 .unwrap_or_default()
1810 })?;
1811
1812 if let Some(transaction) =
1813 project_transaction_command.0.remove(&buffer.handle)
1814 {
1815 zlog::trace!(
1816 logger =>
1817 "Successfully captured {} edits that resulted from command {}",
1818 transaction.edit_ids.len(),
1819 &command.command,
1820 );
1821 let transaction_id_project_transaction = transaction.id;
1822 buffer.handle.update(cx, |buffer, _| {
1823 // it may have been removed from history if push_to_history was
1824 // false in deserialize_workspace_edit. If so push it so we
1825 // can merge it with the format transaction
1826 // and pop the combined transaction off the history stack
1827 // later if push_to_history is false
1828 if buffer.get_transaction(transaction.id).is_none() {
1829 buffer.push_transaction(transaction, Instant::now());
1830 }
1831 buffer.merge_transactions(
1832 transaction_id_project_transaction,
1833 formatting_transaction_id,
1834 );
1835 })?;
1836 }
1837
1838 if !project_transaction_command.0.is_empty() {
1839 let extra_buffers = project_transaction_command
1840 .0
1841 .keys()
1842 .filter_map(|buffer_handle| {
1843 buffer_handle
1844 .read_with(cx, |b, cx| b.project_path(cx))
1845 .ok()
1846 .flatten()
1847 })
1848 .map(|p| p.path.to_sanitized_string())
1849 .join(", ");
1850 zlog::warn!(
1851 logger =>
1852 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1853 &command.command,
1854 extra_buffers,
1855 );
1856 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1857 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1858 // add it so it's included, and merge it into the format transaction when its created later
1859 }
1860 }
1861 }
1862 }
1863 }
1864 }
1865
1866 Ok(())
1867 }
1868
1869 pub async fn format_ranges_via_lsp(
1870 this: &WeakEntity<LspStore>,
1871 buffer_handle: &Entity<Buffer>,
1872 ranges: &[Range<Anchor>],
1873 abs_path: &Path,
1874 language_server: &Arc<LanguageServer>,
1875 settings: &LanguageSettings,
1876 cx: &mut AsyncApp,
1877 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1878 let capabilities = &language_server.capabilities();
1879 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1880 if range_formatting_provider == Some(&OneOf::Left(false)) {
1881 anyhow::bail!(
1882 "{} language server does not support range formatting",
1883 language_server.name()
1884 );
1885 }
1886
1887 let uri = file_path_to_lsp_url(abs_path)?;
1888 let text_document = lsp::TextDocumentIdentifier::new(uri);
1889
1890 let lsp_edits = {
1891 let mut lsp_ranges = Vec::new();
1892 this.update(cx, |_this, cx| {
1893 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1894 // not have been sent to the language server. This seems like a fairly systemic
1895 // issue, though, the resolution probably is not specific to formatting.
1896 //
1897 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1898 // LSP.
1899 let snapshot = buffer_handle.read(cx).snapshot();
1900 for range in ranges {
1901 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1902 }
1903 anyhow::Ok(())
1904 })??;
1905
1906 let mut edits = None;
1907 for range in lsp_ranges {
1908 if let Some(mut edit) = language_server
1909 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1910 text_document: text_document.clone(),
1911 range,
1912 options: lsp_command::lsp_formatting_options(settings),
1913 work_done_progress_params: Default::default(),
1914 })
1915 .await
1916 .into_response()?
1917 {
1918 edits.get_or_insert_with(Vec::new).append(&mut edit);
1919 }
1920 }
1921 edits
1922 };
1923
1924 if let Some(lsp_edits) = lsp_edits {
1925 this.update(cx, |this, cx| {
1926 this.as_local_mut().unwrap().edits_from_lsp(
1927 buffer_handle,
1928 lsp_edits,
1929 language_server.server_id(),
1930 None,
1931 cx,
1932 )
1933 })?
1934 .await
1935 } else {
1936 Ok(Vec::with_capacity(0))
1937 }
1938 }
1939
1940 async fn format_via_lsp(
1941 this: &WeakEntity<LspStore>,
1942 buffer: &Entity<Buffer>,
1943 abs_path: &Path,
1944 language_server: &Arc<LanguageServer>,
1945 settings: &LanguageSettings,
1946 cx: &mut AsyncApp,
1947 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1948 let logger = zlog::scoped!("lsp_format");
1949 zlog::info!(logger => "Formatting via LSP");
1950
1951 let uri = file_path_to_lsp_url(abs_path)?;
1952 let text_document = lsp::TextDocumentIdentifier::new(uri);
1953 let capabilities = &language_server.capabilities();
1954
1955 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1956 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1957
1958 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1959 let _timer = zlog::time!(logger => "format-full");
1960 language_server
1961 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1962 text_document,
1963 options: lsp_command::lsp_formatting_options(settings),
1964 work_done_progress_params: Default::default(),
1965 })
1966 .await
1967 .into_response()?
1968 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1969 let _timer = zlog::time!(logger => "format-range");
1970 let buffer_start = lsp::Position::new(0, 0);
1971 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
1972 language_server
1973 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1974 text_document: text_document.clone(),
1975 range: lsp::Range::new(buffer_start, buffer_end),
1976 options: lsp_command::lsp_formatting_options(settings),
1977 work_done_progress_params: Default::default(),
1978 })
1979 .await
1980 .into_response()?
1981 } else {
1982 None
1983 };
1984
1985 if let Some(lsp_edits) = lsp_edits {
1986 this.update(cx, |this, cx| {
1987 this.as_local_mut().unwrap().edits_from_lsp(
1988 buffer,
1989 lsp_edits,
1990 language_server.server_id(),
1991 None,
1992 cx,
1993 )
1994 })?
1995 .await
1996 } else {
1997 Ok(Vec::with_capacity(0))
1998 }
1999 }
2000
2001 async fn format_via_external_command(
2002 buffer: &FormattableBuffer,
2003 command: &str,
2004 arguments: Option<&[String]>,
2005 cx: &mut AsyncApp,
2006 ) -> Result<Option<Diff>> {
2007 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2008 let file = File::from_dyn(buffer.file())?;
2009 let worktree = file.worktree.read(cx);
2010 let mut worktree_path = worktree.abs_path().to_path_buf();
2011 if worktree.root_entry()?.is_file() {
2012 worktree_path.pop();
2013 }
2014 Some(worktree_path)
2015 })?;
2016
2017 let mut child = util::command::new_smol_command(command);
2018
2019 if let Some(buffer_env) = buffer.env.as_ref() {
2020 child.envs(buffer_env);
2021 }
2022
2023 if let Some(working_dir_path) = working_dir_path {
2024 child.current_dir(working_dir_path);
2025 }
2026
2027 if let Some(arguments) = arguments {
2028 child.args(arguments.iter().map(|arg| {
2029 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2030 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2031 } else {
2032 arg.replace("{buffer_path}", "Untitled")
2033 }
2034 }));
2035 }
2036
2037 let mut child = child
2038 .stdin(smol::process::Stdio::piped())
2039 .stdout(smol::process::Stdio::piped())
2040 .stderr(smol::process::Stdio::piped())
2041 .spawn()?;
2042
2043 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2044 let text = buffer
2045 .handle
2046 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2047 for chunk in text.chunks() {
2048 stdin.write_all(chunk.as_bytes()).await?;
2049 }
2050 stdin.flush().await?;
2051
2052 let output = child.output().await?;
2053 anyhow::ensure!(
2054 output.status.success(),
2055 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2056 output.status.code(),
2057 String::from_utf8_lossy(&output.stdout),
2058 String::from_utf8_lossy(&output.stderr),
2059 );
2060
2061 let stdout = String::from_utf8(output.stdout)?;
2062 Ok(Some(
2063 buffer
2064 .handle
2065 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2066 .await,
2067 ))
2068 }
2069
2070 async fn try_resolve_code_action(
2071 lang_server: &LanguageServer,
2072 action: &mut CodeAction,
2073 ) -> anyhow::Result<()> {
2074 match &mut action.lsp_action {
2075 LspAction::Action(lsp_action) => {
2076 if !action.resolved
2077 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2078 && lsp_action.data.is_some()
2079 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2080 {
2081 *lsp_action = Box::new(
2082 lang_server
2083 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2084 .await
2085 .into_response()?,
2086 );
2087 }
2088 }
2089 LspAction::CodeLens(lens) => {
2090 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2091 *lens = lang_server
2092 .request::<lsp::request::CodeLensResolve>(lens.clone())
2093 .await
2094 .into_response()?;
2095 }
2096 }
2097 LspAction::Command(_) => {}
2098 }
2099
2100 action.resolved = true;
2101 anyhow::Ok(())
2102 }
2103
2104 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2105 let buffer = buffer_handle.read(cx);
2106
2107 let file = buffer.file().cloned();
2108
2109 let Some(file) = File::from_dyn(file.as_ref()) else {
2110 return;
2111 };
2112 if !file.is_local() {
2113 return;
2114 }
2115 let path = ProjectPath::from_file(file, cx);
2116 let worktree_id = file.worktree_id(cx);
2117 let language = buffer.language().cloned();
2118
2119 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2120 for (server_id, diagnostics) in
2121 diagnostics.get(file.path()).cloned().unwrap_or_default()
2122 {
2123 self.update_buffer_diagnostics(
2124 buffer_handle,
2125 server_id,
2126 None,
2127 None,
2128 diagnostics,
2129 Vec::new(),
2130 cx,
2131 )
2132 .log_err();
2133 }
2134 }
2135 let Some(language) = language else {
2136 return;
2137 };
2138 let Some(snapshot) = self
2139 .worktree_store
2140 .read(cx)
2141 .worktree_for_id(worktree_id, cx)
2142 .map(|worktree| worktree.read(cx).snapshot())
2143 else {
2144 return;
2145 };
2146 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2147
2148 for server_id in
2149 self.lsp_tree
2150 .get(path, language.name(), language.manifest(), &delegate, cx)
2151 {
2152 let server = self
2153 .language_servers
2154 .get(&server_id)
2155 .and_then(|server_state| {
2156 if let LanguageServerState::Running { server, .. } = server_state {
2157 Some(server.clone())
2158 } else {
2159 None
2160 }
2161 });
2162 let server = match server {
2163 Some(server) => server,
2164 None => continue,
2165 };
2166
2167 buffer_handle.update(cx, |buffer, cx| {
2168 buffer.set_completion_triggers(
2169 server.server_id(),
2170 server
2171 .capabilities()
2172 .completion_provider
2173 .as_ref()
2174 .and_then(|provider| {
2175 provider
2176 .trigger_characters
2177 .as_ref()
2178 .map(|characters| characters.iter().cloned().collect())
2179 })
2180 .unwrap_or_default(),
2181 cx,
2182 );
2183 });
2184 }
2185 }
2186
2187 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2188 buffer.update(cx, |buffer, cx| {
2189 let Some(language) = buffer.language() else {
2190 return;
2191 };
2192 let path = ProjectPath {
2193 worktree_id: old_file.worktree_id(cx),
2194 path: old_file.path.clone(),
2195 };
2196 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2197 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2198 buffer.set_completion_triggers(server_id, Default::default(), cx);
2199 }
2200 });
2201 }
2202
2203 fn update_buffer_diagnostics(
2204 &mut self,
2205 buffer: &Entity<Buffer>,
2206 server_id: LanguageServerId,
2207 result_id: Option<String>,
2208 version: Option<i32>,
2209 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2210 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2211 cx: &mut Context<LspStore>,
2212 ) -> Result<()> {
2213 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2214 Ordering::Equal
2215 .then_with(|| b.is_primary.cmp(&a.is_primary))
2216 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2217 .then_with(|| a.severity.cmp(&b.severity))
2218 .then_with(|| a.message.cmp(&b.message))
2219 }
2220
2221 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2222 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2223 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2224
2225 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2226 Ordering::Equal
2227 .then_with(|| a.range.start.cmp(&b.range.start))
2228 .then_with(|| b.range.end.cmp(&a.range.end))
2229 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2230 });
2231
2232 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2233
2234 let edits_since_save = std::cell::LazyCell::new(|| {
2235 let saved_version = buffer.read(cx).saved_version();
2236 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2237 });
2238
2239 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2240
2241 for (new_diagnostic, entry) in diagnostics {
2242 let start;
2243 let end;
2244 if new_diagnostic && entry.diagnostic.is_disk_based {
2245 // Some diagnostics are based on files on disk instead of buffers'
2246 // current contents. Adjust these diagnostics' ranges to reflect
2247 // any unsaved edits.
2248 // Do not alter the reused ones though, as their coordinates were stored as anchors
2249 // and were properly adjusted on reuse.
2250 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2251 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2252 } else {
2253 start = entry.range.start;
2254 end = entry.range.end;
2255 }
2256
2257 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2258 ..snapshot.clip_point_utf16(end, Bias::Right);
2259
2260 // Expand empty ranges by one codepoint
2261 if range.start == range.end {
2262 // This will be go to the next boundary when being clipped
2263 range.end.column += 1;
2264 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2265 if range.start == range.end && range.end.column > 0 {
2266 range.start.column -= 1;
2267 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2268 }
2269 }
2270
2271 sanitized_diagnostics.push(DiagnosticEntry {
2272 range,
2273 diagnostic: entry.diagnostic,
2274 });
2275 }
2276 drop(edits_since_save);
2277
2278 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2279 buffer.update(cx, |buffer, cx| {
2280 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2281 self.buffer_pull_diagnostics_result_ids
2282 .entry(server_id)
2283 .or_default()
2284 .insert(abs_path, result_id);
2285 }
2286
2287 buffer.update_diagnostics(server_id, set, cx)
2288 });
2289
2290 Ok(())
2291 }
2292
2293 fn register_language_server_for_invisible_worktree(
2294 &mut self,
2295 worktree: &Entity<Worktree>,
2296 language_server_id: LanguageServerId,
2297 cx: &mut App,
2298 ) {
2299 let worktree = worktree.read(cx);
2300 let worktree_id = worktree.id();
2301 debug_assert!(!worktree.is_visible());
2302 let Some(mut origin_seed) = self
2303 .language_server_ids
2304 .iter()
2305 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2306 else {
2307 return;
2308 };
2309 origin_seed.worktree_id = worktree_id;
2310 self.language_server_ids
2311 .entry(origin_seed)
2312 .or_insert_with(|| UnifiedLanguageServer {
2313 id: language_server_id,
2314 project_roots: Default::default(),
2315 });
2316 }
2317
2318 fn register_buffer_with_language_servers(
2319 &mut self,
2320 buffer_handle: &Entity<Buffer>,
2321 only_register_servers: HashSet<LanguageServerSelector>,
2322 cx: &mut Context<LspStore>,
2323 ) {
2324 let buffer = buffer_handle.read(cx);
2325 let buffer_id = buffer.remote_id();
2326
2327 let Some(file) = File::from_dyn(buffer.file()) else {
2328 return;
2329 };
2330 if !file.is_local() {
2331 return;
2332 }
2333
2334 let abs_path = file.abs_path(cx);
2335 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2336 return;
2337 };
2338 let initial_snapshot = buffer.text_snapshot();
2339 let worktree_id = file.worktree_id(cx);
2340
2341 let Some(language) = buffer.language().cloned() else {
2342 return;
2343 };
2344 let path: Arc<Path> = file
2345 .path()
2346 .parent()
2347 .map(Arc::from)
2348 .unwrap_or_else(|| file.path().clone());
2349 let Some(worktree) = self
2350 .worktree_store
2351 .read(cx)
2352 .worktree_for_id(worktree_id, cx)
2353 else {
2354 return;
2355 };
2356 let language_name = language.name();
2357 let (reused, delegate, servers) = self
2358 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2359 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2360 .unwrap_or_else(|| {
2361 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2362 let delegate: Arc<dyn ManifestDelegate> =
2363 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2364
2365 let servers = self
2366 .lsp_tree
2367 .walk(
2368 ProjectPath { worktree_id, path },
2369 language.name(),
2370 language.manifest(),
2371 &delegate,
2372 cx,
2373 )
2374 .collect::<Vec<_>>();
2375 (false, lsp_delegate, servers)
2376 });
2377 let servers_and_adapters = servers
2378 .into_iter()
2379 .filter_map(|server_node| {
2380 if reused && server_node.server_id().is_none() {
2381 return None;
2382 }
2383 if !only_register_servers.is_empty() {
2384 if let Some(server_id) = server_node.server_id()
2385 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2386 {
2387 return None;
2388 }
2389 if let Some(name) = server_node.name()
2390 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2391 {
2392 return None;
2393 }
2394 }
2395
2396 let server_id = server_node.server_id_or_init(|disposition| {
2397 let path = &disposition.path;
2398
2399 {
2400 let uri =
2401 Url::from_file_path(worktree.read(cx).abs_path().join(&path.path));
2402
2403 let server_id = self.get_or_insert_language_server(
2404 &worktree,
2405 delegate.clone(),
2406 disposition,
2407 &language_name,
2408 cx,
2409 );
2410
2411 if let Some(state) = self.language_servers.get(&server_id)
2412 && let Ok(uri) = uri
2413 {
2414 state.add_workspace_folder(uri);
2415 };
2416 server_id
2417 }
2418 })?;
2419 let server_state = self.language_servers.get(&server_id)?;
2420 if let LanguageServerState::Running {
2421 server, adapter, ..
2422 } = server_state
2423 {
2424 Some((server.clone(), adapter.clone()))
2425 } else {
2426 None
2427 }
2428 })
2429 .collect::<Vec<_>>();
2430 for (server, adapter) in servers_and_adapters {
2431 buffer_handle.update(cx, |buffer, cx| {
2432 buffer.set_completion_triggers(
2433 server.server_id(),
2434 server
2435 .capabilities()
2436 .completion_provider
2437 .as_ref()
2438 .and_then(|provider| {
2439 provider
2440 .trigger_characters
2441 .as_ref()
2442 .map(|characters| characters.iter().cloned().collect())
2443 })
2444 .unwrap_or_default(),
2445 cx,
2446 );
2447 });
2448
2449 let snapshot = LspBufferSnapshot {
2450 version: 0,
2451 snapshot: initial_snapshot.clone(),
2452 };
2453
2454 let mut registered = false;
2455 self.buffer_snapshots
2456 .entry(buffer_id)
2457 .or_default()
2458 .entry(server.server_id())
2459 .or_insert_with(|| {
2460 registered = true;
2461 server.register_buffer(
2462 uri.clone(),
2463 adapter.language_id(&language.name()),
2464 0,
2465 initial_snapshot.text(),
2466 );
2467
2468 vec![snapshot]
2469 });
2470
2471 self.buffers_opened_in_servers
2472 .entry(buffer_id)
2473 .or_default()
2474 .insert(server.server_id());
2475 if registered {
2476 cx.emit(LspStoreEvent::LanguageServerUpdate {
2477 language_server_id: server.server_id(),
2478 name: None,
2479 message: proto::update_language_server::Variant::RegisteredForBuffer(
2480 proto::RegisteredForBuffer {
2481 buffer_abs_path: abs_path.to_string_lossy().to_string(),
2482 buffer_id: buffer_id.to_proto(),
2483 },
2484 ),
2485 });
2486 }
2487 }
2488 }
2489
2490 fn reuse_existing_language_server<'lang_name>(
2491 &self,
2492 server_tree: &LanguageServerTree,
2493 worktree: &Entity<Worktree>,
2494 language_name: &'lang_name LanguageName,
2495 cx: &mut App,
2496 ) -> Option<(
2497 Arc<LocalLspAdapterDelegate>,
2498 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2499 )> {
2500 if worktree.read(cx).is_visible() {
2501 return None;
2502 }
2503
2504 let worktree_store = self.worktree_store.read(cx);
2505 let servers = server_tree
2506 .instances
2507 .iter()
2508 .filter(|(worktree_id, _)| {
2509 worktree_store
2510 .worktree_for_id(**worktree_id, cx)
2511 .is_some_and(|worktree| worktree.read(cx).is_visible())
2512 })
2513 .flat_map(|(worktree_id, servers)| {
2514 servers
2515 .roots
2516 .iter()
2517 .flat_map(|(_, language_servers)| language_servers)
2518 .map(move |(_, (server_node, server_languages))| {
2519 (worktree_id, server_node, server_languages)
2520 })
2521 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2522 .map(|(worktree_id, server_node, _)| {
2523 (
2524 *worktree_id,
2525 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2526 )
2527 })
2528 })
2529 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2530 acc.entry(worktree_id)
2531 .or_insert_with(Vec::new)
2532 .push(server_node);
2533 acc
2534 })
2535 .into_values()
2536 .max_by_key(|servers| servers.len())?;
2537
2538 let worktree_id = worktree.read(cx).id();
2539 let apply = move |tree: &mut LanguageServerTree| {
2540 for server_node in &servers {
2541 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2542 }
2543 servers
2544 };
2545
2546 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2547 Some((delegate, apply))
2548 }
2549
2550 pub(crate) fn unregister_old_buffer_from_language_servers(
2551 &mut self,
2552 buffer: &Entity<Buffer>,
2553 old_file: &File,
2554 cx: &mut App,
2555 ) {
2556 let old_path = match old_file.as_local() {
2557 Some(local) => local.abs_path(cx),
2558 None => return,
2559 };
2560
2561 let Ok(file_url) = lsp::Url::from_file_path(old_path.as_path()) else {
2562 debug_panic!(
2563 "`{}` is not parseable as an URI",
2564 old_path.to_string_lossy()
2565 );
2566 return;
2567 };
2568 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2569 }
2570
2571 pub(crate) fn unregister_buffer_from_language_servers(
2572 &mut self,
2573 buffer: &Entity<Buffer>,
2574 file_url: &lsp::Url,
2575 cx: &mut App,
2576 ) {
2577 buffer.update(cx, |buffer, cx| {
2578 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2579
2580 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2581 language_server.unregister_buffer(file_url.clone());
2582 }
2583 });
2584 }
2585
2586 fn buffer_snapshot_for_lsp_version(
2587 &mut self,
2588 buffer: &Entity<Buffer>,
2589 server_id: LanguageServerId,
2590 version: Option<i32>,
2591 cx: &App,
2592 ) -> Result<TextBufferSnapshot> {
2593 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2594
2595 if let Some(version) = version {
2596 let buffer_id = buffer.read(cx).remote_id();
2597 let snapshots = if let Some(snapshots) = self
2598 .buffer_snapshots
2599 .get_mut(&buffer_id)
2600 .and_then(|m| m.get_mut(&server_id))
2601 {
2602 snapshots
2603 } else if version == 0 {
2604 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2605 // We detect this case and treat it as if the version was `None`.
2606 return Ok(buffer.read(cx).text_snapshot());
2607 } else {
2608 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2609 };
2610
2611 let found_snapshot = snapshots
2612 .binary_search_by_key(&version, |e| e.version)
2613 .map(|ix| snapshots[ix].snapshot.clone())
2614 .map_err(|_| {
2615 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2616 })?;
2617
2618 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2619 Ok(found_snapshot)
2620 } else {
2621 Ok((buffer.read(cx)).text_snapshot())
2622 }
2623 }
2624
2625 async fn get_server_code_actions_from_action_kinds(
2626 lsp_store: &WeakEntity<LspStore>,
2627 language_server_id: LanguageServerId,
2628 code_action_kinds: Vec<lsp::CodeActionKind>,
2629 buffer: &Entity<Buffer>,
2630 cx: &mut AsyncApp,
2631 ) -> Result<Vec<CodeAction>> {
2632 let actions = lsp_store
2633 .update(cx, move |this, cx| {
2634 let request = GetCodeActions {
2635 range: text::Anchor::MIN..text::Anchor::MAX,
2636 kinds: Some(code_action_kinds),
2637 };
2638 let server = LanguageServerToQuery::Other(language_server_id);
2639 this.request_lsp(buffer.clone(), server, request, cx)
2640 })?
2641 .await?;
2642 Ok(actions)
2643 }
2644
2645 pub async fn execute_code_actions_on_server(
2646 lsp_store: &WeakEntity<LspStore>,
2647 language_server: &Arc<LanguageServer>,
2648
2649 actions: Vec<CodeAction>,
2650 push_to_history: bool,
2651 project_transaction: &mut ProjectTransaction,
2652 cx: &mut AsyncApp,
2653 ) -> anyhow::Result<()> {
2654 for mut action in actions {
2655 Self::try_resolve_code_action(language_server, &mut action)
2656 .await
2657 .context("resolving a formatting code action")?;
2658
2659 if let Some(edit) = action.lsp_action.edit() {
2660 if edit.changes.is_none() && edit.document_changes.is_none() {
2661 continue;
2662 }
2663
2664 let new = Self::deserialize_workspace_edit(
2665 lsp_store.upgrade().context("project dropped")?,
2666 edit.clone(),
2667 push_to_history,
2668 language_server.clone(),
2669 cx,
2670 )
2671 .await?;
2672 project_transaction.0.extend(new.0);
2673 }
2674
2675 if let Some(command) = action.lsp_action.command() {
2676 let server_capabilities = language_server.capabilities();
2677 let available_commands = server_capabilities
2678 .execute_command_provider
2679 .as_ref()
2680 .map(|options| options.commands.as_slice())
2681 .unwrap_or_default();
2682 if available_commands.contains(&command.command) {
2683 lsp_store.update(cx, |lsp_store, _| {
2684 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2685 mode.last_workspace_edits_by_language_server
2686 .remove(&language_server.server_id());
2687 }
2688 })?;
2689
2690 language_server
2691 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2692 command: command.command.clone(),
2693 arguments: command.arguments.clone().unwrap_or_default(),
2694 ..Default::default()
2695 })
2696 .await
2697 .into_response()
2698 .context("execute command")?;
2699
2700 lsp_store.update(cx, |this, _| {
2701 if let LspStoreMode::Local(mode) = &mut this.mode {
2702 project_transaction.0.extend(
2703 mode.last_workspace_edits_by_language_server
2704 .remove(&language_server.server_id())
2705 .unwrap_or_default()
2706 .0,
2707 )
2708 }
2709 })?;
2710 } else {
2711 log::warn!(
2712 "Cannot execute a command {} not listed in the language server capabilities",
2713 command.command
2714 )
2715 }
2716 }
2717 }
2718 Ok(())
2719 }
2720
2721 pub async fn deserialize_text_edits(
2722 this: Entity<LspStore>,
2723 buffer_to_edit: Entity<Buffer>,
2724 edits: Vec<lsp::TextEdit>,
2725 push_to_history: bool,
2726 _: Arc<CachedLspAdapter>,
2727 language_server: Arc<LanguageServer>,
2728 cx: &mut AsyncApp,
2729 ) -> Result<Option<Transaction>> {
2730 let edits = this
2731 .update(cx, |this, cx| {
2732 this.as_local_mut().unwrap().edits_from_lsp(
2733 &buffer_to_edit,
2734 edits,
2735 language_server.server_id(),
2736 None,
2737 cx,
2738 )
2739 })?
2740 .await?;
2741
2742 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2743 buffer.finalize_last_transaction();
2744 buffer.start_transaction();
2745 for (range, text) in edits {
2746 buffer.edit([(range, text)], None, cx);
2747 }
2748
2749 if buffer.end_transaction(cx).is_some() {
2750 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2751 if !push_to_history {
2752 buffer.forget_transaction(transaction.id);
2753 }
2754 Some(transaction)
2755 } else {
2756 None
2757 }
2758 })?;
2759
2760 Ok(transaction)
2761 }
2762
2763 #[allow(clippy::type_complexity)]
2764 pub(crate) fn edits_from_lsp(
2765 &mut self,
2766 buffer: &Entity<Buffer>,
2767 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2768 server_id: LanguageServerId,
2769 version: Option<i32>,
2770 cx: &mut Context<LspStore>,
2771 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2772 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2773 cx.background_spawn(async move {
2774 let snapshot = snapshot?;
2775 let mut lsp_edits = lsp_edits
2776 .into_iter()
2777 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2778 .collect::<Vec<_>>();
2779
2780 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2781
2782 let mut lsp_edits = lsp_edits.into_iter().peekable();
2783 let mut edits = Vec::new();
2784 while let Some((range, mut new_text)) = lsp_edits.next() {
2785 // Clip invalid ranges provided by the language server.
2786 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2787 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2788
2789 // Combine any LSP edits that are adjacent.
2790 //
2791 // Also, combine LSP edits that are separated from each other by only
2792 // a newline. This is important because for some code actions,
2793 // Rust-analyzer rewrites the entire buffer via a series of edits that
2794 // are separated by unchanged newline characters.
2795 //
2796 // In order for the diffing logic below to work properly, any edits that
2797 // cancel each other out must be combined into one.
2798 while let Some((next_range, next_text)) = lsp_edits.peek() {
2799 if next_range.start.0 > range.end {
2800 if next_range.start.0.row > range.end.row + 1
2801 || next_range.start.0.column > 0
2802 || snapshot.clip_point_utf16(
2803 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2804 Bias::Left,
2805 ) > range.end
2806 {
2807 break;
2808 }
2809 new_text.push('\n');
2810 }
2811 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2812 new_text.push_str(next_text);
2813 lsp_edits.next();
2814 }
2815
2816 // For multiline edits, perform a diff of the old and new text so that
2817 // we can identify the changes more precisely, preserving the locations
2818 // of any anchors positioned in the unchanged regions.
2819 if range.end.row > range.start.row {
2820 let offset = range.start.to_offset(&snapshot);
2821 let old_text = snapshot.text_for_range(range).collect::<String>();
2822 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2823 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2824 (
2825 snapshot.anchor_after(offset + range.start)
2826 ..snapshot.anchor_before(offset + range.end),
2827 replacement,
2828 )
2829 }));
2830 } else if range.end == range.start {
2831 let anchor = snapshot.anchor_after(range.start);
2832 edits.push((anchor..anchor, new_text.into()));
2833 } else {
2834 let edit_start = snapshot.anchor_after(range.start);
2835 let edit_end = snapshot.anchor_before(range.end);
2836 edits.push((edit_start..edit_end, new_text.into()));
2837 }
2838 }
2839
2840 Ok(edits)
2841 })
2842 }
2843
2844 pub(crate) async fn deserialize_workspace_edit(
2845 this: Entity<LspStore>,
2846 edit: lsp::WorkspaceEdit,
2847 push_to_history: bool,
2848 language_server: Arc<LanguageServer>,
2849 cx: &mut AsyncApp,
2850 ) -> Result<ProjectTransaction> {
2851 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2852
2853 let mut operations = Vec::new();
2854 if let Some(document_changes) = edit.document_changes {
2855 match document_changes {
2856 lsp::DocumentChanges::Edits(edits) => {
2857 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2858 }
2859 lsp::DocumentChanges::Operations(ops) => operations = ops,
2860 }
2861 } else if let Some(changes) = edit.changes {
2862 operations.extend(changes.into_iter().map(|(uri, edits)| {
2863 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2864 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2865 uri,
2866 version: None,
2867 },
2868 edits: edits.into_iter().map(Edit::Plain).collect(),
2869 })
2870 }));
2871 }
2872
2873 let mut project_transaction = ProjectTransaction::default();
2874 for operation in operations {
2875 match operation {
2876 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2877 let abs_path = op
2878 .uri
2879 .to_file_path()
2880 .map_err(|()| anyhow!("can't convert URI to path"))?;
2881
2882 if let Some(parent_path) = abs_path.parent() {
2883 fs.create_dir(parent_path).await?;
2884 }
2885 if abs_path.ends_with("/") {
2886 fs.create_dir(&abs_path).await?;
2887 } else {
2888 fs.create_file(
2889 &abs_path,
2890 op.options
2891 .map(|options| fs::CreateOptions {
2892 overwrite: options.overwrite.unwrap_or(false),
2893 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2894 })
2895 .unwrap_or_default(),
2896 )
2897 .await?;
2898 }
2899 }
2900
2901 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2902 let source_abs_path = op
2903 .old_uri
2904 .to_file_path()
2905 .map_err(|()| anyhow!("can't convert URI to path"))?;
2906 let target_abs_path = op
2907 .new_uri
2908 .to_file_path()
2909 .map_err(|()| anyhow!("can't convert URI to path"))?;
2910 fs.rename(
2911 &source_abs_path,
2912 &target_abs_path,
2913 op.options
2914 .map(|options| fs::RenameOptions {
2915 overwrite: options.overwrite.unwrap_or(false),
2916 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2917 })
2918 .unwrap_or_default(),
2919 )
2920 .await?;
2921 }
2922
2923 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
2924 let abs_path = op
2925 .uri
2926 .to_file_path()
2927 .map_err(|()| anyhow!("can't convert URI to path"))?;
2928 let options = op
2929 .options
2930 .map(|options| fs::RemoveOptions {
2931 recursive: options.recursive.unwrap_or(false),
2932 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
2933 })
2934 .unwrap_or_default();
2935 if abs_path.ends_with("/") {
2936 fs.remove_dir(&abs_path, options).await?;
2937 } else {
2938 fs.remove_file(&abs_path, options).await?;
2939 }
2940 }
2941
2942 lsp::DocumentChangeOperation::Edit(op) => {
2943 let buffer_to_edit = this
2944 .update(cx, |this, cx| {
2945 this.open_local_buffer_via_lsp(
2946 op.text_document.uri.clone(),
2947 language_server.server_id(),
2948 cx,
2949 )
2950 })?
2951 .await?;
2952
2953 let edits = this
2954 .update(cx, |this, cx| {
2955 let path = buffer_to_edit.read(cx).project_path(cx);
2956 let active_entry = this.active_entry;
2957 let is_active_entry = path.is_some_and(|project_path| {
2958 this.worktree_store
2959 .read(cx)
2960 .entry_for_path(&project_path, cx)
2961 .is_some_and(|entry| Some(entry.id) == active_entry)
2962 });
2963 let local = this.as_local_mut().unwrap();
2964
2965 let (mut edits, mut snippet_edits) = (vec![], vec![]);
2966 for edit in op.edits {
2967 match edit {
2968 Edit::Plain(edit) => {
2969 if !edits.contains(&edit) {
2970 edits.push(edit)
2971 }
2972 }
2973 Edit::Annotated(edit) => {
2974 if !edits.contains(&edit.text_edit) {
2975 edits.push(edit.text_edit)
2976 }
2977 }
2978 Edit::Snippet(edit) => {
2979 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
2980 else {
2981 continue;
2982 };
2983
2984 if is_active_entry {
2985 snippet_edits.push((edit.range, snippet));
2986 } else {
2987 // Since this buffer is not focused, apply a normal edit.
2988 let new_edit = TextEdit {
2989 range: edit.range,
2990 new_text: snippet.text,
2991 };
2992 if !edits.contains(&new_edit) {
2993 edits.push(new_edit);
2994 }
2995 }
2996 }
2997 }
2998 }
2999 if !snippet_edits.is_empty() {
3000 let buffer_id = buffer_to_edit.read(cx).remote_id();
3001 let version = if let Some(buffer_version) = op.text_document.version
3002 {
3003 local
3004 .buffer_snapshot_for_lsp_version(
3005 &buffer_to_edit,
3006 language_server.server_id(),
3007 Some(buffer_version),
3008 cx,
3009 )
3010 .ok()
3011 .map(|snapshot| snapshot.version)
3012 } else {
3013 Some(buffer_to_edit.read(cx).saved_version().clone())
3014 };
3015
3016 let most_recent_edit = version.and_then(|version| {
3017 version.iter().max_by_key(|timestamp| timestamp.value)
3018 });
3019 // Check if the edit that triggered that edit has been made by this participant.
3020
3021 if let Some(most_recent_edit) = most_recent_edit {
3022 cx.emit(LspStoreEvent::SnippetEdit {
3023 buffer_id,
3024 edits: snippet_edits,
3025 most_recent_edit,
3026 });
3027 }
3028 }
3029
3030 local.edits_from_lsp(
3031 &buffer_to_edit,
3032 edits,
3033 language_server.server_id(),
3034 op.text_document.version,
3035 cx,
3036 )
3037 })?
3038 .await?;
3039
3040 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3041 buffer.finalize_last_transaction();
3042 buffer.start_transaction();
3043 for (range, text) in edits {
3044 buffer.edit([(range, text)], None, cx);
3045 }
3046
3047 buffer.end_transaction(cx).and_then(|transaction_id| {
3048 if push_to_history {
3049 buffer.finalize_last_transaction();
3050 buffer.get_transaction(transaction_id).cloned()
3051 } else {
3052 buffer.forget_transaction(transaction_id)
3053 }
3054 })
3055 })?;
3056 if let Some(transaction) = transaction {
3057 project_transaction.0.insert(buffer_to_edit, transaction);
3058 }
3059 }
3060 }
3061 }
3062
3063 Ok(project_transaction)
3064 }
3065
3066 async fn on_lsp_workspace_edit(
3067 this: WeakEntity<LspStore>,
3068 params: lsp::ApplyWorkspaceEditParams,
3069 server_id: LanguageServerId,
3070 cx: &mut AsyncApp,
3071 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3072 let this = this.upgrade().context("project project closed")?;
3073 let language_server = this
3074 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3075 .context("language server not found")?;
3076 let transaction = Self::deserialize_workspace_edit(
3077 this.clone(),
3078 params.edit,
3079 true,
3080 language_server.clone(),
3081 cx,
3082 )
3083 .await
3084 .log_err();
3085 this.update(cx, |this, _| {
3086 if let Some(transaction) = transaction {
3087 this.as_local_mut()
3088 .unwrap()
3089 .last_workspace_edits_by_language_server
3090 .insert(server_id, transaction);
3091 }
3092 })?;
3093 Ok(lsp::ApplyWorkspaceEditResponse {
3094 applied: true,
3095 failed_change: None,
3096 failure_reason: None,
3097 })
3098 }
3099
3100 fn remove_worktree(
3101 &mut self,
3102 id_to_remove: WorktreeId,
3103 cx: &mut Context<LspStore>,
3104 ) -> Vec<LanguageServerId> {
3105 self.diagnostics.remove(&id_to_remove);
3106 self.prettier_store.update(cx, |prettier_store, cx| {
3107 prettier_store.remove_worktree(id_to_remove, cx);
3108 });
3109
3110 let mut servers_to_remove = BTreeSet::default();
3111 let mut servers_to_preserve = HashSet::default();
3112 for (seed, state) in &self.language_server_ids {
3113 if seed.worktree_id == id_to_remove {
3114 servers_to_remove.insert(state.id);
3115 } else {
3116 servers_to_preserve.insert(state.id);
3117 }
3118 }
3119 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3120 self.language_server_ids
3121 .retain(|_, state| !servers_to_remove.contains(&state.id));
3122 for server_id_to_remove in &servers_to_remove {
3123 self.language_server_watched_paths
3124 .remove(server_id_to_remove);
3125 self.language_server_paths_watched_for_rename
3126 .remove(server_id_to_remove);
3127 self.last_workspace_edits_by_language_server
3128 .remove(server_id_to_remove);
3129 self.language_servers.remove(server_id_to_remove);
3130 self.buffer_pull_diagnostics_result_ids
3131 .remove(server_id_to_remove);
3132 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3133 buffer_servers.remove(server_id_to_remove);
3134 }
3135 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3136 }
3137 servers_to_remove.into_iter().collect()
3138 }
3139
3140 fn rebuild_watched_paths_inner<'a>(
3141 &'a self,
3142 language_server_id: LanguageServerId,
3143 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3144 cx: &mut Context<LspStore>,
3145 ) -> LanguageServerWatchedPathsBuilder {
3146 let worktrees = self
3147 .worktree_store
3148 .read(cx)
3149 .worktrees()
3150 .filter_map(|worktree| {
3151 self.language_servers_for_worktree(worktree.read(cx).id())
3152 .find(|server| server.server_id() == language_server_id)
3153 .map(|_| worktree)
3154 })
3155 .collect::<Vec<_>>();
3156
3157 let mut worktree_globs = HashMap::default();
3158 let mut abs_globs = HashMap::default();
3159 log::trace!(
3160 "Processing new watcher paths for language server with id {}",
3161 language_server_id
3162 );
3163
3164 for watcher in watchers {
3165 if let Some((worktree, literal_prefix, pattern)) =
3166 self.worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3167 {
3168 worktree.update(cx, |worktree, _| {
3169 if let Some((tree, glob)) =
3170 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3171 {
3172 tree.add_path_prefix_to_scan(literal_prefix.into());
3173 worktree_globs
3174 .entry(tree.id())
3175 .or_insert_with(GlobSetBuilder::new)
3176 .add(glob);
3177 }
3178 });
3179 } else {
3180 let (path, pattern) = match &watcher.glob_pattern {
3181 lsp::GlobPattern::String(s) => {
3182 let watcher_path = SanitizedPath::from(s);
3183 let path = glob_literal_prefix(watcher_path.as_path());
3184 let pattern = watcher_path
3185 .as_path()
3186 .strip_prefix(&path)
3187 .map(|p| p.to_string_lossy().to_string())
3188 .unwrap_or_else(|e| {
3189 debug_panic!(
3190 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3191 s,
3192 path.display(),
3193 e
3194 );
3195 watcher_path.as_path().to_string_lossy().to_string()
3196 });
3197 (path, pattern)
3198 }
3199 lsp::GlobPattern::Relative(rp) => {
3200 let Ok(mut base_uri) = match &rp.base_uri {
3201 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3202 lsp::OneOf::Right(base_uri) => base_uri,
3203 }
3204 .to_file_path() else {
3205 continue;
3206 };
3207
3208 let path = glob_literal_prefix(Path::new(&rp.pattern));
3209 let pattern = Path::new(&rp.pattern)
3210 .strip_prefix(&path)
3211 .map(|p| p.to_string_lossy().to_string())
3212 .unwrap_or_else(|e| {
3213 debug_panic!(
3214 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3215 rp.pattern,
3216 path.display(),
3217 e
3218 );
3219 rp.pattern.clone()
3220 });
3221 base_uri.push(path);
3222 (base_uri, pattern)
3223 }
3224 };
3225
3226 if let Some(glob) = Glob::new(&pattern).log_err() {
3227 if !path
3228 .components()
3229 .any(|c| matches!(c, path::Component::Normal(_)))
3230 {
3231 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3232 // rather than adding a new watcher for `/`.
3233 for worktree in &worktrees {
3234 worktree_globs
3235 .entry(worktree.read(cx).id())
3236 .or_insert_with(GlobSetBuilder::new)
3237 .add(glob.clone());
3238 }
3239 } else {
3240 abs_globs
3241 .entry(path.into())
3242 .or_insert_with(GlobSetBuilder::new)
3243 .add(glob);
3244 }
3245 }
3246 }
3247 }
3248
3249 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3250 for (worktree_id, builder) in worktree_globs {
3251 if let Ok(globset) = builder.build() {
3252 watch_builder.watch_worktree(worktree_id, globset);
3253 }
3254 }
3255 for (abs_path, builder) in abs_globs {
3256 if let Ok(globset) = builder.build() {
3257 watch_builder.watch_abs_path(abs_path, globset);
3258 }
3259 }
3260 watch_builder
3261 }
3262
3263 fn worktree_and_path_for_file_watcher(
3264 &self,
3265 worktrees: &[Entity<Worktree>],
3266 watcher: &FileSystemWatcher,
3267 cx: &App,
3268 ) -> Option<(Entity<Worktree>, PathBuf, String)> {
3269 worktrees.iter().find_map(|worktree| {
3270 let tree = worktree.read(cx);
3271 let worktree_root_path = tree.abs_path();
3272 match &watcher.glob_pattern {
3273 lsp::GlobPattern::String(s) => {
3274 let watcher_path = SanitizedPath::from(s);
3275 let relative = watcher_path
3276 .as_path()
3277 .strip_prefix(&worktree_root_path)
3278 .ok()?;
3279 let literal_prefix = glob_literal_prefix(relative);
3280 Some((
3281 worktree.clone(),
3282 literal_prefix,
3283 relative.to_string_lossy().to_string(),
3284 ))
3285 }
3286 lsp::GlobPattern::Relative(rp) => {
3287 let base_uri = match &rp.base_uri {
3288 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3289 lsp::OneOf::Right(base_uri) => base_uri,
3290 }
3291 .to_file_path()
3292 .ok()?;
3293 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3294 let mut literal_prefix = relative.to_owned();
3295 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3296 Some((worktree.clone(), literal_prefix, rp.pattern.clone()))
3297 }
3298 }
3299 })
3300 }
3301
3302 fn rebuild_watched_paths(
3303 &mut self,
3304 language_server_id: LanguageServerId,
3305 cx: &mut Context<LspStore>,
3306 ) {
3307 let Some(watchers) = self
3308 .language_server_watcher_registrations
3309 .get(&language_server_id)
3310 else {
3311 return;
3312 };
3313
3314 let watch_builder =
3315 self.rebuild_watched_paths_inner(language_server_id, watchers.values().flatten(), cx);
3316 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3317 self.language_server_watched_paths
3318 .insert(language_server_id, watcher);
3319
3320 cx.notify();
3321 }
3322
3323 fn on_lsp_did_change_watched_files(
3324 &mut self,
3325 language_server_id: LanguageServerId,
3326 registration_id: &str,
3327 params: DidChangeWatchedFilesRegistrationOptions,
3328 cx: &mut Context<LspStore>,
3329 ) {
3330 let registrations = self
3331 .language_server_watcher_registrations
3332 .entry(language_server_id)
3333 .or_default();
3334
3335 registrations.insert(registration_id.to_string(), params.watchers);
3336
3337 self.rebuild_watched_paths(language_server_id, cx);
3338 }
3339
3340 fn on_lsp_unregister_did_change_watched_files(
3341 &mut self,
3342 language_server_id: LanguageServerId,
3343 registration_id: &str,
3344 cx: &mut Context<LspStore>,
3345 ) {
3346 let registrations = self
3347 .language_server_watcher_registrations
3348 .entry(language_server_id)
3349 .or_default();
3350
3351 if registrations.remove(registration_id).is_some() {
3352 log::info!(
3353 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3354 language_server_id,
3355 registration_id
3356 );
3357 } else {
3358 log::warn!(
3359 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3360 language_server_id,
3361 registration_id
3362 );
3363 }
3364
3365 self.rebuild_watched_paths(language_server_id, cx);
3366 }
3367
3368 async fn initialization_options_for_adapter(
3369 adapter: Arc<dyn LspAdapter>,
3370 fs: &dyn Fs,
3371 delegate: &Arc<dyn LspAdapterDelegate>,
3372 ) -> Result<Option<serde_json::Value>> {
3373 let Some(mut initialization_config) =
3374 adapter.clone().initialization_options(fs, delegate).await?
3375 else {
3376 return Ok(None);
3377 };
3378
3379 for other_adapter in delegate.registered_lsp_adapters() {
3380 if other_adapter.name() == adapter.name() {
3381 continue;
3382 }
3383 if let Ok(Some(target_config)) = other_adapter
3384 .clone()
3385 .additional_initialization_options(adapter.name(), fs, delegate)
3386 .await
3387 {
3388 merge_json_value_into(target_config.clone(), &mut initialization_config);
3389 }
3390 }
3391
3392 Ok(Some(initialization_config))
3393 }
3394
3395 fn toolchain_store(&self) -> &Entity<LocalToolchainStore> {
3396 &self.toolchain_store
3397 }
3398
3399 async fn workspace_configuration_for_adapter(
3400 adapter: Arc<dyn LspAdapter>,
3401 fs: &dyn Fs,
3402 delegate: &Arc<dyn LspAdapterDelegate>,
3403 toolchain: Option<Toolchain>,
3404 cx: &mut AsyncApp,
3405 ) -> Result<serde_json::Value> {
3406 let mut workspace_config = adapter
3407 .clone()
3408 .workspace_configuration(fs, delegate, toolchain, cx)
3409 .await?;
3410
3411 for other_adapter in delegate.registered_lsp_adapters() {
3412 if other_adapter.name() == adapter.name() {
3413 continue;
3414 }
3415 if let Ok(Some(target_config)) = other_adapter
3416 .clone()
3417 .additional_workspace_configuration(adapter.name(), fs, delegate, cx)
3418 .await
3419 {
3420 merge_json_value_into(target_config.clone(), &mut workspace_config);
3421 }
3422 }
3423
3424 Ok(workspace_config)
3425 }
3426
3427 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3428 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3429 Some(server.clone())
3430 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3431 Some(Arc::clone(server))
3432 } else {
3433 None
3434 }
3435 }
3436}
3437
3438fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3439 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3440 cx.emit(LspStoreEvent::LanguageServerUpdate {
3441 language_server_id: server.server_id(),
3442 name: Some(server.name()),
3443 message: proto::update_language_server::Variant::MetadataUpdated(
3444 proto::ServerMetadataUpdated {
3445 capabilities: Some(capabilities),
3446 },
3447 ),
3448 });
3449 }
3450}
3451
3452#[derive(Debug)]
3453pub struct FormattableBuffer {
3454 handle: Entity<Buffer>,
3455 abs_path: Option<PathBuf>,
3456 env: Option<HashMap<String, String>>,
3457 ranges: Option<Vec<Range<Anchor>>>,
3458}
3459
3460pub struct RemoteLspStore {
3461 upstream_client: Option<AnyProtoClient>,
3462 upstream_project_id: u64,
3463}
3464
3465pub(crate) enum LspStoreMode {
3466 Local(LocalLspStore), // ssh host and collab host
3467 Remote(RemoteLspStore), // collab guest
3468}
3469
3470impl LspStoreMode {
3471 fn is_local(&self) -> bool {
3472 matches!(self, LspStoreMode::Local(_))
3473 }
3474}
3475
3476pub struct LspStore {
3477 mode: LspStoreMode,
3478 last_formatting_failure: Option<String>,
3479 downstream_client: Option<(AnyProtoClient, u64)>,
3480 nonce: u128,
3481 buffer_store: Entity<BufferStore>,
3482 worktree_store: Entity<WorktreeStore>,
3483 pub languages: Arc<LanguageRegistry>,
3484 language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3485 active_entry: Option<ProjectEntryId>,
3486 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3487 _maintain_buffer_languages: Task<()>,
3488 diagnostic_summaries:
3489 HashMap<WorktreeId, HashMap<Arc<Path>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3490 pub(super) lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3491 lsp_document_colors: HashMap<BufferId, DocumentColorData>,
3492 lsp_code_lens: HashMap<BufferId, CodeLensData>,
3493}
3494
3495#[derive(Debug, Default, Clone)]
3496pub struct DocumentColors {
3497 pub colors: HashSet<DocumentColor>,
3498 pub cache_version: Option<usize>,
3499}
3500
3501type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3502type CodeLensTask = Shared<Task<std::result::Result<Vec<CodeAction>, Arc<anyhow::Error>>>>;
3503
3504#[derive(Debug, Default)]
3505struct DocumentColorData {
3506 colors_for_version: Global,
3507 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3508 cache_version: usize,
3509 colors_update: Option<(Global, DocumentColorTask)>,
3510}
3511
3512#[derive(Debug, Default)]
3513struct CodeLensData {
3514 lens_for_version: Global,
3515 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3516 update: Option<(Global, CodeLensTask)>,
3517}
3518
3519#[derive(Debug, PartialEq, Eq, Clone, Copy)]
3520pub enum LspFetchStrategy {
3521 IgnoreCache,
3522 UseCache { known_cache_version: Option<usize> },
3523}
3524
3525#[derive(Debug)]
3526pub enum LspStoreEvent {
3527 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3528 LanguageServerRemoved(LanguageServerId),
3529 LanguageServerUpdate {
3530 language_server_id: LanguageServerId,
3531 name: Option<LanguageServerName>,
3532 message: proto::update_language_server::Variant,
3533 },
3534 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3535 LanguageServerPrompt(LanguageServerPromptRequest),
3536 LanguageDetected {
3537 buffer: Entity<Buffer>,
3538 new_language: Option<Arc<Language>>,
3539 },
3540 Notification(String),
3541 RefreshInlayHints,
3542 RefreshCodeLens,
3543 DiagnosticsUpdated {
3544 server_id: LanguageServerId,
3545 paths: Vec<ProjectPath>,
3546 },
3547 DiskBasedDiagnosticsStarted {
3548 language_server_id: LanguageServerId,
3549 },
3550 DiskBasedDiagnosticsFinished {
3551 language_server_id: LanguageServerId,
3552 },
3553 SnippetEdit {
3554 buffer_id: BufferId,
3555 edits: Vec<(lsp::Range, Snippet)>,
3556 most_recent_edit: clock::Lamport,
3557 },
3558}
3559
3560#[derive(Clone, Debug, Serialize)]
3561pub struct LanguageServerStatus {
3562 pub name: LanguageServerName,
3563 pub pending_work: BTreeMap<String, LanguageServerProgress>,
3564 pub has_pending_diagnostic_updates: bool,
3565 progress_tokens: HashSet<String>,
3566}
3567
3568#[derive(Clone, Debug)]
3569struct CoreSymbol {
3570 pub language_server_name: LanguageServerName,
3571 pub source_worktree_id: WorktreeId,
3572 pub source_language_server_id: LanguageServerId,
3573 pub path: ProjectPath,
3574 pub name: String,
3575 pub kind: lsp::SymbolKind,
3576 pub range: Range<Unclipped<PointUtf16>>,
3577 pub signature: [u8; 32],
3578}
3579
3580impl LspStore {
3581 pub fn init(client: &AnyProtoClient) {
3582 client.add_entity_request_handler(Self::handle_multi_lsp_query);
3583 client.add_entity_request_handler(Self::handle_restart_language_servers);
3584 client.add_entity_request_handler(Self::handle_stop_language_servers);
3585 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3586 client.add_entity_message_handler(Self::handle_start_language_server);
3587 client.add_entity_message_handler(Self::handle_update_language_server);
3588 client.add_entity_message_handler(Self::handle_language_server_log);
3589 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3590 client.add_entity_request_handler(Self::handle_format_buffers);
3591 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3592 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3593 client.add_entity_request_handler(Self::handle_apply_code_action);
3594 client.add_entity_request_handler(Self::handle_inlay_hints);
3595 client.add_entity_request_handler(Self::handle_get_project_symbols);
3596 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3597 client.add_entity_request_handler(Self::handle_get_color_presentation);
3598 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3599 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3600 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3601 client.add_entity_request_handler(Self::handle_on_type_formatting);
3602 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3603 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3604 client.add_entity_request_handler(Self::handle_rename_project_entry);
3605 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3606 client.add_entity_request_handler(Self::handle_lsp_command::<GetCodeActions>);
3607 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3608 client.add_entity_request_handler(Self::handle_lsp_command::<GetHover>);
3609 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3610 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3611 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3612 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3613 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3614
3615 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3616 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3617 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3618 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3619 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3620 client.add_entity_request_handler(
3621 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3622 );
3623 client.add_entity_request_handler(
3624 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3625 );
3626 client.add_entity_request_handler(
3627 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3628 );
3629 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentDiagnostics>);
3630 }
3631
3632 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3633 match &self.mode {
3634 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3635 _ => None,
3636 }
3637 }
3638
3639 pub fn as_local(&self) -> Option<&LocalLspStore> {
3640 match &self.mode {
3641 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3642 _ => None,
3643 }
3644 }
3645
3646 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3647 match &mut self.mode {
3648 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3649 _ => None,
3650 }
3651 }
3652
3653 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3654 match &self.mode {
3655 LspStoreMode::Remote(RemoteLspStore {
3656 upstream_client: Some(upstream_client),
3657 upstream_project_id,
3658 ..
3659 }) => Some((upstream_client.clone(), *upstream_project_id)),
3660
3661 LspStoreMode::Remote(RemoteLspStore {
3662 upstream_client: None,
3663 ..
3664 }) => None,
3665 LspStoreMode::Local(_) => None,
3666 }
3667 }
3668
3669 pub fn new_local(
3670 buffer_store: Entity<BufferStore>,
3671 worktree_store: Entity<WorktreeStore>,
3672 prettier_store: Entity<PrettierStore>,
3673 toolchain_store: Entity<LocalToolchainStore>,
3674 environment: Entity<ProjectEnvironment>,
3675 manifest_tree: Entity<ManifestTree>,
3676 languages: Arc<LanguageRegistry>,
3677 http_client: Arc<dyn HttpClient>,
3678 fs: Arc<dyn Fs>,
3679 cx: &mut Context<Self>,
3680 ) -> Self {
3681 let yarn = YarnPathStore::new(fs.clone(), cx);
3682 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3683 .detach();
3684 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3685 .detach();
3686 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3687 .detach();
3688 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3689 .detach();
3690 if let Some(extension_events) = extension::ExtensionEvents::try_global(cx).as_ref() {
3691 cx.subscribe(
3692 extension_events,
3693 Self::reload_zed_json_schemas_on_extensions_changed,
3694 )
3695 .detach();
3696 } else {
3697 log::debug!("No extension events global found. Skipping JSON schema auto-reload setup");
3698 }
3699 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3700 .detach();
3701 subscribe_to_binary_statuses(&languages, cx).detach();
3702
3703 let _maintain_workspace_config = {
3704 let (sender, receiver) = watch::channel();
3705 (
3706 Self::maintain_workspace_config(fs.clone(), receiver, cx),
3707 sender,
3708 )
3709 };
3710
3711 Self {
3712 mode: LspStoreMode::Local(LocalLspStore {
3713 weak: cx.weak_entity(),
3714 worktree_store: worktree_store.clone(),
3715
3716 supplementary_language_servers: Default::default(),
3717 languages: languages.clone(),
3718 language_server_ids: Default::default(),
3719 language_servers: Default::default(),
3720 last_workspace_edits_by_language_server: Default::default(),
3721 language_server_watched_paths: Default::default(),
3722 language_server_paths_watched_for_rename: Default::default(),
3723 language_server_watcher_registrations: Default::default(),
3724 buffers_being_formatted: Default::default(),
3725 buffer_snapshots: Default::default(),
3726 prettier_store,
3727 environment,
3728 http_client,
3729 fs,
3730 yarn,
3731 next_diagnostic_group_id: Default::default(),
3732 diagnostics: Default::default(),
3733 _subscription: cx.on_app_quit(|this, cx| {
3734 this.as_local_mut()
3735 .unwrap()
3736 .shutdown_language_servers_on_quit(cx)
3737 }),
3738 lsp_tree: LanguageServerTree::new(
3739 manifest_tree,
3740 languages.clone(),
3741 toolchain_store.clone(),
3742 ),
3743 toolchain_store,
3744 registered_buffers: HashMap::default(),
3745 buffers_opened_in_servers: HashMap::default(),
3746 buffer_pull_diagnostics_result_ids: HashMap::default(),
3747 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3748 .manifest_file_names(),
3749 }),
3750 last_formatting_failure: None,
3751 downstream_client: None,
3752 buffer_store,
3753 worktree_store,
3754 languages: languages.clone(),
3755 language_server_statuses: Default::default(),
3756 nonce: StdRng::from_entropy().r#gen(),
3757 diagnostic_summaries: HashMap::default(),
3758 lsp_server_capabilities: HashMap::default(),
3759 lsp_document_colors: HashMap::default(),
3760 lsp_code_lens: HashMap::default(),
3761 active_entry: None,
3762 _maintain_workspace_config,
3763 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3764 }
3765 }
3766
3767 fn send_lsp_proto_request<R: LspCommand>(
3768 &self,
3769 buffer: Entity<Buffer>,
3770 client: AnyProtoClient,
3771 upstream_project_id: u64,
3772 request: R,
3773 cx: &mut Context<LspStore>,
3774 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3775 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3776 return Task::ready(Ok(R::Response::default()));
3777 }
3778 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3779 cx.spawn(async move |this, cx| {
3780 let response = client.request(message).await?;
3781 let this = this.upgrade().context("project dropped")?;
3782 request
3783 .response_from_proto(response, this, buffer, cx.clone())
3784 .await
3785 })
3786 }
3787
3788 pub(super) fn new_remote(
3789 buffer_store: Entity<BufferStore>,
3790 worktree_store: Entity<WorktreeStore>,
3791 languages: Arc<LanguageRegistry>,
3792 upstream_client: AnyProtoClient,
3793 project_id: u64,
3794 fs: Arc<dyn Fs>,
3795 cx: &mut Context<Self>,
3796 ) -> Self {
3797 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3798 .detach();
3799 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3800 .detach();
3801 subscribe_to_binary_statuses(&languages, cx).detach();
3802 let _maintain_workspace_config = {
3803 let (sender, receiver) = watch::channel();
3804 (Self::maintain_workspace_config(fs, receiver, cx), sender)
3805 };
3806 Self {
3807 mode: LspStoreMode::Remote(RemoteLspStore {
3808 upstream_client: Some(upstream_client),
3809 upstream_project_id: project_id,
3810 }),
3811 downstream_client: None,
3812 last_formatting_failure: None,
3813 buffer_store,
3814 worktree_store,
3815 languages: languages.clone(),
3816 language_server_statuses: Default::default(),
3817 nonce: StdRng::from_entropy().r#gen(),
3818 diagnostic_summaries: HashMap::default(),
3819 lsp_server_capabilities: HashMap::default(),
3820 lsp_document_colors: HashMap::default(),
3821 lsp_code_lens: HashMap::default(),
3822 active_entry: None,
3823
3824 _maintain_workspace_config,
3825 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3826 }
3827 }
3828
3829 fn on_buffer_store_event(
3830 &mut self,
3831 _: Entity<BufferStore>,
3832 event: &BufferStoreEvent,
3833 cx: &mut Context<Self>,
3834 ) {
3835 match event {
3836 BufferStoreEvent::BufferAdded(buffer) => {
3837 self.on_buffer_added(buffer, cx).log_err();
3838 }
3839 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3840 let buffer_id = buffer.read(cx).remote_id();
3841 if let Some(local) = self.as_local_mut()
3842 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3843 {
3844 local.reset_buffer(buffer, old_file, cx);
3845
3846 if local.registered_buffers.contains_key(&buffer_id) {
3847 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3848 }
3849 }
3850
3851 self.detect_language_for_buffer(buffer, cx);
3852 if let Some(local) = self.as_local_mut() {
3853 local.initialize_buffer(buffer, cx);
3854 if local.registered_buffers.contains_key(&buffer_id) {
3855 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3856 }
3857 }
3858 }
3859 _ => {}
3860 }
3861 }
3862
3863 fn on_worktree_store_event(
3864 &mut self,
3865 _: Entity<WorktreeStore>,
3866 event: &WorktreeStoreEvent,
3867 cx: &mut Context<Self>,
3868 ) {
3869 match event {
3870 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3871 if !worktree.read(cx).is_local() {
3872 return;
3873 }
3874 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3875 worktree::Event::UpdatedEntries(changes) => {
3876 this.update_local_worktree_language_servers(&worktree, changes, cx);
3877 }
3878 worktree::Event::UpdatedGitRepositories(_)
3879 | worktree::Event::DeletedEntry(_) => {}
3880 })
3881 .detach()
3882 }
3883 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
3884 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
3885 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
3886 }
3887 WorktreeStoreEvent::WorktreeReleased(..)
3888 | WorktreeStoreEvent::WorktreeOrderChanged
3889 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
3890 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
3891 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
3892 }
3893 }
3894
3895 fn on_prettier_store_event(
3896 &mut self,
3897 _: Entity<PrettierStore>,
3898 event: &PrettierStoreEvent,
3899 cx: &mut Context<Self>,
3900 ) {
3901 match event {
3902 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
3903 self.unregister_supplementary_language_server(*prettier_server_id, cx);
3904 }
3905 PrettierStoreEvent::LanguageServerAdded {
3906 new_server_id,
3907 name,
3908 prettier_server,
3909 } => {
3910 self.register_supplementary_language_server(
3911 *new_server_id,
3912 name.clone(),
3913 prettier_server.clone(),
3914 cx,
3915 );
3916 }
3917 }
3918 }
3919
3920 fn on_toolchain_store_event(
3921 &mut self,
3922 _: Entity<LocalToolchainStore>,
3923 event: &ToolchainStoreEvent,
3924 _: &mut Context<Self>,
3925 ) {
3926 match event {
3927 ToolchainStoreEvent::ToolchainActivated { .. } => {
3928 self.request_workspace_config_refresh()
3929 }
3930 }
3931 }
3932
3933 fn request_workspace_config_refresh(&mut self) {
3934 *self._maintain_workspace_config.1.borrow_mut() = ();
3935 }
3936
3937 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
3938 self.as_local().map(|local| local.prettier_store.clone())
3939 }
3940
3941 fn on_buffer_event(
3942 &mut self,
3943 buffer: Entity<Buffer>,
3944 event: &language::BufferEvent,
3945 cx: &mut Context<Self>,
3946 ) {
3947 match event {
3948 language::BufferEvent::Edited => {
3949 self.on_buffer_edited(buffer, cx);
3950 }
3951
3952 language::BufferEvent::Saved => {
3953 self.on_buffer_saved(buffer, cx);
3954 }
3955
3956 _ => {}
3957 }
3958 }
3959
3960 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
3961 buffer
3962 .read(cx)
3963 .set_language_registry(self.languages.clone());
3964
3965 cx.subscribe(buffer, |this, buffer, event, cx| {
3966 this.on_buffer_event(buffer, event, cx);
3967 })
3968 .detach();
3969
3970 self.detect_language_for_buffer(buffer, cx);
3971 if let Some(local) = self.as_local_mut() {
3972 local.initialize_buffer(buffer, cx);
3973 }
3974
3975 Ok(())
3976 }
3977
3978 pub fn reload_zed_json_schemas_on_extensions_changed(
3979 &mut self,
3980 _: Entity<extension::ExtensionEvents>,
3981 evt: &extension::Event,
3982 cx: &mut Context<Self>,
3983 ) {
3984 match evt {
3985 extension::Event::ExtensionInstalled(_)
3986 | extension::Event::ExtensionUninstalled(_)
3987 | extension::Event::ConfigureExtensionRequested(_) => return,
3988 extension::Event::ExtensionsInstalledChanged => {}
3989 }
3990 if self.as_local().is_none() {
3991 return;
3992 }
3993 cx.spawn(async move |this, cx| {
3994 let weak_ref = this.clone();
3995
3996 let servers = this
3997 .update(cx, |this, cx| {
3998 let local = this.as_local()?;
3999
4000 let mut servers = Vec::new();
4001 for (seed, state) in &local.language_server_ids {
4002
4003 let Some(states) = local.language_servers.get(&state.id) else {
4004 continue;
4005 };
4006 let (json_adapter, json_server) = match states {
4007 LanguageServerState::Running {
4008 adapter, server, ..
4009 } if adapter.adapter.is_primary_zed_json_schema_adapter() => {
4010 (adapter.adapter.clone(), server.clone())
4011 }
4012 _ => continue,
4013 };
4014
4015 let Some(worktree) = this
4016 .worktree_store
4017 .read(cx)
4018 .worktree_for_id(seed.worktree_id, cx)
4019 else {
4020 continue;
4021 };
4022 let json_delegate: Arc<dyn LspAdapterDelegate> =
4023 LocalLspAdapterDelegate::new(
4024 local.languages.clone(),
4025 &local.environment,
4026 weak_ref.clone(),
4027 &worktree,
4028 local.http_client.clone(),
4029 local.fs.clone(),
4030 cx,
4031 );
4032
4033 servers.push((json_adapter, json_server, json_delegate));
4034
4035 }
4036 Some(servers)
4037 })
4038 .ok()
4039 .flatten();
4040
4041 let Some(servers) = servers else {
4042 return;
4043 };
4044
4045 let Ok(Some((fs, _))) = this.read_with(cx, |this, _| {
4046 let local = this.as_local()?;
4047 let toolchain_store = local.toolchain_store().clone();
4048 Some((local.fs.clone(), toolchain_store))
4049 }) else {
4050 return;
4051 };
4052 for (adapter, server, delegate) in servers {
4053 adapter.clear_zed_json_schema_cache().await;
4054
4055 let Some(json_workspace_config) = LocalLspStore::workspace_configuration_for_adapter(
4056 adapter,
4057 fs.as_ref(),
4058 &delegate,
4059 None,
4060 cx,
4061 )
4062 .await
4063 .context("generate new workspace configuration for JSON language server while trying to refresh JSON Schemas")
4064 .ok()
4065 else {
4066 continue;
4067 };
4068 server
4069 .notify::<lsp::notification::DidChangeConfiguration>(
4070 &lsp::DidChangeConfigurationParams {
4071 settings: json_workspace_config,
4072 },
4073 )
4074 .ok();
4075 }
4076 })
4077 .detach();
4078 }
4079
4080 pub(crate) fn register_buffer_with_language_servers(
4081 &mut self,
4082 buffer: &Entity<Buffer>,
4083 only_register_servers: HashSet<LanguageServerSelector>,
4084 ignore_refcounts: bool,
4085 cx: &mut Context<Self>,
4086 ) -> OpenLspBufferHandle {
4087 let buffer_id = buffer.read(cx).remote_id();
4088 let handle = cx.new(|_| buffer.clone());
4089 if let Some(local) = self.as_local_mut() {
4090 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4091 if !ignore_refcounts {
4092 *refcount += 1;
4093 }
4094
4095 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4096 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4097 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4098 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4099 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4100 return handle;
4101 };
4102 if !file.is_local() {
4103 return handle;
4104 }
4105
4106 if ignore_refcounts || *refcount == 1 {
4107 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4108 }
4109 if !ignore_refcounts {
4110 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4111 let refcount = {
4112 let local = lsp_store.as_local_mut().unwrap();
4113 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4114 debug_panic!("bad refcounting");
4115 return;
4116 };
4117
4118 *refcount -= 1;
4119 *refcount
4120 };
4121 if refcount == 0 {
4122 lsp_store.lsp_document_colors.remove(&buffer_id);
4123 lsp_store.lsp_code_lens.remove(&buffer_id);
4124 let local = lsp_store.as_local_mut().unwrap();
4125 local.registered_buffers.remove(&buffer_id);
4126 local.buffers_opened_in_servers.remove(&buffer_id);
4127 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4128 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4129 }
4130 }
4131 })
4132 .detach();
4133 }
4134 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4135 let buffer_id = buffer.read(cx).remote_id().to_proto();
4136 cx.background_spawn(async move {
4137 upstream_client
4138 .request(proto::RegisterBufferWithLanguageServers {
4139 project_id: upstream_project_id,
4140 buffer_id,
4141 only_servers: only_register_servers
4142 .into_iter()
4143 .map(|selector| {
4144 let selector = match selector {
4145 LanguageServerSelector::Id(language_server_id) => {
4146 proto::language_server_selector::Selector::ServerId(
4147 language_server_id.to_proto(),
4148 )
4149 }
4150 LanguageServerSelector::Name(language_server_name) => {
4151 proto::language_server_selector::Selector::Name(
4152 language_server_name.to_string(),
4153 )
4154 }
4155 };
4156 proto::LanguageServerSelector {
4157 selector: Some(selector),
4158 }
4159 })
4160 .collect(),
4161 })
4162 .await
4163 })
4164 .detach();
4165 } else {
4166 panic!("oops!");
4167 }
4168 handle
4169 }
4170
4171 fn maintain_buffer_languages(
4172 languages: Arc<LanguageRegistry>,
4173 cx: &mut Context<Self>,
4174 ) -> Task<()> {
4175 let mut subscription = languages.subscribe();
4176 let mut prev_reload_count = languages.reload_count();
4177 cx.spawn(async move |this, cx| {
4178 while let Some(()) = subscription.next().await {
4179 if let Some(this) = this.upgrade() {
4180 // If the language registry has been reloaded, then remove and
4181 // re-assign the languages on all open buffers.
4182 let reload_count = languages.reload_count();
4183 if reload_count > prev_reload_count {
4184 prev_reload_count = reload_count;
4185 this.update(cx, |this, cx| {
4186 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4187 for buffer in buffer_store.buffers() {
4188 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4189 {
4190 buffer
4191 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4192 if let Some(local) = this.as_local_mut() {
4193 local.reset_buffer(&buffer, &f, cx);
4194
4195 if local
4196 .registered_buffers
4197 .contains_key(&buffer.read(cx).remote_id())
4198 && let Some(file_url) =
4199 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4200 {
4201 local.unregister_buffer_from_language_servers(
4202 &buffer, &file_url, cx,
4203 );
4204 }
4205 }
4206 }
4207 }
4208 });
4209 })
4210 .ok();
4211 }
4212
4213 this.update(cx, |this, cx| {
4214 let mut plain_text_buffers = Vec::new();
4215 let mut buffers_with_unknown_injections = Vec::new();
4216 for handle in this.buffer_store.read(cx).buffers() {
4217 let buffer = handle.read(cx);
4218 if buffer.language().is_none()
4219 || buffer.language() == Some(&*language::PLAIN_TEXT)
4220 {
4221 plain_text_buffers.push(handle);
4222 } else if buffer.contains_unknown_injections() {
4223 buffers_with_unknown_injections.push(handle);
4224 }
4225 }
4226
4227 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4228 // and reused later in the invisible worktrees.
4229 plain_text_buffers.sort_by_key(|buffer| {
4230 Reverse(
4231 File::from_dyn(buffer.read(cx).file())
4232 .map(|file| file.worktree.read(cx).is_visible()),
4233 )
4234 });
4235
4236 for buffer in plain_text_buffers {
4237 this.detect_language_for_buffer(&buffer, cx);
4238 if let Some(local) = this.as_local_mut() {
4239 local.initialize_buffer(&buffer, cx);
4240 if local
4241 .registered_buffers
4242 .contains_key(&buffer.read(cx).remote_id())
4243 {
4244 local.register_buffer_with_language_servers(
4245 &buffer,
4246 HashSet::default(),
4247 cx,
4248 );
4249 }
4250 }
4251 }
4252
4253 for buffer in buffers_with_unknown_injections {
4254 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4255 }
4256 })
4257 .ok();
4258 }
4259 }
4260 })
4261 }
4262
4263 fn detect_language_for_buffer(
4264 &mut self,
4265 buffer_handle: &Entity<Buffer>,
4266 cx: &mut Context<Self>,
4267 ) -> Option<language::AvailableLanguage> {
4268 // If the buffer has a language, set it and start the language server if we haven't already.
4269 let buffer = buffer_handle.read(cx);
4270 let file = buffer.file()?;
4271
4272 let content = buffer.as_rope();
4273 let available_language = self.languages.language_for_file(file, Some(content), cx);
4274 if let Some(available_language) = &available_language {
4275 if let Some(Ok(Ok(new_language))) = self
4276 .languages
4277 .load_language(available_language)
4278 .now_or_never()
4279 {
4280 self.set_language_for_buffer(buffer_handle, new_language, cx);
4281 }
4282 } else {
4283 cx.emit(LspStoreEvent::LanguageDetected {
4284 buffer: buffer_handle.clone(),
4285 new_language: None,
4286 });
4287 }
4288
4289 available_language
4290 }
4291
4292 pub(crate) fn set_language_for_buffer(
4293 &mut self,
4294 buffer_entity: &Entity<Buffer>,
4295 new_language: Arc<Language>,
4296 cx: &mut Context<Self>,
4297 ) {
4298 let buffer = buffer_entity.read(cx);
4299 let buffer_file = buffer.file().cloned();
4300 let buffer_id = buffer.remote_id();
4301 if let Some(local_store) = self.as_local_mut()
4302 && local_store.registered_buffers.contains_key(&buffer_id)
4303 && let Some(abs_path) =
4304 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4305 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4306 {
4307 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4308 }
4309 buffer_entity.update(cx, |buffer, cx| {
4310 if buffer
4311 .language()
4312 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4313 {
4314 buffer.set_language(Some(new_language.clone()), cx);
4315 }
4316 });
4317
4318 let settings =
4319 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4320 let buffer_file = File::from_dyn(buffer_file.as_ref());
4321
4322 let worktree_id = if let Some(file) = buffer_file {
4323 let worktree = file.worktree.clone();
4324
4325 if let Some(local) = self.as_local_mut()
4326 && local.registered_buffers.contains_key(&buffer_id)
4327 {
4328 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4329 }
4330 Some(worktree.read(cx).id())
4331 } else {
4332 None
4333 };
4334
4335 if settings.prettier.allowed
4336 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4337 {
4338 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4339 if let Some(prettier_store) = prettier_store {
4340 prettier_store.update(cx, |prettier_store, cx| {
4341 prettier_store.install_default_prettier(
4342 worktree_id,
4343 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4344 cx,
4345 )
4346 })
4347 }
4348 }
4349
4350 cx.emit(LspStoreEvent::LanguageDetected {
4351 buffer: buffer_entity.clone(),
4352 new_language: Some(new_language),
4353 })
4354 }
4355
4356 pub fn buffer_store(&self) -> Entity<BufferStore> {
4357 self.buffer_store.clone()
4358 }
4359
4360 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4361 self.active_entry = active_entry;
4362 }
4363
4364 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4365 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4366 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4367 {
4368 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4369 summaries
4370 .iter()
4371 .map(|(server_id, summary)| summary.to_proto(*server_id, path))
4372 });
4373 if let Some(summary) = summaries.next() {
4374 client
4375 .send(proto::UpdateDiagnosticSummary {
4376 project_id: downstream_project_id,
4377 worktree_id: worktree.id().to_proto(),
4378 summary: Some(summary),
4379 more_summaries: summaries.collect(),
4380 })
4381 .log_err();
4382 }
4383 }
4384 }
4385
4386 // TODO: remove MultiLspQuery: instead, the proto handler should pick appropriate server(s)
4387 // Then, use `send_lsp_proto_request` or analogue for most of the LSP proto requests and inline this check inside
4388 fn is_capable_for_proto_request<R>(
4389 &self,
4390 buffer: &Entity<Buffer>,
4391 request: &R,
4392 cx: &Context<Self>,
4393 ) -> bool
4394 where
4395 R: LspCommand,
4396 {
4397 self.check_if_capable_for_proto_request(
4398 buffer,
4399 |capabilities| {
4400 request.check_capabilities(AdapterServerCapabilities {
4401 server_capabilities: capabilities.clone(),
4402 code_action_kinds: None,
4403 })
4404 },
4405 cx,
4406 )
4407 }
4408
4409 fn check_if_capable_for_proto_request<F>(
4410 &self,
4411 buffer: &Entity<Buffer>,
4412 check: F,
4413 cx: &Context<Self>,
4414 ) -> bool
4415 where
4416 F: Fn(&lsp::ServerCapabilities) -> bool,
4417 {
4418 let Some(language) = buffer.read(cx).language().cloned() else {
4419 return false;
4420 };
4421 let relevant_language_servers = self
4422 .languages
4423 .lsp_adapters(&language.name())
4424 .into_iter()
4425 .map(|lsp_adapter| lsp_adapter.name())
4426 .collect::<HashSet<_>>();
4427 self.language_server_statuses
4428 .iter()
4429 .filter_map(|(server_id, server_status)| {
4430 relevant_language_servers
4431 .contains(&server_status.name)
4432 .then_some(server_id)
4433 })
4434 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4435 .any(check)
4436 }
4437
4438 pub fn request_lsp<R>(
4439 &mut self,
4440 buffer: Entity<Buffer>,
4441 server: LanguageServerToQuery,
4442 request: R,
4443 cx: &mut Context<Self>,
4444 ) -> Task<Result<R::Response>>
4445 where
4446 R: LspCommand,
4447 <R::LspRequest as lsp::request::Request>::Result: Send,
4448 <R::LspRequest as lsp::request::Request>::Params: Send,
4449 {
4450 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4451 return self.send_lsp_proto_request(
4452 buffer,
4453 upstream_client,
4454 upstream_project_id,
4455 request,
4456 cx,
4457 );
4458 }
4459
4460 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4461 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4462 local
4463 .language_servers_for_buffer(buffer, cx)
4464 .find(|(_, server)| {
4465 request.check_capabilities(server.adapter_server_capabilities())
4466 })
4467 .map(|(_, server)| server.clone())
4468 }),
4469 LanguageServerToQuery::Other(id) => self
4470 .language_server_for_local_buffer(buffer, id, cx)
4471 .and_then(|(_, server)| {
4472 request
4473 .check_capabilities(server.adapter_server_capabilities())
4474 .then(|| Arc::clone(server))
4475 }),
4476 }) else {
4477 return Task::ready(Ok(Default::default()));
4478 };
4479
4480 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4481
4482 let Some(file) = file else {
4483 return Task::ready(Ok(Default::default()));
4484 };
4485
4486 let lsp_params = match request.to_lsp_params_or_response(
4487 &file.abs_path(cx),
4488 buffer.read(cx),
4489 &language_server,
4490 cx,
4491 ) {
4492 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4493 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4494
4495 Err(err) => {
4496 let message = format!(
4497 "{} via {} failed: {}",
4498 request.display_name(),
4499 language_server.name(),
4500 err
4501 );
4502 log::warn!("{message}");
4503 return Task::ready(Err(anyhow!(message)));
4504 }
4505 };
4506
4507 let status = request.status();
4508 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4509 return Task::ready(Ok(Default::default()));
4510 }
4511 cx.spawn(async move |this, cx| {
4512 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4513
4514 let id = lsp_request.id();
4515 let _cleanup = if status.is_some() {
4516 cx.update(|cx| {
4517 this.update(cx, |this, cx| {
4518 this.on_lsp_work_start(
4519 language_server.server_id(),
4520 id.to_string(),
4521 LanguageServerProgress {
4522 is_disk_based_diagnostics_progress: false,
4523 is_cancellable: false,
4524 title: None,
4525 message: status.clone(),
4526 percentage: None,
4527 last_update_at: cx.background_executor().now(),
4528 },
4529 cx,
4530 );
4531 })
4532 })
4533 .log_err();
4534
4535 Some(defer(|| {
4536 cx.update(|cx| {
4537 this.update(cx, |this, cx| {
4538 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4539 })
4540 })
4541 .log_err();
4542 }))
4543 } else {
4544 None
4545 };
4546
4547 let result = lsp_request.await.into_response();
4548
4549 let response = result.map_err(|err| {
4550 let message = format!(
4551 "{} via {} failed: {}",
4552 request.display_name(),
4553 language_server.name(),
4554 err
4555 );
4556 log::warn!("{message}");
4557 anyhow::anyhow!(message)
4558 })?;
4559
4560 request
4561 .response_from_lsp(
4562 response,
4563 this.upgrade().context("no app context")?,
4564 buffer,
4565 language_server.server_id(),
4566 cx.clone(),
4567 )
4568 .await
4569 })
4570 }
4571
4572 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4573 let mut language_formatters_to_check = Vec::new();
4574 for buffer in self.buffer_store.read(cx).buffers() {
4575 let buffer = buffer.read(cx);
4576 let buffer_file = File::from_dyn(buffer.file());
4577 let buffer_language = buffer.language();
4578 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4579 if buffer_language.is_some() {
4580 language_formatters_to_check.push((
4581 buffer_file.map(|f| f.worktree_id(cx)),
4582 settings.into_owned(),
4583 ));
4584 }
4585 }
4586
4587 self.request_workspace_config_refresh();
4588
4589 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4590 prettier_store.update(cx, |prettier_store, cx| {
4591 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4592 })
4593 }
4594
4595 cx.notify();
4596 }
4597
4598 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4599 let buffer_store = self.buffer_store.clone();
4600 let Some(local) = self.as_local_mut() else {
4601 return;
4602 };
4603 let mut adapters = BTreeMap::default();
4604 let get_adapter = {
4605 let languages = local.languages.clone();
4606 let environment = local.environment.clone();
4607 let weak = local.weak.clone();
4608 let worktree_store = local.worktree_store.clone();
4609 let http_client = local.http_client.clone();
4610 let fs = local.fs.clone();
4611 move |worktree_id, cx: &mut App| {
4612 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4613 Some(LocalLspAdapterDelegate::new(
4614 languages.clone(),
4615 &environment,
4616 weak.clone(),
4617 &worktree,
4618 http_client.clone(),
4619 fs.clone(),
4620 cx,
4621 ))
4622 }
4623 };
4624
4625 let mut messages_to_report = Vec::new();
4626 let (new_tree, to_stop) = {
4627 let mut rebase = local.lsp_tree.rebase();
4628 let buffers = buffer_store
4629 .read(cx)
4630 .buffers()
4631 .filter_map(|buffer| {
4632 let raw_buffer = buffer.read(cx);
4633 if !local
4634 .registered_buffers
4635 .contains_key(&raw_buffer.remote_id())
4636 {
4637 return None;
4638 }
4639 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4640 let language = raw_buffer.language().cloned()?;
4641 Some((file, language, raw_buffer.remote_id()))
4642 })
4643 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4644
4645 for (file, language, buffer_id) in buffers {
4646 let worktree_id = file.worktree_id(cx);
4647 let Some(worktree) = local
4648 .worktree_store
4649 .read(cx)
4650 .worktree_for_id(worktree_id, cx)
4651 else {
4652 continue;
4653 };
4654
4655 if let Some((_, apply)) = local.reuse_existing_language_server(
4656 rebase.server_tree(),
4657 &worktree,
4658 &language.name(),
4659 cx,
4660 ) {
4661 (apply)(rebase.server_tree());
4662 } else if let Some(lsp_delegate) = adapters
4663 .entry(worktree_id)
4664 .or_insert_with(|| get_adapter(worktree_id, cx))
4665 .clone()
4666 {
4667 let delegate =
4668 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4669 let path = file
4670 .path()
4671 .parent()
4672 .map(Arc::from)
4673 .unwrap_or_else(|| file.path().clone());
4674 let worktree_path = ProjectPath { worktree_id, path };
4675 let abs_path = file.abs_path(cx);
4676 let worktree_root = worktree.read(cx).abs_path();
4677 let nodes = rebase
4678 .walk(
4679 worktree_path,
4680 language.name(),
4681 language.manifest(),
4682 delegate.clone(),
4683 cx,
4684 )
4685 .collect::<Vec<_>>();
4686
4687 for node in nodes {
4688 let server_id = node.server_id_or_init(|disposition| {
4689 let path = &disposition.path;
4690 let uri = Url::from_file_path(worktree_root.join(&path.path));
4691 let key = LanguageServerSeed {
4692 worktree_id,
4693 name: disposition.server_name.clone(),
4694 settings: disposition.settings.clone(),
4695 toolchain: local.toolchain_store.read(cx).active_toolchain(
4696 path.worktree_id,
4697 &path.path,
4698 language.name(),
4699 ),
4700 };
4701 local.language_server_ids.remove(&key);
4702
4703 let server_id = local.get_or_insert_language_server(
4704 &worktree,
4705 lsp_delegate.clone(),
4706 disposition,
4707 &language.name(),
4708 cx,
4709 );
4710 if let Some(state) = local.language_servers.get(&server_id)
4711 && let Ok(uri) = uri
4712 {
4713 state.add_workspace_folder(uri);
4714 };
4715 server_id
4716 });
4717
4718 if let Some(language_server_id) = server_id {
4719 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4720 language_server_id,
4721 name: node.name(),
4722 message:
4723 proto::update_language_server::Variant::RegisteredForBuffer(
4724 proto::RegisteredForBuffer {
4725 buffer_abs_path: abs_path.to_string_lossy().to_string(),
4726 buffer_id: buffer_id.to_proto(),
4727 },
4728 ),
4729 });
4730 }
4731 }
4732 } else {
4733 continue;
4734 }
4735 }
4736 rebase.finish()
4737 };
4738 for message in messages_to_report {
4739 cx.emit(message);
4740 }
4741 local.lsp_tree = new_tree;
4742 for (id, _) in to_stop {
4743 self.stop_local_language_server(id, cx).detach();
4744 }
4745 }
4746
4747 pub fn apply_code_action(
4748 &self,
4749 buffer_handle: Entity<Buffer>,
4750 mut action: CodeAction,
4751 push_to_history: bool,
4752 cx: &mut Context<Self>,
4753 ) -> Task<Result<ProjectTransaction>> {
4754 if let Some((upstream_client, project_id)) = self.upstream_client() {
4755 let request = proto::ApplyCodeAction {
4756 project_id,
4757 buffer_id: buffer_handle.read(cx).remote_id().into(),
4758 action: Some(Self::serialize_code_action(&action)),
4759 };
4760 let buffer_store = self.buffer_store();
4761 cx.spawn(async move |_, cx| {
4762 let response = upstream_client
4763 .request(request)
4764 .await?
4765 .transaction
4766 .context("missing transaction")?;
4767
4768 buffer_store
4769 .update(cx, |buffer_store, cx| {
4770 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4771 })?
4772 .await
4773 })
4774 } else if self.mode.is_local() {
4775 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4776 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4777 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4778 }) else {
4779 return Task::ready(Ok(ProjectTransaction::default()));
4780 };
4781 cx.spawn(async move |this, cx| {
4782 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4783 .await
4784 .context("resolving a code action")?;
4785 if let Some(edit) = action.lsp_action.edit()
4786 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4787 return LocalLspStore::deserialize_workspace_edit(
4788 this.upgrade().context("no app present")?,
4789 edit.clone(),
4790 push_to_history,
4791
4792 lang_server.clone(),
4793 cx,
4794 )
4795 .await;
4796 }
4797
4798 if let Some(command) = action.lsp_action.command() {
4799 let server_capabilities = lang_server.capabilities();
4800 let available_commands = server_capabilities
4801 .execute_command_provider
4802 .as_ref()
4803 .map(|options| options.commands.as_slice())
4804 .unwrap_or_default();
4805 if available_commands.contains(&command.command) {
4806 this.update(cx, |this, _| {
4807 this.as_local_mut()
4808 .unwrap()
4809 .last_workspace_edits_by_language_server
4810 .remove(&lang_server.server_id());
4811 })?;
4812
4813 let _result = lang_server
4814 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4815 command: command.command.clone(),
4816 arguments: command.arguments.clone().unwrap_or_default(),
4817 ..lsp::ExecuteCommandParams::default()
4818 })
4819 .await.into_response()
4820 .context("execute command")?;
4821
4822 return this.update(cx, |this, _| {
4823 this.as_local_mut()
4824 .unwrap()
4825 .last_workspace_edits_by_language_server
4826 .remove(&lang_server.server_id())
4827 .unwrap_or_default()
4828 });
4829 } else {
4830 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4831 }
4832 }
4833
4834 Ok(ProjectTransaction::default())
4835 })
4836 } else {
4837 Task::ready(Err(anyhow!("no upstream client and not local")))
4838 }
4839 }
4840
4841 pub fn apply_code_action_kind(
4842 &mut self,
4843 buffers: HashSet<Entity<Buffer>>,
4844 kind: CodeActionKind,
4845 push_to_history: bool,
4846 cx: &mut Context<Self>,
4847 ) -> Task<anyhow::Result<ProjectTransaction>> {
4848 if self.as_local().is_some() {
4849 cx.spawn(async move |lsp_store, cx| {
4850 let buffers = buffers.into_iter().collect::<Vec<_>>();
4851 let result = LocalLspStore::execute_code_action_kind_locally(
4852 lsp_store.clone(),
4853 buffers,
4854 kind,
4855 push_to_history,
4856 cx,
4857 )
4858 .await;
4859 lsp_store.update(cx, |lsp_store, _| {
4860 lsp_store.update_last_formatting_failure(&result);
4861 })?;
4862 result
4863 })
4864 } else if let Some((client, project_id)) = self.upstream_client() {
4865 let buffer_store = self.buffer_store();
4866 cx.spawn(async move |lsp_store, cx| {
4867 let result = client
4868 .request(proto::ApplyCodeActionKind {
4869 project_id,
4870 kind: kind.as_str().to_owned(),
4871 buffer_ids: buffers
4872 .iter()
4873 .map(|buffer| {
4874 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4875 })
4876 .collect::<Result<_>>()?,
4877 })
4878 .await
4879 .and_then(|result| result.transaction.context("missing transaction"));
4880 lsp_store.update(cx, |lsp_store, _| {
4881 lsp_store.update_last_formatting_failure(&result);
4882 })?;
4883
4884 let transaction_response = result?;
4885 buffer_store
4886 .update(cx, |buffer_store, cx| {
4887 buffer_store.deserialize_project_transaction(
4888 transaction_response,
4889 push_to_history,
4890 cx,
4891 )
4892 })?
4893 .await
4894 })
4895 } else {
4896 Task::ready(Ok(ProjectTransaction::default()))
4897 }
4898 }
4899
4900 pub fn resolve_inlay_hint(
4901 &self,
4902 mut hint: InlayHint,
4903 buffer: Entity<Buffer>,
4904 server_id: LanguageServerId,
4905 cx: &mut Context<Self>,
4906 ) -> Task<anyhow::Result<InlayHint>> {
4907 if let Some((upstream_client, project_id)) = self.upstream_client() {
4908 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4909 {
4910 hint.resolve_state = ResolveState::Resolved;
4911 return Task::ready(Ok(hint));
4912 }
4913 let request = proto::ResolveInlayHint {
4914 project_id,
4915 buffer_id: buffer.read(cx).remote_id().into(),
4916 language_server_id: server_id.0 as u64,
4917 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4918 };
4919 cx.background_spawn(async move {
4920 let response = upstream_client
4921 .request(request)
4922 .await
4923 .context("inlay hints proto request")?;
4924 match response.hint {
4925 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4926 .context("inlay hints proto resolve response conversion"),
4927 None => Ok(hint),
4928 }
4929 })
4930 } else {
4931 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4932 self.language_server_for_local_buffer(buffer, server_id, cx)
4933 .map(|(_, server)| server.clone())
4934 }) else {
4935 return Task::ready(Ok(hint));
4936 };
4937 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4938 return Task::ready(Ok(hint));
4939 }
4940 let buffer_snapshot = buffer.read(cx).snapshot();
4941 cx.spawn(async move |_, cx| {
4942 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4943 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4944 );
4945 let resolved_hint = resolve_task
4946 .await
4947 .into_response()
4948 .context("inlay hint resolve LSP request")?;
4949 let resolved_hint = InlayHints::lsp_to_project_hint(
4950 resolved_hint,
4951 &buffer,
4952 server_id,
4953 ResolveState::Resolved,
4954 false,
4955 cx,
4956 )
4957 .await?;
4958 Ok(resolved_hint)
4959 })
4960 }
4961 }
4962
4963 pub fn resolve_color_presentation(
4964 &mut self,
4965 mut color: DocumentColor,
4966 buffer: Entity<Buffer>,
4967 server_id: LanguageServerId,
4968 cx: &mut Context<Self>,
4969 ) -> Task<Result<DocumentColor>> {
4970 if color.resolved {
4971 return Task::ready(Ok(color));
4972 }
4973
4974 if let Some((upstream_client, project_id)) = self.upstream_client() {
4975 let start = color.lsp_range.start;
4976 let end = color.lsp_range.end;
4977 let request = proto::GetColorPresentation {
4978 project_id,
4979 server_id: server_id.to_proto(),
4980 buffer_id: buffer.read(cx).remote_id().into(),
4981 color: Some(proto::ColorInformation {
4982 red: color.color.red,
4983 green: color.color.green,
4984 blue: color.color.blue,
4985 alpha: color.color.alpha,
4986 lsp_range_start: Some(proto::PointUtf16 {
4987 row: start.line,
4988 column: start.character,
4989 }),
4990 lsp_range_end: Some(proto::PointUtf16 {
4991 row: end.line,
4992 column: end.character,
4993 }),
4994 }),
4995 };
4996 cx.background_spawn(async move {
4997 let response = upstream_client
4998 .request(request)
4999 .await
5000 .context("color presentation proto request")?;
5001 color.resolved = true;
5002 color.color_presentations = response
5003 .presentations
5004 .into_iter()
5005 .map(|presentation| ColorPresentation {
5006 label: SharedString::from(presentation.label),
5007 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5008 additional_text_edits: presentation
5009 .additional_text_edits
5010 .into_iter()
5011 .filter_map(deserialize_lsp_edit)
5012 .collect(),
5013 })
5014 .collect();
5015 Ok(color)
5016 })
5017 } else {
5018 let path = match buffer
5019 .update(cx, |buffer, cx| {
5020 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5021 })
5022 .context("buffer with the missing path")
5023 {
5024 Ok(path) => path,
5025 Err(e) => return Task::ready(Err(e)),
5026 };
5027 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5028 self.language_server_for_local_buffer(buffer, server_id, cx)
5029 .map(|(_, server)| server.clone())
5030 }) else {
5031 return Task::ready(Ok(color));
5032 };
5033 cx.background_spawn(async move {
5034 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5035 lsp::ColorPresentationParams {
5036 text_document: make_text_document_identifier(&path)?,
5037 color: color.color,
5038 range: color.lsp_range,
5039 work_done_progress_params: Default::default(),
5040 partial_result_params: Default::default(),
5041 },
5042 );
5043 color.color_presentations = resolve_task
5044 .await
5045 .into_response()
5046 .context("color presentation resolve LSP request")?
5047 .into_iter()
5048 .map(|presentation| ColorPresentation {
5049 label: SharedString::from(presentation.label),
5050 text_edit: presentation.text_edit,
5051 additional_text_edits: presentation
5052 .additional_text_edits
5053 .unwrap_or_default(),
5054 })
5055 .collect();
5056 color.resolved = true;
5057 Ok(color)
5058 })
5059 }
5060 }
5061
5062 pub(crate) fn linked_edits(
5063 &mut self,
5064 buffer: &Entity<Buffer>,
5065 position: Anchor,
5066 cx: &mut Context<Self>,
5067 ) -> Task<Result<Vec<Range<Anchor>>>> {
5068 let snapshot = buffer.read(cx).snapshot();
5069 let scope = snapshot.language_scope_at(position);
5070 let Some(server_id) = self
5071 .as_local()
5072 .and_then(|local| {
5073 buffer.update(cx, |buffer, cx| {
5074 local
5075 .language_servers_for_buffer(buffer, cx)
5076 .filter(|(_, server)| {
5077 LinkedEditingRange::check_server_capabilities(server.capabilities())
5078 })
5079 .filter(|(adapter, _)| {
5080 scope
5081 .as_ref()
5082 .map(|scope| scope.language_allowed(&adapter.name))
5083 .unwrap_or(true)
5084 })
5085 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5086 .next()
5087 })
5088 })
5089 .or_else(|| {
5090 self.upstream_client()
5091 .is_some()
5092 .then_some(LanguageServerToQuery::FirstCapable)
5093 })
5094 .filter(|_| {
5095 maybe!({
5096 let language = buffer.read(cx).language_at(position)?;
5097 Some(
5098 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5099 .linked_edits,
5100 )
5101 }) == Some(true)
5102 })
5103 else {
5104 return Task::ready(Ok(Vec::new()));
5105 };
5106
5107 self.request_lsp(
5108 buffer.clone(),
5109 server_id,
5110 LinkedEditingRange { position },
5111 cx,
5112 )
5113 }
5114
5115 fn apply_on_type_formatting(
5116 &mut self,
5117 buffer: Entity<Buffer>,
5118 position: Anchor,
5119 trigger: String,
5120 cx: &mut Context<Self>,
5121 ) -> Task<Result<Option<Transaction>>> {
5122 if let Some((client, project_id)) = self.upstream_client() {
5123 if !self.check_if_capable_for_proto_request(
5124 &buffer,
5125 |capabilities| {
5126 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5127 },
5128 cx,
5129 ) {
5130 return Task::ready(Ok(None));
5131 }
5132 let request = proto::OnTypeFormatting {
5133 project_id,
5134 buffer_id: buffer.read(cx).remote_id().into(),
5135 position: Some(serialize_anchor(&position)),
5136 trigger,
5137 version: serialize_version(&buffer.read(cx).version()),
5138 };
5139 cx.background_spawn(async move {
5140 client
5141 .request(request)
5142 .await?
5143 .transaction
5144 .map(language::proto::deserialize_transaction)
5145 .transpose()
5146 })
5147 } else if let Some(local) = self.as_local_mut() {
5148 let buffer_id = buffer.read(cx).remote_id();
5149 local.buffers_being_formatted.insert(buffer_id);
5150 cx.spawn(async move |this, cx| {
5151 let _cleanup = defer({
5152 let this = this.clone();
5153 let mut cx = cx.clone();
5154 move || {
5155 this.update(&mut cx, |this, _| {
5156 if let Some(local) = this.as_local_mut() {
5157 local.buffers_being_formatted.remove(&buffer_id);
5158 }
5159 })
5160 .ok();
5161 }
5162 });
5163
5164 buffer
5165 .update(cx, |buffer, _| {
5166 buffer.wait_for_edits(Some(position.timestamp))
5167 })?
5168 .await?;
5169 this.update(cx, |this, cx| {
5170 let position = position.to_point_utf16(buffer.read(cx));
5171 this.on_type_format(buffer, position, trigger, false, cx)
5172 })?
5173 .await
5174 })
5175 } else {
5176 Task::ready(Err(anyhow!("No upstream client or local language server")))
5177 }
5178 }
5179
5180 pub fn on_type_format<T: ToPointUtf16>(
5181 &mut self,
5182 buffer: Entity<Buffer>,
5183 position: T,
5184 trigger: String,
5185 push_to_history: bool,
5186 cx: &mut Context<Self>,
5187 ) -> Task<Result<Option<Transaction>>> {
5188 let position = position.to_point_utf16(buffer.read(cx));
5189 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5190 }
5191
5192 fn on_type_format_impl(
5193 &mut self,
5194 buffer: Entity<Buffer>,
5195 position: PointUtf16,
5196 trigger: String,
5197 push_to_history: bool,
5198 cx: &mut Context<Self>,
5199 ) -> Task<Result<Option<Transaction>>> {
5200 let options = buffer.update(cx, |buffer, cx| {
5201 lsp_command::lsp_formatting_options(
5202 language_settings(
5203 buffer.language_at(position).map(|l| l.name()),
5204 buffer.file(),
5205 cx,
5206 )
5207 .as_ref(),
5208 )
5209 });
5210
5211 cx.spawn(async move |this, cx| {
5212 if let Some(waiter) =
5213 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5214 {
5215 waiter.await?;
5216 }
5217 cx.update(|cx| {
5218 this.update(cx, |this, cx| {
5219 this.request_lsp(
5220 buffer.clone(),
5221 LanguageServerToQuery::FirstCapable,
5222 OnTypeFormatting {
5223 position,
5224 trigger,
5225 options,
5226 push_to_history,
5227 },
5228 cx,
5229 )
5230 })
5231 })??
5232 .await
5233 })
5234 }
5235
5236 pub fn definitions(
5237 &mut self,
5238 buffer_handle: &Entity<Buffer>,
5239 position: PointUtf16,
5240 cx: &mut Context<Self>,
5241 ) -> Task<Result<Vec<LocationLink>>> {
5242 if let Some((upstream_client, project_id)) = self.upstream_client() {
5243 let request = GetDefinitions { position };
5244 if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
5245 return Task::ready(Ok(Vec::new()));
5246 }
5247 let request_task = upstream_client.request(proto::MultiLspQuery {
5248 buffer_id: buffer_handle.read(cx).remote_id().into(),
5249 version: serialize_version(&buffer_handle.read(cx).version()),
5250 project_id,
5251 strategy: Some(proto::multi_lsp_query::Strategy::All(
5252 proto::AllLanguageServers {},
5253 )),
5254 request: Some(proto::multi_lsp_query::Request::GetDefinition(
5255 request.to_proto(project_id, buffer_handle.read(cx)),
5256 )),
5257 });
5258 let buffer = buffer_handle.clone();
5259 cx.spawn(async move |weak_project, cx| {
5260 let Some(project) = weak_project.upgrade() else {
5261 return Ok(Vec::new());
5262 };
5263 let responses = request_task.await?.responses;
5264 let actions = join_all(
5265 responses
5266 .into_iter()
5267 .filter_map(|lsp_response| match lsp_response.response? {
5268 proto::lsp_response::Response::GetDefinitionResponse(response) => {
5269 Some(response)
5270 }
5271 unexpected => {
5272 debug_panic!("Unexpected response: {unexpected:?}");
5273 None
5274 }
5275 })
5276 .map(|definitions_response| {
5277 GetDefinitions { position }.response_from_proto(
5278 definitions_response,
5279 project.clone(),
5280 buffer.clone(),
5281 cx.clone(),
5282 )
5283 }),
5284 )
5285 .await;
5286
5287 Ok(actions
5288 .into_iter()
5289 .collect::<Result<Vec<Vec<_>>>>()?
5290 .into_iter()
5291 .flatten()
5292 .dedup()
5293 .collect())
5294 })
5295 } else {
5296 let definitions_task = self.request_multiple_lsp_locally(
5297 buffer_handle,
5298 Some(position),
5299 GetDefinitions { position },
5300 cx,
5301 );
5302 cx.background_spawn(async move {
5303 Ok(definitions_task
5304 .await
5305 .into_iter()
5306 .flat_map(|(_, definitions)| definitions)
5307 .dedup()
5308 .collect())
5309 })
5310 }
5311 }
5312
5313 pub fn declarations(
5314 &mut self,
5315 buffer_handle: &Entity<Buffer>,
5316 position: PointUtf16,
5317 cx: &mut Context<Self>,
5318 ) -> Task<Result<Vec<LocationLink>>> {
5319 if let Some((upstream_client, project_id)) = self.upstream_client() {
5320 let request = GetDeclarations { position };
5321 if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
5322 return Task::ready(Ok(Vec::new()));
5323 }
5324 let request_task = upstream_client.request(proto::MultiLspQuery {
5325 buffer_id: buffer_handle.read(cx).remote_id().into(),
5326 version: serialize_version(&buffer_handle.read(cx).version()),
5327 project_id,
5328 strategy: Some(proto::multi_lsp_query::Strategy::All(
5329 proto::AllLanguageServers {},
5330 )),
5331 request: Some(proto::multi_lsp_query::Request::GetDeclaration(
5332 request.to_proto(project_id, buffer_handle.read(cx)),
5333 )),
5334 });
5335 let buffer = buffer_handle.clone();
5336 cx.spawn(async move |weak_project, cx| {
5337 let Some(project) = weak_project.upgrade() else {
5338 return Ok(Vec::new());
5339 };
5340 let responses = request_task.await?.responses;
5341 let actions = join_all(
5342 responses
5343 .into_iter()
5344 .filter_map(|lsp_response| match lsp_response.response? {
5345 proto::lsp_response::Response::GetDeclarationResponse(response) => {
5346 Some(response)
5347 }
5348 unexpected => {
5349 debug_panic!("Unexpected response: {unexpected:?}");
5350 None
5351 }
5352 })
5353 .map(|declarations_response| {
5354 GetDeclarations { position }.response_from_proto(
5355 declarations_response,
5356 project.clone(),
5357 buffer.clone(),
5358 cx.clone(),
5359 )
5360 }),
5361 )
5362 .await;
5363
5364 Ok(actions
5365 .into_iter()
5366 .collect::<Result<Vec<Vec<_>>>>()?
5367 .into_iter()
5368 .flatten()
5369 .dedup()
5370 .collect())
5371 })
5372 } else {
5373 let declarations_task = self.request_multiple_lsp_locally(
5374 buffer_handle,
5375 Some(position),
5376 GetDeclarations { position },
5377 cx,
5378 );
5379 cx.background_spawn(async move {
5380 Ok(declarations_task
5381 .await
5382 .into_iter()
5383 .flat_map(|(_, declarations)| declarations)
5384 .dedup()
5385 .collect())
5386 })
5387 }
5388 }
5389
5390 pub fn type_definitions(
5391 &mut self,
5392 buffer: &Entity<Buffer>,
5393 position: PointUtf16,
5394 cx: &mut Context<Self>,
5395 ) -> Task<Result<Vec<LocationLink>>> {
5396 if let Some((upstream_client, project_id)) = self.upstream_client() {
5397 let request = GetTypeDefinitions { position };
5398 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5399 return Task::ready(Ok(Vec::new()));
5400 }
5401 let request_task = upstream_client.request(proto::MultiLspQuery {
5402 buffer_id: buffer.read(cx).remote_id().into(),
5403 version: serialize_version(&buffer.read(cx).version()),
5404 project_id,
5405 strategy: Some(proto::multi_lsp_query::Strategy::All(
5406 proto::AllLanguageServers {},
5407 )),
5408 request: Some(proto::multi_lsp_query::Request::GetTypeDefinition(
5409 request.to_proto(project_id, buffer.read(cx)),
5410 )),
5411 });
5412 let buffer = buffer.clone();
5413 cx.spawn(async move |weak_project, cx| {
5414 let Some(project) = weak_project.upgrade() else {
5415 return Ok(Vec::new());
5416 };
5417 let responses = request_task.await?.responses;
5418 let actions = join_all(
5419 responses
5420 .into_iter()
5421 .filter_map(|lsp_response| match lsp_response.response? {
5422 proto::lsp_response::Response::GetTypeDefinitionResponse(response) => {
5423 Some(response)
5424 }
5425 unexpected => {
5426 debug_panic!("Unexpected response: {unexpected:?}");
5427 None
5428 }
5429 })
5430 .map(|type_definitions_response| {
5431 GetTypeDefinitions { position }.response_from_proto(
5432 type_definitions_response,
5433 project.clone(),
5434 buffer.clone(),
5435 cx.clone(),
5436 )
5437 }),
5438 )
5439 .await;
5440
5441 Ok(actions
5442 .into_iter()
5443 .collect::<Result<Vec<Vec<_>>>>()?
5444 .into_iter()
5445 .flatten()
5446 .dedup()
5447 .collect())
5448 })
5449 } else {
5450 let type_definitions_task = self.request_multiple_lsp_locally(
5451 buffer,
5452 Some(position),
5453 GetTypeDefinitions { position },
5454 cx,
5455 );
5456 cx.background_spawn(async move {
5457 Ok(type_definitions_task
5458 .await
5459 .into_iter()
5460 .flat_map(|(_, type_definitions)| type_definitions)
5461 .dedup()
5462 .collect())
5463 })
5464 }
5465 }
5466
5467 pub fn implementations(
5468 &mut self,
5469 buffer: &Entity<Buffer>,
5470 position: PointUtf16,
5471 cx: &mut Context<Self>,
5472 ) -> Task<Result<Vec<LocationLink>>> {
5473 if let Some((upstream_client, project_id)) = self.upstream_client() {
5474 let request = GetImplementations { position };
5475 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5476 return Task::ready(Ok(Vec::new()));
5477 }
5478 let request_task = upstream_client.request(proto::MultiLspQuery {
5479 buffer_id: buffer.read(cx).remote_id().into(),
5480 version: serialize_version(&buffer.read(cx).version()),
5481 project_id,
5482 strategy: Some(proto::multi_lsp_query::Strategy::All(
5483 proto::AllLanguageServers {},
5484 )),
5485 request: Some(proto::multi_lsp_query::Request::GetImplementation(
5486 request.to_proto(project_id, buffer.read(cx)),
5487 )),
5488 });
5489 let buffer = buffer.clone();
5490 cx.spawn(async move |weak_project, cx| {
5491 let Some(project) = weak_project.upgrade() else {
5492 return Ok(Vec::new());
5493 };
5494 let responses = request_task.await?.responses;
5495 let actions = join_all(
5496 responses
5497 .into_iter()
5498 .filter_map(|lsp_response| match lsp_response.response? {
5499 proto::lsp_response::Response::GetImplementationResponse(response) => {
5500 Some(response)
5501 }
5502 unexpected => {
5503 debug_panic!("Unexpected response: {unexpected:?}");
5504 None
5505 }
5506 })
5507 .map(|implementations_response| {
5508 GetImplementations { position }.response_from_proto(
5509 implementations_response,
5510 project.clone(),
5511 buffer.clone(),
5512 cx.clone(),
5513 )
5514 }),
5515 )
5516 .await;
5517
5518 Ok(actions
5519 .into_iter()
5520 .collect::<Result<Vec<Vec<_>>>>()?
5521 .into_iter()
5522 .flatten()
5523 .dedup()
5524 .collect())
5525 })
5526 } else {
5527 let implementations_task = self.request_multiple_lsp_locally(
5528 buffer,
5529 Some(position),
5530 GetImplementations { position },
5531 cx,
5532 );
5533 cx.background_spawn(async move {
5534 Ok(implementations_task
5535 .await
5536 .into_iter()
5537 .flat_map(|(_, implementations)| implementations)
5538 .dedup()
5539 .collect())
5540 })
5541 }
5542 }
5543
5544 pub fn references(
5545 &mut self,
5546 buffer: &Entity<Buffer>,
5547 position: PointUtf16,
5548 cx: &mut Context<Self>,
5549 ) -> Task<Result<Vec<Location>>> {
5550 if let Some((upstream_client, project_id)) = self.upstream_client() {
5551 let request = GetReferences { position };
5552 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5553 return Task::ready(Ok(Vec::new()));
5554 }
5555 let request_task = upstream_client.request(proto::MultiLspQuery {
5556 buffer_id: buffer.read(cx).remote_id().into(),
5557 version: serialize_version(&buffer.read(cx).version()),
5558 project_id,
5559 strategy: Some(proto::multi_lsp_query::Strategy::All(
5560 proto::AllLanguageServers {},
5561 )),
5562 request: Some(proto::multi_lsp_query::Request::GetReferences(
5563 request.to_proto(project_id, buffer.read(cx)),
5564 )),
5565 });
5566 let buffer = buffer.clone();
5567 cx.spawn(async move |weak_project, cx| {
5568 let Some(project) = weak_project.upgrade() else {
5569 return Ok(Vec::new());
5570 };
5571 let responses = request_task.await?.responses;
5572 let actions = join_all(
5573 responses
5574 .into_iter()
5575 .filter_map(|lsp_response| match lsp_response.response? {
5576 proto::lsp_response::Response::GetReferencesResponse(response) => {
5577 Some(response)
5578 }
5579 unexpected => {
5580 debug_panic!("Unexpected response: {unexpected:?}");
5581 None
5582 }
5583 })
5584 .map(|references_response| {
5585 GetReferences { position }.response_from_proto(
5586 references_response,
5587 project.clone(),
5588 buffer.clone(),
5589 cx.clone(),
5590 )
5591 }),
5592 )
5593 .await;
5594
5595 Ok(actions
5596 .into_iter()
5597 .collect::<Result<Vec<Vec<_>>>>()?
5598 .into_iter()
5599 .flatten()
5600 .dedup()
5601 .collect())
5602 })
5603 } else {
5604 let references_task = self.request_multiple_lsp_locally(
5605 buffer,
5606 Some(position),
5607 GetReferences { position },
5608 cx,
5609 );
5610 cx.background_spawn(async move {
5611 Ok(references_task
5612 .await
5613 .into_iter()
5614 .flat_map(|(_, references)| references)
5615 .dedup()
5616 .collect())
5617 })
5618 }
5619 }
5620
5621 pub fn code_actions(
5622 &mut self,
5623 buffer: &Entity<Buffer>,
5624 range: Range<Anchor>,
5625 kinds: Option<Vec<CodeActionKind>>,
5626 cx: &mut Context<Self>,
5627 ) -> Task<Result<Vec<CodeAction>>> {
5628 if let Some((upstream_client, project_id)) = self.upstream_client() {
5629 let request = GetCodeActions {
5630 range: range.clone(),
5631 kinds: kinds.clone(),
5632 };
5633 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5634 return Task::ready(Ok(Vec::new()));
5635 }
5636 let request_task = upstream_client.request(proto::MultiLspQuery {
5637 buffer_id: buffer.read(cx).remote_id().into(),
5638 version: serialize_version(&buffer.read(cx).version()),
5639 project_id,
5640 strategy: Some(proto::multi_lsp_query::Strategy::All(
5641 proto::AllLanguageServers {},
5642 )),
5643 request: Some(proto::multi_lsp_query::Request::GetCodeActions(
5644 request.to_proto(project_id, buffer.read(cx)),
5645 )),
5646 });
5647 let buffer = buffer.clone();
5648 cx.spawn(async move |weak_project, cx| {
5649 let Some(project) = weak_project.upgrade() else {
5650 return Ok(Vec::new());
5651 };
5652 let responses = request_task.await?.responses;
5653 let actions = join_all(
5654 responses
5655 .into_iter()
5656 .filter_map(|lsp_response| match lsp_response.response? {
5657 proto::lsp_response::Response::GetCodeActionsResponse(response) => {
5658 Some(response)
5659 }
5660 unexpected => {
5661 debug_panic!("Unexpected response: {unexpected:?}");
5662 None
5663 }
5664 })
5665 .map(|code_actions_response| {
5666 GetCodeActions {
5667 range: range.clone(),
5668 kinds: kinds.clone(),
5669 }
5670 .response_from_proto(
5671 code_actions_response,
5672 project.clone(),
5673 buffer.clone(),
5674 cx.clone(),
5675 )
5676 }),
5677 )
5678 .await;
5679
5680 Ok(actions
5681 .into_iter()
5682 .collect::<Result<Vec<Vec<_>>>>()?
5683 .into_iter()
5684 .flatten()
5685 .collect())
5686 })
5687 } else {
5688 let all_actions_task = self.request_multiple_lsp_locally(
5689 buffer,
5690 Some(range.start),
5691 GetCodeActions { range, kinds },
5692 cx,
5693 );
5694 cx.background_spawn(async move {
5695 Ok(all_actions_task
5696 .await
5697 .into_iter()
5698 .flat_map(|(_, actions)| actions)
5699 .collect())
5700 })
5701 }
5702 }
5703
5704 pub fn code_lens_actions(
5705 &mut self,
5706 buffer: &Entity<Buffer>,
5707 cx: &mut Context<Self>,
5708 ) -> CodeLensTask {
5709 let version_queried_for = buffer.read(cx).version();
5710 let buffer_id = buffer.read(cx).remote_id();
5711
5712 if let Some(cached_data) = self.lsp_code_lens.get(&buffer_id)
5713 && !version_queried_for.changed_since(&cached_data.lens_for_version)
5714 {
5715 let has_different_servers = self.as_local().is_some_and(|local| {
5716 local
5717 .buffers_opened_in_servers
5718 .get(&buffer_id)
5719 .cloned()
5720 .unwrap_or_default()
5721 != cached_data.lens.keys().copied().collect()
5722 });
5723 if !has_different_servers {
5724 return Task::ready(Ok(cached_data.lens.values().flatten().cloned().collect()))
5725 .shared();
5726 }
5727 }
5728
5729 let lsp_data = self.lsp_code_lens.entry(buffer_id).or_default();
5730 if let Some((updating_for, running_update)) = &lsp_data.update
5731 && !version_queried_for.changed_since(updating_for)
5732 {
5733 return running_update.clone();
5734 }
5735 let buffer = buffer.clone();
5736 let query_version_queried_for = version_queried_for.clone();
5737 let new_task = cx
5738 .spawn(async move |lsp_store, cx| {
5739 cx.background_executor()
5740 .timer(Duration::from_millis(30))
5741 .await;
5742 let fetched_lens = lsp_store
5743 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5744 .map_err(Arc::new)?
5745 .await
5746 .context("fetching code lens")
5747 .map_err(Arc::new);
5748 let fetched_lens = match fetched_lens {
5749 Ok(fetched_lens) => fetched_lens,
5750 Err(e) => {
5751 lsp_store
5752 .update(cx, |lsp_store, _| {
5753 lsp_store.lsp_code_lens.entry(buffer_id).or_default().update = None;
5754 })
5755 .ok();
5756 return Err(e);
5757 }
5758 };
5759
5760 lsp_store
5761 .update(cx, |lsp_store, _| {
5762 let lsp_data = lsp_store.lsp_code_lens.entry(buffer_id).or_default();
5763 if lsp_data.lens_for_version == query_version_queried_for {
5764 lsp_data.lens.extend(fetched_lens.clone());
5765 } else if !lsp_data
5766 .lens_for_version
5767 .changed_since(&query_version_queried_for)
5768 {
5769 lsp_data.lens_for_version = query_version_queried_for;
5770 lsp_data.lens = fetched_lens.clone();
5771 }
5772 lsp_data.update = None;
5773 lsp_data.lens.values().flatten().cloned().collect()
5774 })
5775 .map_err(Arc::new)
5776 })
5777 .shared();
5778 lsp_data.update = Some((version_queried_for, new_task.clone()));
5779 new_task
5780 }
5781
5782 fn fetch_code_lens(
5783 &mut self,
5784 buffer: &Entity<Buffer>,
5785 cx: &mut Context<Self>,
5786 ) -> Task<Result<HashMap<LanguageServerId, Vec<CodeAction>>>> {
5787 if let Some((upstream_client, project_id)) = self.upstream_client() {
5788 let request = GetCodeLens;
5789 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5790 return Task::ready(Ok(HashMap::default()));
5791 }
5792 let request_task = upstream_client.request(proto::MultiLspQuery {
5793 buffer_id: buffer.read(cx).remote_id().into(),
5794 version: serialize_version(&buffer.read(cx).version()),
5795 project_id,
5796 strategy: Some(proto::multi_lsp_query::Strategy::All(
5797 proto::AllLanguageServers {},
5798 )),
5799 request: Some(proto::multi_lsp_query::Request::GetCodeLens(
5800 request.to_proto(project_id, buffer.read(cx)),
5801 )),
5802 });
5803 let buffer = buffer.clone();
5804 cx.spawn(async move |weak_lsp_store, cx| {
5805 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5806 return Ok(HashMap::default());
5807 };
5808 let responses = request_task.await?.responses;
5809 let code_lens_actions = join_all(
5810 responses
5811 .into_iter()
5812 .filter_map(|lsp_response| {
5813 let response = match lsp_response.response? {
5814 proto::lsp_response::Response::GetCodeLensResponse(response) => {
5815 Some(response)
5816 }
5817 unexpected => {
5818 debug_panic!("Unexpected response: {unexpected:?}");
5819 None
5820 }
5821 }?;
5822 let server_id = LanguageServerId::from_proto(lsp_response.server_id);
5823 Some((server_id, response))
5824 })
5825 .map(|(server_id, code_lens_response)| {
5826 let lsp_store = lsp_store.clone();
5827 let buffer = buffer.clone();
5828 let cx = cx.clone();
5829 async move {
5830 (
5831 server_id,
5832 GetCodeLens
5833 .response_from_proto(
5834 code_lens_response,
5835 lsp_store,
5836 buffer,
5837 cx,
5838 )
5839 .await,
5840 )
5841 }
5842 }),
5843 )
5844 .await;
5845
5846 let mut has_errors = false;
5847 let code_lens_actions = code_lens_actions
5848 .into_iter()
5849 .filter_map(|(server_id, code_lens)| match code_lens {
5850 Ok(code_lens) => Some((server_id, code_lens)),
5851 Err(e) => {
5852 has_errors = true;
5853 log::error!("{e:#}");
5854 None
5855 }
5856 })
5857 .collect::<HashMap<_, _>>();
5858 anyhow::ensure!(
5859 !has_errors || !code_lens_actions.is_empty(),
5860 "Failed to fetch code lens"
5861 );
5862 Ok(code_lens_actions)
5863 })
5864 } else {
5865 let code_lens_actions_task =
5866 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5867 cx.background_spawn(
5868 async move { Ok(code_lens_actions_task.await.into_iter().collect()) },
5869 )
5870 }
5871 }
5872
5873 #[inline(never)]
5874 pub fn completions(
5875 &self,
5876 buffer: &Entity<Buffer>,
5877 position: PointUtf16,
5878 context: CompletionContext,
5879 cx: &mut Context<Self>,
5880 ) -> Task<Result<Vec<CompletionResponse>>> {
5881 let language_registry = self.languages.clone();
5882
5883 if let Some((upstream_client, project_id)) = self.upstream_client() {
5884 let request = GetCompletions { position, context };
5885 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5886 return Task::ready(Ok(Vec::new()));
5887 }
5888 let task = self.send_lsp_proto_request(
5889 buffer.clone(),
5890 upstream_client,
5891 project_id,
5892 request,
5893 cx,
5894 );
5895 let language = buffer.read(cx).language().cloned();
5896
5897 // In the future, we should provide project guests with the names of LSP adapters,
5898 // so that they can use the correct LSP adapter when computing labels. For now,
5899 // guests just use the first LSP adapter associated with the buffer's language.
5900 let lsp_adapter = language.as_ref().and_then(|language| {
5901 language_registry
5902 .lsp_adapters(&language.name())
5903 .first()
5904 .cloned()
5905 });
5906
5907 cx.foreground_executor().spawn(async move {
5908 let completion_response = task.await?;
5909 let completions = populate_labels_for_completions(
5910 completion_response.completions,
5911 language,
5912 lsp_adapter,
5913 )
5914 .await;
5915 Ok(vec![CompletionResponse {
5916 completions,
5917 is_incomplete: completion_response.is_incomplete,
5918 }])
5919 })
5920 } else if let Some(local) = self.as_local() {
5921 let snapshot = buffer.read(cx).snapshot();
5922 let offset = position.to_offset(&snapshot);
5923 let scope = snapshot.language_scope_at(offset);
5924 let language = snapshot.language().cloned();
5925 let completion_settings = language_settings(
5926 language.as_ref().map(|language| language.name()),
5927 buffer.read(cx).file(),
5928 cx,
5929 )
5930 .completions;
5931 if !completion_settings.lsp {
5932 return Task::ready(Ok(Vec::new()));
5933 }
5934
5935 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5936 local
5937 .language_servers_for_buffer(buffer, cx)
5938 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5939 .filter(|(adapter, _)| {
5940 scope
5941 .as_ref()
5942 .map(|scope| scope.language_allowed(&adapter.name))
5943 .unwrap_or(true)
5944 })
5945 .map(|(_, server)| server.server_id())
5946 .collect()
5947 });
5948
5949 let buffer = buffer.clone();
5950 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5951 let lsp_timeout = if lsp_timeout > 0 {
5952 Some(Duration::from_millis(lsp_timeout))
5953 } else {
5954 None
5955 };
5956 cx.spawn(async move |this, cx| {
5957 let mut tasks = Vec::with_capacity(server_ids.len());
5958 this.update(cx, |lsp_store, cx| {
5959 for server_id in server_ids {
5960 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5961 let lsp_timeout = lsp_timeout
5962 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5963 let mut timeout = cx.background_spawn(async move {
5964 match lsp_timeout {
5965 Some(lsp_timeout) => {
5966 lsp_timeout.await;
5967 true
5968 },
5969 None => false,
5970 }
5971 }).fuse();
5972 let mut lsp_request = lsp_store.request_lsp(
5973 buffer.clone(),
5974 LanguageServerToQuery::Other(server_id),
5975 GetCompletions {
5976 position,
5977 context: context.clone(),
5978 },
5979 cx,
5980 ).fuse();
5981 let new_task = cx.background_spawn(async move {
5982 select_biased! {
5983 response = lsp_request => anyhow::Ok(Some(response?)),
5984 timeout_happened = timeout => {
5985 if timeout_happened {
5986 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5987 Ok(None)
5988 } else {
5989 let completions = lsp_request.await?;
5990 Ok(Some(completions))
5991 }
5992 },
5993 }
5994 });
5995 tasks.push((lsp_adapter, new_task));
5996 }
5997 })?;
5998
5999 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6000 let completion_response = task.await.ok()??;
6001 let completions = populate_labels_for_completions(
6002 completion_response.completions,
6003 language.clone(),
6004 lsp_adapter,
6005 )
6006 .await;
6007 Some(CompletionResponse {
6008 completions,
6009 is_incomplete: completion_response.is_incomplete,
6010 })
6011 });
6012
6013 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6014
6015 Ok(responses.into_iter().flatten().collect())
6016 })
6017 } else {
6018 Task::ready(Err(anyhow!("No upstream client or local language server")))
6019 }
6020 }
6021
6022 pub fn resolve_completions(
6023 &self,
6024 buffer: Entity<Buffer>,
6025 completion_indices: Vec<usize>,
6026 completions: Rc<RefCell<Box<[Completion]>>>,
6027 cx: &mut Context<Self>,
6028 ) -> Task<Result<bool>> {
6029 let client = self.upstream_client();
6030 let buffer_id = buffer.read(cx).remote_id();
6031 let buffer_snapshot = buffer.read(cx).snapshot();
6032
6033 if !self.check_if_capable_for_proto_request(
6034 &buffer,
6035 GetCompletions::can_resolve_completions,
6036 cx,
6037 ) {
6038 return Task::ready(Ok(false));
6039 }
6040 cx.spawn(async move |lsp_store, cx| {
6041 let mut did_resolve = false;
6042 if let Some((client, project_id)) = client {
6043 for completion_index in completion_indices {
6044 let server_id = {
6045 let completion = &completions.borrow()[completion_index];
6046 completion.source.server_id()
6047 };
6048 if let Some(server_id) = server_id {
6049 if Self::resolve_completion_remote(
6050 project_id,
6051 server_id,
6052 buffer_id,
6053 completions.clone(),
6054 completion_index,
6055 client.clone(),
6056 )
6057 .await
6058 .log_err()
6059 .is_some()
6060 {
6061 did_resolve = true;
6062 }
6063 } else {
6064 resolve_word_completion(
6065 &buffer_snapshot,
6066 &mut completions.borrow_mut()[completion_index],
6067 );
6068 }
6069 }
6070 } else {
6071 for completion_index in completion_indices {
6072 let server_id = {
6073 let completion = &completions.borrow()[completion_index];
6074 completion.source.server_id()
6075 };
6076 if let Some(server_id) = server_id {
6077 let server_and_adapter = lsp_store
6078 .read_with(cx, |lsp_store, _| {
6079 let server = lsp_store.language_server_for_id(server_id)?;
6080 let adapter =
6081 lsp_store.language_server_adapter_for_id(server.server_id())?;
6082 Some((server, adapter))
6083 })
6084 .ok()
6085 .flatten();
6086 let Some((server, adapter)) = server_and_adapter else {
6087 continue;
6088 };
6089
6090 let resolved = Self::resolve_completion_local(
6091 server,
6092 completions.clone(),
6093 completion_index,
6094 )
6095 .await
6096 .log_err()
6097 .is_some();
6098 if resolved {
6099 Self::regenerate_completion_labels(
6100 adapter,
6101 &buffer_snapshot,
6102 completions.clone(),
6103 completion_index,
6104 )
6105 .await
6106 .log_err();
6107 did_resolve = true;
6108 }
6109 } else {
6110 resolve_word_completion(
6111 &buffer_snapshot,
6112 &mut completions.borrow_mut()[completion_index],
6113 );
6114 }
6115 }
6116 }
6117
6118 Ok(did_resolve)
6119 })
6120 }
6121
6122 async fn resolve_completion_local(
6123 server: Arc<lsp::LanguageServer>,
6124 completions: Rc<RefCell<Box<[Completion]>>>,
6125 completion_index: usize,
6126 ) -> Result<()> {
6127 let server_id = server.server_id();
6128 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6129 return Ok(());
6130 }
6131
6132 let request = {
6133 let completion = &completions.borrow()[completion_index];
6134 match &completion.source {
6135 CompletionSource::Lsp {
6136 lsp_completion,
6137 resolved,
6138 server_id: completion_server_id,
6139 ..
6140 } => {
6141 if *resolved {
6142 return Ok(());
6143 }
6144 anyhow::ensure!(
6145 server_id == *completion_server_id,
6146 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6147 );
6148 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6149 }
6150 CompletionSource::BufferWord { .. }
6151 | CompletionSource::Dap { .. }
6152 | CompletionSource::Custom => {
6153 return Ok(());
6154 }
6155 }
6156 };
6157 let resolved_completion = request
6158 .await
6159 .into_response()
6160 .context("resolve completion")?;
6161
6162 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6163 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6164
6165 let mut completions = completions.borrow_mut();
6166 let completion = &mut completions[completion_index];
6167 if let CompletionSource::Lsp {
6168 lsp_completion,
6169 resolved,
6170 server_id: completion_server_id,
6171 ..
6172 } = &mut completion.source
6173 {
6174 if *resolved {
6175 return Ok(());
6176 }
6177 anyhow::ensure!(
6178 server_id == *completion_server_id,
6179 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6180 );
6181 *lsp_completion = Box::new(resolved_completion);
6182 *resolved = true;
6183 }
6184 Ok(())
6185 }
6186
6187 async fn regenerate_completion_labels(
6188 adapter: Arc<CachedLspAdapter>,
6189 snapshot: &BufferSnapshot,
6190 completions: Rc<RefCell<Box<[Completion]>>>,
6191 completion_index: usize,
6192 ) -> Result<()> {
6193 let completion_item = completions.borrow()[completion_index]
6194 .source
6195 .lsp_completion(true)
6196 .map(Cow::into_owned);
6197 if let Some(lsp_documentation) = completion_item
6198 .as_ref()
6199 .and_then(|completion_item| completion_item.documentation.clone())
6200 {
6201 let mut completions = completions.borrow_mut();
6202 let completion = &mut completions[completion_index];
6203 completion.documentation = Some(lsp_documentation.into());
6204 } else {
6205 let mut completions = completions.borrow_mut();
6206 let completion = &mut completions[completion_index];
6207 completion.documentation = Some(CompletionDocumentation::Undocumented);
6208 }
6209
6210 let mut new_label = match completion_item {
6211 Some(completion_item) => {
6212 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6213 // So we have to update the label here anyway...
6214 let language = snapshot.language();
6215 match language {
6216 Some(language) => {
6217 adapter
6218 .labels_for_completions(
6219 std::slice::from_ref(&completion_item),
6220 language,
6221 )
6222 .await?
6223 }
6224 None => Vec::new(),
6225 }
6226 .pop()
6227 .flatten()
6228 .unwrap_or_else(|| {
6229 CodeLabel::fallback_for_completion(
6230 &completion_item,
6231 language.map(|language| language.as_ref()),
6232 )
6233 })
6234 }
6235 None => CodeLabel::plain(
6236 completions.borrow()[completion_index].new_text.clone(),
6237 None,
6238 ),
6239 };
6240 ensure_uniform_list_compatible_label(&mut new_label);
6241
6242 let mut completions = completions.borrow_mut();
6243 let completion = &mut completions[completion_index];
6244 if completion.label.filter_text() == new_label.filter_text() {
6245 completion.label = new_label;
6246 } else {
6247 log::error!(
6248 "Resolved completion changed display label from {} to {}. \
6249 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6250 completion.label.text(),
6251 new_label.text(),
6252 completion.label.filter_text(),
6253 new_label.filter_text()
6254 );
6255 }
6256
6257 Ok(())
6258 }
6259
6260 async fn resolve_completion_remote(
6261 project_id: u64,
6262 server_id: LanguageServerId,
6263 buffer_id: BufferId,
6264 completions: Rc<RefCell<Box<[Completion]>>>,
6265 completion_index: usize,
6266 client: AnyProtoClient,
6267 ) -> Result<()> {
6268 let lsp_completion = {
6269 let completion = &completions.borrow()[completion_index];
6270 match &completion.source {
6271 CompletionSource::Lsp {
6272 lsp_completion,
6273 resolved,
6274 server_id: completion_server_id,
6275 ..
6276 } => {
6277 anyhow::ensure!(
6278 server_id == *completion_server_id,
6279 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6280 );
6281 if *resolved {
6282 return Ok(());
6283 }
6284 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6285 }
6286 CompletionSource::Custom
6287 | CompletionSource::Dap { .. }
6288 | CompletionSource::BufferWord { .. } => {
6289 return Ok(());
6290 }
6291 }
6292 };
6293 let request = proto::ResolveCompletionDocumentation {
6294 project_id,
6295 language_server_id: server_id.0 as u64,
6296 lsp_completion,
6297 buffer_id: buffer_id.into(),
6298 };
6299
6300 let response = client
6301 .request(request)
6302 .await
6303 .context("completion documentation resolve proto request")?;
6304 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6305
6306 let documentation = if response.documentation.is_empty() {
6307 CompletionDocumentation::Undocumented
6308 } else if response.documentation_is_markdown {
6309 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6310 } else if response.documentation.lines().count() <= 1 {
6311 CompletionDocumentation::SingleLine(response.documentation.into())
6312 } else {
6313 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6314 };
6315
6316 let mut completions = completions.borrow_mut();
6317 let completion = &mut completions[completion_index];
6318 completion.documentation = Some(documentation);
6319 if let CompletionSource::Lsp {
6320 insert_range,
6321 lsp_completion,
6322 resolved,
6323 server_id: completion_server_id,
6324 lsp_defaults: _,
6325 } = &mut completion.source
6326 {
6327 let completion_insert_range = response
6328 .old_insert_start
6329 .and_then(deserialize_anchor)
6330 .zip(response.old_insert_end.and_then(deserialize_anchor));
6331 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6332
6333 if *resolved {
6334 return Ok(());
6335 }
6336 anyhow::ensure!(
6337 server_id == *completion_server_id,
6338 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6339 );
6340 *lsp_completion = Box::new(resolved_lsp_completion);
6341 *resolved = true;
6342 }
6343
6344 let replace_range = response
6345 .old_replace_start
6346 .and_then(deserialize_anchor)
6347 .zip(response.old_replace_end.and_then(deserialize_anchor));
6348 if let Some((old_replace_start, old_replace_end)) = replace_range
6349 && !response.new_text.is_empty()
6350 {
6351 completion.new_text = response.new_text;
6352 completion.replace_range = old_replace_start..old_replace_end;
6353 }
6354
6355 Ok(())
6356 }
6357
6358 pub fn apply_additional_edits_for_completion(
6359 &self,
6360 buffer_handle: Entity<Buffer>,
6361 completions: Rc<RefCell<Box<[Completion]>>>,
6362 completion_index: usize,
6363 push_to_history: bool,
6364 cx: &mut Context<Self>,
6365 ) -> Task<Result<Option<Transaction>>> {
6366 if let Some((client, project_id)) = self.upstream_client() {
6367 let buffer = buffer_handle.read(cx);
6368 let buffer_id = buffer.remote_id();
6369 cx.spawn(async move |_, cx| {
6370 let request = {
6371 let completion = completions.borrow()[completion_index].clone();
6372 proto::ApplyCompletionAdditionalEdits {
6373 project_id,
6374 buffer_id: buffer_id.into(),
6375 completion: Some(Self::serialize_completion(&CoreCompletion {
6376 replace_range: completion.replace_range,
6377 new_text: completion.new_text,
6378 source: completion.source,
6379 })),
6380 }
6381 };
6382
6383 if let Some(transaction) = client.request(request).await?.transaction {
6384 let transaction = language::proto::deserialize_transaction(transaction)?;
6385 buffer_handle
6386 .update(cx, |buffer, _| {
6387 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6388 })?
6389 .await?;
6390 if push_to_history {
6391 buffer_handle.update(cx, |buffer, _| {
6392 buffer.push_transaction(transaction.clone(), Instant::now());
6393 buffer.finalize_last_transaction();
6394 })?;
6395 }
6396 Ok(Some(transaction))
6397 } else {
6398 Ok(None)
6399 }
6400 })
6401 } else {
6402 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6403 let completion = &completions.borrow()[completion_index];
6404 let server_id = completion.source.server_id()?;
6405 Some(
6406 self.language_server_for_local_buffer(buffer, server_id, cx)?
6407 .1
6408 .clone(),
6409 )
6410 }) else {
6411 return Task::ready(Ok(None));
6412 };
6413
6414 cx.spawn(async move |this, cx| {
6415 Self::resolve_completion_local(
6416 server.clone(),
6417 completions.clone(),
6418 completion_index,
6419 )
6420 .await
6421 .context("resolving completion")?;
6422 let completion = completions.borrow()[completion_index].clone();
6423 let additional_text_edits = completion
6424 .source
6425 .lsp_completion(true)
6426 .as_ref()
6427 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6428 if let Some(edits) = additional_text_edits {
6429 let edits = this
6430 .update(cx, |this, cx| {
6431 this.as_local_mut().unwrap().edits_from_lsp(
6432 &buffer_handle,
6433 edits,
6434 server.server_id(),
6435 None,
6436 cx,
6437 )
6438 })?
6439 .await?;
6440
6441 buffer_handle.update(cx, |buffer, cx| {
6442 buffer.finalize_last_transaction();
6443 buffer.start_transaction();
6444
6445 for (range, text) in edits {
6446 let primary = &completion.replace_range;
6447 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6448 && primary.end.cmp(&range.start, buffer).is_ge();
6449 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6450 && range.end.cmp(&primary.end, buffer).is_ge();
6451
6452 //Skip additional edits which overlap with the primary completion edit
6453 //https://github.com/zed-industries/zed/pull/1871
6454 if !start_within && !end_within {
6455 buffer.edit([(range, text)], None, cx);
6456 }
6457 }
6458
6459 let transaction = if buffer.end_transaction(cx).is_some() {
6460 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6461 if !push_to_history {
6462 buffer.forget_transaction(transaction.id);
6463 }
6464 Some(transaction)
6465 } else {
6466 None
6467 };
6468 Ok(transaction)
6469 })?
6470 } else {
6471 Ok(None)
6472 }
6473 })
6474 }
6475 }
6476
6477 pub fn pull_diagnostics(
6478 &mut self,
6479 buffer: Entity<Buffer>,
6480 cx: &mut Context<Self>,
6481 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6482 let buffer_id = buffer.read(cx).remote_id();
6483
6484 if let Some((client, upstream_project_id)) = self.upstream_client() {
6485 if !self.is_capable_for_proto_request(
6486 &buffer,
6487 &GetDocumentDiagnostics {
6488 previous_result_id: None,
6489 },
6490 cx,
6491 ) {
6492 return Task::ready(Ok(None));
6493 }
6494 let request_task = client.request(proto::MultiLspQuery {
6495 buffer_id: buffer_id.to_proto(),
6496 version: serialize_version(&buffer.read(cx).version()),
6497 project_id: upstream_project_id,
6498 strategy: Some(proto::multi_lsp_query::Strategy::All(
6499 proto::AllLanguageServers {},
6500 )),
6501 request: Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(
6502 proto::GetDocumentDiagnostics {
6503 project_id: upstream_project_id,
6504 buffer_id: buffer_id.to_proto(),
6505 version: serialize_version(&buffer.read(cx).version()),
6506 },
6507 )),
6508 });
6509 cx.background_spawn(async move {
6510 let _proto_responses = request_task
6511 .await?
6512 .responses
6513 .into_iter()
6514 .filter_map(|lsp_response| match lsp_response.response? {
6515 proto::lsp_response::Response::GetDocumentDiagnosticsResponse(response) => {
6516 Some(response)
6517 }
6518 unexpected => {
6519 debug_panic!("Unexpected response: {unexpected:?}");
6520 None
6521 }
6522 })
6523 .collect::<Vec<_>>();
6524 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6525 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6526 // Do not attempt to further process the dummy responses here.
6527 Ok(None)
6528 })
6529 } else {
6530 let server_ids = buffer.update(cx, |buffer, cx| {
6531 self.language_servers_for_local_buffer(buffer, cx)
6532 .map(|(_, server)| server.server_id())
6533 .collect::<Vec<_>>()
6534 });
6535 let pull_diagnostics = server_ids
6536 .into_iter()
6537 .map(|server_id| {
6538 let result_id = self.result_id(server_id, buffer_id, cx);
6539 self.request_lsp(
6540 buffer.clone(),
6541 LanguageServerToQuery::Other(server_id),
6542 GetDocumentDiagnostics {
6543 previous_result_id: result_id,
6544 },
6545 cx,
6546 )
6547 })
6548 .collect::<Vec<_>>();
6549
6550 cx.background_spawn(async move {
6551 let mut responses = Vec::new();
6552 for diagnostics in join_all(pull_diagnostics).await {
6553 responses.extend(diagnostics?);
6554 }
6555 Ok(Some(responses))
6556 })
6557 }
6558 }
6559
6560 pub fn inlay_hints(
6561 &mut self,
6562 buffer: Entity<Buffer>,
6563 range: Range<Anchor>,
6564 cx: &mut Context<Self>,
6565 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
6566 let range_start = range.start;
6567 let range_end = range.end;
6568 let buffer_id = buffer.read(cx).remote_id().into();
6569 let request = InlayHints { range };
6570
6571 if let Some((client, project_id)) = self.upstream_client() {
6572 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6573 return Task::ready(Ok(Vec::new()));
6574 }
6575 let proto_request = proto::InlayHints {
6576 project_id,
6577 buffer_id,
6578 start: Some(serialize_anchor(&range_start)),
6579 end: Some(serialize_anchor(&range_end)),
6580 version: serialize_version(&buffer.read(cx).version()),
6581 };
6582 cx.spawn(async move |project, cx| {
6583 let response = client
6584 .request(proto_request)
6585 .await
6586 .context("inlay hints proto request")?;
6587 LspCommand::response_from_proto(
6588 request,
6589 response,
6590 project.upgrade().context("No project")?,
6591 buffer.clone(),
6592 cx.clone(),
6593 )
6594 .await
6595 .context("inlay hints proto response conversion")
6596 })
6597 } else {
6598 let lsp_request_task = self.request_lsp(
6599 buffer.clone(),
6600 LanguageServerToQuery::FirstCapable,
6601 request,
6602 cx,
6603 );
6604 cx.spawn(async move |_, cx| {
6605 buffer
6606 .update(cx, |buffer, _| {
6607 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
6608 })?
6609 .await
6610 .context("waiting for inlay hint request range edits")?;
6611 lsp_request_task.await.context("inlay hints LSP request")
6612 })
6613 }
6614 }
6615
6616 pub fn pull_diagnostics_for_buffer(
6617 &mut self,
6618 buffer: Entity<Buffer>,
6619 cx: &mut Context<Self>,
6620 ) -> Task<anyhow::Result<()>> {
6621 let diagnostics = self.pull_diagnostics(buffer, cx);
6622 cx.spawn(async move |lsp_store, cx| {
6623 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6624 return Ok(());
6625 };
6626 lsp_store.update(cx, |lsp_store, cx| {
6627 if lsp_store.as_local().is_none() {
6628 return;
6629 }
6630
6631 let mut unchanged_buffers = HashSet::default();
6632 let mut changed_buffers = HashSet::default();
6633 let server_diagnostics_updates = diagnostics
6634 .into_iter()
6635 .filter_map(|diagnostics_set| match diagnostics_set {
6636 LspPullDiagnostics::Response {
6637 server_id,
6638 uri,
6639 diagnostics,
6640 } => Some((server_id, uri, diagnostics)),
6641 LspPullDiagnostics::Default => None,
6642 })
6643 .fold(
6644 HashMap::default(),
6645 |mut acc, (server_id, uri, diagnostics)| {
6646 let (result_id, diagnostics) = match diagnostics {
6647 PulledDiagnostics::Unchanged { result_id } => {
6648 unchanged_buffers.insert(uri.clone());
6649 (Some(result_id), Vec::new())
6650 }
6651 PulledDiagnostics::Changed {
6652 result_id,
6653 diagnostics,
6654 } => {
6655 changed_buffers.insert(uri.clone());
6656 (result_id, diagnostics)
6657 }
6658 };
6659 let disk_based_sources = Cow::Owned(
6660 lsp_store
6661 .language_server_adapter_for_id(server_id)
6662 .as_ref()
6663 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6664 .unwrap_or(&[])
6665 .to_vec(),
6666 );
6667 acc.entry(server_id).or_insert_with(Vec::new).push(
6668 DocumentDiagnosticsUpdate {
6669 server_id,
6670 diagnostics: lsp::PublishDiagnosticsParams {
6671 uri,
6672 diagnostics,
6673 version: None,
6674 },
6675 result_id,
6676 disk_based_sources,
6677 },
6678 );
6679 acc
6680 },
6681 );
6682
6683 for diagnostic_updates in server_diagnostics_updates.into_values() {
6684 lsp_store
6685 .merge_lsp_diagnostics(
6686 DiagnosticSourceKind::Pulled,
6687 diagnostic_updates,
6688 |buffer, old_diagnostic, cx| {
6689 File::from_dyn(buffer.file())
6690 .and_then(|file| {
6691 let abs_path = file.as_local()?.abs_path(cx);
6692 lsp::Url::from_file_path(abs_path).ok()
6693 })
6694 .is_none_or(|buffer_uri| {
6695 unchanged_buffers.contains(&buffer_uri)
6696 || match old_diagnostic.source_kind {
6697 DiagnosticSourceKind::Pulled => {
6698 !changed_buffers.contains(&buffer_uri)
6699 }
6700 DiagnosticSourceKind::Other
6701 | DiagnosticSourceKind::Pushed => true,
6702 }
6703 })
6704 },
6705 cx,
6706 )
6707 .log_err();
6708 }
6709 })
6710 })
6711 }
6712
6713 pub fn document_colors(
6714 &mut self,
6715 fetch_strategy: LspFetchStrategy,
6716 buffer: Entity<Buffer>,
6717 cx: &mut Context<Self>,
6718 ) -> Option<DocumentColorTask> {
6719 let version_queried_for = buffer.read(cx).version();
6720 let buffer_id = buffer.read(cx).remote_id();
6721
6722 match fetch_strategy {
6723 LspFetchStrategy::IgnoreCache => {}
6724 LspFetchStrategy::UseCache {
6725 known_cache_version,
6726 } => {
6727 if let Some(cached_data) = self.lsp_document_colors.get(&buffer_id)
6728 && !version_queried_for.changed_since(&cached_data.colors_for_version)
6729 {
6730 let has_different_servers = self.as_local().is_some_and(|local| {
6731 local
6732 .buffers_opened_in_servers
6733 .get(&buffer_id)
6734 .cloned()
6735 .unwrap_or_default()
6736 != cached_data.colors.keys().copied().collect()
6737 });
6738 if !has_different_servers {
6739 if Some(cached_data.cache_version) == known_cache_version {
6740 return None;
6741 } else {
6742 return Some(
6743 Task::ready(Ok(DocumentColors {
6744 colors: cached_data
6745 .colors
6746 .values()
6747 .flatten()
6748 .cloned()
6749 .collect(),
6750 cache_version: Some(cached_data.cache_version),
6751 }))
6752 .shared(),
6753 );
6754 }
6755 }
6756 }
6757 }
6758 }
6759
6760 let lsp_data = self.lsp_document_colors.entry(buffer_id).or_default();
6761 if let Some((updating_for, running_update)) = &lsp_data.colors_update
6762 && !version_queried_for.changed_since(updating_for)
6763 {
6764 return Some(running_update.clone());
6765 }
6766 let query_version_queried_for = version_queried_for.clone();
6767 let new_task = cx
6768 .spawn(async move |lsp_store, cx| {
6769 cx.background_executor()
6770 .timer(Duration::from_millis(30))
6771 .await;
6772 let fetched_colors = lsp_store
6773 .update(cx, |lsp_store, cx| {
6774 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6775 })?
6776 .await
6777 .context("fetching document colors")
6778 .map_err(Arc::new);
6779 let fetched_colors = match fetched_colors {
6780 Ok(fetched_colors) => {
6781 if fetch_strategy != LspFetchStrategy::IgnoreCache
6782 && Some(true)
6783 == buffer
6784 .update(cx, |buffer, _| {
6785 buffer.version() != query_version_queried_for
6786 })
6787 .ok()
6788 {
6789 return Ok(DocumentColors::default());
6790 }
6791 fetched_colors
6792 }
6793 Err(e) => {
6794 lsp_store
6795 .update(cx, |lsp_store, _| {
6796 lsp_store
6797 .lsp_document_colors
6798 .entry(buffer_id)
6799 .or_default()
6800 .colors_update = None;
6801 })
6802 .ok();
6803 return Err(e);
6804 }
6805 };
6806
6807 lsp_store
6808 .update(cx, |lsp_store, _| {
6809 let lsp_data = lsp_store.lsp_document_colors.entry(buffer_id).or_default();
6810
6811 if lsp_data.colors_for_version == query_version_queried_for {
6812 lsp_data.colors.extend(fetched_colors.clone());
6813 lsp_data.cache_version += 1;
6814 } else if !lsp_data
6815 .colors_for_version
6816 .changed_since(&query_version_queried_for)
6817 {
6818 lsp_data.colors_for_version = query_version_queried_for;
6819 lsp_data.colors = fetched_colors.clone();
6820 lsp_data.cache_version += 1;
6821 }
6822 lsp_data.colors_update = None;
6823 let colors = lsp_data
6824 .colors
6825 .values()
6826 .flatten()
6827 .cloned()
6828 .collect::<HashSet<_>>();
6829 DocumentColors {
6830 colors,
6831 cache_version: Some(lsp_data.cache_version),
6832 }
6833 })
6834 .map_err(Arc::new)
6835 })
6836 .shared();
6837 lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
6838 Some(new_task)
6839 }
6840
6841 fn fetch_document_colors_for_buffer(
6842 &mut self,
6843 buffer: &Entity<Buffer>,
6844 cx: &mut Context<Self>,
6845 ) -> Task<anyhow::Result<HashMap<LanguageServerId, HashSet<DocumentColor>>>> {
6846 if let Some((client, project_id)) = self.upstream_client() {
6847 let request = GetDocumentColor {};
6848 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6849 return Task::ready(Ok(HashMap::default()));
6850 }
6851
6852 let request_task = client.request(proto::MultiLspQuery {
6853 project_id,
6854 buffer_id: buffer.read(cx).remote_id().to_proto(),
6855 version: serialize_version(&buffer.read(cx).version()),
6856 strategy: Some(proto::multi_lsp_query::Strategy::All(
6857 proto::AllLanguageServers {},
6858 )),
6859 request: Some(proto::multi_lsp_query::Request::GetDocumentColor(
6860 request.to_proto(project_id, buffer.read(cx)),
6861 )),
6862 });
6863 let buffer = buffer.clone();
6864 cx.spawn(async move |project, cx| {
6865 let Some(project) = project.upgrade() else {
6866 return Ok(HashMap::default());
6867 };
6868 let colors = join_all(
6869 request_task
6870 .await
6871 .log_err()
6872 .map(|response| response.responses)
6873 .unwrap_or_default()
6874 .into_iter()
6875 .filter_map(|lsp_response| match lsp_response.response? {
6876 proto::lsp_response::Response::GetDocumentColorResponse(response) => {
6877 Some((
6878 LanguageServerId::from_proto(lsp_response.server_id),
6879 response,
6880 ))
6881 }
6882 unexpected => {
6883 debug_panic!("Unexpected response: {unexpected:?}");
6884 None
6885 }
6886 })
6887 .map(|(server_id, color_response)| {
6888 let response = request.response_from_proto(
6889 color_response,
6890 project.clone(),
6891 buffer.clone(),
6892 cx.clone(),
6893 );
6894 async move { (server_id, response.await.log_err().unwrap_or_default()) }
6895 }),
6896 )
6897 .await
6898 .into_iter()
6899 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6900 acc.entry(server_id)
6901 .or_insert_with(HashSet::default)
6902 .extend(colors);
6903 acc
6904 });
6905 Ok(colors)
6906 })
6907 } else {
6908 let document_colors_task =
6909 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
6910 cx.background_spawn(async move {
6911 Ok(document_colors_task
6912 .await
6913 .into_iter()
6914 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6915 acc.entry(server_id)
6916 .or_insert_with(HashSet::default)
6917 .extend(colors);
6918 acc
6919 })
6920 .into_iter()
6921 .collect())
6922 })
6923 }
6924 }
6925
6926 pub fn signature_help<T: ToPointUtf16>(
6927 &mut self,
6928 buffer: &Entity<Buffer>,
6929 position: T,
6930 cx: &mut Context<Self>,
6931 ) -> Task<Vec<SignatureHelp>> {
6932 let position = position.to_point_utf16(buffer.read(cx));
6933
6934 if let Some((client, upstream_project_id)) = self.upstream_client() {
6935 let request = GetSignatureHelp { position };
6936 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6937 return Task::ready(Vec::new());
6938 }
6939 let request_task = client.request(proto::MultiLspQuery {
6940 buffer_id: buffer.read(cx).remote_id().into(),
6941 version: serialize_version(&buffer.read(cx).version()),
6942 project_id: upstream_project_id,
6943 strategy: Some(proto::multi_lsp_query::Strategy::All(
6944 proto::AllLanguageServers {},
6945 )),
6946 request: Some(proto::multi_lsp_query::Request::GetSignatureHelp(
6947 request.to_proto(upstream_project_id, buffer.read(cx)),
6948 )),
6949 });
6950 let buffer = buffer.clone();
6951 cx.spawn(async move |weak_project, cx| {
6952 let Some(project) = weak_project.upgrade() else {
6953 return Vec::new();
6954 };
6955 join_all(
6956 request_task
6957 .await
6958 .log_err()
6959 .map(|response| response.responses)
6960 .unwrap_or_default()
6961 .into_iter()
6962 .filter_map(|lsp_response| match lsp_response.response? {
6963 proto::lsp_response::Response::GetSignatureHelpResponse(response) => {
6964 Some(response)
6965 }
6966 unexpected => {
6967 debug_panic!("Unexpected response: {unexpected:?}");
6968 None
6969 }
6970 })
6971 .map(|signature_response| {
6972 let response = GetSignatureHelp { position }.response_from_proto(
6973 signature_response,
6974 project.clone(),
6975 buffer.clone(),
6976 cx.clone(),
6977 );
6978 async move { response.await.log_err().flatten() }
6979 }),
6980 )
6981 .await
6982 .into_iter()
6983 .flatten()
6984 .collect()
6985 })
6986 } else {
6987 let all_actions_task = self.request_multiple_lsp_locally(
6988 buffer,
6989 Some(position),
6990 GetSignatureHelp { position },
6991 cx,
6992 );
6993 cx.background_spawn(async move {
6994 all_actions_task
6995 .await
6996 .into_iter()
6997 .flat_map(|(_, actions)| actions)
6998 .collect::<Vec<_>>()
6999 })
7000 }
7001 }
7002
7003 pub fn hover(
7004 &mut self,
7005 buffer: &Entity<Buffer>,
7006 position: PointUtf16,
7007 cx: &mut Context<Self>,
7008 ) -> Task<Vec<Hover>> {
7009 if let Some((client, upstream_project_id)) = self.upstream_client() {
7010 let request = GetHover { position };
7011 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7012 return Task::ready(Vec::new());
7013 }
7014 let request_task = client.request(proto::MultiLspQuery {
7015 buffer_id: buffer.read(cx).remote_id().into(),
7016 version: serialize_version(&buffer.read(cx).version()),
7017 project_id: upstream_project_id,
7018 strategy: Some(proto::multi_lsp_query::Strategy::All(
7019 proto::AllLanguageServers {},
7020 )),
7021 request: Some(proto::multi_lsp_query::Request::GetHover(
7022 request.to_proto(upstream_project_id, buffer.read(cx)),
7023 )),
7024 });
7025 let buffer = buffer.clone();
7026 cx.spawn(async move |weak_project, cx| {
7027 let Some(project) = weak_project.upgrade() else {
7028 return Vec::new();
7029 };
7030 join_all(
7031 request_task
7032 .await
7033 .log_err()
7034 .map(|response| response.responses)
7035 .unwrap_or_default()
7036 .into_iter()
7037 .filter_map(|lsp_response| match lsp_response.response? {
7038 proto::lsp_response::Response::GetHoverResponse(response) => {
7039 Some(response)
7040 }
7041 unexpected => {
7042 debug_panic!("Unexpected response: {unexpected:?}");
7043 None
7044 }
7045 })
7046 .map(|hover_response| {
7047 let response = GetHover { position }.response_from_proto(
7048 hover_response,
7049 project.clone(),
7050 buffer.clone(),
7051 cx.clone(),
7052 );
7053 async move {
7054 response
7055 .await
7056 .log_err()
7057 .flatten()
7058 .and_then(remove_empty_hover_blocks)
7059 }
7060 }),
7061 )
7062 .await
7063 .into_iter()
7064 .flatten()
7065 .collect()
7066 })
7067 } else {
7068 let all_actions_task = self.request_multiple_lsp_locally(
7069 buffer,
7070 Some(position),
7071 GetHover { position },
7072 cx,
7073 );
7074 cx.background_spawn(async move {
7075 all_actions_task
7076 .await
7077 .into_iter()
7078 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7079 .collect::<Vec<Hover>>()
7080 })
7081 }
7082 }
7083
7084 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7085 let language_registry = self.languages.clone();
7086
7087 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7088 let request = upstream_client.request(proto::GetProjectSymbols {
7089 project_id: *project_id,
7090 query: query.to_string(),
7091 });
7092 cx.foreground_executor().spawn(async move {
7093 let response = request.await?;
7094 let mut symbols = Vec::new();
7095 let core_symbols = response
7096 .symbols
7097 .into_iter()
7098 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7099 .collect::<Vec<_>>();
7100 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7101 .await;
7102 Ok(symbols)
7103 })
7104 } else if let Some(local) = self.as_local() {
7105 struct WorkspaceSymbolsResult {
7106 server_id: LanguageServerId,
7107 lsp_adapter: Arc<CachedLspAdapter>,
7108 worktree: WeakEntity<Worktree>,
7109 worktree_abs_path: Arc<Path>,
7110 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7111 }
7112
7113 let mut requests = Vec::new();
7114 let mut requested_servers = BTreeSet::new();
7115 for (seed, state) in local.language_server_ids.iter() {
7116 let Some(worktree_handle) = self
7117 .worktree_store
7118 .read(cx)
7119 .worktree_for_id(seed.worktree_id, cx)
7120 else {
7121 continue;
7122 };
7123 let worktree = worktree_handle.read(cx);
7124 if !worktree.is_visible() {
7125 continue;
7126 }
7127
7128 if !requested_servers.insert(state.id) {
7129 continue;
7130 }
7131
7132 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7133 Some(LanguageServerState::Running {
7134 adapter, server, ..
7135 }) => (adapter.clone(), server),
7136
7137 _ => continue,
7138 };
7139 let supports_workspace_symbol_request =
7140 match server.capabilities().workspace_symbol_provider {
7141 Some(OneOf::Left(supported)) => supported,
7142 Some(OneOf::Right(_)) => true,
7143 None => false,
7144 };
7145 if !supports_workspace_symbol_request {
7146 continue;
7147 }
7148 let worktree_abs_path = worktree.abs_path().clone();
7149 let worktree_handle = worktree_handle.clone();
7150 let server_id = server.server_id();
7151 requests.push(
7152 server
7153 .request::<lsp::request::WorkspaceSymbolRequest>(
7154 lsp::WorkspaceSymbolParams {
7155 query: query.to_string(),
7156 ..Default::default()
7157 },
7158 )
7159 .map(move |response| {
7160 let lsp_symbols = response.into_response()
7161 .context("workspace symbols request")
7162 .log_err()
7163 .flatten()
7164 .map(|symbol_response| match symbol_response {
7165 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7166 flat_responses.into_iter().map(|lsp_symbol| {
7167 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7168 }).collect::<Vec<_>>()
7169 }
7170 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7171 nested_responses.into_iter().filter_map(|lsp_symbol| {
7172 let location = match lsp_symbol.location {
7173 OneOf::Left(location) => location,
7174 OneOf::Right(_) => {
7175 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7176 return None
7177 }
7178 };
7179 Some((lsp_symbol.name, lsp_symbol.kind, location))
7180 }).collect::<Vec<_>>()
7181 }
7182 }).unwrap_or_default();
7183
7184 WorkspaceSymbolsResult {
7185 server_id,
7186 lsp_adapter,
7187 worktree: worktree_handle.downgrade(),
7188 worktree_abs_path,
7189 lsp_symbols,
7190 }
7191 }),
7192 );
7193 }
7194
7195 cx.spawn(async move |this, cx| {
7196 let responses = futures::future::join_all(requests).await;
7197 let this = match this.upgrade() {
7198 Some(this) => this,
7199 None => return Ok(Vec::new()),
7200 };
7201
7202 let mut symbols = Vec::new();
7203 for result in responses {
7204 let core_symbols = this.update(cx, |this, cx| {
7205 result
7206 .lsp_symbols
7207 .into_iter()
7208 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7209 let abs_path = symbol_location.uri.to_file_path().ok()?;
7210 let source_worktree = result.worktree.upgrade()?;
7211 let source_worktree_id = source_worktree.read(cx).id();
7212
7213 let path;
7214 let worktree;
7215 if let Some((tree, rel_path)) =
7216 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7217 {
7218 worktree = tree;
7219 path = rel_path;
7220 } else {
7221 worktree = source_worktree;
7222 path = relativize_path(&result.worktree_abs_path, &abs_path);
7223 }
7224
7225 let worktree_id = worktree.read(cx).id();
7226 let project_path = ProjectPath {
7227 worktree_id,
7228 path: path.into(),
7229 };
7230 let signature = this.symbol_signature(&project_path);
7231 Some(CoreSymbol {
7232 source_language_server_id: result.server_id,
7233 language_server_name: result.lsp_adapter.name.clone(),
7234 source_worktree_id,
7235 path: project_path,
7236 kind: symbol_kind,
7237 name: symbol_name,
7238 range: range_from_lsp(symbol_location.range),
7239 signature,
7240 })
7241 })
7242 .collect()
7243 })?;
7244
7245 populate_labels_for_symbols(
7246 core_symbols,
7247 &language_registry,
7248 Some(result.lsp_adapter),
7249 &mut symbols,
7250 )
7251 .await;
7252 }
7253
7254 Ok(symbols)
7255 })
7256 } else {
7257 Task::ready(Err(anyhow!("No upstream client or local language server")))
7258 }
7259 }
7260
7261 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7262 let mut summary = DiagnosticSummary::default();
7263 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7264 summary.error_count += path_summary.error_count;
7265 summary.warning_count += path_summary.warning_count;
7266 }
7267 summary
7268 }
7269
7270 pub fn diagnostic_summaries<'a>(
7271 &'a self,
7272 include_ignored: bool,
7273 cx: &'a App,
7274 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7275 self.worktree_store
7276 .read(cx)
7277 .visible_worktrees(cx)
7278 .filter_map(|worktree| {
7279 let worktree = worktree.read(cx);
7280 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7281 })
7282 .flat_map(move |(worktree, summaries)| {
7283 let worktree_id = worktree.id();
7284 summaries
7285 .iter()
7286 .filter(move |(path, _)| {
7287 include_ignored
7288 || worktree
7289 .entry_for_path(path.as_ref())
7290 .is_some_and(|entry| !entry.is_ignored)
7291 })
7292 .flat_map(move |(path, summaries)| {
7293 summaries.iter().map(move |(server_id, summary)| {
7294 (
7295 ProjectPath {
7296 worktree_id,
7297 path: path.clone(),
7298 },
7299 *server_id,
7300 *summary,
7301 )
7302 })
7303 })
7304 })
7305 }
7306
7307 pub fn on_buffer_edited(
7308 &mut self,
7309 buffer: Entity<Buffer>,
7310 cx: &mut Context<Self>,
7311 ) -> Option<()> {
7312 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7313 Some(
7314 self.as_local()?
7315 .language_servers_for_buffer(buffer, cx)
7316 .map(|i| i.1.clone())
7317 .collect(),
7318 )
7319 })?;
7320
7321 let buffer = buffer.read(cx);
7322 let file = File::from_dyn(buffer.file())?;
7323 let abs_path = file.as_local()?.abs_path(cx);
7324 let uri = lsp::Url::from_file_path(abs_path).unwrap();
7325 let next_snapshot = buffer.text_snapshot();
7326 for language_server in language_servers {
7327 let language_server = language_server.clone();
7328
7329 let buffer_snapshots = self
7330 .as_local_mut()
7331 .unwrap()
7332 .buffer_snapshots
7333 .get_mut(&buffer.remote_id())
7334 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7335 let previous_snapshot = buffer_snapshots.last()?;
7336
7337 let build_incremental_change = || {
7338 buffer
7339 .edits_since::<Dimensions<PointUtf16, usize>>(
7340 previous_snapshot.snapshot.version(),
7341 )
7342 .map(|edit| {
7343 let edit_start = edit.new.start.0;
7344 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7345 let new_text = next_snapshot
7346 .text_for_range(edit.new.start.1..edit.new.end.1)
7347 .collect();
7348 lsp::TextDocumentContentChangeEvent {
7349 range: Some(lsp::Range::new(
7350 point_to_lsp(edit_start),
7351 point_to_lsp(edit_end),
7352 )),
7353 range_length: None,
7354 text: new_text,
7355 }
7356 })
7357 .collect()
7358 };
7359
7360 let document_sync_kind = language_server
7361 .capabilities()
7362 .text_document_sync
7363 .as_ref()
7364 .and_then(|sync| match sync {
7365 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7366 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7367 });
7368
7369 let content_changes: Vec<_> = match document_sync_kind {
7370 Some(lsp::TextDocumentSyncKind::FULL) => {
7371 vec![lsp::TextDocumentContentChangeEvent {
7372 range: None,
7373 range_length: None,
7374 text: next_snapshot.text(),
7375 }]
7376 }
7377 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7378 _ => {
7379 #[cfg(any(test, feature = "test-support"))]
7380 {
7381 build_incremental_change()
7382 }
7383
7384 #[cfg(not(any(test, feature = "test-support")))]
7385 {
7386 continue;
7387 }
7388 }
7389 };
7390
7391 let next_version = previous_snapshot.version + 1;
7392 buffer_snapshots.push(LspBufferSnapshot {
7393 version: next_version,
7394 snapshot: next_snapshot.clone(),
7395 });
7396
7397 language_server
7398 .notify::<lsp::notification::DidChangeTextDocument>(
7399 &lsp::DidChangeTextDocumentParams {
7400 text_document: lsp::VersionedTextDocumentIdentifier::new(
7401 uri.clone(),
7402 next_version,
7403 ),
7404 content_changes,
7405 },
7406 )
7407 .ok();
7408 self.pull_workspace_diagnostics(language_server.server_id());
7409 }
7410
7411 None
7412 }
7413
7414 pub fn on_buffer_saved(
7415 &mut self,
7416 buffer: Entity<Buffer>,
7417 cx: &mut Context<Self>,
7418 ) -> Option<()> {
7419 let file = File::from_dyn(buffer.read(cx).file())?;
7420 let worktree_id = file.worktree_id(cx);
7421 let abs_path = file.as_local()?.abs_path(cx);
7422 let text_document = lsp::TextDocumentIdentifier {
7423 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7424 };
7425 let local = self.as_local()?;
7426
7427 for server in local.language_servers_for_worktree(worktree_id) {
7428 if let Some(include_text) = include_text(server.as_ref()) {
7429 let text = if include_text {
7430 Some(buffer.read(cx).text())
7431 } else {
7432 None
7433 };
7434 server
7435 .notify::<lsp::notification::DidSaveTextDocument>(
7436 &lsp::DidSaveTextDocumentParams {
7437 text_document: text_document.clone(),
7438 text,
7439 },
7440 )
7441 .ok();
7442 }
7443 }
7444
7445 let language_servers = buffer.update(cx, |buffer, cx| {
7446 local.language_server_ids_for_buffer(buffer, cx)
7447 });
7448 for language_server_id in language_servers {
7449 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7450 }
7451
7452 None
7453 }
7454
7455 async fn refresh_workspace_configurations(
7456 lsp_store: &WeakEntity<Self>,
7457 fs: Arc<dyn Fs>,
7458 cx: &mut AsyncApp,
7459 ) {
7460 maybe!(async move {
7461 let mut refreshed_servers = HashSet::default();
7462 let servers = lsp_store
7463 .update(cx, |lsp_store, cx| {
7464 let local = lsp_store.as_local()?;
7465
7466 let servers = local
7467 .language_server_ids
7468 .iter()
7469 .filter_map(|(seed, state)| {
7470 let worktree = lsp_store
7471 .worktree_store
7472 .read(cx)
7473 .worktree_for_id(seed.worktree_id, cx);
7474 let delegate: Arc<dyn LspAdapterDelegate> =
7475 worktree.map(|worktree| {
7476 LocalLspAdapterDelegate::new(
7477 local.languages.clone(),
7478 &local.environment,
7479 cx.weak_entity(),
7480 &worktree,
7481 local.http_client.clone(),
7482 local.fs.clone(),
7483 cx,
7484 )
7485 })?;
7486 let server_id = state.id;
7487
7488 let states = local.language_servers.get(&server_id)?;
7489
7490 match states {
7491 LanguageServerState::Starting { .. } => None,
7492 LanguageServerState::Running {
7493 adapter, server, ..
7494 } => {
7495 let fs = fs.clone();
7496
7497 let adapter = adapter.clone();
7498 let server = server.clone();
7499 refreshed_servers.insert(server.name());
7500 let toolchain = seed.toolchain.clone();
7501 Some(cx.spawn(async move |_, cx| {
7502 let settings =
7503 LocalLspStore::workspace_configuration_for_adapter(
7504 adapter.adapter.clone(),
7505 fs.as_ref(),
7506 &delegate,
7507 toolchain,
7508 cx,
7509 )
7510 .await
7511 .ok()?;
7512 server
7513 .notify::<lsp::notification::DidChangeConfiguration>(
7514 &lsp::DidChangeConfigurationParams { settings },
7515 )
7516 .ok()?;
7517 Some(())
7518 }))
7519 }
7520 }
7521 })
7522 .collect::<Vec<_>>();
7523
7524 Some(servers)
7525 })
7526 .ok()
7527 .flatten()?;
7528
7529 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7530 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7531 // to stop and unregister its language server wrapper.
7532 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7533 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7534 let _: Vec<Option<()>> = join_all(servers).await;
7535
7536 Some(())
7537 })
7538 .await;
7539 }
7540
7541 fn maintain_workspace_config(
7542 fs: Arc<dyn Fs>,
7543 external_refresh_requests: watch::Receiver<()>,
7544 cx: &mut Context<Self>,
7545 ) -> Task<Result<()>> {
7546 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7547 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7548
7549 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7550 *settings_changed_tx.borrow_mut() = ();
7551 });
7552
7553 let mut joint_future =
7554 futures::stream::select(settings_changed_rx, external_refresh_requests);
7555 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7556 // - We might shut down a language server if it's no longer enabled for a given language (and there are no buffers using it otherwise).
7557 // - We might also shut it down when the workspace configuration of all of the users of a given language server converges onto that of the other.
7558 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7559 // - In the easiest case (where we're not wrangling the lifetime of a language server anyhow), if none of the roots of a single language server diverge in their configuration,
7560 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7561 cx.spawn(async move |this, cx| {
7562 while let Some(()) = joint_future.next().await {
7563 this.update(cx, |this, cx| {
7564 this.refresh_server_tree(cx);
7565 })
7566 .ok();
7567
7568 Self::refresh_workspace_configurations(&this, fs.clone(), cx).await;
7569 }
7570
7571 drop(settings_observation);
7572 anyhow::Ok(())
7573 })
7574 }
7575
7576 pub fn language_servers_for_local_buffer<'a>(
7577 &'a self,
7578 buffer: &Buffer,
7579 cx: &mut App,
7580 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7581 let local = self.as_local();
7582 let language_server_ids = local
7583 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7584 .unwrap_or_default();
7585
7586 language_server_ids
7587 .into_iter()
7588 .filter_map(
7589 move |server_id| match local?.language_servers.get(&server_id)? {
7590 LanguageServerState::Running {
7591 adapter, server, ..
7592 } => Some((adapter, server)),
7593 _ => None,
7594 },
7595 )
7596 }
7597
7598 pub fn language_server_for_local_buffer<'a>(
7599 &'a self,
7600 buffer: &'a Buffer,
7601 server_id: LanguageServerId,
7602 cx: &'a mut App,
7603 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7604 self.as_local()?
7605 .language_servers_for_buffer(buffer, cx)
7606 .find(|(_, s)| s.server_id() == server_id)
7607 }
7608
7609 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7610 self.diagnostic_summaries.remove(&id_to_remove);
7611 if let Some(local) = self.as_local_mut() {
7612 let to_remove = local.remove_worktree(id_to_remove, cx);
7613 for server in to_remove {
7614 self.language_server_statuses.remove(&server);
7615 }
7616 }
7617 }
7618
7619 pub fn shared(
7620 &mut self,
7621 project_id: u64,
7622 downstream_client: AnyProtoClient,
7623 _: &mut Context<Self>,
7624 ) {
7625 self.downstream_client = Some((downstream_client.clone(), project_id));
7626
7627 for (server_id, status) in &self.language_server_statuses {
7628 if let Some(server) = self.language_server_for_id(*server_id) {
7629 downstream_client
7630 .send(proto::StartLanguageServer {
7631 project_id,
7632 server: Some(proto::LanguageServer {
7633 id: server_id.to_proto(),
7634 name: status.name.to_string(),
7635 worktree_id: None,
7636 }),
7637 capabilities: serde_json::to_string(&server.capabilities())
7638 .expect("serializing server LSP capabilities"),
7639 })
7640 .log_err();
7641 }
7642 }
7643 }
7644
7645 pub fn disconnected_from_host(&mut self) {
7646 self.downstream_client.take();
7647 }
7648
7649 pub fn disconnected_from_ssh_remote(&mut self) {
7650 if let LspStoreMode::Remote(RemoteLspStore {
7651 upstream_client, ..
7652 }) = &mut self.mode
7653 {
7654 upstream_client.take();
7655 }
7656 }
7657
7658 pub(crate) fn set_language_server_statuses_from_proto(
7659 &mut self,
7660 language_servers: Vec<proto::LanguageServer>,
7661 server_capabilities: Vec<String>,
7662 ) {
7663 self.language_server_statuses = language_servers
7664 .into_iter()
7665 .zip(server_capabilities)
7666 .map(|(server, server_capabilities)| {
7667 let server_id = LanguageServerId(server.id as usize);
7668 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7669 self.lsp_server_capabilities
7670 .insert(server_id, server_capabilities);
7671 }
7672 (
7673 server_id,
7674 LanguageServerStatus {
7675 name: LanguageServerName::from_proto(server.name),
7676 pending_work: Default::default(),
7677 has_pending_diagnostic_updates: false,
7678 progress_tokens: Default::default(),
7679 },
7680 )
7681 })
7682 .collect();
7683 }
7684
7685 #[cfg(test)]
7686 pub fn update_diagnostic_entries(
7687 &mut self,
7688 server_id: LanguageServerId,
7689 abs_path: PathBuf,
7690 result_id: Option<String>,
7691 version: Option<i32>,
7692 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7693 cx: &mut Context<Self>,
7694 ) -> anyhow::Result<()> {
7695 self.merge_diagnostic_entries(
7696 vec![DocumentDiagnosticsUpdate {
7697 diagnostics: DocumentDiagnostics {
7698 diagnostics,
7699 document_abs_path: abs_path,
7700 version,
7701 },
7702 result_id,
7703 server_id,
7704 disk_based_sources: Cow::Borrowed(&[]),
7705 }],
7706 |_, _, _| false,
7707 cx,
7708 )?;
7709 Ok(())
7710 }
7711
7712 pub fn merge_diagnostic_entries<'a>(
7713 &mut self,
7714 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7715 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7716 cx: &mut Context<Self>,
7717 ) -> anyhow::Result<()> {
7718 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7719 let mut updated_diagnostics_paths = HashMap::default();
7720 for mut update in diagnostic_updates {
7721 let abs_path = &update.diagnostics.document_abs_path;
7722 let server_id = update.server_id;
7723 let Some((worktree, relative_path)) =
7724 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7725 else {
7726 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7727 return Ok(());
7728 };
7729
7730 let worktree_id = worktree.read(cx).id();
7731 let project_path = ProjectPath {
7732 worktree_id,
7733 path: relative_path.into(),
7734 };
7735
7736 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7737 let snapshot = buffer_handle.read(cx).snapshot();
7738 let buffer = buffer_handle.read(cx);
7739 let reused_diagnostics = buffer
7740 .get_diagnostics(server_id)
7741 .into_iter()
7742 .flat_map(|diag| {
7743 diag.iter()
7744 .filter(|v| merge(buffer, &v.diagnostic, cx))
7745 .map(|v| {
7746 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7747 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7748 DiagnosticEntry {
7749 range: start..end,
7750 diagnostic: v.diagnostic.clone(),
7751 }
7752 })
7753 })
7754 .collect::<Vec<_>>();
7755
7756 self.as_local_mut()
7757 .context("cannot merge diagnostics on a remote LspStore")?
7758 .update_buffer_diagnostics(
7759 &buffer_handle,
7760 server_id,
7761 update.result_id,
7762 update.diagnostics.version,
7763 update.diagnostics.diagnostics.clone(),
7764 reused_diagnostics.clone(),
7765 cx,
7766 )?;
7767
7768 update.diagnostics.diagnostics.extend(reused_diagnostics);
7769 }
7770
7771 let updated = worktree.update(cx, |worktree, cx| {
7772 self.update_worktree_diagnostics(
7773 worktree.id(),
7774 server_id,
7775 project_path.path.clone(),
7776 update.diagnostics.diagnostics,
7777 cx,
7778 )
7779 })?;
7780 match updated {
7781 ControlFlow::Continue(new_summary) => {
7782 if let Some((project_id, new_summary)) = new_summary {
7783 match &mut diagnostics_summary {
7784 Some(diagnostics_summary) => {
7785 diagnostics_summary
7786 .more_summaries
7787 .push(proto::DiagnosticSummary {
7788 path: project_path.path.as_ref().to_proto(),
7789 language_server_id: server_id.0 as u64,
7790 error_count: new_summary.error_count,
7791 warning_count: new_summary.warning_count,
7792 })
7793 }
7794 None => {
7795 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
7796 project_id,
7797 worktree_id: worktree_id.to_proto(),
7798 summary: Some(proto::DiagnosticSummary {
7799 path: project_path.path.as_ref().to_proto(),
7800 language_server_id: server_id.0 as u64,
7801 error_count: new_summary.error_count,
7802 warning_count: new_summary.warning_count,
7803 }),
7804 more_summaries: Vec::new(),
7805 })
7806 }
7807 }
7808 }
7809 updated_diagnostics_paths
7810 .entry(server_id)
7811 .or_insert_with(Vec::new)
7812 .push(project_path);
7813 }
7814 ControlFlow::Break(()) => {}
7815 }
7816 }
7817
7818 if let Some((diagnostics_summary, (downstream_client, _))) =
7819 diagnostics_summary.zip(self.downstream_client.as_ref())
7820 {
7821 downstream_client.send(diagnostics_summary).log_err();
7822 }
7823 for (server_id, paths) in updated_diagnostics_paths {
7824 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
7825 }
7826 Ok(())
7827 }
7828
7829 fn update_worktree_diagnostics(
7830 &mut self,
7831 worktree_id: WorktreeId,
7832 server_id: LanguageServerId,
7833 path_in_worktree: Arc<Path>,
7834 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7835 _: &mut Context<Worktree>,
7836 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
7837 let local = match &mut self.mode {
7838 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
7839 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
7840 };
7841
7842 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
7843 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
7844 let summaries_by_server_id = summaries_for_tree
7845 .entry(path_in_worktree.clone())
7846 .or_default();
7847
7848 let old_summary = summaries_by_server_id
7849 .remove(&server_id)
7850 .unwrap_or_default();
7851
7852 let new_summary = DiagnosticSummary::new(&diagnostics);
7853 if new_summary.is_empty() {
7854 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
7855 {
7856 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7857 diagnostics_by_server_id.remove(ix);
7858 }
7859 if diagnostics_by_server_id.is_empty() {
7860 diagnostics_for_tree.remove(&path_in_worktree);
7861 }
7862 }
7863 } else {
7864 summaries_by_server_id.insert(server_id, new_summary);
7865 let diagnostics_by_server_id = diagnostics_for_tree
7866 .entry(path_in_worktree.clone())
7867 .or_default();
7868 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7869 Ok(ix) => {
7870 diagnostics_by_server_id[ix] = (server_id, diagnostics);
7871 }
7872 Err(ix) => {
7873 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
7874 }
7875 }
7876 }
7877
7878 if !old_summary.is_empty() || !new_summary.is_empty() {
7879 if let Some((_, project_id)) = &self.downstream_client {
7880 Ok(ControlFlow::Continue(Some((
7881 *project_id,
7882 proto::DiagnosticSummary {
7883 path: path_in_worktree.to_proto(),
7884 language_server_id: server_id.0 as u64,
7885 error_count: new_summary.error_count as u32,
7886 warning_count: new_summary.warning_count as u32,
7887 },
7888 ))))
7889 } else {
7890 Ok(ControlFlow::Continue(None))
7891 }
7892 } else {
7893 Ok(ControlFlow::Break(()))
7894 }
7895 }
7896
7897 pub fn open_buffer_for_symbol(
7898 &mut self,
7899 symbol: &Symbol,
7900 cx: &mut Context<Self>,
7901 ) -> Task<Result<Entity<Buffer>>> {
7902 if let Some((client, project_id)) = self.upstream_client() {
7903 let request = client.request(proto::OpenBufferForSymbol {
7904 project_id,
7905 symbol: Some(Self::serialize_symbol(symbol)),
7906 });
7907 cx.spawn(async move |this, cx| {
7908 let response = request.await?;
7909 let buffer_id = BufferId::new(response.buffer_id)?;
7910 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
7911 .await
7912 })
7913 } else if let Some(local) = self.as_local() {
7914 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
7915 seed.worktree_id == symbol.source_worktree_id
7916 && state.id == symbol.source_language_server_id
7917 && symbol.language_server_name == seed.name
7918 });
7919 if !is_valid {
7920 return Task::ready(Err(anyhow!(
7921 "language server for worktree and language not found"
7922 )));
7923 };
7924
7925 let worktree_abs_path = if let Some(worktree_abs_path) = self
7926 .worktree_store
7927 .read(cx)
7928 .worktree_for_id(symbol.path.worktree_id, cx)
7929 .map(|worktree| worktree.read(cx).abs_path())
7930 {
7931 worktree_abs_path
7932 } else {
7933 return Task::ready(Err(anyhow!("worktree not found for symbol")));
7934 };
7935
7936 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
7937 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
7938 uri
7939 } else {
7940 return Task::ready(Err(anyhow!("invalid symbol path")));
7941 };
7942
7943 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
7944 } else {
7945 Task::ready(Err(anyhow!("no upstream client or local store")))
7946 }
7947 }
7948
7949 pub(crate) fn open_local_buffer_via_lsp(
7950 &mut self,
7951 mut abs_path: lsp::Url,
7952 language_server_id: LanguageServerId,
7953 cx: &mut Context<Self>,
7954 ) -> Task<Result<Entity<Buffer>>> {
7955 cx.spawn(async move |lsp_store, cx| {
7956 // Escape percent-encoded string.
7957 let current_scheme = abs_path.scheme().to_owned();
7958 let _ = abs_path.set_scheme("file");
7959
7960 let abs_path = abs_path
7961 .to_file_path()
7962 .map_err(|()| anyhow!("can't convert URI to path"))?;
7963 let p = abs_path.clone();
7964 let yarn_worktree = lsp_store
7965 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
7966 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
7967 cx.spawn(async move |this, cx| {
7968 let t = this
7969 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
7970 .ok()?;
7971 t.await
7972 })
7973 }),
7974 None => Task::ready(None),
7975 })?
7976 .await;
7977 let (worktree_root_target, known_relative_path) =
7978 if let Some((zip_root, relative_path)) = yarn_worktree {
7979 (zip_root, Some(relative_path))
7980 } else {
7981 (Arc::<Path>::from(abs_path.as_path()), None)
7982 };
7983 let (worktree, relative_path) = if let Some(result) =
7984 lsp_store.update(cx, |lsp_store, cx| {
7985 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7986 worktree_store.find_worktree(&worktree_root_target, cx)
7987 })
7988 })? {
7989 let relative_path =
7990 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
7991 (result.0, relative_path)
7992 } else {
7993 let worktree = lsp_store
7994 .update(cx, |lsp_store, cx| {
7995 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7996 worktree_store.create_worktree(&worktree_root_target, false, cx)
7997 })
7998 })?
7999 .await?;
8000 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8001 lsp_store
8002 .update(cx, |lsp_store, cx| {
8003 if let Some(local) = lsp_store.as_local_mut() {
8004 local.register_language_server_for_invisible_worktree(
8005 &worktree,
8006 language_server_id,
8007 cx,
8008 )
8009 }
8010 })
8011 .ok();
8012 }
8013 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8014 let relative_path = if let Some(known_path) = known_relative_path {
8015 known_path
8016 } else {
8017 abs_path.strip_prefix(worktree_root)?.into()
8018 };
8019 (worktree, relative_path)
8020 };
8021 let project_path = ProjectPath {
8022 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8023 path: relative_path,
8024 };
8025 lsp_store
8026 .update(cx, |lsp_store, cx| {
8027 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8028 buffer_store.open_buffer(project_path, cx)
8029 })
8030 })?
8031 .await
8032 })
8033 }
8034
8035 fn request_multiple_lsp_locally<P, R>(
8036 &mut self,
8037 buffer: &Entity<Buffer>,
8038 position: Option<P>,
8039 request: R,
8040 cx: &mut Context<Self>,
8041 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8042 where
8043 P: ToOffset,
8044 R: LspCommand + Clone,
8045 <R::LspRequest as lsp::request::Request>::Result: Send,
8046 <R::LspRequest as lsp::request::Request>::Params: Send,
8047 {
8048 let Some(local) = self.as_local() else {
8049 return Task::ready(Vec::new());
8050 };
8051
8052 let snapshot = buffer.read(cx).snapshot();
8053 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8054
8055 let server_ids = buffer.update(cx, |buffer, cx| {
8056 local
8057 .language_servers_for_buffer(buffer, cx)
8058 .filter(|(adapter, _)| {
8059 scope
8060 .as_ref()
8061 .map(|scope| scope.language_allowed(&adapter.name))
8062 .unwrap_or(true)
8063 })
8064 .map(|(_, server)| server.server_id())
8065 .filter(|server_id| {
8066 self.as_local().is_none_or(|local| {
8067 local
8068 .buffers_opened_in_servers
8069 .get(&snapshot.remote_id())
8070 .is_some_and(|servers| servers.contains(server_id))
8071 })
8072 })
8073 .collect::<Vec<_>>()
8074 });
8075
8076 let mut response_results = server_ids
8077 .into_iter()
8078 .map(|server_id| {
8079 let task = self.request_lsp(
8080 buffer.clone(),
8081 LanguageServerToQuery::Other(server_id),
8082 request.clone(),
8083 cx,
8084 );
8085 async move { (server_id, task.await) }
8086 })
8087 .collect::<FuturesUnordered<_>>();
8088
8089 cx.background_spawn(async move {
8090 let mut responses = Vec::with_capacity(response_results.len());
8091 while let Some((server_id, response_result)) = response_results.next().await {
8092 if let Some(response) = response_result.log_err() {
8093 responses.push((server_id, response));
8094 }
8095 }
8096 responses
8097 })
8098 }
8099
8100 async fn handle_lsp_command<T: LspCommand>(
8101 this: Entity<Self>,
8102 envelope: TypedEnvelope<T::ProtoRequest>,
8103 mut cx: AsyncApp,
8104 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8105 where
8106 <T::LspRequest as lsp::request::Request>::Params: Send,
8107 <T::LspRequest as lsp::request::Request>::Result: Send,
8108 {
8109 let sender_id = envelope.original_sender_id().unwrap_or_default();
8110 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8111 let buffer_handle = this.update(&mut cx, |this, cx| {
8112 this.buffer_store.read(cx).get_existing(buffer_id)
8113 })??;
8114 let request = T::from_proto(
8115 envelope.payload,
8116 this.clone(),
8117 buffer_handle.clone(),
8118 cx.clone(),
8119 )
8120 .await?;
8121 let response = this
8122 .update(&mut cx, |this, cx| {
8123 this.request_lsp(
8124 buffer_handle.clone(),
8125 LanguageServerToQuery::FirstCapable,
8126 request,
8127 cx,
8128 )
8129 })?
8130 .await?;
8131 this.update(&mut cx, |this, cx| {
8132 Ok(T::response_to_proto(
8133 response,
8134 this,
8135 sender_id,
8136 &buffer_handle.read(cx).version(),
8137 cx,
8138 ))
8139 })?
8140 }
8141
8142 async fn handle_multi_lsp_query(
8143 lsp_store: Entity<Self>,
8144 envelope: TypedEnvelope<proto::MultiLspQuery>,
8145 mut cx: AsyncApp,
8146 ) -> Result<proto::MultiLspQueryResponse> {
8147 let response_from_ssh = lsp_store.read_with(&cx, |this, _| {
8148 let (upstream_client, project_id) = this.upstream_client()?;
8149 let mut payload = envelope.payload.clone();
8150 payload.project_id = project_id;
8151
8152 Some(upstream_client.request(payload))
8153 })?;
8154 if let Some(response_from_ssh) = response_from_ssh {
8155 return response_from_ssh.await;
8156 }
8157
8158 let sender_id = envelope.original_sender_id().unwrap_or_default();
8159 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8160 let version = deserialize_version(&envelope.payload.version);
8161 let buffer = lsp_store.update(&mut cx, |this, cx| {
8162 this.buffer_store.read(cx).get_existing(buffer_id)
8163 })??;
8164 buffer
8165 .update(&mut cx, |buffer, _| {
8166 buffer.wait_for_version(version.clone())
8167 })?
8168 .await?;
8169 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
8170 match envelope
8171 .payload
8172 .strategy
8173 .context("invalid request without the strategy")?
8174 {
8175 proto::multi_lsp_query::Strategy::All(_) => {
8176 // currently, there's only one multiple language servers query strategy,
8177 // so just ensure it's specified correctly
8178 }
8179 }
8180 match envelope.payload.request {
8181 Some(proto::multi_lsp_query::Request::GetHover(message)) => {
8182 buffer
8183 .update(&mut cx, |buffer, _| {
8184 buffer.wait_for_version(deserialize_version(&message.version))
8185 })?
8186 .await?;
8187 let get_hover =
8188 GetHover::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8189 .await?;
8190 let all_hovers = lsp_store
8191 .update(&mut cx, |this, cx| {
8192 this.request_multiple_lsp_locally(
8193 &buffer,
8194 Some(get_hover.position),
8195 get_hover,
8196 cx,
8197 )
8198 })?
8199 .await
8200 .into_iter()
8201 .filter_map(|(server_id, hover)| {
8202 Some((server_id, remove_empty_hover_blocks(hover?)?))
8203 });
8204 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8205 responses: all_hovers
8206 .map(|(server_id, hover)| proto::LspResponse {
8207 server_id: server_id.to_proto(),
8208 response: Some(proto::lsp_response::Response::GetHoverResponse(
8209 GetHover::response_to_proto(
8210 Some(hover),
8211 project,
8212 sender_id,
8213 &buffer_version,
8214 cx,
8215 ),
8216 )),
8217 })
8218 .collect(),
8219 })
8220 }
8221 Some(proto::multi_lsp_query::Request::GetCodeActions(message)) => {
8222 buffer
8223 .update(&mut cx, |buffer, _| {
8224 buffer.wait_for_version(deserialize_version(&message.version))
8225 })?
8226 .await?;
8227 let get_code_actions = GetCodeActions::from_proto(
8228 message,
8229 lsp_store.clone(),
8230 buffer.clone(),
8231 cx.clone(),
8232 )
8233 .await?;
8234
8235 let all_actions = lsp_store
8236 .update(&mut cx, |project, cx| {
8237 project.request_multiple_lsp_locally(
8238 &buffer,
8239 Some(get_code_actions.range.start),
8240 get_code_actions,
8241 cx,
8242 )
8243 })?
8244 .await
8245 .into_iter();
8246
8247 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8248 responses: all_actions
8249 .map(|(server_id, code_actions)| proto::LspResponse {
8250 server_id: server_id.to_proto(),
8251 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
8252 GetCodeActions::response_to_proto(
8253 code_actions,
8254 project,
8255 sender_id,
8256 &buffer_version,
8257 cx,
8258 ),
8259 )),
8260 })
8261 .collect(),
8262 })
8263 }
8264 Some(proto::multi_lsp_query::Request::GetSignatureHelp(message)) => {
8265 buffer
8266 .update(&mut cx, |buffer, _| {
8267 buffer.wait_for_version(deserialize_version(&message.version))
8268 })?
8269 .await?;
8270 let get_signature_help = GetSignatureHelp::from_proto(
8271 message,
8272 lsp_store.clone(),
8273 buffer.clone(),
8274 cx.clone(),
8275 )
8276 .await?;
8277
8278 let all_signatures = lsp_store
8279 .update(&mut cx, |project, cx| {
8280 project.request_multiple_lsp_locally(
8281 &buffer,
8282 Some(get_signature_help.position),
8283 get_signature_help,
8284 cx,
8285 )
8286 })?
8287 .await
8288 .into_iter();
8289
8290 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8291 responses: all_signatures
8292 .map(|(server_id, signature_help)| proto::LspResponse {
8293 server_id: server_id.to_proto(),
8294 response: Some(
8295 proto::lsp_response::Response::GetSignatureHelpResponse(
8296 GetSignatureHelp::response_to_proto(
8297 signature_help,
8298 project,
8299 sender_id,
8300 &buffer_version,
8301 cx,
8302 ),
8303 ),
8304 ),
8305 })
8306 .collect(),
8307 })
8308 }
8309 Some(proto::multi_lsp_query::Request::GetCodeLens(message)) => {
8310 buffer
8311 .update(&mut cx, |buffer, _| {
8312 buffer.wait_for_version(deserialize_version(&message.version))
8313 })?
8314 .await?;
8315 let get_code_lens =
8316 GetCodeLens::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8317 .await?;
8318
8319 let code_lens_actions = lsp_store
8320 .update(&mut cx, |project, cx| {
8321 project.request_multiple_lsp_locally(
8322 &buffer,
8323 None::<usize>,
8324 get_code_lens,
8325 cx,
8326 )
8327 })?
8328 .await
8329 .into_iter();
8330
8331 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8332 responses: code_lens_actions
8333 .map(|(server_id, actions)| proto::LspResponse {
8334 server_id: server_id.to_proto(),
8335 response: Some(proto::lsp_response::Response::GetCodeLensResponse(
8336 GetCodeLens::response_to_proto(
8337 actions,
8338 project,
8339 sender_id,
8340 &buffer_version,
8341 cx,
8342 ),
8343 )),
8344 })
8345 .collect(),
8346 })
8347 }
8348 Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(message)) => {
8349 buffer
8350 .update(&mut cx, |buffer, _| {
8351 buffer.wait_for_version(deserialize_version(&message.version))
8352 })?
8353 .await?;
8354 lsp_store
8355 .update(&mut cx, |lsp_store, cx| {
8356 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8357 })?
8358 .await?;
8359 // `pull_diagnostics_for_buffer` will merge in the new diagnostics and send them to the client.
8360 // The client cannot merge anything into its non-local LspStore, so we do not need to return anything.
8361 Ok(proto::MultiLspQueryResponse {
8362 responses: Vec::new(),
8363 })
8364 }
8365 Some(proto::multi_lsp_query::Request::GetDocumentColor(message)) => {
8366 buffer
8367 .update(&mut cx, |buffer, _| {
8368 buffer.wait_for_version(deserialize_version(&message.version))
8369 })?
8370 .await?;
8371 let get_document_color = GetDocumentColor::from_proto(
8372 message,
8373 lsp_store.clone(),
8374 buffer.clone(),
8375 cx.clone(),
8376 )
8377 .await?;
8378
8379 let all_colors = lsp_store
8380 .update(&mut cx, |project, cx| {
8381 project.request_multiple_lsp_locally(
8382 &buffer,
8383 None::<usize>,
8384 get_document_color,
8385 cx,
8386 )
8387 })?
8388 .await
8389 .into_iter();
8390
8391 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8392 responses: all_colors
8393 .map(|(server_id, colors)| proto::LspResponse {
8394 server_id: server_id.to_proto(),
8395 response: Some(
8396 proto::lsp_response::Response::GetDocumentColorResponse(
8397 GetDocumentColor::response_to_proto(
8398 colors,
8399 project,
8400 sender_id,
8401 &buffer_version,
8402 cx,
8403 ),
8404 ),
8405 ),
8406 })
8407 .collect(),
8408 })
8409 }
8410 Some(proto::multi_lsp_query::Request::GetDefinition(message)) => {
8411 let get_definitions = GetDefinitions::from_proto(
8412 message,
8413 lsp_store.clone(),
8414 buffer.clone(),
8415 cx.clone(),
8416 )
8417 .await?;
8418
8419 let definitions = lsp_store
8420 .update(&mut cx, |project, cx| {
8421 project.request_multiple_lsp_locally(
8422 &buffer,
8423 Some(get_definitions.position),
8424 get_definitions,
8425 cx,
8426 )
8427 })?
8428 .await
8429 .into_iter();
8430
8431 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8432 responses: definitions
8433 .map(|(server_id, definitions)| proto::LspResponse {
8434 server_id: server_id.to_proto(),
8435 response: Some(proto::lsp_response::Response::GetDefinitionResponse(
8436 GetDefinitions::response_to_proto(
8437 definitions,
8438 project,
8439 sender_id,
8440 &buffer_version,
8441 cx,
8442 ),
8443 )),
8444 })
8445 .collect(),
8446 })
8447 }
8448 Some(proto::multi_lsp_query::Request::GetDeclaration(message)) => {
8449 let get_declarations = GetDeclarations::from_proto(
8450 message,
8451 lsp_store.clone(),
8452 buffer.clone(),
8453 cx.clone(),
8454 )
8455 .await?;
8456
8457 let declarations = lsp_store
8458 .update(&mut cx, |project, cx| {
8459 project.request_multiple_lsp_locally(
8460 &buffer,
8461 Some(get_declarations.position),
8462 get_declarations,
8463 cx,
8464 )
8465 })?
8466 .await
8467 .into_iter();
8468
8469 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8470 responses: declarations
8471 .map(|(server_id, declarations)| proto::LspResponse {
8472 server_id: server_id.to_proto(),
8473 response: Some(proto::lsp_response::Response::GetDeclarationResponse(
8474 GetDeclarations::response_to_proto(
8475 declarations,
8476 project,
8477 sender_id,
8478 &buffer_version,
8479 cx,
8480 ),
8481 )),
8482 })
8483 .collect(),
8484 })
8485 }
8486 Some(proto::multi_lsp_query::Request::GetTypeDefinition(message)) => {
8487 let get_type_definitions = GetTypeDefinitions::from_proto(
8488 message,
8489 lsp_store.clone(),
8490 buffer.clone(),
8491 cx.clone(),
8492 )
8493 .await?;
8494
8495 let type_definitions = lsp_store
8496 .update(&mut cx, |project, cx| {
8497 project.request_multiple_lsp_locally(
8498 &buffer,
8499 Some(get_type_definitions.position),
8500 get_type_definitions,
8501 cx,
8502 )
8503 })?
8504 .await
8505 .into_iter();
8506
8507 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8508 responses: type_definitions
8509 .map(|(server_id, type_definitions)| proto::LspResponse {
8510 server_id: server_id.to_proto(),
8511 response: Some(
8512 proto::lsp_response::Response::GetTypeDefinitionResponse(
8513 GetTypeDefinitions::response_to_proto(
8514 type_definitions,
8515 project,
8516 sender_id,
8517 &buffer_version,
8518 cx,
8519 ),
8520 ),
8521 ),
8522 })
8523 .collect(),
8524 })
8525 }
8526 Some(proto::multi_lsp_query::Request::GetImplementation(message)) => {
8527 let get_implementations = GetImplementations::from_proto(
8528 message,
8529 lsp_store.clone(),
8530 buffer.clone(),
8531 cx.clone(),
8532 )
8533 .await?;
8534
8535 let implementations = lsp_store
8536 .update(&mut cx, |project, cx| {
8537 project.request_multiple_lsp_locally(
8538 &buffer,
8539 Some(get_implementations.position),
8540 get_implementations,
8541 cx,
8542 )
8543 })?
8544 .await
8545 .into_iter();
8546
8547 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8548 responses: implementations
8549 .map(|(server_id, implementations)| proto::LspResponse {
8550 server_id: server_id.to_proto(),
8551 response: Some(
8552 proto::lsp_response::Response::GetImplementationResponse(
8553 GetImplementations::response_to_proto(
8554 implementations,
8555 project,
8556 sender_id,
8557 &buffer_version,
8558 cx,
8559 ),
8560 ),
8561 ),
8562 })
8563 .collect(),
8564 })
8565 }
8566 Some(proto::multi_lsp_query::Request::GetReferences(message)) => {
8567 let get_references = GetReferences::from_proto(
8568 message,
8569 lsp_store.clone(),
8570 buffer.clone(),
8571 cx.clone(),
8572 )
8573 .await?;
8574
8575 let references = lsp_store
8576 .update(&mut cx, |project, cx| {
8577 project.request_multiple_lsp_locally(
8578 &buffer,
8579 Some(get_references.position),
8580 get_references,
8581 cx,
8582 )
8583 })?
8584 .await
8585 .into_iter();
8586
8587 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8588 responses: references
8589 .map(|(server_id, references)| proto::LspResponse {
8590 server_id: server_id.to_proto(),
8591 response: Some(proto::lsp_response::Response::GetReferencesResponse(
8592 GetReferences::response_to_proto(
8593 references,
8594 project,
8595 sender_id,
8596 &buffer_version,
8597 cx,
8598 ),
8599 )),
8600 })
8601 .collect(),
8602 })
8603 }
8604 None => anyhow::bail!("empty multi lsp query request"),
8605 }
8606 }
8607
8608 async fn handle_apply_code_action(
8609 this: Entity<Self>,
8610 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8611 mut cx: AsyncApp,
8612 ) -> Result<proto::ApplyCodeActionResponse> {
8613 let sender_id = envelope.original_sender_id().unwrap_or_default();
8614 let action =
8615 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8616 let apply_code_action = this.update(&mut cx, |this, cx| {
8617 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8618 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8619 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8620 })??;
8621
8622 let project_transaction = apply_code_action.await?;
8623 let project_transaction = this.update(&mut cx, |this, cx| {
8624 this.buffer_store.update(cx, |buffer_store, cx| {
8625 buffer_store.serialize_project_transaction_for_peer(
8626 project_transaction,
8627 sender_id,
8628 cx,
8629 )
8630 })
8631 })?;
8632 Ok(proto::ApplyCodeActionResponse {
8633 transaction: Some(project_transaction),
8634 })
8635 }
8636
8637 async fn handle_register_buffer_with_language_servers(
8638 this: Entity<Self>,
8639 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8640 mut cx: AsyncApp,
8641 ) -> Result<proto::Ack> {
8642 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8643 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8644 this.update(&mut cx, |this, cx| {
8645 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8646 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8647 project_id: upstream_project_id,
8648 buffer_id: buffer_id.to_proto(),
8649 only_servers: envelope.payload.only_servers,
8650 });
8651 }
8652
8653 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8654 anyhow::bail!("buffer is not open");
8655 };
8656
8657 let handle = this.register_buffer_with_language_servers(
8658 &buffer,
8659 envelope
8660 .payload
8661 .only_servers
8662 .into_iter()
8663 .filter_map(|selector| {
8664 Some(match selector.selector? {
8665 proto::language_server_selector::Selector::ServerId(server_id) => {
8666 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8667 }
8668 proto::language_server_selector::Selector::Name(name) => {
8669 LanguageServerSelector::Name(LanguageServerName(
8670 SharedString::from(name),
8671 ))
8672 }
8673 })
8674 })
8675 .collect(),
8676 false,
8677 cx,
8678 );
8679 this.buffer_store().update(cx, |buffer_store, _| {
8680 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8681 });
8682
8683 Ok(())
8684 })??;
8685 Ok(proto::Ack {})
8686 }
8687
8688 async fn handle_rename_project_entry(
8689 this: Entity<Self>,
8690 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8691 mut cx: AsyncApp,
8692 ) -> Result<proto::ProjectEntryResponse> {
8693 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8694 let (worktree_id, worktree, old_path, is_dir) = this
8695 .update(&mut cx, |this, cx| {
8696 this.worktree_store
8697 .read(cx)
8698 .worktree_and_entry_for_id(entry_id, cx)
8699 .map(|(worktree, entry)| {
8700 (
8701 worktree.read(cx).id(),
8702 worktree,
8703 entry.path.clone(),
8704 entry.is_dir(),
8705 )
8706 })
8707 })?
8708 .context("worktree not found")?;
8709 let (old_abs_path, new_abs_path) = {
8710 let root_path = worktree.read_with(&cx, |this, _| this.abs_path())?;
8711 let new_path = PathBuf::from_proto(envelope.payload.new_path.clone());
8712 (root_path.join(&old_path), root_path.join(&new_path))
8713 };
8714
8715 Self::will_rename_entry(
8716 this.downgrade(),
8717 worktree_id,
8718 &old_abs_path,
8719 &new_abs_path,
8720 is_dir,
8721 cx.clone(),
8722 )
8723 .await;
8724 let response = Worktree::handle_rename_entry(worktree, envelope.payload, cx.clone()).await;
8725 this.read_with(&cx, |this, _| {
8726 this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
8727 })
8728 .ok();
8729 response
8730 }
8731
8732 async fn handle_update_diagnostic_summary(
8733 this: Entity<Self>,
8734 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8735 mut cx: AsyncApp,
8736 ) -> Result<()> {
8737 this.update(&mut cx, |lsp_store, cx| {
8738 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8739 let mut updated_diagnostics_paths = HashMap::default();
8740 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8741 for message_summary in envelope
8742 .payload
8743 .summary
8744 .into_iter()
8745 .chain(envelope.payload.more_summaries)
8746 {
8747 let project_path = ProjectPath {
8748 worktree_id,
8749 path: Arc::<Path>::from_proto(message_summary.path),
8750 };
8751 let path = project_path.path.clone();
8752 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8753 let summary = DiagnosticSummary {
8754 error_count: message_summary.error_count as usize,
8755 warning_count: message_summary.warning_count as usize,
8756 };
8757
8758 if summary.is_empty() {
8759 if let Some(worktree_summaries) =
8760 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8761 && let Some(summaries) = worktree_summaries.get_mut(&path)
8762 {
8763 summaries.remove(&server_id);
8764 if summaries.is_empty() {
8765 worktree_summaries.remove(&path);
8766 }
8767 }
8768 } else {
8769 lsp_store
8770 .diagnostic_summaries
8771 .entry(worktree_id)
8772 .or_default()
8773 .entry(path)
8774 .or_default()
8775 .insert(server_id, summary);
8776 }
8777
8778 if let Some((_, project_id)) = &lsp_store.downstream_client {
8779 match &mut diagnostics_summary {
8780 Some(diagnostics_summary) => {
8781 diagnostics_summary
8782 .more_summaries
8783 .push(proto::DiagnosticSummary {
8784 path: project_path.path.as_ref().to_proto(),
8785 language_server_id: server_id.0 as u64,
8786 error_count: summary.error_count as u32,
8787 warning_count: summary.warning_count as u32,
8788 })
8789 }
8790 None => {
8791 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8792 project_id: *project_id,
8793 worktree_id: worktree_id.to_proto(),
8794 summary: Some(proto::DiagnosticSummary {
8795 path: project_path.path.as_ref().to_proto(),
8796 language_server_id: server_id.0 as u64,
8797 error_count: summary.error_count as u32,
8798 warning_count: summary.warning_count as u32,
8799 }),
8800 more_summaries: Vec::new(),
8801 })
8802 }
8803 }
8804 }
8805 updated_diagnostics_paths
8806 .entry(server_id)
8807 .or_insert_with(Vec::new)
8808 .push(project_path);
8809 }
8810
8811 if let Some((diagnostics_summary, (downstream_client, _))) =
8812 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8813 {
8814 downstream_client.send(diagnostics_summary).log_err();
8815 }
8816 for (server_id, paths) in updated_diagnostics_paths {
8817 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8818 }
8819 Ok(())
8820 })?
8821 }
8822
8823 async fn handle_start_language_server(
8824 lsp_store: Entity<Self>,
8825 envelope: TypedEnvelope<proto::StartLanguageServer>,
8826 mut cx: AsyncApp,
8827 ) -> Result<()> {
8828 let server = envelope.payload.server.context("invalid server")?;
8829 let server_capabilities =
8830 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8831 .with_context(|| {
8832 format!(
8833 "incorrect server capabilities {}",
8834 envelope.payload.capabilities
8835 )
8836 })?;
8837 lsp_store.update(&mut cx, |lsp_store, cx| {
8838 let server_id = LanguageServerId(server.id as usize);
8839 let server_name = LanguageServerName::from_proto(server.name.clone());
8840 lsp_store
8841 .lsp_server_capabilities
8842 .insert(server_id, server_capabilities);
8843 lsp_store.language_server_statuses.insert(
8844 server_id,
8845 LanguageServerStatus {
8846 name: server_name.clone(),
8847 pending_work: Default::default(),
8848 has_pending_diagnostic_updates: false,
8849 progress_tokens: Default::default(),
8850 },
8851 );
8852 cx.emit(LspStoreEvent::LanguageServerAdded(
8853 server_id,
8854 server_name,
8855 server.worktree_id.map(WorktreeId::from_proto),
8856 ));
8857 cx.notify();
8858 })?;
8859 Ok(())
8860 }
8861
8862 async fn handle_update_language_server(
8863 lsp_store: Entity<Self>,
8864 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8865 mut cx: AsyncApp,
8866 ) -> Result<()> {
8867 lsp_store.update(&mut cx, |lsp_store, cx| {
8868 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8869
8870 match envelope.payload.variant.context("invalid variant")? {
8871 proto::update_language_server::Variant::WorkStart(payload) => {
8872 lsp_store.on_lsp_work_start(
8873 language_server_id,
8874 payload.token,
8875 LanguageServerProgress {
8876 title: payload.title,
8877 is_disk_based_diagnostics_progress: false,
8878 is_cancellable: payload.is_cancellable.unwrap_or(false),
8879 message: payload.message,
8880 percentage: payload.percentage.map(|p| p as usize),
8881 last_update_at: cx.background_executor().now(),
8882 },
8883 cx,
8884 );
8885 }
8886 proto::update_language_server::Variant::WorkProgress(payload) => {
8887 lsp_store.on_lsp_work_progress(
8888 language_server_id,
8889 payload.token,
8890 LanguageServerProgress {
8891 title: None,
8892 is_disk_based_diagnostics_progress: false,
8893 is_cancellable: payload.is_cancellable.unwrap_or(false),
8894 message: payload.message,
8895 percentage: payload.percentage.map(|p| p as usize),
8896 last_update_at: cx.background_executor().now(),
8897 },
8898 cx,
8899 );
8900 }
8901
8902 proto::update_language_server::Variant::WorkEnd(payload) => {
8903 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8904 }
8905
8906 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8907 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8908 }
8909
8910 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8911 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8912 }
8913
8914 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8915 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8916 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8917 cx.emit(LspStoreEvent::LanguageServerUpdate {
8918 language_server_id,
8919 name: envelope
8920 .payload
8921 .server_name
8922 .map(SharedString::new)
8923 .map(LanguageServerName),
8924 message: non_lsp,
8925 });
8926 }
8927 }
8928
8929 Ok(())
8930 })?
8931 }
8932
8933 async fn handle_language_server_log(
8934 this: Entity<Self>,
8935 envelope: TypedEnvelope<proto::LanguageServerLog>,
8936 mut cx: AsyncApp,
8937 ) -> Result<()> {
8938 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8939 let log_type = envelope
8940 .payload
8941 .log_type
8942 .map(LanguageServerLogType::from_proto)
8943 .context("invalid language server log type")?;
8944
8945 let message = envelope.payload.message;
8946
8947 this.update(&mut cx, |_, cx| {
8948 cx.emit(LspStoreEvent::LanguageServerLog(
8949 language_server_id,
8950 log_type,
8951 message,
8952 ));
8953 })
8954 }
8955
8956 async fn handle_lsp_ext_cancel_flycheck(
8957 lsp_store: Entity<Self>,
8958 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
8959 cx: AsyncApp,
8960 ) -> Result<proto::Ack> {
8961 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8962 lsp_store.read_with(&cx, |lsp_store, _| {
8963 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8964 server
8965 .notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(&())
8966 .context("handling lsp ext cancel flycheck")
8967 } else {
8968 anyhow::Ok(())
8969 }
8970 })??;
8971
8972 Ok(proto::Ack {})
8973 }
8974
8975 async fn handle_lsp_ext_run_flycheck(
8976 lsp_store: Entity<Self>,
8977 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
8978 mut cx: AsyncApp,
8979 ) -> Result<proto::Ack> {
8980 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8981 lsp_store.update(&mut cx, |lsp_store, cx| {
8982 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8983 let text_document = if envelope.payload.current_file_only {
8984 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8985 lsp_store
8986 .buffer_store()
8987 .read(cx)
8988 .get(buffer_id)
8989 .and_then(|buffer| Some(buffer.read(cx).file()?.as_local()?.abs_path(cx)))
8990 .map(|path| make_text_document_identifier(&path))
8991 .transpose()?
8992 } else {
8993 None
8994 };
8995 server
8996 .notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
8997 &lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
8998 )
8999 .context("handling lsp ext run flycheck")
9000 } else {
9001 anyhow::Ok(())
9002 }
9003 })??;
9004
9005 Ok(proto::Ack {})
9006 }
9007
9008 async fn handle_lsp_ext_clear_flycheck(
9009 lsp_store: Entity<Self>,
9010 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9011 cx: AsyncApp,
9012 ) -> Result<proto::Ack> {
9013 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9014 lsp_store.read_with(&cx, |lsp_store, _| {
9015 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9016 server
9017 .notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(&())
9018 .context("handling lsp ext clear flycheck")
9019 } else {
9020 anyhow::Ok(())
9021 }
9022 })??;
9023
9024 Ok(proto::Ack {})
9025 }
9026
9027 pub fn disk_based_diagnostics_started(
9028 &mut self,
9029 language_server_id: LanguageServerId,
9030 cx: &mut Context<Self>,
9031 ) {
9032 if let Some(language_server_status) =
9033 self.language_server_statuses.get_mut(&language_server_id)
9034 {
9035 language_server_status.has_pending_diagnostic_updates = true;
9036 }
9037
9038 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9039 cx.emit(LspStoreEvent::LanguageServerUpdate {
9040 language_server_id,
9041 name: self
9042 .language_server_adapter_for_id(language_server_id)
9043 .map(|adapter| adapter.name()),
9044 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9045 Default::default(),
9046 ),
9047 })
9048 }
9049
9050 pub fn disk_based_diagnostics_finished(
9051 &mut self,
9052 language_server_id: LanguageServerId,
9053 cx: &mut Context<Self>,
9054 ) {
9055 if let Some(language_server_status) =
9056 self.language_server_statuses.get_mut(&language_server_id)
9057 {
9058 language_server_status.has_pending_diagnostic_updates = false;
9059 }
9060
9061 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9062 cx.emit(LspStoreEvent::LanguageServerUpdate {
9063 language_server_id,
9064 name: self
9065 .language_server_adapter_for_id(language_server_id)
9066 .map(|adapter| adapter.name()),
9067 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9068 Default::default(),
9069 ),
9070 })
9071 }
9072
9073 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9074 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9075 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9076 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9077 // the language server might take some time to publish diagnostics.
9078 fn simulate_disk_based_diagnostics_events_if_needed(
9079 &mut self,
9080 language_server_id: LanguageServerId,
9081 cx: &mut Context<Self>,
9082 ) {
9083 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9084
9085 let Some(LanguageServerState::Running {
9086 simulate_disk_based_diagnostics_completion,
9087 adapter,
9088 ..
9089 }) = self
9090 .as_local_mut()
9091 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9092 else {
9093 return;
9094 };
9095
9096 if adapter.disk_based_diagnostics_progress_token.is_some() {
9097 return;
9098 }
9099
9100 let prev_task =
9101 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9102 cx.background_executor()
9103 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9104 .await;
9105
9106 this.update(cx, |this, cx| {
9107 this.disk_based_diagnostics_finished(language_server_id, cx);
9108
9109 if let Some(LanguageServerState::Running {
9110 simulate_disk_based_diagnostics_completion,
9111 ..
9112 }) = this.as_local_mut().and_then(|local_store| {
9113 local_store.language_servers.get_mut(&language_server_id)
9114 }) {
9115 *simulate_disk_based_diagnostics_completion = None;
9116 }
9117 })
9118 .ok();
9119 }));
9120
9121 if prev_task.is_none() {
9122 self.disk_based_diagnostics_started(language_server_id, cx);
9123 }
9124 }
9125
9126 pub fn language_server_statuses(
9127 &self,
9128 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9129 self.language_server_statuses
9130 .iter()
9131 .map(|(key, value)| (*key, value))
9132 }
9133
9134 pub(super) fn did_rename_entry(
9135 &self,
9136 worktree_id: WorktreeId,
9137 old_path: &Path,
9138 new_path: &Path,
9139 is_dir: bool,
9140 ) {
9141 maybe!({
9142 let local_store = self.as_local()?;
9143
9144 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from)?;
9145 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from)?;
9146
9147 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9148 let Some(filter) = local_store
9149 .language_server_paths_watched_for_rename
9150 .get(&language_server.server_id())
9151 else {
9152 continue;
9153 };
9154
9155 if filter.should_send_did_rename(&old_uri, is_dir) {
9156 language_server
9157 .notify::<DidRenameFiles>(&RenameFilesParams {
9158 files: vec![FileRename {
9159 old_uri: old_uri.clone(),
9160 new_uri: new_uri.clone(),
9161 }],
9162 })
9163 .ok();
9164 }
9165 }
9166 Some(())
9167 });
9168 }
9169
9170 pub(super) fn will_rename_entry(
9171 this: WeakEntity<Self>,
9172 worktree_id: WorktreeId,
9173 old_path: &Path,
9174 new_path: &Path,
9175 is_dir: bool,
9176 cx: AsyncApp,
9177 ) -> Task<()> {
9178 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from);
9179 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from);
9180 cx.spawn(async move |cx| {
9181 let mut tasks = vec![];
9182 this.update(cx, |this, cx| {
9183 let local_store = this.as_local()?;
9184 let old_uri = old_uri?;
9185 let new_uri = new_uri?;
9186 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9187 let Some(filter) = local_store
9188 .language_server_paths_watched_for_rename
9189 .get(&language_server.server_id())
9190 else {
9191 continue;
9192 };
9193
9194 if filter.should_send_will_rename(&old_uri, is_dir) {
9195 let apply_edit = cx.spawn({
9196 let old_uri = old_uri.clone();
9197 let new_uri = new_uri.clone();
9198 let language_server = language_server.clone();
9199 async move |this, cx| {
9200 let edit = language_server
9201 .request::<WillRenameFiles>(RenameFilesParams {
9202 files: vec![FileRename { old_uri, new_uri }],
9203 })
9204 .await
9205 .into_response()
9206 .context("will rename files")
9207 .log_err()
9208 .flatten()?;
9209
9210 LocalLspStore::deserialize_workspace_edit(
9211 this.upgrade()?,
9212 edit,
9213 false,
9214 language_server.clone(),
9215 cx,
9216 )
9217 .await
9218 .ok();
9219 Some(())
9220 }
9221 });
9222 tasks.push(apply_edit);
9223 }
9224 }
9225 Some(())
9226 })
9227 .ok()
9228 .flatten();
9229 for task in tasks {
9230 // Await on tasks sequentially so that the order of application of edits is deterministic
9231 // (at least with regards to the order of registration of language servers)
9232 task.await;
9233 }
9234 })
9235 }
9236
9237 fn lsp_notify_abs_paths_changed(
9238 &mut self,
9239 server_id: LanguageServerId,
9240 changes: Vec<PathEvent>,
9241 ) {
9242 maybe!({
9243 let server = self.language_server_for_id(server_id)?;
9244 let changes = changes
9245 .into_iter()
9246 .filter_map(|event| {
9247 let typ = match event.kind? {
9248 PathEventKind::Created => lsp::FileChangeType::CREATED,
9249 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9250 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9251 };
9252 Some(lsp::FileEvent {
9253 uri: file_path_to_lsp_url(&event.path).log_err()?,
9254 typ,
9255 })
9256 })
9257 .collect::<Vec<_>>();
9258 if !changes.is_empty() {
9259 server
9260 .notify::<lsp::notification::DidChangeWatchedFiles>(
9261 &lsp::DidChangeWatchedFilesParams { changes },
9262 )
9263 .ok();
9264 }
9265 Some(())
9266 });
9267 }
9268
9269 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9270 self.as_local()?.language_server_for_id(id)
9271 }
9272
9273 fn on_lsp_progress(
9274 &mut self,
9275 progress: lsp::ProgressParams,
9276 language_server_id: LanguageServerId,
9277 disk_based_diagnostics_progress_token: Option<String>,
9278 cx: &mut Context<Self>,
9279 ) {
9280 let token = match progress.token {
9281 lsp::NumberOrString::String(token) => token,
9282 lsp::NumberOrString::Number(token) => {
9283 log::info!("skipping numeric progress token {}", token);
9284 return;
9285 }
9286 };
9287
9288 match progress.value {
9289 lsp::ProgressParamsValue::WorkDone(progress) => {
9290 self.handle_work_done_progress(
9291 progress,
9292 language_server_id,
9293 disk_based_diagnostics_progress_token,
9294 token,
9295 cx,
9296 );
9297 }
9298 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9299 if let Some(LanguageServerState::Running {
9300 workspace_refresh_task: Some(workspace_refresh_task),
9301 ..
9302 }) = self
9303 .as_local_mut()
9304 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9305 {
9306 workspace_refresh_task.progress_tx.try_send(()).ok();
9307 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9308 }
9309 }
9310 }
9311 }
9312
9313 fn handle_work_done_progress(
9314 &mut self,
9315 progress: lsp::WorkDoneProgress,
9316 language_server_id: LanguageServerId,
9317 disk_based_diagnostics_progress_token: Option<String>,
9318 token: String,
9319 cx: &mut Context<Self>,
9320 ) {
9321 let language_server_status =
9322 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9323 status
9324 } else {
9325 return;
9326 };
9327
9328 if !language_server_status.progress_tokens.contains(&token) {
9329 return;
9330 }
9331
9332 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9333 .as_ref()
9334 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9335
9336 match progress {
9337 lsp::WorkDoneProgress::Begin(report) => {
9338 if is_disk_based_diagnostics_progress {
9339 self.disk_based_diagnostics_started(language_server_id, cx);
9340 }
9341 self.on_lsp_work_start(
9342 language_server_id,
9343 token.clone(),
9344 LanguageServerProgress {
9345 title: Some(report.title),
9346 is_disk_based_diagnostics_progress,
9347 is_cancellable: report.cancellable.unwrap_or(false),
9348 message: report.message.clone(),
9349 percentage: report.percentage.map(|p| p as usize),
9350 last_update_at: cx.background_executor().now(),
9351 },
9352 cx,
9353 );
9354 }
9355 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9356 language_server_id,
9357 token,
9358 LanguageServerProgress {
9359 title: None,
9360 is_disk_based_diagnostics_progress,
9361 is_cancellable: report.cancellable.unwrap_or(false),
9362 message: report.message,
9363 percentage: report.percentage.map(|p| p as usize),
9364 last_update_at: cx.background_executor().now(),
9365 },
9366 cx,
9367 ),
9368 lsp::WorkDoneProgress::End(_) => {
9369 language_server_status.progress_tokens.remove(&token);
9370 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9371 if is_disk_based_diagnostics_progress {
9372 self.disk_based_diagnostics_finished(language_server_id, cx);
9373 }
9374 }
9375 }
9376 }
9377
9378 fn on_lsp_work_start(
9379 &mut self,
9380 language_server_id: LanguageServerId,
9381 token: String,
9382 progress: LanguageServerProgress,
9383 cx: &mut Context<Self>,
9384 ) {
9385 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9386 status.pending_work.insert(token.clone(), progress.clone());
9387 cx.notify();
9388 }
9389 cx.emit(LspStoreEvent::LanguageServerUpdate {
9390 language_server_id,
9391 name: self
9392 .language_server_adapter_for_id(language_server_id)
9393 .map(|adapter| adapter.name()),
9394 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9395 token,
9396 title: progress.title,
9397 message: progress.message,
9398 percentage: progress.percentage.map(|p| p as u32),
9399 is_cancellable: Some(progress.is_cancellable),
9400 }),
9401 })
9402 }
9403
9404 fn on_lsp_work_progress(
9405 &mut self,
9406 language_server_id: LanguageServerId,
9407 token: String,
9408 progress: LanguageServerProgress,
9409 cx: &mut Context<Self>,
9410 ) {
9411 let mut did_update = false;
9412 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9413 match status.pending_work.entry(token.clone()) {
9414 btree_map::Entry::Vacant(entry) => {
9415 entry.insert(progress.clone());
9416 did_update = true;
9417 }
9418 btree_map::Entry::Occupied(mut entry) => {
9419 let entry = entry.get_mut();
9420 if (progress.last_update_at - entry.last_update_at)
9421 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9422 {
9423 entry.last_update_at = progress.last_update_at;
9424 if progress.message.is_some() {
9425 entry.message = progress.message.clone();
9426 }
9427 if progress.percentage.is_some() {
9428 entry.percentage = progress.percentage;
9429 }
9430 if progress.is_cancellable != entry.is_cancellable {
9431 entry.is_cancellable = progress.is_cancellable;
9432 }
9433 did_update = true;
9434 }
9435 }
9436 }
9437 }
9438
9439 if did_update {
9440 cx.emit(LspStoreEvent::LanguageServerUpdate {
9441 language_server_id,
9442 name: self
9443 .language_server_adapter_for_id(language_server_id)
9444 .map(|adapter| adapter.name()),
9445 message: proto::update_language_server::Variant::WorkProgress(
9446 proto::LspWorkProgress {
9447 token,
9448 message: progress.message,
9449 percentage: progress.percentage.map(|p| p as u32),
9450 is_cancellable: Some(progress.is_cancellable),
9451 },
9452 ),
9453 })
9454 }
9455 }
9456
9457 fn on_lsp_work_end(
9458 &mut self,
9459 language_server_id: LanguageServerId,
9460 token: String,
9461 cx: &mut Context<Self>,
9462 ) {
9463 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9464 if let Some(work) = status.pending_work.remove(&token)
9465 && !work.is_disk_based_diagnostics_progress
9466 {
9467 cx.emit(LspStoreEvent::RefreshInlayHints);
9468 }
9469 cx.notify();
9470 }
9471
9472 cx.emit(LspStoreEvent::LanguageServerUpdate {
9473 language_server_id,
9474 name: self
9475 .language_server_adapter_for_id(language_server_id)
9476 .map(|adapter| adapter.name()),
9477 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9478 })
9479 }
9480
9481 pub async fn handle_resolve_completion_documentation(
9482 this: Entity<Self>,
9483 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9484 mut cx: AsyncApp,
9485 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9486 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9487
9488 let completion = this
9489 .read_with(&cx, |this, cx| {
9490 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9491 let server = this
9492 .language_server_for_id(id)
9493 .with_context(|| format!("No language server {id}"))?;
9494
9495 anyhow::Ok(cx.background_spawn(async move {
9496 let can_resolve = server
9497 .capabilities()
9498 .completion_provider
9499 .as_ref()
9500 .and_then(|options| options.resolve_provider)
9501 .unwrap_or(false);
9502 if can_resolve {
9503 server
9504 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9505 .await
9506 .into_response()
9507 .context("resolve completion item")
9508 } else {
9509 anyhow::Ok(lsp_completion)
9510 }
9511 }))
9512 })??
9513 .await?;
9514
9515 let mut documentation_is_markdown = false;
9516 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9517 let documentation = match completion.documentation {
9518 Some(lsp::Documentation::String(text)) => text,
9519
9520 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9521 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9522 value
9523 }
9524
9525 _ => String::new(),
9526 };
9527
9528 // If we have a new buffer_id, that means we're talking to a new client
9529 // and want to check for new text_edits in the completion too.
9530 let mut old_replace_start = None;
9531 let mut old_replace_end = None;
9532 let mut old_insert_start = None;
9533 let mut old_insert_end = None;
9534 let mut new_text = String::default();
9535 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9536 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9537 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9538 anyhow::Ok(buffer.read(cx).snapshot())
9539 })??;
9540
9541 if let Some(text_edit) = completion.text_edit.as_ref() {
9542 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9543
9544 if let Some(mut edit) = edit {
9545 LineEnding::normalize(&mut edit.new_text);
9546
9547 new_text = edit.new_text;
9548 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9549 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9550 if let Some(insert_range) = edit.insert_range {
9551 old_insert_start = Some(serialize_anchor(&insert_range.start));
9552 old_insert_end = Some(serialize_anchor(&insert_range.end));
9553 }
9554 }
9555 }
9556 }
9557
9558 Ok(proto::ResolveCompletionDocumentationResponse {
9559 documentation,
9560 documentation_is_markdown,
9561 old_replace_start,
9562 old_replace_end,
9563 new_text,
9564 lsp_completion,
9565 old_insert_start,
9566 old_insert_end,
9567 })
9568 }
9569
9570 async fn handle_on_type_formatting(
9571 this: Entity<Self>,
9572 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9573 mut cx: AsyncApp,
9574 ) -> Result<proto::OnTypeFormattingResponse> {
9575 let on_type_formatting = this.update(&mut cx, |this, cx| {
9576 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9577 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9578 let position = envelope
9579 .payload
9580 .position
9581 .and_then(deserialize_anchor)
9582 .context("invalid position")?;
9583 anyhow::Ok(this.apply_on_type_formatting(
9584 buffer,
9585 position,
9586 envelope.payload.trigger.clone(),
9587 cx,
9588 ))
9589 })??;
9590
9591 let transaction = on_type_formatting
9592 .await?
9593 .as_ref()
9594 .map(language::proto::serialize_transaction);
9595 Ok(proto::OnTypeFormattingResponse { transaction })
9596 }
9597
9598 async fn handle_refresh_inlay_hints(
9599 this: Entity<Self>,
9600 _: TypedEnvelope<proto::RefreshInlayHints>,
9601 mut cx: AsyncApp,
9602 ) -> Result<proto::Ack> {
9603 this.update(&mut cx, |_, cx| {
9604 cx.emit(LspStoreEvent::RefreshInlayHints);
9605 })?;
9606 Ok(proto::Ack {})
9607 }
9608
9609 async fn handle_pull_workspace_diagnostics(
9610 lsp_store: Entity<Self>,
9611 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9612 mut cx: AsyncApp,
9613 ) -> Result<proto::Ack> {
9614 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9615 lsp_store.update(&mut cx, |lsp_store, _| {
9616 lsp_store.pull_workspace_diagnostics(server_id);
9617 })?;
9618 Ok(proto::Ack {})
9619 }
9620
9621 async fn handle_inlay_hints(
9622 this: Entity<Self>,
9623 envelope: TypedEnvelope<proto::InlayHints>,
9624 mut cx: AsyncApp,
9625 ) -> Result<proto::InlayHintsResponse> {
9626 let sender_id = envelope.original_sender_id().unwrap_or_default();
9627 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9628 let buffer = this.update(&mut cx, |this, cx| {
9629 this.buffer_store.read(cx).get_existing(buffer_id)
9630 })??;
9631 buffer
9632 .update(&mut cx, |buffer, _| {
9633 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
9634 })?
9635 .await
9636 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
9637
9638 let start = envelope
9639 .payload
9640 .start
9641 .and_then(deserialize_anchor)
9642 .context("missing range start")?;
9643 let end = envelope
9644 .payload
9645 .end
9646 .and_then(deserialize_anchor)
9647 .context("missing range end")?;
9648 let buffer_hints = this
9649 .update(&mut cx, |lsp_store, cx| {
9650 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
9651 })?
9652 .await
9653 .context("inlay hints fetch")?;
9654
9655 this.update(&mut cx, |project, cx| {
9656 InlayHints::response_to_proto(
9657 buffer_hints,
9658 project,
9659 sender_id,
9660 &buffer.read(cx).version(),
9661 cx,
9662 )
9663 })
9664 }
9665
9666 async fn handle_get_color_presentation(
9667 lsp_store: Entity<Self>,
9668 envelope: TypedEnvelope<proto::GetColorPresentation>,
9669 mut cx: AsyncApp,
9670 ) -> Result<proto::GetColorPresentationResponse> {
9671 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9672 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9673 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9674 })??;
9675
9676 let color = envelope
9677 .payload
9678 .color
9679 .context("invalid color resolve request")?;
9680 let start = color
9681 .lsp_range_start
9682 .context("invalid color resolve request")?;
9683 let end = color
9684 .lsp_range_end
9685 .context("invalid color resolve request")?;
9686
9687 let color = DocumentColor {
9688 lsp_range: lsp::Range {
9689 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9690 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9691 },
9692 color: lsp::Color {
9693 red: color.red,
9694 green: color.green,
9695 blue: color.blue,
9696 alpha: color.alpha,
9697 },
9698 resolved: false,
9699 color_presentations: Vec::new(),
9700 };
9701 let resolved_color = lsp_store
9702 .update(&mut cx, |lsp_store, cx| {
9703 lsp_store.resolve_color_presentation(
9704 color,
9705 buffer.clone(),
9706 LanguageServerId(envelope.payload.server_id as usize),
9707 cx,
9708 )
9709 })?
9710 .await
9711 .context("resolving color presentation")?;
9712
9713 Ok(proto::GetColorPresentationResponse {
9714 presentations: resolved_color
9715 .color_presentations
9716 .into_iter()
9717 .map(|presentation| proto::ColorPresentation {
9718 label: presentation.label.to_string(),
9719 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9720 additional_text_edits: presentation
9721 .additional_text_edits
9722 .into_iter()
9723 .map(serialize_lsp_edit)
9724 .collect(),
9725 })
9726 .collect(),
9727 })
9728 }
9729
9730 async fn handle_resolve_inlay_hint(
9731 this: Entity<Self>,
9732 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9733 mut cx: AsyncApp,
9734 ) -> Result<proto::ResolveInlayHintResponse> {
9735 let proto_hint = envelope
9736 .payload
9737 .hint
9738 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9739 let hint = InlayHints::proto_to_project_hint(proto_hint)
9740 .context("resolved proto inlay hint conversion")?;
9741 let buffer = this.update(&mut cx, |this, cx| {
9742 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9743 this.buffer_store.read(cx).get_existing(buffer_id)
9744 })??;
9745 let response_hint = this
9746 .update(&mut cx, |this, cx| {
9747 this.resolve_inlay_hint(
9748 hint,
9749 buffer,
9750 LanguageServerId(envelope.payload.language_server_id as usize),
9751 cx,
9752 )
9753 })?
9754 .await
9755 .context("inlay hints fetch")?;
9756 Ok(proto::ResolveInlayHintResponse {
9757 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9758 })
9759 }
9760
9761 async fn handle_refresh_code_lens(
9762 this: Entity<Self>,
9763 _: TypedEnvelope<proto::RefreshCodeLens>,
9764 mut cx: AsyncApp,
9765 ) -> Result<proto::Ack> {
9766 this.update(&mut cx, |_, cx| {
9767 cx.emit(LspStoreEvent::RefreshCodeLens);
9768 })?;
9769 Ok(proto::Ack {})
9770 }
9771
9772 async fn handle_open_buffer_for_symbol(
9773 this: Entity<Self>,
9774 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9775 mut cx: AsyncApp,
9776 ) -> Result<proto::OpenBufferForSymbolResponse> {
9777 let peer_id = envelope.original_sender_id().unwrap_or_default();
9778 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9779 let symbol = Self::deserialize_symbol(symbol)?;
9780 let symbol = this.read_with(&cx, |this, _| {
9781 let signature = this.symbol_signature(&symbol.path);
9782 anyhow::ensure!(signature == symbol.signature, "invalid symbol signature");
9783 Ok(symbol)
9784 })??;
9785 let buffer = this
9786 .update(&mut cx, |this, cx| {
9787 this.open_buffer_for_symbol(
9788 &Symbol {
9789 language_server_name: symbol.language_server_name,
9790 source_worktree_id: symbol.source_worktree_id,
9791 source_language_server_id: symbol.source_language_server_id,
9792 path: symbol.path,
9793 name: symbol.name,
9794 kind: symbol.kind,
9795 range: symbol.range,
9796 signature: symbol.signature,
9797 label: CodeLabel {
9798 text: Default::default(),
9799 runs: Default::default(),
9800 filter_range: Default::default(),
9801 },
9802 },
9803 cx,
9804 )
9805 })?
9806 .await?;
9807
9808 this.update(&mut cx, |this, cx| {
9809 let is_private = buffer
9810 .read(cx)
9811 .file()
9812 .map(|f| f.is_private())
9813 .unwrap_or_default();
9814 if is_private {
9815 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9816 } else {
9817 this.buffer_store
9818 .update(cx, |buffer_store, cx| {
9819 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9820 })
9821 .detach_and_log_err(cx);
9822 let buffer_id = buffer.read(cx).remote_id().to_proto();
9823 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9824 }
9825 })?
9826 }
9827
9828 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
9829 let mut hasher = Sha256::new();
9830 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
9831 hasher.update(project_path.path.to_string_lossy().as_bytes());
9832 hasher.update(self.nonce.to_be_bytes());
9833 hasher.finalize().as_slice().try_into().unwrap()
9834 }
9835
9836 pub async fn handle_get_project_symbols(
9837 this: Entity<Self>,
9838 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9839 mut cx: AsyncApp,
9840 ) -> Result<proto::GetProjectSymbolsResponse> {
9841 let symbols = this
9842 .update(&mut cx, |this, cx| {
9843 this.symbols(&envelope.payload.query, cx)
9844 })?
9845 .await?;
9846
9847 Ok(proto::GetProjectSymbolsResponse {
9848 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9849 })
9850 }
9851
9852 pub async fn handle_restart_language_servers(
9853 this: Entity<Self>,
9854 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9855 mut cx: AsyncApp,
9856 ) -> Result<proto::Ack> {
9857 this.update(&mut cx, |lsp_store, cx| {
9858 let buffers =
9859 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9860 lsp_store.restart_language_servers_for_buffers(
9861 buffers,
9862 envelope
9863 .payload
9864 .only_servers
9865 .into_iter()
9866 .filter_map(|selector| {
9867 Some(match selector.selector? {
9868 proto::language_server_selector::Selector::ServerId(server_id) => {
9869 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9870 }
9871 proto::language_server_selector::Selector::Name(name) => {
9872 LanguageServerSelector::Name(LanguageServerName(
9873 SharedString::from(name),
9874 ))
9875 }
9876 })
9877 })
9878 .collect(),
9879 cx,
9880 );
9881 })?;
9882
9883 Ok(proto::Ack {})
9884 }
9885
9886 pub async fn handle_stop_language_servers(
9887 lsp_store: Entity<Self>,
9888 envelope: TypedEnvelope<proto::StopLanguageServers>,
9889 mut cx: AsyncApp,
9890 ) -> Result<proto::Ack> {
9891 lsp_store.update(&mut cx, |lsp_store, cx| {
9892 if envelope.payload.all
9893 && envelope.payload.also_servers.is_empty()
9894 && envelope.payload.buffer_ids.is_empty()
9895 {
9896 lsp_store.stop_all_language_servers(cx);
9897 } else {
9898 let buffers =
9899 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9900 lsp_store
9901 .stop_language_servers_for_buffers(
9902 buffers,
9903 envelope
9904 .payload
9905 .also_servers
9906 .into_iter()
9907 .filter_map(|selector| {
9908 Some(match selector.selector? {
9909 proto::language_server_selector::Selector::ServerId(
9910 server_id,
9911 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9912 server_id,
9913 )),
9914 proto::language_server_selector::Selector::Name(name) => {
9915 LanguageServerSelector::Name(LanguageServerName(
9916 SharedString::from(name),
9917 ))
9918 }
9919 })
9920 })
9921 .collect(),
9922 cx,
9923 )
9924 .detach_and_log_err(cx);
9925 }
9926 })?;
9927
9928 Ok(proto::Ack {})
9929 }
9930
9931 pub async fn handle_cancel_language_server_work(
9932 this: Entity<Self>,
9933 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9934 mut cx: AsyncApp,
9935 ) -> Result<proto::Ack> {
9936 this.update(&mut cx, |this, cx| {
9937 if let Some(work) = envelope.payload.work {
9938 match work {
9939 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9940 let buffers =
9941 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9942 this.cancel_language_server_work_for_buffers(buffers, cx);
9943 }
9944 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9945 let server_id = LanguageServerId::from_proto(work.language_server_id);
9946 this.cancel_language_server_work(server_id, work.token, cx);
9947 }
9948 }
9949 }
9950 })?;
9951
9952 Ok(proto::Ack {})
9953 }
9954
9955 fn buffer_ids_to_buffers(
9956 &mut self,
9957 buffer_ids: impl Iterator<Item = u64>,
9958 cx: &mut Context<Self>,
9959 ) -> Vec<Entity<Buffer>> {
9960 buffer_ids
9961 .into_iter()
9962 .flat_map(|buffer_id| {
9963 self.buffer_store
9964 .read(cx)
9965 .get(BufferId::new(buffer_id).log_err()?)
9966 })
9967 .collect::<Vec<_>>()
9968 }
9969
9970 async fn handle_apply_additional_edits_for_completion(
9971 this: Entity<Self>,
9972 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
9973 mut cx: AsyncApp,
9974 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
9975 let (buffer, completion) = this.update(&mut cx, |this, cx| {
9976 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9977 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9978 let completion = Self::deserialize_completion(
9979 envelope.payload.completion.context("invalid completion")?,
9980 )?;
9981 anyhow::Ok((buffer, completion))
9982 })??;
9983
9984 let apply_additional_edits = this.update(&mut cx, |this, cx| {
9985 this.apply_additional_edits_for_completion(
9986 buffer,
9987 Rc::new(RefCell::new(Box::new([Completion {
9988 replace_range: completion.replace_range,
9989 new_text: completion.new_text,
9990 source: completion.source,
9991 documentation: None,
9992 label: CodeLabel {
9993 text: Default::default(),
9994 runs: Default::default(),
9995 filter_range: Default::default(),
9996 },
9997 insert_text_mode: None,
9998 icon_path: None,
9999 confirm: None,
10000 }]))),
10001 0,
10002 false,
10003 cx,
10004 )
10005 })?;
10006
10007 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10008 transaction: apply_additional_edits
10009 .await?
10010 .as_ref()
10011 .map(language::proto::serialize_transaction),
10012 })
10013 }
10014
10015 pub fn last_formatting_failure(&self) -> Option<&str> {
10016 self.last_formatting_failure.as_deref()
10017 }
10018
10019 pub fn reset_last_formatting_failure(&mut self) {
10020 self.last_formatting_failure = None;
10021 }
10022
10023 pub fn environment_for_buffer(
10024 &self,
10025 buffer: &Entity<Buffer>,
10026 cx: &mut Context<Self>,
10027 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10028 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10029 environment.update(cx, |env, cx| {
10030 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10031 })
10032 } else {
10033 Task::ready(None).shared()
10034 }
10035 }
10036
10037 pub fn format(
10038 &mut self,
10039 buffers: HashSet<Entity<Buffer>>,
10040 target: LspFormatTarget,
10041 push_to_history: bool,
10042 trigger: FormatTrigger,
10043 cx: &mut Context<Self>,
10044 ) -> Task<anyhow::Result<ProjectTransaction>> {
10045 let logger = zlog::scoped!("format");
10046 if self.as_local().is_some() {
10047 zlog::trace!(logger => "Formatting locally");
10048 let logger = zlog::scoped!(logger => "local");
10049 let buffers = buffers
10050 .into_iter()
10051 .map(|buffer_handle| {
10052 let buffer = buffer_handle.read(cx);
10053 let buffer_abs_path = File::from_dyn(buffer.file())
10054 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10055
10056 (buffer_handle, buffer_abs_path, buffer.remote_id())
10057 })
10058 .collect::<Vec<_>>();
10059
10060 cx.spawn(async move |lsp_store, cx| {
10061 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10062
10063 for (handle, abs_path, id) in buffers {
10064 let env = lsp_store
10065 .update(cx, |lsp_store, cx| {
10066 lsp_store.environment_for_buffer(&handle, cx)
10067 })?
10068 .await;
10069
10070 let ranges = match &target {
10071 LspFormatTarget::Buffers => None,
10072 LspFormatTarget::Ranges(ranges) => {
10073 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10074 }
10075 };
10076
10077 formattable_buffers.push(FormattableBuffer {
10078 handle,
10079 abs_path,
10080 env,
10081 ranges,
10082 });
10083 }
10084 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10085
10086 let format_timer = zlog::time!(logger => "Formatting buffers");
10087 let result = LocalLspStore::format_locally(
10088 lsp_store.clone(),
10089 formattable_buffers,
10090 push_to_history,
10091 trigger,
10092 logger,
10093 cx,
10094 )
10095 .await;
10096 format_timer.end();
10097
10098 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10099
10100 lsp_store.update(cx, |lsp_store, _| {
10101 lsp_store.update_last_formatting_failure(&result);
10102 })?;
10103
10104 result
10105 })
10106 } else if let Some((client, project_id)) = self.upstream_client() {
10107 zlog::trace!(logger => "Formatting remotely");
10108 let logger = zlog::scoped!(logger => "remote");
10109 // Don't support formatting ranges via remote
10110 match target {
10111 LspFormatTarget::Buffers => {}
10112 LspFormatTarget::Ranges(_) => {
10113 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10114 return Task::ready(Ok(ProjectTransaction::default()));
10115 }
10116 }
10117
10118 let buffer_store = self.buffer_store();
10119 cx.spawn(async move |lsp_store, cx| {
10120 zlog::trace!(logger => "Sending remote format request");
10121 let request_timer = zlog::time!(logger => "remote format request");
10122 let result = client
10123 .request(proto::FormatBuffers {
10124 project_id,
10125 trigger: trigger as i32,
10126 buffer_ids: buffers
10127 .iter()
10128 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10129 .collect::<Result<_>>()?,
10130 })
10131 .await
10132 .and_then(|result| result.transaction.context("missing transaction"));
10133 request_timer.end();
10134
10135 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10136
10137 lsp_store.update(cx, |lsp_store, _| {
10138 lsp_store.update_last_formatting_failure(&result);
10139 })?;
10140
10141 let transaction_response = result?;
10142 let _timer = zlog::time!(logger => "deserializing project transaction");
10143 buffer_store
10144 .update(cx, |buffer_store, cx| {
10145 buffer_store.deserialize_project_transaction(
10146 transaction_response,
10147 push_to_history,
10148 cx,
10149 )
10150 })?
10151 .await
10152 })
10153 } else {
10154 zlog::trace!(logger => "Not formatting");
10155 Task::ready(Ok(ProjectTransaction::default()))
10156 }
10157 }
10158
10159 async fn handle_format_buffers(
10160 this: Entity<Self>,
10161 envelope: TypedEnvelope<proto::FormatBuffers>,
10162 mut cx: AsyncApp,
10163 ) -> Result<proto::FormatBuffersResponse> {
10164 let sender_id = envelope.original_sender_id().unwrap_or_default();
10165 let format = this.update(&mut cx, |this, cx| {
10166 let mut buffers = HashSet::default();
10167 for buffer_id in &envelope.payload.buffer_ids {
10168 let buffer_id = BufferId::new(*buffer_id)?;
10169 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10170 }
10171 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10172 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10173 })??;
10174
10175 let project_transaction = format.await?;
10176 let project_transaction = this.update(&mut cx, |this, cx| {
10177 this.buffer_store.update(cx, |buffer_store, cx| {
10178 buffer_store.serialize_project_transaction_for_peer(
10179 project_transaction,
10180 sender_id,
10181 cx,
10182 )
10183 })
10184 })?;
10185 Ok(proto::FormatBuffersResponse {
10186 transaction: Some(project_transaction),
10187 })
10188 }
10189
10190 async fn handle_apply_code_action_kind(
10191 this: Entity<Self>,
10192 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10193 mut cx: AsyncApp,
10194 ) -> Result<proto::ApplyCodeActionKindResponse> {
10195 let sender_id = envelope.original_sender_id().unwrap_or_default();
10196 let format = this.update(&mut cx, |this, cx| {
10197 let mut buffers = HashSet::default();
10198 for buffer_id in &envelope.payload.buffer_ids {
10199 let buffer_id = BufferId::new(*buffer_id)?;
10200 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10201 }
10202 let kind = match envelope.payload.kind.as_str() {
10203 "" => CodeActionKind::EMPTY,
10204 "quickfix" => CodeActionKind::QUICKFIX,
10205 "refactor" => CodeActionKind::REFACTOR,
10206 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10207 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10208 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10209 "source" => CodeActionKind::SOURCE,
10210 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10211 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10212 _ => anyhow::bail!(
10213 "Invalid code action kind {}",
10214 envelope.payload.kind.as_str()
10215 ),
10216 };
10217 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10218 })??;
10219
10220 let project_transaction = format.await?;
10221 let project_transaction = this.update(&mut cx, |this, cx| {
10222 this.buffer_store.update(cx, |buffer_store, cx| {
10223 buffer_store.serialize_project_transaction_for_peer(
10224 project_transaction,
10225 sender_id,
10226 cx,
10227 )
10228 })
10229 })?;
10230 Ok(proto::ApplyCodeActionKindResponse {
10231 transaction: Some(project_transaction),
10232 })
10233 }
10234
10235 async fn shutdown_language_server(
10236 server_state: Option<LanguageServerState>,
10237 name: LanguageServerName,
10238 cx: &mut AsyncApp,
10239 ) {
10240 let server = match server_state {
10241 Some(LanguageServerState::Starting { startup, .. }) => {
10242 let mut timer = cx
10243 .background_executor()
10244 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10245 .fuse();
10246
10247 select! {
10248 server = startup.fuse() => server,
10249 () = timer => {
10250 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10251 None
10252 },
10253 }
10254 }
10255
10256 Some(LanguageServerState::Running { server, .. }) => Some(server),
10257
10258 None => None,
10259 };
10260
10261 if let Some(server) = server
10262 && let Some(shutdown) = server.shutdown()
10263 {
10264 shutdown.await;
10265 }
10266 }
10267
10268 // Returns a list of all of the worktrees which no longer have a language server and the root path
10269 // for the stopped server
10270 fn stop_local_language_server(
10271 &mut self,
10272 server_id: LanguageServerId,
10273 cx: &mut Context<Self>,
10274 ) -> Task<()> {
10275 let local = match &mut self.mode {
10276 LspStoreMode::Local(local) => local,
10277 _ => {
10278 return Task::ready(());
10279 }
10280 };
10281
10282 // Remove this server ID from all entries in the given worktree.
10283 local
10284 .language_server_ids
10285 .retain(|_, state| state.id != server_id);
10286 self.buffer_store.update(cx, |buffer_store, cx| {
10287 for buffer in buffer_store.buffers() {
10288 buffer.update(cx, |buffer, cx| {
10289 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10290 buffer.set_completion_triggers(server_id, Default::default(), cx);
10291 });
10292 }
10293 });
10294
10295 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10296 summaries.retain(|path, summaries_by_server_id| {
10297 if summaries_by_server_id.remove(&server_id).is_some() {
10298 if let Some((client, project_id)) = self.downstream_client.clone() {
10299 client
10300 .send(proto::UpdateDiagnosticSummary {
10301 project_id,
10302 worktree_id: worktree_id.to_proto(),
10303 summary: Some(proto::DiagnosticSummary {
10304 path: path.as_ref().to_proto(),
10305 language_server_id: server_id.0 as u64,
10306 error_count: 0,
10307 warning_count: 0,
10308 }),
10309 more_summaries: Vec::new(),
10310 })
10311 .log_err();
10312 }
10313 !summaries_by_server_id.is_empty()
10314 } else {
10315 true
10316 }
10317 });
10318 }
10319
10320 let local = self.as_local_mut().unwrap();
10321 for diagnostics in local.diagnostics.values_mut() {
10322 diagnostics.retain(|_, diagnostics_by_server_id| {
10323 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10324 diagnostics_by_server_id.remove(ix);
10325 !diagnostics_by_server_id.is_empty()
10326 } else {
10327 true
10328 }
10329 });
10330 }
10331 local.language_server_watched_paths.remove(&server_id);
10332
10333 let server_state = local.language_servers.remove(&server_id);
10334 self.cleanup_lsp_data(server_id);
10335 let name = self
10336 .language_server_statuses
10337 .remove(&server_id)
10338 .map(|status| status.name)
10339 .or_else(|| {
10340 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10341 Some(adapter.name())
10342 } else {
10343 None
10344 }
10345 });
10346
10347 if let Some(name) = name {
10348 log::info!("stopping language server {name}");
10349 self.languages
10350 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10351 cx.notify();
10352
10353 return cx.spawn(async move |lsp_store, cx| {
10354 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10355 lsp_store
10356 .update(cx, |lsp_store, cx| {
10357 lsp_store
10358 .languages
10359 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10360 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10361 cx.notify();
10362 })
10363 .ok();
10364 });
10365 }
10366
10367 if server_state.is_some() {
10368 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10369 }
10370 Task::ready(())
10371 }
10372
10373 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10374 if let Some((client, project_id)) = self.upstream_client() {
10375 let request = client.request(proto::StopLanguageServers {
10376 project_id,
10377 buffer_ids: Vec::new(),
10378 also_servers: Vec::new(),
10379 all: true,
10380 });
10381 cx.background_spawn(request).detach_and_log_err(cx);
10382 } else {
10383 let Some(local) = self.as_local_mut() else {
10384 return;
10385 };
10386 let language_servers_to_stop = local
10387 .language_server_ids
10388 .values()
10389 .map(|state| state.id)
10390 .collect();
10391 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10392 let tasks = language_servers_to_stop
10393 .into_iter()
10394 .map(|server| self.stop_local_language_server(server, cx))
10395 .collect::<Vec<_>>();
10396 cx.background_spawn(async move {
10397 futures::future::join_all(tasks).await;
10398 })
10399 .detach();
10400 }
10401 }
10402
10403 pub fn restart_language_servers_for_buffers(
10404 &mut self,
10405 buffers: Vec<Entity<Buffer>>,
10406 only_restart_servers: HashSet<LanguageServerSelector>,
10407 cx: &mut Context<Self>,
10408 ) {
10409 if let Some((client, project_id)) = self.upstream_client() {
10410 let request = client.request(proto::RestartLanguageServers {
10411 project_id,
10412 buffer_ids: buffers
10413 .into_iter()
10414 .map(|b| b.read(cx).remote_id().to_proto())
10415 .collect(),
10416 only_servers: only_restart_servers
10417 .into_iter()
10418 .map(|selector| {
10419 let selector = match selector {
10420 LanguageServerSelector::Id(language_server_id) => {
10421 proto::language_server_selector::Selector::ServerId(
10422 language_server_id.to_proto(),
10423 )
10424 }
10425 LanguageServerSelector::Name(language_server_name) => {
10426 proto::language_server_selector::Selector::Name(
10427 language_server_name.to_string(),
10428 )
10429 }
10430 };
10431 proto::LanguageServerSelector {
10432 selector: Some(selector),
10433 }
10434 })
10435 .collect(),
10436 all: false,
10437 });
10438 cx.background_spawn(request).detach_and_log_err(cx);
10439 } else {
10440 let stop_task = if only_restart_servers.is_empty() {
10441 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10442 } else {
10443 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10444 };
10445 cx.spawn(async move |lsp_store, cx| {
10446 stop_task.await;
10447 lsp_store
10448 .update(cx, |lsp_store, cx| {
10449 for buffer in buffers {
10450 lsp_store.register_buffer_with_language_servers(
10451 &buffer,
10452 only_restart_servers.clone(),
10453 true,
10454 cx,
10455 );
10456 }
10457 })
10458 .ok()
10459 })
10460 .detach();
10461 }
10462 }
10463
10464 pub fn stop_language_servers_for_buffers(
10465 &mut self,
10466 buffers: Vec<Entity<Buffer>>,
10467 also_stop_servers: HashSet<LanguageServerSelector>,
10468 cx: &mut Context<Self>,
10469 ) -> Task<Result<()>> {
10470 if let Some((client, project_id)) = self.upstream_client() {
10471 let request = client.request(proto::StopLanguageServers {
10472 project_id,
10473 buffer_ids: buffers
10474 .into_iter()
10475 .map(|b| b.read(cx).remote_id().to_proto())
10476 .collect(),
10477 also_servers: also_stop_servers
10478 .into_iter()
10479 .map(|selector| {
10480 let selector = match selector {
10481 LanguageServerSelector::Id(language_server_id) => {
10482 proto::language_server_selector::Selector::ServerId(
10483 language_server_id.to_proto(),
10484 )
10485 }
10486 LanguageServerSelector::Name(language_server_name) => {
10487 proto::language_server_selector::Selector::Name(
10488 language_server_name.to_string(),
10489 )
10490 }
10491 };
10492 proto::LanguageServerSelector {
10493 selector: Some(selector),
10494 }
10495 })
10496 .collect(),
10497 all: false,
10498 });
10499 cx.background_spawn(async move {
10500 let _ = request.await?;
10501 Ok(())
10502 })
10503 } else {
10504 let task =
10505 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10506 cx.background_spawn(async move {
10507 task.await;
10508 Ok(())
10509 })
10510 }
10511 }
10512
10513 fn stop_local_language_servers_for_buffers(
10514 &mut self,
10515 buffers: &[Entity<Buffer>],
10516 also_stop_servers: HashSet<LanguageServerSelector>,
10517 cx: &mut Context<Self>,
10518 ) -> Task<()> {
10519 let Some(local) = self.as_local_mut() else {
10520 return Task::ready(());
10521 };
10522 let mut language_server_names_to_stop = BTreeSet::default();
10523 let mut language_servers_to_stop = also_stop_servers
10524 .into_iter()
10525 .flat_map(|selector| match selector {
10526 LanguageServerSelector::Id(id) => Some(id),
10527 LanguageServerSelector::Name(name) => {
10528 language_server_names_to_stop.insert(name);
10529 None
10530 }
10531 })
10532 .collect::<BTreeSet<_>>();
10533
10534 let mut covered_worktrees = HashSet::default();
10535 for buffer in buffers {
10536 buffer.update(cx, |buffer, cx| {
10537 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10538 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10539 && covered_worktrees.insert(worktree_id)
10540 {
10541 language_server_names_to_stop.retain(|name| {
10542 let old_ids_count = language_servers_to_stop.len();
10543 let all_language_servers_with_this_name = local
10544 .language_server_ids
10545 .iter()
10546 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10547 language_servers_to_stop.extend(all_language_servers_with_this_name);
10548 old_ids_count == language_servers_to_stop.len()
10549 });
10550 }
10551 });
10552 }
10553 for name in language_server_names_to_stop {
10554 language_servers_to_stop.extend(
10555 local
10556 .language_server_ids
10557 .iter()
10558 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10559 );
10560 }
10561
10562 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10563 let tasks = language_servers_to_stop
10564 .into_iter()
10565 .map(|server| self.stop_local_language_server(server, cx))
10566 .collect::<Vec<_>>();
10567
10568 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10569 }
10570
10571 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10572 let (worktree, relative_path) =
10573 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10574
10575 let project_path = ProjectPath {
10576 worktree_id: worktree.read(cx).id(),
10577 path: relative_path.into(),
10578 };
10579
10580 Some(
10581 self.buffer_store()
10582 .read(cx)
10583 .get_by_path(&project_path)?
10584 .read(cx),
10585 )
10586 }
10587
10588 #[cfg(any(test, feature = "test-support"))]
10589 pub fn update_diagnostics(
10590 &mut self,
10591 server_id: LanguageServerId,
10592 diagnostics: lsp::PublishDiagnosticsParams,
10593 result_id: Option<String>,
10594 source_kind: DiagnosticSourceKind,
10595 disk_based_sources: &[String],
10596 cx: &mut Context<Self>,
10597 ) -> Result<()> {
10598 self.merge_lsp_diagnostics(
10599 source_kind,
10600 vec![DocumentDiagnosticsUpdate {
10601 diagnostics,
10602 result_id,
10603 server_id,
10604 disk_based_sources: Cow::Borrowed(disk_based_sources),
10605 }],
10606 |_, _, _| false,
10607 cx,
10608 )
10609 }
10610
10611 pub fn merge_lsp_diagnostics(
10612 &mut self,
10613 source_kind: DiagnosticSourceKind,
10614 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10615 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10616 cx: &mut Context<Self>,
10617 ) -> Result<()> {
10618 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10619 let updates = lsp_diagnostics
10620 .into_iter()
10621 .filter_map(|update| {
10622 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10623 Some(DocumentDiagnosticsUpdate {
10624 diagnostics: self.lsp_to_document_diagnostics(
10625 abs_path,
10626 source_kind,
10627 update.server_id,
10628 update.diagnostics,
10629 &update.disk_based_sources,
10630 ),
10631 result_id: update.result_id,
10632 server_id: update.server_id,
10633 disk_based_sources: update.disk_based_sources,
10634 })
10635 })
10636 .collect();
10637 self.merge_diagnostic_entries(updates, merge, cx)?;
10638 Ok(())
10639 }
10640
10641 fn lsp_to_document_diagnostics(
10642 &mut self,
10643 document_abs_path: PathBuf,
10644 source_kind: DiagnosticSourceKind,
10645 server_id: LanguageServerId,
10646 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10647 disk_based_sources: &[String],
10648 ) -> DocumentDiagnostics {
10649 let mut diagnostics = Vec::default();
10650 let mut primary_diagnostic_group_ids = HashMap::default();
10651 let mut sources_by_group_id = HashMap::default();
10652 let mut supporting_diagnostics = HashMap::default();
10653
10654 let adapter = self.language_server_adapter_for_id(server_id);
10655
10656 // Ensure that primary diagnostics are always the most severe
10657 lsp_diagnostics
10658 .diagnostics
10659 .sort_by_key(|item| item.severity);
10660
10661 for diagnostic in &lsp_diagnostics.diagnostics {
10662 let source = diagnostic.source.as_ref();
10663 let range = range_from_lsp(diagnostic.range);
10664 let is_supporting = diagnostic
10665 .related_information
10666 .as_ref()
10667 .is_some_and(|infos| {
10668 infos.iter().any(|info| {
10669 primary_diagnostic_group_ids.contains_key(&(
10670 source,
10671 diagnostic.code.clone(),
10672 range_from_lsp(info.location.range),
10673 ))
10674 })
10675 });
10676
10677 let is_unnecessary = diagnostic
10678 .tags
10679 .as_ref()
10680 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10681
10682 let underline = self
10683 .language_server_adapter_for_id(server_id)
10684 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10685
10686 if is_supporting {
10687 supporting_diagnostics.insert(
10688 (source, diagnostic.code.clone(), range),
10689 (diagnostic.severity, is_unnecessary),
10690 );
10691 } else {
10692 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10693 let is_disk_based =
10694 source.is_some_and(|source| disk_based_sources.contains(source));
10695
10696 sources_by_group_id.insert(group_id, source);
10697 primary_diagnostic_group_ids
10698 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10699
10700 diagnostics.push(DiagnosticEntry {
10701 range,
10702 diagnostic: Diagnostic {
10703 source: diagnostic.source.clone(),
10704 source_kind,
10705 code: diagnostic.code.clone(),
10706 code_description: diagnostic
10707 .code_description
10708 .as_ref()
10709 .and_then(|d| d.href.clone()),
10710 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10711 markdown: adapter.as_ref().and_then(|adapter| {
10712 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10713 }),
10714 message: diagnostic.message.trim().to_string(),
10715 group_id,
10716 is_primary: true,
10717 is_disk_based,
10718 is_unnecessary,
10719 underline,
10720 data: diagnostic.data.clone(),
10721 },
10722 });
10723 if let Some(infos) = &diagnostic.related_information {
10724 for info in infos {
10725 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10726 let range = range_from_lsp(info.location.range);
10727 diagnostics.push(DiagnosticEntry {
10728 range,
10729 diagnostic: Diagnostic {
10730 source: diagnostic.source.clone(),
10731 source_kind,
10732 code: diagnostic.code.clone(),
10733 code_description: diagnostic
10734 .code_description
10735 .as_ref()
10736 .and_then(|d| d.href.clone()),
10737 severity: DiagnosticSeverity::INFORMATION,
10738 markdown: adapter.as_ref().and_then(|adapter| {
10739 adapter.diagnostic_message_to_markdown(&info.message)
10740 }),
10741 message: info.message.trim().to_string(),
10742 group_id,
10743 is_primary: false,
10744 is_disk_based,
10745 is_unnecessary: false,
10746 underline,
10747 data: diagnostic.data.clone(),
10748 },
10749 });
10750 }
10751 }
10752 }
10753 }
10754 }
10755
10756 for entry in &mut diagnostics {
10757 let diagnostic = &mut entry.diagnostic;
10758 if !diagnostic.is_primary {
10759 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10760 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10761 source,
10762 diagnostic.code.clone(),
10763 entry.range.clone(),
10764 )) {
10765 if let Some(severity) = severity {
10766 diagnostic.severity = severity;
10767 }
10768 diagnostic.is_unnecessary = is_unnecessary;
10769 }
10770 }
10771 }
10772
10773 DocumentDiagnostics {
10774 diagnostics,
10775 document_abs_path,
10776 version: lsp_diagnostics.version,
10777 }
10778 }
10779
10780 fn insert_newly_running_language_server(
10781 &mut self,
10782 adapter: Arc<CachedLspAdapter>,
10783 language_server: Arc<LanguageServer>,
10784 server_id: LanguageServerId,
10785 key: LanguageServerSeed,
10786 workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
10787 cx: &mut Context<Self>,
10788 ) {
10789 let Some(local) = self.as_local_mut() else {
10790 return;
10791 };
10792 // If the language server for this key doesn't match the server id, don't store the
10793 // server. Which will cause it to be dropped, killing the process
10794 if local
10795 .language_server_ids
10796 .get(&key)
10797 .map(|state| state.id != server_id)
10798 .unwrap_or(false)
10799 {
10800 return;
10801 }
10802
10803 // Update language_servers collection with Running variant of LanguageServerState
10804 // indicating that the server is up and running and ready
10805 let workspace_folders = workspace_folders.lock().clone();
10806 language_server.set_workspace_folders(workspace_folders);
10807
10808 local.language_servers.insert(
10809 server_id,
10810 LanguageServerState::Running {
10811 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10812 language_server.clone(),
10813 cx,
10814 ),
10815 adapter: adapter.clone(),
10816 server: language_server.clone(),
10817 simulate_disk_based_diagnostics_completion: None,
10818 },
10819 );
10820 local
10821 .languages
10822 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10823 if let Some(file_ops_caps) = language_server
10824 .capabilities()
10825 .workspace
10826 .as_ref()
10827 .and_then(|ws| ws.file_operations.as_ref())
10828 {
10829 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10830 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10831 if did_rename_caps.or(will_rename_caps).is_some() {
10832 let watcher = RenamePathsWatchedForServer::default()
10833 .with_did_rename_patterns(did_rename_caps)
10834 .with_will_rename_patterns(will_rename_caps);
10835 local
10836 .language_server_paths_watched_for_rename
10837 .insert(server_id, watcher);
10838 }
10839 }
10840
10841 self.language_server_statuses.insert(
10842 server_id,
10843 LanguageServerStatus {
10844 name: language_server.name(),
10845 pending_work: Default::default(),
10846 has_pending_diagnostic_updates: false,
10847 progress_tokens: Default::default(),
10848 },
10849 );
10850
10851 cx.emit(LspStoreEvent::LanguageServerAdded(
10852 server_id,
10853 language_server.name(),
10854 Some(key.worktree_id),
10855 ));
10856 cx.emit(LspStoreEvent::RefreshInlayHints);
10857
10858 let server_capabilities = language_server.capabilities();
10859 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10860 downstream_client
10861 .send(proto::StartLanguageServer {
10862 project_id: *project_id,
10863 server: Some(proto::LanguageServer {
10864 id: server_id.to_proto(),
10865 name: language_server.name().to_string(),
10866 worktree_id: Some(key.worktree_id.to_proto()),
10867 }),
10868 capabilities: serde_json::to_string(&server_capabilities)
10869 .expect("serializing server LSP capabilities"),
10870 })
10871 .log_err();
10872 }
10873 self.lsp_server_capabilities
10874 .insert(server_id, server_capabilities);
10875
10876 // Tell the language server about every open buffer in the worktree that matches the language.
10877 // Also check for buffers in worktrees that reused this server
10878 let mut worktrees_using_server = vec![key.worktree_id];
10879 if let Some(local) = self.as_local() {
10880 // Find all worktrees that have this server in their language server tree
10881 for (worktree_id, servers) in &local.lsp_tree.instances {
10882 if *worktree_id != key.worktree_id {
10883 for server_map in servers.roots.values() {
10884 if server_map.contains_key(&key.name) {
10885 worktrees_using_server.push(*worktree_id);
10886 }
10887 }
10888 }
10889 }
10890 }
10891
10892 let mut buffer_paths_registered = Vec::new();
10893 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10894 for buffer_handle in buffer_store.buffers() {
10895 let buffer = buffer_handle.read(cx);
10896 let file = match File::from_dyn(buffer.file()) {
10897 Some(file) => file,
10898 None => continue,
10899 };
10900 let language = match buffer.language() {
10901 Some(language) => language,
10902 None => continue,
10903 };
10904
10905 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10906 || !self
10907 .languages
10908 .lsp_adapters(&language.name())
10909 .iter()
10910 .any(|a| a.name == key.name)
10911 {
10912 continue;
10913 }
10914 // didOpen
10915 let file = match file.as_local() {
10916 Some(file) => file,
10917 None => continue,
10918 };
10919
10920 let local = self.as_local_mut().unwrap();
10921
10922 let buffer_id = buffer.remote_id();
10923 if local.registered_buffers.contains_key(&buffer_id) {
10924 let versions = local
10925 .buffer_snapshots
10926 .entry(buffer_id)
10927 .or_default()
10928 .entry(server_id)
10929 .and_modify(|_| {
10930 assert!(
10931 false,
10932 "There should not be an existing snapshot for a newly inserted buffer"
10933 )
10934 })
10935 .or_insert_with(|| {
10936 vec![LspBufferSnapshot {
10937 version: 0,
10938 snapshot: buffer.text_snapshot(),
10939 }]
10940 });
10941
10942 let snapshot = versions.last().unwrap();
10943 let version = snapshot.version;
10944 let initial_snapshot = &snapshot.snapshot;
10945 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
10946 language_server.register_buffer(
10947 uri,
10948 adapter.language_id(&language.name()),
10949 version,
10950 initial_snapshot.text(),
10951 );
10952 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
10953 local
10954 .buffers_opened_in_servers
10955 .entry(buffer_id)
10956 .or_default()
10957 .insert(server_id);
10958 }
10959 buffer_handle.update(cx, |buffer, cx| {
10960 buffer.set_completion_triggers(
10961 server_id,
10962 language_server
10963 .capabilities()
10964 .completion_provider
10965 .as_ref()
10966 .and_then(|provider| {
10967 provider
10968 .trigger_characters
10969 .as_ref()
10970 .map(|characters| characters.iter().cloned().collect())
10971 })
10972 .unwrap_or_default(),
10973 cx,
10974 )
10975 });
10976 }
10977 });
10978
10979 for (buffer_id, abs_path) in buffer_paths_registered {
10980 cx.emit(LspStoreEvent::LanguageServerUpdate {
10981 language_server_id: server_id,
10982 name: Some(adapter.name()),
10983 message: proto::update_language_server::Variant::RegisteredForBuffer(
10984 proto::RegisteredForBuffer {
10985 buffer_abs_path: abs_path.to_string_lossy().to_string(),
10986 buffer_id: buffer_id.to_proto(),
10987 },
10988 ),
10989 });
10990 }
10991
10992 cx.notify();
10993 }
10994
10995 pub fn language_servers_running_disk_based_diagnostics(
10996 &self,
10997 ) -> impl Iterator<Item = LanguageServerId> + '_ {
10998 self.language_server_statuses
10999 .iter()
11000 .filter_map(|(id, status)| {
11001 if status.has_pending_diagnostic_updates {
11002 Some(*id)
11003 } else {
11004 None
11005 }
11006 })
11007 }
11008
11009 pub(crate) fn cancel_language_server_work_for_buffers(
11010 &mut self,
11011 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11012 cx: &mut Context<Self>,
11013 ) {
11014 if let Some((client, project_id)) = self.upstream_client() {
11015 let request = client.request(proto::CancelLanguageServerWork {
11016 project_id,
11017 work: Some(proto::cancel_language_server_work::Work::Buffers(
11018 proto::cancel_language_server_work::Buffers {
11019 buffer_ids: buffers
11020 .into_iter()
11021 .map(|b| b.read(cx).remote_id().to_proto())
11022 .collect(),
11023 },
11024 )),
11025 });
11026 cx.background_spawn(request).detach_and_log_err(cx);
11027 } else if let Some(local) = self.as_local() {
11028 let servers = buffers
11029 .into_iter()
11030 .flat_map(|buffer| {
11031 buffer.update(cx, |buffer, cx| {
11032 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11033 })
11034 })
11035 .collect::<HashSet<_>>();
11036 for server_id in servers {
11037 self.cancel_language_server_work(server_id, None, cx);
11038 }
11039 }
11040 }
11041
11042 pub(crate) fn cancel_language_server_work(
11043 &mut self,
11044 server_id: LanguageServerId,
11045 token_to_cancel: Option<String>,
11046 cx: &mut Context<Self>,
11047 ) {
11048 if let Some(local) = self.as_local() {
11049 let status = self.language_server_statuses.get(&server_id);
11050 let server = local.language_servers.get(&server_id);
11051 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11052 {
11053 for (token, progress) in &status.pending_work {
11054 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11055 && token != token_to_cancel
11056 {
11057 continue;
11058 }
11059 if progress.is_cancellable {
11060 server
11061 .notify::<lsp::notification::WorkDoneProgressCancel>(
11062 &WorkDoneProgressCancelParams {
11063 token: lsp::NumberOrString::String(token.clone()),
11064 },
11065 )
11066 .ok();
11067 }
11068 }
11069 }
11070 } else if let Some((client, project_id)) = self.upstream_client() {
11071 let request = client.request(proto::CancelLanguageServerWork {
11072 project_id,
11073 work: Some(
11074 proto::cancel_language_server_work::Work::LanguageServerWork(
11075 proto::cancel_language_server_work::LanguageServerWork {
11076 language_server_id: server_id.to_proto(),
11077 token: token_to_cancel,
11078 },
11079 ),
11080 ),
11081 });
11082 cx.background_spawn(request).detach_and_log_err(cx);
11083 }
11084 }
11085
11086 fn register_supplementary_language_server(
11087 &mut self,
11088 id: LanguageServerId,
11089 name: LanguageServerName,
11090 server: Arc<LanguageServer>,
11091 cx: &mut Context<Self>,
11092 ) {
11093 if let Some(local) = self.as_local_mut() {
11094 local
11095 .supplementary_language_servers
11096 .insert(id, (name.clone(), server));
11097 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11098 }
11099 }
11100
11101 fn unregister_supplementary_language_server(
11102 &mut self,
11103 id: LanguageServerId,
11104 cx: &mut Context<Self>,
11105 ) {
11106 if let Some(local) = self.as_local_mut() {
11107 local.supplementary_language_servers.remove(&id);
11108 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11109 }
11110 }
11111
11112 pub(crate) fn supplementary_language_servers(
11113 &self,
11114 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11115 self.as_local().into_iter().flat_map(|local| {
11116 local
11117 .supplementary_language_servers
11118 .iter()
11119 .map(|(id, (name, _))| (*id, name.clone()))
11120 })
11121 }
11122
11123 pub fn language_server_adapter_for_id(
11124 &self,
11125 id: LanguageServerId,
11126 ) -> Option<Arc<CachedLspAdapter>> {
11127 self.as_local()
11128 .and_then(|local| local.language_servers.get(&id))
11129 .and_then(|language_server_state| match language_server_state {
11130 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11131 _ => None,
11132 })
11133 }
11134
11135 pub(super) fn update_local_worktree_language_servers(
11136 &mut self,
11137 worktree_handle: &Entity<Worktree>,
11138 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
11139 cx: &mut Context<Self>,
11140 ) {
11141 if changes.is_empty() {
11142 return;
11143 }
11144
11145 let Some(local) = self.as_local() else { return };
11146
11147 local.prettier_store.update(cx, |prettier_store, cx| {
11148 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11149 });
11150
11151 let worktree_id = worktree_handle.read(cx).id();
11152 let mut language_server_ids = local
11153 .language_server_ids
11154 .iter()
11155 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11156 .collect::<Vec<_>>();
11157 language_server_ids.sort();
11158 language_server_ids.dedup();
11159
11160 let abs_path = worktree_handle.read(cx).abs_path();
11161 for server_id in &language_server_ids {
11162 if let Some(LanguageServerState::Running { server, .. }) =
11163 local.language_servers.get(server_id)
11164 && let Some(watched_paths) = local
11165 .language_server_watched_paths
11166 .get(server_id)
11167 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11168 {
11169 let params = lsp::DidChangeWatchedFilesParams {
11170 changes: changes
11171 .iter()
11172 .filter_map(|(path, _, change)| {
11173 if !watched_paths.is_match(path) {
11174 return None;
11175 }
11176 let typ = match change {
11177 PathChange::Loaded => return None,
11178 PathChange::Added => lsp::FileChangeType::CREATED,
11179 PathChange::Removed => lsp::FileChangeType::DELETED,
11180 PathChange::Updated => lsp::FileChangeType::CHANGED,
11181 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11182 };
11183 Some(lsp::FileEvent {
11184 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
11185 typ,
11186 })
11187 })
11188 .collect(),
11189 };
11190 if !params.changes.is_empty() {
11191 server
11192 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
11193 .ok();
11194 }
11195 }
11196 }
11197 for (path, _, _) in changes {
11198 if let Some(file_name) = path.file_name().and_then(|file_name| file_name.to_str())
11199 && local.watched_manifest_filenames.contains(file_name)
11200 {
11201 self.request_workspace_config_refresh();
11202 break;
11203 }
11204 }
11205 }
11206
11207 pub fn wait_for_remote_buffer(
11208 &mut self,
11209 id: BufferId,
11210 cx: &mut Context<Self>,
11211 ) -> Task<Result<Entity<Buffer>>> {
11212 self.buffer_store.update(cx, |buffer_store, cx| {
11213 buffer_store.wait_for_remote_buffer(id, cx)
11214 })
11215 }
11216
11217 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11218 proto::Symbol {
11219 language_server_name: symbol.language_server_name.0.to_string(),
11220 source_worktree_id: symbol.source_worktree_id.to_proto(),
11221 language_server_id: symbol.source_language_server_id.to_proto(),
11222 worktree_id: symbol.path.worktree_id.to_proto(),
11223 path: symbol.path.path.as_ref().to_proto(),
11224 name: symbol.name.clone(),
11225 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11226 start: Some(proto::PointUtf16 {
11227 row: symbol.range.start.0.row,
11228 column: symbol.range.start.0.column,
11229 }),
11230 end: Some(proto::PointUtf16 {
11231 row: symbol.range.end.0.row,
11232 column: symbol.range.end.0.column,
11233 }),
11234 signature: symbol.signature.to_vec(),
11235 }
11236 }
11237
11238 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11239 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11240 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11241 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11242 let path = ProjectPath {
11243 worktree_id,
11244 path: Arc::<Path>::from_proto(serialized_symbol.path),
11245 };
11246
11247 let start = serialized_symbol.start.context("invalid start")?;
11248 let end = serialized_symbol.end.context("invalid end")?;
11249 Ok(CoreSymbol {
11250 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11251 source_worktree_id,
11252 source_language_server_id: LanguageServerId::from_proto(
11253 serialized_symbol.language_server_id,
11254 ),
11255 path,
11256 name: serialized_symbol.name,
11257 range: Unclipped(PointUtf16::new(start.row, start.column))
11258 ..Unclipped(PointUtf16::new(end.row, end.column)),
11259 kind,
11260 signature: serialized_symbol
11261 .signature
11262 .try_into()
11263 .map_err(|_| anyhow!("invalid signature"))?,
11264 })
11265 }
11266
11267 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11268 let mut serialized_completion = proto::Completion {
11269 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11270 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11271 new_text: completion.new_text.clone(),
11272 ..proto::Completion::default()
11273 };
11274 match &completion.source {
11275 CompletionSource::Lsp {
11276 insert_range,
11277 server_id,
11278 lsp_completion,
11279 lsp_defaults,
11280 resolved,
11281 } => {
11282 let (old_insert_start, old_insert_end) = insert_range
11283 .as_ref()
11284 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11285 .unzip();
11286
11287 serialized_completion.old_insert_start = old_insert_start;
11288 serialized_completion.old_insert_end = old_insert_end;
11289 serialized_completion.source = proto::completion::Source::Lsp as i32;
11290 serialized_completion.server_id = server_id.0 as u64;
11291 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11292 serialized_completion.lsp_defaults = lsp_defaults
11293 .as_deref()
11294 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11295 serialized_completion.resolved = *resolved;
11296 }
11297 CompletionSource::BufferWord {
11298 word_range,
11299 resolved,
11300 } => {
11301 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11302 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11303 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11304 serialized_completion.resolved = *resolved;
11305 }
11306 CompletionSource::Custom => {
11307 serialized_completion.source = proto::completion::Source::Custom as i32;
11308 serialized_completion.resolved = true;
11309 }
11310 CompletionSource::Dap { sort_text } => {
11311 serialized_completion.source = proto::completion::Source::Dap as i32;
11312 serialized_completion.sort_text = Some(sort_text.clone());
11313 }
11314 }
11315
11316 serialized_completion
11317 }
11318
11319 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11320 let old_replace_start = completion
11321 .old_replace_start
11322 .and_then(deserialize_anchor)
11323 .context("invalid old start")?;
11324 let old_replace_end = completion
11325 .old_replace_end
11326 .and_then(deserialize_anchor)
11327 .context("invalid old end")?;
11328 let insert_range = {
11329 match completion.old_insert_start.zip(completion.old_insert_end) {
11330 Some((start, end)) => {
11331 let start = deserialize_anchor(start).context("invalid insert old start")?;
11332 let end = deserialize_anchor(end).context("invalid insert old end")?;
11333 Some(start..end)
11334 }
11335 None => None,
11336 }
11337 };
11338 Ok(CoreCompletion {
11339 replace_range: old_replace_start..old_replace_end,
11340 new_text: completion.new_text,
11341 source: match proto::completion::Source::from_i32(completion.source) {
11342 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11343 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11344 insert_range,
11345 server_id: LanguageServerId::from_proto(completion.server_id),
11346 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11347 lsp_defaults: completion
11348 .lsp_defaults
11349 .as_deref()
11350 .map(serde_json::from_slice)
11351 .transpose()?,
11352 resolved: completion.resolved,
11353 },
11354 Some(proto::completion::Source::BufferWord) => {
11355 let word_range = completion
11356 .buffer_word_start
11357 .and_then(deserialize_anchor)
11358 .context("invalid buffer word start")?
11359 ..completion
11360 .buffer_word_end
11361 .and_then(deserialize_anchor)
11362 .context("invalid buffer word end")?;
11363 CompletionSource::BufferWord {
11364 word_range,
11365 resolved: completion.resolved,
11366 }
11367 }
11368 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11369 sort_text: completion
11370 .sort_text
11371 .context("expected sort text to exist")?,
11372 },
11373 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11374 },
11375 })
11376 }
11377
11378 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11379 let (kind, lsp_action) = match &action.lsp_action {
11380 LspAction::Action(code_action) => (
11381 proto::code_action::Kind::Action as i32,
11382 serde_json::to_vec(code_action).unwrap(),
11383 ),
11384 LspAction::Command(command) => (
11385 proto::code_action::Kind::Command as i32,
11386 serde_json::to_vec(command).unwrap(),
11387 ),
11388 LspAction::CodeLens(code_lens) => (
11389 proto::code_action::Kind::CodeLens as i32,
11390 serde_json::to_vec(code_lens).unwrap(),
11391 ),
11392 };
11393
11394 proto::CodeAction {
11395 server_id: action.server_id.0 as u64,
11396 start: Some(serialize_anchor(&action.range.start)),
11397 end: Some(serialize_anchor(&action.range.end)),
11398 lsp_action,
11399 kind,
11400 resolved: action.resolved,
11401 }
11402 }
11403
11404 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11405 let start = action
11406 .start
11407 .and_then(deserialize_anchor)
11408 .context("invalid start")?;
11409 let end = action
11410 .end
11411 .and_then(deserialize_anchor)
11412 .context("invalid end")?;
11413 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11414 Some(proto::code_action::Kind::Action) => {
11415 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11416 }
11417 Some(proto::code_action::Kind::Command) => {
11418 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11419 }
11420 Some(proto::code_action::Kind::CodeLens) => {
11421 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11422 }
11423 None => anyhow::bail!("Unknown action kind {}", action.kind),
11424 };
11425 Ok(CodeAction {
11426 server_id: LanguageServerId(action.server_id as usize),
11427 range: start..end,
11428 resolved: action.resolved,
11429 lsp_action,
11430 })
11431 }
11432
11433 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11434 match &formatting_result {
11435 Ok(_) => self.last_formatting_failure = None,
11436 Err(error) => {
11437 let error_string = format!("{error:#}");
11438 log::error!("Formatting failed: {error_string}");
11439 self.last_formatting_failure
11440 .replace(error_string.lines().join(" "));
11441 }
11442 }
11443 }
11444
11445 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11446 self.lsp_server_capabilities.remove(&for_server);
11447 for buffer_colors in self.lsp_document_colors.values_mut() {
11448 buffer_colors.colors.remove(&for_server);
11449 buffer_colors.cache_version += 1;
11450 }
11451 for buffer_lens in self.lsp_code_lens.values_mut() {
11452 buffer_lens.lens.remove(&for_server);
11453 }
11454 if let Some(local) = self.as_local_mut() {
11455 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11456 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11457 buffer_servers.remove(&for_server);
11458 }
11459 }
11460 }
11461
11462 pub fn result_id(
11463 &self,
11464 server_id: LanguageServerId,
11465 buffer_id: BufferId,
11466 cx: &App,
11467 ) -> Option<String> {
11468 let abs_path = self
11469 .buffer_store
11470 .read(cx)
11471 .get(buffer_id)
11472 .and_then(|b| File::from_dyn(b.read(cx).file()))
11473 .map(|f| f.abs_path(cx))?;
11474 self.as_local()?
11475 .buffer_pull_diagnostics_result_ids
11476 .get(&server_id)?
11477 .get(&abs_path)?
11478 .clone()
11479 }
11480
11481 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11482 let Some(local) = self.as_local() else {
11483 return HashMap::default();
11484 };
11485 local
11486 .buffer_pull_diagnostics_result_ids
11487 .get(&server_id)
11488 .into_iter()
11489 .flatten()
11490 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11491 .collect()
11492 }
11493
11494 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11495 if let Some(LanguageServerState::Running {
11496 workspace_refresh_task: Some(workspace_refresh_task),
11497 ..
11498 }) = self
11499 .as_local_mut()
11500 .and_then(|local| local.language_servers.get_mut(&server_id))
11501 {
11502 workspace_refresh_task.refresh_tx.try_send(()).ok();
11503 }
11504 }
11505
11506 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11507 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11508 return;
11509 };
11510 let Some(local) = self.as_local_mut() else {
11511 return;
11512 };
11513
11514 for server_id in buffer.update(cx, |buffer, cx| {
11515 local.language_server_ids_for_buffer(buffer, cx)
11516 }) {
11517 if let Some(LanguageServerState::Running {
11518 workspace_refresh_task: Some(workspace_refresh_task),
11519 ..
11520 }) = local.language_servers.get_mut(&server_id)
11521 {
11522 workspace_refresh_task.refresh_tx.try_send(()).ok();
11523 }
11524 }
11525 }
11526
11527 fn apply_workspace_diagnostic_report(
11528 &mut self,
11529 server_id: LanguageServerId,
11530 report: lsp::WorkspaceDiagnosticReportResult,
11531 cx: &mut Context<Self>,
11532 ) {
11533 let workspace_diagnostics =
11534 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11535 let mut unchanged_buffers = HashSet::default();
11536 let mut changed_buffers = HashSet::default();
11537 let workspace_diagnostics_updates = workspace_diagnostics
11538 .into_iter()
11539 .filter_map(
11540 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11541 LspPullDiagnostics::Response {
11542 server_id,
11543 uri,
11544 diagnostics,
11545 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11546 LspPullDiagnostics::Default => None,
11547 },
11548 )
11549 .fold(
11550 HashMap::default(),
11551 |mut acc, (server_id, uri, diagnostics, version)| {
11552 let (result_id, diagnostics) = match diagnostics {
11553 PulledDiagnostics::Unchanged { result_id } => {
11554 unchanged_buffers.insert(uri.clone());
11555 (Some(result_id), Vec::new())
11556 }
11557 PulledDiagnostics::Changed {
11558 result_id,
11559 diagnostics,
11560 } => {
11561 changed_buffers.insert(uri.clone());
11562 (result_id, diagnostics)
11563 }
11564 };
11565 let disk_based_sources = Cow::Owned(
11566 self.language_server_adapter_for_id(server_id)
11567 .as_ref()
11568 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11569 .unwrap_or(&[])
11570 .to_vec(),
11571 );
11572 acc.entry(server_id)
11573 .or_insert_with(Vec::new)
11574 .push(DocumentDiagnosticsUpdate {
11575 server_id,
11576 diagnostics: lsp::PublishDiagnosticsParams {
11577 uri,
11578 diagnostics,
11579 version,
11580 },
11581 result_id,
11582 disk_based_sources,
11583 });
11584 acc
11585 },
11586 );
11587
11588 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11589 self.merge_lsp_diagnostics(
11590 DiagnosticSourceKind::Pulled,
11591 diagnostic_updates,
11592 |buffer, old_diagnostic, cx| {
11593 File::from_dyn(buffer.file())
11594 .and_then(|file| {
11595 let abs_path = file.as_local()?.abs_path(cx);
11596 lsp::Url::from_file_path(abs_path).ok()
11597 })
11598 .is_none_or(|buffer_uri| {
11599 unchanged_buffers.contains(&buffer_uri)
11600 || match old_diagnostic.source_kind {
11601 DiagnosticSourceKind::Pulled => {
11602 !changed_buffers.contains(&buffer_uri)
11603 }
11604 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11605 true
11606 }
11607 }
11608 })
11609 },
11610 cx,
11611 )
11612 .log_err();
11613 }
11614 }
11615
11616 fn register_server_capabilities(
11617 &mut self,
11618 server_id: LanguageServerId,
11619 params: lsp::RegistrationParams,
11620 cx: &mut Context<Self>,
11621 ) -> anyhow::Result<()> {
11622 let server = self
11623 .language_server_for_id(server_id)
11624 .with_context(|| format!("no server {server_id} found"))?;
11625 for reg in params.registrations {
11626 match reg.method.as_str() {
11627 "workspace/didChangeWatchedFiles" => {
11628 if let Some(options) = reg.register_options {
11629 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11630 let caps = serde_json::from_value(options)?;
11631 local_lsp_store
11632 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11633 true
11634 } else {
11635 false
11636 };
11637 if notify {
11638 notify_server_capabilities_updated(&server, cx);
11639 }
11640 }
11641 }
11642 "workspace/didChangeConfiguration" => {
11643 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11644 }
11645 "workspace/symbol" => {
11646 if let Some(options) = parse_register_capabilities(reg)? {
11647 server.update_capabilities(|capabilities| {
11648 capabilities.workspace_symbol_provider = Some(options);
11649 });
11650 notify_server_capabilities_updated(&server, cx);
11651 }
11652 }
11653 "workspace/fileOperations" => {
11654 if let Some(options) = reg.register_options {
11655 let caps = serde_json::from_value(options)?;
11656 server.update_capabilities(|capabilities| {
11657 capabilities
11658 .workspace
11659 .get_or_insert_default()
11660 .file_operations = Some(caps);
11661 });
11662 notify_server_capabilities_updated(&server, cx);
11663 }
11664 }
11665 "workspace/executeCommand" => {
11666 if let Some(options) = reg.register_options {
11667 let options = serde_json::from_value(options)?;
11668 server.update_capabilities(|capabilities| {
11669 capabilities.execute_command_provider = Some(options);
11670 });
11671 notify_server_capabilities_updated(&server, cx);
11672 }
11673 }
11674 "textDocument/rangeFormatting" => {
11675 if let Some(options) = parse_register_capabilities(reg)? {
11676 server.update_capabilities(|capabilities| {
11677 capabilities.document_range_formatting_provider = Some(options);
11678 });
11679 notify_server_capabilities_updated(&server, cx);
11680 }
11681 }
11682 "textDocument/onTypeFormatting" => {
11683 if let Some(options) = reg
11684 .register_options
11685 .map(serde_json::from_value)
11686 .transpose()?
11687 {
11688 server.update_capabilities(|capabilities| {
11689 capabilities.document_on_type_formatting_provider = Some(options);
11690 });
11691 notify_server_capabilities_updated(&server, cx);
11692 }
11693 }
11694 "textDocument/formatting" => {
11695 if let Some(options) = parse_register_capabilities(reg)? {
11696 server.update_capabilities(|capabilities| {
11697 capabilities.document_formatting_provider = Some(options);
11698 });
11699 notify_server_capabilities_updated(&server, cx);
11700 }
11701 }
11702 "textDocument/rename" => {
11703 if let Some(options) = parse_register_capabilities(reg)? {
11704 server.update_capabilities(|capabilities| {
11705 capabilities.rename_provider = Some(options);
11706 });
11707 notify_server_capabilities_updated(&server, cx);
11708 }
11709 }
11710 "textDocument/inlayHint" => {
11711 if let Some(options) = parse_register_capabilities(reg)? {
11712 server.update_capabilities(|capabilities| {
11713 capabilities.inlay_hint_provider = Some(options);
11714 });
11715 notify_server_capabilities_updated(&server, cx);
11716 }
11717 }
11718 "textDocument/documentSymbol" => {
11719 if let Some(options) = parse_register_capabilities(reg)? {
11720 server.update_capabilities(|capabilities| {
11721 capabilities.document_symbol_provider = Some(options);
11722 });
11723 notify_server_capabilities_updated(&server, cx);
11724 }
11725 }
11726 "textDocument/codeAction" => {
11727 if let Some(options) = reg
11728 .register_options
11729 .map(serde_json::from_value)
11730 .transpose()?
11731 {
11732 server.update_capabilities(|capabilities| {
11733 capabilities.code_action_provider =
11734 Some(lsp::CodeActionProviderCapability::Options(options));
11735 });
11736 notify_server_capabilities_updated(&server, cx);
11737 }
11738 }
11739 "textDocument/definition" => {
11740 if let Some(options) = parse_register_capabilities(reg)? {
11741 server.update_capabilities(|capabilities| {
11742 capabilities.definition_provider = Some(options);
11743 });
11744 notify_server_capabilities_updated(&server, cx);
11745 }
11746 }
11747 "textDocument/completion" => {
11748 if let Some(caps) = reg
11749 .register_options
11750 .map(serde_json::from_value)
11751 .transpose()?
11752 {
11753 server.update_capabilities(|capabilities| {
11754 capabilities.completion_provider = Some(caps);
11755 });
11756 notify_server_capabilities_updated(&server, cx);
11757 }
11758 }
11759 "textDocument/hover" => {
11760 if let Some(caps) = reg
11761 .register_options
11762 .map(serde_json::from_value)
11763 .transpose()?
11764 {
11765 server.update_capabilities(|capabilities| {
11766 capabilities.hover_provider = Some(caps);
11767 });
11768 notify_server_capabilities_updated(&server, cx);
11769 }
11770 }
11771 "textDocument/signatureHelp" => {
11772 if let Some(caps) = reg
11773 .register_options
11774 .map(serde_json::from_value)
11775 .transpose()?
11776 {
11777 server.update_capabilities(|capabilities| {
11778 capabilities.signature_help_provider = Some(caps);
11779 });
11780 notify_server_capabilities_updated(&server, cx);
11781 }
11782 }
11783 "textDocument/didChange" => {
11784 if let Some(sync_kind) = reg
11785 .register_options
11786 .and_then(|opts| opts.get("syncKind").cloned())
11787 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11788 .transpose()?
11789 {
11790 server.update_capabilities(|capabilities| {
11791 let mut sync_options =
11792 Self::take_text_document_sync_options(capabilities);
11793 sync_options.change = Some(sync_kind);
11794 capabilities.text_document_sync =
11795 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11796 });
11797 notify_server_capabilities_updated(&server, cx);
11798 }
11799 }
11800 "textDocument/didSave" => {
11801 if let Some(include_text) = reg
11802 .register_options
11803 .map(|opts| {
11804 let transpose = opts
11805 .get("includeText")
11806 .cloned()
11807 .map(serde_json::from_value::<Option<bool>>)
11808 .transpose();
11809 match transpose {
11810 Ok(value) => Ok(value.flatten()),
11811 Err(e) => Err(e),
11812 }
11813 })
11814 .transpose()?
11815 {
11816 server.update_capabilities(|capabilities| {
11817 let mut sync_options =
11818 Self::take_text_document_sync_options(capabilities);
11819 sync_options.save =
11820 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11821 include_text,
11822 }));
11823 capabilities.text_document_sync =
11824 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11825 });
11826 notify_server_capabilities_updated(&server, cx);
11827 }
11828 }
11829 "textDocument/codeLens" => {
11830 if let Some(caps) = reg
11831 .register_options
11832 .map(serde_json::from_value)
11833 .transpose()?
11834 {
11835 server.update_capabilities(|capabilities| {
11836 capabilities.code_lens_provider = Some(caps);
11837 });
11838 notify_server_capabilities_updated(&server, cx);
11839 }
11840 }
11841 "textDocument/diagnostic" => {
11842 if let Some(caps) = reg
11843 .register_options
11844 .map(serde_json::from_value)
11845 .transpose()?
11846 {
11847 server.update_capabilities(|capabilities| {
11848 capabilities.diagnostic_provider = Some(caps);
11849 });
11850 notify_server_capabilities_updated(&server, cx);
11851 }
11852 }
11853 "textDocument/colorProvider" => {
11854 if let Some(caps) = reg
11855 .register_options
11856 .map(serde_json::from_value)
11857 .transpose()?
11858 {
11859 server.update_capabilities(|capabilities| {
11860 capabilities.color_provider = Some(caps);
11861 });
11862 notify_server_capabilities_updated(&server, cx);
11863 }
11864 }
11865 _ => log::warn!("unhandled capability registration: {reg:?}"),
11866 }
11867 }
11868
11869 Ok(())
11870 }
11871
11872 fn unregister_server_capabilities(
11873 &mut self,
11874 server_id: LanguageServerId,
11875 params: lsp::UnregistrationParams,
11876 cx: &mut Context<Self>,
11877 ) -> anyhow::Result<()> {
11878 let server = self
11879 .language_server_for_id(server_id)
11880 .with_context(|| format!("no server {server_id} found"))?;
11881 for unreg in params.unregisterations.iter() {
11882 match unreg.method.as_str() {
11883 "workspace/didChangeWatchedFiles" => {
11884 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11885 local_lsp_store
11886 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11887 true
11888 } else {
11889 false
11890 };
11891 if notify {
11892 notify_server_capabilities_updated(&server, cx);
11893 }
11894 }
11895 "workspace/didChangeConfiguration" => {
11896 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11897 }
11898 "workspace/symbol" => {
11899 server.update_capabilities(|capabilities| {
11900 capabilities.workspace_symbol_provider = None
11901 });
11902 notify_server_capabilities_updated(&server, cx);
11903 }
11904 "workspace/fileOperations" => {
11905 server.update_capabilities(|capabilities| {
11906 capabilities
11907 .workspace
11908 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11909 workspace_folders: None,
11910 file_operations: None,
11911 })
11912 .file_operations = None;
11913 });
11914 notify_server_capabilities_updated(&server, cx);
11915 }
11916 "workspace/executeCommand" => {
11917 server.update_capabilities(|capabilities| {
11918 capabilities.execute_command_provider = None;
11919 });
11920 notify_server_capabilities_updated(&server, cx);
11921 }
11922 "textDocument/rangeFormatting" => {
11923 server.update_capabilities(|capabilities| {
11924 capabilities.document_range_formatting_provider = None
11925 });
11926 notify_server_capabilities_updated(&server, cx);
11927 }
11928 "textDocument/onTypeFormatting" => {
11929 server.update_capabilities(|capabilities| {
11930 capabilities.document_on_type_formatting_provider = None;
11931 });
11932 notify_server_capabilities_updated(&server, cx);
11933 }
11934 "textDocument/formatting" => {
11935 server.update_capabilities(|capabilities| {
11936 capabilities.document_formatting_provider = None;
11937 });
11938 notify_server_capabilities_updated(&server, cx);
11939 }
11940 "textDocument/rename" => {
11941 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
11942 notify_server_capabilities_updated(&server, cx);
11943 }
11944 "textDocument/codeAction" => {
11945 server.update_capabilities(|capabilities| {
11946 capabilities.code_action_provider = None;
11947 });
11948 notify_server_capabilities_updated(&server, cx);
11949 }
11950 "textDocument/definition" => {
11951 server.update_capabilities(|capabilities| {
11952 capabilities.definition_provider = None;
11953 });
11954 notify_server_capabilities_updated(&server, cx);
11955 }
11956 "textDocument/completion" => {
11957 server.update_capabilities(|capabilities| {
11958 capabilities.completion_provider = None;
11959 });
11960 notify_server_capabilities_updated(&server, cx);
11961 }
11962 "textDocument/hover" => {
11963 server.update_capabilities(|capabilities| {
11964 capabilities.hover_provider = None;
11965 });
11966 notify_server_capabilities_updated(&server, cx);
11967 }
11968 "textDocument/signatureHelp" => {
11969 server.update_capabilities(|capabilities| {
11970 capabilities.signature_help_provider = None;
11971 });
11972 notify_server_capabilities_updated(&server, cx);
11973 }
11974 "textDocument/didChange" => {
11975 server.update_capabilities(|capabilities| {
11976 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11977 sync_options.change = None;
11978 capabilities.text_document_sync =
11979 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11980 });
11981 notify_server_capabilities_updated(&server, cx);
11982 }
11983 "textDocument/didSave" => {
11984 server.update_capabilities(|capabilities| {
11985 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11986 sync_options.save = None;
11987 capabilities.text_document_sync =
11988 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11989 });
11990 notify_server_capabilities_updated(&server, cx);
11991 }
11992 "textDocument/codeLens" => {
11993 server.update_capabilities(|capabilities| {
11994 capabilities.code_lens_provider = None;
11995 });
11996 notify_server_capabilities_updated(&server, cx);
11997 }
11998 "textDocument/diagnostic" => {
11999 server.update_capabilities(|capabilities| {
12000 capabilities.diagnostic_provider = None;
12001 });
12002 notify_server_capabilities_updated(&server, cx);
12003 }
12004 "textDocument/colorProvider" => {
12005 server.update_capabilities(|capabilities| {
12006 capabilities.color_provider = None;
12007 });
12008 notify_server_capabilities_updated(&server, cx);
12009 }
12010 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12011 }
12012 }
12013
12014 Ok(())
12015 }
12016
12017 fn take_text_document_sync_options(
12018 capabilities: &mut lsp::ServerCapabilities,
12019 ) -> lsp::TextDocumentSyncOptions {
12020 match capabilities.text_document_sync.take() {
12021 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12022 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12023 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12024 sync_options.change = Some(sync_kind);
12025 sync_options
12026 }
12027 None => lsp::TextDocumentSyncOptions::default(),
12028 }
12029 }
12030}
12031
12032// Registration with registerOptions as null, should fallback to true.
12033// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12034fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12035 reg: lsp::Registration,
12036) -> anyhow::Result<Option<OneOf<bool, T>>> {
12037 Ok(match reg.register_options {
12038 Some(options) => Some(OneOf::Right(serde_json::from_value::<T>(options)?)),
12039 None => Some(OneOf::Left(true)),
12040 })
12041}
12042
12043fn subscribe_to_binary_statuses(
12044 languages: &Arc<LanguageRegistry>,
12045 cx: &mut Context<'_, LspStore>,
12046) -> Task<()> {
12047 let mut server_statuses = languages.language_server_binary_statuses();
12048 cx.spawn(async move |lsp_store, cx| {
12049 while let Some((server_name, binary_status)) = server_statuses.next().await {
12050 if lsp_store
12051 .update(cx, |_, cx| {
12052 let mut message = None;
12053 let binary_status = match binary_status {
12054 BinaryStatus::None => proto::ServerBinaryStatus::None,
12055 BinaryStatus::CheckingForUpdate => {
12056 proto::ServerBinaryStatus::CheckingForUpdate
12057 }
12058 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12059 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12060 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12061 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12062 BinaryStatus::Failed { error } => {
12063 message = Some(error);
12064 proto::ServerBinaryStatus::Failed
12065 }
12066 };
12067 cx.emit(LspStoreEvent::LanguageServerUpdate {
12068 // Binary updates are about the binary that might not have any language server id at that point.
12069 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12070 language_server_id: LanguageServerId(0),
12071 name: Some(server_name),
12072 message: proto::update_language_server::Variant::StatusUpdate(
12073 proto::StatusUpdate {
12074 message,
12075 status: Some(proto::status_update::Status::Binary(
12076 binary_status as i32,
12077 )),
12078 },
12079 ),
12080 });
12081 })
12082 .is_err()
12083 {
12084 break;
12085 }
12086 }
12087 })
12088}
12089
12090fn lsp_workspace_diagnostics_refresh(
12091 server: Arc<LanguageServer>,
12092 cx: &mut Context<'_, LspStore>,
12093) -> Option<WorkspaceRefreshTask> {
12094 let identifier = match server.capabilities().diagnostic_provider? {
12095 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12096 if !diagnostic_options.workspace_diagnostics {
12097 return None;
12098 }
12099 diagnostic_options.identifier
12100 }
12101 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12102 let diagnostic_options = registration_options.diagnostic_options;
12103 if !diagnostic_options.workspace_diagnostics {
12104 return None;
12105 }
12106 diagnostic_options.identifier
12107 }
12108 };
12109
12110 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12111 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12112 refresh_tx.try_send(()).ok();
12113
12114 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12115 let mut attempts = 0;
12116 let max_attempts = 50;
12117 let mut requests = 0;
12118
12119 loop {
12120 let Some(()) = refresh_rx.recv().await else {
12121 return;
12122 };
12123
12124 'request: loop {
12125 requests += 1;
12126 if attempts > max_attempts {
12127 log::error!(
12128 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12129 );
12130 return;
12131 }
12132 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12133 cx.background_executor()
12134 .timer(Duration::from_millis(backoff_millis))
12135 .await;
12136 attempts += 1;
12137
12138 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12139 lsp_store
12140 .all_result_ids(server.server_id())
12141 .into_iter()
12142 .filter_map(|(abs_path, result_id)| {
12143 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12144 Some(lsp::PreviousResultId {
12145 uri,
12146 value: result_id,
12147 })
12148 })
12149 .collect()
12150 }) else {
12151 return;
12152 };
12153
12154 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
12155
12156 progress_rx.try_recv().ok();
12157 let timer =
12158 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12159 let progress = pin!(progress_rx.recv().fuse());
12160 let response_result = server
12161 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12162 lsp::WorkspaceDiagnosticParams {
12163 previous_result_ids,
12164 identifier: identifier.clone(),
12165 work_done_progress_params: Default::default(),
12166 partial_result_params: lsp::PartialResultParams {
12167 partial_result_token: Some(lsp::ProgressToken::String(token)),
12168 },
12169 },
12170 select(timer, progress).then(|either| match either {
12171 Either::Left((message, ..)) => ready(message).left_future(),
12172 Either::Right(..) => pending::<String>().right_future(),
12173 }),
12174 )
12175 .await;
12176
12177 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12178 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12179 match response_result {
12180 ConnectionResult::Timeout => {
12181 log::error!("Timeout during workspace diagnostics pull");
12182 continue 'request;
12183 }
12184 ConnectionResult::ConnectionReset => {
12185 log::error!("Server closed a workspace diagnostics pull request");
12186 continue 'request;
12187 }
12188 ConnectionResult::Result(Err(e)) => {
12189 log::error!("Error during workspace diagnostics pull: {e:#}");
12190 break 'request;
12191 }
12192 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12193 attempts = 0;
12194 if lsp_store
12195 .update(cx, |lsp_store, cx| {
12196 lsp_store.apply_workspace_diagnostic_report(
12197 server.server_id(),
12198 pulled_diagnostics,
12199 cx,
12200 )
12201 })
12202 .is_err()
12203 {
12204 return;
12205 }
12206 break 'request;
12207 }
12208 }
12209 }
12210 }
12211 });
12212
12213 Some(WorkspaceRefreshTask {
12214 refresh_tx,
12215 progress_tx,
12216 task: workspace_query_language_server,
12217 })
12218}
12219
12220fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12221 let CompletionSource::BufferWord {
12222 word_range,
12223 resolved,
12224 } = &mut completion.source
12225 else {
12226 return;
12227 };
12228 if *resolved {
12229 return;
12230 }
12231
12232 if completion.new_text
12233 != snapshot
12234 .text_for_range(word_range.clone())
12235 .collect::<String>()
12236 {
12237 return;
12238 }
12239
12240 let mut offset = 0;
12241 for chunk in snapshot.chunks(word_range.clone(), true) {
12242 let end_offset = offset + chunk.text.len();
12243 if let Some(highlight_id) = chunk.syntax_highlight_id {
12244 completion
12245 .label
12246 .runs
12247 .push((offset..end_offset, highlight_id));
12248 }
12249 offset = end_offset;
12250 }
12251 *resolved = true;
12252}
12253
12254impl EventEmitter<LspStoreEvent> for LspStore {}
12255
12256fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12257 hover
12258 .contents
12259 .retain(|hover_block| !hover_block.text.trim().is_empty());
12260 if hover.contents.is_empty() {
12261 None
12262 } else {
12263 Some(hover)
12264 }
12265}
12266
12267async fn populate_labels_for_completions(
12268 new_completions: Vec<CoreCompletion>,
12269 language: Option<Arc<Language>>,
12270 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12271) -> Vec<Completion> {
12272 let lsp_completions = new_completions
12273 .iter()
12274 .filter_map(|new_completion| {
12275 if let Some(lsp_completion) = new_completion.source.lsp_completion(true) {
12276 Some(lsp_completion.into_owned())
12277 } else {
12278 None
12279 }
12280 })
12281 .collect::<Vec<_>>();
12282
12283 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12284 lsp_adapter
12285 .labels_for_completions(&lsp_completions, language)
12286 .await
12287 .log_err()
12288 .unwrap_or_default()
12289 } else {
12290 Vec::new()
12291 }
12292 .into_iter()
12293 .fuse();
12294
12295 let mut completions = Vec::new();
12296 for completion in new_completions {
12297 match completion.source.lsp_completion(true) {
12298 Some(lsp_completion) => {
12299 let documentation = if let Some(docs) = lsp_completion.documentation.clone() {
12300 Some(docs.into())
12301 } else {
12302 None
12303 };
12304
12305 let mut label = labels.next().flatten().unwrap_or_else(|| {
12306 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12307 });
12308 ensure_uniform_list_compatible_label(&mut label);
12309 completions.push(Completion {
12310 label,
12311 documentation,
12312 replace_range: completion.replace_range,
12313 new_text: completion.new_text,
12314 insert_text_mode: lsp_completion.insert_text_mode,
12315 source: completion.source,
12316 icon_path: None,
12317 confirm: None,
12318 });
12319 }
12320 None => {
12321 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12322 ensure_uniform_list_compatible_label(&mut label);
12323 completions.push(Completion {
12324 label,
12325 documentation: None,
12326 replace_range: completion.replace_range,
12327 new_text: completion.new_text,
12328 source: completion.source,
12329 insert_text_mode: None,
12330 icon_path: None,
12331 confirm: None,
12332 });
12333 }
12334 }
12335 }
12336 completions
12337}
12338
12339#[derive(Debug)]
12340pub enum LanguageServerToQuery {
12341 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12342 FirstCapable,
12343 /// Query a specific language server.
12344 Other(LanguageServerId),
12345}
12346
12347#[derive(Default)]
12348struct RenamePathsWatchedForServer {
12349 did_rename: Vec<RenameActionPredicate>,
12350 will_rename: Vec<RenameActionPredicate>,
12351}
12352
12353impl RenamePathsWatchedForServer {
12354 fn with_did_rename_patterns(
12355 mut self,
12356 did_rename: Option<&FileOperationRegistrationOptions>,
12357 ) -> Self {
12358 if let Some(did_rename) = did_rename {
12359 self.did_rename = did_rename
12360 .filters
12361 .iter()
12362 .filter_map(|filter| filter.try_into().log_err())
12363 .collect();
12364 }
12365 self
12366 }
12367 fn with_will_rename_patterns(
12368 mut self,
12369 will_rename: Option<&FileOperationRegistrationOptions>,
12370 ) -> Self {
12371 if let Some(will_rename) = will_rename {
12372 self.will_rename = will_rename
12373 .filters
12374 .iter()
12375 .filter_map(|filter| filter.try_into().log_err())
12376 .collect();
12377 }
12378 self
12379 }
12380
12381 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12382 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12383 }
12384 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12385 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12386 }
12387}
12388
12389impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12390 type Error = globset::Error;
12391 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12392 Ok(Self {
12393 kind: ops.pattern.matches.clone(),
12394 glob: GlobBuilder::new(&ops.pattern.glob)
12395 .case_insensitive(
12396 ops.pattern
12397 .options
12398 .as_ref()
12399 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12400 )
12401 .build()?
12402 .compile_matcher(),
12403 })
12404 }
12405}
12406struct RenameActionPredicate {
12407 glob: GlobMatcher,
12408 kind: Option<FileOperationPatternKind>,
12409}
12410
12411impl RenameActionPredicate {
12412 // Returns true if language server should be notified
12413 fn eval(&self, path: &str, is_dir: bool) -> bool {
12414 self.kind.as_ref().is_none_or(|kind| {
12415 let expected_kind = if is_dir {
12416 FileOperationPatternKind::Folder
12417 } else {
12418 FileOperationPatternKind::File
12419 };
12420 kind == &expected_kind
12421 }) && self.glob.is_match(path)
12422 }
12423}
12424
12425#[derive(Default)]
12426struct LanguageServerWatchedPaths {
12427 worktree_paths: HashMap<WorktreeId, GlobSet>,
12428 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12429}
12430
12431#[derive(Default)]
12432struct LanguageServerWatchedPathsBuilder {
12433 worktree_paths: HashMap<WorktreeId, GlobSet>,
12434 abs_paths: HashMap<Arc<Path>, GlobSet>,
12435}
12436
12437impl LanguageServerWatchedPathsBuilder {
12438 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12439 self.worktree_paths.insert(worktree_id, glob_set);
12440 }
12441 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12442 self.abs_paths.insert(path, glob_set);
12443 }
12444 fn build(
12445 self,
12446 fs: Arc<dyn Fs>,
12447 language_server_id: LanguageServerId,
12448 cx: &mut Context<LspStore>,
12449 ) -> LanguageServerWatchedPaths {
12450 let project = cx.weak_entity();
12451
12452 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12453 let abs_paths = self
12454 .abs_paths
12455 .into_iter()
12456 .map(|(abs_path, globset)| {
12457 let task = cx.spawn({
12458 let abs_path = abs_path.clone();
12459 let fs = fs.clone();
12460
12461 let lsp_store = project.clone();
12462 async move |_, cx| {
12463 maybe!(async move {
12464 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12465 while let Some(update) = push_updates.0.next().await {
12466 let action = lsp_store
12467 .update(cx, |this, _| {
12468 let Some(local) = this.as_local() else {
12469 return ControlFlow::Break(());
12470 };
12471 let Some(watcher) = local
12472 .language_server_watched_paths
12473 .get(&language_server_id)
12474 else {
12475 return ControlFlow::Break(());
12476 };
12477 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12478 "Watched abs path is not registered with a watcher",
12479 );
12480 let matching_entries = update
12481 .into_iter()
12482 .filter(|event| globs.is_match(&event.path))
12483 .collect::<Vec<_>>();
12484 this.lsp_notify_abs_paths_changed(
12485 language_server_id,
12486 matching_entries,
12487 );
12488 ControlFlow::Continue(())
12489 })
12490 .ok()?;
12491
12492 if action.is_break() {
12493 break;
12494 }
12495 }
12496 Some(())
12497 })
12498 .await;
12499 }
12500 });
12501 (abs_path, (globset, task))
12502 })
12503 .collect();
12504 LanguageServerWatchedPaths {
12505 worktree_paths: self.worktree_paths,
12506 abs_paths,
12507 }
12508 }
12509}
12510
12511struct LspBufferSnapshot {
12512 version: i32,
12513 snapshot: TextBufferSnapshot,
12514}
12515
12516/// A prompt requested by LSP server.
12517#[derive(Clone, Debug)]
12518pub struct LanguageServerPromptRequest {
12519 pub level: PromptLevel,
12520 pub message: String,
12521 pub actions: Vec<MessageActionItem>,
12522 pub lsp_name: String,
12523 pub(crate) response_channel: Sender<MessageActionItem>,
12524}
12525
12526impl LanguageServerPromptRequest {
12527 pub async fn respond(self, index: usize) -> Option<()> {
12528 if let Some(response) = self.actions.into_iter().nth(index) {
12529 self.response_channel.send(response).await.ok()
12530 } else {
12531 None
12532 }
12533 }
12534}
12535impl PartialEq for LanguageServerPromptRequest {
12536 fn eq(&self, other: &Self) -> bool {
12537 self.message == other.message && self.actions == other.actions
12538 }
12539}
12540
12541#[derive(Clone, Debug, PartialEq)]
12542pub enum LanguageServerLogType {
12543 Log(MessageType),
12544 Trace(Option<String>),
12545}
12546
12547impl LanguageServerLogType {
12548 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12549 match self {
12550 Self::Log(log_type) => {
12551 let message_type = match *log_type {
12552 MessageType::ERROR => 1,
12553 MessageType::WARNING => 2,
12554 MessageType::INFO => 3,
12555 MessageType::LOG => 4,
12556 other => {
12557 log::warn!("Unknown lsp log message type: {:?}", other);
12558 4
12559 }
12560 };
12561 proto::language_server_log::LogType::LogMessageType(message_type)
12562 }
12563 Self::Trace(message) => {
12564 proto::language_server_log::LogType::LogTrace(proto::LspLogTrace {
12565 message: message.clone(),
12566 })
12567 }
12568 }
12569 }
12570
12571 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12572 match log_type {
12573 proto::language_server_log::LogType::LogMessageType(message_type) => {
12574 Self::Log(match message_type {
12575 1 => MessageType::ERROR,
12576 2 => MessageType::WARNING,
12577 3 => MessageType::INFO,
12578 4 => MessageType::LOG,
12579 _ => MessageType::LOG,
12580 })
12581 }
12582 proto::language_server_log::LogType::LogTrace(trace) => Self::Trace(trace.message),
12583 }
12584 }
12585}
12586
12587pub struct WorkspaceRefreshTask {
12588 refresh_tx: mpsc::Sender<()>,
12589 progress_tx: mpsc::Sender<()>,
12590 #[allow(dead_code)]
12591 task: Task<()>,
12592}
12593
12594pub enum LanguageServerState {
12595 Starting {
12596 startup: Task<Option<Arc<LanguageServer>>>,
12597 /// List of language servers that will be added to the workspace once it's initialization completes.
12598 pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
12599 },
12600
12601 Running {
12602 adapter: Arc<CachedLspAdapter>,
12603 server: Arc<LanguageServer>,
12604 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12605 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12606 },
12607}
12608
12609impl LanguageServerState {
12610 fn add_workspace_folder(&self, uri: Url) {
12611 match self {
12612 LanguageServerState::Starting {
12613 pending_workspace_folders,
12614 ..
12615 } => {
12616 pending_workspace_folders.lock().insert(uri);
12617 }
12618 LanguageServerState::Running { server, .. } => {
12619 server.add_workspace_folder(uri);
12620 }
12621 }
12622 }
12623 fn _remove_workspace_folder(&self, uri: Url) {
12624 match self {
12625 LanguageServerState::Starting {
12626 pending_workspace_folders,
12627 ..
12628 } => {
12629 pending_workspace_folders.lock().remove(&uri);
12630 }
12631 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12632 }
12633 }
12634}
12635
12636impl std::fmt::Debug for LanguageServerState {
12637 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12638 match self {
12639 LanguageServerState::Starting { .. } => {
12640 f.debug_struct("LanguageServerState::Starting").finish()
12641 }
12642 LanguageServerState::Running { .. } => {
12643 f.debug_struct("LanguageServerState::Running").finish()
12644 }
12645 }
12646 }
12647}
12648
12649#[derive(Clone, Debug, Serialize)]
12650pub struct LanguageServerProgress {
12651 pub is_disk_based_diagnostics_progress: bool,
12652 pub is_cancellable: bool,
12653 pub title: Option<String>,
12654 pub message: Option<String>,
12655 pub percentage: Option<usize>,
12656 #[serde(skip_serializing)]
12657 pub last_update_at: Instant,
12658}
12659
12660#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12661pub struct DiagnosticSummary {
12662 pub error_count: usize,
12663 pub warning_count: usize,
12664}
12665
12666impl DiagnosticSummary {
12667 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12668 let mut this = Self {
12669 error_count: 0,
12670 warning_count: 0,
12671 };
12672
12673 for entry in diagnostics {
12674 if entry.diagnostic.is_primary {
12675 match entry.diagnostic.severity {
12676 DiagnosticSeverity::ERROR => this.error_count += 1,
12677 DiagnosticSeverity::WARNING => this.warning_count += 1,
12678 _ => {}
12679 }
12680 }
12681 }
12682
12683 this
12684 }
12685
12686 pub fn is_empty(&self) -> bool {
12687 self.error_count == 0 && self.warning_count == 0
12688 }
12689
12690 pub fn to_proto(
12691 self,
12692 language_server_id: LanguageServerId,
12693 path: &Path,
12694 ) -> proto::DiagnosticSummary {
12695 proto::DiagnosticSummary {
12696 path: path.to_proto(),
12697 language_server_id: language_server_id.0 as u64,
12698 error_count: self.error_count as u32,
12699 warning_count: self.warning_count as u32,
12700 }
12701 }
12702}
12703
12704#[derive(Clone, Debug)]
12705pub enum CompletionDocumentation {
12706 /// There is no documentation for this completion.
12707 Undocumented,
12708 /// A single line of documentation.
12709 SingleLine(SharedString),
12710 /// Multiple lines of plain text documentation.
12711 MultiLinePlainText(SharedString),
12712 /// Markdown documentation.
12713 MultiLineMarkdown(SharedString),
12714 /// Both single line and multiple lines of plain text documentation.
12715 SingleLineAndMultiLinePlainText {
12716 single_line: SharedString,
12717 plain_text: Option<SharedString>,
12718 },
12719}
12720
12721impl From<lsp::Documentation> for CompletionDocumentation {
12722 fn from(docs: lsp::Documentation) -> Self {
12723 match docs {
12724 lsp::Documentation::String(text) => {
12725 if text.lines().count() <= 1 {
12726 CompletionDocumentation::SingleLine(text.into())
12727 } else {
12728 CompletionDocumentation::MultiLinePlainText(text.into())
12729 }
12730 }
12731
12732 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
12733 lsp::MarkupKind::PlainText => {
12734 if value.lines().count() <= 1 {
12735 CompletionDocumentation::SingleLine(value.into())
12736 } else {
12737 CompletionDocumentation::MultiLinePlainText(value.into())
12738 }
12739 }
12740
12741 lsp::MarkupKind::Markdown => {
12742 CompletionDocumentation::MultiLineMarkdown(value.into())
12743 }
12744 },
12745 }
12746 }
12747}
12748
12749fn glob_literal_prefix(glob: &Path) -> PathBuf {
12750 glob.components()
12751 .take_while(|component| match component {
12752 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
12753 _ => true,
12754 })
12755 .collect()
12756}
12757
12758pub struct SshLspAdapter {
12759 name: LanguageServerName,
12760 binary: LanguageServerBinary,
12761 initialization_options: Option<String>,
12762 code_action_kinds: Option<Vec<CodeActionKind>>,
12763}
12764
12765impl SshLspAdapter {
12766 pub fn new(
12767 name: LanguageServerName,
12768 binary: LanguageServerBinary,
12769 initialization_options: Option<String>,
12770 code_action_kinds: Option<String>,
12771 ) -> Self {
12772 Self {
12773 name,
12774 binary,
12775 initialization_options,
12776 code_action_kinds: code_action_kinds
12777 .as_ref()
12778 .and_then(|c| serde_json::from_str(c).ok()),
12779 }
12780 }
12781}
12782
12783#[async_trait(?Send)]
12784impl LspAdapter for SshLspAdapter {
12785 fn name(&self) -> LanguageServerName {
12786 self.name.clone()
12787 }
12788
12789 async fn initialization_options(
12790 self: Arc<Self>,
12791 _: &dyn Fs,
12792 _: &Arc<dyn LspAdapterDelegate>,
12793 ) -> Result<Option<serde_json::Value>> {
12794 let Some(options) = &self.initialization_options else {
12795 return Ok(None);
12796 };
12797 let result = serde_json::from_str(options)?;
12798 Ok(result)
12799 }
12800
12801 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
12802 self.code_action_kinds.clone()
12803 }
12804
12805 async fn check_if_user_installed(
12806 &self,
12807 _: &dyn LspAdapterDelegate,
12808 _: Option<Toolchain>,
12809 _: &AsyncApp,
12810 ) -> Option<LanguageServerBinary> {
12811 Some(self.binary.clone())
12812 }
12813
12814 async fn cached_server_binary(
12815 &self,
12816 _: PathBuf,
12817 _: &dyn LspAdapterDelegate,
12818 ) -> Option<LanguageServerBinary> {
12819 None
12820 }
12821
12822 async fn fetch_latest_server_version(
12823 &self,
12824 _: &dyn LspAdapterDelegate,
12825 ) -> Result<Box<dyn 'static + Send + Any>> {
12826 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
12827 }
12828
12829 async fn fetch_server_binary(
12830 &self,
12831 _: Box<dyn 'static + Send + Any>,
12832 _: PathBuf,
12833 _: &dyn LspAdapterDelegate,
12834 ) -> Result<LanguageServerBinary> {
12835 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
12836 }
12837}
12838
12839pub fn language_server_settings<'a>(
12840 delegate: &'a dyn LspAdapterDelegate,
12841 language: &LanguageServerName,
12842 cx: &'a App,
12843) -> Option<&'a LspSettings> {
12844 language_server_settings_for(
12845 SettingsLocation {
12846 worktree_id: delegate.worktree_id(),
12847 path: delegate.worktree_root_path(),
12848 },
12849 language,
12850 cx,
12851 )
12852}
12853
12854pub(crate) fn language_server_settings_for<'a>(
12855 location: SettingsLocation<'a>,
12856 language: &LanguageServerName,
12857 cx: &'a App,
12858) -> Option<&'a LspSettings> {
12859 ProjectSettings::get(Some(location), cx).lsp.get(language)
12860}
12861
12862pub struct LocalLspAdapterDelegate {
12863 lsp_store: WeakEntity<LspStore>,
12864 worktree: worktree::Snapshot,
12865 fs: Arc<dyn Fs>,
12866 http_client: Arc<dyn HttpClient>,
12867 language_registry: Arc<LanguageRegistry>,
12868 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
12869}
12870
12871impl LocalLspAdapterDelegate {
12872 pub fn new(
12873 language_registry: Arc<LanguageRegistry>,
12874 environment: &Entity<ProjectEnvironment>,
12875 lsp_store: WeakEntity<LspStore>,
12876 worktree: &Entity<Worktree>,
12877 http_client: Arc<dyn HttpClient>,
12878 fs: Arc<dyn Fs>,
12879 cx: &mut App,
12880 ) -> Arc<Self> {
12881 let load_shell_env_task = environment.update(cx, |env, cx| {
12882 env.get_worktree_environment(worktree.clone(), cx)
12883 });
12884
12885 Arc::new(Self {
12886 lsp_store,
12887 worktree: worktree.read(cx).snapshot(),
12888 fs,
12889 http_client,
12890 language_registry,
12891 load_shell_env_task,
12892 })
12893 }
12894
12895 fn from_local_lsp(
12896 local: &LocalLspStore,
12897 worktree: &Entity<Worktree>,
12898 cx: &mut App,
12899 ) -> Arc<Self> {
12900 Self::new(
12901 local.languages.clone(),
12902 &local.environment,
12903 local.weak.clone(),
12904 worktree,
12905 local.http_client.clone(),
12906 local.fs.clone(),
12907 cx,
12908 )
12909 }
12910}
12911
12912#[async_trait]
12913impl LspAdapterDelegate for LocalLspAdapterDelegate {
12914 fn show_notification(&self, message: &str, cx: &mut App) {
12915 self.lsp_store
12916 .update(cx, |_, cx| {
12917 cx.emit(LspStoreEvent::Notification(message.to_owned()))
12918 })
12919 .ok();
12920 }
12921
12922 fn http_client(&self) -> Arc<dyn HttpClient> {
12923 self.http_client.clone()
12924 }
12925
12926 fn worktree_id(&self) -> WorktreeId {
12927 self.worktree.id()
12928 }
12929
12930 fn worktree_root_path(&self) -> &Path {
12931 self.worktree.abs_path().as_ref()
12932 }
12933
12934 async fn shell_env(&self) -> HashMap<String, String> {
12935 let task = self.load_shell_env_task.clone();
12936 task.await.unwrap_or_default()
12937 }
12938
12939 async fn npm_package_installed_version(
12940 &self,
12941 package_name: &str,
12942 ) -> Result<Option<(PathBuf, String)>> {
12943 let local_package_directory = self.worktree_root_path();
12944 let node_modules_directory = local_package_directory.join("node_modules");
12945
12946 if let Some(version) =
12947 read_package_installed_version(node_modules_directory.clone(), package_name).await?
12948 {
12949 return Ok(Some((node_modules_directory, version)));
12950 }
12951 let Some(npm) = self.which("npm".as_ref()).await else {
12952 log::warn!(
12953 "Failed to find npm executable for {:?}",
12954 local_package_directory
12955 );
12956 return Ok(None);
12957 };
12958
12959 let env = self.shell_env().await;
12960 let output = util::command::new_smol_command(&npm)
12961 .args(["root", "-g"])
12962 .envs(env)
12963 .current_dir(local_package_directory)
12964 .output()
12965 .await?;
12966 let global_node_modules =
12967 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
12968
12969 if let Some(version) =
12970 read_package_installed_version(global_node_modules.clone(), package_name).await?
12971 {
12972 return Ok(Some((global_node_modules, version)));
12973 }
12974 return Ok(None);
12975 }
12976
12977 #[cfg(not(target_os = "windows"))]
12978 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12979 let worktree_abs_path = self.worktree.abs_path();
12980 let shell_path = self.shell_env().await.get("PATH").cloned();
12981 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
12982 }
12983
12984 #[cfg(target_os = "windows")]
12985 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12986 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
12987 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
12988 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
12989 which::which(command).ok()
12990 }
12991
12992 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
12993 let working_dir = self.worktree_root_path();
12994 let output = util::command::new_smol_command(&command.path)
12995 .args(command.arguments)
12996 .envs(command.env.clone().unwrap_or_default())
12997 .current_dir(working_dir)
12998 .output()
12999 .await?;
13000
13001 anyhow::ensure!(
13002 output.status.success(),
13003 "{}, stdout: {:?}, stderr: {:?}",
13004 output.status,
13005 String::from_utf8_lossy(&output.stdout),
13006 String::from_utf8_lossy(&output.stderr)
13007 );
13008 Ok(())
13009 }
13010
13011 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13012 self.language_registry
13013 .update_lsp_binary_status(server_name, status);
13014 }
13015
13016 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13017 self.language_registry
13018 .all_lsp_adapters()
13019 .into_iter()
13020 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13021 .collect()
13022 }
13023
13024 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13025 let dir = self.language_registry.language_server_download_dir(name)?;
13026
13027 if !dir.exists() {
13028 smol::fs::create_dir_all(&dir)
13029 .await
13030 .context("failed to create container directory")
13031 .log_err()?;
13032 }
13033
13034 Some(dir)
13035 }
13036
13037 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
13038 let entry = self
13039 .worktree
13040 .entry_for_path(&path)
13041 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13042 let abs_path = self
13043 .worktree
13044 .absolutize(&entry.path)
13045 .with_context(|| format!("cannot absolutize path {path:?}"))?;
13046
13047 self.fs.load(&abs_path).await
13048 }
13049}
13050
13051async fn populate_labels_for_symbols(
13052 symbols: Vec<CoreSymbol>,
13053 language_registry: &Arc<LanguageRegistry>,
13054 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13055 output: &mut Vec<Symbol>,
13056) {
13057 #[allow(clippy::mutable_key_type)]
13058 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13059
13060 let mut unknown_paths = BTreeSet::new();
13061 for symbol in symbols {
13062 let language = language_registry
13063 .language_for_file_path(&symbol.path.path)
13064 .await
13065 .ok()
13066 .or_else(|| {
13067 unknown_paths.insert(symbol.path.path.clone());
13068 None
13069 });
13070 symbols_by_language
13071 .entry(language)
13072 .or_default()
13073 .push(symbol);
13074 }
13075
13076 for unknown_path in unknown_paths {
13077 log::info!(
13078 "no language found for symbol path {}",
13079 unknown_path.display()
13080 );
13081 }
13082
13083 let mut label_params = Vec::new();
13084 for (language, mut symbols) in symbols_by_language {
13085 label_params.clear();
13086 label_params.extend(
13087 symbols
13088 .iter_mut()
13089 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13090 );
13091
13092 let mut labels = Vec::new();
13093 if let Some(language) = language {
13094 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13095 language_registry
13096 .lsp_adapters(&language.name())
13097 .first()
13098 .cloned()
13099 });
13100 if let Some(lsp_adapter) = lsp_adapter {
13101 labels = lsp_adapter
13102 .labels_for_symbols(&label_params, &language)
13103 .await
13104 .log_err()
13105 .unwrap_or_default();
13106 }
13107 }
13108
13109 for ((symbol, (name, _)), label) in symbols
13110 .into_iter()
13111 .zip(label_params.drain(..))
13112 .zip(labels.into_iter().chain(iter::repeat(None)))
13113 {
13114 output.push(Symbol {
13115 language_server_name: symbol.language_server_name,
13116 source_worktree_id: symbol.source_worktree_id,
13117 source_language_server_id: symbol.source_language_server_id,
13118 path: symbol.path,
13119 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13120 name,
13121 kind: symbol.kind,
13122 range: symbol.range,
13123 signature: symbol.signature,
13124 });
13125 }
13126 }
13127}
13128
13129fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13130 match server.capabilities().text_document_sync.as_ref()? {
13131 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13132 // Server wants didSave but didn't specify includeText.
13133 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13134 // Server doesn't want didSave at all.
13135 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13136 // Server provided SaveOptions.
13137 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13138 Some(save_options.include_text.unwrap_or(false))
13139 }
13140 },
13141 // We do not have any save info. Kind affects didChange only.
13142 lsp::TextDocumentSyncCapability::Kind(_) => None,
13143 }
13144}
13145
13146/// Completion items are displayed in a `UniformList`.
13147/// Usually, those items are single-line strings, but in LSP responses,
13148/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13149/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13150/// All that may lead to a newline being inserted into resulting `CodeLabel.text`, which will force `UniformList` to bloat each entry to occupy more space,
13151/// breaking the completions menu presentation.
13152///
13153/// Sanitize the text to ensure there are no newlines, or, if there are some, remove them and also remove long space sequences if there were newlines.
13154fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13155 let mut new_text = String::with_capacity(label.text.len());
13156 let mut offset_map = vec![0; label.text.len() + 1];
13157 let mut last_char_was_space = false;
13158 let mut new_idx = 0;
13159 let mut chars = label.text.char_indices().fuse();
13160 let mut newlines_removed = false;
13161
13162 while let Some((idx, c)) = chars.next() {
13163 offset_map[idx] = new_idx;
13164
13165 match c {
13166 '\n' if last_char_was_space => {
13167 newlines_removed = true;
13168 }
13169 '\t' | ' ' if last_char_was_space => {}
13170 '\n' if !last_char_was_space => {
13171 new_text.push(' ');
13172 new_idx += 1;
13173 last_char_was_space = true;
13174 newlines_removed = true;
13175 }
13176 ' ' | '\t' => {
13177 new_text.push(' ');
13178 new_idx += 1;
13179 last_char_was_space = true;
13180 }
13181 _ => {
13182 new_text.push(c);
13183 new_idx += c.len_utf8();
13184 last_char_was_space = false;
13185 }
13186 }
13187 }
13188 offset_map[label.text.len()] = new_idx;
13189
13190 // Only modify the label if newlines were removed.
13191 if !newlines_removed {
13192 return;
13193 }
13194
13195 let last_index = new_idx;
13196 let mut run_ranges_errors = Vec::new();
13197 label.runs.retain_mut(|(range, _)| {
13198 match offset_map.get(range.start) {
13199 Some(&start) => range.start = start,
13200 None => {
13201 run_ranges_errors.push(range.clone());
13202 return false;
13203 }
13204 }
13205
13206 match offset_map.get(range.end) {
13207 Some(&end) => range.end = end,
13208 None => {
13209 run_ranges_errors.push(range.clone());
13210 range.end = last_index;
13211 }
13212 }
13213 true
13214 });
13215 if !run_ranges_errors.is_empty() {
13216 log::error!(
13217 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13218 label.text
13219 );
13220 }
13221
13222 let mut wrong_filter_range = None;
13223 if label.filter_range == (0..label.text.len()) {
13224 label.filter_range = 0..new_text.len();
13225 } else {
13226 let mut original_filter_range = Some(label.filter_range.clone());
13227 match offset_map.get(label.filter_range.start) {
13228 Some(&start) => label.filter_range.start = start,
13229 None => {
13230 wrong_filter_range = original_filter_range.take();
13231 label.filter_range.start = last_index;
13232 }
13233 }
13234
13235 match offset_map.get(label.filter_range.end) {
13236 Some(&end) => label.filter_range.end = end,
13237 None => {
13238 wrong_filter_range = original_filter_range.take();
13239 label.filter_range.end = last_index;
13240 }
13241 }
13242 }
13243 if let Some(wrong_filter_range) = wrong_filter_range {
13244 log::error!(
13245 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13246 label.text
13247 );
13248 }
13249
13250 label.text = new_text;
13251}
13252
13253#[cfg(test)]
13254mod tests {
13255 use language::HighlightId;
13256
13257 use super::*;
13258
13259 #[test]
13260 fn test_glob_literal_prefix() {
13261 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13262 assert_eq!(
13263 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13264 Path::new("node_modules")
13265 );
13266 assert_eq!(
13267 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13268 Path::new("foo")
13269 );
13270 assert_eq!(
13271 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13272 Path::new("foo/bar/baz.js")
13273 );
13274
13275 #[cfg(target_os = "windows")]
13276 {
13277 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13278 assert_eq!(
13279 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13280 Path::new("node_modules")
13281 );
13282 assert_eq!(
13283 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13284 Path::new("foo")
13285 );
13286 assert_eq!(
13287 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13288 Path::new("foo/bar/baz.js")
13289 );
13290 }
13291 }
13292
13293 #[test]
13294 fn test_multi_len_chars_normalization() {
13295 let mut label = CodeLabel {
13296 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13297 runs: vec![(0..6, HighlightId(1))],
13298 filter_range: 0..6,
13299 };
13300 ensure_uniform_list_compatible_label(&mut label);
13301 assert_eq!(
13302 label,
13303 CodeLabel {
13304 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13305 runs: vec![(0..6, HighlightId(1))],
13306 filter_range: 0..6,
13307 }
13308 );
13309 }
13310}