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