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