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