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