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