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