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