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