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