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