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