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