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