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