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