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