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