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