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