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