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