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