1use crate::{
2 buffer_store::{BufferStore, BufferStoreEvent},
3 deserialize_code_actions,
4 environment::ProjectEnvironment,
5 lsp_command::{self, *},
6 lsp_ext_command,
7 prettier_store::{self, PrettierStore, PrettierStoreEvent},
8 project_settings::{LspSettings, ProjectSettings},
9 project_tree::{AdapterQuery, LanguageServerTree, LaunchDisposition, ProjectTree},
10 relativize_path, resolve_path,
11 toolchain_store::{EmptyToolchainStore, ToolchainStoreEvent},
12 worktree_store::{WorktreeStore, WorktreeStoreEvent},
13 yarn::YarnPathStore,
14 CodeAction, Completion, CoreCompletion, Hover, InlayHint, ProjectItem as _, ProjectPath,
15 ProjectTransaction, ResolveState, Symbol, ToolchainStore,
16};
17use anyhow::{anyhow, Context as _, Result};
18use async_trait::async_trait;
19use client::{proto, TypedEnvelope};
20use collections::{btree_map, BTreeMap, BTreeSet, HashMap, HashSet};
21use futures::{
22 future::{join_all, Shared},
23 select,
24 stream::FuturesUnordered,
25 AsyncWriteExt, Future, FutureExt, StreamExt,
26};
27use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
28use gpui::{
29 App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
30 WeakEntity,
31};
32use http_client::HttpClient;
33use itertools::Itertools as _;
34use language::{
35 language_settings::{
36 language_settings, FormatOnSave, Formatter, LanguageSettings, SelectedFormatter,
37 },
38 point_to_lsp,
39 proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
40 range_from_lsp, range_to_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel,
41 Diagnostic, DiagnosticEntry, DiagnosticSet, Diff, File as _, Language, LanguageRegistry,
42 LanguageServerBinaryStatus, LanguageToolchainStore, LocalFile, LspAdapter, LspAdapterDelegate,
43 Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,
44};
45use lsp::{
46 notification::DidRenameFiles, CodeActionKind, CompletionContext, DiagnosticSeverity,
47 DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter,
48 FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
49 InsertTextFormat, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions,
50 LanguageServerId, LanguageServerName, LspRequestFuture, MessageActionItem, MessageType, OneOf,
51 RenameFilesParams, ServerHealthStatus, ServerStatus, SymbolKind, TextEdit, WillRenameFiles,
52 WorkDoneProgressCancelParams, WorkspaceFolder,
53};
54use node_runtime::read_package_installed_version;
55use parking_lot::Mutex;
56use postage::watch;
57use rand::prelude::*;
58
59use rpc::{
60 proto::{FromProto, ToProto},
61 AnyProtoClient,
62};
63use serde::Serialize;
64use settings::{Settings, SettingsLocation, SettingsStore};
65use sha2::{Digest, Sha256};
66use smol::channel::Sender;
67use snippet::Snippet;
68use std::{
69 any::Any,
70 cell::RefCell,
71 cmp::Ordering,
72 convert::TryInto,
73 ffi::OsStr,
74 iter, mem,
75 ops::{ControlFlow, Range},
76 path::{self, Path, PathBuf},
77 rc::Rc,
78 str,
79 sync::Arc,
80 time::{Duration, Instant},
81};
82use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, TransactionId};
83use url::Url;
84use util::{
85 debug_panic, defer, maybe, merge_json_value_into, paths::SanitizedPath, post_inc, ResultExt,
86 TryFutureExt as _,
87};
88
89pub use fs::*;
90pub use language::Location;
91#[cfg(any(test, feature = "test-support"))]
92pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
93pub use worktree::{
94 Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, UpdatedEntriesSet,
95 UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings, FS_WATCH_LATENCY,
96};
97
98const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
99pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub enum FormatTrigger {
103 Save,
104 Manual,
105}
106
107pub enum LspFormatTarget {
108 Buffers,
109 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
110}
111
112pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
113
114// Currently, formatting operations are represented differently depending on
115// whether they come from a language server or an external command.
116#[derive(Debug)]
117pub enum FormatOperation {
118 Lsp(Vec<(Range<Anchor>, Arc<str>)>),
119 External(Diff),
120 Prettier(Diff),
121}
122
123impl FormatTrigger {
124 fn from_proto(value: i32) -> FormatTrigger {
125 match value {
126 0 => FormatTrigger::Save,
127 1 => FormatTrigger::Manual,
128 _ => FormatTrigger::Save,
129 }
130 }
131}
132
133pub struct LocalLspStore {
134 weak: WeakEntity<LspStore>,
135 worktree_store: Entity<WorktreeStore>,
136 toolchain_store: Entity<ToolchainStore>,
137 http_client: Arc<dyn HttpClient>,
138 environment: Entity<ProjectEnvironment>,
139 fs: Arc<dyn Fs>,
140 languages: Arc<LanguageRegistry>,
141 language_server_ids: HashMap<(WorktreeId, LanguageServerName), BTreeSet<LanguageServerId>>,
142 yarn: Entity<YarnPathStore>,
143 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
144 buffers_being_formatted: HashSet<BufferId>,
145 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
146 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
147 language_server_paths_watched_for_rename:
148 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
149 language_server_watcher_registrations:
150 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
151 supplementary_language_servers:
152 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
153 prettier_store: Entity<PrettierStore>,
154 next_diagnostic_group_id: usize,
155 diagnostics: HashMap<
156 WorktreeId,
157 HashMap<
158 Arc<Path>,
159 Vec<(
160 LanguageServerId,
161 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
162 )>,
163 >,
164 >,
165 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
166 _subscription: gpui::Subscription,
167 lsp_tree: Entity<LanguageServerTree>,
168 registered_buffers: HashMap<BufferId, usize>,
169}
170
171impl LocalLspStore {
172 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
173 pub fn running_language_server_for_id(
174 &self,
175 id: LanguageServerId,
176 ) -> Option<&Arc<LanguageServer>> {
177 let language_server_state = self.language_servers.get(&id)?;
178
179 match language_server_state {
180 LanguageServerState::Running { server, .. } => Some(server),
181 LanguageServerState::Starting { .. } => None,
182 }
183 }
184
185 fn start_language_server(
186 &mut self,
187 worktree_handle: &Entity<Worktree>,
188 delegate: Arc<LocalLspAdapterDelegate>,
189 adapter: Arc<CachedLspAdapter>,
190 settings: Arc<LspSettings>,
191 cx: &mut App,
192 ) -> LanguageServerId {
193 let worktree = worktree_handle.read(cx);
194 let worktree_id = worktree.id();
195 let root_path = worktree.abs_path();
196 let key = (worktree_id, adapter.name.clone());
197
198 let override_options = settings.initialization_options.clone();
199
200 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
201
202 let server_id = self.languages.next_language_server_id();
203 log::info!(
204 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
205 adapter.name.0
206 );
207
208 let binary = self.get_language_server_binary(adapter.clone(), delegate.clone(), true, cx);
209
210 let pending_server = cx.spawn({
211 let adapter = adapter.clone();
212 let server_name = adapter.name.clone();
213 let stderr_capture = stderr_capture.clone();
214 #[cfg(any(test, feature = "test-support"))]
215 let lsp_store = self.weak.clone();
216
217 move |cx| async move {
218 let binary = binary.await?;
219 #[cfg(any(test, feature = "test-support"))]
220 if let Some(server) = lsp_store
221 .update(&mut cx.clone(), |this, cx| {
222 this.languages.create_fake_language_server(
223 server_id,
224 &server_name,
225 binary.clone(),
226 cx.to_async(),
227 )
228 })
229 .ok()
230 .flatten()
231 {
232 return Ok(server);
233 }
234
235 lsp::LanguageServer::new(
236 stderr_capture,
237 server_id,
238 server_name,
239 binary,
240 &root_path,
241 adapter.code_action_kinds(),
242 cx,
243 )
244 }
245 });
246
247 let pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
248 let startup = {
249 let server_name = adapter.name.0.clone();
250 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
251 let key = key.clone();
252 let adapter = adapter.clone();
253 let this = self.weak.clone();
254 let pending_workspace_folders = pending_workspace_folders.clone();
255 let fs = self.fs.clone();
256 cx.spawn(move |mut cx| async move {
257 let result = {
258 let delegate = delegate.clone();
259 let adapter = adapter.clone();
260 let this = this.clone();
261 let toolchains = this
262 .update(&mut cx, |this, cx| this.toolchain_store(cx))
263 .ok()?;
264 let mut cx = cx.clone();
265 async move {
266 let language_server = pending_server.await?;
267
268 let workspace_config = adapter
269 .adapter
270 .clone()
271 .workspace_configuration(
272 fs.as_ref(),
273 &delegate,
274 toolchains.clone(),
275 &mut cx,
276 )
277 .await?;
278
279 let mut initialization_options = adapter
280 .adapter
281 .clone()
282 .initialization_options(fs.as_ref(), &(delegate))
283 .await?;
284
285 match (&mut initialization_options, override_options) {
286 (Some(initialization_options), Some(override_options)) => {
287 merge_json_value_into(override_options, initialization_options);
288 }
289 (None, override_options) => initialization_options = override_options,
290 _ => {}
291 }
292
293 let initialization_params = cx.update(|cx| {
294 let mut params = language_server.default_initialize_params(cx);
295 params.initialization_options = initialization_options;
296 adapter.adapter.prepare_initialize_params(params)
297 })??;
298
299 Self::setup_lsp_messages(
300 this.clone(),
301 fs,
302 &language_server,
303 delegate,
304 adapter,
305 );
306
307 let did_change_configuration_params =
308 Arc::new(lsp::DidChangeConfigurationParams {
309 settings: workspace_config,
310 });
311 let language_server = cx
312 .update(|cx| {
313 language_server.initialize(
314 initialization_params,
315 did_change_configuration_params.clone(),
316 cx,
317 )
318 })?
319 .await
320 .inspect_err(|_| {
321 if let Some(this) = this.upgrade() {
322 this.update(&mut cx, |_, cx| {
323 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
324 })
325 .ok();
326 }
327 })?;
328
329 language_server
330 .notify::<lsp::notification::DidChangeConfiguration>(
331 &did_change_configuration_params,
332 )
333 .ok();
334
335 anyhow::Ok(language_server)
336 }
337 }
338 .await;
339
340 match result {
341 Ok(server) => {
342 this.update(&mut cx, |this, mut cx| {
343 this.insert_newly_running_language_server(
344 adapter,
345 server.clone(),
346 server_id,
347 key,
348 pending_workspace_folders,
349 &mut cx,
350 );
351 })
352 .ok();
353 stderr_capture.lock().take();
354 Some(server)
355 }
356
357 Err(err) => {
358 let log = stderr_capture.lock().take().unwrap_or_default();
359 delegate.update_status(
360 adapter.name(),
361 LanguageServerBinaryStatus::Failed {
362 error: format!("{err}\n-- stderr--\n{}", log),
363 },
364 );
365 log::error!("Failed to start language server {server_name:?}: {err}");
366 log::error!("server stderr: {:?}", log);
367 None
368 }
369 }
370 })
371 };
372 let state = LanguageServerState::Starting {
373 startup,
374 pending_workspace_folders,
375 };
376
377 self.language_servers.insert(server_id, state);
378 self.language_server_ids
379 .entry(key)
380 .or_default()
381 .insert(server_id);
382 server_id
383 }
384
385 fn get_language_server_binary(
386 &self,
387 adapter: Arc<CachedLspAdapter>,
388 delegate: Arc<dyn LspAdapterDelegate>,
389 allow_binary_download: bool,
390 cx: &mut App,
391 ) -> Task<Result<LanguageServerBinary>> {
392 let settings = ProjectSettings::get(
393 Some(SettingsLocation {
394 worktree_id: delegate.worktree_id(),
395 path: Path::new(""),
396 }),
397 cx,
398 )
399 .lsp
400 .get(&adapter.name)
401 .and_then(|s| s.binary.clone());
402
403 if settings.as_ref().is_some_and(|b| b.path.is_some()) {
404 let settings = settings.unwrap();
405 return cx.spawn(|_| async move {
406 Ok(LanguageServerBinary {
407 path: PathBuf::from(&settings.path.unwrap()),
408 env: Some(delegate.shell_env().await),
409 arguments: settings
410 .arguments
411 .unwrap_or_default()
412 .iter()
413 .map(Into::into)
414 .collect(),
415 })
416 });
417 }
418 let lsp_binary_options = LanguageServerBinaryOptions {
419 allow_path_lookup: !settings
420 .as_ref()
421 .and_then(|b| b.ignore_system_version)
422 .unwrap_or_default(),
423 allow_binary_download,
424 };
425 let toolchains = self.toolchain_store.read(cx).as_language_toolchain_store();
426 cx.spawn(|mut cx| async move {
427 let binary_result = adapter
428 .clone()
429 .get_language_server_command(
430 delegate.clone(),
431 toolchains,
432 lsp_binary_options,
433 &mut cx,
434 )
435 .await;
436
437 delegate.update_status(adapter.name.clone(), LanguageServerBinaryStatus::None);
438
439 let mut binary = binary_result?;
440 if let Some(arguments) = settings.and_then(|b| b.arguments) {
441 binary.arguments = arguments.into_iter().map(Into::into).collect();
442 }
443
444 let mut shell_env = delegate.shell_env().await;
445 shell_env.extend(binary.env.unwrap_or_default());
446 binary.env = Some(shell_env);
447 Ok(binary)
448 })
449 }
450
451 fn setup_lsp_messages(
452 this: WeakEntity<LspStore>,
453 fs: Arc<dyn Fs>,
454 language_server: &LanguageServer,
455 delegate: Arc<dyn LspAdapterDelegate>,
456 adapter: Arc<CachedLspAdapter>,
457 ) {
458 let name = language_server.name();
459 let server_id = language_server.server_id();
460 language_server
461 .on_notification::<lsp::notification::PublishDiagnostics, _>({
462 let adapter = adapter.clone();
463 let this = this.clone();
464 move |mut params, mut cx| {
465 let adapter = adapter.clone();
466 if let Some(this) = this.upgrade() {
467 adapter.process_diagnostics(&mut params);
468 this.update(&mut cx, |this, cx| {
469 this.update_diagnostics(
470 server_id,
471 params,
472 &adapter.disk_based_diagnostic_sources,
473 cx,
474 )
475 .log_err();
476 })
477 .ok();
478 }
479 }
480 })
481 .detach();
482 language_server
483 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
484 let adapter = adapter.adapter.clone();
485 let delegate = delegate.clone();
486 let this = this.clone();
487 let fs = fs.clone();
488 move |params, mut cx| {
489 let adapter = adapter.clone();
490 let delegate = delegate.clone();
491 let this = this.clone();
492 let fs = fs.clone();
493 async move {
494 let toolchains =
495 this.update(&mut cx, |this, cx| this.toolchain_store(cx))?;
496 let workspace_config = adapter
497 .workspace_configuration(fs.as_ref(), &delegate, toolchains, &mut cx)
498 .await?;
499 Ok(params
500 .items
501 .into_iter()
502 .map(|item| {
503 if let Some(section) = &item.section {
504 workspace_config
505 .get(section)
506 .cloned()
507 .unwrap_or(serde_json::Value::Null)
508 } else {
509 workspace_config.clone()
510 }
511 })
512 .collect())
513 }
514 }
515 })
516 .detach();
517
518 language_server
519 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
520 let this = this.clone();
521 move |_, mut cx| {
522 let this = this.clone();
523 async move {
524 let Some(server) =
525 this.update(&mut cx, |this, _| this.language_server_for_id(server_id))?
526 else {
527 return Ok(None);
528 };
529 let root = server.workspace_folders();
530 Ok(Some(
531 root.iter()
532 .cloned()
533 .map(|uri| WorkspaceFolder {
534 uri,
535 name: Default::default(),
536 })
537 .collect(),
538 ))
539 }
540 }
541 })
542 .detach();
543 // Even though we don't have handling for these requests, respond to them to
544 // avoid stalling any language server like `gopls` which waits for a response
545 // to these requests when initializing.
546 language_server
547 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
548 let this = this.clone();
549 move |params, mut cx| {
550 let this = this.clone();
551 async move {
552 this.update(&mut cx, |this, _| {
553 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
554 {
555 if let lsp::NumberOrString::String(token) = params.token {
556 status.progress_tokens.insert(token);
557 }
558 }
559 })?;
560
561 Ok(())
562 }
563 }
564 })
565 .detach();
566
567 language_server
568 .on_request::<lsp::request::RegisterCapability, _, _>({
569 let this = this.clone();
570 move |params, mut cx| {
571 let this = this.clone();
572 async move {
573 for reg in params.registrations {
574 match reg.method.as_str() {
575 "workspace/didChangeWatchedFiles" => {
576 if let Some(options) = reg.register_options {
577 let options = serde_json::from_value(options)?;
578 this.update(&mut cx, |this, cx| {
579 this.as_local_mut()?.on_lsp_did_change_watched_files(
580 server_id, ®.id, options, cx,
581 );
582 Some(())
583 })?;
584 }
585 }
586 "textDocument/rangeFormatting" => {
587 this.update(&mut cx, |this, _| {
588 if let Some(server) = this.language_server_for_id(server_id)
589 {
590 let options = reg
591 .register_options
592 .map(|options| {
593 serde_json::from_value::<
594 lsp::DocumentRangeFormattingOptions,
595 >(
596 options
597 )
598 })
599 .transpose()?;
600 let provider = match options {
601 None => OneOf::Left(true),
602 Some(options) => OneOf::Right(options),
603 };
604 server.update_capabilities(|capabilities| {
605 capabilities.document_range_formatting_provider =
606 Some(provider);
607 })
608 }
609 anyhow::Ok(())
610 })??;
611 }
612 "textDocument/onTypeFormatting" => {
613 this.update(&mut cx, |this, _| {
614 if let Some(server) = this.language_server_for_id(server_id)
615 {
616 let options = reg
617 .register_options
618 .map(|options| {
619 serde_json::from_value::<
620 lsp::DocumentOnTypeFormattingOptions,
621 >(
622 options
623 )
624 })
625 .transpose()?;
626 if let Some(options) = options {
627 server.update_capabilities(|capabilities| {
628 capabilities
629 .document_on_type_formatting_provider =
630 Some(options);
631 })
632 }
633 }
634 anyhow::Ok(())
635 })??;
636 }
637 "textDocument/formatting" => {
638 this.update(&mut cx, |this, _| {
639 if let Some(server) = this.language_server_for_id(server_id)
640 {
641 let options = reg
642 .register_options
643 .map(|options| {
644 serde_json::from_value::<
645 lsp::DocumentFormattingOptions,
646 >(
647 options
648 )
649 })
650 .transpose()?;
651 let provider = match options {
652 None => OneOf::Left(true),
653 Some(options) => OneOf::Right(options),
654 };
655 server.update_capabilities(|capabilities| {
656 capabilities.document_formatting_provider =
657 Some(provider);
658 })
659 }
660 anyhow::Ok(())
661 })??;
662 }
663 "workspace/didChangeConfiguration" => {
664 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
665 }
666 "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 local.language_servers.insert(
7555 server_id,
7556 LanguageServerState::running(
7557 workspace_folders.lock().clone(),
7558 adapter.clone(),
7559 language_server.clone(),
7560 None,
7561 ),
7562 );
7563 if let Some(file_ops_caps) = language_server
7564 .capabilities()
7565 .workspace
7566 .as_ref()
7567 .and_then(|ws| ws.file_operations.as_ref())
7568 {
7569 let did_rename_caps = file_ops_caps.did_rename.as_ref();
7570 let will_rename_caps = file_ops_caps.will_rename.as_ref();
7571 if did_rename_caps.or(will_rename_caps).is_some() {
7572 let watcher = RenamePathsWatchedForServer::default()
7573 .with_did_rename_patterns(did_rename_caps)
7574 .with_will_rename_patterns(will_rename_caps);
7575 local
7576 .language_server_paths_watched_for_rename
7577 .insert(server_id, watcher);
7578 }
7579 }
7580
7581 self.language_server_statuses.insert(
7582 server_id,
7583 LanguageServerStatus {
7584 name: language_server.name().to_string(),
7585 pending_work: Default::default(),
7586 has_pending_diagnostic_updates: false,
7587 progress_tokens: Default::default(),
7588 },
7589 );
7590
7591 cx.emit(LspStoreEvent::LanguageServerAdded(
7592 server_id,
7593 language_server.name(),
7594 Some(key.0),
7595 ));
7596 cx.emit(LspStoreEvent::RefreshInlayHints);
7597
7598 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
7599 downstream_client
7600 .send(proto::StartLanguageServer {
7601 project_id: *project_id,
7602 server: Some(proto::LanguageServer {
7603 id: server_id.0 as u64,
7604 name: language_server.name().to_string(),
7605 worktree_id: Some(key.0.to_proto()),
7606 }),
7607 })
7608 .log_err();
7609 }
7610
7611 // Tell the language server about every open buffer in the worktree that matches the language.
7612 self.buffer_store.clone().update(cx, |buffer_store, cx| {
7613 for buffer_handle in buffer_store.buffers() {
7614 let buffer = buffer_handle.read(cx);
7615 let file = match File::from_dyn(buffer.file()) {
7616 Some(file) => file,
7617 None => continue,
7618 };
7619 let language = match buffer.language() {
7620 Some(language) => language,
7621 None => continue,
7622 };
7623
7624 if file.worktree.read(cx).id() != key.0
7625 || !self
7626 .languages
7627 .lsp_adapters(&language.name())
7628 .iter()
7629 .any(|a| a.name == key.1)
7630 {
7631 continue;
7632 }
7633 // didOpen
7634 let file = match file.as_local() {
7635 Some(file) => file,
7636 None => continue,
7637 };
7638
7639 let local = self.as_local_mut().unwrap();
7640
7641 if local.registered_buffers.contains_key(&buffer.remote_id()) {
7642 let versions = local
7643 .buffer_snapshots
7644 .entry(buffer.remote_id())
7645 .or_default()
7646 .entry(server_id)
7647 .and_modify(|_| {
7648 assert!(
7649 false,
7650 "There should not be an existing snapshot for a newly inserted buffer"
7651 )
7652 })
7653 .or_insert_with(|| {
7654 vec![LspBufferSnapshot {
7655 version: 0,
7656 snapshot: buffer.text_snapshot(),
7657 }]
7658 });
7659
7660 let snapshot = versions.last().unwrap();
7661 let version = snapshot.version;
7662 let initial_snapshot = &snapshot.snapshot;
7663 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
7664 language_server.register_buffer(
7665 uri,
7666 adapter.language_id(&language.name()),
7667 version,
7668 initial_snapshot.text(),
7669 );
7670 }
7671 buffer_handle.update(cx, |buffer, cx| {
7672 buffer.set_completion_triggers(
7673 server_id,
7674 language_server
7675 .capabilities()
7676 .completion_provider
7677 .as_ref()
7678 .and_then(|provider| {
7679 provider
7680 .trigger_characters
7681 .as_ref()
7682 .map(|characters| characters.iter().cloned().collect())
7683 })
7684 .unwrap_or_default(),
7685 cx,
7686 )
7687 });
7688 }
7689 });
7690
7691 cx.notify();
7692 }
7693
7694 pub fn language_servers_running_disk_based_diagnostics(
7695 &self,
7696 ) -> impl Iterator<Item = LanguageServerId> + '_ {
7697 self.language_server_statuses
7698 .iter()
7699 .filter_map(|(id, status)| {
7700 if status.has_pending_diagnostic_updates {
7701 Some(*id)
7702 } else {
7703 None
7704 }
7705 })
7706 }
7707
7708 pub(crate) fn cancel_language_server_work_for_buffers(
7709 &mut self,
7710 buffers: impl IntoIterator<Item = Entity<Buffer>>,
7711 cx: &mut Context<Self>,
7712 ) {
7713 if let Some((client, project_id)) = self.upstream_client() {
7714 let request = client.request(proto::CancelLanguageServerWork {
7715 project_id,
7716 work: Some(proto::cancel_language_server_work::Work::Buffers(
7717 proto::cancel_language_server_work::Buffers {
7718 buffer_ids: buffers
7719 .into_iter()
7720 .map(|b| b.read(cx).remote_id().to_proto())
7721 .collect(),
7722 },
7723 )),
7724 });
7725 cx.background_spawn(request).detach_and_log_err(cx);
7726 } else if let Some(local) = self.as_local() {
7727 let servers = buffers
7728 .into_iter()
7729 .flat_map(|buffer| {
7730 buffer.update(cx, |buffer, cx| {
7731 local.language_server_ids_for_buffer(buffer, cx).into_iter()
7732 })
7733 })
7734 .collect::<HashSet<_>>();
7735 for server_id in servers {
7736 self.cancel_language_server_work(server_id, None, cx);
7737 }
7738 }
7739 }
7740
7741 pub(crate) fn cancel_language_server_work(
7742 &mut self,
7743 server_id: LanguageServerId,
7744 token_to_cancel: Option<String>,
7745 cx: &mut Context<Self>,
7746 ) {
7747 if let Some(local) = self.as_local() {
7748 let status = self.language_server_statuses.get(&server_id);
7749 let server = local.language_servers.get(&server_id);
7750 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
7751 {
7752 for (token, progress) in &status.pending_work {
7753 if let Some(token_to_cancel) = token_to_cancel.as_ref() {
7754 if token != token_to_cancel {
7755 continue;
7756 }
7757 }
7758 if progress.is_cancellable {
7759 server
7760 .notify::<lsp::notification::WorkDoneProgressCancel>(
7761 &WorkDoneProgressCancelParams {
7762 token: lsp::NumberOrString::String(token.clone()),
7763 },
7764 )
7765 .ok();
7766 }
7767 }
7768 }
7769 } else if let Some((client, project_id)) = self.upstream_client() {
7770 let request = client.request(proto::CancelLanguageServerWork {
7771 project_id,
7772 work: Some(
7773 proto::cancel_language_server_work::Work::LanguageServerWork(
7774 proto::cancel_language_server_work::LanguageServerWork {
7775 language_server_id: server_id.to_proto(),
7776 token: token_to_cancel,
7777 },
7778 ),
7779 ),
7780 });
7781 cx.background_spawn(request).detach_and_log_err(cx);
7782 }
7783 }
7784
7785 fn register_supplementary_language_server(
7786 &mut self,
7787 id: LanguageServerId,
7788 name: LanguageServerName,
7789 server: Arc<LanguageServer>,
7790 cx: &mut Context<Self>,
7791 ) {
7792 if let Some(local) = self.as_local_mut() {
7793 local
7794 .supplementary_language_servers
7795 .insert(id, (name.clone(), server));
7796 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
7797 }
7798 }
7799
7800 fn unregister_supplementary_language_server(
7801 &mut self,
7802 id: LanguageServerId,
7803 cx: &mut Context<Self>,
7804 ) {
7805 if let Some(local) = self.as_local_mut() {
7806 local.supplementary_language_servers.remove(&id);
7807 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
7808 }
7809 }
7810
7811 pub(crate) fn supplementary_language_servers(
7812 &self,
7813 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
7814 self.as_local().into_iter().flat_map(|local| {
7815 local
7816 .supplementary_language_servers
7817 .iter()
7818 .map(|(id, (name, _))| (*id, name.clone()))
7819 })
7820 }
7821
7822 pub fn language_server_adapter_for_id(
7823 &self,
7824 id: LanguageServerId,
7825 ) -> Option<Arc<CachedLspAdapter>> {
7826 self.as_local()
7827 .and_then(|local| local.language_servers.get(&id))
7828 .and_then(|language_server_state| match language_server_state {
7829 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
7830 _ => None,
7831 })
7832 }
7833
7834 pub(super) fn update_local_worktree_language_servers(
7835 &mut self,
7836 worktree_handle: &Entity<Worktree>,
7837 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
7838 cx: &mut Context<Self>,
7839 ) {
7840 if changes.is_empty() {
7841 return;
7842 }
7843
7844 let Some(local) = self.as_local() else { return };
7845
7846 local.prettier_store.update(cx, |prettier_store, cx| {
7847 prettier_store.update_prettier_settings(&worktree_handle, changes, cx)
7848 });
7849
7850 let worktree_id = worktree_handle.read(cx).id();
7851 let mut language_server_ids = local
7852 .language_server_ids
7853 .iter()
7854 .flat_map(|((server_worktree, _), server_ids)| {
7855 server_ids
7856 .iter()
7857 .filter_map(|server_id| server_worktree.eq(&worktree_id).then(|| *server_id))
7858 })
7859 .collect::<Vec<_>>();
7860 language_server_ids.sort();
7861 language_server_ids.dedup();
7862
7863 let abs_path = worktree_handle.read(cx).abs_path();
7864 for server_id in &language_server_ids {
7865 if let Some(LanguageServerState::Running { server, .. }) =
7866 local.language_servers.get(server_id)
7867 {
7868 if let Some(watched_paths) = local
7869 .language_server_watched_paths
7870 .get(server_id)
7871 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
7872 {
7873 let params = lsp::DidChangeWatchedFilesParams {
7874 changes: changes
7875 .iter()
7876 .filter_map(|(path, _, change)| {
7877 if !watched_paths.is_match(path) {
7878 return None;
7879 }
7880 let typ = match change {
7881 PathChange::Loaded => return None,
7882 PathChange::Added => lsp::FileChangeType::CREATED,
7883 PathChange::Removed => lsp::FileChangeType::DELETED,
7884 PathChange::Updated => lsp::FileChangeType::CHANGED,
7885 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
7886 };
7887 Some(lsp::FileEvent {
7888 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
7889 typ,
7890 })
7891 })
7892 .collect(),
7893 };
7894 if !params.changes.is_empty() {
7895 server
7896 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
7897 .log_err();
7898 }
7899 }
7900 }
7901 }
7902 }
7903
7904 pub fn wait_for_remote_buffer(
7905 &mut self,
7906 id: BufferId,
7907 cx: &mut Context<Self>,
7908 ) -> Task<Result<Entity<Buffer>>> {
7909 self.buffer_store.update(cx, |buffer_store, cx| {
7910 buffer_store.wait_for_remote_buffer(id, cx)
7911 })
7912 }
7913
7914 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
7915 proto::Symbol {
7916 language_server_name: symbol.language_server_name.0.to_string(),
7917 source_worktree_id: symbol.source_worktree_id.to_proto(),
7918 language_server_id: symbol.source_language_server_id.to_proto(),
7919 worktree_id: symbol.path.worktree_id.to_proto(),
7920 path: symbol.path.path.as_ref().to_proto(),
7921 name: symbol.name.clone(),
7922 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
7923 start: Some(proto::PointUtf16 {
7924 row: symbol.range.start.0.row,
7925 column: symbol.range.start.0.column,
7926 }),
7927 end: Some(proto::PointUtf16 {
7928 row: symbol.range.end.0.row,
7929 column: symbol.range.end.0.column,
7930 }),
7931 signature: symbol.signature.to_vec(),
7932 }
7933 }
7934
7935 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
7936 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
7937 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
7938 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
7939 let path = ProjectPath {
7940 worktree_id,
7941 path: Arc::<Path>::from_proto(serialized_symbol.path),
7942 };
7943
7944 let start = serialized_symbol
7945 .start
7946 .ok_or_else(|| anyhow!("invalid start"))?;
7947 let end = serialized_symbol
7948 .end
7949 .ok_or_else(|| anyhow!("invalid end"))?;
7950 Ok(CoreSymbol {
7951 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
7952 source_worktree_id,
7953 source_language_server_id: LanguageServerId::from_proto(
7954 serialized_symbol.language_server_id,
7955 ),
7956 path,
7957 name: serialized_symbol.name,
7958 range: Unclipped(PointUtf16::new(start.row, start.column))
7959 ..Unclipped(PointUtf16::new(end.row, end.column)),
7960 kind,
7961 signature: serialized_symbol
7962 .signature
7963 .try_into()
7964 .map_err(|_| anyhow!("invalid signature"))?,
7965 })
7966 }
7967
7968 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
7969 proto::Completion {
7970 old_start: Some(serialize_anchor(&completion.old_range.start)),
7971 old_end: Some(serialize_anchor(&completion.old_range.end)),
7972 new_text: completion.new_text.clone(),
7973 server_id: completion.server_id.0 as u64,
7974 lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
7975 resolved: completion.resolved,
7976 }
7977 }
7978
7979 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
7980 let old_start = completion
7981 .old_start
7982 .and_then(deserialize_anchor)
7983 .ok_or_else(|| anyhow!("invalid old start"))?;
7984 let old_end = completion
7985 .old_end
7986 .and_then(deserialize_anchor)
7987 .ok_or_else(|| anyhow!("invalid old end"))?;
7988 let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
7989
7990 Ok(CoreCompletion {
7991 old_range: old_start..old_end,
7992 new_text: completion.new_text,
7993 server_id: LanguageServerId(completion.server_id as usize),
7994 lsp_completion,
7995 resolved: completion.resolved,
7996 })
7997 }
7998
7999 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
8000 proto::CodeAction {
8001 server_id: action.server_id.0 as u64,
8002 start: Some(serialize_anchor(&action.range.start)),
8003 end: Some(serialize_anchor(&action.range.end)),
8004 lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
8005 }
8006 }
8007
8008 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
8009 let start = action
8010 .start
8011 .and_then(deserialize_anchor)
8012 .ok_or_else(|| anyhow!("invalid start"))?;
8013 let end = action
8014 .end
8015 .and_then(deserialize_anchor)
8016 .ok_or_else(|| anyhow!("invalid end"))?;
8017 let lsp_action = serde_json::from_slice(&action.lsp_action)?;
8018 Ok(CodeAction {
8019 server_id: LanguageServerId(action.server_id as usize),
8020 range: start..end,
8021 lsp_action,
8022 })
8023 }
8024
8025 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
8026 match &formatting_result {
8027 Ok(_) => self.last_formatting_failure = None,
8028 Err(error) => {
8029 let error_string = format!("{error:#}");
8030 log::error!("Formatting failed: {error_string}");
8031 self.last_formatting_failure
8032 .replace(error_string.lines().join(" "));
8033 }
8034 }
8035 }
8036}
8037
8038impl EventEmitter<LspStoreEvent> for LspStore {}
8039
8040fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
8041 hover
8042 .contents
8043 .retain(|hover_block| !hover_block.text.trim().is_empty());
8044 if hover.contents.is_empty() {
8045 None
8046 } else {
8047 Some(hover)
8048 }
8049}
8050
8051async fn populate_labels_for_completions(
8052 mut new_completions: Vec<CoreCompletion>,
8053 language: Option<Arc<Language>>,
8054 lsp_adapter: Option<Arc<CachedLspAdapter>>,
8055 completions: &mut Vec<Completion>,
8056) {
8057 let lsp_completions = new_completions
8058 .iter_mut()
8059 .map(|completion| mem::take(&mut completion.lsp_completion))
8060 .collect::<Vec<_>>();
8061
8062 let labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
8063 lsp_adapter
8064 .labels_for_completions(&lsp_completions, language)
8065 .await
8066 .log_err()
8067 .unwrap_or_default()
8068 } else {
8069 Vec::new()
8070 };
8071
8072 for ((completion, lsp_completion), label) in new_completions
8073 .into_iter()
8074 .zip(lsp_completions)
8075 .zip(labels.into_iter().chain(iter::repeat(None)))
8076 {
8077 let documentation = if let Some(docs) = lsp_completion.documentation.clone() {
8078 Some(docs.into())
8079 } else {
8080 None
8081 };
8082
8083 let mut label = label.unwrap_or_else(|| {
8084 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
8085 });
8086 ensure_uniform_list_compatible_label(&mut label);
8087
8088 completions.push(Completion {
8089 old_range: completion.old_range,
8090 new_text: completion.new_text,
8091 label,
8092 server_id: completion.server_id,
8093 documentation,
8094 lsp_completion,
8095 confirm: None,
8096 resolved: false,
8097 })
8098 }
8099}
8100
8101#[derive(Debug)]
8102pub enum LanguageServerToQuery {
8103 /// Query language servers in order of users preference, up until one capable of handling the request is found.
8104 FirstCapable,
8105 /// Query a specific language server.
8106 Other(LanguageServerId),
8107}
8108
8109#[derive(Default)]
8110struct RenamePathsWatchedForServer {
8111 did_rename: Vec<RenameActionPredicate>,
8112 will_rename: Vec<RenameActionPredicate>,
8113}
8114
8115impl RenamePathsWatchedForServer {
8116 fn with_did_rename_patterns(
8117 mut self,
8118 did_rename: Option<&FileOperationRegistrationOptions>,
8119 ) -> Self {
8120 if let Some(did_rename) = did_rename {
8121 self.did_rename = did_rename
8122 .filters
8123 .iter()
8124 .filter_map(|filter| filter.try_into().log_err())
8125 .collect();
8126 }
8127 self
8128 }
8129 fn with_will_rename_patterns(
8130 mut self,
8131 will_rename: Option<&FileOperationRegistrationOptions>,
8132 ) -> Self {
8133 if let Some(will_rename) = will_rename {
8134 self.will_rename = will_rename
8135 .filters
8136 .iter()
8137 .filter_map(|filter| filter.try_into().log_err())
8138 .collect();
8139 }
8140 self
8141 }
8142
8143 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
8144 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
8145 }
8146 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
8147 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
8148 }
8149}
8150
8151impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
8152 type Error = globset::Error;
8153 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
8154 Ok(Self {
8155 kind: ops.pattern.matches.clone(),
8156 glob: GlobBuilder::new(&ops.pattern.glob)
8157 .case_insensitive(
8158 ops.pattern
8159 .options
8160 .as_ref()
8161 .map_or(false, |ops| ops.ignore_case.unwrap_or(false)),
8162 )
8163 .build()?
8164 .compile_matcher(),
8165 })
8166 }
8167}
8168struct RenameActionPredicate {
8169 glob: GlobMatcher,
8170 kind: Option<FileOperationPatternKind>,
8171}
8172
8173impl RenameActionPredicate {
8174 // Returns true if language server should be notified
8175 fn eval(&self, path: &str, is_dir: bool) -> bool {
8176 self.kind.as_ref().map_or(true, |kind| {
8177 let expected_kind = if is_dir {
8178 FileOperationPatternKind::Folder
8179 } else {
8180 FileOperationPatternKind::File
8181 };
8182 kind == &expected_kind
8183 }) && self.glob.is_match(path)
8184 }
8185}
8186
8187#[derive(Default)]
8188struct LanguageServerWatchedPaths {
8189 worktree_paths: HashMap<WorktreeId, GlobSet>,
8190 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
8191}
8192
8193#[derive(Default)]
8194struct LanguageServerWatchedPathsBuilder {
8195 worktree_paths: HashMap<WorktreeId, GlobSet>,
8196 abs_paths: HashMap<Arc<Path>, GlobSet>,
8197}
8198
8199impl LanguageServerWatchedPathsBuilder {
8200 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
8201 self.worktree_paths.insert(worktree_id, glob_set);
8202 }
8203 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
8204 self.abs_paths.insert(path, glob_set);
8205 }
8206 fn build(
8207 self,
8208 fs: Arc<dyn Fs>,
8209 language_server_id: LanguageServerId,
8210 cx: &mut Context<LspStore>,
8211 ) -> LanguageServerWatchedPaths {
8212 let project = cx.weak_entity();
8213
8214 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
8215 let abs_paths = self
8216 .abs_paths
8217 .into_iter()
8218 .map(|(abs_path, globset)| {
8219 let task = cx.spawn({
8220 let abs_path = abs_path.clone();
8221 let fs = fs.clone();
8222
8223 let lsp_store = project.clone();
8224 |_, mut cx| async move {
8225 maybe!(async move {
8226 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
8227 while let Some(update) = push_updates.0.next().await {
8228 let action = lsp_store
8229 .update(&mut cx, |this, _| {
8230 let Some(local) = this.as_local() else {
8231 return ControlFlow::Break(());
8232 };
8233 let Some(watcher) = local
8234 .language_server_watched_paths
8235 .get(&language_server_id)
8236 else {
8237 return ControlFlow::Break(());
8238 };
8239 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
8240 "Watched abs path is not registered with a watcher",
8241 );
8242 let matching_entries = update
8243 .into_iter()
8244 .filter(|event| globs.is_match(&event.path))
8245 .collect::<Vec<_>>();
8246 this.lsp_notify_abs_paths_changed(
8247 language_server_id,
8248 matching_entries,
8249 );
8250 ControlFlow::Continue(())
8251 })
8252 .ok()?;
8253
8254 if action.is_break() {
8255 break;
8256 }
8257 }
8258 Some(())
8259 })
8260 .await;
8261 }
8262 });
8263 (abs_path, (globset, task))
8264 })
8265 .collect();
8266 LanguageServerWatchedPaths {
8267 worktree_paths: self.worktree_paths,
8268 abs_paths,
8269 }
8270 }
8271}
8272
8273struct LspBufferSnapshot {
8274 version: i32,
8275 snapshot: TextBufferSnapshot,
8276}
8277
8278/// A prompt requested by LSP server.
8279#[derive(Clone, Debug)]
8280pub struct LanguageServerPromptRequest {
8281 pub level: PromptLevel,
8282 pub message: String,
8283 pub actions: Vec<MessageActionItem>,
8284 pub lsp_name: String,
8285 pub(crate) response_channel: Sender<MessageActionItem>,
8286}
8287
8288impl LanguageServerPromptRequest {
8289 pub async fn respond(self, index: usize) -> Option<()> {
8290 if let Some(response) = self.actions.into_iter().nth(index) {
8291 self.response_channel.send(response).await.ok()
8292 } else {
8293 None
8294 }
8295 }
8296}
8297impl PartialEq for LanguageServerPromptRequest {
8298 fn eq(&self, other: &Self) -> bool {
8299 self.message == other.message && self.actions == other.actions
8300 }
8301}
8302
8303#[derive(Clone, Debug, PartialEq)]
8304pub enum LanguageServerLogType {
8305 Log(MessageType),
8306 Trace(Option<String>),
8307}
8308
8309impl LanguageServerLogType {
8310 pub fn to_proto(&self) -> proto::language_server_log::LogType {
8311 match self {
8312 Self::Log(log_type) => {
8313 let message_type = match *log_type {
8314 MessageType::ERROR => 1,
8315 MessageType::WARNING => 2,
8316 MessageType::INFO => 3,
8317 MessageType::LOG => 4,
8318 other => {
8319 log::warn!("Unknown lsp log message type: {:?}", other);
8320 4
8321 }
8322 };
8323 proto::language_server_log::LogType::LogMessageType(message_type)
8324 }
8325 Self::Trace(message) => {
8326 proto::language_server_log::LogType::LogTrace(proto::LspLogTrace {
8327 message: message.clone(),
8328 })
8329 }
8330 }
8331 }
8332
8333 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
8334 match log_type {
8335 proto::language_server_log::LogType::LogMessageType(message_type) => {
8336 Self::Log(match message_type {
8337 1 => MessageType::ERROR,
8338 2 => MessageType::WARNING,
8339 3 => MessageType::INFO,
8340 4 => MessageType::LOG,
8341 _ => MessageType::LOG,
8342 })
8343 }
8344 proto::language_server_log::LogType::LogTrace(trace) => Self::Trace(trace.message),
8345 }
8346 }
8347}
8348
8349pub enum LanguageServerState {
8350 Starting {
8351 startup: Task<Option<Arc<LanguageServer>>>,
8352 /// List of language servers that will be added to the workspace once it's initialization completes.
8353 pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
8354 },
8355
8356 Running {
8357 adapter: Arc<CachedLspAdapter>,
8358 server: Arc<LanguageServer>,
8359 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
8360 },
8361}
8362
8363impl LanguageServerState {
8364 fn add_workspace_folder(&self, uri: Url) {
8365 match self {
8366 LanguageServerState::Starting {
8367 pending_workspace_folders,
8368 ..
8369 } => {
8370 pending_workspace_folders.lock().insert(uri);
8371 }
8372 LanguageServerState::Running { server, .. } => {
8373 server.add_workspace_folder(uri);
8374 }
8375 }
8376 }
8377 fn _remove_workspace_folder(&self, uri: Url) {
8378 match self {
8379 LanguageServerState::Starting {
8380 pending_workspace_folders,
8381 ..
8382 } => {
8383 pending_workspace_folders.lock().remove(&uri);
8384 }
8385 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
8386 }
8387 }
8388 fn running(
8389 workspace_folders: BTreeSet<Url>,
8390 adapter: Arc<CachedLspAdapter>,
8391 server: Arc<LanguageServer>,
8392 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
8393 ) -> Self {
8394 server.set_workspace_folders(workspace_folders);
8395 Self::Running {
8396 adapter,
8397 server,
8398 simulate_disk_based_diagnostics_completion,
8399 }
8400 }
8401}
8402
8403impl std::fmt::Debug for LanguageServerState {
8404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8405 match self {
8406 LanguageServerState::Starting { .. } => {
8407 f.debug_struct("LanguageServerState::Starting").finish()
8408 }
8409 LanguageServerState::Running { .. } => {
8410 f.debug_struct("LanguageServerState::Running").finish()
8411 }
8412 }
8413 }
8414}
8415
8416#[derive(Clone, Debug, Serialize)]
8417pub struct LanguageServerProgress {
8418 pub is_disk_based_diagnostics_progress: bool,
8419 pub is_cancellable: bool,
8420 pub title: Option<String>,
8421 pub message: Option<String>,
8422 pub percentage: Option<usize>,
8423 #[serde(skip_serializing)]
8424 pub last_update_at: Instant,
8425}
8426
8427#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
8428pub struct DiagnosticSummary {
8429 pub error_count: usize,
8430 pub warning_count: usize,
8431}
8432
8433impl DiagnosticSummary {
8434 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
8435 let mut this = Self {
8436 error_count: 0,
8437 warning_count: 0,
8438 };
8439
8440 for entry in diagnostics {
8441 if entry.diagnostic.is_primary {
8442 match entry.diagnostic.severity {
8443 DiagnosticSeverity::ERROR => this.error_count += 1,
8444 DiagnosticSeverity::WARNING => this.warning_count += 1,
8445 _ => {}
8446 }
8447 }
8448 }
8449
8450 this
8451 }
8452
8453 pub fn is_empty(&self) -> bool {
8454 self.error_count == 0 && self.warning_count == 0
8455 }
8456
8457 pub fn to_proto(
8458 &self,
8459 language_server_id: LanguageServerId,
8460 path: &Path,
8461 ) -> proto::DiagnosticSummary {
8462 proto::DiagnosticSummary {
8463 path: path.to_proto(),
8464 language_server_id: language_server_id.0 as u64,
8465 error_count: self.error_count as u32,
8466 warning_count: self.warning_count as u32,
8467 }
8468 }
8469}
8470
8471#[derive(Clone, Debug)]
8472pub enum CompletionDocumentation {
8473 /// There is no documentation for this completion.
8474 Undocumented,
8475 /// A single line of documentation.
8476 SingleLine(SharedString),
8477 /// Multiple lines of plain text documentation.
8478 MultiLinePlainText(SharedString),
8479 /// Markdown documentation.
8480 MultiLineMarkdown(SharedString),
8481}
8482
8483impl From<lsp::Documentation> for CompletionDocumentation {
8484 fn from(docs: lsp::Documentation) -> Self {
8485 match docs {
8486 lsp::Documentation::String(text) => {
8487 if text.lines().count() <= 1 {
8488 CompletionDocumentation::SingleLine(text.into())
8489 } else {
8490 CompletionDocumentation::MultiLinePlainText(text.into())
8491 }
8492 }
8493
8494 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
8495 lsp::MarkupKind::PlainText => {
8496 if value.lines().count() <= 1 {
8497 CompletionDocumentation::SingleLine(value.into())
8498 } else {
8499 CompletionDocumentation::MultiLinePlainText(value.into())
8500 }
8501 }
8502
8503 lsp::MarkupKind::Markdown => {
8504 CompletionDocumentation::MultiLineMarkdown(value.into())
8505 }
8506 },
8507 }
8508 }
8509}
8510
8511fn glob_literal_prefix(glob: &Path) -> PathBuf {
8512 glob.components()
8513 .take_while(|component| match component {
8514 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
8515 _ => true,
8516 })
8517 .collect()
8518}
8519
8520pub struct SshLspAdapter {
8521 name: LanguageServerName,
8522 binary: LanguageServerBinary,
8523 initialization_options: Option<String>,
8524 code_action_kinds: Option<Vec<CodeActionKind>>,
8525}
8526
8527impl SshLspAdapter {
8528 pub fn new(
8529 name: LanguageServerName,
8530 binary: LanguageServerBinary,
8531 initialization_options: Option<String>,
8532 code_action_kinds: Option<String>,
8533 ) -> Self {
8534 Self {
8535 name,
8536 binary,
8537 initialization_options,
8538 code_action_kinds: code_action_kinds
8539 .as_ref()
8540 .and_then(|c| serde_json::from_str(c).ok()),
8541 }
8542 }
8543}
8544
8545#[async_trait(?Send)]
8546impl LspAdapter for SshLspAdapter {
8547 fn name(&self) -> LanguageServerName {
8548 self.name.clone()
8549 }
8550
8551 async fn initialization_options(
8552 self: Arc<Self>,
8553 _: &dyn Fs,
8554 _: &Arc<dyn LspAdapterDelegate>,
8555 ) -> Result<Option<serde_json::Value>> {
8556 let Some(options) = &self.initialization_options else {
8557 return Ok(None);
8558 };
8559 let result = serde_json::from_str(options)?;
8560 Ok(result)
8561 }
8562
8563 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
8564 self.code_action_kinds.clone()
8565 }
8566
8567 async fn check_if_user_installed(
8568 &self,
8569 _: &dyn LspAdapterDelegate,
8570 _: Arc<dyn LanguageToolchainStore>,
8571 _: &AsyncApp,
8572 ) -> Option<LanguageServerBinary> {
8573 Some(self.binary.clone())
8574 }
8575
8576 async fn cached_server_binary(
8577 &self,
8578 _: PathBuf,
8579 _: &dyn LspAdapterDelegate,
8580 ) -> Option<LanguageServerBinary> {
8581 None
8582 }
8583
8584 async fn fetch_latest_server_version(
8585 &self,
8586 _: &dyn LspAdapterDelegate,
8587 ) -> Result<Box<dyn 'static + Send + Any>> {
8588 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
8589 }
8590
8591 async fn fetch_server_binary(
8592 &self,
8593 _: Box<dyn 'static + Send + Any>,
8594 _: PathBuf,
8595 _: &dyn LspAdapterDelegate,
8596 ) -> Result<LanguageServerBinary> {
8597 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
8598 }
8599}
8600
8601pub fn language_server_settings<'a>(
8602 delegate: &'a dyn LspAdapterDelegate,
8603 language: &LanguageServerName,
8604 cx: &'a App,
8605) -> Option<&'a LspSettings> {
8606 language_server_settings_for(
8607 SettingsLocation {
8608 worktree_id: delegate.worktree_id(),
8609 path: delegate.worktree_root_path(),
8610 },
8611 language,
8612 cx,
8613 )
8614}
8615
8616pub(crate) fn language_server_settings_for<'a>(
8617 location: SettingsLocation<'a>,
8618 language: &LanguageServerName,
8619 cx: &'a App,
8620) -> Option<&'a LspSettings> {
8621 ProjectSettings::get(Some(location), cx).lsp.get(language)
8622}
8623
8624pub struct LocalLspAdapterDelegate {
8625 lsp_store: WeakEntity<LspStore>,
8626 worktree: worktree::Snapshot,
8627 fs: Arc<dyn Fs>,
8628 http_client: Arc<dyn HttpClient>,
8629 language_registry: Arc<LanguageRegistry>,
8630 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
8631}
8632
8633impl LocalLspAdapterDelegate {
8634 pub fn new(
8635 language_registry: Arc<LanguageRegistry>,
8636 environment: &Entity<ProjectEnvironment>,
8637 lsp_store: WeakEntity<LspStore>,
8638 worktree: &Entity<Worktree>,
8639 http_client: Arc<dyn HttpClient>,
8640 fs: Arc<dyn Fs>,
8641 cx: &mut App,
8642 ) -> Arc<Self> {
8643 let (worktree_id, worktree_abs_path) = {
8644 let worktree = worktree.read(cx);
8645 (worktree.id(), worktree.abs_path())
8646 };
8647
8648 let load_shell_env_task = environment.update(cx, |env, cx| {
8649 env.get_environment(Some(worktree_id), Some(worktree_abs_path), cx)
8650 });
8651
8652 Arc::new(Self {
8653 lsp_store,
8654 worktree: worktree.read(cx).snapshot(),
8655 fs,
8656 http_client,
8657 language_registry,
8658 load_shell_env_task,
8659 })
8660 }
8661
8662 fn from_local_lsp(
8663 local: &LocalLspStore,
8664 worktree: &Entity<Worktree>,
8665 cx: &mut App,
8666 ) -> Arc<Self> {
8667 Self::new(
8668 local.languages.clone(),
8669 &local.environment,
8670 local.weak.clone(),
8671 worktree,
8672 local.http_client.clone(),
8673 local.fs.clone(),
8674 cx,
8675 )
8676 }
8677}
8678
8679#[async_trait]
8680impl LspAdapterDelegate for LocalLspAdapterDelegate {
8681 fn show_notification(&self, message: &str, cx: &mut App) {
8682 self.lsp_store
8683 .update(cx, |_, cx| {
8684 cx.emit(LspStoreEvent::Notification(message.to_owned()))
8685 })
8686 .ok();
8687 }
8688
8689 fn http_client(&self) -> Arc<dyn HttpClient> {
8690 self.http_client.clone()
8691 }
8692
8693 fn worktree_id(&self) -> WorktreeId {
8694 self.worktree.id()
8695 }
8696
8697 fn exists(&self, path: &Path, is_dir: Option<bool>) -> bool {
8698 self.worktree.entry_for_path(path).map_or(false, |entry| {
8699 is_dir.map_or(true, |is_required_to_be_dir| {
8700 is_required_to_be_dir == entry.is_dir()
8701 })
8702 })
8703 }
8704
8705 fn worktree_root_path(&self) -> &Path {
8706 self.worktree.abs_path().as_ref()
8707 }
8708
8709 async fn shell_env(&self) -> HashMap<String, String> {
8710 let task = self.load_shell_env_task.clone();
8711 task.await.unwrap_or_default()
8712 }
8713
8714 async fn npm_package_installed_version(
8715 &self,
8716 package_name: &str,
8717 ) -> Result<Option<(PathBuf, String)>> {
8718 let local_package_directory = self.worktree_root_path();
8719 let node_modules_directory = local_package_directory.join("node_modules");
8720
8721 if let Some(version) =
8722 read_package_installed_version(node_modules_directory.clone(), package_name).await?
8723 {
8724 return Ok(Some((node_modules_directory, version)));
8725 }
8726 let Some(npm) = self.which("npm".as_ref()).await else {
8727 log::warn!(
8728 "Failed to find npm executable for {:?}",
8729 local_package_directory
8730 );
8731 return Ok(None);
8732 };
8733
8734 let env = self.shell_env().await;
8735 let output = util::command::new_smol_command(&npm)
8736 .args(["root", "-g"])
8737 .envs(env)
8738 .current_dir(local_package_directory)
8739 .output()
8740 .await?;
8741 let global_node_modules =
8742 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
8743
8744 if let Some(version) =
8745 read_package_installed_version(global_node_modules.clone(), package_name).await?
8746 {
8747 return Ok(Some((global_node_modules, version)));
8748 }
8749 return Ok(None);
8750 }
8751
8752 #[cfg(not(target_os = "windows"))]
8753 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
8754 let worktree_abs_path = self.worktree.abs_path();
8755 let shell_path = self.shell_env().await.get("PATH").cloned();
8756 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
8757 }
8758
8759 #[cfg(target_os = "windows")]
8760 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
8761 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
8762 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
8763 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
8764 which::which(command).ok()
8765 }
8766
8767 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
8768 let working_dir = self.worktree_root_path();
8769 let output = util::command::new_smol_command(&command.path)
8770 .args(command.arguments)
8771 .envs(command.env.clone().unwrap_or_default())
8772 .current_dir(working_dir)
8773 .output()
8774 .await?;
8775
8776 if output.status.success() {
8777 return Ok(());
8778 }
8779 Err(anyhow!(
8780 "{}, stdout: {:?}, stderr: {:?}",
8781 output.status,
8782 String::from_utf8_lossy(&output.stdout),
8783 String::from_utf8_lossy(&output.stderr)
8784 ))
8785 }
8786
8787 fn update_status(
8788 &self,
8789 server_name: LanguageServerName,
8790 status: language::LanguageServerBinaryStatus,
8791 ) {
8792 self.language_registry
8793 .update_lsp_status(server_name, status);
8794 }
8795
8796 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
8797 let dir = self.language_registry.language_server_download_dir(name)?;
8798
8799 if !dir.exists() {
8800 smol::fs::create_dir_all(&dir)
8801 .await
8802 .context("failed to create container directory")
8803 .log_err()?;
8804 }
8805
8806 Some(dir)
8807 }
8808
8809 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
8810 let entry = self
8811 .worktree
8812 .entry_for_path(&path)
8813 .with_context(|| format!("no worktree entry for path {path:?}"))?;
8814 let abs_path = self
8815 .worktree
8816 .absolutize(&entry.path)
8817 .with_context(|| format!("cannot absolutize path {path:?}"))?;
8818
8819 self.fs.load(&abs_path).await
8820 }
8821}
8822
8823async fn populate_labels_for_symbols(
8824 symbols: Vec<CoreSymbol>,
8825 language_registry: &Arc<LanguageRegistry>,
8826 lsp_adapter: Option<Arc<CachedLspAdapter>>,
8827 output: &mut Vec<Symbol>,
8828) {
8829 #[allow(clippy::mutable_key_type)]
8830 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
8831
8832 let mut unknown_paths = BTreeSet::new();
8833 for symbol in symbols {
8834 let language = language_registry
8835 .language_for_file_path(&symbol.path.path)
8836 .await
8837 .ok()
8838 .or_else(|| {
8839 unknown_paths.insert(symbol.path.path.clone());
8840 None
8841 });
8842 symbols_by_language
8843 .entry(language)
8844 .or_default()
8845 .push(symbol);
8846 }
8847
8848 for unknown_path in unknown_paths {
8849 log::info!(
8850 "no language found for symbol path {}",
8851 unknown_path.display()
8852 );
8853 }
8854
8855 let mut label_params = Vec::new();
8856 for (language, mut symbols) in symbols_by_language {
8857 label_params.clear();
8858 label_params.extend(
8859 symbols
8860 .iter_mut()
8861 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
8862 );
8863
8864 let mut labels = Vec::new();
8865 if let Some(language) = language {
8866 let lsp_adapter = lsp_adapter.clone().or_else(|| {
8867 language_registry
8868 .lsp_adapters(&language.name())
8869 .first()
8870 .cloned()
8871 });
8872 if let Some(lsp_adapter) = lsp_adapter {
8873 labels = lsp_adapter
8874 .labels_for_symbols(&label_params, &language)
8875 .await
8876 .log_err()
8877 .unwrap_or_default();
8878 }
8879 }
8880
8881 for ((symbol, (name, _)), label) in symbols
8882 .into_iter()
8883 .zip(label_params.drain(..))
8884 .zip(labels.into_iter().chain(iter::repeat(None)))
8885 {
8886 output.push(Symbol {
8887 language_server_name: symbol.language_server_name,
8888 source_worktree_id: symbol.source_worktree_id,
8889 source_language_server_id: symbol.source_language_server_id,
8890 path: symbol.path,
8891 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
8892 name,
8893 kind: symbol.kind,
8894 range: symbol.range,
8895 signature: symbol.signature,
8896 });
8897 }
8898 }
8899}
8900
8901fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
8902 match server.capabilities().text_document_sync.as_ref()? {
8903 lsp::TextDocumentSyncCapability::Kind(kind) => match *kind {
8904 lsp::TextDocumentSyncKind::NONE => None,
8905 lsp::TextDocumentSyncKind::FULL => Some(true),
8906 lsp::TextDocumentSyncKind::INCREMENTAL => Some(false),
8907 _ => None,
8908 },
8909 lsp::TextDocumentSyncCapability::Options(options) => match options.save.as_ref()? {
8910 lsp::TextDocumentSyncSaveOptions::Supported(supported) => {
8911 if *supported {
8912 Some(true)
8913 } else {
8914 None
8915 }
8916 }
8917 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
8918 Some(save_options.include_text.unwrap_or(false))
8919 }
8920 },
8921 }
8922}
8923
8924/// Completion items are displayed in a `UniformList`.
8925/// Usually, those items are single-line strings, but in LSP responses,
8926/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
8927/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
8928/// 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,
8929/// breaking the completions menu presentation.
8930///
8931/// 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.
8932fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
8933 let mut new_text = String::with_capacity(label.text.len());
8934 let mut offset_map = vec![0; label.text.len() + 1];
8935 let mut last_char_was_space = false;
8936 let mut new_idx = 0;
8937 let mut chars = label.text.char_indices().fuse();
8938 let mut newlines_removed = false;
8939
8940 while let Some((idx, c)) = chars.next() {
8941 offset_map[idx] = new_idx;
8942
8943 match c {
8944 '\n' if last_char_was_space => {
8945 newlines_removed = true;
8946 }
8947 '\t' | ' ' if last_char_was_space => {}
8948 '\n' if !last_char_was_space => {
8949 new_text.push(' ');
8950 new_idx += 1;
8951 last_char_was_space = true;
8952 newlines_removed = true;
8953 }
8954 ' ' | '\t' => {
8955 new_text.push(' ');
8956 new_idx += 1;
8957 last_char_was_space = true;
8958 }
8959 _ => {
8960 new_text.push(c);
8961 new_idx += c.len_utf8();
8962 last_char_was_space = false;
8963 }
8964 }
8965 }
8966 offset_map[label.text.len()] = new_idx;
8967
8968 // Only modify the label if newlines were removed.
8969 if !newlines_removed {
8970 return;
8971 }
8972
8973 let last_index = new_idx;
8974 let mut run_ranges_errors = Vec::new();
8975 label.runs.retain_mut(|(range, _)| {
8976 match offset_map.get(range.start) {
8977 Some(&start) => range.start = start,
8978 None => {
8979 run_ranges_errors.push(range.clone());
8980 return false;
8981 }
8982 }
8983
8984 match offset_map.get(range.end) {
8985 Some(&end) => range.end = end,
8986 None => {
8987 run_ranges_errors.push(range.clone());
8988 range.end = last_index;
8989 }
8990 }
8991 true
8992 });
8993 if !run_ranges_errors.is_empty() {
8994 log::error!(
8995 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
8996 label.text
8997 );
8998 }
8999
9000 let mut wrong_filter_range = None;
9001 if label.filter_range == (0..label.text.len()) {
9002 label.filter_range = 0..new_text.len();
9003 } else {
9004 let mut original_filter_range = Some(label.filter_range.clone());
9005 match offset_map.get(label.filter_range.start) {
9006 Some(&start) => label.filter_range.start = start,
9007 None => {
9008 wrong_filter_range = original_filter_range.take();
9009 label.filter_range.start = last_index;
9010 }
9011 }
9012
9013 match offset_map.get(label.filter_range.end) {
9014 Some(&end) => label.filter_range.end = end,
9015 None => {
9016 wrong_filter_range = original_filter_range.take();
9017 label.filter_range.end = last_index;
9018 }
9019 }
9020 }
9021 if let Some(wrong_filter_range) = wrong_filter_range {
9022 log::error!(
9023 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
9024 label.text
9025 );
9026 }
9027
9028 label.text = new_text;
9029}
9030
9031#[cfg(test)]
9032mod tests {
9033 use language::HighlightId;
9034
9035 use super::*;
9036
9037 #[test]
9038 fn test_glob_literal_prefix() {
9039 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
9040 assert_eq!(
9041 glob_literal_prefix(Path::new("node_modules/**/*.js")),
9042 Path::new("node_modules")
9043 );
9044 assert_eq!(
9045 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
9046 Path::new("foo")
9047 );
9048 assert_eq!(
9049 glob_literal_prefix(Path::new("foo/bar/baz.js")),
9050 Path::new("foo/bar/baz.js")
9051 );
9052
9053 #[cfg(target_os = "windows")]
9054 {
9055 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
9056 assert_eq!(
9057 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
9058 Path::new("node_modules")
9059 );
9060 assert_eq!(
9061 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
9062 Path::new("foo")
9063 );
9064 assert_eq!(
9065 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
9066 Path::new("foo/bar/baz.js")
9067 );
9068 }
9069 }
9070
9071 #[test]
9072 fn test_multi_len_chars_normalization() {
9073 let mut label = CodeLabel {
9074 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
9075 runs: vec![(0..6, HighlightId(1))],
9076 filter_range: 0..6,
9077 };
9078 ensure_uniform_list_compatible_label(&mut label);
9079 assert_eq!(
9080 label,
9081 CodeLabel {
9082 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
9083 runs: vec![(0..6, HighlightId(1))],
9084 filter_range: 0..6,
9085 }
9086 );
9087 }
9088}