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