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