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