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