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 => self.request_workspace_config_refresh(),
3928 }
3929 }
3930
3931 fn request_workspace_config_refresh(&mut self) {
3932 *self._maintain_workspace_config.1.borrow_mut() = ();
3933 }
3934
3935 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
3936 self.as_local().map(|local| local.prettier_store.clone())
3937 }
3938
3939 fn on_buffer_event(
3940 &mut self,
3941 buffer: Entity<Buffer>,
3942 event: &language::BufferEvent,
3943 cx: &mut Context<Self>,
3944 ) {
3945 match event {
3946 language::BufferEvent::Edited => {
3947 self.on_buffer_edited(buffer, cx);
3948 }
3949
3950 language::BufferEvent::Saved => {
3951 self.on_buffer_saved(buffer, cx);
3952 }
3953
3954 _ => {}
3955 }
3956 }
3957
3958 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
3959 buffer
3960 .read(cx)
3961 .set_language_registry(self.languages.clone());
3962
3963 cx.subscribe(buffer, |this, buffer, event, cx| {
3964 this.on_buffer_event(buffer, event, cx);
3965 })
3966 .detach();
3967
3968 self.detect_language_for_buffer(buffer, cx);
3969 if let Some(local) = self.as_local_mut() {
3970 local.initialize_buffer(buffer, cx);
3971 }
3972
3973 Ok(())
3974 }
3975
3976 pub fn reload_zed_json_schemas_on_extensions_changed(
3977 &mut self,
3978 _: Entity<extension::ExtensionEvents>,
3979 evt: &extension::Event,
3980 cx: &mut Context<Self>,
3981 ) {
3982 match evt {
3983 extension::Event::ExtensionInstalled(_)
3984 | extension::Event::ExtensionUninstalled(_)
3985 | extension::Event::ConfigureExtensionRequested(_) => return,
3986 extension::Event::ExtensionsInstalledChanged => {}
3987 }
3988 if self.as_local().is_none() {
3989 return;
3990 }
3991 cx.spawn(async move |this, cx| {
3992 let weak_ref = this.clone();
3993
3994 let servers = this
3995 .update(cx, |this, cx| {
3996 let local = this.as_local()?;
3997
3998 let mut servers = Vec::new();
3999 for (seed, state) in &local.language_server_ids {
4000
4001 let Some(states) = local.language_servers.get(&state.id) else {
4002 continue;
4003 };
4004 let (json_adapter, json_server) = match states {
4005 LanguageServerState::Running {
4006 adapter, server, ..
4007 } if adapter.adapter.is_primary_zed_json_schema_adapter() => {
4008 (adapter.adapter.clone(), server.clone())
4009 }
4010 _ => continue,
4011 };
4012
4013 let Some(worktree) = this
4014 .worktree_store
4015 .read(cx)
4016 .worktree_for_id(seed.worktree_id, cx)
4017 else {
4018 continue;
4019 };
4020 let json_delegate: Arc<dyn LspAdapterDelegate> =
4021 LocalLspAdapterDelegate::new(
4022 local.languages.clone(),
4023 &local.environment,
4024 weak_ref.clone(),
4025 &worktree,
4026 local.http_client.clone(),
4027 local.fs.clone(),
4028 cx,
4029 );
4030
4031 servers.push((json_adapter, json_server, json_delegate));
4032
4033 }
4034 Some(servers)
4035 })
4036 .ok()
4037 .flatten();
4038
4039 let Some(servers) = servers else {
4040 return;
4041 };
4042
4043 let Ok(Some((fs, _))) = this.read_with(cx, |this, _| {
4044 let local = this.as_local()?;
4045 let toolchain_store = local.toolchain_store().clone();
4046 Some((local.fs.clone(), toolchain_store))
4047 }) else {
4048 return;
4049 };
4050 for (adapter, server, delegate) in servers {
4051 adapter.clear_zed_json_schema_cache().await;
4052
4053 let Some(json_workspace_config) = LocalLspStore::workspace_configuration_for_adapter(
4054 adapter,
4055 fs.as_ref(),
4056 &delegate,
4057 None,
4058 cx,
4059 )
4060 .await
4061 .context("generate new workspace configuration for JSON language server while trying to refresh JSON Schemas")
4062 .ok()
4063 else {
4064 continue;
4065 };
4066 server
4067 .notify::<lsp::notification::DidChangeConfiguration>(
4068 &lsp::DidChangeConfigurationParams {
4069 settings: json_workspace_config,
4070 },
4071 )
4072 .ok();
4073 }
4074 })
4075 .detach();
4076 }
4077
4078 pub(crate) fn register_buffer_with_language_servers(
4079 &mut self,
4080 buffer: &Entity<Buffer>,
4081 only_register_servers: HashSet<LanguageServerSelector>,
4082 ignore_refcounts: bool,
4083 cx: &mut Context<Self>,
4084 ) -> OpenLspBufferHandle {
4085 let buffer_id = buffer.read(cx).remote_id();
4086 let handle = cx.new(|_| buffer.clone());
4087 if let Some(local) = self.as_local_mut() {
4088 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4089 if !ignore_refcounts {
4090 *refcount += 1;
4091 }
4092
4093 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4094 // 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
4095 // 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
4096 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4097 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4098 return handle;
4099 };
4100 if !file.is_local() {
4101 return handle;
4102 }
4103
4104 if ignore_refcounts || *refcount == 1 {
4105 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4106 }
4107 if !ignore_refcounts {
4108 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4109 let refcount = {
4110 let local = lsp_store.as_local_mut().unwrap();
4111 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4112 debug_panic!("bad refcounting");
4113 return;
4114 };
4115
4116 *refcount -= 1;
4117 *refcount
4118 };
4119 if refcount == 0 {
4120 lsp_store.lsp_document_colors.remove(&buffer_id);
4121 lsp_store.lsp_code_lens.remove(&buffer_id);
4122 let local = lsp_store.as_local_mut().unwrap();
4123 local.registered_buffers.remove(&buffer_id);
4124 local.buffers_opened_in_servers.remove(&buffer_id);
4125 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4126 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4127 }
4128 }
4129 })
4130 .detach();
4131 }
4132 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4133 let buffer_id = buffer.read(cx).remote_id().to_proto();
4134 cx.background_spawn(async move {
4135 upstream_client
4136 .request(proto::RegisterBufferWithLanguageServers {
4137 project_id: upstream_project_id,
4138 buffer_id,
4139 only_servers: only_register_servers
4140 .into_iter()
4141 .map(|selector| {
4142 let selector = match selector {
4143 LanguageServerSelector::Id(language_server_id) => {
4144 proto::language_server_selector::Selector::ServerId(
4145 language_server_id.to_proto(),
4146 )
4147 }
4148 LanguageServerSelector::Name(language_server_name) => {
4149 proto::language_server_selector::Selector::Name(
4150 language_server_name.to_string(),
4151 )
4152 }
4153 };
4154 proto::LanguageServerSelector {
4155 selector: Some(selector),
4156 }
4157 })
4158 .collect(),
4159 })
4160 .await
4161 })
4162 .detach();
4163 } else {
4164 panic!("oops!");
4165 }
4166 handle
4167 }
4168
4169 fn maintain_buffer_languages(
4170 languages: Arc<LanguageRegistry>,
4171 cx: &mut Context<Self>,
4172 ) -> Task<()> {
4173 let mut subscription = languages.subscribe();
4174 let mut prev_reload_count = languages.reload_count();
4175 cx.spawn(async move |this, cx| {
4176 while let Some(()) = subscription.next().await {
4177 if let Some(this) = this.upgrade() {
4178 // If the language registry has been reloaded, then remove and
4179 // re-assign the languages on all open buffers.
4180 let reload_count = languages.reload_count();
4181 if reload_count > prev_reload_count {
4182 prev_reload_count = reload_count;
4183 this.update(cx, |this, cx| {
4184 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4185 for buffer in buffer_store.buffers() {
4186 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4187 {
4188 buffer
4189 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4190 if let Some(local) = this.as_local_mut() {
4191 local.reset_buffer(&buffer, &f, cx);
4192
4193 if local
4194 .registered_buffers
4195 .contains_key(&buffer.read(cx).remote_id())
4196 && let Some(file_url) =
4197 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4198 {
4199 local.unregister_buffer_from_language_servers(
4200 &buffer, &file_url, cx,
4201 );
4202 }
4203 }
4204 }
4205 }
4206 });
4207 })
4208 .ok();
4209 }
4210
4211 this.update(cx, |this, cx| {
4212 let mut plain_text_buffers = Vec::new();
4213 let mut buffers_with_unknown_injections = Vec::new();
4214 for handle in this.buffer_store.read(cx).buffers() {
4215 let buffer = handle.read(cx);
4216 if buffer.language().is_none()
4217 || buffer.language() == Some(&*language::PLAIN_TEXT)
4218 {
4219 plain_text_buffers.push(handle);
4220 } else if buffer.contains_unknown_injections() {
4221 buffers_with_unknown_injections.push(handle);
4222 }
4223 }
4224
4225 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4226 // and reused later in the invisible worktrees.
4227 plain_text_buffers.sort_by_key(|buffer| {
4228 Reverse(
4229 File::from_dyn(buffer.read(cx).file())
4230 .map(|file| file.worktree.read(cx).is_visible()),
4231 )
4232 });
4233
4234 for buffer in plain_text_buffers {
4235 this.detect_language_for_buffer(&buffer, cx);
4236 if let Some(local) = this.as_local_mut() {
4237 local.initialize_buffer(&buffer, cx);
4238 if local
4239 .registered_buffers
4240 .contains_key(&buffer.read(cx).remote_id())
4241 {
4242 local.register_buffer_with_language_servers(
4243 &buffer,
4244 HashSet::default(),
4245 cx,
4246 );
4247 }
4248 }
4249 }
4250
4251 for buffer in buffers_with_unknown_injections {
4252 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4253 }
4254 })
4255 .ok();
4256 }
4257 }
4258 })
4259 }
4260
4261 fn detect_language_for_buffer(
4262 &mut self,
4263 buffer_handle: &Entity<Buffer>,
4264 cx: &mut Context<Self>,
4265 ) -> Option<language::AvailableLanguage> {
4266 // If the buffer has a language, set it and start the language server if we haven't already.
4267 let buffer = buffer_handle.read(cx);
4268 let file = buffer.file()?;
4269
4270 let content = buffer.as_rope();
4271 let available_language = self.languages.language_for_file(file, Some(content), cx);
4272 if let Some(available_language) = &available_language {
4273 if let Some(Ok(Ok(new_language))) = self
4274 .languages
4275 .load_language(available_language)
4276 .now_or_never()
4277 {
4278 self.set_language_for_buffer(buffer_handle, new_language, cx);
4279 }
4280 } else {
4281 cx.emit(LspStoreEvent::LanguageDetected {
4282 buffer: buffer_handle.clone(),
4283 new_language: None,
4284 });
4285 }
4286
4287 available_language
4288 }
4289
4290 pub(crate) fn set_language_for_buffer(
4291 &mut self,
4292 buffer_entity: &Entity<Buffer>,
4293 new_language: Arc<Language>,
4294 cx: &mut Context<Self>,
4295 ) {
4296 let buffer = buffer_entity.read(cx);
4297 let buffer_file = buffer.file().cloned();
4298 let buffer_id = buffer.remote_id();
4299 if let Some(local_store) = self.as_local_mut()
4300 && local_store.registered_buffers.contains_key(&buffer_id)
4301 && let Some(abs_path) =
4302 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4303 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4304 {
4305 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4306 }
4307 buffer_entity.update(cx, |buffer, cx| {
4308 if buffer
4309 .language()
4310 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4311 {
4312 buffer.set_language(Some(new_language.clone()), cx);
4313 }
4314 });
4315
4316 let settings =
4317 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4318 let buffer_file = File::from_dyn(buffer_file.as_ref());
4319
4320 let worktree_id = if let Some(file) = buffer_file {
4321 let worktree = file.worktree.clone();
4322
4323 if let Some(local) = self.as_local_mut()
4324 && local.registered_buffers.contains_key(&buffer_id)
4325 {
4326 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4327 }
4328 Some(worktree.read(cx).id())
4329 } else {
4330 None
4331 };
4332
4333 if settings.prettier.allowed
4334 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4335 {
4336 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4337 if let Some(prettier_store) = prettier_store {
4338 prettier_store.update(cx, |prettier_store, cx| {
4339 prettier_store.install_default_prettier(
4340 worktree_id,
4341 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4342 cx,
4343 )
4344 })
4345 }
4346 }
4347
4348 cx.emit(LspStoreEvent::LanguageDetected {
4349 buffer: buffer_entity.clone(),
4350 new_language: Some(new_language),
4351 })
4352 }
4353
4354 pub fn buffer_store(&self) -> Entity<BufferStore> {
4355 self.buffer_store.clone()
4356 }
4357
4358 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4359 self.active_entry = active_entry;
4360 }
4361
4362 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4363 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4364 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4365 {
4366 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4367 summaries
4368 .iter()
4369 .map(|(server_id, summary)| summary.to_proto(*server_id, path))
4370 });
4371 if let Some(summary) = summaries.next() {
4372 client
4373 .send(proto::UpdateDiagnosticSummary {
4374 project_id: downstream_project_id,
4375 worktree_id: worktree.id().to_proto(),
4376 summary: Some(summary),
4377 more_summaries: summaries.collect(),
4378 })
4379 .log_err();
4380 }
4381 }
4382 }
4383
4384 // TODO: remove MultiLspQuery: instead, the proto handler should pick appropriate server(s)
4385 // Then, use `send_lsp_proto_request` or analogue for most of the LSP proto requests and inline this check inside
4386 fn is_capable_for_proto_request<R>(
4387 &self,
4388 buffer: &Entity<Buffer>,
4389 request: &R,
4390 cx: &Context<Self>,
4391 ) -> bool
4392 where
4393 R: LspCommand,
4394 {
4395 self.check_if_capable_for_proto_request(
4396 buffer,
4397 |capabilities| {
4398 request.check_capabilities(AdapterServerCapabilities {
4399 server_capabilities: capabilities.clone(),
4400 code_action_kinds: None,
4401 })
4402 },
4403 cx,
4404 )
4405 }
4406
4407 fn check_if_capable_for_proto_request<F>(
4408 &self,
4409 buffer: &Entity<Buffer>,
4410 check: F,
4411 cx: &Context<Self>,
4412 ) -> bool
4413 where
4414 F: Fn(&lsp::ServerCapabilities) -> bool,
4415 {
4416 let Some(language) = buffer.read(cx).language().cloned() else {
4417 return false;
4418 };
4419 let relevant_language_servers = self
4420 .languages
4421 .lsp_adapters(&language.name())
4422 .into_iter()
4423 .map(|lsp_adapter| lsp_adapter.name())
4424 .collect::<HashSet<_>>();
4425 self.language_server_statuses
4426 .iter()
4427 .filter_map(|(server_id, server_status)| {
4428 relevant_language_servers
4429 .contains(&server_status.name)
4430 .then_some(server_id)
4431 })
4432 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4433 .any(check)
4434 }
4435
4436 pub fn request_lsp<R>(
4437 &mut self,
4438 buffer: Entity<Buffer>,
4439 server: LanguageServerToQuery,
4440 request: R,
4441 cx: &mut Context<Self>,
4442 ) -> Task<Result<R::Response>>
4443 where
4444 R: LspCommand,
4445 <R::LspRequest as lsp::request::Request>::Result: Send,
4446 <R::LspRequest as lsp::request::Request>::Params: Send,
4447 {
4448 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4449 return self.send_lsp_proto_request(
4450 buffer,
4451 upstream_client,
4452 upstream_project_id,
4453 request,
4454 cx,
4455 );
4456 }
4457
4458 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4459 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4460 local
4461 .language_servers_for_buffer(buffer, cx)
4462 .find(|(_, server)| {
4463 request.check_capabilities(server.adapter_server_capabilities())
4464 })
4465 .map(|(_, server)| server.clone())
4466 }),
4467 LanguageServerToQuery::Other(id) => self
4468 .language_server_for_local_buffer(buffer, id, cx)
4469 .and_then(|(_, server)| {
4470 request
4471 .check_capabilities(server.adapter_server_capabilities())
4472 .then(|| Arc::clone(server))
4473 }),
4474 }) else {
4475 return Task::ready(Ok(Default::default()));
4476 };
4477
4478 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4479
4480 let Some(file) = file else {
4481 return Task::ready(Ok(Default::default()));
4482 };
4483
4484 let lsp_params = match request.to_lsp_params_or_response(
4485 &file.abs_path(cx),
4486 buffer.read(cx),
4487 &language_server,
4488 cx,
4489 ) {
4490 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4491 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4492
4493 Err(err) => {
4494 let message = format!(
4495 "{} via {} failed: {}",
4496 request.display_name(),
4497 language_server.name(),
4498 err
4499 );
4500 log::warn!("{message}");
4501 return Task::ready(Err(anyhow!(message)));
4502 }
4503 };
4504
4505 let status = request.status();
4506 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4507 return Task::ready(Ok(Default::default()));
4508 }
4509 cx.spawn(async move |this, cx| {
4510 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4511
4512 let id = lsp_request.id();
4513 let _cleanup = if status.is_some() {
4514 cx.update(|cx| {
4515 this.update(cx, |this, cx| {
4516 this.on_lsp_work_start(
4517 language_server.server_id(),
4518 id.to_string(),
4519 LanguageServerProgress {
4520 is_disk_based_diagnostics_progress: false,
4521 is_cancellable: false,
4522 title: None,
4523 message: status.clone(),
4524 percentage: None,
4525 last_update_at: cx.background_executor().now(),
4526 },
4527 cx,
4528 );
4529 })
4530 })
4531 .log_err();
4532
4533 Some(defer(|| {
4534 cx.update(|cx| {
4535 this.update(cx, |this, cx| {
4536 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4537 })
4538 })
4539 .log_err();
4540 }))
4541 } else {
4542 None
4543 };
4544
4545 let result = lsp_request.await.into_response();
4546
4547 let response = result.map_err(|err| {
4548 let message = format!(
4549 "{} via {} failed: {}",
4550 request.display_name(),
4551 language_server.name(),
4552 err
4553 );
4554 log::warn!("{message}");
4555 anyhow::anyhow!(message)
4556 })?;
4557
4558 request
4559 .response_from_lsp(
4560 response,
4561 this.upgrade().context("no app context")?,
4562 buffer,
4563 language_server.server_id(),
4564 cx.clone(),
4565 )
4566 .await
4567 })
4568 }
4569
4570 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4571 let mut language_formatters_to_check = Vec::new();
4572 for buffer in self.buffer_store.read(cx).buffers() {
4573 let buffer = buffer.read(cx);
4574 let buffer_file = File::from_dyn(buffer.file());
4575 let buffer_language = buffer.language();
4576 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4577 if buffer_language.is_some() {
4578 language_formatters_to_check.push((
4579 buffer_file.map(|f| f.worktree_id(cx)),
4580 settings.into_owned(),
4581 ));
4582 }
4583 }
4584
4585 self.request_workspace_config_refresh();
4586
4587 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4588 prettier_store.update(cx, |prettier_store, cx| {
4589 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4590 })
4591 }
4592
4593 cx.notify();
4594 }
4595
4596 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4597 let buffer_store = self.buffer_store.clone();
4598 let Some(local) = self.as_local_mut() else {
4599 return;
4600 };
4601 let mut adapters = BTreeMap::default();
4602 let get_adapter = {
4603 let languages = local.languages.clone();
4604 let environment = local.environment.clone();
4605 let weak = local.weak.clone();
4606 let worktree_store = local.worktree_store.clone();
4607 let http_client = local.http_client.clone();
4608 let fs = local.fs.clone();
4609 move |worktree_id, cx: &mut App| {
4610 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4611 Some(LocalLspAdapterDelegate::new(
4612 languages.clone(),
4613 &environment,
4614 weak.clone(),
4615 &worktree,
4616 http_client.clone(),
4617 fs.clone(),
4618 cx,
4619 ))
4620 }
4621 };
4622
4623 let mut messages_to_report = Vec::new();
4624 let (new_tree, to_stop) = {
4625 let mut rebase = local.lsp_tree.rebase();
4626 let buffers = buffer_store
4627 .read(cx)
4628 .buffers()
4629 .filter_map(|buffer| {
4630 let raw_buffer = buffer.read(cx);
4631 if !local
4632 .registered_buffers
4633 .contains_key(&raw_buffer.remote_id())
4634 {
4635 return None;
4636 }
4637 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4638 let language = raw_buffer.language().cloned()?;
4639 Some((file, language, raw_buffer.remote_id()))
4640 })
4641 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4642
4643 for (file, language, buffer_id) in buffers {
4644 let worktree_id = file.worktree_id(cx);
4645 let Some(worktree) = local
4646 .worktree_store
4647 .read(cx)
4648 .worktree_for_id(worktree_id, cx)
4649 else {
4650 continue;
4651 };
4652
4653 if let Some((_, apply)) = local.reuse_existing_language_server(
4654 rebase.server_tree(),
4655 &worktree,
4656 &language.name(),
4657 cx,
4658 ) {
4659 (apply)(rebase.server_tree());
4660 } else if let Some(lsp_delegate) = adapters
4661 .entry(worktree_id)
4662 .or_insert_with(|| get_adapter(worktree_id, cx))
4663 .clone()
4664 {
4665 let delegate =
4666 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4667 let path = file
4668 .path()
4669 .parent()
4670 .map(Arc::from)
4671 .unwrap_or_else(|| file.path().clone());
4672 let worktree_path = ProjectPath { worktree_id, path };
4673 let abs_path = file.abs_path(cx);
4674 let worktree_root = worktree.read(cx).abs_path();
4675 let nodes = rebase
4676 .walk(
4677 worktree_path,
4678 language.name(),
4679 language.manifest(),
4680 delegate.clone(),
4681 cx,
4682 )
4683 .collect::<Vec<_>>();
4684
4685 for node in nodes {
4686 let server_id = node.server_id_or_init(|disposition| {
4687 let path = &disposition.path;
4688 let uri = Url::from_file_path(worktree_root.join(&path.path));
4689 let key = LanguageServerSeed {
4690 worktree_id,
4691 name: disposition.server_name.clone(),
4692 settings: disposition.settings.clone(),
4693 toolchain: local.toolchain_store.read(cx).active_toolchain(
4694 path.worktree_id,
4695 &path.path,
4696 language.name(),
4697 ),
4698 };
4699 local.language_server_ids.remove(&key);
4700
4701 let server_id = local.get_or_insert_language_server(
4702 &worktree,
4703 lsp_delegate.clone(),
4704 disposition,
4705 &language.name(),
4706 cx,
4707 );
4708 if let Some(state) = local.language_servers.get(&server_id)
4709 && let Ok(uri) = uri
4710 {
4711 state.add_workspace_folder(uri);
4712 };
4713 server_id
4714 });
4715
4716 if let Some(language_server_id) = server_id {
4717 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4718 language_server_id,
4719 name: node.name(),
4720 message:
4721 proto::update_language_server::Variant::RegisteredForBuffer(
4722 proto::RegisteredForBuffer {
4723 buffer_abs_path: abs_path.to_string_lossy().to_string(),
4724 buffer_id: buffer_id.to_proto(),
4725 },
4726 ),
4727 });
4728 }
4729 }
4730 } else {
4731 continue;
4732 }
4733 }
4734 rebase.finish()
4735 };
4736 for message in messages_to_report {
4737 cx.emit(message);
4738 }
4739 local.lsp_tree = new_tree;
4740 for (id, _) in to_stop {
4741 self.stop_local_language_server(id, cx).detach();
4742 }
4743 }
4744
4745 pub fn apply_code_action(
4746 &self,
4747 buffer_handle: Entity<Buffer>,
4748 mut action: CodeAction,
4749 push_to_history: bool,
4750 cx: &mut Context<Self>,
4751 ) -> Task<Result<ProjectTransaction>> {
4752 if let Some((upstream_client, project_id)) = self.upstream_client() {
4753 let request = proto::ApplyCodeAction {
4754 project_id,
4755 buffer_id: buffer_handle.read(cx).remote_id().into(),
4756 action: Some(Self::serialize_code_action(&action)),
4757 };
4758 let buffer_store = self.buffer_store();
4759 cx.spawn(async move |_, cx| {
4760 let response = upstream_client
4761 .request(request)
4762 .await?
4763 .transaction
4764 .context("missing transaction")?;
4765
4766 buffer_store
4767 .update(cx, |buffer_store, cx| {
4768 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4769 })?
4770 .await
4771 })
4772 } else if self.mode.is_local() {
4773 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4774 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4775 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4776 }) else {
4777 return Task::ready(Ok(ProjectTransaction::default()));
4778 };
4779 cx.spawn(async move |this, cx| {
4780 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4781 .await
4782 .context("resolving a code action")?;
4783 if let Some(edit) = action.lsp_action.edit()
4784 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4785 return LocalLspStore::deserialize_workspace_edit(
4786 this.upgrade().context("no app present")?,
4787 edit.clone(),
4788 push_to_history,
4789
4790 lang_server.clone(),
4791 cx,
4792 )
4793 .await;
4794 }
4795
4796 if let Some(command) = action.lsp_action.command() {
4797 let server_capabilities = lang_server.capabilities();
4798 let available_commands = server_capabilities
4799 .execute_command_provider
4800 .as_ref()
4801 .map(|options| options.commands.as_slice())
4802 .unwrap_or_default();
4803 if available_commands.contains(&command.command) {
4804 this.update(cx, |this, _| {
4805 this.as_local_mut()
4806 .unwrap()
4807 .last_workspace_edits_by_language_server
4808 .remove(&lang_server.server_id());
4809 })?;
4810
4811 let _result = lang_server
4812 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4813 command: command.command.clone(),
4814 arguments: command.arguments.clone().unwrap_or_default(),
4815 ..lsp::ExecuteCommandParams::default()
4816 })
4817 .await.into_response()
4818 .context("execute command")?;
4819
4820 return this.update(cx, |this, _| {
4821 this.as_local_mut()
4822 .unwrap()
4823 .last_workspace_edits_by_language_server
4824 .remove(&lang_server.server_id())
4825 .unwrap_or_default()
4826 });
4827 } else {
4828 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4829 }
4830 }
4831
4832 Ok(ProjectTransaction::default())
4833 })
4834 } else {
4835 Task::ready(Err(anyhow!("no upstream client and not local")))
4836 }
4837 }
4838
4839 pub fn apply_code_action_kind(
4840 &mut self,
4841 buffers: HashSet<Entity<Buffer>>,
4842 kind: CodeActionKind,
4843 push_to_history: bool,
4844 cx: &mut Context<Self>,
4845 ) -> Task<anyhow::Result<ProjectTransaction>> {
4846 if self.as_local().is_some() {
4847 cx.spawn(async move |lsp_store, cx| {
4848 let buffers = buffers.into_iter().collect::<Vec<_>>();
4849 let result = LocalLspStore::execute_code_action_kind_locally(
4850 lsp_store.clone(),
4851 buffers,
4852 kind,
4853 push_to_history,
4854 cx,
4855 )
4856 .await;
4857 lsp_store.update(cx, |lsp_store, _| {
4858 lsp_store.update_last_formatting_failure(&result);
4859 })?;
4860 result
4861 })
4862 } else if let Some((client, project_id)) = self.upstream_client() {
4863 let buffer_store = self.buffer_store();
4864 cx.spawn(async move |lsp_store, cx| {
4865 let result = client
4866 .request(proto::ApplyCodeActionKind {
4867 project_id,
4868 kind: kind.as_str().to_owned(),
4869 buffer_ids: buffers
4870 .iter()
4871 .map(|buffer| {
4872 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4873 })
4874 .collect::<Result<_>>()?,
4875 })
4876 .await
4877 .and_then(|result| result.transaction.context("missing transaction"));
4878 lsp_store.update(cx, |lsp_store, _| {
4879 lsp_store.update_last_formatting_failure(&result);
4880 })?;
4881
4882 let transaction_response = result?;
4883 buffer_store
4884 .update(cx, |buffer_store, cx| {
4885 buffer_store.deserialize_project_transaction(
4886 transaction_response,
4887 push_to_history,
4888 cx,
4889 )
4890 })?
4891 .await
4892 })
4893 } else {
4894 Task::ready(Ok(ProjectTransaction::default()))
4895 }
4896 }
4897
4898 pub fn resolve_inlay_hint(
4899 &self,
4900 mut hint: InlayHint,
4901 buffer: Entity<Buffer>,
4902 server_id: LanguageServerId,
4903 cx: &mut Context<Self>,
4904 ) -> Task<anyhow::Result<InlayHint>> {
4905 if let Some((upstream_client, project_id)) = self.upstream_client() {
4906 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4907 {
4908 hint.resolve_state = ResolveState::Resolved;
4909 return Task::ready(Ok(hint));
4910 }
4911 let request = proto::ResolveInlayHint {
4912 project_id,
4913 buffer_id: buffer.read(cx).remote_id().into(),
4914 language_server_id: server_id.0 as u64,
4915 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4916 };
4917 cx.background_spawn(async move {
4918 let response = upstream_client
4919 .request(request)
4920 .await
4921 .context("inlay hints proto request")?;
4922 match response.hint {
4923 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4924 .context("inlay hints proto resolve response conversion"),
4925 None => Ok(hint),
4926 }
4927 })
4928 } else {
4929 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4930 self.language_server_for_local_buffer(buffer, server_id, cx)
4931 .map(|(_, server)| server.clone())
4932 }) else {
4933 return Task::ready(Ok(hint));
4934 };
4935 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4936 return Task::ready(Ok(hint));
4937 }
4938 let buffer_snapshot = buffer.read(cx).snapshot();
4939 cx.spawn(async move |_, cx| {
4940 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4941 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4942 );
4943 let resolved_hint = resolve_task
4944 .await
4945 .into_response()
4946 .context("inlay hint resolve LSP request")?;
4947 let resolved_hint = InlayHints::lsp_to_project_hint(
4948 resolved_hint,
4949 &buffer,
4950 server_id,
4951 ResolveState::Resolved,
4952 false,
4953 cx,
4954 )
4955 .await?;
4956 Ok(resolved_hint)
4957 })
4958 }
4959 }
4960
4961 pub fn resolve_color_presentation(
4962 &mut self,
4963 mut color: DocumentColor,
4964 buffer: Entity<Buffer>,
4965 server_id: LanguageServerId,
4966 cx: &mut Context<Self>,
4967 ) -> Task<Result<DocumentColor>> {
4968 if color.resolved {
4969 return Task::ready(Ok(color));
4970 }
4971
4972 if let Some((upstream_client, project_id)) = self.upstream_client() {
4973 let start = color.lsp_range.start;
4974 let end = color.lsp_range.end;
4975 let request = proto::GetColorPresentation {
4976 project_id,
4977 server_id: server_id.to_proto(),
4978 buffer_id: buffer.read(cx).remote_id().into(),
4979 color: Some(proto::ColorInformation {
4980 red: color.color.red,
4981 green: color.color.green,
4982 blue: color.color.blue,
4983 alpha: color.color.alpha,
4984 lsp_range_start: Some(proto::PointUtf16 {
4985 row: start.line,
4986 column: start.character,
4987 }),
4988 lsp_range_end: Some(proto::PointUtf16 {
4989 row: end.line,
4990 column: end.character,
4991 }),
4992 }),
4993 };
4994 cx.background_spawn(async move {
4995 let response = upstream_client
4996 .request(request)
4997 .await
4998 .context("color presentation proto request")?;
4999 color.resolved = true;
5000 color.color_presentations = response
5001 .presentations
5002 .into_iter()
5003 .map(|presentation| ColorPresentation {
5004 label: SharedString::from(presentation.label),
5005 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5006 additional_text_edits: presentation
5007 .additional_text_edits
5008 .into_iter()
5009 .filter_map(deserialize_lsp_edit)
5010 .collect(),
5011 })
5012 .collect();
5013 Ok(color)
5014 })
5015 } else {
5016 let path = match buffer
5017 .update(cx, |buffer, cx| {
5018 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5019 })
5020 .context("buffer with the missing path")
5021 {
5022 Ok(path) => path,
5023 Err(e) => return Task::ready(Err(e)),
5024 };
5025 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5026 self.language_server_for_local_buffer(buffer, server_id, cx)
5027 .map(|(_, server)| server.clone())
5028 }) else {
5029 return Task::ready(Ok(color));
5030 };
5031 cx.background_spawn(async move {
5032 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5033 lsp::ColorPresentationParams {
5034 text_document: make_text_document_identifier(&path)?,
5035 color: color.color,
5036 range: color.lsp_range,
5037 work_done_progress_params: Default::default(),
5038 partial_result_params: Default::default(),
5039 },
5040 );
5041 color.color_presentations = resolve_task
5042 .await
5043 .into_response()
5044 .context("color presentation resolve LSP request")?
5045 .into_iter()
5046 .map(|presentation| ColorPresentation {
5047 label: SharedString::from(presentation.label),
5048 text_edit: presentation.text_edit,
5049 additional_text_edits: presentation
5050 .additional_text_edits
5051 .unwrap_or_default(),
5052 })
5053 .collect();
5054 color.resolved = true;
5055 Ok(color)
5056 })
5057 }
5058 }
5059
5060 pub(crate) fn linked_edits(
5061 &mut self,
5062 buffer: &Entity<Buffer>,
5063 position: Anchor,
5064 cx: &mut Context<Self>,
5065 ) -> Task<Result<Vec<Range<Anchor>>>> {
5066 let snapshot = buffer.read(cx).snapshot();
5067 let scope = snapshot.language_scope_at(position);
5068 let Some(server_id) = self
5069 .as_local()
5070 .and_then(|local| {
5071 buffer.update(cx, |buffer, cx| {
5072 local
5073 .language_servers_for_buffer(buffer, cx)
5074 .filter(|(_, server)| {
5075 LinkedEditingRange::check_server_capabilities(server.capabilities())
5076 })
5077 .filter(|(adapter, _)| {
5078 scope
5079 .as_ref()
5080 .map(|scope| scope.language_allowed(&adapter.name))
5081 .unwrap_or(true)
5082 })
5083 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5084 .next()
5085 })
5086 })
5087 .or_else(|| {
5088 self.upstream_client()
5089 .is_some()
5090 .then_some(LanguageServerToQuery::FirstCapable)
5091 })
5092 .filter(|_| {
5093 maybe!({
5094 let language = buffer.read(cx).language_at(position)?;
5095 Some(
5096 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5097 .linked_edits,
5098 )
5099 }) == Some(true)
5100 })
5101 else {
5102 return Task::ready(Ok(Vec::new()));
5103 };
5104
5105 self.request_lsp(
5106 buffer.clone(),
5107 server_id,
5108 LinkedEditingRange { position },
5109 cx,
5110 )
5111 }
5112
5113 fn apply_on_type_formatting(
5114 &mut self,
5115 buffer: Entity<Buffer>,
5116 position: Anchor,
5117 trigger: String,
5118 cx: &mut Context<Self>,
5119 ) -> Task<Result<Option<Transaction>>> {
5120 if let Some((client, project_id)) = self.upstream_client() {
5121 if !self.check_if_capable_for_proto_request(
5122 &buffer,
5123 |capabilities| {
5124 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5125 },
5126 cx,
5127 ) {
5128 return Task::ready(Ok(None));
5129 }
5130 let request = proto::OnTypeFormatting {
5131 project_id,
5132 buffer_id: buffer.read(cx).remote_id().into(),
5133 position: Some(serialize_anchor(&position)),
5134 trigger,
5135 version: serialize_version(&buffer.read(cx).version()),
5136 };
5137 cx.background_spawn(async move {
5138 client
5139 .request(request)
5140 .await?
5141 .transaction
5142 .map(language::proto::deserialize_transaction)
5143 .transpose()
5144 })
5145 } else if let Some(local) = self.as_local_mut() {
5146 let buffer_id = buffer.read(cx).remote_id();
5147 local.buffers_being_formatted.insert(buffer_id);
5148 cx.spawn(async move |this, cx| {
5149 let _cleanup = defer({
5150 let this = this.clone();
5151 let mut cx = cx.clone();
5152 move || {
5153 this.update(&mut cx, |this, _| {
5154 if let Some(local) = this.as_local_mut() {
5155 local.buffers_being_formatted.remove(&buffer_id);
5156 }
5157 })
5158 .ok();
5159 }
5160 });
5161
5162 buffer
5163 .update(cx, |buffer, _| {
5164 buffer.wait_for_edits(Some(position.timestamp))
5165 })?
5166 .await?;
5167 this.update(cx, |this, cx| {
5168 let position = position.to_point_utf16(buffer.read(cx));
5169 this.on_type_format(buffer, position, trigger, false, cx)
5170 })?
5171 .await
5172 })
5173 } else {
5174 Task::ready(Err(anyhow!("No upstream client or local language server")))
5175 }
5176 }
5177
5178 pub fn on_type_format<T: ToPointUtf16>(
5179 &mut self,
5180 buffer: Entity<Buffer>,
5181 position: T,
5182 trigger: String,
5183 push_to_history: bool,
5184 cx: &mut Context<Self>,
5185 ) -> Task<Result<Option<Transaction>>> {
5186 let position = position.to_point_utf16(buffer.read(cx));
5187 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5188 }
5189
5190 fn on_type_format_impl(
5191 &mut self,
5192 buffer: Entity<Buffer>,
5193 position: PointUtf16,
5194 trigger: String,
5195 push_to_history: bool,
5196 cx: &mut Context<Self>,
5197 ) -> Task<Result<Option<Transaction>>> {
5198 let options = buffer.update(cx, |buffer, cx| {
5199 lsp_command::lsp_formatting_options(
5200 language_settings(
5201 buffer.language_at(position).map(|l| l.name()),
5202 buffer.file(),
5203 cx,
5204 )
5205 .as_ref(),
5206 )
5207 });
5208
5209 cx.spawn(async move |this, cx| {
5210 if let Some(waiter) =
5211 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5212 {
5213 waiter.await?;
5214 }
5215 cx.update(|cx| {
5216 this.update(cx, |this, cx| {
5217 this.request_lsp(
5218 buffer.clone(),
5219 LanguageServerToQuery::FirstCapable,
5220 OnTypeFormatting {
5221 position,
5222 trigger,
5223 options,
5224 push_to_history,
5225 },
5226 cx,
5227 )
5228 })
5229 })??
5230 .await
5231 })
5232 }
5233
5234 pub fn definitions(
5235 &mut self,
5236 buffer_handle: &Entity<Buffer>,
5237 position: PointUtf16,
5238 cx: &mut Context<Self>,
5239 ) -> Task<Result<Vec<LocationLink>>> {
5240 if let Some((upstream_client, project_id)) = self.upstream_client() {
5241 let request = GetDefinitions { position };
5242 if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
5243 return Task::ready(Ok(Vec::new()));
5244 }
5245 let request_task = upstream_client.request(proto::MultiLspQuery {
5246 buffer_id: buffer_handle.read(cx).remote_id().into(),
5247 version: serialize_version(&buffer_handle.read(cx).version()),
5248 project_id,
5249 strategy: Some(proto::multi_lsp_query::Strategy::All(
5250 proto::AllLanguageServers {},
5251 )),
5252 request: Some(proto::multi_lsp_query::Request::GetDefinition(
5253 request.to_proto(project_id, buffer_handle.read(cx)),
5254 )),
5255 });
5256 let buffer = buffer_handle.clone();
5257 cx.spawn(async move |weak_project, cx| {
5258 let Some(project) = weak_project.upgrade() else {
5259 return Ok(Vec::new());
5260 };
5261 let responses = request_task.await?.responses;
5262 let actions = join_all(
5263 responses
5264 .into_iter()
5265 .filter_map(|lsp_response| match lsp_response.response? {
5266 proto::lsp_response::Response::GetDefinitionResponse(response) => {
5267 Some(response)
5268 }
5269 unexpected => {
5270 debug_panic!("Unexpected response: {unexpected:?}");
5271 None
5272 }
5273 })
5274 .map(|definitions_response| {
5275 GetDefinitions { position }.response_from_proto(
5276 definitions_response,
5277 project.clone(),
5278 buffer.clone(),
5279 cx.clone(),
5280 )
5281 }),
5282 )
5283 .await;
5284
5285 Ok(actions
5286 .into_iter()
5287 .collect::<Result<Vec<Vec<_>>>>()?
5288 .into_iter()
5289 .flatten()
5290 .dedup()
5291 .collect())
5292 })
5293 } else {
5294 let definitions_task = self.request_multiple_lsp_locally(
5295 buffer_handle,
5296 Some(position),
5297 GetDefinitions { position },
5298 cx,
5299 );
5300 cx.background_spawn(async move {
5301 Ok(definitions_task
5302 .await
5303 .into_iter()
5304 .flat_map(|(_, definitions)| definitions)
5305 .dedup()
5306 .collect())
5307 })
5308 }
5309 }
5310
5311 pub fn declarations(
5312 &mut self,
5313 buffer_handle: &Entity<Buffer>,
5314 position: PointUtf16,
5315 cx: &mut Context<Self>,
5316 ) -> Task<Result<Vec<LocationLink>>> {
5317 if let Some((upstream_client, project_id)) = self.upstream_client() {
5318 let request = GetDeclarations { position };
5319 if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
5320 return Task::ready(Ok(Vec::new()));
5321 }
5322 let request_task = upstream_client.request(proto::MultiLspQuery {
5323 buffer_id: buffer_handle.read(cx).remote_id().into(),
5324 version: serialize_version(&buffer_handle.read(cx).version()),
5325 project_id,
5326 strategy: Some(proto::multi_lsp_query::Strategy::All(
5327 proto::AllLanguageServers {},
5328 )),
5329 request: Some(proto::multi_lsp_query::Request::GetDeclaration(
5330 request.to_proto(project_id, buffer_handle.read(cx)),
5331 )),
5332 });
5333 let buffer = buffer_handle.clone();
5334 cx.spawn(async move |weak_project, cx| {
5335 let Some(project) = weak_project.upgrade() else {
5336 return Ok(Vec::new());
5337 };
5338 let responses = request_task.await?.responses;
5339 let actions = join_all(
5340 responses
5341 .into_iter()
5342 .filter_map(|lsp_response| match lsp_response.response? {
5343 proto::lsp_response::Response::GetDeclarationResponse(response) => {
5344 Some(response)
5345 }
5346 unexpected => {
5347 debug_panic!("Unexpected response: {unexpected:?}");
5348 None
5349 }
5350 })
5351 .map(|declarations_response| {
5352 GetDeclarations { position }.response_from_proto(
5353 declarations_response,
5354 project.clone(),
5355 buffer.clone(),
5356 cx.clone(),
5357 )
5358 }),
5359 )
5360 .await;
5361
5362 Ok(actions
5363 .into_iter()
5364 .collect::<Result<Vec<Vec<_>>>>()?
5365 .into_iter()
5366 .flatten()
5367 .dedup()
5368 .collect())
5369 })
5370 } else {
5371 let declarations_task = self.request_multiple_lsp_locally(
5372 buffer_handle,
5373 Some(position),
5374 GetDeclarations { position },
5375 cx,
5376 );
5377 cx.background_spawn(async move {
5378 Ok(declarations_task
5379 .await
5380 .into_iter()
5381 .flat_map(|(_, declarations)| declarations)
5382 .dedup()
5383 .collect())
5384 })
5385 }
5386 }
5387
5388 pub fn type_definitions(
5389 &mut self,
5390 buffer: &Entity<Buffer>,
5391 position: PointUtf16,
5392 cx: &mut Context<Self>,
5393 ) -> Task<Result<Vec<LocationLink>>> {
5394 if let Some((upstream_client, project_id)) = self.upstream_client() {
5395 let request = GetTypeDefinitions { position };
5396 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5397 return Task::ready(Ok(Vec::new()));
5398 }
5399 let request_task = upstream_client.request(proto::MultiLspQuery {
5400 buffer_id: buffer.read(cx).remote_id().into(),
5401 version: serialize_version(&buffer.read(cx).version()),
5402 project_id,
5403 strategy: Some(proto::multi_lsp_query::Strategy::All(
5404 proto::AllLanguageServers {},
5405 )),
5406 request: Some(proto::multi_lsp_query::Request::GetTypeDefinition(
5407 request.to_proto(project_id, buffer.read(cx)),
5408 )),
5409 });
5410 let buffer = buffer.clone();
5411 cx.spawn(async move |weak_project, cx| {
5412 let Some(project) = weak_project.upgrade() else {
5413 return Ok(Vec::new());
5414 };
5415 let responses = request_task.await?.responses;
5416 let actions = join_all(
5417 responses
5418 .into_iter()
5419 .filter_map(|lsp_response| match lsp_response.response? {
5420 proto::lsp_response::Response::GetTypeDefinitionResponse(response) => {
5421 Some(response)
5422 }
5423 unexpected => {
5424 debug_panic!("Unexpected response: {unexpected:?}");
5425 None
5426 }
5427 })
5428 .map(|type_definitions_response| {
5429 GetTypeDefinitions { position }.response_from_proto(
5430 type_definitions_response,
5431 project.clone(),
5432 buffer.clone(),
5433 cx.clone(),
5434 )
5435 }),
5436 )
5437 .await;
5438
5439 Ok(actions
5440 .into_iter()
5441 .collect::<Result<Vec<Vec<_>>>>()?
5442 .into_iter()
5443 .flatten()
5444 .dedup()
5445 .collect())
5446 })
5447 } else {
5448 let type_definitions_task = self.request_multiple_lsp_locally(
5449 buffer,
5450 Some(position),
5451 GetTypeDefinitions { position },
5452 cx,
5453 );
5454 cx.background_spawn(async move {
5455 Ok(type_definitions_task
5456 .await
5457 .into_iter()
5458 .flat_map(|(_, type_definitions)| type_definitions)
5459 .dedup()
5460 .collect())
5461 })
5462 }
5463 }
5464
5465 pub fn implementations(
5466 &mut self,
5467 buffer: &Entity<Buffer>,
5468 position: PointUtf16,
5469 cx: &mut Context<Self>,
5470 ) -> Task<Result<Vec<LocationLink>>> {
5471 if let Some((upstream_client, project_id)) = self.upstream_client() {
5472 let request = GetImplementations { position };
5473 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5474 return Task::ready(Ok(Vec::new()));
5475 }
5476 let request_task = upstream_client.request(proto::MultiLspQuery {
5477 buffer_id: buffer.read(cx).remote_id().into(),
5478 version: serialize_version(&buffer.read(cx).version()),
5479 project_id,
5480 strategy: Some(proto::multi_lsp_query::Strategy::All(
5481 proto::AllLanguageServers {},
5482 )),
5483 request: Some(proto::multi_lsp_query::Request::GetImplementation(
5484 request.to_proto(project_id, buffer.read(cx)),
5485 )),
5486 });
5487 let buffer = buffer.clone();
5488 cx.spawn(async move |weak_project, cx| {
5489 let Some(project) = weak_project.upgrade() else {
5490 return Ok(Vec::new());
5491 };
5492 let responses = request_task.await?.responses;
5493 let actions = join_all(
5494 responses
5495 .into_iter()
5496 .filter_map(|lsp_response| match lsp_response.response? {
5497 proto::lsp_response::Response::GetImplementationResponse(response) => {
5498 Some(response)
5499 }
5500 unexpected => {
5501 debug_panic!("Unexpected response: {unexpected:?}");
5502 None
5503 }
5504 })
5505 .map(|implementations_response| {
5506 GetImplementations { position }.response_from_proto(
5507 implementations_response,
5508 project.clone(),
5509 buffer.clone(),
5510 cx.clone(),
5511 )
5512 }),
5513 )
5514 .await;
5515
5516 Ok(actions
5517 .into_iter()
5518 .collect::<Result<Vec<Vec<_>>>>()?
5519 .into_iter()
5520 .flatten()
5521 .dedup()
5522 .collect())
5523 })
5524 } else {
5525 let implementations_task = self.request_multiple_lsp_locally(
5526 buffer,
5527 Some(position),
5528 GetImplementations { position },
5529 cx,
5530 );
5531 cx.background_spawn(async move {
5532 Ok(implementations_task
5533 .await
5534 .into_iter()
5535 .flat_map(|(_, implementations)| implementations)
5536 .dedup()
5537 .collect())
5538 })
5539 }
5540 }
5541
5542 pub fn references(
5543 &mut self,
5544 buffer: &Entity<Buffer>,
5545 position: PointUtf16,
5546 cx: &mut Context<Self>,
5547 ) -> Task<Result<Vec<Location>>> {
5548 if let Some((upstream_client, project_id)) = self.upstream_client() {
5549 let request = GetReferences { position };
5550 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5551 return Task::ready(Ok(Vec::new()));
5552 }
5553 let request_task = upstream_client.request(proto::MultiLspQuery {
5554 buffer_id: buffer.read(cx).remote_id().into(),
5555 version: serialize_version(&buffer.read(cx).version()),
5556 project_id,
5557 strategy: Some(proto::multi_lsp_query::Strategy::All(
5558 proto::AllLanguageServers {},
5559 )),
5560 request: Some(proto::multi_lsp_query::Request::GetReferences(
5561 request.to_proto(project_id, buffer.read(cx)),
5562 )),
5563 });
5564 let buffer = buffer.clone();
5565 cx.spawn(async move |weak_project, cx| {
5566 let Some(project) = weak_project.upgrade() else {
5567 return Ok(Vec::new());
5568 };
5569 let responses = request_task.await?.responses;
5570 let actions = join_all(
5571 responses
5572 .into_iter()
5573 .filter_map(|lsp_response| match lsp_response.response? {
5574 proto::lsp_response::Response::GetReferencesResponse(response) => {
5575 Some(response)
5576 }
5577 unexpected => {
5578 debug_panic!("Unexpected response: {unexpected:?}");
5579 None
5580 }
5581 })
5582 .map(|references_response| {
5583 GetReferences { position }.response_from_proto(
5584 references_response,
5585 project.clone(),
5586 buffer.clone(),
5587 cx.clone(),
5588 )
5589 }),
5590 )
5591 .await;
5592
5593 Ok(actions
5594 .into_iter()
5595 .collect::<Result<Vec<Vec<_>>>>()?
5596 .into_iter()
5597 .flatten()
5598 .dedup()
5599 .collect())
5600 })
5601 } else {
5602 let references_task = self.request_multiple_lsp_locally(
5603 buffer,
5604 Some(position),
5605 GetReferences { position },
5606 cx,
5607 );
5608 cx.background_spawn(async move {
5609 Ok(references_task
5610 .await
5611 .into_iter()
5612 .flat_map(|(_, references)| references)
5613 .dedup()
5614 .collect())
5615 })
5616 }
5617 }
5618
5619 pub fn code_actions(
5620 &mut self,
5621 buffer: &Entity<Buffer>,
5622 range: Range<Anchor>,
5623 kinds: Option<Vec<CodeActionKind>>,
5624 cx: &mut Context<Self>,
5625 ) -> Task<Result<Vec<CodeAction>>> {
5626 if let Some((upstream_client, project_id)) = self.upstream_client() {
5627 let request = GetCodeActions {
5628 range: range.clone(),
5629 kinds: kinds.clone(),
5630 };
5631 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5632 return Task::ready(Ok(Vec::new()));
5633 }
5634 let request_task = upstream_client.request(proto::MultiLspQuery {
5635 buffer_id: buffer.read(cx).remote_id().into(),
5636 version: serialize_version(&buffer.read(cx).version()),
5637 project_id,
5638 strategy: Some(proto::multi_lsp_query::Strategy::All(
5639 proto::AllLanguageServers {},
5640 )),
5641 request: Some(proto::multi_lsp_query::Request::GetCodeActions(
5642 request.to_proto(project_id, buffer.read(cx)),
5643 )),
5644 });
5645 let buffer = buffer.clone();
5646 cx.spawn(async move |weak_project, cx| {
5647 let Some(project) = weak_project.upgrade() else {
5648 return Ok(Vec::new());
5649 };
5650 let responses = request_task.await?.responses;
5651 let actions = join_all(
5652 responses
5653 .into_iter()
5654 .filter_map(|lsp_response| match lsp_response.response? {
5655 proto::lsp_response::Response::GetCodeActionsResponse(response) => {
5656 Some(response)
5657 }
5658 unexpected => {
5659 debug_panic!("Unexpected response: {unexpected:?}");
5660 None
5661 }
5662 })
5663 .map(|code_actions_response| {
5664 GetCodeActions {
5665 range: range.clone(),
5666 kinds: kinds.clone(),
5667 }
5668 .response_from_proto(
5669 code_actions_response,
5670 project.clone(),
5671 buffer.clone(),
5672 cx.clone(),
5673 )
5674 }),
5675 )
5676 .await;
5677
5678 Ok(actions
5679 .into_iter()
5680 .collect::<Result<Vec<Vec<_>>>>()?
5681 .into_iter()
5682 .flatten()
5683 .collect())
5684 })
5685 } else {
5686 let all_actions_task = self.request_multiple_lsp_locally(
5687 buffer,
5688 Some(range.start),
5689 GetCodeActions { range, kinds },
5690 cx,
5691 );
5692 cx.background_spawn(async move {
5693 Ok(all_actions_task
5694 .await
5695 .into_iter()
5696 .flat_map(|(_, actions)| actions)
5697 .collect())
5698 })
5699 }
5700 }
5701
5702 pub fn code_lens_actions(
5703 &mut self,
5704 buffer: &Entity<Buffer>,
5705 cx: &mut Context<Self>,
5706 ) -> CodeLensTask {
5707 let version_queried_for = buffer.read(cx).version();
5708 let buffer_id = buffer.read(cx).remote_id();
5709
5710 if let Some(cached_data) = self.lsp_code_lens.get(&buffer_id)
5711 && !version_queried_for.changed_since(&cached_data.lens_for_version)
5712 {
5713 let has_different_servers = self.as_local().is_some_and(|local| {
5714 local
5715 .buffers_opened_in_servers
5716 .get(&buffer_id)
5717 .cloned()
5718 .unwrap_or_default()
5719 != cached_data.lens.keys().copied().collect()
5720 });
5721 if !has_different_servers {
5722 return Task::ready(Ok(cached_data.lens.values().flatten().cloned().collect()))
5723 .shared();
5724 }
5725 }
5726
5727 let lsp_data = self.lsp_code_lens.entry(buffer_id).or_default();
5728 if let Some((updating_for, running_update)) = &lsp_data.update
5729 && !version_queried_for.changed_since(updating_for)
5730 {
5731 return running_update.clone();
5732 }
5733 let buffer = buffer.clone();
5734 let query_version_queried_for = version_queried_for.clone();
5735 let new_task = cx
5736 .spawn(async move |lsp_store, cx| {
5737 cx.background_executor()
5738 .timer(Duration::from_millis(30))
5739 .await;
5740 let fetched_lens = lsp_store
5741 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5742 .map_err(Arc::new)?
5743 .await
5744 .context("fetching code lens")
5745 .map_err(Arc::new);
5746 let fetched_lens = match fetched_lens {
5747 Ok(fetched_lens) => fetched_lens,
5748 Err(e) => {
5749 lsp_store
5750 .update(cx, |lsp_store, _| {
5751 lsp_store.lsp_code_lens.entry(buffer_id).or_default().update = None;
5752 })
5753 .ok();
5754 return Err(e);
5755 }
5756 };
5757
5758 lsp_store
5759 .update(cx, |lsp_store, _| {
5760 let lsp_data = lsp_store.lsp_code_lens.entry(buffer_id).or_default();
5761 if lsp_data.lens_for_version == query_version_queried_for {
5762 lsp_data.lens.extend(fetched_lens.clone());
5763 } else if !lsp_data
5764 .lens_for_version
5765 .changed_since(&query_version_queried_for)
5766 {
5767 lsp_data.lens_for_version = query_version_queried_for;
5768 lsp_data.lens = fetched_lens.clone();
5769 }
5770 lsp_data.update = None;
5771 lsp_data.lens.values().flatten().cloned().collect()
5772 })
5773 .map_err(Arc::new)
5774 })
5775 .shared();
5776 lsp_data.update = Some((version_queried_for, new_task.clone()));
5777 new_task
5778 }
5779
5780 fn fetch_code_lens(
5781 &mut self,
5782 buffer: &Entity<Buffer>,
5783 cx: &mut Context<Self>,
5784 ) -> Task<Result<HashMap<LanguageServerId, Vec<CodeAction>>>> {
5785 if let Some((upstream_client, project_id)) = self.upstream_client() {
5786 let request = GetCodeLens;
5787 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5788 return Task::ready(Ok(HashMap::default()));
5789 }
5790 let request_task = upstream_client.request(proto::MultiLspQuery {
5791 buffer_id: buffer.read(cx).remote_id().into(),
5792 version: serialize_version(&buffer.read(cx).version()),
5793 project_id,
5794 strategy: Some(proto::multi_lsp_query::Strategy::All(
5795 proto::AllLanguageServers {},
5796 )),
5797 request: Some(proto::multi_lsp_query::Request::GetCodeLens(
5798 request.to_proto(project_id, buffer.read(cx)),
5799 )),
5800 });
5801 let buffer = buffer.clone();
5802 cx.spawn(async move |weak_lsp_store, cx| {
5803 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5804 return Ok(HashMap::default());
5805 };
5806 let responses = request_task.await?.responses;
5807 let code_lens_actions = join_all(
5808 responses
5809 .into_iter()
5810 .filter_map(|lsp_response| {
5811 let response = match lsp_response.response? {
5812 proto::lsp_response::Response::GetCodeLensResponse(response) => {
5813 Some(response)
5814 }
5815 unexpected => {
5816 debug_panic!("Unexpected response: {unexpected:?}");
5817 None
5818 }
5819 }?;
5820 let server_id = LanguageServerId::from_proto(lsp_response.server_id);
5821 Some((server_id, response))
5822 })
5823 .map(|(server_id, code_lens_response)| {
5824 let lsp_store = lsp_store.clone();
5825 let buffer = buffer.clone();
5826 let cx = cx.clone();
5827 async move {
5828 (
5829 server_id,
5830 GetCodeLens
5831 .response_from_proto(
5832 code_lens_response,
5833 lsp_store,
5834 buffer,
5835 cx,
5836 )
5837 .await,
5838 )
5839 }
5840 }),
5841 )
5842 .await;
5843
5844 let mut has_errors = false;
5845 let code_lens_actions = code_lens_actions
5846 .into_iter()
5847 .filter_map(|(server_id, code_lens)| match code_lens {
5848 Ok(code_lens) => Some((server_id, code_lens)),
5849 Err(e) => {
5850 has_errors = true;
5851 log::error!("{e:#}");
5852 None
5853 }
5854 })
5855 .collect::<HashMap<_, _>>();
5856 anyhow::ensure!(
5857 !has_errors || !code_lens_actions.is_empty(),
5858 "Failed to fetch code lens"
5859 );
5860 Ok(code_lens_actions)
5861 })
5862 } else {
5863 let code_lens_actions_task =
5864 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5865 cx.background_spawn(
5866 async move { Ok(code_lens_actions_task.await.into_iter().collect()) },
5867 )
5868 }
5869 }
5870
5871 #[inline(never)]
5872 pub fn completions(
5873 &self,
5874 buffer: &Entity<Buffer>,
5875 position: PointUtf16,
5876 context: CompletionContext,
5877 cx: &mut Context<Self>,
5878 ) -> Task<Result<Vec<CompletionResponse>>> {
5879 let language_registry = self.languages.clone();
5880
5881 if let Some((upstream_client, project_id)) = self.upstream_client() {
5882 let request = GetCompletions { position, context };
5883 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5884 return Task::ready(Ok(Vec::new()));
5885 }
5886 let task = self.send_lsp_proto_request(
5887 buffer.clone(),
5888 upstream_client,
5889 project_id,
5890 request,
5891 cx,
5892 );
5893 let language = buffer.read(cx).language().cloned();
5894
5895 // In the future, we should provide project guests with the names of LSP adapters,
5896 // so that they can use the correct LSP adapter when computing labels. For now,
5897 // guests just use the first LSP adapter associated with the buffer's language.
5898 let lsp_adapter = language.as_ref().and_then(|language| {
5899 language_registry
5900 .lsp_adapters(&language.name())
5901 .first()
5902 .cloned()
5903 });
5904
5905 cx.foreground_executor().spawn(async move {
5906 let completion_response = task.await?;
5907 let completions = populate_labels_for_completions(
5908 completion_response.completions,
5909 language,
5910 lsp_adapter,
5911 )
5912 .await;
5913 Ok(vec![CompletionResponse {
5914 completions,
5915 is_incomplete: completion_response.is_incomplete,
5916 }])
5917 })
5918 } else if let Some(local) = self.as_local() {
5919 let snapshot = buffer.read(cx).snapshot();
5920 let offset = position.to_offset(&snapshot);
5921 let scope = snapshot.language_scope_at(offset);
5922 let language = snapshot.language().cloned();
5923 let completion_settings = language_settings(
5924 language.as_ref().map(|language| language.name()),
5925 buffer.read(cx).file(),
5926 cx,
5927 )
5928 .completions;
5929 if !completion_settings.lsp {
5930 return Task::ready(Ok(Vec::new()));
5931 }
5932
5933 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5934 local
5935 .language_servers_for_buffer(buffer, cx)
5936 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5937 .filter(|(adapter, _)| {
5938 scope
5939 .as_ref()
5940 .map(|scope| scope.language_allowed(&adapter.name))
5941 .unwrap_or(true)
5942 })
5943 .map(|(_, server)| server.server_id())
5944 .collect()
5945 });
5946
5947 let buffer = buffer.clone();
5948 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5949 let lsp_timeout = if lsp_timeout > 0 {
5950 Some(Duration::from_millis(lsp_timeout))
5951 } else {
5952 None
5953 };
5954 cx.spawn(async move |this, cx| {
5955 let mut tasks = Vec::with_capacity(server_ids.len());
5956 this.update(cx, |lsp_store, cx| {
5957 for server_id in server_ids {
5958 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5959 let lsp_timeout = lsp_timeout
5960 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5961 let mut timeout = cx.background_spawn(async move {
5962 match lsp_timeout {
5963 Some(lsp_timeout) => {
5964 lsp_timeout.await;
5965 true
5966 },
5967 None => false,
5968 }
5969 }).fuse();
5970 let mut lsp_request = lsp_store.request_lsp(
5971 buffer.clone(),
5972 LanguageServerToQuery::Other(server_id),
5973 GetCompletions {
5974 position,
5975 context: context.clone(),
5976 },
5977 cx,
5978 ).fuse();
5979 let new_task = cx.background_spawn(async move {
5980 select_biased! {
5981 response = lsp_request => anyhow::Ok(Some(response?)),
5982 timeout_happened = timeout => {
5983 if timeout_happened {
5984 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5985 Ok(None)
5986 } else {
5987 let completions = lsp_request.await?;
5988 Ok(Some(completions))
5989 }
5990 },
5991 }
5992 });
5993 tasks.push((lsp_adapter, new_task));
5994 }
5995 })?;
5996
5997 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5998 let completion_response = task.await.ok()??;
5999 let completions = populate_labels_for_completions(
6000 completion_response.completions,
6001 language.clone(),
6002 lsp_adapter,
6003 )
6004 .await;
6005 Some(CompletionResponse {
6006 completions,
6007 is_incomplete: completion_response.is_incomplete,
6008 })
6009 });
6010
6011 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6012
6013 Ok(responses.into_iter().flatten().collect())
6014 })
6015 } else {
6016 Task::ready(Err(anyhow!("No upstream client or local language server")))
6017 }
6018 }
6019
6020 pub fn resolve_completions(
6021 &self,
6022 buffer: Entity<Buffer>,
6023 completion_indices: Vec<usize>,
6024 completions: Rc<RefCell<Box<[Completion]>>>,
6025 cx: &mut Context<Self>,
6026 ) -> Task<Result<bool>> {
6027 let client = self.upstream_client();
6028 let buffer_id = buffer.read(cx).remote_id();
6029 let buffer_snapshot = buffer.read(cx).snapshot();
6030
6031 if !self.check_if_capable_for_proto_request(
6032 &buffer,
6033 GetCompletions::can_resolve_completions,
6034 cx,
6035 ) {
6036 return Task::ready(Ok(false));
6037 }
6038 cx.spawn(async move |lsp_store, cx| {
6039 let mut did_resolve = false;
6040 if let Some((client, project_id)) = client {
6041 for completion_index in completion_indices {
6042 let server_id = {
6043 let completion = &completions.borrow()[completion_index];
6044 completion.source.server_id()
6045 };
6046 if let Some(server_id) = server_id {
6047 if Self::resolve_completion_remote(
6048 project_id,
6049 server_id,
6050 buffer_id,
6051 completions.clone(),
6052 completion_index,
6053 client.clone(),
6054 )
6055 .await
6056 .log_err()
6057 .is_some()
6058 {
6059 did_resolve = true;
6060 }
6061 } else {
6062 resolve_word_completion(
6063 &buffer_snapshot,
6064 &mut completions.borrow_mut()[completion_index],
6065 );
6066 }
6067 }
6068 } else {
6069 for completion_index in completion_indices {
6070 let server_id = {
6071 let completion = &completions.borrow()[completion_index];
6072 completion.source.server_id()
6073 };
6074 if let Some(server_id) = server_id {
6075 let server_and_adapter = lsp_store
6076 .read_with(cx, |lsp_store, _| {
6077 let server = lsp_store.language_server_for_id(server_id)?;
6078 let adapter =
6079 lsp_store.language_server_adapter_for_id(server.server_id())?;
6080 Some((server, adapter))
6081 })
6082 .ok()
6083 .flatten();
6084 let Some((server, adapter)) = server_and_adapter else {
6085 continue;
6086 };
6087
6088 let resolved = Self::resolve_completion_local(
6089 server,
6090 completions.clone(),
6091 completion_index,
6092 )
6093 .await
6094 .log_err()
6095 .is_some();
6096 if resolved {
6097 Self::regenerate_completion_labels(
6098 adapter,
6099 &buffer_snapshot,
6100 completions.clone(),
6101 completion_index,
6102 )
6103 .await
6104 .log_err();
6105 did_resolve = true;
6106 }
6107 } else {
6108 resolve_word_completion(
6109 &buffer_snapshot,
6110 &mut completions.borrow_mut()[completion_index],
6111 );
6112 }
6113 }
6114 }
6115
6116 Ok(did_resolve)
6117 })
6118 }
6119
6120 async fn resolve_completion_local(
6121 server: Arc<lsp::LanguageServer>,
6122 completions: Rc<RefCell<Box<[Completion]>>>,
6123 completion_index: usize,
6124 ) -> Result<()> {
6125 let server_id = server.server_id();
6126 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6127 return Ok(());
6128 }
6129
6130 let request = {
6131 let completion = &completions.borrow()[completion_index];
6132 match &completion.source {
6133 CompletionSource::Lsp {
6134 lsp_completion,
6135 resolved,
6136 server_id: completion_server_id,
6137 ..
6138 } => {
6139 if *resolved {
6140 return Ok(());
6141 }
6142 anyhow::ensure!(
6143 server_id == *completion_server_id,
6144 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6145 );
6146 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6147 }
6148 CompletionSource::BufferWord { .. }
6149 | CompletionSource::Dap { .. }
6150 | CompletionSource::Custom => {
6151 return Ok(());
6152 }
6153 }
6154 };
6155 let resolved_completion = request
6156 .await
6157 .into_response()
6158 .context("resolve completion")?;
6159
6160 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6161 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6162
6163 let mut completions = completions.borrow_mut();
6164 let completion = &mut completions[completion_index];
6165 if let CompletionSource::Lsp {
6166 lsp_completion,
6167 resolved,
6168 server_id: completion_server_id,
6169 ..
6170 } = &mut completion.source
6171 {
6172 if *resolved {
6173 return Ok(());
6174 }
6175 anyhow::ensure!(
6176 server_id == *completion_server_id,
6177 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6178 );
6179 *lsp_completion = Box::new(resolved_completion);
6180 *resolved = true;
6181 }
6182 Ok(())
6183 }
6184
6185 async fn regenerate_completion_labels(
6186 adapter: Arc<CachedLspAdapter>,
6187 snapshot: &BufferSnapshot,
6188 completions: Rc<RefCell<Box<[Completion]>>>,
6189 completion_index: usize,
6190 ) -> Result<()> {
6191 let completion_item = completions.borrow()[completion_index]
6192 .source
6193 .lsp_completion(true)
6194 .map(Cow::into_owned);
6195 if let Some(lsp_documentation) = completion_item
6196 .as_ref()
6197 .and_then(|completion_item| completion_item.documentation.clone())
6198 {
6199 let mut completions = completions.borrow_mut();
6200 let completion = &mut completions[completion_index];
6201 completion.documentation = Some(lsp_documentation.into());
6202 } else {
6203 let mut completions = completions.borrow_mut();
6204 let completion = &mut completions[completion_index];
6205 completion.documentation = Some(CompletionDocumentation::Undocumented);
6206 }
6207
6208 let mut new_label = match completion_item {
6209 Some(completion_item) => {
6210 // 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
6211 // So we have to update the label here anyway...
6212 let language = snapshot.language();
6213 match language {
6214 Some(language) => {
6215 adapter
6216 .labels_for_completions(
6217 std::slice::from_ref(&completion_item),
6218 language,
6219 )
6220 .await?
6221 }
6222 None => Vec::new(),
6223 }
6224 .pop()
6225 .flatten()
6226 .unwrap_or_else(|| {
6227 CodeLabel::fallback_for_completion(
6228 &completion_item,
6229 language.map(|language| language.as_ref()),
6230 )
6231 })
6232 }
6233 None => CodeLabel::plain(
6234 completions.borrow()[completion_index].new_text.clone(),
6235 None,
6236 ),
6237 };
6238 ensure_uniform_list_compatible_label(&mut new_label);
6239
6240 let mut completions = completions.borrow_mut();
6241 let completion = &mut completions[completion_index];
6242 if completion.label.filter_text() == new_label.filter_text() {
6243 completion.label = new_label;
6244 } else {
6245 log::error!(
6246 "Resolved completion changed display label from {} to {}. \
6247 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6248 completion.label.text(),
6249 new_label.text(),
6250 completion.label.filter_text(),
6251 new_label.filter_text()
6252 );
6253 }
6254
6255 Ok(())
6256 }
6257
6258 async fn resolve_completion_remote(
6259 project_id: u64,
6260 server_id: LanguageServerId,
6261 buffer_id: BufferId,
6262 completions: Rc<RefCell<Box<[Completion]>>>,
6263 completion_index: usize,
6264 client: AnyProtoClient,
6265 ) -> Result<()> {
6266 let lsp_completion = {
6267 let completion = &completions.borrow()[completion_index];
6268 match &completion.source {
6269 CompletionSource::Lsp {
6270 lsp_completion,
6271 resolved,
6272 server_id: completion_server_id,
6273 ..
6274 } => {
6275 anyhow::ensure!(
6276 server_id == *completion_server_id,
6277 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6278 );
6279 if *resolved {
6280 return Ok(());
6281 }
6282 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6283 }
6284 CompletionSource::Custom
6285 | CompletionSource::Dap { .. }
6286 | CompletionSource::BufferWord { .. } => {
6287 return Ok(());
6288 }
6289 }
6290 };
6291 let request = proto::ResolveCompletionDocumentation {
6292 project_id,
6293 language_server_id: server_id.0 as u64,
6294 lsp_completion,
6295 buffer_id: buffer_id.into(),
6296 };
6297
6298 let response = client
6299 .request(request)
6300 .await
6301 .context("completion documentation resolve proto request")?;
6302 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6303
6304 let documentation = if response.documentation.is_empty() {
6305 CompletionDocumentation::Undocumented
6306 } else if response.documentation_is_markdown {
6307 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6308 } else if response.documentation.lines().count() <= 1 {
6309 CompletionDocumentation::SingleLine(response.documentation.into())
6310 } else {
6311 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6312 };
6313
6314 let mut completions = completions.borrow_mut();
6315 let completion = &mut completions[completion_index];
6316 completion.documentation = Some(documentation);
6317 if let CompletionSource::Lsp {
6318 insert_range,
6319 lsp_completion,
6320 resolved,
6321 server_id: completion_server_id,
6322 lsp_defaults: _,
6323 } = &mut completion.source
6324 {
6325 let completion_insert_range = response
6326 .old_insert_start
6327 .and_then(deserialize_anchor)
6328 .zip(response.old_insert_end.and_then(deserialize_anchor));
6329 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6330
6331 if *resolved {
6332 return Ok(());
6333 }
6334 anyhow::ensure!(
6335 server_id == *completion_server_id,
6336 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6337 );
6338 *lsp_completion = Box::new(resolved_lsp_completion);
6339 *resolved = true;
6340 }
6341
6342 let replace_range = response
6343 .old_replace_start
6344 .and_then(deserialize_anchor)
6345 .zip(response.old_replace_end.and_then(deserialize_anchor));
6346 if let Some((old_replace_start, old_replace_end)) = replace_range
6347 && !response.new_text.is_empty()
6348 {
6349 completion.new_text = response.new_text;
6350 completion.replace_range = old_replace_start..old_replace_end;
6351 }
6352
6353 Ok(())
6354 }
6355
6356 pub fn apply_additional_edits_for_completion(
6357 &self,
6358 buffer_handle: Entity<Buffer>,
6359 completions: Rc<RefCell<Box<[Completion]>>>,
6360 completion_index: usize,
6361 push_to_history: bool,
6362 cx: &mut Context<Self>,
6363 ) -> Task<Result<Option<Transaction>>> {
6364 if let Some((client, project_id)) = self.upstream_client() {
6365 let buffer = buffer_handle.read(cx);
6366 let buffer_id = buffer.remote_id();
6367 cx.spawn(async move |_, cx| {
6368 let request = {
6369 let completion = completions.borrow()[completion_index].clone();
6370 proto::ApplyCompletionAdditionalEdits {
6371 project_id,
6372 buffer_id: buffer_id.into(),
6373 completion: Some(Self::serialize_completion(&CoreCompletion {
6374 replace_range: completion.replace_range,
6375 new_text: completion.new_text,
6376 source: completion.source,
6377 })),
6378 }
6379 };
6380
6381 if let Some(transaction) = client.request(request).await?.transaction {
6382 let transaction = language::proto::deserialize_transaction(transaction)?;
6383 buffer_handle
6384 .update(cx, |buffer, _| {
6385 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6386 })?
6387 .await?;
6388 if push_to_history {
6389 buffer_handle.update(cx, |buffer, _| {
6390 buffer.push_transaction(transaction.clone(), Instant::now());
6391 buffer.finalize_last_transaction();
6392 })?;
6393 }
6394 Ok(Some(transaction))
6395 } else {
6396 Ok(None)
6397 }
6398 })
6399 } else {
6400 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6401 let completion = &completions.borrow()[completion_index];
6402 let server_id = completion.source.server_id()?;
6403 Some(
6404 self.language_server_for_local_buffer(buffer, server_id, cx)?
6405 .1
6406 .clone(),
6407 )
6408 }) else {
6409 return Task::ready(Ok(None));
6410 };
6411
6412 cx.spawn(async move |this, cx| {
6413 Self::resolve_completion_local(
6414 server.clone(),
6415 completions.clone(),
6416 completion_index,
6417 )
6418 .await
6419 .context("resolving completion")?;
6420 let completion = completions.borrow()[completion_index].clone();
6421 let additional_text_edits = completion
6422 .source
6423 .lsp_completion(true)
6424 .as_ref()
6425 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6426 if let Some(edits) = additional_text_edits {
6427 let edits = this
6428 .update(cx, |this, cx| {
6429 this.as_local_mut().unwrap().edits_from_lsp(
6430 &buffer_handle,
6431 edits,
6432 server.server_id(),
6433 None,
6434 cx,
6435 )
6436 })?
6437 .await?;
6438
6439 buffer_handle.update(cx, |buffer, cx| {
6440 buffer.finalize_last_transaction();
6441 buffer.start_transaction();
6442
6443 for (range, text) in edits {
6444 let primary = &completion.replace_range;
6445 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6446 && primary.end.cmp(&range.start, buffer).is_ge();
6447 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6448 && range.end.cmp(&primary.end, buffer).is_ge();
6449
6450 //Skip additional edits which overlap with the primary completion edit
6451 //https://github.com/zed-industries/zed/pull/1871
6452 if !start_within && !end_within {
6453 buffer.edit([(range, text)], None, cx);
6454 }
6455 }
6456
6457 let transaction = if buffer.end_transaction(cx).is_some() {
6458 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6459 if !push_to_history {
6460 buffer.forget_transaction(transaction.id);
6461 }
6462 Some(transaction)
6463 } else {
6464 None
6465 };
6466 Ok(transaction)
6467 })?
6468 } else {
6469 Ok(None)
6470 }
6471 })
6472 }
6473 }
6474
6475 pub fn pull_diagnostics(
6476 &mut self,
6477 buffer: Entity<Buffer>,
6478 cx: &mut Context<Self>,
6479 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6480 let buffer_id = buffer.read(cx).remote_id();
6481
6482 if let Some((client, upstream_project_id)) = self.upstream_client() {
6483 if !self.is_capable_for_proto_request(
6484 &buffer,
6485 &GetDocumentDiagnostics {
6486 previous_result_id: None,
6487 },
6488 cx,
6489 ) {
6490 return Task::ready(Ok(None));
6491 }
6492 let request_task = client.request(proto::MultiLspQuery {
6493 buffer_id: buffer_id.to_proto(),
6494 version: serialize_version(&buffer.read(cx).version()),
6495 project_id: upstream_project_id,
6496 strategy: Some(proto::multi_lsp_query::Strategy::All(
6497 proto::AllLanguageServers {},
6498 )),
6499 request: Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(
6500 proto::GetDocumentDiagnostics {
6501 project_id: upstream_project_id,
6502 buffer_id: buffer_id.to_proto(),
6503 version: serialize_version(&buffer.read(cx).version()),
6504 },
6505 )),
6506 });
6507 cx.background_spawn(async move {
6508 let _proto_responses = request_task
6509 .await?
6510 .responses
6511 .into_iter()
6512 .filter_map(|lsp_response| match lsp_response.response? {
6513 proto::lsp_response::Response::GetDocumentDiagnosticsResponse(response) => {
6514 Some(response)
6515 }
6516 unexpected => {
6517 debug_panic!("Unexpected response: {unexpected:?}");
6518 None
6519 }
6520 })
6521 .collect::<Vec<_>>();
6522 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6523 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6524 // Do not attempt to further process the dummy responses here.
6525 Ok(None)
6526 })
6527 } else {
6528 let server_ids = buffer.update(cx, |buffer, cx| {
6529 self.language_servers_for_local_buffer(buffer, cx)
6530 .map(|(_, server)| server.server_id())
6531 .collect::<Vec<_>>()
6532 });
6533 let pull_diagnostics = server_ids
6534 .into_iter()
6535 .map(|server_id| {
6536 let result_id = self.result_id(server_id, buffer_id, cx);
6537 self.request_lsp(
6538 buffer.clone(),
6539 LanguageServerToQuery::Other(server_id),
6540 GetDocumentDiagnostics {
6541 previous_result_id: result_id,
6542 },
6543 cx,
6544 )
6545 })
6546 .collect::<Vec<_>>();
6547
6548 cx.background_spawn(async move {
6549 let mut responses = Vec::new();
6550 for diagnostics in join_all(pull_diagnostics).await {
6551 responses.extend(diagnostics?);
6552 }
6553 Ok(Some(responses))
6554 })
6555 }
6556 }
6557
6558 pub fn inlay_hints(
6559 &mut self,
6560 buffer: Entity<Buffer>,
6561 range: Range<Anchor>,
6562 cx: &mut Context<Self>,
6563 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
6564 let range_start = range.start;
6565 let range_end = range.end;
6566 let buffer_id = buffer.read(cx).remote_id().into();
6567 let request = InlayHints { range };
6568
6569 if let Some((client, project_id)) = self.upstream_client() {
6570 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6571 return Task::ready(Ok(Vec::new()));
6572 }
6573 let proto_request = proto::InlayHints {
6574 project_id,
6575 buffer_id,
6576 start: Some(serialize_anchor(&range_start)),
6577 end: Some(serialize_anchor(&range_end)),
6578 version: serialize_version(&buffer.read(cx).version()),
6579 };
6580 cx.spawn(async move |project, cx| {
6581 let response = client
6582 .request(proto_request)
6583 .await
6584 .context("inlay hints proto request")?;
6585 LspCommand::response_from_proto(
6586 request,
6587 response,
6588 project.upgrade().context("No project")?,
6589 buffer.clone(),
6590 cx.clone(),
6591 )
6592 .await
6593 .context("inlay hints proto response conversion")
6594 })
6595 } else {
6596 let lsp_request_task = self.request_lsp(
6597 buffer.clone(),
6598 LanguageServerToQuery::FirstCapable,
6599 request,
6600 cx,
6601 );
6602 cx.spawn(async move |_, cx| {
6603 buffer
6604 .update(cx, |buffer, _| {
6605 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
6606 })?
6607 .await
6608 .context("waiting for inlay hint request range edits")?;
6609 lsp_request_task.await.context("inlay hints LSP request")
6610 })
6611 }
6612 }
6613
6614 pub fn pull_diagnostics_for_buffer(
6615 &mut self,
6616 buffer: Entity<Buffer>,
6617 cx: &mut Context<Self>,
6618 ) -> Task<anyhow::Result<()>> {
6619 let diagnostics = self.pull_diagnostics(buffer, cx);
6620 cx.spawn(async move |lsp_store, cx| {
6621 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6622 return Ok(());
6623 };
6624 lsp_store.update(cx, |lsp_store, cx| {
6625 if lsp_store.as_local().is_none() {
6626 return;
6627 }
6628
6629 let mut unchanged_buffers = HashSet::default();
6630 let mut changed_buffers = HashSet::default();
6631 let server_diagnostics_updates = diagnostics
6632 .into_iter()
6633 .filter_map(|diagnostics_set| match diagnostics_set {
6634 LspPullDiagnostics::Response {
6635 server_id,
6636 uri,
6637 diagnostics,
6638 } => Some((server_id, uri, diagnostics)),
6639 LspPullDiagnostics::Default => None,
6640 })
6641 .fold(
6642 HashMap::default(),
6643 |mut acc, (server_id, uri, diagnostics)| {
6644 let (result_id, diagnostics) = match diagnostics {
6645 PulledDiagnostics::Unchanged { result_id } => {
6646 unchanged_buffers.insert(uri.clone());
6647 (Some(result_id), Vec::new())
6648 }
6649 PulledDiagnostics::Changed {
6650 result_id,
6651 diagnostics,
6652 } => {
6653 changed_buffers.insert(uri.clone());
6654 (result_id, diagnostics)
6655 }
6656 };
6657 let disk_based_sources = Cow::Owned(
6658 lsp_store
6659 .language_server_adapter_for_id(server_id)
6660 .as_ref()
6661 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6662 .unwrap_or(&[])
6663 .to_vec(),
6664 );
6665 acc.entry(server_id).or_insert_with(Vec::new).push(
6666 DocumentDiagnosticsUpdate {
6667 server_id,
6668 diagnostics: lsp::PublishDiagnosticsParams {
6669 uri,
6670 diagnostics,
6671 version: None,
6672 },
6673 result_id,
6674 disk_based_sources,
6675 },
6676 );
6677 acc
6678 },
6679 );
6680
6681 for diagnostic_updates in server_diagnostics_updates.into_values() {
6682 lsp_store
6683 .merge_lsp_diagnostics(
6684 DiagnosticSourceKind::Pulled,
6685 diagnostic_updates,
6686 |buffer, old_diagnostic, cx| {
6687 File::from_dyn(buffer.file())
6688 .and_then(|file| {
6689 let abs_path = file.as_local()?.abs_path(cx);
6690 lsp::Url::from_file_path(abs_path).ok()
6691 })
6692 .is_none_or(|buffer_uri| {
6693 unchanged_buffers.contains(&buffer_uri)
6694 || match old_diagnostic.source_kind {
6695 DiagnosticSourceKind::Pulled => {
6696 !changed_buffers.contains(&buffer_uri)
6697 }
6698 DiagnosticSourceKind::Other
6699 | DiagnosticSourceKind::Pushed => true,
6700 }
6701 })
6702 },
6703 cx,
6704 )
6705 .log_err();
6706 }
6707 })
6708 })
6709 }
6710
6711 pub fn document_colors(
6712 &mut self,
6713 fetch_strategy: LspFetchStrategy,
6714 buffer: Entity<Buffer>,
6715 cx: &mut Context<Self>,
6716 ) -> Option<DocumentColorTask> {
6717 let version_queried_for = buffer.read(cx).version();
6718 let buffer_id = buffer.read(cx).remote_id();
6719
6720 match fetch_strategy {
6721 LspFetchStrategy::IgnoreCache => {}
6722 LspFetchStrategy::UseCache {
6723 known_cache_version,
6724 } => {
6725 if let Some(cached_data) = self.lsp_document_colors.get(&buffer_id)
6726 && !version_queried_for.changed_since(&cached_data.colors_for_version)
6727 {
6728 let has_different_servers = self.as_local().is_some_and(|local| {
6729 local
6730 .buffers_opened_in_servers
6731 .get(&buffer_id)
6732 .cloned()
6733 .unwrap_or_default()
6734 != cached_data.colors.keys().copied().collect()
6735 });
6736 if !has_different_servers {
6737 if Some(cached_data.cache_version) == known_cache_version {
6738 return None;
6739 } else {
6740 return Some(
6741 Task::ready(Ok(DocumentColors {
6742 colors: cached_data
6743 .colors
6744 .values()
6745 .flatten()
6746 .cloned()
6747 .collect(),
6748 cache_version: Some(cached_data.cache_version),
6749 }))
6750 .shared(),
6751 );
6752 }
6753 }
6754 }
6755 }
6756 }
6757
6758 let lsp_data = self.lsp_document_colors.entry(buffer_id).or_default();
6759 if let Some((updating_for, running_update)) = &lsp_data.colors_update
6760 && !version_queried_for.changed_since(updating_for)
6761 {
6762 return Some(running_update.clone());
6763 }
6764 let query_version_queried_for = version_queried_for.clone();
6765 let new_task = cx
6766 .spawn(async move |lsp_store, cx| {
6767 cx.background_executor()
6768 .timer(Duration::from_millis(30))
6769 .await;
6770 let fetched_colors = lsp_store
6771 .update(cx, |lsp_store, cx| {
6772 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6773 })?
6774 .await
6775 .context("fetching document colors")
6776 .map_err(Arc::new);
6777 let fetched_colors = match fetched_colors {
6778 Ok(fetched_colors) => {
6779 if fetch_strategy != LspFetchStrategy::IgnoreCache
6780 && Some(true)
6781 == buffer
6782 .update(cx, |buffer, _| {
6783 buffer.version() != query_version_queried_for
6784 })
6785 .ok()
6786 {
6787 return Ok(DocumentColors::default());
6788 }
6789 fetched_colors
6790 }
6791 Err(e) => {
6792 lsp_store
6793 .update(cx, |lsp_store, _| {
6794 lsp_store
6795 .lsp_document_colors
6796 .entry(buffer_id)
6797 .or_default()
6798 .colors_update = None;
6799 })
6800 .ok();
6801 return Err(e);
6802 }
6803 };
6804
6805 lsp_store
6806 .update(cx, |lsp_store, _| {
6807 let lsp_data = lsp_store.lsp_document_colors.entry(buffer_id).or_default();
6808
6809 if lsp_data.colors_for_version == query_version_queried_for {
6810 lsp_data.colors.extend(fetched_colors.clone());
6811 lsp_data.cache_version += 1;
6812 } else if !lsp_data
6813 .colors_for_version
6814 .changed_since(&query_version_queried_for)
6815 {
6816 lsp_data.colors_for_version = query_version_queried_for;
6817 lsp_data.colors = fetched_colors.clone();
6818 lsp_data.cache_version += 1;
6819 }
6820 lsp_data.colors_update = None;
6821 let colors = lsp_data
6822 .colors
6823 .values()
6824 .flatten()
6825 .cloned()
6826 .collect::<HashSet<_>>();
6827 DocumentColors {
6828 colors,
6829 cache_version: Some(lsp_data.cache_version),
6830 }
6831 })
6832 .map_err(Arc::new)
6833 })
6834 .shared();
6835 lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
6836 Some(new_task)
6837 }
6838
6839 fn fetch_document_colors_for_buffer(
6840 &mut self,
6841 buffer: &Entity<Buffer>,
6842 cx: &mut Context<Self>,
6843 ) -> Task<anyhow::Result<HashMap<LanguageServerId, HashSet<DocumentColor>>>> {
6844 if let Some((client, project_id)) = self.upstream_client() {
6845 let request = GetDocumentColor {};
6846 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6847 return Task::ready(Ok(HashMap::default()));
6848 }
6849
6850 let request_task = client.request(proto::MultiLspQuery {
6851 project_id,
6852 buffer_id: buffer.read(cx).remote_id().to_proto(),
6853 version: serialize_version(&buffer.read(cx).version()),
6854 strategy: Some(proto::multi_lsp_query::Strategy::All(
6855 proto::AllLanguageServers {},
6856 )),
6857 request: Some(proto::multi_lsp_query::Request::GetDocumentColor(
6858 request.to_proto(project_id, buffer.read(cx)),
6859 )),
6860 });
6861 let buffer = buffer.clone();
6862 cx.spawn(async move |project, cx| {
6863 let Some(project) = project.upgrade() else {
6864 return Ok(HashMap::default());
6865 };
6866 let colors = join_all(
6867 request_task
6868 .await
6869 .log_err()
6870 .map(|response| response.responses)
6871 .unwrap_or_default()
6872 .into_iter()
6873 .filter_map(|lsp_response| match lsp_response.response? {
6874 proto::lsp_response::Response::GetDocumentColorResponse(response) => {
6875 Some((
6876 LanguageServerId::from_proto(lsp_response.server_id),
6877 response,
6878 ))
6879 }
6880 unexpected => {
6881 debug_panic!("Unexpected response: {unexpected:?}");
6882 None
6883 }
6884 })
6885 .map(|(server_id, color_response)| {
6886 let response = request.response_from_proto(
6887 color_response,
6888 project.clone(),
6889 buffer.clone(),
6890 cx.clone(),
6891 );
6892 async move { (server_id, response.await.log_err().unwrap_or_default()) }
6893 }),
6894 )
6895 .await
6896 .into_iter()
6897 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6898 acc.entry(server_id)
6899 .or_insert_with(HashSet::default)
6900 .extend(colors);
6901 acc
6902 });
6903 Ok(colors)
6904 })
6905 } else {
6906 let document_colors_task =
6907 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
6908 cx.background_spawn(async move {
6909 Ok(document_colors_task
6910 .await
6911 .into_iter()
6912 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6913 acc.entry(server_id)
6914 .or_insert_with(HashSet::default)
6915 .extend(colors);
6916 acc
6917 })
6918 .into_iter()
6919 .collect())
6920 })
6921 }
6922 }
6923
6924 pub fn signature_help<T: ToPointUtf16>(
6925 &mut self,
6926 buffer: &Entity<Buffer>,
6927 position: T,
6928 cx: &mut Context<Self>,
6929 ) -> Task<Vec<SignatureHelp>> {
6930 let position = position.to_point_utf16(buffer.read(cx));
6931
6932 if let Some((client, upstream_project_id)) = self.upstream_client() {
6933 let request = GetSignatureHelp { position };
6934 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6935 return Task::ready(Vec::new());
6936 }
6937 let request_task = client.request(proto::MultiLspQuery {
6938 buffer_id: buffer.read(cx).remote_id().into(),
6939 version: serialize_version(&buffer.read(cx).version()),
6940 project_id: upstream_project_id,
6941 strategy: Some(proto::multi_lsp_query::Strategy::All(
6942 proto::AllLanguageServers {},
6943 )),
6944 request: Some(proto::multi_lsp_query::Request::GetSignatureHelp(
6945 request.to_proto(upstream_project_id, buffer.read(cx)),
6946 )),
6947 });
6948 let buffer = buffer.clone();
6949 cx.spawn(async move |weak_project, cx| {
6950 let Some(project) = weak_project.upgrade() else {
6951 return Vec::new();
6952 };
6953 join_all(
6954 request_task
6955 .await
6956 .log_err()
6957 .map(|response| response.responses)
6958 .unwrap_or_default()
6959 .into_iter()
6960 .filter_map(|lsp_response| match lsp_response.response? {
6961 proto::lsp_response::Response::GetSignatureHelpResponse(response) => {
6962 Some(response)
6963 }
6964 unexpected => {
6965 debug_panic!("Unexpected response: {unexpected:?}");
6966 None
6967 }
6968 })
6969 .map(|signature_response| {
6970 let response = GetSignatureHelp { position }.response_from_proto(
6971 signature_response,
6972 project.clone(),
6973 buffer.clone(),
6974 cx.clone(),
6975 );
6976 async move { response.await.log_err().flatten() }
6977 }),
6978 )
6979 .await
6980 .into_iter()
6981 .flatten()
6982 .collect()
6983 })
6984 } else {
6985 let all_actions_task = self.request_multiple_lsp_locally(
6986 buffer,
6987 Some(position),
6988 GetSignatureHelp { position },
6989 cx,
6990 );
6991 cx.background_spawn(async move {
6992 all_actions_task
6993 .await
6994 .into_iter()
6995 .flat_map(|(_, actions)| actions)
6996 .collect::<Vec<_>>()
6997 })
6998 }
6999 }
7000
7001 pub fn hover(
7002 &mut self,
7003 buffer: &Entity<Buffer>,
7004 position: PointUtf16,
7005 cx: &mut Context<Self>,
7006 ) -> Task<Vec<Hover>> {
7007 if let Some((client, upstream_project_id)) = self.upstream_client() {
7008 let request = GetHover { position };
7009 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7010 return Task::ready(Vec::new());
7011 }
7012 let request_task = client.request(proto::MultiLspQuery {
7013 buffer_id: buffer.read(cx).remote_id().into(),
7014 version: serialize_version(&buffer.read(cx).version()),
7015 project_id: upstream_project_id,
7016 strategy: Some(proto::multi_lsp_query::Strategy::All(
7017 proto::AllLanguageServers {},
7018 )),
7019 request: Some(proto::multi_lsp_query::Request::GetHover(
7020 request.to_proto(upstream_project_id, buffer.read(cx)),
7021 )),
7022 });
7023 let buffer = buffer.clone();
7024 cx.spawn(async move |weak_project, cx| {
7025 let Some(project) = weak_project.upgrade() else {
7026 return Vec::new();
7027 };
7028 join_all(
7029 request_task
7030 .await
7031 .log_err()
7032 .map(|response| response.responses)
7033 .unwrap_or_default()
7034 .into_iter()
7035 .filter_map(|lsp_response| match lsp_response.response? {
7036 proto::lsp_response::Response::GetHoverResponse(response) => {
7037 Some(response)
7038 }
7039 unexpected => {
7040 debug_panic!("Unexpected response: {unexpected:?}");
7041 None
7042 }
7043 })
7044 .map(|hover_response| {
7045 let response = GetHover { position }.response_from_proto(
7046 hover_response,
7047 project.clone(),
7048 buffer.clone(),
7049 cx.clone(),
7050 );
7051 async move {
7052 response
7053 .await
7054 .log_err()
7055 .flatten()
7056 .and_then(remove_empty_hover_blocks)
7057 }
7058 }),
7059 )
7060 .await
7061 .into_iter()
7062 .flatten()
7063 .collect()
7064 })
7065 } else {
7066 let all_actions_task = self.request_multiple_lsp_locally(
7067 buffer,
7068 Some(position),
7069 GetHover { position },
7070 cx,
7071 );
7072 cx.background_spawn(async move {
7073 all_actions_task
7074 .await
7075 .into_iter()
7076 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7077 .collect::<Vec<Hover>>()
7078 })
7079 }
7080 }
7081
7082 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7083 let language_registry = self.languages.clone();
7084
7085 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7086 let request = upstream_client.request(proto::GetProjectSymbols {
7087 project_id: *project_id,
7088 query: query.to_string(),
7089 });
7090 cx.foreground_executor().spawn(async move {
7091 let response = request.await?;
7092 let mut symbols = Vec::new();
7093 let core_symbols = response
7094 .symbols
7095 .into_iter()
7096 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7097 .collect::<Vec<_>>();
7098 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7099 .await;
7100 Ok(symbols)
7101 })
7102 } else if let Some(local) = self.as_local() {
7103 struct WorkspaceSymbolsResult {
7104 server_id: LanguageServerId,
7105 lsp_adapter: Arc<CachedLspAdapter>,
7106 worktree: WeakEntity<Worktree>,
7107 worktree_abs_path: Arc<Path>,
7108 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7109 }
7110
7111 let mut requests = Vec::new();
7112 let mut requested_servers = BTreeSet::new();
7113 for (seed, state) in local.language_server_ids.iter() {
7114 let Some(worktree_handle) = self
7115 .worktree_store
7116 .read(cx)
7117 .worktree_for_id(seed.worktree_id, cx)
7118 else {
7119 continue;
7120 };
7121 let worktree = worktree_handle.read(cx);
7122 if !worktree.is_visible() {
7123 continue;
7124 }
7125
7126 if !requested_servers.insert(state.id) {
7127 continue;
7128 }
7129
7130 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7131 Some(LanguageServerState::Running {
7132 adapter, server, ..
7133 }) => (adapter.clone(), server),
7134
7135 _ => continue,
7136 };
7137 let supports_workspace_symbol_request =
7138 match server.capabilities().workspace_symbol_provider {
7139 Some(OneOf::Left(supported)) => supported,
7140 Some(OneOf::Right(_)) => true,
7141 None => false,
7142 };
7143 if !supports_workspace_symbol_request {
7144 continue;
7145 }
7146 let worktree_abs_path = worktree.abs_path().clone();
7147 let worktree_handle = worktree_handle.clone();
7148 let server_id = server.server_id();
7149 requests.push(
7150 server
7151 .request::<lsp::request::WorkspaceSymbolRequest>(
7152 lsp::WorkspaceSymbolParams {
7153 query: query.to_string(),
7154 ..Default::default()
7155 },
7156 )
7157 .map(move |response| {
7158 let lsp_symbols = response.into_response()
7159 .context("workspace symbols request")
7160 .log_err()
7161 .flatten()
7162 .map(|symbol_response| match symbol_response {
7163 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7164 flat_responses.into_iter().map(|lsp_symbol| {
7165 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7166 }).collect::<Vec<_>>()
7167 }
7168 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7169 nested_responses.into_iter().filter_map(|lsp_symbol| {
7170 let location = match lsp_symbol.location {
7171 OneOf::Left(location) => location,
7172 OneOf::Right(_) => {
7173 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7174 return None
7175 }
7176 };
7177 Some((lsp_symbol.name, lsp_symbol.kind, location))
7178 }).collect::<Vec<_>>()
7179 }
7180 }).unwrap_or_default();
7181
7182 WorkspaceSymbolsResult {
7183 server_id,
7184 lsp_adapter,
7185 worktree: worktree_handle.downgrade(),
7186 worktree_abs_path,
7187 lsp_symbols,
7188 }
7189 }),
7190 );
7191 }
7192
7193 cx.spawn(async move |this, cx| {
7194 let responses = futures::future::join_all(requests).await;
7195 let this = match this.upgrade() {
7196 Some(this) => this,
7197 None => return Ok(Vec::new()),
7198 };
7199
7200 let mut symbols = Vec::new();
7201 for result in responses {
7202 let core_symbols = this.update(cx, |this, cx| {
7203 result
7204 .lsp_symbols
7205 .into_iter()
7206 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7207 let abs_path = symbol_location.uri.to_file_path().ok()?;
7208 let source_worktree = result.worktree.upgrade()?;
7209 let source_worktree_id = source_worktree.read(cx).id();
7210
7211 let path;
7212 let worktree;
7213 if let Some((tree, rel_path)) =
7214 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7215 {
7216 worktree = tree;
7217 path = rel_path;
7218 } else {
7219 worktree = source_worktree;
7220 path = relativize_path(&result.worktree_abs_path, &abs_path);
7221 }
7222
7223 let worktree_id = worktree.read(cx).id();
7224 let project_path = ProjectPath {
7225 worktree_id,
7226 path: path.into(),
7227 };
7228 let signature = this.symbol_signature(&project_path);
7229 Some(CoreSymbol {
7230 source_language_server_id: result.server_id,
7231 language_server_name: result.lsp_adapter.name.clone(),
7232 source_worktree_id,
7233 path: project_path,
7234 kind: symbol_kind,
7235 name: symbol_name,
7236 range: range_from_lsp(symbol_location.range),
7237 signature,
7238 })
7239 })
7240 .collect()
7241 })?;
7242
7243 populate_labels_for_symbols(
7244 core_symbols,
7245 &language_registry,
7246 Some(result.lsp_adapter),
7247 &mut symbols,
7248 )
7249 .await;
7250 }
7251
7252 Ok(symbols)
7253 })
7254 } else {
7255 Task::ready(Err(anyhow!("No upstream client or local language server")))
7256 }
7257 }
7258
7259 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7260 let mut summary = DiagnosticSummary::default();
7261 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7262 summary.error_count += path_summary.error_count;
7263 summary.warning_count += path_summary.warning_count;
7264 }
7265 summary
7266 }
7267
7268 pub fn diagnostic_summaries<'a>(
7269 &'a self,
7270 include_ignored: bool,
7271 cx: &'a App,
7272 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7273 self.worktree_store
7274 .read(cx)
7275 .visible_worktrees(cx)
7276 .filter_map(|worktree| {
7277 let worktree = worktree.read(cx);
7278 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7279 })
7280 .flat_map(move |(worktree, summaries)| {
7281 let worktree_id = worktree.id();
7282 summaries
7283 .iter()
7284 .filter(move |(path, _)| {
7285 include_ignored
7286 || worktree
7287 .entry_for_path(path.as_ref())
7288 .is_some_and(|entry| !entry.is_ignored)
7289 })
7290 .flat_map(move |(path, summaries)| {
7291 summaries.iter().map(move |(server_id, summary)| {
7292 (
7293 ProjectPath {
7294 worktree_id,
7295 path: path.clone(),
7296 },
7297 *server_id,
7298 *summary,
7299 )
7300 })
7301 })
7302 })
7303 }
7304
7305 pub fn on_buffer_edited(
7306 &mut self,
7307 buffer: Entity<Buffer>,
7308 cx: &mut Context<Self>,
7309 ) -> Option<()> {
7310 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7311 Some(
7312 self.as_local()?
7313 .language_servers_for_buffer(buffer, cx)
7314 .map(|i| i.1.clone())
7315 .collect(),
7316 )
7317 })?;
7318
7319 let buffer = buffer.read(cx);
7320 let file = File::from_dyn(buffer.file())?;
7321 let abs_path = file.as_local()?.abs_path(cx);
7322 let uri = lsp::Url::from_file_path(abs_path).unwrap();
7323 let next_snapshot = buffer.text_snapshot();
7324 for language_server in language_servers {
7325 let language_server = language_server.clone();
7326
7327 let buffer_snapshots = self
7328 .as_local_mut()
7329 .unwrap()
7330 .buffer_snapshots
7331 .get_mut(&buffer.remote_id())
7332 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7333 let previous_snapshot = buffer_snapshots.last()?;
7334
7335 let build_incremental_change = || {
7336 buffer
7337 .edits_since::<Dimensions<PointUtf16, usize>>(
7338 previous_snapshot.snapshot.version(),
7339 )
7340 .map(|edit| {
7341 let edit_start = edit.new.start.0;
7342 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7343 let new_text = next_snapshot
7344 .text_for_range(edit.new.start.1..edit.new.end.1)
7345 .collect();
7346 lsp::TextDocumentContentChangeEvent {
7347 range: Some(lsp::Range::new(
7348 point_to_lsp(edit_start),
7349 point_to_lsp(edit_end),
7350 )),
7351 range_length: None,
7352 text: new_text,
7353 }
7354 })
7355 .collect()
7356 };
7357
7358 let document_sync_kind = language_server
7359 .capabilities()
7360 .text_document_sync
7361 .as_ref()
7362 .and_then(|sync| match sync {
7363 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7364 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7365 });
7366
7367 let content_changes: Vec<_> = match document_sync_kind {
7368 Some(lsp::TextDocumentSyncKind::FULL) => {
7369 vec![lsp::TextDocumentContentChangeEvent {
7370 range: None,
7371 range_length: None,
7372 text: next_snapshot.text(),
7373 }]
7374 }
7375 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7376 _ => {
7377 #[cfg(any(test, feature = "test-support"))]
7378 {
7379 build_incremental_change()
7380 }
7381
7382 #[cfg(not(any(test, feature = "test-support")))]
7383 {
7384 continue;
7385 }
7386 }
7387 };
7388
7389 let next_version = previous_snapshot.version + 1;
7390 buffer_snapshots.push(LspBufferSnapshot {
7391 version: next_version,
7392 snapshot: next_snapshot.clone(),
7393 });
7394
7395 language_server
7396 .notify::<lsp::notification::DidChangeTextDocument>(
7397 &lsp::DidChangeTextDocumentParams {
7398 text_document: lsp::VersionedTextDocumentIdentifier::new(
7399 uri.clone(),
7400 next_version,
7401 ),
7402 content_changes,
7403 },
7404 )
7405 .ok();
7406 self.pull_workspace_diagnostics(language_server.server_id());
7407 }
7408
7409 None
7410 }
7411
7412 pub fn on_buffer_saved(
7413 &mut self,
7414 buffer: Entity<Buffer>,
7415 cx: &mut Context<Self>,
7416 ) -> Option<()> {
7417 let file = File::from_dyn(buffer.read(cx).file())?;
7418 let worktree_id = file.worktree_id(cx);
7419 let abs_path = file.as_local()?.abs_path(cx);
7420 let text_document = lsp::TextDocumentIdentifier {
7421 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7422 };
7423 let local = self.as_local()?;
7424
7425 for server in local.language_servers_for_worktree(worktree_id) {
7426 if let Some(include_text) = include_text(server.as_ref()) {
7427 let text = if include_text {
7428 Some(buffer.read(cx).text())
7429 } else {
7430 None
7431 };
7432 server
7433 .notify::<lsp::notification::DidSaveTextDocument>(
7434 &lsp::DidSaveTextDocumentParams {
7435 text_document: text_document.clone(),
7436 text,
7437 },
7438 )
7439 .ok();
7440 }
7441 }
7442
7443 let language_servers = buffer.update(cx, |buffer, cx| {
7444 local.language_server_ids_for_buffer(buffer, cx)
7445 });
7446 for language_server_id in language_servers {
7447 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7448 }
7449
7450 None
7451 }
7452
7453 async fn refresh_workspace_configurations(
7454 lsp_store: &WeakEntity<Self>,
7455 fs: Arc<dyn Fs>,
7456 cx: &mut AsyncApp,
7457 ) {
7458 maybe!(async move {
7459 let mut refreshed_servers = HashSet::default();
7460 let servers = lsp_store
7461 .update(cx, |lsp_store, cx| {
7462 let local = lsp_store.as_local()?;
7463
7464 let servers = local
7465 .language_server_ids
7466 .iter()
7467 .filter_map(|(seed, state)| {
7468 let worktree = lsp_store
7469 .worktree_store
7470 .read(cx)
7471 .worktree_for_id(seed.worktree_id, cx);
7472 let delegate: Arc<dyn LspAdapterDelegate> =
7473 worktree.map(|worktree| {
7474 LocalLspAdapterDelegate::new(
7475 local.languages.clone(),
7476 &local.environment,
7477 cx.weak_entity(),
7478 &worktree,
7479 local.http_client.clone(),
7480 local.fs.clone(),
7481 cx,
7482 )
7483 })?;
7484 let server_id = state.id;
7485
7486 let states = local.language_servers.get(&server_id)?;
7487
7488 match states {
7489 LanguageServerState::Starting { .. } => None,
7490 LanguageServerState::Running {
7491 adapter, server, ..
7492 } => {
7493 let fs = fs.clone();
7494
7495 let adapter = adapter.clone();
7496 let server = server.clone();
7497 refreshed_servers.insert(server.name());
7498 let toolchain = seed.toolchain.clone();
7499 Some(cx.spawn(async move |_, cx| {
7500 let settings =
7501 LocalLspStore::workspace_configuration_for_adapter(
7502 adapter.adapter.clone(),
7503 fs.as_ref(),
7504 &delegate,
7505 toolchain,
7506 cx,
7507 )
7508 .await
7509 .ok()?;
7510 server
7511 .notify::<lsp::notification::DidChangeConfiguration>(
7512 &lsp::DidChangeConfigurationParams { settings },
7513 )
7514 .ok()?;
7515 Some(())
7516 }))
7517 }
7518 }
7519 })
7520 .collect::<Vec<_>>();
7521
7522 Some(servers)
7523 })
7524 .ok()
7525 .flatten()?;
7526
7527 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7528 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7529 // to stop and unregister its language server wrapper.
7530 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7531 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7532 let _: Vec<Option<()>> = join_all(servers).await;
7533
7534 Some(())
7535 })
7536 .await;
7537 }
7538
7539 fn maintain_workspace_config(
7540 fs: Arc<dyn Fs>,
7541 external_refresh_requests: watch::Receiver<()>,
7542 cx: &mut Context<Self>,
7543 ) -> Task<Result<()>> {
7544 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7545 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7546
7547 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7548 *settings_changed_tx.borrow_mut() = ();
7549 });
7550
7551 let mut joint_future =
7552 futures::stream::select(settings_changed_rx, external_refresh_requests);
7553 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7554 // - 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).
7555 // - 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.
7556 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7557 // - 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,
7558 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7559 cx.spawn(async move |this, cx| {
7560 while let Some(()) = joint_future.next().await {
7561 this.update(cx, |this, cx| {
7562 this.refresh_server_tree(cx);
7563 })
7564 .ok();
7565
7566 Self::refresh_workspace_configurations(&this, fs.clone(), cx).await;
7567 }
7568
7569 drop(settings_observation);
7570 anyhow::Ok(())
7571 })
7572 }
7573
7574 pub fn language_servers_for_local_buffer<'a>(
7575 &'a self,
7576 buffer: &Buffer,
7577 cx: &mut App,
7578 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7579 let local = self.as_local();
7580 let language_server_ids = local
7581 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7582 .unwrap_or_default();
7583
7584 language_server_ids
7585 .into_iter()
7586 .filter_map(
7587 move |server_id| match local?.language_servers.get(&server_id)? {
7588 LanguageServerState::Running {
7589 adapter, server, ..
7590 } => Some((adapter, server)),
7591 _ => None,
7592 },
7593 )
7594 }
7595
7596 pub fn language_server_for_local_buffer<'a>(
7597 &'a self,
7598 buffer: &'a Buffer,
7599 server_id: LanguageServerId,
7600 cx: &'a mut App,
7601 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7602 self.as_local()?
7603 .language_servers_for_buffer(buffer, cx)
7604 .find(|(_, s)| s.server_id() == server_id)
7605 }
7606
7607 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7608 self.diagnostic_summaries.remove(&id_to_remove);
7609 if let Some(local) = self.as_local_mut() {
7610 let to_remove = local.remove_worktree(id_to_remove, cx);
7611 for server in to_remove {
7612 self.language_server_statuses.remove(&server);
7613 }
7614 }
7615 }
7616
7617 pub fn shared(
7618 &mut self,
7619 project_id: u64,
7620 downstream_client: AnyProtoClient,
7621 _: &mut Context<Self>,
7622 ) {
7623 self.downstream_client = Some((downstream_client.clone(), project_id));
7624
7625 for (server_id, status) in &self.language_server_statuses {
7626 if let Some(server) = self.language_server_for_id(*server_id) {
7627 downstream_client
7628 .send(proto::StartLanguageServer {
7629 project_id,
7630 server: Some(proto::LanguageServer {
7631 id: server_id.to_proto(),
7632 name: status.name.to_string(),
7633 worktree_id: None,
7634 }),
7635 capabilities: serde_json::to_string(&server.capabilities())
7636 .expect("serializing server LSP capabilities"),
7637 })
7638 .log_err();
7639 }
7640 }
7641 }
7642
7643 pub fn disconnected_from_host(&mut self) {
7644 self.downstream_client.take();
7645 }
7646
7647 pub fn disconnected_from_ssh_remote(&mut self) {
7648 if let LspStoreMode::Remote(RemoteLspStore {
7649 upstream_client, ..
7650 }) = &mut self.mode
7651 {
7652 upstream_client.take();
7653 }
7654 }
7655
7656 pub(crate) fn set_language_server_statuses_from_proto(
7657 &mut self,
7658 language_servers: Vec<proto::LanguageServer>,
7659 server_capabilities: Vec<String>,
7660 ) {
7661 self.language_server_statuses = language_servers
7662 .into_iter()
7663 .zip(server_capabilities)
7664 .map(|(server, server_capabilities)| {
7665 let server_id = LanguageServerId(server.id as usize);
7666 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7667 self.lsp_server_capabilities
7668 .insert(server_id, server_capabilities);
7669 }
7670 (
7671 server_id,
7672 LanguageServerStatus {
7673 name: LanguageServerName::from_proto(server.name),
7674 pending_work: Default::default(),
7675 has_pending_diagnostic_updates: false,
7676 progress_tokens: Default::default(),
7677 },
7678 )
7679 })
7680 .collect();
7681 }
7682
7683 #[cfg(test)]
7684 pub fn update_diagnostic_entries(
7685 &mut self,
7686 server_id: LanguageServerId,
7687 abs_path: PathBuf,
7688 result_id: Option<String>,
7689 version: Option<i32>,
7690 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7691 cx: &mut Context<Self>,
7692 ) -> anyhow::Result<()> {
7693 self.merge_diagnostic_entries(
7694 vec![DocumentDiagnosticsUpdate {
7695 diagnostics: DocumentDiagnostics {
7696 diagnostics,
7697 document_abs_path: abs_path,
7698 version,
7699 },
7700 result_id,
7701 server_id,
7702 disk_based_sources: Cow::Borrowed(&[]),
7703 }],
7704 |_, _, _| false,
7705 cx,
7706 )?;
7707 Ok(())
7708 }
7709
7710 pub fn merge_diagnostic_entries<'a>(
7711 &mut self,
7712 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7713 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7714 cx: &mut Context<Self>,
7715 ) -> anyhow::Result<()> {
7716 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7717 let mut updated_diagnostics_paths = HashMap::default();
7718 for mut update in diagnostic_updates {
7719 let abs_path = &update.diagnostics.document_abs_path;
7720 let server_id = update.server_id;
7721 let Some((worktree, relative_path)) =
7722 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7723 else {
7724 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7725 return Ok(());
7726 };
7727
7728 let worktree_id = worktree.read(cx).id();
7729 let project_path = ProjectPath {
7730 worktree_id,
7731 path: relative_path.into(),
7732 };
7733
7734 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7735 let snapshot = buffer_handle.read(cx).snapshot();
7736 let buffer = buffer_handle.read(cx);
7737 let reused_diagnostics = buffer
7738 .get_diagnostics(server_id)
7739 .into_iter()
7740 .flat_map(|diag| {
7741 diag.iter()
7742 .filter(|v| merge(buffer, &v.diagnostic, cx))
7743 .map(|v| {
7744 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7745 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7746 DiagnosticEntry {
7747 range: start..end,
7748 diagnostic: v.diagnostic.clone(),
7749 }
7750 })
7751 })
7752 .collect::<Vec<_>>();
7753
7754 self.as_local_mut()
7755 .context("cannot merge diagnostics on a remote LspStore")?
7756 .update_buffer_diagnostics(
7757 &buffer_handle,
7758 server_id,
7759 update.result_id,
7760 update.diagnostics.version,
7761 update.diagnostics.diagnostics.clone(),
7762 reused_diagnostics.clone(),
7763 cx,
7764 )?;
7765
7766 update.diagnostics.diagnostics.extend(reused_diagnostics);
7767 }
7768
7769 let updated = worktree.update(cx, |worktree, cx| {
7770 self.update_worktree_diagnostics(
7771 worktree.id(),
7772 server_id,
7773 project_path.path.clone(),
7774 update.diagnostics.diagnostics,
7775 cx,
7776 )
7777 })?;
7778 match updated {
7779 ControlFlow::Continue(new_summary) => {
7780 if let Some((project_id, new_summary)) = new_summary {
7781 match &mut diagnostics_summary {
7782 Some(diagnostics_summary) => {
7783 diagnostics_summary
7784 .more_summaries
7785 .push(proto::DiagnosticSummary {
7786 path: project_path.path.as_ref().to_proto(),
7787 language_server_id: server_id.0 as u64,
7788 error_count: new_summary.error_count,
7789 warning_count: new_summary.warning_count,
7790 })
7791 }
7792 None => {
7793 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
7794 project_id,
7795 worktree_id: worktree_id.to_proto(),
7796 summary: Some(proto::DiagnosticSummary {
7797 path: project_path.path.as_ref().to_proto(),
7798 language_server_id: server_id.0 as u64,
7799 error_count: new_summary.error_count,
7800 warning_count: new_summary.warning_count,
7801 }),
7802 more_summaries: Vec::new(),
7803 })
7804 }
7805 }
7806 }
7807 updated_diagnostics_paths
7808 .entry(server_id)
7809 .or_insert_with(Vec::new)
7810 .push(project_path);
7811 }
7812 ControlFlow::Break(()) => {}
7813 }
7814 }
7815
7816 if let Some((diagnostics_summary, (downstream_client, _))) =
7817 diagnostics_summary.zip(self.downstream_client.as_ref())
7818 {
7819 downstream_client.send(diagnostics_summary).log_err();
7820 }
7821 for (server_id, paths) in updated_diagnostics_paths {
7822 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
7823 }
7824 Ok(())
7825 }
7826
7827 fn update_worktree_diagnostics(
7828 &mut self,
7829 worktree_id: WorktreeId,
7830 server_id: LanguageServerId,
7831 path_in_worktree: Arc<Path>,
7832 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7833 _: &mut Context<Worktree>,
7834 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
7835 let local = match &mut self.mode {
7836 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
7837 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
7838 };
7839
7840 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
7841 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
7842 let summaries_by_server_id = summaries_for_tree
7843 .entry(path_in_worktree.clone())
7844 .or_default();
7845
7846 let old_summary = summaries_by_server_id
7847 .remove(&server_id)
7848 .unwrap_or_default();
7849
7850 let new_summary = DiagnosticSummary::new(&diagnostics);
7851 if new_summary.is_empty() {
7852 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
7853 {
7854 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7855 diagnostics_by_server_id.remove(ix);
7856 }
7857 if diagnostics_by_server_id.is_empty() {
7858 diagnostics_for_tree.remove(&path_in_worktree);
7859 }
7860 }
7861 } else {
7862 summaries_by_server_id.insert(server_id, new_summary);
7863 let diagnostics_by_server_id = diagnostics_for_tree
7864 .entry(path_in_worktree.clone())
7865 .or_default();
7866 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7867 Ok(ix) => {
7868 diagnostics_by_server_id[ix] = (server_id, diagnostics);
7869 }
7870 Err(ix) => {
7871 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
7872 }
7873 }
7874 }
7875
7876 if !old_summary.is_empty() || !new_summary.is_empty() {
7877 if let Some((_, project_id)) = &self.downstream_client {
7878 Ok(ControlFlow::Continue(Some((
7879 *project_id,
7880 proto::DiagnosticSummary {
7881 path: path_in_worktree.to_proto(),
7882 language_server_id: server_id.0 as u64,
7883 error_count: new_summary.error_count as u32,
7884 warning_count: new_summary.warning_count as u32,
7885 },
7886 ))))
7887 } else {
7888 Ok(ControlFlow::Continue(None))
7889 }
7890 } else {
7891 Ok(ControlFlow::Break(()))
7892 }
7893 }
7894
7895 pub fn open_buffer_for_symbol(
7896 &mut self,
7897 symbol: &Symbol,
7898 cx: &mut Context<Self>,
7899 ) -> Task<Result<Entity<Buffer>>> {
7900 if let Some((client, project_id)) = self.upstream_client() {
7901 let request = client.request(proto::OpenBufferForSymbol {
7902 project_id,
7903 symbol: Some(Self::serialize_symbol(symbol)),
7904 });
7905 cx.spawn(async move |this, cx| {
7906 let response = request.await?;
7907 let buffer_id = BufferId::new(response.buffer_id)?;
7908 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
7909 .await
7910 })
7911 } else if let Some(local) = self.as_local() {
7912 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
7913 seed.worktree_id == symbol.source_worktree_id
7914 && state.id == symbol.source_language_server_id
7915 && symbol.language_server_name == seed.name
7916 });
7917 if !is_valid {
7918 return Task::ready(Err(anyhow!(
7919 "language server for worktree and language not found"
7920 )));
7921 };
7922
7923 let worktree_abs_path = if let Some(worktree_abs_path) = self
7924 .worktree_store
7925 .read(cx)
7926 .worktree_for_id(symbol.path.worktree_id, cx)
7927 .map(|worktree| worktree.read(cx).abs_path())
7928 {
7929 worktree_abs_path
7930 } else {
7931 return Task::ready(Err(anyhow!("worktree not found for symbol")));
7932 };
7933
7934 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
7935 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
7936 uri
7937 } else {
7938 return Task::ready(Err(anyhow!("invalid symbol path")));
7939 };
7940
7941 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
7942 } else {
7943 Task::ready(Err(anyhow!("no upstream client or local store")))
7944 }
7945 }
7946
7947 pub(crate) fn open_local_buffer_via_lsp(
7948 &mut self,
7949 mut abs_path: lsp::Url,
7950 language_server_id: LanguageServerId,
7951 cx: &mut Context<Self>,
7952 ) -> Task<Result<Entity<Buffer>>> {
7953 cx.spawn(async move |lsp_store, cx| {
7954 // Escape percent-encoded string.
7955 let current_scheme = abs_path.scheme().to_owned();
7956 let _ = abs_path.set_scheme("file");
7957
7958 let abs_path = abs_path
7959 .to_file_path()
7960 .map_err(|()| anyhow!("can't convert URI to path"))?;
7961 let p = abs_path.clone();
7962 let yarn_worktree = lsp_store
7963 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
7964 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
7965 cx.spawn(async move |this, cx| {
7966 let t = this
7967 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
7968 .ok()?;
7969 t.await
7970 })
7971 }),
7972 None => Task::ready(None),
7973 })?
7974 .await;
7975 let (worktree_root_target, known_relative_path) =
7976 if let Some((zip_root, relative_path)) = yarn_worktree {
7977 (zip_root, Some(relative_path))
7978 } else {
7979 (Arc::<Path>::from(abs_path.as_path()), None)
7980 };
7981 let (worktree, relative_path) = if let Some(result) =
7982 lsp_store.update(cx, |lsp_store, cx| {
7983 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7984 worktree_store.find_worktree(&worktree_root_target, cx)
7985 })
7986 })? {
7987 let relative_path =
7988 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
7989 (result.0, relative_path)
7990 } else {
7991 let worktree = lsp_store
7992 .update(cx, |lsp_store, cx| {
7993 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7994 worktree_store.create_worktree(&worktree_root_target, false, cx)
7995 })
7996 })?
7997 .await?;
7998 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
7999 lsp_store
8000 .update(cx, |lsp_store, cx| {
8001 if let Some(local) = lsp_store.as_local_mut() {
8002 local.register_language_server_for_invisible_worktree(
8003 &worktree,
8004 language_server_id,
8005 cx,
8006 )
8007 }
8008 })
8009 .ok();
8010 }
8011 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8012 let relative_path = if let Some(known_path) = known_relative_path {
8013 known_path
8014 } else {
8015 abs_path.strip_prefix(worktree_root)?.into()
8016 };
8017 (worktree, relative_path)
8018 };
8019 let project_path = ProjectPath {
8020 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8021 path: relative_path,
8022 };
8023 lsp_store
8024 .update(cx, |lsp_store, cx| {
8025 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8026 buffer_store.open_buffer(project_path, cx)
8027 })
8028 })?
8029 .await
8030 })
8031 }
8032
8033 fn request_multiple_lsp_locally<P, R>(
8034 &mut self,
8035 buffer: &Entity<Buffer>,
8036 position: Option<P>,
8037 request: R,
8038 cx: &mut Context<Self>,
8039 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8040 where
8041 P: ToOffset,
8042 R: LspCommand + Clone,
8043 <R::LspRequest as lsp::request::Request>::Result: Send,
8044 <R::LspRequest as lsp::request::Request>::Params: Send,
8045 {
8046 let Some(local) = self.as_local() else {
8047 return Task::ready(Vec::new());
8048 };
8049
8050 let snapshot = buffer.read(cx).snapshot();
8051 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8052
8053 let server_ids = buffer.update(cx, |buffer, cx| {
8054 local
8055 .language_servers_for_buffer(buffer, cx)
8056 .filter(|(adapter, _)| {
8057 scope
8058 .as_ref()
8059 .map(|scope| scope.language_allowed(&adapter.name))
8060 .unwrap_or(true)
8061 })
8062 .map(|(_, server)| server.server_id())
8063 .filter(|server_id| {
8064 self.as_local().is_none_or(|local| {
8065 local
8066 .buffers_opened_in_servers
8067 .get(&snapshot.remote_id())
8068 .is_some_and(|servers| servers.contains(server_id))
8069 })
8070 })
8071 .collect::<Vec<_>>()
8072 });
8073
8074 let mut response_results = server_ids
8075 .into_iter()
8076 .map(|server_id| {
8077 let task = self.request_lsp(
8078 buffer.clone(),
8079 LanguageServerToQuery::Other(server_id),
8080 request.clone(),
8081 cx,
8082 );
8083 async move { (server_id, task.await) }
8084 })
8085 .collect::<FuturesUnordered<_>>();
8086
8087 cx.background_spawn(async move {
8088 let mut responses = Vec::with_capacity(response_results.len());
8089 while let Some((server_id, response_result)) = response_results.next().await {
8090 if let Some(response) = response_result.log_err() {
8091 responses.push((server_id, response));
8092 }
8093 }
8094 responses
8095 })
8096 }
8097
8098 async fn handle_lsp_command<T: LspCommand>(
8099 this: Entity<Self>,
8100 envelope: TypedEnvelope<T::ProtoRequest>,
8101 mut cx: AsyncApp,
8102 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8103 where
8104 <T::LspRequest as lsp::request::Request>::Params: Send,
8105 <T::LspRequest as lsp::request::Request>::Result: Send,
8106 {
8107 let sender_id = envelope.original_sender_id().unwrap_or_default();
8108 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8109 let buffer_handle = this.update(&mut cx, |this, cx| {
8110 this.buffer_store.read(cx).get_existing(buffer_id)
8111 })??;
8112 let request = T::from_proto(
8113 envelope.payload,
8114 this.clone(),
8115 buffer_handle.clone(),
8116 cx.clone(),
8117 )
8118 .await?;
8119 let response = this
8120 .update(&mut cx, |this, cx| {
8121 this.request_lsp(
8122 buffer_handle.clone(),
8123 LanguageServerToQuery::FirstCapable,
8124 request,
8125 cx,
8126 )
8127 })?
8128 .await?;
8129 this.update(&mut cx, |this, cx| {
8130 Ok(T::response_to_proto(
8131 response,
8132 this,
8133 sender_id,
8134 &buffer_handle.read(cx).version(),
8135 cx,
8136 ))
8137 })?
8138 }
8139
8140 async fn handle_multi_lsp_query(
8141 lsp_store: Entity<Self>,
8142 envelope: TypedEnvelope<proto::MultiLspQuery>,
8143 mut cx: AsyncApp,
8144 ) -> Result<proto::MultiLspQueryResponse> {
8145 let response_from_ssh = lsp_store.read_with(&cx, |this, _| {
8146 let (upstream_client, project_id) = this.upstream_client()?;
8147 let mut payload = envelope.payload.clone();
8148 payload.project_id = project_id;
8149
8150 Some(upstream_client.request(payload))
8151 })?;
8152 if let Some(response_from_ssh) = response_from_ssh {
8153 return response_from_ssh.await;
8154 }
8155
8156 let sender_id = envelope.original_sender_id().unwrap_or_default();
8157 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8158 let version = deserialize_version(&envelope.payload.version);
8159 let buffer = lsp_store.update(&mut cx, |this, cx| {
8160 this.buffer_store.read(cx).get_existing(buffer_id)
8161 })??;
8162 buffer
8163 .update(&mut cx, |buffer, _| {
8164 buffer.wait_for_version(version.clone())
8165 })?
8166 .await?;
8167 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
8168 match envelope
8169 .payload
8170 .strategy
8171 .context("invalid request without the strategy")?
8172 {
8173 proto::multi_lsp_query::Strategy::All(_) => {
8174 // currently, there's only one multiple language servers query strategy,
8175 // so just ensure it's specified correctly
8176 }
8177 }
8178 match envelope.payload.request {
8179 Some(proto::multi_lsp_query::Request::GetHover(message)) => {
8180 buffer
8181 .update(&mut cx, |buffer, _| {
8182 buffer.wait_for_version(deserialize_version(&message.version))
8183 })?
8184 .await?;
8185 let get_hover =
8186 GetHover::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8187 .await?;
8188 let all_hovers = lsp_store
8189 .update(&mut cx, |this, cx| {
8190 this.request_multiple_lsp_locally(
8191 &buffer,
8192 Some(get_hover.position),
8193 get_hover,
8194 cx,
8195 )
8196 })?
8197 .await
8198 .into_iter()
8199 .filter_map(|(server_id, hover)| {
8200 Some((server_id, remove_empty_hover_blocks(hover?)?))
8201 });
8202 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8203 responses: all_hovers
8204 .map(|(server_id, hover)| proto::LspResponse {
8205 server_id: server_id.to_proto(),
8206 response: Some(proto::lsp_response::Response::GetHoverResponse(
8207 GetHover::response_to_proto(
8208 Some(hover),
8209 project,
8210 sender_id,
8211 &buffer_version,
8212 cx,
8213 ),
8214 )),
8215 })
8216 .collect(),
8217 })
8218 }
8219 Some(proto::multi_lsp_query::Request::GetCodeActions(message)) => {
8220 buffer
8221 .update(&mut cx, |buffer, _| {
8222 buffer.wait_for_version(deserialize_version(&message.version))
8223 })?
8224 .await?;
8225 let get_code_actions = GetCodeActions::from_proto(
8226 message,
8227 lsp_store.clone(),
8228 buffer.clone(),
8229 cx.clone(),
8230 )
8231 .await?;
8232
8233 let all_actions = lsp_store
8234 .update(&mut cx, |project, cx| {
8235 project.request_multiple_lsp_locally(
8236 &buffer,
8237 Some(get_code_actions.range.start),
8238 get_code_actions,
8239 cx,
8240 )
8241 })?
8242 .await
8243 .into_iter();
8244
8245 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8246 responses: all_actions
8247 .map(|(server_id, code_actions)| proto::LspResponse {
8248 server_id: server_id.to_proto(),
8249 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
8250 GetCodeActions::response_to_proto(
8251 code_actions,
8252 project,
8253 sender_id,
8254 &buffer_version,
8255 cx,
8256 ),
8257 )),
8258 })
8259 .collect(),
8260 })
8261 }
8262 Some(proto::multi_lsp_query::Request::GetSignatureHelp(message)) => {
8263 buffer
8264 .update(&mut cx, |buffer, _| {
8265 buffer.wait_for_version(deserialize_version(&message.version))
8266 })?
8267 .await?;
8268 let get_signature_help = GetSignatureHelp::from_proto(
8269 message,
8270 lsp_store.clone(),
8271 buffer.clone(),
8272 cx.clone(),
8273 )
8274 .await?;
8275
8276 let all_signatures = lsp_store
8277 .update(&mut cx, |project, cx| {
8278 project.request_multiple_lsp_locally(
8279 &buffer,
8280 Some(get_signature_help.position),
8281 get_signature_help,
8282 cx,
8283 )
8284 })?
8285 .await
8286 .into_iter();
8287
8288 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8289 responses: all_signatures
8290 .map(|(server_id, signature_help)| proto::LspResponse {
8291 server_id: server_id.to_proto(),
8292 response: Some(
8293 proto::lsp_response::Response::GetSignatureHelpResponse(
8294 GetSignatureHelp::response_to_proto(
8295 signature_help,
8296 project,
8297 sender_id,
8298 &buffer_version,
8299 cx,
8300 ),
8301 ),
8302 ),
8303 })
8304 .collect(),
8305 })
8306 }
8307 Some(proto::multi_lsp_query::Request::GetCodeLens(message)) => {
8308 buffer
8309 .update(&mut cx, |buffer, _| {
8310 buffer.wait_for_version(deserialize_version(&message.version))
8311 })?
8312 .await?;
8313 let get_code_lens =
8314 GetCodeLens::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8315 .await?;
8316
8317 let code_lens_actions = lsp_store
8318 .update(&mut cx, |project, cx| {
8319 project.request_multiple_lsp_locally(
8320 &buffer,
8321 None::<usize>,
8322 get_code_lens,
8323 cx,
8324 )
8325 })?
8326 .await
8327 .into_iter();
8328
8329 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8330 responses: code_lens_actions
8331 .map(|(server_id, actions)| proto::LspResponse {
8332 server_id: server_id.to_proto(),
8333 response: Some(proto::lsp_response::Response::GetCodeLensResponse(
8334 GetCodeLens::response_to_proto(
8335 actions,
8336 project,
8337 sender_id,
8338 &buffer_version,
8339 cx,
8340 ),
8341 )),
8342 })
8343 .collect(),
8344 })
8345 }
8346 Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(message)) => {
8347 buffer
8348 .update(&mut cx, |buffer, _| {
8349 buffer.wait_for_version(deserialize_version(&message.version))
8350 })?
8351 .await?;
8352 lsp_store
8353 .update(&mut cx, |lsp_store, cx| {
8354 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8355 })?
8356 .await?;
8357 // `pull_diagnostics_for_buffer` will merge in the new diagnostics and send them to the client.
8358 // The client cannot merge anything into its non-local LspStore, so we do not need to return anything.
8359 Ok(proto::MultiLspQueryResponse {
8360 responses: Vec::new(),
8361 })
8362 }
8363 Some(proto::multi_lsp_query::Request::GetDocumentColor(message)) => {
8364 buffer
8365 .update(&mut cx, |buffer, _| {
8366 buffer.wait_for_version(deserialize_version(&message.version))
8367 })?
8368 .await?;
8369 let get_document_color = GetDocumentColor::from_proto(
8370 message,
8371 lsp_store.clone(),
8372 buffer.clone(),
8373 cx.clone(),
8374 )
8375 .await?;
8376
8377 let all_colors = lsp_store
8378 .update(&mut cx, |project, cx| {
8379 project.request_multiple_lsp_locally(
8380 &buffer,
8381 None::<usize>,
8382 get_document_color,
8383 cx,
8384 )
8385 })?
8386 .await
8387 .into_iter();
8388
8389 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8390 responses: all_colors
8391 .map(|(server_id, colors)| proto::LspResponse {
8392 server_id: server_id.to_proto(),
8393 response: Some(
8394 proto::lsp_response::Response::GetDocumentColorResponse(
8395 GetDocumentColor::response_to_proto(
8396 colors,
8397 project,
8398 sender_id,
8399 &buffer_version,
8400 cx,
8401 ),
8402 ),
8403 ),
8404 })
8405 .collect(),
8406 })
8407 }
8408 Some(proto::multi_lsp_query::Request::GetDefinition(message)) => {
8409 let get_definitions = GetDefinitions::from_proto(
8410 message,
8411 lsp_store.clone(),
8412 buffer.clone(),
8413 cx.clone(),
8414 )
8415 .await?;
8416
8417 let definitions = lsp_store
8418 .update(&mut cx, |project, cx| {
8419 project.request_multiple_lsp_locally(
8420 &buffer,
8421 Some(get_definitions.position),
8422 get_definitions,
8423 cx,
8424 )
8425 })?
8426 .await
8427 .into_iter();
8428
8429 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8430 responses: definitions
8431 .map(|(server_id, definitions)| proto::LspResponse {
8432 server_id: server_id.to_proto(),
8433 response: Some(proto::lsp_response::Response::GetDefinitionResponse(
8434 GetDefinitions::response_to_proto(
8435 definitions,
8436 project,
8437 sender_id,
8438 &buffer_version,
8439 cx,
8440 ),
8441 )),
8442 })
8443 .collect(),
8444 })
8445 }
8446 Some(proto::multi_lsp_query::Request::GetDeclaration(message)) => {
8447 let get_declarations = GetDeclarations::from_proto(
8448 message,
8449 lsp_store.clone(),
8450 buffer.clone(),
8451 cx.clone(),
8452 )
8453 .await?;
8454
8455 let declarations = lsp_store
8456 .update(&mut cx, |project, cx| {
8457 project.request_multiple_lsp_locally(
8458 &buffer,
8459 Some(get_declarations.position),
8460 get_declarations,
8461 cx,
8462 )
8463 })?
8464 .await
8465 .into_iter();
8466
8467 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8468 responses: declarations
8469 .map(|(server_id, declarations)| proto::LspResponse {
8470 server_id: server_id.to_proto(),
8471 response: Some(proto::lsp_response::Response::GetDeclarationResponse(
8472 GetDeclarations::response_to_proto(
8473 declarations,
8474 project,
8475 sender_id,
8476 &buffer_version,
8477 cx,
8478 ),
8479 )),
8480 })
8481 .collect(),
8482 })
8483 }
8484 Some(proto::multi_lsp_query::Request::GetTypeDefinition(message)) => {
8485 let get_type_definitions = GetTypeDefinitions::from_proto(
8486 message,
8487 lsp_store.clone(),
8488 buffer.clone(),
8489 cx.clone(),
8490 )
8491 .await?;
8492
8493 let type_definitions = lsp_store
8494 .update(&mut cx, |project, cx| {
8495 project.request_multiple_lsp_locally(
8496 &buffer,
8497 Some(get_type_definitions.position),
8498 get_type_definitions,
8499 cx,
8500 )
8501 })?
8502 .await
8503 .into_iter();
8504
8505 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8506 responses: type_definitions
8507 .map(|(server_id, type_definitions)| proto::LspResponse {
8508 server_id: server_id.to_proto(),
8509 response: Some(
8510 proto::lsp_response::Response::GetTypeDefinitionResponse(
8511 GetTypeDefinitions::response_to_proto(
8512 type_definitions,
8513 project,
8514 sender_id,
8515 &buffer_version,
8516 cx,
8517 ),
8518 ),
8519 ),
8520 })
8521 .collect(),
8522 })
8523 }
8524 Some(proto::multi_lsp_query::Request::GetImplementation(message)) => {
8525 let get_implementations = GetImplementations::from_proto(
8526 message,
8527 lsp_store.clone(),
8528 buffer.clone(),
8529 cx.clone(),
8530 )
8531 .await?;
8532
8533 let implementations = lsp_store
8534 .update(&mut cx, |project, cx| {
8535 project.request_multiple_lsp_locally(
8536 &buffer,
8537 Some(get_implementations.position),
8538 get_implementations,
8539 cx,
8540 )
8541 })?
8542 .await
8543 .into_iter();
8544
8545 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8546 responses: implementations
8547 .map(|(server_id, implementations)| proto::LspResponse {
8548 server_id: server_id.to_proto(),
8549 response: Some(
8550 proto::lsp_response::Response::GetImplementationResponse(
8551 GetImplementations::response_to_proto(
8552 implementations,
8553 project,
8554 sender_id,
8555 &buffer_version,
8556 cx,
8557 ),
8558 ),
8559 ),
8560 })
8561 .collect(),
8562 })
8563 }
8564 Some(proto::multi_lsp_query::Request::GetReferences(message)) => {
8565 let get_references = GetReferences::from_proto(
8566 message,
8567 lsp_store.clone(),
8568 buffer.clone(),
8569 cx.clone(),
8570 )
8571 .await?;
8572
8573 let references = lsp_store
8574 .update(&mut cx, |project, cx| {
8575 project.request_multiple_lsp_locally(
8576 &buffer,
8577 Some(get_references.position),
8578 get_references,
8579 cx,
8580 )
8581 })?
8582 .await
8583 .into_iter();
8584
8585 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8586 responses: references
8587 .map(|(server_id, references)| proto::LspResponse {
8588 server_id: server_id.to_proto(),
8589 response: Some(proto::lsp_response::Response::GetReferencesResponse(
8590 GetReferences::response_to_proto(
8591 references,
8592 project,
8593 sender_id,
8594 &buffer_version,
8595 cx,
8596 ),
8597 )),
8598 })
8599 .collect(),
8600 })
8601 }
8602 None => anyhow::bail!("empty multi lsp query request"),
8603 }
8604 }
8605
8606 async fn handle_apply_code_action(
8607 this: Entity<Self>,
8608 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8609 mut cx: AsyncApp,
8610 ) -> Result<proto::ApplyCodeActionResponse> {
8611 let sender_id = envelope.original_sender_id().unwrap_or_default();
8612 let action =
8613 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8614 let apply_code_action = this.update(&mut cx, |this, cx| {
8615 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8616 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8617 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8618 })??;
8619
8620 let project_transaction = apply_code_action.await?;
8621 let project_transaction = this.update(&mut cx, |this, cx| {
8622 this.buffer_store.update(cx, |buffer_store, cx| {
8623 buffer_store.serialize_project_transaction_for_peer(
8624 project_transaction,
8625 sender_id,
8626 cx,
8627 )
8628 })
8629 })?;
8630 Ok(proto::ApplyCodeActionResponse {
8631 transaction: Some(project_transaction),
8632 })
8633 }
8634
8635 async fn handle_register_buffer_with_language_servers(
8636 this: Entity<Self>,
8637 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8638 mut cx: AsyncApp,
8639 ) -> Result<proto::Ack> {
8640 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8641 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8642 this.update(&mut cx, |this, cx| {
8643 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8644 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8645 project_id: upstream_project_id,
8646 buffer_id: buffer_id.to_proto(),
8647 only_servers: envelope.payload.only_servers,
8648 });
8649 }
8650
8651 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8652 anyhow::bail!("buffer is not open");
8653 };
8654
8655 let handle = this.register_buffer_with_language_servers(
8656 &buffer,
8657 envelope
8658 .payload
8659 .only_servers
8660 .into_iter()
8661 .filter_map(|selector| {
8662 Some(match selector.selector? {
8663 proto::language_server_selector::Selector::ServerId(server_id) => {
8664 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8665 }
8666 proto::language_server_selector::Selector::Name(name) => {
8667 LanguageServerSelector::Name(LanguageServerName(
8668 SharedString::from(name),
8669 ))
8670 }
8671 })
8672 })
8673 .collect(),
8674 false,
8675 cx,
8676 );
8677 this.buffer_store().update(cx, |buffer_store, _| {
8678 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8679 });
8680
8681 Ok(())
8682 })??;
8683 Ok(proto::Ack {})
8684 }
8685
8686 async fn handle_rename_project_entry(
8687 this: Entity<Self>,
8688 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8689 mut cx: AsyncApp,
8690 ) -> Result<proto::ProjectEntryResponse> {
8691 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8692 let (worktree_id, worktree, old_path, is_dir) = this
8693 .update(&mut cx, |this, cx| {
8694 this.worktree_store
8695 .read(cx)
8696 .worktree_and_entry_for_id(entry_id, cx)
8697 .map(|(worktree, entry)| {
8698 (
8699 worktree.read(cx).id(),
8700 worktree,
8701 entry.path.clone(),
8702 entry.is_dir(),
8703 )
8704 })
8705 })?
8706 .context("worktree not found")?;
8707 let (old_abs_path, new_abs_path) = {
8708 let root_path = worktree.read_with(&cx, |this, _| this.abs_path())?;
8709 let new_path = PathBuf::from_proto(envelope.payload.new_path.clone());
8710 (root_path.join(&old_path), root_path.join(&new_path))
8711 };
8712
8713 Self::will_rename_entry(
8714 this.downgrade(),
8715 worktree_id,
8716 &old_abs_path,
8717 &new_abs_path,
8718 is_dir,
8719 cx.clone(),
8720 )
8721 .await;
8722 let response = Worktree::handle_rename_entry(worktree, envelope.payload, cx.clone()).await;
8723 this.read_with(&cx, |this, _| {
8724 this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
8725 })
8726 .ok();
8727 response
8728 }
8729
8730 async fn handle_update_diagnostic_summary(
8731 this: Entity<Self>,
8732 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8733 mut cx: AsyncApp,
8734 ) -> Result<()> {
8735 this.update(&mut cx, |lsp_store, cx| {
8736 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8737 let mut updated_diagnostics_paths = HashMap::default();
8738 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8739 for message_summary in envelope
8740 .payload
8741 .summary
8742 .into_iter()
8743 .chain(envelope.payload.more_summaries)
8744 {
8745 let project_path = ProjectPath {
8746 worktree_id,
8747 path: Arc::<Path>::from_proto(message_summary.path),
8748 };
8749 let path = project_path.path.clone();
8750 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8751 let summary = DiagnosticSummary {
8752 error_count: message_summary.error_count as usize,
8753 warning_count: message_summary.warning_count as usize,
8754 };
8755
8756 if summary.is_empty() {
8757 if let Some(worktree_summaries) =
8758 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8759 && let Some(summaries) = worktree_summaries.get_mut(&path)
8760 {
8761 summaries.remove(&server_id);
8762 if summaries.is_empty() {
8763 worktree_summaries.remove(&path);
8764 }
8765 }
8766 } else {
8767 lsp_store
8768 .diagnostic_summaries
8769 .entry(worktree_id)
8770 .or_default()
8771 .entry(path)
8772 .or_default()
8773 .insert(server_id, summary);
8774 }
8775
8776 if let Some((_, project_id)) = &lsp_store.downstream_client {
8777 match &mut diagnostics_summary {
8778 Some(diagnostics_summary) => {
8779 diagnostics_summary
8780 .more_summaries
8781 .push(proto::DiagnosticSummary {
8782 path: project_path.path.as_ref().to_proto(),
8783 language_server_id: server_id.0 as u64,
8784 error_count: summary.error_count as u32,
8785 warning_count: summary.warning_count as u32,
8786 })
8787 }
8788 None => {
8789 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8790 project_id: *project_id,
8791 worktree_id: worktree_id.to_proto(),
8792 summary: Some(proto::DiagnosticSummary {
8793 path: project_path.path.as_ref().to_proto(),
8794 language_server_id: server_id.0 as u64,
8795 error_count: summary.error_count as u32,
8796 warning_count: summary.warning_count as u32,
8797 }),
8798 more_summaries: Vec::new(),
8799 })
8800 }
8801 }
8802 }
8803 updated_diagnostics_paths
8804 .entry(server_id)
8805 .or_insert_with(Vec::new)
8806 .push(project_path);
8807 }
8808
8809 if let Some((diagnostics_summary, (downstream_client, _))) =
8810 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8811 {
8812 downstream_client.send(diagnostics_summary).log_err();
8813 }
8814 for (server_id, paths) in updated_diagnostics_paths {
8815 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8816 }
8817 Ok(())
8818 })?
8819 }
8820
8821 async fn handle_start_language_server(
8822 lsp_store: Entity<Self>,
8823 envelope: TypedEnvelope<proto::StartLanguageServer>,
8824 mut cx: AsyncApp,
8825 ) -> Result<()> {
8826 let server = envelope.payload.server.context("invalid server")?;
8827 let server_capabilities =
8828 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8829 .with_context(|| {
8830 format!(
8831 "incorrect server capabilities {}",
8832 envelope.payload.capabilities
8833 )
8834 })?;
8835 lsp_store.update(&mut cx, |lsp_store, cx| {
8836 let server_id = LanguageServerId(server.id as usize);
8837 let server_name = LanguageServerName::from_proto(server.name.clone());
8838 lsp_store
8839 .lsp_server_capabilities
8840 .insert(server_id, server_capabilities);
8841 lsp_store.language_server_statuses.insert(
8842 server_id,
8843 LanguageServerStatus {
8844 name: server_name.clone(),
8845 pending_work: Default::default(),
8846 has_pending_diagnostic_updates: false,
8847 progress_tokens: Default::default(),
8848 },
8849 );
8850 cx.emit(LspStoreEvent::LanguageServerAdded(
8851 server_id,
8852 server_name,
8853 server.worktree_id.map(WorktreeId::from_proto),
8854 ));
8855 cx.notify();
8856 })?;
8857 Ok(())
8858 }
8859
8860 async fn handle_update_language_server(
8861 lsp_store: Entity<Self>,
8862 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8863 mut cx: AsyncApp,
8864 ) -> Result<()> {
8865 lsp_store.update(&mut cx, |lsp_store, cx| {
8866 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8867
8868 match envelope.payload.variant.context("invalid variant")? {
8869 proto::update_language_server::Variant::WorkStart(payload) => {
8870 lsp_store.on_lsp_work_start(
8871 language_server_id,
8872 payload.token,
8873 LanguageServerProgress {
8874 title: payload.title,
8875 is_disk_based_diagnostics_progress: false,
8876 is_cancellable: payload.is_cancellable.unwrap_or(false),
8877 message: payload.message,
8878 percentage: payload.percentage.map(|p| p as usize),
8879 last_update_at: cx.background_executor().now(),
8880 },
8881 cx,
8882 );
8883 }
8884 proto::update_language_server::Variant::WorkProgress(payload) => {
8885 lsp_store.on_lsp_work_progress(
8886 language_server_id,
8887 payload.token,
8888 LanguageServerProgress {
8889 title: None,
8890 is_disk_based_diagnostics_progress: false,
8891 is_cancellable: payload.is_cancellable.unwrap_or(false),
8892 message: payload.message,
8893 percentage: payload.percentage.map(|p| p as usize),
8894 last_update_at: cx.background_executor().now(),
8895 },
8896 cx,
8897 );
8898 }
8899
8900 proto::update_language_server::Variant::WorkEnd(payload) => {
8901 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8902 }
8903
8904 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8905 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8906 }
8907
8908 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8909 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8910 }
8911
8912 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8913 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8914 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8915 cx.emit(LspStoreEvent::LanguageServerUpdate {
8916 language_server_id,
8917 name: envelope
8918 .payload
8919 .server_name
8920 .map(SharedString::new)
8921 .map(LanguageServerName),
8922 message: non_lsp,
8923 });
8924 }
8925 }
8926
8927 Ok(())
8928 })?
8929 }
8930
8931 async fn handle_language_server_log(
8932 this: Entity<Self>,
8933 envelope: TypedEnvelope<proto::LanguageServerLog>,
8934 mut cx: AsyncApp,
8935 ) -> Result<()> {
8936 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8937 let log_type = envelope
8938 .payload
8939 .log_type
8940 .map(LanguageServerLogType::from_proto)
8941 .context("invalid language server log type")?;
8942
8943 let message = envelope.payload.message;
8944
8945 this.update(&mut cx, |_, cx| {
8946 cx.emit(LspStoreEvent::LanguageServerLog(
8947 language_server_id,
8948 log_type,
8949 message,
8950 ));
8951 })
8952 }
8953
8954 async fn handle_lsp_ext_cancel_flycheck(
8955 lsp_store: Entity<Self>,
8956 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
8957 cx: AsyncApp,
8958 ) -> Result<proto::Ack> {
8959 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8960 lsp_store.read_with(&cx, |lsp_store, _| {
8961 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8962 server
8963 .notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(&())
8964 .context("handling lsp ext cancel flycheck")
8965 } else {
8966 anyhow::Ok(())
8967 }
8968 })??;
8969
8970 Ok(proto::Ack {})
8971 }
8972
8973 async fn handle_lsp_ext_run_flycheck(
8974 lsp_store: Entity<Self>,
8975 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
8976 mut cx: AsyncApp,
8977 ) -> Result<proto::Ack> {
8978 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8979 lsp_store.update(&mut cx, |lsp_store, cx| {
8980 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8981 let text_document = if envelope.payload.current_file_only {
8982 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8983 lsp_store
8984 .buffer_store()
8985 .read(cx)
8986 .get(buffer_id)
8987 .and_then(|buffer| Some(buffer.read(cx).file()?.as_local()?.abs_path(cx)))
8988 .map(|path| make_text_document_identifier(&path))
8989 .transpose()?
8990 } else {
8991 None
8992 };
8993 server
8994 .notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
8995 &lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
8996 )
8997 .context("handling lsp ext run flycheck")
8998 } else {
8999 anyhow::Ok(())
9000 }
9001 })??;
9002
9003 Ok(proto::Ack {})
9004 }
9005
9006 async fn handle_lsp_ext_clear_flycheck(
9007 lsp_store: Entity<Self>,
9008 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9009 cx: AsyncApp,
9010 ) -> Result<proto::Ack> {
9011 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9012 lsp_store.read_with(&cx, |lsp_store, _| {
9013 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9014 server
9015 .notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(&())
9016 .context("handling lsp ext clear flycheck")
9017 } else {
9018 anyhow::Ok(())
9019 }
9020 })??;
9021
9022 Ok(proto::Ack {})
9023 }
9024
9025 pub fn disk_based_diagnostics_started(
9026 &mut self,
9027 language_server_id: LanguageServerId,
9028 cx: &mut Context<Self>,
9029 ) {
9030 if let Some(language_server_status) =
9031 self.language_server_statuses.get_mut(&language_server_id)
9032 {
9033 language_server_status.has_pending_diagnostic_updates = true;
9034 }
9035
9036 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9037 cx.emit(LspStoreEvent::LanguageServerUpdate {
9038 language_server_id,
9039 name: self
9040 .language_server_adapter_for_id(language_server_id)
9041 .map(|adapter| adapter.name()),
9042 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9043 Default::default(),
9044 ),
9045 })
9046 }
9047
9048 pub fn disk_based_diagnostics_finished(
9049 &mut self,
9050 language_server_id: LanguageServerId,
9051 cx: &mut Context<Self>,
9052 ) {
9053 if let Some(language_server_status) =
9054 self.language_server_statuses.get_mut(&language_server_id)
9055 {
9056 language_server_status.has_pending_diagnostic_updates = false;
9057 }
9058
9059 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9060 cx.emit(LspStoreEvent::LanguageServerUpdate {
9061 language_server_id,
9062 name: self
9063 .language_server_adapter_for_id(language_server_id)
9064 .map(|adapter| adapter.name()),
9065 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9066 Default::default(),
9067 ),
9068 })
9069 }
9070
9071 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9072 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9073 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9074 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9075 // the language server might take some time to publish diagnostics.
9076 fn simulate_disk_based_diagnostics_events_if_needed(
9077 &mut self,
9078 language_server_id: LanguageServerId,
9079 cx: &mut Context<Self>,
9080 ) {
9081 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9082
9083 let Some(LanguageServerState::Running {
9084 simulate_disk_based_diagnostics_completion,
9085 adapter,
9086 ..
9087 }) = self
9088 .as_local_mut()
9089 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9090 else {
9091 return;
9092 };
9093
9094 if adapter.disk_based_diagnostics_progress_token.is_some() {
9095 return;
9096 }
9097
9098 let prev_task =
9099 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9100 cx.background_executor()
9101 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9102 .await;
9103
9104 this.update(cx, |this, cx| {
9105 this.disk_based_diagnostics_finished(language_server_id, cx);
9106
9107 if let Some(LanguageServerState::Running {
9108 simulate_disk_based_diagnostics_completion,
9109 ..
9110 }) = this.as_local_mut().and_then(|local_store| {
9111 local_store.language_servers.get_mut(&language_server_id)
9112 }) {
9113 *simulate_disk_based_diagnostics_completion = None;
9114 }
9115 })
9116 .ok();
9117 }));
9118
9119 if prev_task.is_none() {
9120 self.disk_based_diagnostics_started(language_server_id, cx);
9121 }
9122 }
9123
9124 pub fn language_server_statuses(
9125 &self,
9126 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9127 self.language_server_statuses
9128 .iter()
9129 .map(|(key, value)| (*key, value))
9130 }
9131
9132 pub(super) fn did_rename_entry(
9133 &self,
9134 worktree_id: WorktreeId,
9135 old_path: &Path,
9136 new_path: &Path,
9137 is_dir: bool,
9138 ) {
9139 maybe!({
9140 let local_store = self.as_local()?;
9141
9142 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from)?;
9143 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from)?;
9144
9145 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9146 let Some(filter) = local_store
9147 .language_server_paths_watched_for_rename
9148 .get(&language_server.server_id())
9149 else {
9150 continue;
9151 };
9152
9153 if filter.should_send_did_rename(&old_uri, is_dir) {
9154 language_server
9155 .notify::<DidRenameFiles>(&RenameFilesParams {
9156 files: vec![FileRename {
9157 old_uri: old_uri.clone(),
9158 new_uri: new_uri.clone(),
9159 }],
9160 })
9161 .ok();
9162 }
9163 }
9164 Some(())
9165 });
9166 }
9167
9168 pub(super) fn will_rename_entry(
9169 this: WeakEntity<Self>,
9170 worktree_id: WorktreeId,
9171 old_path: &Path,
9172 new_path: &Path,
9173 is_dir: bool,
9174 cx: AsyncApp,
9175 ) -> Task<()> {
9176 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from);
9177 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from);
9178 cx.spawn(async move |cx| {
9179 let mut tasks = vec![];
9180 this.update(cx, |this, cx| {
9181 let local_store = this.as_local()?;
9182 let old_uri = old_uri?;
9183 let new_uri = new_uri?;
9184 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9185 let Some(filter) = local_store
9186 .language_server_paths_watched_for_rename
9187 .get(&language_server.server_id())
9188 else {
9189 continue;
9190 };
9191
9192 if filter.should_send_will_rename(&old_uri, is_dir) {
9193 let apply_edit = cx.spawn({
9194 let old_uri = old_uri.clone();
9195 let new_uri = new_uri.clone();
9196 let language_server = language_server.clone();
9197 async move |this, cx| {
9198 let edit = language_server
9199 .request::<WillRenameFiles>(RenameFilesParams {
9200 files: vec![FileRename { old_uri, new_uri }],
9201 })
9202 .await
9203 .into_response()
9204 .context("will rename files")
9205 .log_err()
9206 .flatten()?;
9207
9208 LocalLspStore::deserialize_workspace_edit(
9209 this.upgrade()?,
9210 edit,
9211 false,
9212 language_server.clone(),
9213 cx,
9214 )
9215 .await
9216 .ok();
9217 Some(())
9218 }
9219 });
9220 tasks.push(apply_edit);
9221 }
9222 }
9223 Some(())
9224 })
9225 .ok()
9226 .flatten();
9227 for task in tasks {
9228 // Await on tasks sequentially so that the order of application of edits is deterministic
9229 // (at least with regards to the order of registration of language servers)
9230 task.await;
9231 }
9232 })
9233 }
9234
9235 fn lsp_notify_abs_paths_changed(
9236 &mut self,
9237 server_id: LanguageServerId,
9238 changes: Vec<PathEvent>,
9239 ) {
9240 maybe!({
9241 let server = self.language_server_for_id(server_id)?;
9242 let changes = changes
9243 .into_iter()
9244 .filter_map(|event| {
9245 let typ = match event.kind? {
9246 PathEventKind::Created => lsp::FileChangeType::CREATED,
9247 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9248 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9249 };
9250 Some(lsp::FileEvent {
9251 uri: file_path_to_lsp_url(&event.path).log_err()?,
9252 typ,
9253 })
9254 })
9255 .collect::<Vec<_>>();
9256 if !changes.is_empty() {
9257 server
9258 .notify::<lsp::notification::DidChangeWatchedFiles>(
9259 &lsp::DidChangeWatchedFilesParams { changes },
9260 )
9261 .ok();
9262 }
9263 Some(())
9264 });
9265 }
9266
9267 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9268 self.as_local()?.language_server_for_id(id)
9269 }
9270
9271 fn on_lsp_progress(
9272 &mut self,
9273 progress: lsp::ProgressParams,
9274 language_server_id: LanguageServerId,
9275 disk_based_diagnostics_progress_token: Option<String>,
9276 cx: &mut Context<Self>,
9277 ) {
9278 let token = match progress.token {
9279 lsp::NumberOrString::String(token) => token,
9280 lsp::NumberOrString::Number(token) => {
9281 log::info!("skipping numeric progress token {}", token);
9282 return;
9283 }
9284 };
9285
9286 match progress.value {
9287 lsp::ProgressParamsValue::WorkDone(progress) => {
9288 self.handle_work_done_progress(
9289 progress,
9290 language_server_id,
9291 disk_based_diagnostics_progress_token,
9292 token,
9293 cx,
9294 );
9295 }
9296 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9297 if let Some(LanguageServerState::Running {
9298 workspace_refresh_task: Some(workspace_refresh_task),
9299 ..
9300 }) = self
9301 .as_local_mut()
9302 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9303 {
9304 workspace_refresh_task.progress_tx.try_send(()).ok();
9305 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9306 }
9307 }
9308 }
9309 }
9310
9311 fn handle_work_done_progress(
9312 &mut self,
9313 progress: lsp::WorkDoneProgress,
9314 language_server_id: LanguageServerId,
9315 disk_based_diagnostics_progress_token: Option<String>,
9316 token: String,
9317 cx: &mut Context<Self>,
9318 ) {
9319 let language_server_status =
9320 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9321 status
9322 } else {
9323 return;
9324 };
9325
9326 if !language_server_status.progress_tokens.contains(&token) {
9327 return;
9328 }
9329
9330 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9331 .as_ref()
9332 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9333
9334 match progress {
9335 lsp::WorkDoneProgress::Begin(report) => {
9336 if is_disk_based_diagnostics_progress {
9337 self.disk_based_diagnostics_started(language_server_id, cx);
9338 }
9339 self.on_lsp_work_start(
9340 language_server_id,
9341 token.clone(),
9342 LanguageServerProgress {
9343 title: Some(report.title),
9344 is_disk_based_diagnostics_progress,
9345 is_cancellable: report.cancellable.unwrap_or(false),
9346 message: report.message.clone(),
9347 percentage: report.percentage.map(|p| p as usize),
9348 last_update_at: cx.background_executor().now(),
9349 },
9350 cx,
9351 );
9352 }
9353 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9354 language_server_id,
9355 token,
9356 LanguageServerProgress {
9357 title: None,
9358 is_disk_based_diagnostics_progress,
9359 is_cancellable: report.cancellable.unwrap_or(false),
9360 message: report.message,
9361 percentage: report.percentage.map(|p| p as usize),
9362 last_update_at: cx.background_executor().now(),
9363 },
9364 cx,
9365 ),
9366 lsp::WorkDoneProgress::End(_) => {
9367 language_server_status.progress_tokens.remove(&token);
9368 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9369 if is_disk_based_diagnostics_progress {
9370 self.disk_based_diagnostics_finished(language_server_id, cx);
9371 }
9372 }
9373 }
9374 }
9375
9376 fn on_lsp_work_start(
9377 &mut self,
9378 language_server_id: LanguageServerId,
9379 token: String,
9380 progress: LanguageServerProgress,
9381 cx: &mut Context<Self>,
9382 ) {
9383 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9384 status.pending_work.insert(token.clone(), progress.clone());
9385 cx.notify();
9386 }
9387 cx.emit(LspStoreEvent::LanguageServerUpdate {
9388 language_server_id,
9389 name: self
9390 .language_server_adapter_for_id(language_server_id)
9391 .map(|adapter| adapter.name()),
9392 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9393 token,
9394 title: progress.title,
9395 message: progress.message,
9396 percentage: progress.percentage.map(|p| p as u32),
9397 is_cancellable: Some(progress.is_cancellable),
9398 }),
9399 })
9400 }
9401
9402 fn on_lsp_work_progress(
9403 &mut self,
9404 language_server_id: LanguageServerId,
9405 token: String,
9406 progress: LanguageServerProgress,
9407 cx: &mut Context<Self>,
9408 ) {
9409 let mut did_update = false;
9410 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9411 match status.pending_work.entry(token.clone()) {
9412 btree_map::Entry::Vacant(entry) => {
9413 entry.insert(progress.clone());
9414 did_update = true;
9415 }
9416 btree_map::Entry::Occupied(mut entry) => {
9417 let entry = entry.get_mut();
9418 if (progress.last_update_at - entry.last_update_at)
9419 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9420 {
9421 entry.last_update_at = progress.last_update_at;
9422 if progress.message.is_some() {
9423 entry.message = progress.message.clone();
9424 }
9425 if progress.percentage.is_some() {
9426 entry.percentage = progress.percentage;
9427 }
9428 if progress.is_cancellable != entry.is_cancellable {
9429 entry.is_cancellable = progress.is_cancellable;
9430 }
9431 did_update = true;
9432 }
9433 }
9434 }
9435 }
9436
9437 if did_update {
9438 cx.emit(LspStoreEvent::LanguageServerUpdate {
9439 language_server_id,
9440 name: self
9441 .language_server_adapter_for_id(language_server_id)
9442 .map(|adapter| adapter.name()),
9443 message: proto::update_language_server::Variant::WorkProgress(
9444 proto::LspWorkProgress {
9445 token,
9446 message: progress.message,
9447 percentage: progress.percentage.map(|p| p as u32),
9448 is_cancellable: Some(progress.is_cancellable),
9449 },
9450 ),
9451 })
9452 }
9453 }
9454
9455 fn on_lsp_work_end(
9456 &mut self,
9457 language_server_id: LanguageServerId,
9458 token: String,
9459 cx: &mut Context<Self>,
9460 ) {
9461 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9462 if let Some(work) = status.pending_work.remove(&token)
9463 && !work.is_disk_based_diagnostics_progress
9464 {
9465 cx.emit(LspStoreEvent::RefreshInlayHints);
9466 }
9467 cx.notify();
9468 }
9469
9470 cx.emit(LspStoreEvent::LanguageServerUpdate {
9471 language_server_id,
9472 name: self
9473 .language_server_adapter_for_id(language_server_id)
9474 .map(|adapter| adapter.name()),
9475 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9476 })
9477 }
9478
9479 pub async fn handle_resolve_completion_documentation(
9480 this: Entity<Self>,
9481 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9482 mut cx: AsyncApp,
9483 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9484 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9485
9486 let completion = this
9487 .read_with(&cx, |this, cx| {
9488 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9489 let server = this
9490 .language_server_for_id(id)
9491 .with_context(|| format!("No language server {id}"))?;
9492
9493 anyhow::Ok(cx.background_spawn(async move {
9494 let can_resolve = server
9495 .capabilities()
9496 .completion_provider
9497 .as_ref()
9498 .and_then(|options| options.resolve_provider)
9499 .unwrap_or(false);
9500 if can_resolve {
9501 server
9502 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9503 .await
9504 .into_response()
9505 .context("resolve completion item")
9506 } else {
9507 anyhow::Ok(lsp_completion)
9508 }
9509 }))
9510 })??
9511 .await?;
9512
9513 let mut documentation_is_markdown = false;
9514 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9515 let documentation = match completion.documentation {
9516 Some(lsp::Documentation::String(text)) => text,
9517
9518 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9519 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9520 value
9521 }
9522
9523 _ => String::new(),
9524 };
9525
9526 // If we have a new buffer_id, that means we're talking to a new client
9527 // and want to check for new text_edits in the completion too.
9528 let mut old_replace_start = None;
9529 let mut old_replace_end = None;
9530 let mut old_insert_start = None;
9531 let mut old_insert_end = None;
9532 let mut new_text = String::default();
9533 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9534 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9535 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9536 anyhow::Ok(buffer.read(cx).snapshot())
9537 })??;
9538
9539 if let Some(text_edit) = completion.text_edit.as_ref() {
9540 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9541
9542 if let Some(mut edit) = edit {
9543 LineEnding::normalize(&mut edit.new_text);
9544
9545 new_text = edit.new_text;
9546 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9547 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9548 if let Some(insert_range) = edit.insert_range {
9549 old_insert_start = Some(serialize_anchor(&insert_range.start));
9550 old_insert_end = Some(serialize_anchor(&insert_range.end));
9551 }
9552 }
9553 }
9554 }
9555
9556 Ok(proto::ResolveCompletionDocumentationResponse {
9557 documentation,
9558 documentation_is_markdown,
9559 old_replace_start,
9560 old_replace_end,
9561 new_text,
9562 lsp_completion,
9563 old_insert_start,
9564 old_insert_end,
9565 })
9566 }
9567
9568 async fn handle_on_type_formatting(
9569 this: Entity<Self>,
9570 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9571 mut cx: AsyncApp,
9572 ) -> Result<proto::OnTypeFormattingResponse> {
9573 let on_type_formatting = this.update(&mut cx, |this, cx| {
9574 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9575 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9576 let position = envelope
9577 .payload
9578 .position
9579 .and_then(deserialize_anchor)
9580 .context("invalid position")?;
9581 anyhow::Ok(this.apply_on_type_formatting(
9582 buffer,
9583 position,
9584 envelope.payload.trigger.clone(),
9585 cx,
9586 ))
9587 })??;
9588
9589 let transaction = on_type_formatting
9590 .await?
9591 .as_ref()
9592 .map(language::proto::serialize_transaction);
9593 Ok(proto::OnTypeFormattingResponse { transaction })
9594 }
9595
9596 async fn handle_refresh_inlay_hints(
9597 this: Entity<Self>,
9598 _: TypedEnvelope<proto::RefreshInlayHints>,
9599 mut cx: AsyncApp,
9600 ) -> Result<proto::Ack> {
9601 this.update(&mut cx, |_, cx| {
9602 cx.emit(LspStoreEvent::RefreshInlayHints);
9603 })?;
9604 Ok(proto::Ack {})
9605 }
9606
9607 async fn handle_pull_workspace_diagnostics(
9608 lsp_store: Entity<Self>,
9609 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9610 mut cx: AsyncApp,
9611 ) -> Result<proto::Ack> {
9612 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9613 lsp_store.update(&mut cx, |lsp_store, _| {
9614 lsp_store.pull_workspace_diagnostics(server_id);
9615 })?;
9616 Ok(proto::Ack {})
9617 }
9618
9619 async fn handle_inlay_hints(
9620 this: Entity<Self>,
9621 envelope: TypedEnvelope<proto::InlayHints>,
9622 mut cx: AsyncApp,
9623 ) -> Result<proto::InlayHintsResponse> {
9624 let sender_id = envelope.original_sender_id().unwrap_or_default();
9625 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9626 let buffer = this.update(&mut cx, |this, cx| {
9627 this.buffer_store.read(cx).get_existing(buffer_id)
9628 })??;
9629 buffer
9630 .update(&mut cx, |buffer, _| {
9631 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
9632 })?
9633 .await
9634 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
9635
9636 let start = envelope
9637 .payload
9638 .start
9639 .and_then(deserialize_anchor)
9640 .context("missing range start")?;
9641 let end = envelope
9642 .payload
9643 .end
9644 .and_then(deserialize_anchor)
9645 .context("missing range end")?;
9646 let buffer_hints = this
9647 .update(&mut cx, |lsp_store, cx| {
9648 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
9649 })?
9650 .await
9651 .context("inlay hints fetch")?;
9652
9653 this.update(&mut cx, |project, cx| {
9654 InlayHints::response_to_proto(
9655 buffer_hints,
9656 project,
9657 sender_id,
9658 &buffer.read(cx).version(),
9659 cx,
9660 )
9661 })
9662 }
9663
9664 async fn handle_get_color_presentation(
9665 lsp_store: Entity<Self>,
9666 envelope: TypedEnvelope<proto::GetColorPresentation>,
9667 mut cx: AsyncApp,
9668 ) -> Result<proto::GetColorPresentationResponse> {
9669 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9670 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9671 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9672 })??;
9673
9674 let color = envelope
9675 .payload
9676 .color
9677 .context("invalid color resolve request")?;
9678 let start = color
9679 .lsp_range_start
9680 .context("invalid color resolve request")?;
9681 let end = color
9682 .lsp_range_end
9683 .context("invalid color resolve request")?;
9684
9685 let color = DocumentColor {
9686 lsp_range: lsp::Range {
9687 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9688 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9689 },
9690 color: lsp::Color {
9691 red: color.red,
9692 green: color.green,
9693 blue: color.blue,
9694 alpha: color.alpha,
9695 },
9696 resolved: false,
9697 color_presentations: Vec::new(),
9698 };
9699 let resolved_color = lsp_store
9700 .update(&mut cx, |lsp_store, cx| {
9701 lsp_store.resolve_color_presentation(
9702 color,
9703 buffer.clone(),
9704 LanguageServerId(envelope.payload.server_id as usize),
9705 cx,
9706 )
9707 })?
9708 .await
9709 .context("resolving color presentation")?;
9710
9711 Ok(proto::GetColorPresentationResponse {
9712 presentations: resolved_color
9713 .color_presentations
9714 .into_iter()
9715 .map(|presentation| proto::ColorPresentation {
9716 label: presentation.label.to_string(),
9717 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9718 additional_text_edits: presentation
9719 .additional_text_edits
9720 .into_iter()
9721 .map(serialize_lsp_edit)
9722 .collect(),
9723 })
9724 .collect(),
9725 })
9726 }
9727
9728 async fn handle_resolve_inlay_hint(
9729 this: Entity<Self>,
9730 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9731 mut cx: AsyncApp,
9732 ) -> Result<proto::ResolveInlayHintResponse> {
9733 let proto_hint = envelope
9734 .payload
9735 .hint
9736 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9737 let hint = InlayHints::proto_to_project_hint(proto_hint)
9738 .context("resolved proto inlay hint conversion")?;
9739 let buffer = this.update(&mut cx, |this, cx| {
9740 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9741 this.buffer_store.read(cx).get_existing(buffer_id)
9742 })??;
9743 let response_hint = this
9744 .update(&mut cx, |this, cx| {
9745 this.resolve_inlay_hint(
9746 hint,
9747 buffer,
9748 LanguageServerId(envelope.payload.language_server_id as usize),
9749 cx,
9750 )
9751 })?
9752 .await
9753 .context("inlay hints fetch")?;
9754 Ok(proto::ResolveInlayHintResponse {
9755 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9756 })
9757 }
9758
9759 async fn handle_refresh_code_lens(
9760 this: Entity<Self>,
9761 _: TypedEnvelope<proto::RefreshCodeLens>,
9762 mut cx: AsyncApp,
9763 ) -> Result<proto::Ack> {
9764 this.update(&mut cx, |_, cx| {
9765 cx.emit(LspStoreEvent::RefreshCodeLens);
9766 })?;
9767 Ok(proto::Ack {})
9768 }
9769
9770 async fn handle_open_buffer_for_symbol(
9771 this: Entity<Self>,
9772 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9773 mut cx: AsyncApp,
9774 ) -> Result<proto::OpenBufferForSymbolResponse> {
9775 let peer_id = envelope.original_sender_id().unwrap_or_default();
9776 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9777 let symbol = Self::deserialize_symbol(symbol)?;
9778 let symbol = this.read_with(&cx, |this, _| {
9779 let signature = this.symbol_signature(&symbol.path);
9780 anyhow::ensure!(signature == symbol.signature, "invalid symbol signature");
9781 Ok(symbol)
9782 })??;
9783 let buffer = this
9784 .update(&mut cx, |this, cx| {
9785 this.open_buffer_for_symbol(
9786 &Symbol {
9787 language_server_name: symbol.language_server_name,
9788 source_worktree_id: symbol.source_worktree_id,
9789 source_language_server_id: symbol.source_language_server_id,
9790 path: symbol.path,
9791 name: symbol.name,
9792 kind: symbol.kind,
9793 range: symbol.range,
9794 signature: symbol.signature,
9795 label: CodeLabel {
9796 text: Default::default(),
9797 runs: Default::default(),
9798 filter_range: Default::default(),
9799 },
9800 },
9801 cx,
9802 )
9803 })?
9804 .await?;
9805
9806 this.update(&mut cx, |this, cx| {
9807 let is_private = buffer
9808 .read(cx)
9809 .file()
9810 .map(|f| f.is_private())
9811 .unwrap_or_default();
9812 if is_private {
9813 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9814 } else {
9815 this.buffer_store
9816 .update(cx, |buffer_store, cx| {
9817 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9818 })
9819 .detach_and_log_err(cx);
9820 let buffer_id = buffer.read(cx).remote_id().to_proto();
9821 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9822 }
9823 })?
9824 }
9825
9826 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
9827 let mut hasher = Sha256::new();
9828 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
9829 hasher.update(project_path.path.to_string_lossy().as_bytes());
9830 hasher.update(self.nonce.to_be_bytes());
9831 hasher.finalize().as_slice().try_into().unwrap()
9832 }
9833
9834 pub async fn handle_get_project_symbols(
9835 this: Entity<Self>,
9836 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9837 mut cx: AsyncApp,
9838 ) -> Result<proto::GetProjectSymbolsResponse> {
9839 let symbols = this
9840 .update(&mut cx, |this, cx| {
9841 this.symbols(&envelope.payload.query, cx)
9842 })?
9843 .await?;
9844
9845 Ok(proto::GetProjectSymbolsResponse {
9846 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9847 })
9848 }
9849
9850 pub async fn handle_restart_language_servers(
9851 this: Entity<Self>,
9852 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9853 mut cx: AsyncApp,
9854 ) -> Result<proto::Ack> {
9855 this.update(&mut cx, |lsp_store, cx| {
9856 let buffers =
9857 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9858 lsp_store.restart_language_servers_for_buffers(
9859 buffers,
9860 envelope
9861 .payload
9862 .only_servers
9863 .into_iter()
9864 .filter_map(|selector| {
9865 Some(match selector.selector? {
9866 proto::language_server_selector::Selector::ServerId(server_id) => {
9867 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9868 }
9869 proto::language_server_selector::Selector::Name(name) => {
9870 LanguageServerSelector::Name(LanguageServerName(
9871 SharedString::from(name),
9872 ))
9873 }
9874 })
9875 })
9876 .collect(),
9877 cx,
9878 );
9879 })?;
9880
9881 Ok(proto::Ack {})
9882 }
9883
9884 pub async fn handle_stop_language_servers(
9885 lsp_store: Entity<Self>,
9886 envelope: TypedEnvelope<proto::StopLanguageServers>,
9887 mut cx: AsyncApp,
9888 ) -> Result<proto::Ack> {
9889 lsp_store.update(&mut cx, |lsp_store, cx| {
9890 if envelope.payload.all
9891 && envelope.payload.also_servers.is_empty()
9892 && envelope.payload.buffer_ids.is_empty()
9893 {
9894 lsp_store.stop_all_language_servers(cx);
9895 } else {
9896 let buffers =
9897 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9898 lsp_store
9899 .stop_language_servers_for_buffers(
9900 buffers,
9901 envelope
9902 .payload
9903 .also_servers
9904 .into_iter()
9905 .filter_map(|selector| {
9906 Some(match selector.selector? {
9907 proto::language_server_selector::Selector::ServerId(
9908 server_id,
9909 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9910 server_id,
9911 )),
9912 proto::language_server_selector::Selector::Name(name) => {
9913 LanguageServerSelector::Name(LanguageServerName(
9914 SharedString::from(name),
9915 ))
9916 }
9917 })
9918 })
9919 .collect(),
9920 cx,
9921 )
9922 .detach_and_log_err(cx);
9923 }
9924 })?;
9925
9926 Ok(proto::Ack {})
9927 }
9928
9929 pub async fn handle_cancel_language_server_work(
9930 this: Entity<Self>,
9931 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9932 mut cx: AsyncApp,
9933 ) -> Result<proto::Ack> {
9934 this.update(&mut cx, |this, cx| {
9935 if let Some(work) = envelope.payload.work {
9936 match work {
9937 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9938 let buffers =
9939 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9940 this.cancel_language_server_work_for_buffers(buffers, cx);
9941 }
9942 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9943 let server_id = LanguageServerId::from_proto(work.language_server_id);
9944 this.cancel_language_server_work(server_id, work.token, cx);
9945 }
9946 }
9947 }
9948 })?;
9949
9950 Ok(proto::Ack {})
9951 }
9952
9953 fn buffer_ids_to_buffers(
9954 &mut self,
9955 buffer_ids: impl Iterator<Item = u64>,
9956 cx: &mut Context<Self>,
9957 ) -> Vec<Entity<Buffer>> {
9958 buffer_ids
9959 .into_iter()
9960 .flat_map(|buffer_id| {
9961 self.buffer_store
9962 .read(cx)
9963 .get(BufferId::new(buffer_id).log_err()?)
9964 })
9965 .collect::<Vec<_>>()
9966 }
9967
9968 async fn handle_apply_additional_edits_for_completion(
9969 this: Entity<Self>,
9970 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
9971 mut cx: AsyncApp,
9972 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
9973 let (buffer, completion) = this.update(&mut cx, |this, cx| {
9974 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9975 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9976 let completion = Self::deserialize_completion(
9977 envelope.payload.completion.context("invalid completion")?,
9978 )?;
9979 anyhow::Ok((buffer, completion))
9980 })??;
9981
9982 let apply_additional_edits = this.update(&mut cx, |this, cx| {
9983 this.apply_additional_edits_for_completion(
9984 buffer,
9985 Rc::new(RefCell::new(Box::new([Completion {
9986 replace_range: completion.replace_range,
9987 new_text: completion.new_text,
9988 source: completion.source,
9989 documentation: None,
9990 label: CodeLabel {
9991 text: Default::default(),
9992 runs: Default::default(),
9993 filter_range: Default::default(),
9994 },
9995 insert_text_mode: None,
9996 icon_path: None,
9997 confirm: None,
9998 }]))),
9999 0,
10000 false,
10001 cx,
10002 )
10003 })?;
10004
10005 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10006 transaction: apply_additional_edits
10007 .await?
10008 .as_ref()
10009 .map(language::proto::serialize_transaction),
10010 })
10011 }
10012
10013 pub fn last_formatting_failure(&self) -> Option<&str> {
10014 self.last_formatting_failure.as_deref()
10015 }
10016
10017 pub fn reset_last_formatting_failure(&mut self) {
10018 self.last_formatting_failure = None;
10019 }
10020
10021 pub fn environment_for_buffer(
10022 &self,
10023 buffer: &Entity<Buffer>,
10024 cx: &mut Context<Self>,
10025 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10026 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10027 environment.update(cx, |env, cx| {
10028 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10029 })
10030 } else {
10031 Task::ready(None).shared()
10032 }
10033 }
10034
10035 pub fn format(
10036 &mut self,
10037 buffers: HashSet<Entity<Buffer>>,
10038 target: LspFormatTarget,
10039 push_to_history: bool,
10040 trigger: FormatTrigger,
10041 cx: &mut Context<Self>,
10042 ) -> Task<anyhow::Result<ProjectTransaction>> {
10043 let logger = zlog::scoped!("format");
10044 if self.as_local().is_some() {
10045 zlog::trace!(logger => "Formatting locally");
10046 let logger = zlog::scoped!(logger => "local");
10047 let buffers = buffers
10048 .into_iter()
10049 .map(|buffer_handle| {
10050 let buffer = buffer_handle.read(cx);
10051 let buffer_abs_path = File::from_dyn(buffer.file())
10052 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10053
10054 (buffer_handle, buffer_abs_path, buffer.remote_id())
10055 })
10056 .collect::<Vec<_>>();
10057
10058 cx.spawn(async move |lsp_store, cx| {
10059 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10060
10061 for (handle, abs_path, id) in buffers {
10062 let env = lsp_store
10063 .update(cx, |lsp_store, cx| {
10064 lsp_store.environment_for_buffer(&handle, cx)
10065 })?
10066 .await;
10067
10068 let ranges = match &target {
10069 LspFormatTarget::Buffers => None,
10070 LspFormatTarget::Ranges(ranges) => {
10071 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10072 }
10073 };
10074
10075 formattable_buffers.push(FormattableBuffer {
10076 handle,
10077 abs_path,
10078 env,
10079 ranges,
10080 });
10081 }
10082 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10083
10084 let format_timer = zlog::time!(logger => "Formatting buffers");
10085 let result = LocalLspStore::format_locally(
10086 lsp_store.clone(),
10087 formattable_buffers,
10088 push_to_history,
10089 trigger,
10090 logger,
10091 cx,
10092 )
10093 .await;
10094 format_timer.end();
10095
10096 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10097
10098 lsp_store.update(cx, |lsp_store, _| {
10099 lsp_store.update_last_formatting_failure(&result);
10100 })?;
10101
10102 result
10103 })
10104 } else if let Some((client, project_id)) = self.upstream_client() {
10105 zlog::trace!(logger => "Formatting remotely");
10106 let logger = zlog::scoped!(logger => "remote");
10107 // Don't support formatting ranges via remote
10108 match target {
10109 LspFormatTarget::Buffers => {}
10110 LspFormatTarget::Ranges(_) => {
10111 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10112 return Task::ready(Ok(ProjectTransaction::default()));
10113 }
10114 }
10115
10116 let buffer_store = self.buffer_store();
10117 cx.spawn(async move |lsp_store, cx| {
10118 zlog::trace!(logger => "Sending remote format request");
10119 let request_timer = zlog::time!(logger => "remote format request");
10120 let result = client
10121 .request(proto::FormatBuffers {
10122 project_id,
10123 trigger: trigger as i32,
10124 buffer_ids: buffers
10125 .iter()
10126 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10127 .collect::<Result<_>>()?,
10128 })
10129 .await
10130 .and_then(|result| result.transaction.context("missing transaction"));
10131 request_timer.end();
10132
10133 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10134
10135 lsp_store.update(cx, |lsp_store, _| {
10136 lsp_store.update_last_formatting_failure(&result);
10137 })?;
10138
10139 let transaction_response = result?;
10140 let _timer = zlog::time!(logger => "deserializing project transaction");
10141 buffer_store
10142 .update(cx, |buffer_store, cx| {
10143 buffer_store.deserialize_project_transaction(
10144 transaction_response,
10145 push_to_history,
10146 cx,
10147 )
10148 })?
10149 .await
10150 })
10151 } else {
10152 zlog::trace!(logger => "Not formatting");
10153 Task::ready(Ok(ProjectTransaction::default()))
10154 }
10155 }
10156
10157 async fn handle_format_buffers(
10158 this: Entity<Self>,
10159 envelope: TypedEnvelope<proto::FormatBuffers>,
10160 mut cx: AsyncApp,
10161 ) -> Result<proto::FormatBuffersResponse> {
10162 let sender_id = envelope.original_sender_id().unwrap_or_default();
10163 let format = this.update(&mut cx, |this, cx| {
10164 let mut buffers = HashSet::default();
10165 for buffer_id in &envelope.payload.buffer_ids {
10166 let buffer_id = BufferId::new(*buffer_id)?;
10167 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10168 }
10169 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10170 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10171 })??;
10172
10173 let project_transaction = format.await?;
10174 let project_transaction = this.update(&mut cx, |this, cx| {
10175 this.buffer_store.update(cx, |buffer_store, cx| {
10176 buffer_store.serialize_project_transaction_for_peer(
10177 project_transaction,
10178 sender_id,
10179 cx,
10180 )
10181 })
10182 })?;
10183 Ok(proto::FormatBuffersResponse {
10184 transaction: Some(project_transaction),
10185 })
10186 }
10187
10188 async fn handle_apply_code_action_kind(
10189 this: Entity<Self>,
10190 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10191 mut cx: AsyncApp,
10192 ) -> Result<proto::ApplyCodeActionKindResponse> {
10193 let sender_id = envelope.original_sender_id().unwrap_or_default();
10194 let format = this.update(&mut cx, |this, cx| {
10195 let mut buffers = HashSet::default();
10196 for buffer_id in &envelope.payload.buffer_ids {
10197 let buffer_id = BufferId::new(*buffer_id)?;
10198 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10199 }
10200 let kind = match envelope.payload.kind.as_str() {
10201 "" => CodeActionKind::EMPTY,
10202 "quickfix" => CodeActionKind::QUICKFIX,
10203 "refactor" => CodeActionKind::REFACTOR,
10204 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10205 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10206 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10207 "source" => CodeActionKind::SOURCE,
10208 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10209 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10210 _ => anyhow::bail!(
10211 "Invalid code action kind {}",
10212 envelope.payload.kind.as_str()
10213 ),
10214 };
10215 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10216 })??;
10217
10218 let project_transaction = format.await?;
10219 let project_transaction = this.update(&mut cx, |this, cx| {
10220 this.buffer_store.update(cx, |buffer_store, cx| {
10221 buffer_store.serialize_project_transaction_for_peer(
10222 project_transaction,
10223 sender_id,
10224 cx,
10225 )
10226 })
10227 })?;
10228 Ok(proto::ApplyCodeActionKindResponse {
10229 transaction: Some(project_transaction),
10230 })
10231 }
10232
10233 async fn shutdown_language_server(
10234 server_state: Option<LanguageServerState>,
10235 name: LanguageServerName,
10236 cx: &mut AsyncApp,
10237 ) {
10238 let server = match server_state {
10239 Some(LanguageServerState::Starting { startup, .. }) => {
10240 let mut timer = cx
10241 .background_executor()
10242 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10243 .fuse();
10244
10245 select! {
10246 server = startup.fuse() => server,
10247 () = timer => {
10248 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10249 None
10250 },
10251 }
10252 }
10253
10254 Some(LanguageServerState::Running { server, .. }) => Some(server),
10255
10256 None => None,
10257 };
10258
10259 if let Some(server) = server
10260 && let Some(shutdown) = server.shutdown()
10261 {
10262 shutdown.await;
10263 }
10264 }
10265
10266 // Returns a list of all of the worktrees which no longer have a language server and the root path
10267 // for the stopped server
10268 fn stop_local_language_server(
10269 &mut self,
10270 server_id: LanguageServerId,
10271 cx: &mut Context<Self>,
10272 ) -> Task<()> {
10273 let local = match &mut self.mode {
10274 LspStoreMode::Local(local) => local,
10275 _ => {
10276 return Task::ready(());
10277 }
10278 };
10279
10280 // Remove this server ID from all entries in the given worktree.
10281 local
10282 .language_server_ids
10283 .retain(|_, state| state.id != server_id);
10284 self.buffer_store.update(cx, |buffer_store, cx| {
10285 for buffer in buffer_store.buffers() {
10286 buffer.update(cx, |buffer, cx| {
10287 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10288 buffer.set_completion_triggers(server_id, Default::default(), cx);
10289 });
10290 }
10291 });
10292
10293 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10294 summaries.retain(|path, summaries_by_server_id| {
10295 if summaries_by_server_id.remove(&server_id).is_some() {
10296 if let Some((client, project_id)) = self.downstream_client.clone() {
10297 client
10298 .send(proto::UpdateDiagnosticSummary {
10299 project_id,
10300 worktree_id: worktree_id.to_proto(),
10301 summary: Some(proto::DiagnosticSummary {
10302 path: path.as_ref().to_proto(),
10303 language_server_id: server_id.0 as u64,
10304 error_count: 0,
10305 warning_count: 0,
10306 }),
10307 more_summaries: Vec::new(),
10308 })
10309 .log_err();
10310 }
10311 !summaries_by_server_id.is_empty()
10312 } else {
10313 true
10314 }
10315 });
10316 }
10317
10318 let local = self.as_local_mut().unwrap();
10319 for diagnostics in local.diagnostics.values_mut() {
10320 diagnostics.retain(|_, diagnostics_by_server_id| {
10321 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10322 diagnostics_by_server_id.remove(ix);
10323 !diagnostics_by_server_id.is_empty()
10324 } else {
10325 true
10326 }
10327 });
10328 }
10329 local.language_server_watched_paths.remove(&server_id);
10330
10331 let server_state = local.language_servers.remove(&server_id);
10332 self.cleanup_lsp_data(server_id);
10333 let name = self
10334 .language_server_statuses
10335 .remove(&server_id)
10336 .map(|status| status.name)
10337 .or_else(|| {
10338 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10339 Some(adapter.name())
10340 } else {
10341 None
10342 }
10343 });
10344
10345 if let Some(name) = name {
10346 log::info!("stopping language server {name}");
10347 self.languages
10348 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10349 cx.notify();
10350
10351 return cx.spawn(async move |lsp_store, cx| {
10352 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10353 lsp_store
10354 .update(cx, |lsp_store, cx| {
10355 lsp_store
10356 .languages
10357 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10358 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10359 cx.notify();
10360 })
10361 .ok();
10362 });
10363 }
10364
10365 if server_state.is_some() {
10366 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10367 }
10368 Task::ready(())
10369 }
10370
10371 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10372 if let Some((client, project_id)) = self.upstream_client() {
10373 let request = client.request(proto::StopLanguageServers {
10374 project_id,
10375 buffer_ids: Vec::new(),
10376 also_servers: Vec::new(),
10377 all: true,
10378 });
10379 cx.background_spawn(request).detach_and_log_err(cx);
10380 } else {
10381 let Some(local) = self.as_local_mut() else {
10382 return;
10383 };
10384 let language_servers_to_stop = local
10385 .language_server_ids
10386 .values()
10387 .map(|state| state.id)
10388 .collect();
10389 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10390 let tasks = language_servers_to_stop
10391 .into_iter()
10392 .map(|server| self.stop_local_language_server(server, cx))
10393 .collect::<Vec<_>>();
10394 cx.background_spawn(async move {
10395 futures::future::join_all(tasks).await;
10396 })
10397 .detach();
10398 }
10399 }
10400
10401 pub fn restart_language_servers_for_buffers(
10402 &mut self,
10403 buffers: Vec<Entity<Buffer>>,
10404 only_restart_servers: HashSet<LanguageServerSelector>,
10405 cx: &mut Context<Self>,
10406 ) {
10407 if let Some((client, project_id)) = self.upstream_client() {
10408 let request = client.request(proto::RestartLanguageServers {
10409 project_id,
10410 buffer_ids: buffers
10411 .into_iter()
10412 .map(|b| b.read(cx).remote_id().to_proto())
10413 .collect(),
10414 only_servers: only_restart_servers
10415 .into_iter()
10416 .map(|selector| {
10417 let selector = match selector {
10418 LanguageServerSelector::Id(language_server_id) => {
10419 proto::language_server_selector::Selector::ServerId(
10420 language_server_id.to_proto(),
10421 )
10422 }
10423 LanguageServerSelector::Name(language_server_name) => {
10424 proto::language_server_selector::Selector::Name(
10425 language_server_name.to_string(),
10426 )
10427 }
10428 };
10429 proto::LanguageServerSelector {
10430 selector: Some(selector),
10431 }
10432 })
10433 .collect(),
10434 all: false,
10435 });
10436 cx.background_spawn(request).detach_and_log_err(cx);
10437 } else {
10438 let stop_task = if only_restart_servers.is_empty() {
10439 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10440 } else {
10441 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10442 };
10443 cx.spawn(async move |lsp_store, cx| {
10444 stop_task.await;
10445 lsp_store
10446 .update(cx, |lsp_store, cx| {
10447 for buffer in buffers {
10448 lsp_store.register_buffer_with_language_servers(
10449 &buffer,
10450 only_restart_servers.clone(),
10451 true,
10452 cx,
10453 );
10454 }
10455 })
10456 .ok()
10457 })
10458 .detach();
10459 }
10460 }
10461
10462 pub fn stop_language_servers_for_buffers(
10463 &mut self,
10464 buffers: Vec<Entity<Buffer>>,
10465 also_stop_servers: HashSet<LanguageServerSelector>,
10466 cx: &mut Context<Self>,
10467 ) -> Task<Result<()>> {
10468 if let Some((client, project_id)) = self.upstream_client() {
10469 let request = client.request(proto::StopLanguageServers {
10470 project_id,
10471 buffer_ids: buffers
10472 .into_iter()
10473 .map(|b| b.read(cx).remote_id().to_proto())
10474 .collect(),
10475 also_servers: also_stop_servers
10476 .into_iter()
10477 .map(|selector| {
10478 let selector = match selector {
10479 LanguageServerSelector::Id(language_server_id) => {
10480 proto::language_server_selector::Selector::ServerId(
10481 language_server_id.to_proto(),
10482 )
10483 }
10484 LanguageServerSelector::Name(language_server_name) => {
10485 proto::language_server_selector::Selector::Name(
10486 language_server_name.to_string(),
10487 )
10488 }
10489 };
10490 proto::LanguageServerSelector {
10491 selector: Some(selector),
10492 }
10493 })
10494 .collect(),
10495 all: false,
10496 });
10497 cx.background_spawn(async move {
10498 let _ = request.await?;
10499 Ok(())
10500 })
10501 } else {
10502 let task =
10503 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10504 cx.background_spawn(async move {
10505 task.await;
10506 Ok(())
10507 })
10508 }
10509 }
10510
10511 fn stop_local_language_servers_for_buffers(
10512 &mut self,
10513 buffers: &[Entity<Buffer>],
10514 also_stop_servers: HashSet<LanguageServerSelector>,
10515 cx: &mut Context<Self>,
10516 ) -> Task<()> {
10517 let Some(local) = self.as_local_mut() else {
10518 return Task::ready(());
10519 };
10520 let mut language_server_names_to_stop = BTreeSet::default();
10521 let mut language_servers_to_stop = also_stop_servers
10522 .into_iter()
10523 .flat_map(|selector| match selector {
10524 LanguageServerSelector::Id(id) => Some(id),
10525 LanguageServerSelector::Name(name) => {
10526 language_server_names_to_stop.insert(name);
10527 None
10528 }
10529 })
10530 .collect::<BTreeSet<_>>();
10531
10532 let mut covered_worktrees = HashSet::default();
10533 for buffer in buffers {
10534 buffer.update(cx, |buffer, cx| {
10535 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10536 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10537 && covered_worktrees.insert(worktree_id)
10538 {
10539 language_server_names_to_stop.retain(|name| {
10540 let old_ids_count = language_servers_to_stop.len();
10541 let all_language_servers_with_this_name = local
10542 .language_server_ids
10543 .iter()
10544 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10545 language_servers_to_stop.extend(all_language_servers_with_this_name);
10546 old_ids_count == language_servers_to_stop.len()
10547 });
10548 }
10549 });
10550 }
10551 for name in language_server_names_to_stop {
10552 language_servers_to_stop.extend(
10553 local
10554 .language_server_ids
10555 .iter()
10556 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10557 );
10558 }
10559
10560 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10561 let tasks = language_servers_to_stop
10562 .into_iter()
10563 .map(|server| self.stop_local_language_server(server, cx))
10564 .collect::<Vec<_>>();
10565
10566 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10567 }
10568
10569 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10570 let (worktree, relative_path) =
10571 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10572
10573 let project_path = ProjectPath {
10574 worktree_id: worktree.read(cx).id(),
10575 path: relative_path.into(),
10576 };
10577
10578 Some(
10579 self.buffer_store()
10580 .read(cx)
10581 .get_by_path(&project_path)?
10582 .read(cx),
10583 )
10584 }
10585
10586 #[cfg(any(test, feature = "test-support"))]
10587 pub fn update_diagnostics(
10588 &mut self,
10589 server_id: LanguageServerId,
10590 diagnostics: lsp::PublishDiagnosticsParams,
10591 result_id: Option<String>,
10592 source_kind: DiagnosticSourceKind,
10593 disk_based_sources: &[String],
10594 cx: &mut Context<Self>,
10595 ) -> Result<()> {
10596 self.merge_lsp_diagnostics(
10597 source_kind,
10598 vec![DocumentDiagnosticsUpdate {
10599 diagnostics,
10600 result_id,
10601 server_id,
10602 disk_based_sources: Cow::Borrowed(disk_based_sources),
10603 }],
10604 |_, _, _| false,
10605 cx,
10606 )
10607 }
10608
10609 pub fn merge_lsp_diagnostics(
10610 &mut self,
10611 source_kind: DiagnosticSourceKind,
10612 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10613 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10614 cx: &mut Context<Self>,
10615 ) -> Result<()> {
10616 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10617 let updates = lsp_diagnostics
10618 .into_iter()
10619 .filter_map(|update| {
10620 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10621 Some(DocumentDiagnosticsUpdate {
10622 diagnostics: self.lsp_to_document_diagnostics(
10623 abs_path,
10624 source_kind,
10625 update.server_id,
10626 update.diagnostics,
10627 &update.disk_based_sources,
10628 ),
10629 result_id: update.result_id,
10630 server_id: update.server_id,
10631 disk_based_sources: update.disk_based_sources,
10632 })
10633 })
10634 .collect();
10635 self.merge_diagnostic_entries(updates, merge, cx)?;
10636 Ok(())
10637 }
10638
10639 fn lsp_to_document_diagnostics(
10640 &mut self,
10641 document_abs_path: PathBuf,
10642 source_kind: DiagnosticSourceKind,
10643 server_id: LanguageServerId,
10644 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10645 disk_based_sources: &[String],
10646 ) -> DocumentDiagnostics {
10647 let mut diagnostics = Vec::default();
10648 let mut primary_diagnostic_group_ids = HashMap::default();
10649 let mut sources_by_group_id = HashMap::default();
10650 let mut supporting_diagnostics = HashMap::default();
10651
10652 let adapter = self.language_server_adapter_for_id(server_id);
10653
10654 // Ensure that primary diagnostics are always the most severe
10655 lsp_diagnostics
10656 .diagnostics
10657 .sort_by_key(|item| item.severity);
10658
10659 for diagnostic in &lsp_diagnostics.diagnostics {
10660 let source = diagnostic.source.as_ref();
10661 let range = range_from_lsp(diagnostic.range);
10662 let is_supporting = diagnostic
10663 .related_information
10664 .as_ref()
10665 .is_some_and(|infos| {
10666 infos.iter().any(|info| {
10667 primary_diagnostic_group_ids.contains_key(&(
10668 source,
10669 diagnostic.code.clone(),
10670 range_from_lsp(info.location.range),
10671 ))
10672 })
10673 });
10674
10675 let is_unnecessary = diagnostic
10676 .tags
10677 .as_ref()
10678 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10679
10680 let underline = self
10681 .language_server_adapter_for_id(server_id)
10682 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10683
10684 if is_supporting {
10685 supporting_diagnostics.insert(
10686 (source, diagnostic.code.clone(), range),
10687 (diagnostic.severity, is_unnecessary),
10688 );
10689 } else {
10690 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10691 let is_disk_based =
10692 source.is_some_and(|source| disk_based_sources.contains(source));
10693
10694 sources_by_group_id.insert(group_id, source);
10695 primary_diagnostic_group_ids
10696 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10697
10698 diagnostics.push(DiagnosticEntry {
10699 range,
10700 diagnostic: Diagnostic {
10701 source: diagnostic.source.clone(),
10702 source_kind,
10703 code: diagnostic.code.clone(),
10704 code_description: diagnostic
10705 .code_description
10706 .as_ref()
10707 .and_then(|d| d.href.clone()),
10708 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10709 markdown: adapter.as_ref().and_then(|adapter| {
10710 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10711 }),
10712 message: diagnostic.message.trim().to_string(),
10713 group_id,
10714 is_primary: true,
10715 is_disk_based,
10716 is_unnecessary,
10717 underline,
10718 data: diagnostic.data.clone(),
10719 },
10720 });
10721 if let Some(infos) = &diagnostic.related_information {
10722 for info in infos {
10723 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10724 let range = range_from_lsp(info.location.range);
10725 diagnostics.push(DiagnosticEntry {
10726 range,
10727 diagnostic: Diagnostic {
10728 source: diagnostic.source.clone(),
10729 source_kind,
10730 code: diagnostic.code.clone(),
10731 code_description: diagnostic
10732 .code_description
10733 .as_ref()
10734 .and_then(|d| d.href.clone()),
10735 severity: DiagnosticSeverity::INFORMATION,
10736 markdown: adapter.as_ref().and_then(|adapter| {
10737 adapter.diagnostic_message_to_markdown(&info.message)
10738 }),
10739 message: info.message.trim().to_string(),
10740 group_id,
10741 is_primary: false,
10742 is_disk_based,
10743 is_unnecessary: false,
10744 underline,
10745 data: diagnostic.data.clone(),
10746 },
10747 });
10748 }
10749 }
10750 }
10751 }
10752 }
10753
10754 for entry in &mut diagnostics {
10755 let diagnostic = &mut entry.diagnostic;
10756 if !diagnostic.is_primary {
10757 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10758 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10759 source,
10760 diagnostic.code.clone(),
10761 entry.range.clone(),
10762 )) {
10763 if let Some(severity) = severity {
10764 diagnostic.severity = severity;
10765 }
10766 diagnostic.is_unnecessary = is_unnecessary;
10767 }
10768 }
10769 }
10770
10771 DocumentDiagnostics {
10772 diagnostics,
10773 document_abs_path,
10774 version: lsp_diagnostics.version,
10775 }
10776 }
10777
10778 fn insert_newly_running_language_server(
10779 &mut self,
10780 adapter: Arc<CachedLspAdapter>,
10781 language_server: Arc<LanguageServer>,
10782 server_id: LanguageServerId,
10783 key: LanguageServerSeed,
10784 workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
10785 cx: &mut Context<Self>,
10786 ) {
10787 let Some(local) = self.as_local_mut() else {
10788 return;
10789 };
10790 // If the language server for this key doesn't match the server id, don't store the
10791 // server. Which will cause it to be dropped, killing the process
10792 if local
10793 .language_server_ids
10794 .get(&key)
10795 .map(|state| state.id != server_id)
10796 .unwrap_or(false)
10797 {
10798 return;
10799 }
10800
10801 // Update language_servers collection with Running variant of LanguageServerState
10802 // indicating that the server is up and running and ready
10803 let workspace_folders = workspace_folders.lock().clone();
10804 language_server.set_workspace_folders(workspace_folders);
10805
10806 local.language_servers.insert(
10807 server_id,
10808 LanguageServerState::Running {
10809 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10810 language_server.clone(),
10811 cx,
10812 ),
10813 adapter: adapter.clone(),
10814 server: language_server.clone(),
10815 simulate_disk_based_diagnostics_completion: None,
10816 },
10817 );
10818 local
10819 .languages
10820 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10821 if let Some(file_ops_caps) = language_server
10822 .capabilities()
10823 .workspace
10824 .as_ref()
10825 .and_then(|ws| ws.file_operations.as_ref())
10826 {
10827 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10828 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10829 if did_rename_caps.or(will_rename_caps).is_some() {
10830 let watcher = RenamePathsWatchedForServer::default()
10831 .with_did_rename_patterns(did_rename_caps)
10832 .with_will_rename_patterns(will_rename_caps);
10833 local
10834 .language_server_paths_watched_for_rename
10835 .insert(server_id, watcher);
10836 }
10837 }
10838
10839 self.language_server_statuses.insert(
10840 server_id,
10841 LanguageServerStatus {
10842 name: language_server.name(),
10843 pending_work: Default::default(),
10844 has_pending_diagnostic_updates: false,
10845 progress_tokens: Default::default(),
10846 },
10847 );
10848
10849 cx.emit(LspStoreEvent::LanguageServerAdded(
10850 server_id,
10851 language_server.name(),
10852 Some(key.worktree_id),
10853 ));
10854 cx.emit(LspStoreEvent::RefreshInlayHints);
10855
10856 let server_capabilities = language_server.capabilities();
10857 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10858 downstream_client
10859 .send(proto::StartLanguageServer {
10860 project_id: *project_id,
10861 server: Some(proto::LanguageServer {
10862 id: server_id.to_proto(),
10863 name: language_server.name().to_string(),
10864 worktree_id: Some(key.worktree_id.to_proto()),
10865 }),
10866 capabilities: serde_json::to_string(&server_capabilities)
10867 .expect("serializing server LSP capabilities"),
10868 })
10869 .log_err();
10870 }
10871 self.lsp_server_capabilities
10872 .insert(server_id, server_capabilities);
10873
10874 // Tell the language server about every open buffer in the worktree that matches the language.
10875 // Also check for buffers in worktrees that reused this server
10876 let mut worktrees_using_server = vec![key.worktree_id];
10877 if let Some(local) = self.as_local() {
10878 // Find all worktrees that have this server in their language server tree
10879 for (worktree_id, servers) in &local.lsp_tree.instances {
10880 if *worktree_id != key.worktree_id {
10881 for server_map in servers.roots.values() {
10882 if server_map.contains_key(&key.name) {
10883 worktrees_using_server.push(*worktree_id);
10884 }
10885 }
10886 }
10887 }
10888 }
10889
10890 let mut buffer_paths_registered = Vec::new();
10891 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10892 for buffer_handle in buffer_store.buffers() {
10893 let buffer = buffer_handle.read(cx);
10894 let file = match File::from_dyn(buffer.file()) {
10895 Some(file) => file,
10896 None => continue,
10897 };
10898 let language = match buffer.language() {
10899 Some(language) => language,
10900 None => continue,
10901 };
10902
10903 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10904 || !self
10905 .languages
10906 .lsp_adapters(&language.name())
10907 .iter()
10908 .any(|a| a.name == key.name)
10909 {
10910 continue;
10911 }
10912 // didOpen
10913 let file = match file.as_local() {
10914 Some(file) => file,
10915 None => continue,
10916 };
10917
10918 let local = self.as_local_mut().unwrap();
10919
10920 let buffer_id = buffer.remote_id();
10921 if local.registered_buffers.contains_key(&buffer_id) {
10922 let versions = local
10923 .buffer_snapshots
10924 .entry(buffer_id)
10925 .or_default()
10926 .entry(server_id)
10927 .and_modify(|_| {
10928 assert!(
10929 false,
10930 "There should not be an existing snapshot for a newly inserted buffer"
10931 )
10932 })
10933 .or_insert_with(|| {
10934 vec![LspBufferSnapshot {
10935 version: 0,
10936 snapshot: buffer.text_snapshot(),
10937 }]
10938 });
10939
10940 let snapshot = versions.last().unwrap();
10941 let version = snapshot.version;
10942 let initial_snapshot = &snapshot.snapshot;
10943 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
10944 language_server.register_buffer(
10945 uri,
10946 adapter.language_id(&language.name()),
10947 version,
10948 initial_snapshot.text(),
10949 );
10950 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
10951 local
10952 .buffers_opened_in_servers
10953 .entry(buffer_id)
10954 .or_default()
10955 .insert(server_id);
10956 }
10957 buffer_handle.update(cx, |buffer, cx| {
10958 buffer.set_completion_triggers(
10959 server_id,
10960 language_server
10961 .capabilities()
10962 .completion_provider
10963 .as_ref()
10964 .and_then(|provider| {
10965 provider
10966 .trigger_characters
10967 .as_ref()
10968 .map(|characters| characters.iter().cloned().collect())
10969 })
10970 .unwrap_or_default(),
10971 cx,
10972 )
10973 });
10974 }
10975 });
10976
10977 for (buffer_id, abs_path) in buffer_paths_registered {
10978 cx.emit(LspStoreEvent::LanguageServerUpdate {
10979 language_server_id: server_id,
10980 name: Some(adapter.name()),
10981 message: proto::update_language_server::Variant::RegisteredForBuffer(
10982 proto::RegisteredForBuffer {
10983 buffer_abs_path: abs_path.to_string_lossy().to_string(),
10984 buffer_id: buffer_id.to_proto(),
10985 },
10986 ),
10987 });
10988 }
10989
10990 cx.notify();
10991 }
10992
10993 pub fn language_servers_running_disk_based_diagnostics(
10994 &self,
10995 ) -> impl Iterator<Item = LanguageServerId> + '_ {
10996 self.language_server_statuses
10997 .iter()
10998 .filter_map(|(id, status)| {
10999 if status.has_pending_diagnostic_updates {
11000 Some(*id)
11001 } else {
11002 None
11003 }
11004 })
11005 }
11006
11007 pub(crate) fn cancel_language_server_work_for_buffers(
11008 &mut self,
11009 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11010 cx: &mut Context<Self>,
11011 ) {
11012 if let Some((client, project_id)) = self.upstream_client() {
11013 let request = client.request(proto::CancelLanguageServerWork {
11014 project_id,
11015 work: Some(proto::cancel_language_server_work::Work::Buffers(
11016 proto::cancel_language_server_work::Buffers {
11017 buffer_ids: buffers
11018 .into_iter()
11019 .map(|b| b.read(cx).remote_id().to_proto())
11020 .collect(),
11021 },
11022 )),
11023 });
11024 cx.background_spawn(request).detach_and_log_err(cx);
11025 } else if let Some(local) = self.as_local() {
11026 let servers = buffers
11027 .into_iter()
11028 .flat_map(|buffer| {
11029 buffer.update(cx, |buffer, cx| {
11030 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11031 })
11032 })
11033 .collect::<HashSet<_>>();
11034 for server_id in servers {
11035 self.cancel_language_server_work(server_id, None, cx);
11036 }
11037 }
11038 }
11039
11040 pub(crate) fn cancel_language_server_work(
11041 &mut self,
11042 server_id: LanguageServerId,
11043 token_to_cancel: Option<String>,
11044 cx: &mut Context<Self>,
11045 ) {
11046 if let Some(local) = self.as_local() {
11047 let status = self.language_server_statuses.get(&server_id);
11048 let server = local.language_servers.get(&server_id);
11049 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11050 {
11051 for (token, progress) in &status.pending_work {
11052 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11053 && token != token_to_cancel
11054 {
11055 continue;
11056 }
11057 if progress.is_cancellable {
11058 server
11059 .notify::<lsp::notification::WorkDoneProgressCancel>(
11060 &WorkDoneProgressCancelParams {
11061 token: lsp::NumberOrString::String(token.clone()),
11062 },
11063 )
11064 .ok();
11065 }
11066 }
11067 }
11068 } else if let Some((client, project_id)) = self.upstream_client() {
11069 let request = client.request(proto::CancelLanguageServerWork {
11070 project_id,
11071 work: Some(
11072 proto::cancel_language_server_work::Work::LanguageServerWork(
11073 proto::cancel_language_server_work::LanguageServerWork {
11074 language_server_id: server_id.to_proto(),
11075 token: token_to_cancel,
11076 },
11077 ),
11078 ),
11079 });
11080 cx.background_spawn(request).detach_and_log_err(cx);
11081 }
11082 }
11083
11084 fn register_supplementary_language_server(
11085 &mut self,
11086 id: LanguageServerId,
11087 name: LanguageServerName,
11088 server: Arc<LanguageServer>,
11089 cx: &mut Context<Self>,
11090 ) {
11091 if let Some(local) = self.as_local_mut() {
11092 local
11093 .supplementary_language_servers
11094 .insert(id, (name.clone(), server));
11095 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11096 }
11097 }
11098
11099 fn unregister_supplementary_language_server(
11100 &mut self,
11101 id: LanguageServerId,
11102 cx: &mut Context<Self>,
11103 ) {
11104 if let Some(local) = self.as_local_mut() {
11105 local.supplementary_language_servers.remove(&id);
11106 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11107 }
11108 }
11109
11110 pub(crate) fn supplementary_language_servers(
11111 &self,
11112 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11113 self.as_local().into_iter().flat_map(|local| {
11114 local
11115 .supplementary_language_servers
11116 .iter()
11117 .map(|(id, (name, _))| (*id, name.clone()))
11118 })
11119 }
11120
11121 pub fn language_server_adapter_for_id(
11122 &self,
11123 id: LanguageServerId,
11124 ) -> Option<Arc<CachedLspAdapter>> {
11125 self.as_local()
11126 .and_then(|local| local.language_servers.get(&id))
11127 .and_then(|language_server_state| match language_server_state {
11128 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11129 _ => None,
11130 })
11131 }
11132
11133 pub(super) fn update_local_worktree_language_servers(
11134 &mut self,
11135 worktree_handle: &Entity<Worktree>,
11136 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
11137 cx: &mut Context<Self>,
11138 ) {
11139 if changes.is_empty() {
11140 return;
11141 }
11142
11143 let Some(local) = self.as_local() else { return };
11144
11145 local.prettier_store.update(cx, |prettier_store, cx| {
11146 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11147 });
11148
11149 let worktree_id = worktree_handle.read(cx).id();
11150 let mut language_server_ids = local
11151 .language_server_ids
11152 .iter()
11153 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11154 .collect::<Vec<_>>();
11155 language_server_ids.sort();
11156 language_server_ids.dedup();
11157
11158 let abs_path = worktree_handle.read(cx).abs_path();
11159 for server_id in &language_server_ids {
11160 if let Some(LanguageServerState::Running { server, .. }) =
11161 local.language_servers.get(server_id)
11162 && let Some(watched_paths) = local
11163 .language_server_watched_paths
11164 .get(server_id)
11165 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11166 {
11167 let params = lsp::DidChangeWatchedFilesParams {
11168 changes: changes
11169 .iter()
11170 .filter_map(|(path, _, change)| {
11171 if !watched_paths.is_match(path) {
11172 return None;
11173 }
11174 let typ = match change {
11175 PathChange::Loaded => return None,
11176 PathChange::Added => lsp::FileChangeType::CREATED,
11177 PathChange::Removed => lsp::FileChangeType::DELETED,
11178 PathChange::Updated => lsp::FileChangeType::CHANGED,
11179 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11180 };
11181 Some(lsp::FileEvent {
11182 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
11183 typ,
11184 })
11185 })
11186 .collect(),
11187 };
11188 if !params.changes.is_empty() {
11189 server
11190 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
11191 .ok();
11192 }
11193 }
11194 }
11195 for (path, _, _) in changes {
11196 if let Some(file_name) = path.file_name().and_then(|file_name| file_name.to_str())
11197 && local.watched_manifest_filenames.contains(file_name)
11198 {
11199 self.request_workspace_config_refresh();
11200 break;
11201 }
11202 }
11203 }
11204
11205 pub fn wait_for_remote_buffer(
11206 &mut self,
11207 id: BufferId,
11208 cx: &mut Context<Self>,
11209 ) -> Task<Result<Entity<Buffer>>> {
11210 self.buffer_store.update(cx, |buffer_store, cx| {
11211 buffer_store.wait_for_remote_buffer(id, cx)
11212 })
11213 }
11214
11215 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11216 proto::Symbol {
11217 language_server_name: symbol.language_server_name.0.to_string(),
11218 source_worktree_id: symbol.source_worktree_id.to_proto(),
11219 language_server_id: symbol.source_language_server_id.to_proto(),
11220 worktree_id: symbol.path.worktree_id.to_proto(),
11221 path: symbol.path.path.as_ref().to_proto(),
11222 name: symbol.name.clone(),
11223 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11224 start: Some(proto::PointUtf16 {
11225 row: symbol.range.start.0.row,
11226 column: symbol.range.start.0.column,
11227 }),
11228 end: Some(proto::PointUtf16 {
11229 row: symbol.range.end.0.row,
11230 column: symbol.range.end.0.column,
11231 }),
11232 signature: symbol.signature.to_vec(),
11233 }
11234 }
11235
11236 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11237 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11238 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11239 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11240 let path = ProjectPath {
11241 worktree_id,
11242 path: Arc::<Path>::from_proto(serialized_symbol.path),
11243 };
11244
11245 let start = serialized_symbol.start.context("invalid start")?;
11246 let end = serialized_symbol.end.context("invalid end")?;
11247 Ok(CoreSymbol {
11248 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11249 source_worktree_id,
11250 source_language_server_id: LanguageServerId::from_proto(
11251 serialized_symbol.language_server_id,
11252 ),
11253 path,
11254 name: serialized_symbol.name,
11255 range: Unclipped(PointUtf16::new(start.row, start.column))
11256 ..Unclipped(PointUtf16::new(end.row, end.column)),
11257 kind,
11258 signature: serialized_symbol
11259 .signature
11260 .try_into()
11261 .map_err(|_| anyhow!("invalid signature"))?,
11262 })
11263 }
11264
11265 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11266 let mut serialized_completion = proto::Completion {
11267 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11268 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11269 new_text: completion.new_text.clone(),
11270 ..proto::Completion::default()
11271 };
11272 match &completion.source {
11273 CompletionSource::Lsp {
11274 insert_range,
11275 server_id,
11276 lsp_completion,
11277 lsp_defaults,
11278 resolved,
11279 } => {
11280 let (old_insert_start, old_insert_end) = insert_range
11281 .as_ref()
11282 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11283 .unzip();
11284
11285 serialized_completion.old_insert_start = old_insert_start;
11286 serialized_completion.old_insert_end = old_insert_end;
11287 serialized_completion.source = proto::completion::Source::Lsp as i32;
11288 serialized_completion.server_id = server_id.0 as u64;
11289 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11290 serialized_completion.lsp_defaults = lsp_defaults
11291 .as_deref()
11292 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11293 serialized_completion.resolved = *resolved;
11294 }
11295 CompletionSource::BufferWord {
11296 word_range,
11297 resolved,
11298 } => {
11299 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11300 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11301 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11302 serialized_completion.resolved = *resolved;
11303 }
11304 CompletionSource::Custom => {
11305 serialized_completion.source = proto::completion::Source::Custom as i32;
11306 serialized_completion.resolved = true;
11307 }
11308 CompletionSource::Dap { sort_text } => {
11309 serialized_completion.source = proto::completion::Source::Dap as i32;
11310 serialized_completion.sort_text = Some(sort_text.clone());
11311 }
11312 }
11313
11314 serialized_completion
11315 }
11316
11317 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11318 let old_replace_start = completion
11319 .old_replace_start
11320 .and_then(deserialize_anchor)
11321 .context("invalid old start")?;
11322 let old_replace_end = completion
11323 .old_replace_end
11324 .and_then(deserialize_anchor)
11325 .context("invalid old end")?;
11326 let insert_range = {
11327 match completion.old_insert_start.zip(completion.old_insert_end) {
11328 Some((start, end)) => {
11329 let start = deserialize_anchor(start).context("invalid insert old start")?;
11330 let end = deserialize_anchor(end).context("invalid insert old end")?;
11331 Some(start..end)
11332 }
11333 None => None,
11334 }
11335 };
11336 Ok(CoreCompletion {
11337 replace_range: old_replace_start..old_replace_end,
11338 new_text: completion.new_text,
11339 source: match proto::completion::Source::from_i32(completion.source) {
11340 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11341 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11342 insert_range,
11343 server_id: LanguageServerId::from_proto(completion.server_id),
11344 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11345 lsp_defaults: completion
11346 .lsp_defaults
11347 .as_deref()
11348 .map(serde_json::from_slice)
11349 .transpose()?,
11350 resolved: completion.resolved,
11351 },
11352 Some(proto::completion::Source::BufferWord) => {
11353 let word_range = completion
11354 .buffer_word_start
11355 .and_then(deserialize_anchor)
11356 .context("invalid buffer word start")?
11357 ..completion
11358 .buffer_word_end
11359 .and_then(deserialize_anchor)
11360 .context("invalid buffer word end")?;
11361 CompletionSource::BufferWord {
11362 word_range,
11363 resolved: completion.resolved,
11364 }
11365 }
11366 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11367 sort_text: completion
11368 .sort_text
11369 .context("expected sort text to exist")?,
11370 },
11371 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11372 },
11373 })
11374 }
11375
11376 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11377 let (kind, lsp_action) = match &action.lsp_action {
11378 LspAction::Action(code_action) => (
11379 proto::code_action::Kind::Action as i32,
11380 serde_json::to_vec(code_action).unwrap(),
11381 ),
11382 LspAction::Command(command) => (
11383 proto::code_action::Kind::Command as i32,
11384 serde_json::to_vec(command).unwrap(),
11385 ),
11386 LspAction::CodeLens(code_lens) => (
11387 proto::code_action::Kind::CodeLens as i32,
11388 serde_json::to_vec(code_lens).unwrap(),
11389 ),
11390 };
11391
11392 proto::CodeAction {
11393 server_id: action.server_id.0 as u64,
11394 start: Some(serialize_anchor(&action.range.start)),
11395 end: Some(serialize_anchor(&action.range.end)),
11396 lsp_action,
11397 kind,
11398 resolved: action.resolved,
11399 }
11400 }
11401
11402 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11403 let start = action
11404 .start
11405 .and_then(deserialize_anchor)
11406 .context("invalid start")?;
11407 let end = action
11408 .end
11409 .and_then(deserialize_anchor)
11410 .context("invalid end")?;
11411 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11412 Some(proto::code_action::Kind::Action) => {
11413 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11414 }
11415 Some(proto::code_action::Kind::Command) => {
11416 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11417 }
11418 Some(proto::code_action::Kind::CodeLens) => {
11419 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11420 }
11421 None => anyhow::bail!("Unknown action kind {}", action.kind),
11422 };
11423 Ok(CodeAction {
11424 server_id: LanguageServerId(action.server_id as usize),
11425 range: start..end,
11426 resolved: action.resolved,
11427 lsp_action,
11428 })
11429 }
11430
11431 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11432 match &formatting_result {
11433 Ok(_) => self.last_formatting_failure = None,
11434 Err(error) => {
11435 let error_string = format!("{error:#}");
11436 log::error!("Formatting failed: {error_string}");
11437 self.last_formatting_failure
11438 .replace(error_string.lines().join(" "));
11439 }
11440 }
11441 }
11442
11443 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11444 self.lsp_server_capabilities.remove(&for_server);
11445 for buffer_colors in self.lsp_document_colors.values_mut() {
11446 buffer_colors.colors.remove(&for_server);
11447 buffer_colors.cache_version += 1;
11448 }
11449 for buffer_lens in self.lsp_code_lens.values_mut() {
11450 buffer_lens.lens.remove(&for_server);
11451 }
11452 if let Some(local) = self.as_local_mut() {
11453 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11454 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11455 buffer_servers.remove(&for_server);
11456 }
11457 }
11458 }
11459
11460 pub fn result_id(
11461 &self,
11462 server_id: LanguageServerId,
11463 buffer_id: BufferId,
11464 cx: &App,
11465 ) -> Option<String> {
11466 let abs_path = self
11467 .buffer_store
11468 .read(cx)
11469 .get(buffer_id)
11470 .and_then(|b| File::from_dyn(b.read(cx).file()))
11471 .map(|f| f.abs_path(cx))?;
11472 self.as_local()?
11473 .buffer_pull_diagnostics_result_ids
11474 .get(&server_id)?
11475 .get(&abs_path)?
11476 .clone()
11477 }
11478
11479 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11480 let Some(local) = self.as_local() else {
11481 return HashMap::default();
11482 };
11483 local
11484 .buffer_pull_diagnostics_result_ids
11485 .get(&server_id)
11486 .into_iter()
11487 .flatten()
11488 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11489 .collect()
11490 }
11491
11492 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11493 if let Some(LanguageServerState::Running {
11494 workspace_refresh_task: Some(workspace_refresh_task),
11495 ..
11496 }) = self
11497 .as_local_mut()
11498 .and_then(|local| local.language_servers.get_mut(&server_id))
11499 {
11500 workspace_refresh_task.refresh_tx.try_send(()).ok();
11501 }
11502 }
11503
11504 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11505 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11506 return;
11507 };
11508 let Some(local) = self.as_local_mut() else {
11509 return;
11510 };
11511
11512 for server_id in buffer.update(cx, |buffer, cx| {
11513 local.language_server_ids_for_buffer(buffer, cx)
11514 }) {
11515 if let Some(LanguageServerState::Running {
11516 workspace_refresh_task: Some(workspace_refresh_task),
11517 ..
11518 }) = local.language_servers.get_mut(&server_id)
11519 {
11520 workspace_refresh_task.refresh_tx.try_send(()).ok();
11521 }
11522 }
11523 }
11524
11525 fn apply_workspace_diagnostic_report(
11526 &mut self,
11527 server_id: LanguageServerId,
11528 report: lsp::WorkspaceDiagnosticReportResult,
11529 cx: &mut Context<Self>,
11530 ) {
11531 let workspace_diagnostics =
11532 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11533 let mut unchanged_buffers = HashSet::default();
11534 let mut changed_buffers = HashSet::default();
11535 let workspace_diagnostics_updates = workspace_diagnostics
11536 .into_iter()
11537 .filter_map(
11538 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11539 LspPullDiagnostics::Response {
11540 server_id,
11541 uri,
11542 diagnostics,
11543 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11544 LspPullDiagnostics::Default => None,
11545 },
11546 )
11547 .fold(
11548 HashMap::default(),
11549 |mut acc, (server_id, uri, diagnostics, version)| {
11550 let (result_id, diagnostics) = match diagnostics {
11551 PulledDiagnostics::Unchanged { result_id } => {
11552 unchanged_buffers.insert(uri.clone());
11553 (Some(result_id), Vec::new())
11554 }
11555 PulledDiagnostics::Changed {
11556 result_id,
11557 diagnostics,
11558 } => {
11559 changed_buffers.insert(uri.clone());
11560 (result_id, diagnostics)
11561 }
11562 };
11563 let disk_based_sources = Cow::Owned(
11564 self.language_server_adapter_for_id(server_id)
11565 .as_ref()
11566 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11567 .unwrap_or(&[])
11568 .to_vec(),
11569 );
11570 acc.entry(server_id)
11571 .or_insert_with(Vec::new)
11572 .push(DocumentDiagnosticsUpdate {
11573 server_id,
11574 diagnostics: lsp::PublishDiagnosticsParams {
11575 uri,
11576 diagnostics,
11577 version,
11578 },
11579 result_id,
11580 disk_based_sources,
11581 });
11582 acc
11583 },
11584 );
11585
11586 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11587 self.merge_lsp_diagnostics(
11588 DiagnosticSourceKind::Pulled,
11589 diagnostic_updates,
11590 |buffer, old_diagnostic, cx| {
11591 File::from_dyn(buffer.file())
11592 .and_then(|file| {
11593 let abs_path = file.as_local()?.abs_path(cx);
11594 lsp::Url::from_file_path(abs_path).ok()
11595 })
11596 .is_none_or(|buffer_uri| {
11597 unchanged_buffers.contains(&buffer_uri)
11598 || match old_diagnostic.source_kind {
11599 DiagnosticSourceKind::Pulled => {
11600 !changed_buffers.contains(&buffer_uri)
11601 }
11602 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11603 true
11604 }
11605 }
11606 })
11607 },
11608 cx,
11609 )
11610 .log_err();
11611 }
11612 }
11613
11614 fn register_server_capabilities(
11615 &mut self,
11616 server_id: LanguageServerId,
11617 params: lsp::RegistrationParams,
11618 cx: &mut Context<Self>,
11619 ) -> anyhow::Result<()> {
11620 let server = self
11621 .language_server_for_id(server_id)
11622 .with_context(|| format!("no server {server_id} found"))?;
11623 for reg in params.registrations {
11624 match reg.method.as_str() {
11625 "workspace/didChangeWatchedFiles" => {
11626 if let Some(options) = reg.register_options {
11627 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11628 let caps = serde_json::from_value(options)?;
11629 local_lsp_store
11630 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11631 true
11632 } else {
11633 false
11634 };
11635 if notify {
11636 notify_server_capabilities_updated(&server, cx);
11637 }
11638 }
11639 }
11640 "workspace/didChangeConfiguration" => {
11641 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11642 }
11643 "workspace/symbol" => {
11644 if let Some(options) = parse_register_capabilities(reg)? {
11645 server.update_capabilities(|capabilities| {
11646 capabilities.workspace_symbol_provider = Some(options);
11647 });
11648 notify_server_capabilities_updated(&server, cx);
11649 }
11650 }
11651 "workspace/fileOperations" => {
11652 if let Some(options) = reg.register_options {
11653 let caps = serde_json::from_value(options)?;
11654 server.update_capabilities(|capabilities| {
11655 capabilities
11656 .workspace
11657 .get_or_insert_default()
11658 .file_operations = Some(caps);
11659 });
11660 notify_server_capabilities_updated(&server, cx);
11661 }
11662 }
11663 "workspace/executeCommand" => {
11664 if let Some(options) = reg.register_options {
11665 let options = serde_json::from_value(options)?;
11666 server.update_capabilities(|capabilities| {
11667 capabilities.execute_command_provider = Some(options);
11668 });
11669 notify_server_capabilities_updated(&server, cx);
11670 }
11671 }
11672 "textDocument/rangeFormatting" => {
11673 if let Some(options) = parse_register_capabilities(reg)? {
11674 server.update_capabilities(|capabilities| {
11675 capabilities.document_range_formatting_provider = Some(options);
11676 });
11677 notify_server_capabilities_updated(&server, cx);
11678 }
11679 }
11680 "textDocument/onTypeFormatting" => {
11681 if let Some(options) = reg
11682 .register_options
11683 .map(serde_json::from_value)
11684 .transpose()?
11685 {
11686 server.update_capabilities(|capabilities| {
11687 capabilities.document_on_type_formatting_provider = Some(options);
11688 });
11689 notify_server_capabilities_updated(&server, cx);
11690 }
11691 }
11692 "textDocument/formatting" => {
11693 if let Some(options) = parse_register_capabilities(reg)? {
11694 server.update_capabilities(|capabilities| {
11695 capabilities.document_formatting_provider = Some(options);
11696 });
11697 notify_server_capabilities_updated(&server, cx);
11698 }
11699 }
11700 "textDocument/rename" => {
11701 if let Some(options) = parse_register_capabilities(reg)? {
11702 server.update_capabilities(|capabilities| {
11703 capabilities.rename_provider = Some(options);
11704 });
11705 notify_server_capabilities_updated(&server, cx);
11706 }
11707 }
11708 "textDocument/inlayHint" => {
11709 if let Some(options) = parse_register_capabilities(reg)? {
11710 server.update_capabilities(|capabilities| {
11711 capabilities.inlay_hint_provider = Some(options);
11712 });
11713 notify_server_capabilities_updated(&server, cx);
11714 }
11715 }
11716 "textDocument/documentSymbol" => {
11717 if let Some(options) = parse_register_capabilities(reg)? {
11718 server.update_capabilities(|capabilities| {
11719 capabilities.document_symbol_provider = Some(options);
11720 });
11721 notify_server_capabilities_updated(&server, cx);
11722 }
11723 }
11724 "textDocument/codeAction" => {
11725 if let Some(options) = reg
11726 .register_options
11727 .map(serde_json::from_value)
11728 .transpose()?
11729 {
11730 server.update_capabilities(|capabilities| {
11731 capabilities.code_action_provider =
11732 Some(lsp::CodeActionProviderCapability::Options(options));
11733 });
11734 notify_server_capabilities_updated(&server, cx);
11735 }
11736 }
11737 "textDocument/definition" => {
11738 if let Some(options) = parse_register_capabilities(reg)? {
11739 server.update_capabilities(|capabilities| {
11740 capabilities.definition_provider = Some(options);
11741 });
11742 notify_server_capabilities_updated(&server, cx);
11743 }
11744 }
11745 "textDocument/completion" => {
11746 if let Some(caps) = reg
11747 .register_options
11748 .map(serde_json::from_value)
11749 .transpose()?
11750 {
11751 server.update_capabilities(|capabilities| {
11752 capabilities.completion_provider = Some(caps);
11753 });
11754 notify_server_capabilities_updated(&server, cx);
11755 }
11756 }
11757 "textDocument/hover" => {
11758 if let Some(caps) = reg
11759 .register_options
11760 .map(serde_json::from_value)
11761 .transpose()?
11762 {
11763 server.update_capabilities(|capabilities| {
11764 capabilities.hover_provider = Some(caps);
11765 });
11766 notify_server_capabilities_updated(&server, cx);
11767 }
11768 }
11769 "textDocument/signatureHelp" => {
11770 if let Some(caps) = reg
11771 .register_options
11772 .map(serde_json::from_value)
11773 .transpose()?
11774 {
11775 server.update_capabilities(|capabilities| {
11776 capabilities.signature_help_provider = Some(caps);
11777 });
11778 notify_server_capabilities_updated(&server, cx);
11779 }
11780 }
11781 "textDocument/didChange" => {
11782 if let Some(sync_kind) = reg
11783 .register_options
11784 .and_then(|opts| opts.get("syncKind").cloned())
11785 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11786 .transpose()?
11787 {
11788 server.update_capabilities(|capabilities| {
11789 let mut sync_options =
11790 Self::take_text_document_sync_options(capabilities);
11791 sync_options.change = Some(sync_kind);
11792 capabilities.text_document_sync =
11793 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11794 });
11795 notify_server_capabilities_updated(&server, cx);
11796 }
11797 }
11798 "textDocument/didSave" => {
11799 if let Some(include_text) = reg
11800 .register_options
11801 .map(|opts| {
11802 let transpose = opts
11803 .get("includeText")
11804 .cloned()
11805 .map(serde_json::from_value::<Option<bool>>)
11806 .transpose();
11807 match transpose {
11808 Ok(value) => Ok(value.flatten()),
11809 Err(e) => Err(e),
11810 }
11811 })
11812 .transpose()?
11813 {
11814 server.update_capabilities(|capabilities| {
11815 let mut sync_options =
11816 Self::take_text_document_sync_options(capabilities);
11817 sync_options.save =
11818 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11819 include_text,
11820 }));
11821 capabilities.text_document_sync =
11822 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11823 });
11824 notify_server_capabilities_updated(&server, cx);
11825 }
11826 }
11827 "textDocument/codeLens" => {
11828 if let Some(caps) = reg
11829 .register_options
11830 .map(serde_json::from_value)
11831 .transpose()?
11832 {
11833 server.update_capabilities(|capabilities| {
11834 capabilities.code_lens_provider = Some(caps);
11835 });
11836 notify_server_capabilities_updated(&server, cx);
11837 }
11838 }
11839 "textDocument/diagnostic" => {
11840 if let Some(caps) = reg
11841 .register_options
11842 .map(serde_json::from_value)
11843 .transpose()?
11844 {
11845 server.update_capabilities(|capabilities| {
11846 capabilities.diagnostic_provider = Some(caps);
11847 });
11848 notify_server_capabilities_updated(&server, cx);
11849 }
11850 }
11851 "textDocument/colorProvider" => {
11852 if let Some(caps) = reg
11853 .register_options
11854 .map(serde_json::from_value)
11855 .transpose()?
11856 {
11857 server.update_capabilities(|capabilities| {
11858 capabilities.color_provider = Some(caps);
11859 });
11860 notify_server_capabilities_updated(&server, cx);
11861 }
11862 }
11863 _ => log::warn!("unhandled capability registration: {reg:?}"),
11864 }
11865 }
11866
11867 Ok(())
11868 }
11869
11870 fn unregister_server_capabilities(
11871 &mut self,
11872 server_id: LanguageServerId,
11873 params: lsp::UnregistrationParams,
11874 cx: &mut Context<Self>,
11875 ) -> anyhow::Result<()> {
11876 let server = self
11877 .language_server_for_id(server_id)
11878 .with_context(|| format!("no server {server_id} found"))?;
11879 for unreg in params.unregisterations.iter() {
11880 match unreg.method.as_str() {
11881 "workspace/didChangeWatchedFiles" => {
11882 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11883 local_lsp_store
11884 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11885 true
11886 } else {
11887 false
11888 };
11889 if notify {
11890 notify_server_capabilities_updated(&server, cx);
11891 }
11892 }
11893 "workspace/didChangeConfiguration" => {
11894 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11895 }
11896 "workspace/symbol" => {
11897 server.update_capabilities(|capabilities| {
11898 capabilities.workspace_symbol_provider = None
11899 });
11900 notify_server_capabilities_updated(&server, cx);
11901 }
11902 "workspace/fileOperations" => {
11903 server.update_capabilities(|capabilities| {
11904 capabilities
11905 .workspace
11906 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11907 workspace_folders: None,
11908 file_operations: None,
11909 })
11910 .file_operations = None;
11911 });
11912 notify_server_capabilities_updated(&server, cx);
11913 }
11914 "workspace/executeCommand" => {
11915 server.update_capabilities(|capabilities| {
11916 capabilities.execute_command_provider = None;
11917 });
11918 notify_server_capabilities_updated(&server, cx);
11919 }
11920 "textDocument/rangeFormatting" => {
11921 server.update_capabilities(|capabilities| {
11922 capabilities.document_range_formatting_provider = None
11923 });
11924 notify_server_capabilities_updated(&server, cx);
11925 }
11926 "textDocument/onTypeFormatting" => {
11927 server.update_capabilities(|capabilities| {
11928 capabilities.document_on_type_formatting_provider = None;
11929 });
11930 notify_server_capabilities_updated(&server, cx);
11931 }
11932 "textDocument/formatting" => {
11933 server.update_capabilities(|capabilities| {
11934 capabilities.document_formatting_provider = None;
11935 });
11936 notify_server_capabilities_updated(&server, cx);
11937 }
11938 "textDocument/rename" => {
11939 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
11940 notify_server_capabilities_updated(&server, cx);
11941 }
11942 "textDocument/codeAction" => {
11943 server.update_capabilities(|capabilities| {
11944 capabilities.code_action_provider = None;
11945 });
11946 notify_server_capabilities_updated(&server, cx);
11947 }
11948 "textDocument/definition" => {
11949 server.update_capabilities(|capabilities| {
11950 capabilities.definition_provider = None;
11951 });
11952 notify_server_capabilities_updated(&server, cx);
11953 }
11954 "textDocument/completion" => {
11955 server.update_capabilities(|capabilities| {
11956 capabilities.completion_provider = None;
11957 });
11958 notify_server_capabilities_updated(&server, cx);
11959 }
11960 "textDocument/hover" => {
11961 server.update_capabilities(|capabilities| {
11962 capabilities.hover_provider = None;
11963 });
11964 notify_server_capabilities_updated(&server, cx);
11965 }
11966 "textDocument/signatureHelp" => {
11967 server.update_capabilities(|capabilities| {
11968 capabilities.signature_help_provider = None;
11969 });
11970 notify_server_capabilities_updated(&server, cx);
11971 }
11972 "textDocument/didChange" => {
11973 server.update_capabilities(|capabilities| {
11974 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11975 sync_options.change = None;
11976 capabilities.text_document_sync =
11977 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11978 });
11979 notify_server_capabilities_updated(&server, cx);
11980 }
11981 "textDocument/didSave" => {
11982 server.update_capabilities(|capabilities| {
11983 let mut sync_options = Self::take_text_document_sync_options(capabilities);
11984 sync_options.save = None;
11985 capabilities.text_document_sync =
11986 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11987 });
11988 notify_server_capabilities_updated(&server, cx);
11989 }
11990 "textDocument/codeLens" => {
11991 server.update_capabilities(|capabilities| {
11992 capabilities.code_lens_provider = None;
11993 });
11994 notify_server_capabilities_updated(&server, cx);
11995 }
11996 "textDocument/diagnostic" => {
11997 server.update_capabilities(|capabilities| {
11998 capabilities.diagnostic_provider = None;
11999 });
12000 notify_server_capabilities_updated(&server, cx);
12001 }
12002 "textDocument/colorProvider" => {
12003 server.update_capabilities(|capabilities| {
12004 capabilities.color_provider = None;
12005 });
12006 notify_server_capabilities_updated(&server, cx);
12007 }
12008 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12009 }
12010 }
12011
12012 Ok(())
12013 }
12014
12015 fn take_text_document_sync_options(
12016 capabilities: &mut lsp::ServerCapabilities,
12017 ) -> lsp::TextDocumentSyncOptions {
12018 match capabilities.text_document_sync.take() {
12019 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12020 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12021 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12022 sync_options.change = Some(sync_kind);
12023 sync_options
12024 }
12025 None => lsp::TextDocumentSyncOptions::default(),
12026 }
12027 }
12028}
12029
12030// Registration with registerOptions as null, should fallback to true.
12031// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12032fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12033 reg: lsp::Registration,
12034) -> anyhow::Result<Option<OneOf<bool, T>>> {
12035 Ok(match reg.register_options {
12036 Some(options) => Some(OneOf::Right(serde_json::from_value::<T>(options)?)),
12037 None => Some(OneOf::Left(true)),
12038 })
12039}
12040
12041fn subscribe_to_binary_statuses(
12042 languages: &Arc<LanguageRegistry>,
12043 cx: &mut Context<'_, LspStore>,
12044) -> Task<()> {
12045 let mut server_statuses = languages.language_server_binary_statuses();
12046 cx.spawn(async move |lsp_store, cx| {
12047 while let Some((server_name, binary_status)) = server_statuses.next().await {
12048 if lsp_store
12049 .update(cx, |_, cx| {
12050 let mut message = None;
12051 let binary_status = match binary_status {
12052 BinaryStatus::None => proto::ServerBinaryStatus::None,
12053 BinaryStatus::CheckingForUpdate => {
12054 proto::ServerBinaryStatus::CheckingForUpdate
12055 }
12056 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12057 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12058 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12059 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12060 BinaryStatus::Failed { error } => {
12061 message = Some(error);
12062 proto::ServerBinaryStatus::Failed
12063 }
12064 };
12065 cx.emit(LspStoreEvent::LanguageServerUpdate {
12066 // Binary updates are about the binary that might not have any language server id at that point.
12067 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12068 language_server_id: LanguageServerId(0),
12069 name: Some(server_name),
12070 message: proto::update_language_server::Variant::StatusUpdate(
12071 proto::StatusUpdate {
12072 message,
12073 status: Some(proto::status_update::Status::Binary(
12074 binary_status as i32,
12075 )),
12076 },
12077 ),
12078 });
12079 })
12080 .is_err()
12081 {
12082 break;
12083 }
12084 }
12085 })
12086}
12087
12088fn lsp_workspace_diagnostics_refresh(
12089 server: Arc<LanguageServer>,
12090 cx: &mut Context<'_, LspStore>,
12091) -> Option<WorkspaceRefreshTask> {
12092 let identifier = match server.capabilities().diagnostic_provider? {
12093 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12094 if !diagnostic_options.workspace_diagnostics {
12095 return None;
12096 }
12097 diagnostic_options.identifier
12098 }
12099 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12100 let diagnostic_options = registration_options.diagnostic_options;
12101 if !diagnostic_options.workspace_diagnostics {
12102 return None;
12103 }
12104 diagnostic_options.identifier
12105 }
12106 };
12107
12108 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12109 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12110 refresh_tx.try_send(()).ok();
12111
12112 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12113 let mut attempts = 0;
12114 let max_attempts = 50;
12115 let mut requests = 0;
12116
12117 loop {
12118 let Some(()) = refresh_rx.recv().await else {
12119 return;
12120 };
12121
12122 'request: loop {
12123 requests += 1;
12124 if attempts > max_attempts {
12125 log::error!(
12126 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12127 );
12128 return;
12129 }
12130 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12131 cx.background_executor()
12132 .timer(Duration::from_millis(backoff_millis))
12133 .await;
12134 attempts += 1;
12135
12136 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12137 lsp_store
12138 .all_result_ids(server.server_id())
12139 .into_iter()
12140 .filter_map(|(abs_path, result_id)| {
12141 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12142 Some(lsp::PreviousResultId {
12143 uri,
12144 value: result_id,
12145 })
12146 })
12147 .collect()
12148 }) else {
12149 return;
12150 };
12151
12152 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
12153
12154 progress_rx.try_recv().ok();
12155 let timer =
12156 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12157 let progress = pin!(progress_rx.recv().fuse());
12158 let response_result = server
12159 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12160 lsp::WorkspaceDiagnosticParams {
12161 previous_result_ids,
12162 identifier: identifier.clone(),
12163 work_done_progress_params: Default::default(),
12164 partial_result_params: lsp::PartialResultParams {
12165 partial_result_token: Some(lsp::ProgressToken::String(token)),
12166 },
12167 },
12168 select(timer, progress).then(|either| match either {
12169 Either::Left((message, ..)) => ready(message).left_future(),
12170 Either::Right(..) => pending::<String>().right_future(),
12171 }),
12172 )
12173 .await;
12174
12175 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12176 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12177 match response_result {
12178 ConnectionResult::Timeout => {
12179 log::error!("Timeout during workspace diagnostics pull");
12180 continue 'request;
12181 }
12182 ConnectionResult::ConnectionReset => {
12183 log::error!("Server closed a workspace diagnostics pull request");
12184 continue 'request;
12185 }
12186 ConnectionResult::Result(Err(e)) => {
12187 log::error!("Error during workspace diagnostics pull: {e:#}");
12188 break 'request;
12189 }
12190 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12191 attempts = 0;
12192 if lsp_store
12193 .update(cx, |lsp_store, cx| {
12194 lsp_store.apply_workspace_diagnostic_report(
12195 server.server_id(),
12196 pulled_diagnostics,
12197 cx,
12198 )
12199 })
12200 .is_err()
12201 {
12202 return;
12203 }
12204 break 'request;
12205 }
12206 }
12207 }
12208 }
12209 });
12210
12211 Some(WorkspaceRefreshTask {
12212 refresh_tx,
12213 progress_tx,
12214 task: workspace_query_language_server,
12215 })
12216}
12217
12218fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12219 let CompletionSource::BufferWord {
12220 word_range,
12221 resolved,
12222 } = &mut completion.source
12223 else {
12224 return;
12225 };
12226 if *resolved {
12227 return;
12228 }
12229
12230 if completion.new_text
12231 != snapshot
12232 .text_for_range(word_range.clone())
12233 .collect::<String>()
12234 {
12235 return;
12236 }
12237
12238 let mut offset = 0;
12239 for chunk in snapshot.chunks(word_range.clone(), true) {
12240 let end_offset = offset + chunk.text.len();
12241 if let Some(highlight_id) = chunk.syntax_highlight_id {
12242 completion
12243 .label
12244 .runs
12245 .push((offset..end_offset, highlight_id));
12246 }
12247 offset = end_offset;
12248 }
12249 *resolved = true;
12250}
12251
12252impl EventEmitter<LspStoreEvent> for LspStore {}
12253
12254fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12255 hover
12256 .contents
12257 .retain(|hover_block| !hover_block.text.trim().is_empty());
12258 if hover.contents.is_empty() {
12259 None
12260 } else {
12261 Some(hover)
12262 }
12263}
12264
12265async fn populate_labels_for_completions(
12266 new_completions: Vec<CoreCompletion>,
12267 language: Option<Arc<Language>>,
12268 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12269) -> Vec<Completion> {
12270 let lsp_completions = new_completions
12271 .iter()
12272 .filter_map(|new_completion| {
12273 new_completion
12274 .source
12275 .lsp_completion(true)
12276 .map(|lsp_completion| lsp_completion.into_owned())
12277 })
12278 .collect::<Vec<_>>();
12279
12280 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12281 lsp_adapter
12282 .labels_for_completions(&lsp_completions, language)
12283 .await
12284 .log_err()
12285 .unwrap_or_default()
12286 } else {
12287 Vec::new()
12288 }
12289 .into_iter()
12290 .fuse();
12291
12292 let mut completions = Vec::new();
12293 for completion in new_completions {
12294 match completion.source.lsp_completion(true) {
12295 Some(lsp_completion) => {
12296 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12297
12298 let mut label = labels.next().flatten().unwrap_or_else(|| {
12299 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12300 });
12301 ensure_uniform_list_compatible_label(&mut label);
12302 completions.push(Completion {
12303 label,
12304 documentation,
12305 replace_range: completion.replace_range,
12306 new_text: completion.new_text,
12307 insert_text_mode: lsp_completion.insert_text_mode,
12308 source: completion.source,
12309 icon_path: None,
12310 confirm: None,
12311 });
12312 }
12313 None => {
12314 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12315 ensure_uniform_list_compatible_label(&mut label);
12316 completions.push(Completion {
12317 label,
12318 documentation: None,
12319 replace_range: completion.replace_range,
12320 new_text: completion.new_text,
12321 source: completion.source,
12322 insert_text_mode: None,
12323 icon_path: None,
12324 confirm: None,
12325 });
12326 }
12327 }
12328 }
12329 completions
12330}
12331
12332#[derive(Debug)]
12333pub enum LanguageServerToQuery {
12334 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12335 FirstCapable,
12336 /// Query a specific language server.
12337 Other(LanguageServerId),
12338}
12339
12340#[derive(Default)]
12341struct RenamePathsWatchedForServer {
12342 did_rename: Vec<RenameActionPredicate>,
12343 will_rename: Vec<RenameActionPredicate>,
12344}
12345
12346impl RenamePathsWatchedForServer {
12347 fn with_did_rename_patterns(
12348 mut self,
12349 did_rename: Option<&FileOperationRegistrationOptions>,
12350 ) -> Self {
12351 if let Some(did_rename) = did_rename {
12352 self.did_rename = did_rename
12353 .filters
12354 .iter()
12355 .filter_map(|filter| filter.try_into().log_err())
12356 .collect();
12357 }
12358 self
12359 }
12360 fn with_will_rename_patterns(
12361 mut self,
12362 will_rename: Option<&FileOperationRegistrationOptions>,
12363 ) -> Self {
12364 if let Some(will_rename) = will_rename {
12365 self.will_rename = will_rename
12366 .filters
12367 .iter()
12368 .filter_map(|filter| filter.try_into().log_err())
12369 .collect();
12370 }
12371 self
12372 }
12373
12374 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12375 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12376 }
12377 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12378 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12379 }
12380}
12381
12382impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12383 type Error = globset::Error;
12384 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12385 Ok(Self {
12386 kind: ops.pattern.matches.clone(),
12387 glob: GlobBuilder::new(&ops.pattern.glob)
12388 .case_insensitive(
12389 ops.pattern
12390 .options
12391 .as_ref()
12392 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12393 )
12394 .build()?
12395 .compile_matcher(),
12396 })
12397 }
12398}
12399struct RenameActionPredicate {
12400 glob: GlobMatcher,
12401 kind: Option<FileOperationPatternKind>,
12402}
12403
12404impl RenameActionPredicate {
12405 // Returns true if language server should be notified
12406 fn eval(&self, path: &str, is_dir: bool) -> bool {
12407 self.kind.as_ref().is_none_or(|kind| {
12408 let expected_kind = if is_dir {
12409 FileOperationPatternKind::Folder
12410 } else {
12411 FileOperationPatternKind::File
12412 };
12413 kind == &expected_kind
12414 }) && self.glob.is_match(path)
12415 }
12416}
12417
12418#[derive(Default)]
12419struct LanguageServerWatchedPaths {
12420 worktree_paths: HashMap<WorktreeId, GlobSet>,
12421 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12422}
12423
12424#[derive(Default)]
12425struct LanguageServerWatchedPathsBuilder {
12426 worktree_paths: HashMap<WorktreeId, GlobSet>,
12427 abs_paths: HashMap<Arc<Path>, GlobSet>,
12428}
12429
12430impl LanguageServerWatchedPathsBuilder {
12431 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12432 self.worktree_paths.insert(worktree_id, glob_set);
12433 }
12434 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12435 self.abs_paths.insert(path, glob_set);
12436 }
12437 fn build(
12438 self,
12439 fs: Arc<dyn Fs>,
12440 language_server_id: LanguageServerId,
12441 cx: &mut Context<LspStore>,
12442 ) -> LanguageServerWatchedPaths {
12443 let project = cx.weak_entity();
12444
12445 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12446 let abs_paths = self
12447 .abs_paths
12448 .into_iter()
12449 .map(|(abs_path, globset)| {
12450 let task = cx.spawn({
12451 let abs_path = abs_path.clone();
12452 let fs = fs.clone();
12453
12454 let lsp_store = project.clone();
12455 async move |_, cx| {
12456 maybe!(async move {
12457 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12458 while let Some(update) = push_updates.0.next().await {
12459 let action = lsp_store
12460 .update(cx, |this, _| {
12461 let Some(local) = this.as_local() else {
12462 return ControlFlow::Break(());
12463 };
12464 let Some(watcher) = local
12465 .language_server_watched_paths
12466 .get(&language_server_id)
12467 else {
12468 return ControlFlow::Break(());
12469 };
12470 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12471 "Watched abs path is not registered with a watcher",
12472 );
12473 let matching_entries = update
12474 .into_iter()
12475 .filter(|event| globs.is_match(&event.path))
12476 .collect::<Vec<_>>();
12477 this.lsp_notify_abs_paths_changed(
12478 language_server_id,
12479 matching_entries,
12480 );
12481 ControlFlow::Continue(())
12482 })
12483 .ok()?;
12484
12485 if action.is_break() {
12486 break;
12487 }
12488 }
12489 Some(())
12490 })
12491 .await;
12492 }
12493 });
12494 (abs_path, (globset, task))
12495 })
12496 .collect();
12497 LanguageServerWatchedPaths {
12498 worktree_paths: self.worktree_paths,
12499 abs_paths,
12500 }
12501 }
12502}
12503
12504struct LspBufferSnapshot {
12505 version: i32,
12506 snapshot: TextBufferSnapshot,
12507}
12508
12509/// A prompt requested by LSP server.
12510#[derive(Clone, Debug)]
12511pub struct LanguageServerPromptRequest {
12512 pub level: PromptLevel,
12513 pub message: String,
12514 pub actions: Vec<MessageActionItem>,
12515 pub lsp_name: String,
12516 pub(crate) response_channel: Sender<MessageActionItem>,
12517}
12518
12519impl LanguageServerPromptRequest {
12520 pub async fn respond(self, index: usize) -> Option<()> {
12521 if let Some(response) = self.actions.into_iter().nth(index) {
12522 self.response_channel.send(response).await.ok()
12523 } else {
12524 None
12525 }
12526 }
12527}
12528impl PartialEq for LanguageServerPromptRequest {
12529 fn eq(&self, other: &Self) -> bool {
12530 self.message == other.message && self.actions == other.actions
12531 }
12532}
12533
12534#[derive(Clone, Debug, PartialEq)]
12535pub enum LanguageServerLogType {
12536 Log(MessageType),
12537 Trace(Option<String>),
12538}
12539
12540impl LanguageServerLogType {
12541 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12542 match self {
12543 Self::Log(log_type) => {
12544 let message_type = match *log_type {
12545 MessageType::ERROR => 1,
12546 MessageType::WARNING => 2,
12547 MessageType::INFO => 3,
12548 MessageType::LOG => 4,
12549 other => {
12550 log::warn!("Unknown lsp log message type: {:?}", other);
12551 4
12552 }
12553 };
12554 proto::language_server_log::LogType::LogMessageType(message_type)
12555 }
12556 Self::Trace(message) => {
12557 proto::language_server_log::LogType::LogTrace(proto::LspLogTrace {
12558 message: message.clone(),
12559 })
12560 }
12561 }
12562 }
12563
12564 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12565 match log_type {
12566 proto::language_server_log::LogType::LogMessageType(message_type) => {
12567 Self::Log(match message_type {
12568 1 => MessageType::ERROR,
12569 2 => MessageType::WARNING,
12570 3 => MessageType::INFO,
12571 4 => MessageType::LOG,
12572 _ => MessageType::LOG,
12573 })
12574 }
12575 proto::language_server_log::LogType::LogTrace(trace) => Self::Trace(trace.message),
12576 }
12577 }
12578}
12579
12580pub struct WorkspaceRefreshTask {
12581 refresh_tx: mpsc::Sender<()>,
12582 progress_tx: mpsc::Sender<()>,
12583 #[allow(dead_code)]
12584 task: Task<()>,
12585}
12586
12587pub enum LanguageServerState {
12588 Starting {
12589 startup: Task<Option<Arc<LanguageServer>>>,
12590 /// List of language servers that will be added to the workspace once it's initialization completes.
12591 pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
12592 },
12593
12594 Running {
12595 adapter: Arc<CachedLspAdapter>,
12596 server: Arc<LanguageServer>,
12597 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12598 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12599 },
12600}
12601
12602impl LanguageServerState {
12603 fn add_workspace_folder(&self, uri: Url) {
12604 match self {
12605 LanguageServerState::Starting {
12606 pending_workspace_folders,
12607 ..
12608 } => {
12609 pending_workspace_folders.lock().insert(uri);
12610 }
12611 LanguageServerState::Running { server, .. } => {
12612 server.add_workspace_folder(uri);
12613 }
12614 }
12615 }
12616 fn _remove_workspace_folder(&self, uri: Url) {
12617 match self {
12618 LanguageServerState::Starting {
12619 pending_workspace_folders,
12620 ..
12621 } => {
12622 pending_workspace_folders.lock().remove(&uri);
12623 }
12624 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12625 }
12626 }
12627}
12628
12629impl std::fmt::Debug for LanguageServerState {
12630 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12631 match self {
12632 LanguageServerState::Starting { .. } => {
12633 f.debug_struct("LanguageServerState::Starting").finish()
12634 }
12635 LanguageServerState::Running { .. } => {
12636 f.debug_struct("LanguageServerState::Running").finish()
12637 }
12638 }
12639 }
12640}
12641
12642#[derive(Clone, Debug, Serialize)]
12643pub struct LanguageServerProgress {
12644 pub is_disk_based_diagnostics_progress: bool,
12645 pub is_cancellable: bool,
12646 pub title: Option<String>,
12647 pub message: Option<String>,
12648 pub percentage: Option<usize>,
12649 #[serde(skip_serializing)]
12650 pub last_update_at: Instant,
12651}
12652
12653#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12654pub struct DiagnosticSummary {
12655 pub error_count: usize,
12656 pub warning_count: usize,
12657}
12658
12659impl DiagnosticSummary {
12660 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12661 let mut this = Self {
12662 error_count: 0,
12663 warning_count: 0,
12664 };
12665
12666 for entry in diagnostics {
12667 if entry.diagnostic.is_primary {
12668 match entry.diagnostic.severity {
12669 DiagnosticSeverity::ERROR => this.error_count += 1,
12670 DiagnosticSeverity::WARNING => this.warning_count += 1,
12671 _ => {}
12672 }
12673 }
12674 }
12675
12676 this
12677 }
12678
12679 pub fn is_empty(&self) -> bool {
12680 self.error_count == 0 && self.warning_count == 0
12681 }
12682
12683 pub fn to_proto(
12684 self,
12685 language_server_id: LanguageServerId,
12686 path: &Path,
12687 ) -> proto::DiagnosticSummary {
12688 proto::DiagnosticSummary {
12689 path: path.to_proto(),
12690 language_server_id: language_server_id.0 as u64,
12691 error_count: self.error_count as u32,
12692 warning_count: self.warning_count as u32,
12693 }
12694 }
12695}
12696
12697#[derive(Clone, Debug)]
12698pub enum CompletionDocumentation {
12699 /// There is no documentation for this completion.
12700 Undocumented,
12701 /// A single line of documentation.
12702 SingleLine(SharedString),
12703 /// Multiple lines of plain text documentation.
12704 MultiLinePlainText(SharedString),
12705 /// Markdown documentation.
12706 MultiLineMarkdown(SharedString),
12707 /// Both single line and multiple lines of plain text documentation.
12708 SingleLineAndMultiLinePlainText {
12709 single_line: SharedString,
12710 plain_text: Option<SharedString>,
12711 },
12712}
12713
12714impl From<lsp::Documentation> for CompletionDocumentation {
12715 fn from(docs: lsp::Documentation) -> Self {
12716 match docs {
12717 lsp::Documentation::String(text) => {
12718 if text.lines().count() <= 1 {
12719 CompletionDocumentation::SingleLine(text.into())
12720 } else {
12721 CompletionDocumentation::MultiLinePlainText(text.into())
12722 }
12723 }
12724
12725 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
12726 lsp::MarkupKind::PlainText => {
12727 if value.lines().count() <= 1 {
12728 CompletionDocumentation::SingleLine(value.into())
12729 } else {
12730 CompletionDocumentation::MultiLinePlainText(value.into())
12731 }
12732 }
12733
12734 lsp::MarkupKind::Markdown => {
12735 CompletionDocumentation::MultiLineMarkdown(value.into())
12736 }
12737 },
12738 }
12739 }
12740}
12741
12742fn glob_literal_prefix(glob: &Path) -> PathBuf {
12743 glob.components()
12744 .take_while(|component| match component {
12745 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
12746 _ => true,
12747 })
12748 .collect()
12749}
12750
12751pub struct SshLspAdapter {
12752 name: LanguageServerName,
12753 binary: LanguageServerBinary,
12754 initialization_options: Option<String>,
12755 code_action_kinds: Option<Vec<CodeActionKind>>,
12756}
12757
12758impl SshLspAdapter {
12759 pub fn new(
12760 name: LanguageServerName,
12761 binary: LanguageServerBinary,
12762 initialization_options: Option<String>,
12763 code_action_kinds: Option<String>,
12764 ) -> Self {
12765 Self {
12766 name,
12767 binary,
12768 initialization_options,
12769 code_action_kinds: code_action_kinds
12770 .as_ref()
12771 .and_then(|c| serde_json::from_str(c).ok()),
12772 }
12773 }
12774}
12775
12776#[async_trait(?Send)]
12777impl LspAdapter for SshLspAdapter {
12778 fn name(&self) -> LanguageServerName {
12779 self.name.clone()
12780 }
12781
12782 async fn initialization_options(
12783 self: Arc<Self>,
12784 _: &dyn Fs,
12785 _: &Arc<dyn LspAdapterDelegate>,
12786 ) -> Result<Option<serde_json::Value>> {
12787 let Some(options) = &self.initialization_options else {
12788 return Ok(None);
12789 };
12790 let result = serde_json::from_str(options)?;
12791 Ok(result)
12792 }
12793
12794 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
12795 self.code_action_kinds.clone()
12796 }
12797
12798 async fn check_if_user_installed(
12799 &self,
12800 _: &dyn LspAdapterDelegate,
12801 _: Option<Toolchain>,
12802 _: &AsyncApp,
12803 ) -> Option<LanguageServerBinary> {
12804 Some(self.binary.clone())
12805 }
12806
12807 async fn cached_server_binary(
12808 &self,
12809 _: PathBuf,
12810 _: &dyn LspAdapterDelegate,
12811 ) -> Option<LanguageServerBinary> {
12812 None
12813 }
12814
12815 async fn fetch_latest_server_version(
12816 &self,
12817 _: &dyn LspAdapterDelegate,
12818 ) -> Result<Box<dyn 'static + Send + Any>> {
12819 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
12820 }
12821
12822 async fn fetch_server_binary(
12823 &self,
12824 _: Box<dyn 'static + Send + Any>,
12825 _: PathBuf,
12826 _: &dyn LspAdapterDelegate,
12827 ) -> Result<LanguageServerBinary> {
12828 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
12829 }
12830}
12831
12832pub fn language_server_settings<'a>(
12833 delegate: &'a dyn LspAdapterDelegate,
12834 language: &LanguageServerName,
12835 cx: &'a App,
12836) -> Option<&'a LspSettings> {
12837 language_server_settings_for(
12838 SettingsLocation {
12839 worktree_id: delegate.worktree_id(),
12840 path: delegate.worktree_root_path(),
12841 },
12842 language,
12843 cx,
12844 )
12845}
12846
12847pub(crate) fn language_server_settings_for<'a>(
12848 location: SettingsLocation<'a>,
12849 language: &LanguageServerName,
12850 cx: &'a App,
12851) -> Option<&'a LspSettings> {
12852 ProjectSettings::get(Some(location), cx).lsp.get(language)
12853}
12854
12855pub struct LocalLspAdapterDelegate {
12856 lsp_store: WeakEntity<LspStore>,
12857 worktree: worktree::Snapshot,
12858 fs: Arc<dyn Fs>,
12859 http_client: Arc<dyn HttpClient>,
12860 language_registry: Arc<LanguageRegistry>,
12861 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
12862}
12863
12864impl LocalLspAdapterDelegate {
12865 pub fn new(
12866 language_registry: Arc<LanguageRegistry>,
12867 environment: &Entity<ProjectEnvironment>,
12868 lsp_store: WeakEntity<LspStore>,
12869 worktree: &Entity<Worktree>,
12870 http_client: Arc<dyn HttpClient>,
12871 fs: Arc<dyn Fs>,
12872 cx: &mut App,
12873 ) -> Arc<Self> {
12874 let load_shell_env_task = environment.update(cx, |env, cx| {
12875 env.get_worktree_environment(worktree.clone(), cx)
12876 });
12877
12878 Arc::new(Self {
12879 lsp_store,
12880 worktree: worktree.read(cx).snapshot(),
12881 fs,
12882 http_client,
12883 language_registry,
12884 load_shell_env_task,
12885 })
12886 }
12887
12888 fn from_local_lsp(
12889 local: &LocalLspStore,
12890 worktree: &Entity<Worktree>,
12891 cx: &mut App,
12892 ) -> Arc<Self> {
12893 Self::new(
12894 local.languages.clone(),
12895 &local.environment,
12896 local.weak.clone(),
12897 worktree,
12898 local.http_client.clone(),
12899 local.fs.clone(),
12900 cx,
12901 )
12902 }
12903}
12904
12905#[async_trait]
12906impl LspAdapterDelegate for LocalLspAdapterDelegate {
12907 fn show_notification(&self, message: &str, cx: &mut App) {
12908 self.lsp_store
12909 .update(cx, |_, cx| {
12910 cx.emit(LspStoreEvent::Notification(message.to_owned()))
12911 })
12912 .ok();
12913 }
12914
12915 fn http_client(&self) -> Arc<dyn HttpClient> {
12916 self.http_client.clone()
12917 }
12918
12919 fn worktree_id(&self) -> WorktreeId {
12920 self.worktree.id()
12921 }
12922
12923 fn worktree_root_path(&self) -> &Path {
12924 self.worktree.abs_path().as_ref()
12925 }
12926
12927 async fn shell_env(&self) -> HashMap<String, String> {
12928 let task = self.load_shell_env_task.clone();
12929 task.await.unwrap_or_default()
12930 }
12931
12932 async fn npm_package_installed_version(
12933 &self,
12934 package_name: &str,
12935 ) -> Result<Option<(PathBuf, String)>> {
12936 let local_package_directory = self.worktree_root_path();
12937 let node_modules_directory = local_package_directory.join("node_modules");
12938
12939 if let Some(version) =
12940 read_package_installed_version(node_modules_directory.clone(), package_name).await?
12941 {
12942 return Ok(Some((node_modules_directory, version)));
12943 }
12944 let Some(npm) = self.which("npm".as_ref()).await else {
12945 log::warn!(
12946 "Failed to find npm executable for {:?}",
12947 local_package_directory
12948 );
12949 return Ok(None);
12950 };
12951
12952 let env = self.shell_env().await;
12953 let output = util::command::new_smol_command(&npm)
12954 .args(["root", "-g"])
12955 .envs(env)
12956 .current_dir(local_package_directory)
12957 .output()
12958 .await?;
12959 let global_node_modules =
12960 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
12961
12962 if let Some(version) =
12963 read_package_installed_version(global_node_modules.clone(), package_name).await?
12964 {
12965 return Ok(Some((global_node_modules, version)));
12966 }
12967 return Ok(None);
12968 }
12969
12970 #[cfg(not(target_os = "windows"))]
12971 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12972 let worktree_abs_path = self.worktree.abs_path();
12973 let shell_path = self.shell_env().await.get("PATH").cloned();
12974 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
12975 }
12976
12977 #[cfg(target_os = "windows")]
12978 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12979 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
12980 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
12981 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
12982 which::which(command).ok()
12983 }
12984
12985 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
12986 let working_dir = self.worktree_root_path();
12987 let output = util::command::new_smol_command(&command.path)
12988 .args(command.arguments)
12989 .envs(command.env.clone().unwrap_or_default())
12990 .current_dir(working_dir)
12991 .output()
12992 .await?;
12993
12994 anyhow::ensure!(
12995 output.status.success(),
12996 "{}, stdout: {:?}, stderr: {:?}",
12997 output.status,
12998 String::from_utf8_lossy(&output.stdout),
12999 String::from_utf8_lossy(&output.stderr)
13000 );
13001 Ok(())
13002 }
13003
13004 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13005 self.language_registry
13006 .update_lsp_binary_status(server_name, status);
13007 }
13008
13009 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13010 self.language_registry
13011 .all_lsp_adapters()
13012 .into_iter()
13013 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13014 .collect()
13015 }
13016
13017 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13018 let dir = self.language_registry.language_server_download_dir(name)?;
13019
13020 if !dir.exists() {
13021 smol::fs::create_dir_all(&dir)
13022 .await
13023 .context("failed to create container directory")
13024 .log_err()?;
13025 }
13026
13027 Some(dir)
13028 }
13029
13030 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
13031 let entry = self
13032 .worktree
13033 .entry_for_path(&path)
13034 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13035 let abs_path = self
13036 .worktree
13037 .absolutize(&entry.path)
13038 .with_context(|| format!("cannot absolutize path {path:?}"))?;
13039
13040 self.fs.load(&abs_path).await
13041 }
13042}
13043
13044async fn populate_labels_for_symbols(
13045 symbols: Vec<CoreSymbol>,
13046 language_registry: &Arc<LanguageRegistry>,
13047 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13048 output: &mut Vec<Symbol>,
13049) {
13050 #[allow(clippy::mutable_key_type)]
13051 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13052
13053 let mut unknown_paths = BTreeSet::new();
13054 for symbol in symbols {
13055 let language = language_registry
13056 .language_for_file_path(&symbol.path.path)
13057 .await
13058 .ok()
13059 .or_else(|| {
13060 unknown_paths.insert(symbol.path.path.clone());
13061 None
13062 });
13063 symbols_by_language
13064 .entry(language)
13065 .or_default()
13066 .push(symbol);
13067 }
13068
13069 for unknown_path in unknown_paths {
13070 log::info!(
13071 "no language found for symbol path {}",
13072 unknown_path.display()
13073 );
13074 }
13075
13076 let mut label_params = Vec::new();
13077 for (language, mut symbols) in symbols_by_language {
13078 label_params.clear();
13079 label_params.extend(
13080 symbols
13081 .iter_mut()
13082 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13083 );
13084
13085 let mut labels = Vec::new();
13086 if let Some(language) = language {
13087 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13088 language_registry
13089 .lsp_adapters(&language.name())
13090 .first()
13091 .cloned()
13092 });
13093 if let Some(lsp_adapter) = lsp_adapter {
13094 labels = lsp_adapter
13095 .labels_for_symbols(&label_params, &language)
13096 .await
13097 .log_err()
13098 .unwrap_or_default();
13099 }
13100 }
13101
13102 for ((symbol, (name, _)), label) in symbols
13103 .into_iter()
13104 .zip(label_params.drain(..))
13105 .zip(labels.into_iter().chain(iter::repeat(None)))
13106 {
13107 output.push(Symbol {
13108 language_server_name: symbol.language_server_name,
13109 source_worktree_id: symbol.source_worktree_id,
13110 source_language_server_id: symbol.source_language_server_id,
13111 path: symbol.path,
13112 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13113 name,
13114 kind: symbol.kind,
13115 range: symbol.range,
13116 signature: symbol.signature,
13117 });
13118 }
13119 }
13120}
13121
13122fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13123 match server.capabilities().text_document_sync.as_ref()? {
13124 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13125 // Server wants didSave but didn't specify includeText.
13126 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13127 // Server doesn't want didSave at all.
13128 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13129 // Server provided SaveOptions.
13130 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13131 Some(save_options.include_text.unwrap_or(false))
13132 }
13133 },
13134 // We do not have any save info. Kind affects didChange only.
13135 lsp::TextDocumentSyncCapability::Kind(_) => None,
13136 }
13137}
13138
13139/// Completion items are displayed in a `UniformList`.
13140/// Usually, those items are single-line strings, but in LSP responses,
13141/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13142/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13143/// 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,
13144/// breaking the completions menu presentation.
13145///
13146/// 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.
13147fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13148 let mut new_text = String::with_capacity(label.text.len());
13149 let mut offset_map = vec![0; label.text.len() + 1];
13150 let mut last_char_was_space = false;
13151 let mut new_idx = 0;
13152 let chars = label.text.char_indices().fuse();
13153 let mut newlines_removed = false;
13154
13155 for (idx, c) in chars {
13156 offset_map[idx] = new_idx;
13157
13158 match c {
13159 '\n' if last_char_was_space => {
13160 newlines_removed = true;
13161 }
13162 '\t' | ' ' if last_char_was_space => {}
13163 '\n' if !last_char_was_space => {
13164 new_text.push(' ');
13165 new_idx += 1;
13166 last_char_was_space = true;
13167 newlines_removed = true;
13168 }
13169 ' ' | '\t' => {
13170 new_text.push(' ');
13171 new_idx += 1;
13172 last_char_was_space = true;
13173 }
13174 _ => {
13175 new_text.push(c);
13176 new_idx += c.len_utf8();
13177 last_char_was_space = false;
13178 }
13179 }
13180 }
13181 offset_map[label.text.len()] = new_idx;
13182
13183 // Only modify the label if newlines were removed.
13184 if !newlines_removed {
13185 return;
13186 }
13187
13188 let last_index = new_idx;
13189 let mut run_ranges_errors = Vec::new();
13190 label.runs.retain_mut(|(range, _)| {
13191 match offset_map.get(range.start) {
13192 Some(&start) => range.start = start,
13193 None => {
13194 run_ranges_errors.push(range.clone());
13195 return false;
13196 }
13197 }
13198
13199 match offset_map.get(range.end) {
13200 Some(&end) => range.end = end,
13201 None => {
13202 run_ranges_errors.push(range.clone());
13203 range.end = last_index;
13204 }
13205 }
13206 true
13207 });
13208 if !run_ranges_errors.is_empty() {
13209 log::error!(
13210 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13211 label.text
13212 );
13213 }
13214
13215 let mut wrong_filter_range = None;
13216 if label.filter_range == (0..label.text.len()) {
13217 label.filter_range = 0..new_text.len();
13218 } else {
13219 let mut original_filter_range = Some(label.filter_range.clone());
13220 match offset_map.get(label.filter_range.start) {
13221 Some(&start) => label.filter_range.start = start,
13222 None => {
13223 wrong_filter_range = original_filter_range.take();
13224 label.filter_range.start = last_index;
13225 }
13226 }
13227
13228 match offset_map.get(label.filter_range.end) {
13229 Some(&end) => label.filter_range.end = end,
13230 None => {
13231 wrong_filter_range = original_filter_range.take();
13232 label.filter_range.end = last_index;
13233 }
13234 }
13235 }
13236 if let Some(wrong_filter_range) = wrong_filter_range {
13237 log::error!(
13238 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13239 label.text
13240 );
13241 }
13242
13243 label.text = new_text;
13244}
13245
13246#[cfg(test)]
13247mod tests {
13248 use language::HighlightId;
13249
13250 use super::*;
13251
13252 #[test]
13253 fn test_glob_literal_prefix() {
13254 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13255 assert_eq!(
13256 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13257 Path::new("node_modules")
13258 );
13259 assert_eq!(
13260 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13261 Path::new("foo")
13262 );
13263 assert_eq!(
13264 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13265 Path::new("foo/bar/baz.js")
13266 );
13267
13268 #[cfg(target_os = "windows")]
13269 {
13270 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13271 assert_eq!(
13272 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13273 Path::new("node_modules")
13274 );
13275 assert_eq!(
13276 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13277 Path::new("foo")
13278 );
13279 assert_eq!(
13280 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13281 Path::new("foo/bar/baz.js")
13282 );
13283 }
13284 }
13285
13286 #[test]
13287 fn test_multi_len_chars_normalization() {
13288 let mut label = CodeLabel {
13289 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13290 runs: vec![(0..6, HighlightId(1))],
13291 filter_range: 0..6,
13292 };
13293 ensure_uniform_list_compatible_label(&mut label);
13294 assert_eq!(
13295 label,
13296 CodeLabel {
13297 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13298 runs: vec![(0..6, HighlightId(1))],
13299 filter_range: 0..6,
13300 }
13301 );
13302 }
13303}