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