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