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