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