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