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