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