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