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