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