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 cx.spawn(move |this, cx| async move {
1605 let response = upstream_client
1606 .request(request)
1607 .await?
1608 .transaction
1609 .ok_or_else(|| anyhow!("missing transaction"))?;
1610 BufferStore::deserialize_project_transaction(
1611 this.read_with(&cx, |this, _| this.buffer_store.downgrade())?,
1612 response,
1613 push_to_history,
1614 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 let adapter = this.languages.get_or_register_lsp_adapter(
5066 language_name.clone(),
5067 server_name.clone(),
5068 || {
5069 Arc::new(SshLspAdapter::new(
5070 server_name,
5071 binary,
5072 envelope.payload.initialization_options,
5073 envelope.payload.code_action_kinds,
5074 ))
5075 },
5076 );
5077
5078 this.start_language_server(&worktree, adapter, language_name, cx);
5079 Ok(())
5080 })??;
5081 Ok(proto::Ack {})
5082 }
5083
5084 pub async fn handle_which_command(
5085 this: Model<Self>,
5086 envelope: TypedEnvelope<proto::WhichCommand>,
5087 mut cx: AsyncAppContext,
5088 ) -> Result<proto::WhichCommandResponse> {
5089 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
5090 let command = PathBuf::from(envelope.payload.command);
5091 let response = this
5092 .update(&mut cx, |this, cx| {
5093 let worktree = this.worktree_for_id(worktree_id, cx)?;
5094 let delegate = LocalLspAdapterDelegate::for_local(this, &worktree, cx);
5095 anyhow::Ok(
5096 cx.spawn(|_, _| async move { delegate.which(command.as_os_str()).await }),
5097 )
5098 })??
5099 .await;
5100
5101 Ok(proto::WhichCommandResponse {
5102 path: response.map(|path| path.to_string_lossy().to_string()),
5103 })
5104 }
5105
5106 pub async fn handle_shell_env(
5107 this: Model<Self>,
5108 envelope: TypedEnvelope<proto::ShellEnv>,
5109 mut cx: AsyncAppContext,
5110 ) -> Result<proto::ShellEnvResponse> {
5111 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
5112 let response = this
5113 .update(&mut cx, |this, cx| {
5114 let worktree = this.worktree_for_id(worktree_id, cx)?;
5115 let delegate = LocalLspAdapterDelegate::for_local(this, &worktree, cx);
5116 anyhow::Ok(cx.spawn(|_, _| async move { delegate.shell_env().await }))
5117 })??
5118 .await;
5119
5120 Ok(proto::ShellEnvResponse {
5121 env: response.into_iter().collect(),
5122 })
5123 }
5124 pub async fn handle_try_exec(
5125 this: Model<Self>,
5126 envelope: TypedEnvelope<proto::TryExec>,
5127 mut cx: AsyncAppContext,
5128 ) -> Result<proto::Ack> {
5129 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
5130 let binary = envelope
5131 .payload
5132 .binary
5133 .ok_or_else(|| anyhow!("missing binary"))?;
5134 let binary = LanguageServerBinary {
5135 path: PathBuf::from(binary.path),
5136 env: None,
5137 arguments: binary.arguments.into_iter().map(Into::into).collect(),
5138 };
5139 this.update(&mut cx, |this, cx| {
5140 let worktree = this.worktree_for_id(worktree_id, cx)?;
5141 let delegate = LocalLspAdapterDelegate::for_local(this, &worktree, cx);
5142 anyhow::Ok(cx.spawn(|_, _| async move { delegate.try_exec(binary).await }))
5143 })??
5144 .await?;
5145
5146 Ok(proto::Ack {})
5147 }
5148
5149 pub async fn handle_read_text_file(
5150 this: Model<Self>,
5151 envelope: TypedEnvelope<proto::ReadTextFile>,
5152 mut cx: AsyncAppContext,
5153 ) -> Result<proto::ReadTextFileResponse> {
5154 let path = envelope
5155 .payload
5156 .path
5157 .ok_or_else(|| anyhow!("missing path"))?;
5158 let worktree_id = WorktreeId::from_proto(path.worktree_id);
5159 let path = PathBuf::from(path.path);
5160 let response = this
5161 .update(&mut cx, |this, cx| {
5162 let worktree = this.worktree_for_id(worktree_id, cx)?;
5163 let delegate = LocalLspAdapterDelegate::for_local(this, &worktree, cx);
5164 anyhow::Ok(cx.spawn(|_, _| async move { delegate.read_text_file(path).await }))
5165 })??
5166 .await?;
5167
5168 Ok(proto::ReadTextFileResponse { text: response })
5169 }
5170
5171 async fn handle_apply_additional_edits_for_completion(
5172 this: Model<Self>,
5173 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
5174 mut cx: AsyncAppContext,
5175 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
5176 let (buffer, completion) = this.update(&mut cx, |this, cx| {
5177 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
5178 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
5179 let completion = Self::deserialize_completion(
5180 envelope
5181 .payload
5182 .completion
5183 .ok_or_else(|| anyhow!("invalid completion"))?,
5184 )?;
5185 anyhow::Ok((buffer, completion))
5186 })??;
5187
5188 let apply_additional_edits = this.update(&mut cx, |this, cx| {
5189 this.apply_additional_edits_for_completion(
5190 buffer,
5191 Completion {
5192 old_range: completion.old_range,
5193 new_text: completion.new_text,
5194 lsp_completion: completion.lsp_completion,
5195 server_id: completion.server_id,
5196 documentation: None,
5197 label: CodeLabel {
5198 text: Default::default(),
5199 runs: Default::default(),
5200 filter_range: Default::default(),
5201 },
5202 confirm: None,
5203 },
5204 false,
5205 cx,
5206 )
5207 })?;
5208
5209 Ok(proto::ApplyCompletionAdditionalEditsResponse {
5210 transaction: apply_additional_edits
5211 .await?
5212 .as_ref()
5213 .map(language::proto::serialize_transaction),
5214 })
5215 }
5216 pub fn last_formatting_failure(&self) -> Option<&str> {
5217 self.as_local()
5218 .and_then(|local| local.last_formatting_failure.as_deref())
5219 }
5220
5221 pub fn format(
5222 &mut self,
5223 buffers: HashSet<Model<Buffer>>,
5224 push_to_history: bool,
5225 trigger: FormatTrigger,
5226 cx: &mut ModelContext<Self>,
5227 ) -> Task<anyhow::Result<ProjectTransaction>> {
5228 if let Some(_) = self.as_local() {
5229 let buffers_with_paths = buffers
5230 .into_iter()
5231 .map(|buffer_handle| {
5232 let buffer = buffer_handle.read(cx);
5233 let buffer_abs_path = File::from_dyn(buffer.file())
5234 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
5235 (buffer_handle, buffer_abs_path)
5236 })
5237 .collect::<Vec<_>>();
5238
5239 cx.spawn(move |lsp_store, mut cx| async move {
5240 let result = LocalLspStore::format_locally(
5241 lsp_store.clone(),
5242 buffers_with_paths,
5243 push_to_history,
5244 trigger,
5245 cx.clone(),
5246 )
5247 .await;
5248
5249 lsp_store.update(&mut cx, |lsp_store, _| {
5250 let local = lsp_store.as_local_mut().unwrap();
5251 match &result {
5252 Ok(_) => local.last_formatting_failure = None,
5253 Err(error) => {
5254 local.last_formatting_failure.replace(error.to_string());
5255 }
5256 }
5257 })?;
5258
5259 result
5260 })
5261 } else if let Some((client, project_id)) = self.upstream_client() {
5262 cx.spawn(move |this, mut cx| async move {
5263 let response = client
5264 .request(proto::FormatBuffers {
5265 project_id,
5266 trigger: trigger as i32,
5267 buffer_ids: buffers
5268 .iter()
5269 .map(|buffer| {
5270 buffer.update(&mut cx, |buffer, _| buffer.remote_id().into())
5271 })
5272 .collect::<Result<_>>()?,
5273 })
5274 .await?
5275 .transaction
5276 .ok_or_else(|| anyhow!("missing transaction"))?;
5277 BufferStore::deserialize_project_transaction(
5278 this.read_with(&cx, |this, _| this.buffer_store.downgrade())?,
5279 response,
5280 push_to_history,
5281 cx,
5282 )
5283 .await
5284 })
5285 } else {
5286 Task::ready(Ok(ProjectTransaction::default()))
5287 }
5288 }
5289
5290 async fn handle_format_buffers(
5291 this: Model<Self>,
5292 envelope: TypedEnvelope<proto::FormatBuffers>,
5293 mut cx: AsyncAppContext,
5294 ) -> Result<proto::FormatBuffersResponse> {
5295 let sender_id = envelope.original_sender_id().unwrap_or_default();
5296 let format = this.update(&mut cx, |this, cx| {
5297 let mut buffers = HashSet::default();
5298 for buffer_id in &envelope.payload.buffer_ids {
5299 let buffer_id = BufferId::new(*buffer_id)?;
5300 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
5301 }
5302 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
5303 Ok::<_, anyhow::Error>(this.format(buffers, false, trigger, cx))
5304 })??;
5305
5306 let project_transaction = format.await?;
5307 let project_transaction = this.update(&mut cx, |this, cx| {
5308 this.buffer_store.update(cx, |buffer_store, cx| {
5309 buffer_store.serialize_project_transaction_for_peer(
5310 project_transaction,
5311 sender_id,
5312 cx,
5313 )
5314 })
5315 })?;
5316 Ok(proto::FormatBuffersResponse {
5317 transaction: Some(project_transaction),
5318 })
5319 }
5320
5321 fn language_settings<'a>(
5322 &'a self,
5323 worktree: &'a Model<Worktree>,
5324 language: &LanguageName,
5325 cx: &'a mut ModelContext<Self>,
5326 ) -> &'a LanguageSettings {
5327 let root_file = worktree.update(cx, |tree, cx| tree.root_file(cx));
5328 all_language_settings(root_file.map(|f| f as _).as_ref(), cx).language(Some(language))
5329 }
5330
5331 pub fn start_language_servers(
5332 &mut self,
5333 worktree: &Model<Worktree>,
5334 language: LanguageName,
5335 cx: &mut ModelContext<Self>,
5336 ) {
5337 let settings = self.language_settings(worktree, &language, cx);
5338 if !settings.enable_language_server || self.mode.is_remote() {
5339 return;
5340 }
5341
5342 let available_lsp_adapters = self.languages.clone().lsp_adapters(&language);
5343 let available_language_servers = available_lsp_adapters
5344 .iter()
5345 .map(|lsp_adapter| lsp_adapter.name.clone())
5346 .collect::<Vec<_>>();
5347
5348 let desired_language_servers =
5349 settings.customized_language_servers(&available_language_servers);
5350
5351 let mut enabled_lsp_adapters: Vec<Arc<CachedLspAdapter>> = Vec::new();
5352 for desired_language_server in desired_language_servers {
5353 if let Some(adapter) = available_lsp_adapters
5354 .iter()
5355 .find(|adapter| adapter.name == desired_language_server)
5356 {
5357 enabled_lsp_adapters.push(adapter.clone());
5358 continue;
5359 }
5360
5361 if let Some(adapter) = self
5362 .languages
5363 .load_available_lsp_adapter(&desired_language_server)
5364 {
5365 self.languages
5366 .register_lsp_adapter(language.clone(), adapter.adapter.clone());
5367 enabled_lsp_adapters.push(adapter);
5368 continue;
5369 }
5370
5371 log::warn!(
5372 "no language server found matching '{}'",
5373 desired_language_server.0
5374 );
5375 }
5376
5377 for adapter in &enabled_lsp_adapters {
5378 self.start_language_server(worktree, adapter.clone(), language.clone(), cx);
5379 }
5380
5381 // After starting all the language servers, reorder them to reflect the desired order
5382 // based on the settings.
5383 //
5384 // This is done, in part, to ensure that language servers loaded at different points
5385 // (e.g., native vs extension) still end up in the right order at the end, rather than
5386 // it being based on which language server happened to be loaded in first.
5387 self.languages
5388 .reorder_language_servers(&language, enabled_lsp_adapters);
5389 }
5390
5391 fn start_language_server_on_ssh_host(
5392 &mut self,
5393 worktree: &Model<Worktree>,
5394 adapter: Arc<CachedLspAdapter>,
5395 language: LanguageName,
5396 cx: &mut ModelContext<Self>,
5397 ) {
5398 let ssh = self.as_ssh().unwrap();
5399
5400 let delegate = Arc::new(SshLspAdapterDelegate {
5401 lsp_store: cx.handle().downgrade(),
5402 worktree: worktree.read(cx).snapshot(),
5403 upstream_client: ssh.upstream_client.clone(),
5404 language_registry: self.languages.clone(),
5405 }) as Arc<dyn LspAdapterDelegate>;
5406
5407 // TODO: We should use `adapter` here instead of reaching through the `CachedLspAdapter`.
5408 let lsp_adapter = adapter.adapter.clone();
5409
5410 let Some((upstream_client, project_id)) = self.upstream_client() else {
5411 return;
5412 };
5413 let worktree_id = worktree.read(cx).id().to_proto();
5414 let name = adapter.name().to_string();
5415
5416 let Some(available_language) = self.languages.available_language_for_name(&language) else {
5417 log::error!("failed to find available language {language}");
5418 return;
5419 };
5420
5421 let task = cx.spawn(|_, cx| async move {
5422 let user_binary_task = lsp_adapter.check_if_user_installed(delegate.as_ref(), &cx);
5423 let binary = match user_binary_task.await {
5424 Some(binary) => binary,
5425 None => {
5426 return Err(anyhow!(
5427 "Downloading language server for ssh host is not supported yet"
5428 ))
5429 }
5430 };
5431
5432 let name = adapter.name();
5433 let code_action_kinds = adapter
5434 .adapter
5435 .code_action_kinds()
5436 .map(|kinds| serde_json::to_string(&kinds))
5437 .transpose()?;
5438 let get_options = adapter.adapter.clone().initialization_options(&delegate);
5439 let initialization_options = get_options
5440 .await?
5441 .map(|options| serde_json::to_string(&options))
5442 .transpose()?;
5443
5444 let language_server_command = proto::LanguageServerCommand {
5445 path: binary.path.to_string_lossy().to_string(),
5446 arguments: binary
5447 .arguments
5448 .iter()
5449 .map(|args| args.to_string_lossy().to_string())
5450 .collect(),
5451 env: binary.env.unwrap_or_default().into_iter().collect(),
5452 };
5453
5454 upstream_client
5455 .request(proto::CreateLanguageServer {
5456 project_id,
5457 worktree_id,
5458 name: name.0.to_string(),
5459 binary: Some(language_server_command),
5460 initialization_options,
5461 code_action_kinds,
5462 language: Some(proto::AvailableLanguage {
5463 name: language.to_proto(),
5464 matcher: serde_json::to_string(&available_language.matcher())?,
5465 }),
5466 })
5467 .await
5468 });
5469 cx.spawn(|this, mut cx| async move {
5470 if let Err(e) = task.await {
5471 this.update(&mut cx, |_this, cx| {
5472 cx.emit(LspStoreEvent::Notification(format!(
5473 "failed to start {}: {}",
5474 name, e
5475 )))
5476 })
5477 .ok();
5478 }
5479 })
5480 .detach();
5481 }
5482
5483 fn start_language_server(
5484 &mut self,
5485 worktree_handle: &Model<Worktree>,
5486 adapter: Arc<CachedLspAdapter>,
5487 language: LanguageName,
5488 cx: &mut ModelContext<Self>,
5489 ) {
5490 if self.mode.is_remote() {
5491 return;
5492 }
5493
5494 let worktree = worktree_handle.read(cx);
5495 let worktree_id = worktree.id();
5496 let worktree_path = worktree.abs_path();
5497 let key = (worktree_id, adapter.name.clone());
5498 if self.language_server_ids.contains_key(&key) {
5499 return;
5500 }
5501
5502 if self.mode.is_ssh() {
5503 self.start_language_server_on_ssh_host(worktree_handle, adapter, language, cx);
5504 return;
5505 }
5506
5507 if adapter.reinstall_attempt_count.load(SeqCst) > MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
5508 return;
5509 }
5510
5511 let local = self.as_local().unwrap();
5512
5513 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
5514 let lsp_adapter_delegate = LocalLspAdapterDelegate::for_local(self, worktree_handle, cx);
5515 let project_environment = local.environment.update(cx, |environment, cx| {
5516 environment.get_environment(Some(worktree_id), Some(worktree_path.clone()), cx)
5517 });
5518
5519 let pending_server = match self.languages.create_pending_language_server(
5520 stderr_capture.clone(),
5521 language.clone(),
5522 adapter.clone(),
5523 Arc::clone(&worktree_path),
5524 lsp_adapter_delegate.clone(),
5525 project_environment,
5526 cx,
5527 ) {
5528 Some(pending_server) => pending_server,
5529 None => return,
5530 };
5531
5532 let project_settings = ProjectSettings::get(
5533 Some(SettingsLocation {
5534 worktree_id,
5535 path: Path::new(""),
5536 }),
5537 cx,
5538 );
5539
5540 // We need some on the SSH client, and some on SSH host
5541 let lsp = project_settings.lsp.get(&adapter.name);
5542 let override_options = lsp.and_then(|s| s.initialization_options.clone());
5543
5544 let server_id = pending_server.server_id;
5545 let container_dir = pending_server.container_dir.clone();
5546 let state = LanguageServerState::Starting({
5547 let adapter = adapter.clone();
5548 let server_name = adapter.name.0.clone();
5549 let language = language.clone();
5550 let key = key.clone();
5551
5552 cx.spawn(move |this, mut cx| async move {
5553 let result = Self::setup_and_insert_language_server(
5554 this.clone(),
5555 lsp_adapter_delegate,
5556 override_options,
5557 pending_server,
5558 adapter.clone(),
5559 language.clone(),
5560 server_id,
5561 key,
5562 &mut cx,
5563 )
5564 .await;
5565
5566 match result {
5567 Ok(server) => {
5568 stderr_capture.lock().take();
5569 server
5570 }
5571
5572 Err(err) => {
5573 log::error!("failed to start language server {server_name:?}: {err}");
5574 log::error!("server stderr: {:?}", stderr_capture.lock().take());
5575
5576 let this = this.upgrade()?;
5577 let container_dir = container_dir?;
5578
5579 let attempt_count = adapter.reinstall_attempt_count.fetch_add(1, SeqCst);
5580 if attempt_count >= MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
5581 let max = MAX_SERVER_REINSTALL_ATTEMPT_COUNT;
5582 log::error!("Hit {max} reinstallation attempts for {server_name:?}");
5583 return None;
5584 }
5585
5586 log::info!(
5587 "retrying installation of language server {server_name:?} in {}s",
5588 SERVER_REINSTALL_DEBOUNCE_TIMEOUT.as_secs()
5589 );
5590 cx.background_executor()
5591 .timer(SERVER_REINSTALL_DEBOUNCE_TIMEOUT)
5592 .await;
5593
5594 let installation_test_binary = adapter
5595 .installation_test_binary(container_dir.to_path_buf())
5596 .await;
5597
5598 this.update(&mut cx, |_, cx| {
5599 Self::check_errored_server(
5600 language,
5601 adapter,
5602 server_id,
5603 installation_test_binary,
5604 cx,
5605 )
5606 })
5607 .ok();
5608
5609 None
5610 }
5611 }
5612 })
5613 });
5614
5615 self.as_local_mut()
5616 .unwrap()
5617 .language_servers
5618 .insert(server_id, state);
5619 self.language_server_ids.insert(key, server_id);
5620 }
5621
5622 #[allow(clippy::too_many_arguments)]
5623 async fn setup_and_insert_language_server(
5624 this: WeakModel<Self>,
5625 delegate: Arc<dyn LspAdapterDelegate>,
5626 override_initialization_options: Option<serde_json::Value>,
5627 pending_server: PendingLanguageServer,
5628 adapter: Arc<CachedLspAdapter>,
5629 language: LanguageName,
5630 server_id: LanguageServerId,
5631 key: (WorktreeId, LanguageServerName),
5632 cx: &mut AsyncAppContext,
5633 ) -> Result<Option<Arc<LanguageServer>>> {
5634 let language_server = Self::setup_pending_language_server(
5635 this.clone(),
5636 override_initialization_options,
5637 pending_server,
5638 delegate,
5639 adapter.clone(),
5640 server_id,
5641 cx,
5642 )
5643 .await?;
5644
5645 let this = match this.upgrade() {
5646 Some(this) => this,
5647 None => return Err(anyhow!("failed to upgrade project handle")),
5648 };
5649
5650 this.update(cx, |this, cx| {
5651 this.insert_newly_running_language_server(
5652 language,
5653 adapter,
5654 language_server.clone(),
5655 server_id,
5656 key,
5657 cx,
5658 )
5659 })??;
5660
5661 Ok(Some(language_server))
5662 }
5663
5664 fn reinstall_language_server(
5665 &mut self,
5666 language: LanguageName,
5667 adapter: Arc<CachedLspAdapter>,
5668 server_id: LanguageServerId,
5669 cx: &mut ModelContext<Self>,
5670 ) -> Option<Task<()>> {
5671 log::info!("beginning to reinstall server");
5672
5673 if let Some(local) = self.as_local_mut() {
5674 let existing_server = match local.language_servers.remove(&server_id) {
5675 Some(LanguageServerState::Running { server, .. }) => Some(server),
5676 _ => None,
5677 };
5678
5679 self.worktree_store.update(cx, |store, cx| {
5680 for worktree in store.worktrees() {
5681 let key = (worktree.read(cx).id(), adapter.name.clone());
5682 self.language_server_ids.remove(&key);
5683 }
5684 });
5685
5686 Some(cx.spawn(move |this, mut cx| async move {
5687 if let Some(task) = existing_server.and_then(|server| server.shutdown()) {
5688 log::info!("shutting down existing server");
5689 task.await;
5690 }
5691
5692 // TODO: This is race-safe with regards to preventing new instances from
5693 // starting while deleting, but existing instances in other projects are going
5694 // to be very confused and messed up
5695 let Some(task) = this
5696 .update(&mut cx, |this, cx| {
5697 this.languages.delete_server_container(adapter.clone(), cx)
5698 })
5699 .log_err()
5700 else {
5701 return;
5702 };
5703 task.await;
5704
5705 this.update(&mut cx, |this, cx| {
5706 for worktree in this.worktree_store.read(cx).worktrees().collect::<Vec<_>>() {
5707 this.start_language_server(
5708 &worktree,
5709 adapter.clone(),
5710 language.clone(),
5711 cx,
5712 );
5713 }
5714 })
5715 .ok();
5716 }))
5717 } else if let Some(_ssh_store) = self.as_ssh() {
5718 // TODO
5719 None
5720 } else {
5721 None
5722 }
5723 }
5724
5725 async fn shutdown_language_server(
5726 server_state: Option<LanguageServerState>,
5727 name: LanguageServerName,
5728 cx: AsyncAppContext,
5729 ) {
5730 let server = match server_state {
5731 Some(LanguageServerState::Starting(task)) => {
5732 let mut timer = cx
5733 .background_executor()
5734 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
5735 .fuse();
5736
5737 select! {
5738 server = task.fuse() => server,
5739 _ = timer => {
5740 log::info!(
5741 "timeout waiting for language server {} to finish launching before stopping",
5742 name
5743 );
5744 None
5745 },
5746 }
5747 }
5748
5749 Some(LanguageServerState::Running { server, .. }) => Some(server),
5750
5751 None => None,
5752 };
5753
5754 if let Some(server) = server {
5755 if let Some(shutdown) = server.shutdown() {
5756 shutdown.await;
5757 }
5758 }
5759 }
5760
5761 // Returns a list of all of the worktrees which no longer have a language server and the root path
5762 // for the stopped server
5763 pub fn stop_language_server(
5764 &mut self,
5765 worktree_id: WorktreeId,
5766 adapter_name: LanguageServerName,
5767 cx: &mut ModelContext<Self>,
5768 ) -> Task<Vec<WorktreeId>> {
5769 let key = (worktree_id, adapter_name);
5770 if self.mode.is_local() {
5771 if let Some(server_id) = self.language_server_ids.remove(&key) {
5772 let name = key.1;
5773 log::info!("stopping language server {name}");
5774
5775 // Remove other entries for this language server as well
5776 let mut orphaned_worktrees = vec![worktree_id];
5777 let other_keys = self.language_server_ids.keys().cloned().collect::<Vec<_>>();
5778 for other_key in other_keys {
5779 if self.language_server_ids.get(&other_key) == Some(&server_id) {
5780 self.language_server_ids.remove(&other_key);
5781 orphaned_worktrees.push(other_key.0);
5782 }
5783 }
5784
5785 self.buffer_store.update(cx, |buffer_store, cx| {
5786 for buffer in buffer_store.buffers() {
5787 buffer.update(cx, |buffer, cx| {
5788 buffer.update_diagnostics(
5789 server_id,
5790 DiagnosticSet::new([], buffer),
5791 cx,
5792 );
5793 });
5794 }
5795 });
5796
5797 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
5798 summaries.retain(|path, summaries_by_server_id| {
5799 if summaries_by_server_id.remove(&server_id).is_some() {
5800 if let Some((client, project_id)) = self.downstream_client.clone() {
5801 client
5802 .send(proto::UpdateDiagnosticSummary {
5803 project_id,
5804 worktree_id: worktree_id.to_proto(),
5805 summary: Some(proto::DiagnosticSummary {
5806 path: path.to_string_lossy().to_string(),
5807 language_server_id: server_id.0 as u64,
5808 error_count: 0,
5809 warning_count: 0,
5810 }),
5811 })
5812 .log_err();
5813 }
5814 !summaries_by_server_id.is_empty()
5815 } else {
5816 true
5817 }
5818 });
5819 }
5820
5821 for diagnostics in self.diagnostics.values_mut() {
5822 diagnostics.retain(|_, diagnostics_by_server_id| {
5823 if let Ok(ix) =
5824 diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0)
5825 {
5826 diagnostics_by_server_id.remove(ix);
5827 !diagnostics_by_server_id.is_empty()
5828 } else {
5829 true
5830 }
5831 });
5832 }
5833
5834 self.as_local_mut()
5835 .unwrap()
5836 .language_server_watched_paths
5837 .remove(&server_id);
5838 self.language_server_statuses.remove(&server_id);
5839 cx.notify();
5840
5841 let server_state = self
5842 .as_local_mut()
5843 .unwrap()
5844 .language_servers
5845 .remove(&server_id);
5846 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
5847 cx.spawn(move |_, cx| async move {
5848 Self::shutdown_language_server(server_state, name, cx).await;
5849 orphaned_worktrees
5850 })
5851 } else {
5852 Task::ready(Vec::new())
5853 }
5854 } else if self.mode.is_ssh() {
5855 // TODO ssh
5856 Task::ready(Vec::new())
5857 } else {
5858 Task::ready(Vec::new())
5859 }
5860 }
5861
5862 pub fn restart_language_servers_for_buffers(
5863 &mut self,
5864 buffers: impl IntoIterator<Item = Model<Buffer>>,
5865 cx: &mut ModelContext<Self>,
5866 ) {
5867 if let Some((client, project_id)) = self.upstream_client() {
5868 let request = client.request(proto::RestartLanguageServers {
5869 project_id,
5870 buffer_ids: buffers
5871 .into_iter()
5872 .map(|b| b.read(cx).remote_id().to_proto())
5873 .collect(),
5874 });
5875 cx.background_executor()
5876 .spawn(request)
5877 .detach_and_log_err(cx);
5878 } else {
5879 #[allow(clippy::mutable_key_type)]
5880 let language_server_lookup_info: HashSet<(Model<Worktree>, LanguageName)> = buffers
5881 .into_iter()
5882 .filter_map(|buffer| {
5883 let buffer = buffer.read(cx);
5884 let file = buffer.file()?;
5885 let worktree = File::from_dyn(Some(file))?.worktree.clone();
5886 let language =
5887 self.languages
5888 .language_for_file(file, Some(buffer.as_rope()), cx)?;
5889
5890 Some((worktree, language.name()))
5891 })
5892 .collect();
5893
5894 for (worktree, language) in language_server_lookup_info {
5895 self.restart_language_servers(worktree, language, cx);
5896 }
5897 }
5898 }
5899
5900 pub fn restart_language_servers(
5901 &mut self,
5902 worktree: Model<Worktree>,
5903 language: LanguageName,
5904 cx: &mut ModelContext<Self>,
5905 ) {
5906 let worktree_id = worktree.read(cx).id();
5907
5908 let stop_tasks = self
5909 .languages
5910 .clone()
5911 .lsp_adapters(&language)
5912 .iter()
5913 .map(|adapter| {
5914 let stop_task = self.stop_language_server(worktree_id, adapter.name.clone(), cx);
5915 (stop_task, adapter.name.clone())
5916 })
5917 .collect::<Vec<_>>();
5918 if stop_tasks.is_empty() {
5919 return;
5920 }
5921
5922 cx.spawn(move |this, mut cx| async move {
5923 // For each stopped language server, record all of the worktrees with which
5924 // it was associated.
5925 let mut affected_worktrees = Vec::new();
5926 for (stop_task, language_server_name) in stop_tasks {
5927 for affected_worktree_id in stop_task.await {
5928 affected_worktrees.push((affected_worktree_id, language_server_name.clone()));
5929 }
5930 }
5931
5932 this.update(&mut cx, |this, cx| {
5933 // Restart the language server for the given worktree.
5934 this.start_language_servers(&worktree, language.clone(), cx);
5935
5936 // Lookup new server ids and set them for each of the orphaned worktrees
5937 for (affected_worktree_id, language_server_name) in affected_worktrees {
5938 if let Some(new_server_id) = this
5939 .language_server_ids
5940 .get(&(worktree_id, language_server_name.clone()))
5941 .cloned()
5942 {
5943 this.language_server_ids
5944 .insert((affected_worktree_id, language_server_name), new_server_id);
5945 }
5946 }
5947 })
5948 .ok();
5949 })
5950 .detach();
5951 }
5952
5953 fn check_errored_server(
5954 language: LanguageName,
5955 adapter: Arc<CachedLspAdapter>,
5956 server_id: LanguageServerId,
5957 installation_test_binary: Option<LanguageServerBinary>,
5958 cx: &mut ModelContext<Self>,
5959 ) {
5960 if !adapter.can_be_reinstalled() {
5961 log::info!(
5962 "Validation check requested for {:?} but it cannot be reinstalled",
5963 adapter.name.0
5964 );
5965 return;
5966 }
5967
5968 cx.spawn(move |this, mut cx| async move {
5969 log::info!("About to spawn test binary");
5970
5971 // A lack of test binary counts as a failure
5972 let process = installation_test_binary.and_then(|binary| {
5973 smol::process::Command::new(&binary.path)
5974 .current_dir(&binary.path)
5975 .args(binary.arguments)
5976 .stdin(Stdio::piped())
5977 .stdout(Stdio::piped())
5978 .stderr(Stdio::inherit())
5979 .kill_on_drop(true)
5980 .spawn()
5981 .ok()
5982 });
5983
5984 const PROCESS_TIMEOUT: Duration = Duration::from_secs(5);
5985 let mut timeout = cx.background_executor().timer(PROCESS_TIMEOUT).fuse();
5986
5987 let mut errored = false;
5988 if let Some(mut process) = process {
5989 futures::select! {
5990 status = process.status().fuse() => match status {
5991 Ok(status) => errored = !status.success(),
5992 Err(_) => errored = true,
5993 },
5994
5995 _ = timeout => {
5996 log::info!("test binary time-ed out, this counts as a success");
5997 _ = process.kill();
5998 }
5999 }
6000 } else {
6001 log::warn!("test binary failed to launch");
6002 errored = true;
6003 }
6004
6005 if errored {
6006 log::warn!("test binary check failed");
6007 let task = this
6008 .update(&mut cx, move |this, cx| {
6009 this.reinstall_language_server(language, adapter, server_id, cx)
6010 })
6011 .ok()
6012 .flatten();
6013
6014 if let Some(task) = task {
6015 task.await;
6016 }
6017 }
6018 })
6019 .detach();
6020 }
6021
6022 async fn setup_pending_language_server(
6023 this: WeakModel<Self>,
6024 override_options: Option<serde_json::Value>,
6025 pending_server: PendingLanguageServer,
6026 delegate: Arc<dyn LspAdapterDelegate>,
6027 adapter: Arc<CachedLspAdapter>,
6028 server_id: LanguageServerId,
6029 cx: &mut AsyncAppContext,
6030 ) -> Result<Arc<LanguageServer>> {
6031 let workspace_config = adapter
6032 .adapter
6033 .clone()
6034 .workspace_configuration(&delegate, cx)
6035 .await?;
6036 // This has to come from the server
6037 let (language_server, mut initialization_options) = pending_server.task.await?;
6038
6039 let name = language_server.name();
6040 language_server
6041 .on_notification::<lsp::notification::PublishDiagnostics, _>({
6042 let adapter = adapter.clone();
6043 let this = this.clone();
6044 move |mut params, mut cx| {
6045 let adapter = adapter.clone();
6046 if let Some(this) = this.upgrade() {
6047 adapter.process_diagnostics(&mut params);
6048 // Everything else has to be on the server, Can we make it on the client?
6049 this.update(&mut cx, |this, cx| {
6050 this.update_diagnostics(
6051 server_id,
6052 params,
6053 &adapter.disk_based_diagnostic_sources,
6054 cx,
6055 )
6056 .log_err();
6057 })
6058 .ok();
6059 }
6060 }
6061 })
6062 .detach();
6063
6064 language_server
6065 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
6066 let adapter = adapter.adapter.clone();
6067 let delegate = delegate.clone();
6068 move |params, mut cx| {
6069 let adapter = adapter.clone();
6070 let delegate = delegate.clone();
6071 async move {
6072 let workspace_config =
6073 adapter.workspace_configuration(&delegate, &mut cx).await?;
6074 Ok(params
6075 .items
6076 .into_iter()
6077 .map(|item| {
6078 if let Some(section) = &item.section {
6079 workspace_config
6080 .get(section)
6081 .cloned()
6082 .unwrap_or(serde_json::Value::Null)
6083 } else {
6084 workspace_config.clone()
6085 }
6086 })
6087 .collect())
6088 }
6089 }
6090 })
6091 .detach();
6092
6093 let id = language_server.server_id();
6094 language_server
6095 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
6096 let this = this.clone();
6097 move |_, mut cx| {
6098 let this = this.clone();
6099 async move {
6100 let Some(server) =
6101 this.update(&mut cx, |this, _| this.language_server_for_id(id))?
6102 else {
6103 return Ok(None);
6104 };
6105 let root = server.root_path();
6106 let Ok(uri) = Url::from_file_path(&root) else {
6107 return Ok(None);
6108 };
6109 Ok(Some(vec![WorkspaceFolder {
6110 uri,
6111 name: Default::default(),
6112 }]))
6113 }
6114 }
6115 })
6116 .detach();
6117 // Even though we don't have handling for these requests, respond to them to
6118 // avoid stalling any language server like `gopls` which waits for a response
6119 // to these requests when initializing.
6120 language_server
6121 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
6122 let this = this.clone();
6123 move |params, mut cx| {
6124 let this = this.clone();
6125 async move {
6126 this.update(&mut cx, |this, _| {
6127 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
6128 {
6129 if let lsp::NumberOrString::String(token) = params.token {
6130 status.progress_tokens.insert(token);
6131 }
6132 }
6133 })?;
6134
6135 Ok(())
6136 }
6137 }
6138 })
6139 .detach();
6140
6141 language_server
6142 .on_request::<lsp::request::RegisterCapability, _, _>({
6143 let this = this.clone();
6144 move |params, mut cx| {
6145 let this = this.clone();
6146 async move {
6147 for reg in params.registrations {
6148 match reg.method.as_str() {
6149 "workspace/didChangeWatchedFiles" => {
6150 if let Some(options) = reg.register_options {
6151 let options = serde_json::from_value(options)?;
6152 this.update(&mut cx, |this, cx| {
6153 this.on_lsp_did_change_watched_files(
6154 server_id, ®.id, options, cx,
6155 );
6156 })?;
6157 }
6158 }
6159 "textDocument/rangeFormatting" => {
6160 this.update(&mut cx, |this, _| {
6161 if let Some(server) = this.language_server_for_id(server_id)
6162 {
6163 let options = reg
6164 .register_options
6165 .map(|options| {
6166 serde_json::from_value::<
6167 lsp::DocumentRangeFormattingOptions,
6168 >(
6169 options
6170 )
6171 })
6172 .transpose()?;
6173 let provider = match options {
6174 None => OneOf::Left(true),
6175 Some(options) => OneOf::Right(options),
6176 };
6177 server.update_capabilities(|capabilities| {
6178 capabilities.document_range_formatting_provider =
6179 Some(provider);
6180 })
6181 }
6182 anyhow::Ok(())
6183 })??;
6184 }
6185 "textDocument/onTypeFormatting" => {
6186 this.update(&mut cx, |this, _| {
6187 if let Some(server) = this.language_server_for_id(server_id)
6188 {
6189 let options = reg
6190 .register_options
6191 .map(|options| {
6192 serde_json::from_value::<
6193 lsp::DocumentOnTypeFormattingOptions,
6194 >(
6195 options
6196 )
6197 })
6198 .transpose()?;
6199 if let Some(options) = options {
6200 server.update_capabilities(|capabilities| {
6201 capabilities
6202 .document_on_type_formatting_provider =
6203 Some(options);
6204 })
6205 }
6206 }
6207 anyhow::Ok(())
6208 })??;
6209 }
6210 "textDocument/formatting" => {
6211 this.update(&mut cx, |this, _| {
6212 if let Some(server) = this.language_server_for_id(server_id)
6213 {
6214 let options = reg
6215 .register_options
6216 .map(|options| {
6217 serde_json::from_value::<
6218 lsp::DocumentFormattingOptions,
6219 >(
6220 options
6221 )
6222 })
6223 .transpose()?;
6224 let provider = match options {
6225 None => OneOf::Left(true),
6226 Some(options) => OneOf::Right(options),
6227 };
6228 server.update_capabilities(|capabilities| {
6229 capabilities.document_formatting_provider =
6230 Some(provider);
6231 })
6232 }
6233 anyhow::Ok(())
6234 })??;
6235 }
6236 _ => log::warn!("unhandled capability registration: {reg:?}"),
6237 }
6238 }
6239 Ok(())
6240 }
6241 }
6242 })
6243 .detach();
6244
6245 language_server
6246 .on_request::<lsp::request::UnregisterCapability, _, _>({
6247 let this = this.clone();
6248 move |params, mut cx| {
6249 let this = this.clone();
6250 async move {
6251 for unreg in params.unregisterations.iter() {
6252 match unreg.method.as_str() {
6253 "workspace/didChangeWatchedFiles" => {
6254 this.update(&mut cx, |this, cx| {
6255 this.on_lsp_unregister_did_change_watched_files(
6256 server_id, &unreg.id, cx,
6257 );
6258 })?;
6259 }
6260 "textDocument/rangeFormatting" => {
6261 this.update(&mut cx, |this, _| {
6262 if let Some(server) = this.language_server_for_id(server_id)
6263 {
6264 server.update_capabilities(|capabilities| {
6265 capabilities.document_range_formatting_provider =
6266 None
6267 })
6268 }
6269 })?;
6270 }
6271 "textDocument/onTypeFormatting" => {
6272 this.update(&mut cx, |this, _| {
6273 if let Some(server) = this.language_server_for_id(server_id)
6274 {
6275 server.update_capabilities(|capabilities| {
6276 capabilities.document_on_type_formatting_provider =
6277 None;
6278 })
6279 }
6280 })?;
6281 }
6282 "textDocument/formatting" => {
6283 this.update(&mut cx, |this, _| {
6284 if let Some(server) = this.language_server_for_id(server_id)
6285 {
6286 server.update_capabilities(|capabilities| {
6287 capabilities.document_formatting_provider = None;
6288 })
6289 }
6290 })?;
6291 }
6292 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
6293 }
6294 }
6295 Ok(())
6296 }
6297 }
6298 })
6299 .detach();
6300
6301 language_server
6302 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
6303 let adapter = adapter.clone();
6304 let this = this.clone();
6305 move |params, cx| {
6306 Self::on_lsp_workspace_edit(
6307 this.clone(),
6308 params,
6309 server_id,
6310 adapter.clone(),
6311 cx,
6312 )
6313 }
6314 })
6315 .detach();
6316
6317 language_server
6318 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
6319 let this = this.clone();
6320 move |(), mut cx| {
6321 let this = this.clone();
6322 async move {
6323 this.update(&mut cx, |this, cx| {
6324 cx.emit(LspStoreEvent::RefreshInlayHints);
6325 this.downstream_client.as_ref().map(|(client, project_id)| {
6326 client.send(proto::RefreshInlayHints {
6327 project_id: *project_id,
6328 })
6329 })
6330 })?
6331 .transpose()?;
6332 Ok(())
6333 }
6334 }
6335 })
6336 .detach();
6337
6338 language_server
6339 .on_request::<lsp::request::ShowMessageRequest, _, _>({
6340 let this = this.clone();
6341 let name = name.to_string();
6342 move |params, mut cx| {
6343 let this = this.clone();
6344 let name = name.to_string();
6345 async move {
6346 let actions = params.actions.unwrap_or_default();
6347 let (tx, mut rx) = smol::channel::bounded(1);
6348 let request = LanguageServerPromptRequest {
6349 level: match params.typ {
6350 lsp::MessageType::ERROR => PromptLevel::Critical,
6351 lsp::MessageType::WARNING => PromptLevel::Warning,
6352 _ => PromptLevel::Info,
6353 },
6354 message: params.message,
6355 actions,
6356 response_channel: tx,
6357 lsp_name: name.clone(),
6358 };
6359
6360 let did_update = this
6361 .update(&mut cx, |_, cx| {
6362 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
6363 })
6364 .is_ok();
6365 if did_update {
6366 let response = rx.next().await;
6367
6368 Ok(response)
6369 } else {
6370 Ok(None)
6371 }
6372 }
6373 }
6374 })
6375 .detach();
6376
6377 let disk_based_diagnostics_progress_token =
6378 adapter.disk_based_diagnostics_progress_token.clone();
6379
6380 language_server
6381 .on_notification::<ServerStatus, _>({
6382 let this = this.clone();
6383 let name = name.to_string();
6384 move |params, mut cx| {
6385 let this = this.clone();
6386 let name = name.to_string();
6387 if let Some(ref message) = params.message {
6388 let message = message.trim();
6389 if !message.is_empty() {
6390 let formatted_message = format!(
6391 "Language server {name} (id {server_id}) status update: {message}"
6392 );
6393 match params.health {
6394 ServerHealthStatus::Ok => log::info!("{}", formatted_message),
6395 ServerHealthStatus::Warning => log::warn!("{}", formatted_message),
6396 ServerHealthStatus::Error => {
6397 log::error!("{}", formatted_message);
6398 let (tx, _rx) = smol::channel::bounded(1);
6399 let request = LanguageServerPromptRequest {
6400 level: PromptLevel::Critical,
6401 message: params.message.unwrap_or_default(),
6402 actions: Vec::new(),
6403 response_channel: tx,
6404 lsp_name: name.clone(),
6405 };
6406 let _ = this
6407 .update(&mut cx, |_, cx| {
6408 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
6409 })
6410 .ok();
6411 }
6412 ServerHealthStatus::Other(status) => {
6413 log::info!(
6414 "Unknown server health: {status}\n{formatted_message}"
6415 )
6416 }
6417 }
6418 }
6419 }
6420 }
6421 })
6422 .detach();
6423 language_server
6424 .on_notification::<lsp::notification::ShowMessage, _>({
6425 let this = this.clone();
6426 let name = name.to_string();
6427 move |params, mut cx| {
6428 let this = this.clone();
6429 let name = name.to_string();
6430
6431 let (tx, _) = smol::channel::bounded(1);
6432 let request = LanguageServerPromptRequest {
6433 level: match params.typ {
6434 lsp::MessageType::ERROR => PromptLevel::Critical,
6435 lsp::MessageType::WARNING => PromptLevel::Warning,
6436 _ => PromptLevel::Info,
6437 },
6438 message: params.message,
6439 actions: vec![],
6440 response_channel: tx,
6441 lsp_name: name.clone(),
6442 };
6443
6444 let _ = this.update(&mut cx, |_, cx| {
6445 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
6446 });
6447 }
6448 })
6449 .detach();
6450 language_server
6451 .on_notification::<lsp::notification::Progress, _>({
6452 let this = this.clone();
6453 move |params, mut cx| {
6454 if let Some(this) = this.upgrade() {
6455 this.update(&mut cx, |this, cx| {
6456 this.on_lsp_progress(
6457 params,
6458 server_id,
6459 disk_based_diagnostics_progress_token.clone(),
6460 cx,
6461 );
6462 })
6463 .ok();
6464 }
6465 }
6466 })
6467 .detach();
6468
6469 language_server
6470 .on_notification::<lsp::notification::LogMessage, _>({
6471 let this = this.clone();
6472 move |params, mut cx| {
6473 if let Some(this) = this.upgrade() {
6474 this.update(&mut cx, |_, cx| {
6475 cx.emit(LspStoreEvent::LanguageServerLog(
6476 server_id,
6477 LanguageServerLogType::Log(params.typ),
6478 params.message,
6479 ));
6480 })
6481 .ok();
6482 }
6483 }
6484 })
6485 .detach();
6486
6487 language_server
6488 .on_notification::<lsp::notification::LogTrace, _>({
6489 let this = this.clone();
6490 move |params, mut cx| {
6491 if let Some(this) = this.upgrade() {
6492 this.update(&mut cx, |_, cx| {
6493 cx.emit(LspStoreEvent::LanguageServerLog(
6494 server_id,
6495 LanguageServerLogType::Trace(params.verbose),
6496 params.message,
6497 ));
6498 })
6499 .ok();
6500 }
6501 }
6502 })
6503 .detach();
6504
6505 match (&mut initialization_options, override_options) {
6506 (Some(initialization_options), Some(override_options)) => {
6507 merge_json_value_into(override_options, initialization_options);
6508 }
6509 (None, override_options) => initialization_options = override_options,
6510 _ => {}
6511 }
6512
6513 let language_server = cx
6514 .update(|cx| language_server.initialize(initialization_options, cx))?
6515 .await
6516 .inspect_err(|_| {
6517 if let Some(this) = this.upgrade() {
6518 this.update(cx, |_, cx| {
6519 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
6520 })
6521 .ok();
6522 }
6523 })?;
6524
6525 language_server
6526 .notify::<lsp::notification::DidChangeConfiguration>(
6527 lsp::DidChangeConfigurationParams {
6528 settings: workspace_config,
6529 },
6530 )
6531 .ok();
6532
6533 Ok(language_server)
6534 }
6535
6536 pub fn update_diagnostics(
6537 &mut self,
6538 language_server_id: LanguageServerId,
6539 mut params: lsp::PublishDiagnosticsParams,
6540 disk_based_sources: &[String],
6541 cx: &mut ModelContext<Self>,
6542 ) -> Result<()> {
6543 let abs_path = params
6544 .uri
6545 .to_file_path()
6546 .map_err(|_| anyhow!("URI is not a file"))?;
6547 let mut diagnostics = Vec::default();
6548 let mut primary_diagnostic_group_ids = HashMap::default();
6549 let mut sources_by_group_id = HashMap::default();
6550 let mut supporting_diagnostics = HashMap::default();
6551
6552 // Ensure that primary diagnostics are always the most severe
6553 params.diagnostics.sort_by_key(|item| item.severity);
6554
6555 for diagnostic in ¶ms.diagnostics {
6556 let source = diagnostic.source.as_ref();
6557 let code = diagnostic.code.as_ref().map(|code| match code {
6558 lsp::NumberOrString::Number(code) => code.to_string(),
6559 lsp::NumberOrString::String(code) => code.clone(),
6560 });
6561 let range = range_from_lsp(diagnostic.range);
6562 let is_supporting = diagnostic
6563 .related_information
6564 .as_ref()
6565 .map_or(false, |infos| {
6566 infos.iter().any(|info| {
6567 primary_diagnostic_group_ids.contains_key(&(
6568 source,
6569 code.clone(),
6570 range_from_lsp(info.location.range),
6571 ))
6572 })
6573 });
6574
6575 let is_unnecessary = diagnostic.tags.as_ref().map_or(false, |tags| {
6576 tags.iter().any(|tag| *tag == DiagnosticTag::UNNECESSARY)
6577 });
6578
6579 if is_supporting {
6580 supporting_diagnostics.insert(
6581 (source, code.clone(), range),
6582 (diagnostic.severity, is_unnecessary),
6583 );
6584 } else {
6585 let group_id = post_inc(&mut self.next_diagnostic_group_id);
6586 let is_disk_based =
6587 source.map_or(false, |source| disk_based_sources.contains(source));
6588
6589 sources_by_group_id.insert(group_id, source);
6590 primary_diagnostic_group_ids
6591 .insert((source, code.clone(), range.clone()), group_id);
6592
6593 diagnostics.push(DiagnosticEntry {
6594 range,
6595 diagnostic: Diagnostic {
6596 source: diagnostic.source.clone(),
6597 code: code.clone(),
6598 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
6599 message: diagnostic.message.trim().to_string(),
6600 group_id,
6601 is_primary: true,
6602 is_disk_based,
6603 is_unnecessary,
6604 data: diagnostic.data.clone(),
6605 },
6606 });
6607 if let Some(infos) = &diagnostic.related_information {
6608 for info in infos {
6609 if info.location.uri == params.uri && !info.message.is_empty() {
6610 let range = range_from_lsp(info.location.range);
6611 diagnostics.push(DiagnosticEntry {
6612 range,
6613 diagnostic: Diagnostic {
6614 source: diagnostic.source.clone(),
6615 code: code.clone(),
6616 severity: DiagnosticSeverity::INFORMATION,
6617 message: info.message.trim().to_string(),
6618 group_id,
6619 is_primary: false,
6620 is_disk_based,
6621 is_unnecessary: false,
6622 data: diagnostic.data.clone(),
6623 },
6624 });
6625 }
6626 }
6627 }
6628 }
6629 }
6630
6631 for entry in &mut diagnostics {
6632 let diagnostic = &mut entry.diagnostic;
6633 if !diagnostic.is_primary {
6634 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
6635 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
6636 source,
6637 diagnostic.code.clone(),
6638 entry.range.clone(),
6639 )) {
6640 if let Some(severity) = severity {
6641 diagnostic.severity = severity;
6642 }
6643 diagnostic.is_unnecessary = is_unnecessary;
6644 }
6645 }
6646 }
6647
6648 self.update_diagnostic_entries(
6649 language_server_id,
6650 abs_path,
6651 params.version,
6652 diagnostics,
6653 cx,
6654 )?;
6655 Ok(())
6656 }
6657
6658 fn insert_newly_running_language_server(
6659 &mut self,
6660 language: LanguageName,
6661 adapter: Arc<CachedLspAdapter>,
6662 language_server: Arc<LanguageServer>,
6663 server_id: LanguageServerId,
6664 key: (WorktreeId, LanguageServerName),
6665 cx: &mut ModelContext<Self>,
6666 ) -> Result<()> {
6667 // If the language server for this key doesn't match the server id, don't store the
6668 // server. Which will cause it to be dropped, killing the process
6669 if self
6670 .language_server_ids
6671 .get(&key)
6672 .map(|id| id != &server_id)
6673 .unwrap_or(false)
6674 {
6675 return Ok(());
6676 }
6677
6678 // Update language_servers collection with Running variant of LanguageServerState
6679 // indicating that the server is up and running and ready
6680 if let Some(local) = self.as_local_mut() {
6681 local.language_servers.insert(
6682 server_id,
6683 LanguageServerState::Running {
6684 adapter: adapter.clone(),
6685 language: language.clone(),
6686 server: language_server.clone(),
6687 simulate_disk_based_diagnostics_completion: None,
6688 },
6689 );
6690 }
6691
6692 self.language_server_statuses.insert(
6693 server_id,
6694 LanguageServerStatus {
6695 name: language_server.name().to_string(),
6696 pending_work: Default::default(),
6697 has_pending_diagnostic_updates: false,
6698 progress_tokens: Default::default(),
6699 },
6700 );
6701
6702 cx.emit(LspStoreEvent::LanguageServerAdded(server_id));
6703
6704 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
6705 downstream_client.send(proto::StartLanguageServer {
6706 project_id: *project_id,
6707 server: Some(proto::LanguageServer {
6708 id: server_id.0 as u64,
6709 name: language_server.name().to_string(),
6710 }),
6711 })?;
6712 }
6713
6714 // Tell the language server about every open buffer in the worktree that matches the language.
6715 self.buffer_store.update(cx, |buffer_store, cx| {
6716 for buffer_handle in buffer_store.buffers() {
6717 let buffer = buffer_handle.read(cx);
6718 let file = match File::from_dyn(buffer.file()) {
6719 Some(file) => file,
6720 None => continue,
6721 };
6722 let language = match buffer.language() {
6723 Some(language) => language,
6724 None => continue,
6725 };
6726
6727 if file.worktree.read(cx).id() != key.0
6728 || !self
6729 .languages
6730 .lsp_adapters(&language.name())
6731 .iter()
6732 .any(|a| a.name == key.1)
6733 {
6734 continue;
6735 }
6736
6737 let file = match file.as_local() {
6738 Some(file) => file,
6739 None => continue,
6740 };
6741
6742 let versions = self
6743 .buffer_snapshots
6744 .entry(buffer.remote_id())
6745 .or_default()
6746 .entry(server_id)
6747 .or_insert_with(|| {
6748 vec![LspBufferSnapshot {
6749 version: 0,
6750 snapshot: buffer.text_snapshot(),
6751 }]
6752 });
6753
6754 let snapshot = versions.last().unwrap();
6755 let version = snapshot.version;
6756 let initial_snapshot = &snapshot.snapshot;
6757 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
6758 language_server.notify::<lsp::notification::DidOpenTextDocument>(
6759 lsp::DidOpenTextDocumentParams {
6760 text_document: lsp::TextDocumentItem::new(
6761 uri,
6762 adapter.language_id(&language.name()),
6763 version,
6764 initial_snapshot.text(),
6765 ),
6766 },
6767 )?;
6768
6769 buffer_handle.update(cx, |buffer, cx| {
6770 buffer.set_completion_triggers(
6771 language_server
6772 .capabilities()
6773 .completion_provider
6774 .as_ref()
6775 .and_then(|provider| provider.trigger_characters.clone())
6776 .unwrap_or_default(),
6777 cx,
6778 )
6779 });
6780 }
6781 anyhow::Ok(())
6782 })?;
6783
6784 cx.notify();
6785 Ok(())
6786 }
6787
6788 fn buffer_snapshot_for_lsp_version(
6789 &mut self,
6790 buffer: &Model<Buffer>,
6791 server_id: LanguageServerId,
6792 version: Option<i32>,
6793 cx: &AppContext,
6794 ) -> Result<TextBufferSnapshot> {
6795 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
6796
6797 if let Some(version) = version {
6798 let buffer_id = buffer.read(cx).remote_id();
6799 let snapshots = self
6800 .buffer_snapshots
6801 .get_mut(&buffer_id)
6802 .and_then(|m| m.get_mut(&server_id))
6803 .ok_or_else(|| {
6804 anyhow!("no snapshots found for buffer {buffer_id} and server {server_id}")
6805 })?;
6806
6807 let found_snapshot = snapshots
6808 .binary_search_by_key(&version, |e| e.version)
6809 .map(|ix| snapshots[ix].snapshot.clone())
6810 .map_err(|_| {
6811 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
6812 })?;
6813
6814 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
6815 Ok(found_snapshot)
6816 } else {
6817 Ok((buffer.read(cx)).text_snapshot())
6818 }
6819 }
6820
6821 pub fn language_servers_running_disk_based_diagnostics(
6822 &self,
6823 ) -> impl Iterator<Item = LanguageServerId> + '_ {
6824 self.language_server_statuses
6825 .iter()
6826 .filter_map(|(id, status)| {
6827 if status.has_pending_diagnostic_updates {
6828 Some(*id)
6829 } else {
6830 None
6831 }
6832 })
6833 }
6834
6835 pub(crate) fn language_servers_for_buffer<'a>(
6836 &'a self,
6837 buffer: &'a Buffer,
6838 cx: &'a AppContext,
6839 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
6840 self.language_server_ids_for_buffer(buffer, cx)
6841 .into_iter()
6842 .filter_map(
6843 |server_id| match self.as_local()?.language_servers.get(&server_id)? {
6844 LanguageServerState::Running {
6845 adapter, server, ..
6846 } => Some((adapter, server)),
6847 _ => None,
6848 },
6849 )
6850 }
6851
6852 pub(crate) fn cancel_language_server_work_for_buffers(
6853 &mut self,
6854 buffers: impl IntoIterator<Item = Model<Buffer>>,
6855 cx: &mut ModelContext<Self>,
6856 ) {
6857 let servers = buffers
6858 .into_iter()
6859 .flat_map(|buffer| {
6860 self.language_server_ids_for_buffer(buffer.read(cx), cx)
6861 .into_iter()
6862 })
6863 .collect::<HashSet<_>>();
6864
6865 for server_id in servers {
6866 self.cancel_language_server_work(server_id, None, cx);
6867 }
6868 }
6869
6870 pub fn language_servers(
6871 &self,
6872 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName, WorktreeId)> {
6873 self.language_server_ids
6874 .iter()
6875 .map(|((worktree_id, server_name), server_id)| {
6876 (*server_id, server_name.clone(), *worktree_id)
6877 })
6878 }
6879
6880 pub fn register_supplementary_language_server(
6881 &mut self,
6882 id: LanguageServerId,
6883 name: LanguageServerName,
6884 server: Arc<LanguageServer>,
6885 cx: &mut ModelContext<Self>,
6886 ) {
6887 if let Some(local) = self.as_local_mut() {
6888 local
6889 .supplementary_language_servers
6890 .insert(id, (name, server));
6891 cx.emit(LspStoreEvent::LanguageServerAdded(id));
6892 }
6893 }
6894
6895 pub fn unregister_supplementary_language_server(
6896 &mut self,
6897 id: LanguageServerId,
6898 cx: &mut ModelContext<Self>,
6899 ) {
6900 if let Some(local) = self.as_local_mut() {
6901 local.supplementary_language_servers.remove(&id);
6902 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
6903 }
6904 }
6905
6906 pub fn supplementary_language_servers(
6907 &self,
6908 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
6909 self.as_local().into_iter().flat_map(|local| {
6910 local
6911 .supplementary_language_servers
6912 .iter()
6913 .map(|(id, (name, _))| (*id, name.clone()))
6914 })
6915 }
6916
6917 pub fn language_server_adapter_for_id(
6918 &self,
6919 id: LanguageServerId,
6920 ) -> Option<Arc<CachedLspAdapter>> {
6921 self.as_local()
6922 .and_then(|local| local.language_servers.get(&id))
6923 .and_then(|language_server_state| match language_server_state {
6924 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
6925 _ => None,
6926 })
6927 }
6928
6929 pub(super) fn update_local_worktree_language_servers(
6930 &mut self,
6931 worktree_handle: &Model<Worktree>,
6932 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
6933 cx: &mut ModelContext<Self>,
6934 ) {
6935 if changes.is_empty() {
6936 return;
6937 }
6938
6939 let Some(local) = self.as_local() else { return };
6940
6941 local.prettier_store.update(cx, |prettier_store, cx| {
6942 prettier_store.update_prettier_settings(&worktree_handle, changes, cx)
6943 });
6944
6945 let worktree_id = worktree_handle.read(cx).id();
6946 let mut language_server_ids = self
6947 .language_server_ids
6948 .iter()
6949 .filter_map(|((server_worktree_id, _), server_id)| {
6950 (*server_worktree_id == worktree_id).then_some(*server_id)
6951 })
6952 .collect::<Vec<_>>();
6953 language_server_ids.sort();
6954 language_server_ids.dedup();
6955
6956 let abs_path = worktree_handle.read(cx).abs_path();
6957 for server_id in &language_server_ids {
6958 if let Some(LanguageServerState::Running { server, .. }) =
6959 local.language_servers.get(server_id)
6960 {
6961 if let Some(watched_paths) = local
6962 .language_server_watched_paths
6963 .get(server_id)
6964 .and_then(|paths| paths.read(cx).worktree_paths.get(&worktree_id))
6965 {
6966 let params = lsp::DidChangeWatchedFilesParams {
6967 changes: changes
6968 .iter()
6969 .filter_map(|(path, _, change)| {
6970 if !watched_paths.is_match(path) {
6971 return None;
6972 }
6973 let typ = match change {
6974 PathChange::Loaded => return None,
6975 PathChange::Added => lsp::FileChangeType::CREATED,
6976 PathChange::Removed => lsp::FileChangeType::DELETED,
6977 PathChange::Updated => lsp::FileChangeType::CHANGED,
6978 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
6979 };
6980 Some(lsp::FileEvent {
6981 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
6982 typ,
6983 })
6984 })
6985 .collect(),
6986 };
6987 if !params.changes.is_empty() {
6988 server
6989 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
6990 .log_err();
6991 }
6992 }
6993 }
6994 }
6995 }
6996
6997 pub(crate) fn cancel_language_server_work(
6998 &mut self,
6999 server_id: LanguageServerId,
7000 token_to_cancel: Option<String>,
7001 _cx: &mut ModelContext<Self>,
7002 ) {
7003 let Some(local) = self.as_local() else {
7004 return;
7005 };
7006 let status = self.language_server_statuses.get(&server_id);
7007 let server = local.language_servers.get(&server_id);
7008 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status) {
7009 for (token, progress) in &status.pending_work {
7010 if let Some(token_to_cancel) = token_to_cancel.as_ref() {
7011 if token != token_to_cancel {
7012 continue;
7013 }
7014 }
7015 if progress.is_cancellable {
7016 server
7017 .notify::<lsp::notification::WorkDoneProgressCancel>(
7018 WorkDoneProgressCancelParams {
7019 token: lsp::NumberOrString::String(token.clone()),
7020 },
7021 )
7022 .ok();
7023 }
7024
7025 if progress.is_cancellable {
7026 server
7027 .notify::<lsp::notification::WorkDoneProgressCancel>(
7028 WorkDoneProgressCancelParams {
7029 token: lsp::NumberOrString::String(token.clone()),
7030 },
7031 )
7032 .ok();
7033 }
7034 }
7035 }
7036 }
7037
7038 pub fn wait_for_remote_buffer(
7039 &mut self,
7040 id: BufferId,
7041 cx: &mut ModelContext<Self>,
7042 ) -> Task<Result<Model<Buffer>>> {
7043 self.buffer_store.update(cx, |buffer_store, cx| {
7044 buffer_store.wait_for_remote_buffer(id, cx)
7045 })
7046 }
7047
7048 pub(crate) fn language_server_ids_for_buffer(
7049 &self,
7050 buffer: &Buffer,
7051 cx: &AppContext,
7052 ) -> Vec<LanguageServerId> {
7053 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
7054 let worktree_id = file.worktree_id(cx);
7055 self.languages
7056 .lsp_adapters(&language.name())
7057 .iter()
7058 .flat_map(|adapter| {
7059 let key = (worktree_id, adapter.name.clone());
7060 self.language_server_ids.get(&key).copied()
7061 })
7062 .collect()
7063 } else {
7064 Vec::new()
7065 }
7066 }
7067
7068 pub async fn deserialize_text_edits(
7069 this: Model<Self>,
7070 buffer_to_edit: Model<Buffer>,
7071 edits: Vec<lsp::TextEdit>,
7072 push_to_history: bool,
7073 _: Arc<CachedLspAdapter>,
7074 language_server: Arc<LanguageServer>,
7075 cx: &mut AsyncAppContext,
7076 ) -> Result<Option<Transaction>> {
7077 let edits = this
7078 .update(cx, |this, cx| {
7079 this.edits_from_lsp(
7080 &buffer_to_edit,
7081 edits,
7082 language_server.server_id(),
7083 None,
7084 cx,
7085 )
7086 })?
7087 .await?;
7088
7089 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
7090 buffer.finalize_last_transaction();
7091 buffer.start_transaction();
7092 for (range, text) in edits {
7093 buffer.edit([(range, text)], None, cx);
7094 }
7095
7096 if buffer.end_transaction(cx).is_some() {
7097 let transaction = buffer.finalize_last_transaction().unwrap().clone();
7098 if !push_to_history {
7099 buffer.forget_transaction(transaction.id);
7100 }
7101 Some(transaction)
7102 } else {
7103 None
7104 }
7105 })?;
7106
7107 Ok(transaction)
7108 }
7109
7110 pub async fn deserialize_workspace_edit(
7111 this: Model<Self>,
7112 edit: lsp::WorkspaceEdit,
7113 push_to_history: bool,
7114 lsp_adapter: Arc<CachedLspAdapter>,
7115 language_server: Arc<LanguageServer>,
7116 cx: &mut AsyncAppContext,
7117 ) -> Result<ProjectTransaction> {
7118 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
7119
7120 let mut operations = Vec::new();
7121 if let Some(document_changes) = edit.document_changes {
7122 match document_changes {
7123 lsp::DocumentChanges::Edits(edits) => {
7124 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
7125 }
7126 lsp::DocumentChanges::Operations(ops) => operations = ops,
7127 }
7128 } else if let Some(changes) = edit.changes {
7129 operations.extend(changes.into_iter().map(|(uri, edits)| {
7130 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
7131 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
7132 uri,
7133 version: None,
7134 },
7135 edits: edits.into_iter().map(Edit::Plain).collect(),
7136 })
7137 }));
7138 }
7139
7140 let mut project_transaction = ProjectTransaction::default();
7141 for operation in operations {
7142 match operation {
7143 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
7144 let abs_path = op
7145 .uri
7146 .to_file_path()
7147 .map_err(|_| anyhow!("can't convert URI to path"))?;
7148
7149 if let Some(parent_path) = abs_path.parent() {
7150 fs.create_dir(parent_path).await?;
7151 }
7152 if abs_path.ends_with("/") {
7153 fs.create_dir(&abs_path).await?;
7154 } else {
7155 fs.create_file(
7156 &abs_path,
7157 op.options
7158 .map(|options| fs::CreateOptions {
7159 overwrite: options.overwrite.unwrap_or(false),
7160 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
7161 })
7162 .unwrap_or_default(),
7163 )
7164 .await?;
7165 }
7166 }
7167
7168 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
7169 let source_abs_path = op
7170 .old_uri
7171 .to_file_path()
7172 .map_err(|_| anyhow!("can't convert URI to path"))?;
7173 let target_abs_path = op
7174 .new_uri
7175 .to_file_path()
7176 .map_err(|_| anyhow!("can't convert URI to path"))?;
7177 fs.rename(
7178 &source_abs_path,
7179 &target_abs_path,
7180 op.options
7181 .map(|options| fs::RenameOptions {
7182 overwrite: options.overwrite.unwrap_or(false),
7183 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
7184 })
7185 .unwrap_or_default(),
7186 )
7187 .await?;
7188 }
7189
7190 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
7191 let abs_path = op
7192 .uri
7193 .to_file_path()
7194 .map_err(|_| anyhow!("can't convert URI to path"))?;
7195 let options = op
7196 .options
7197 .map(|options| fs::RemoveOptions {
7198 recursive: options.recursive.unwrap_or(false),
7199 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
7200 })
7201 .unwrap_or_default();
7202 if abs_path.ends_with("/") {
7203 fs.remove_dir(&abs_path, options).await?;
7204 } else {
7205 fs.remove_file(&abs_path, options).await?;
7206 }
7207 }
7208
7209 lsp::DocumentChangeOperation::Edit(op) => {
7210 let buffer_to_edit = this
7211 .update(cx, |this, cx| {
7212 this.open_local_buffer_via_lsp(
7213 op.text_document.uri.clone(),
7214 language_server.server_id(),
7215 lsp_adapter.name.clone(),
7216 cx,
7217 )
7218 })?
7219 .await?;
7220
7221 let edits = this
7222 .update(cx, |this, cx| {
7223 let path = buffer_to_edit.read(cx).project_path(cx);
7224 let active_entry = this.active_entry;
7225 let is_active_entry = path.clone().map_or(false, |project_path| {
7226 this.worktree_store
7227 .read(cx)
7228 .entry_for_path(&project_path, cx)
7229 .map_or(false, |entry| Some(entry.id) == active_entry)
7230 });
7231
7232 let (mut edits, mut snippet_edits) = (vec![], vec![]);
7233 for edit in op.edits {
7234 match edit {
7235 Edit::Plain(edit) => edits.push(edit),
7236 Edit::Annotated(edit) => edits.push(edit.text_edit),
7237 Edit::Snippet(edit) => {
7238 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
7239 else {
7240 continue;
7241 };
7242
7243 if is_active_entry {
7244 snippet_edits.push((edit.range, snippet));
7245 } else {
7246 // Since this buffer is not focused, apply a normal edit.
7247 edits.push(TextEdit {
7248 range: edit.range,
7249 new_text: snippet.text,
7250 });
7251 }
7252 }
7253 }
7254 }
7255 if !snippet_edits.is_empty() {
7256 let buffer_id = buffer_to_edit.read(cx).remote_id();
7257 let version = if let Some(buffer_version) = op.text_document.version
7258 {
7259 this.buffer_snapshot_for_lsp_version(
7260 &buffer_to_edit,
7261 language_server.server_id(),
7262 Some(buffer_version),
7263 cx,
7264 )
7265 .ok()
7266 .map(|snapshot| snapshot.version)
7267 } else {
7268 Some(buffer_to_edit.read(cx).saved_version().clone())
7269 };
7270
7271 let most_recent_edit = version.and_then(|version| {
7272 version.iter().max_by_key(|timestamp| timestamp.value)
7273 });
7274 // Check if the edit that triggered that edit has been made by this participant.
7275
7276 if let Some(most_recent_edit) = most_recent_edit {
7277 cx.emit(LspStoreEvent::SnippetEdit {
7278 buffer_id,
7279 edits: snippet_edits,
7280 most_recent_edit,
7281 });
7282 }
7283 }
7284
7285 this.edits_from_lsp(
7286 &buffer_to_edit,
7287 edits,
7288 language_server.server_id(),
7289 op.text_document.version,
7290 cx,
7291 )
7292 })?
7293 .await?;
7294
7295 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
7296 buffer.finalize_last_transaction();
7297 buffer.start_transaction();
7298 for (range, text) in edits {
7299 buffer.edit([(range, text)], None, cx);
7300 }
7301 let transaction = if buffer.end_transaction(cx).is_some() {
7302 let transaction = buffer.finalize_last_transaction().unwrap().clone();
7303 if !push_to_history {
7304 buffer.forget_transaction(transaction.id);
7305 }
7306 Some(transaction)
7307 } else {
7308 None
7309 };
7310
7311 transaction
7312 })?;
7313 if let Some(transaction) = transaction {
7314 project_transaction.0.insert(buffer_to_edit, transaction);
7315 }
7316 }
7317 }
7318 }
7319
7320 Ok(project_transaction)
7321 }
7322
7323 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
7324 proto::Symbol {
7325 language_server_name: symbol.language_server_name.0.to_string(),
7326 source_worktree_id: symbol.source_worktree_id.to_proto(),
7327 worktree_id: symbol.path.worktree_id.to_proto(),
7328 path: symbol.path.path.to_string_lossy().to_string(),
7329 name: symbol.name.clone(),
7330 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
7331 start: Some(proto::PointUtf16 {
7332 row: symbol.range.start.0.row,
7333 column: symbol.range.start.0.column,
7334 }),
7335 end: Some(proto::PointUtf16 {
7336 row: symbol.range.end.0.row,
7337 column: symbol.range.end.0.column,
7338 }),
7339 signature: symbol.signature.to_vec(),
7340 }
7341 }
7342
7343 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
7344 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
7345 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
7346 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
7347 let path = ProjectPath {
7348 worktree_id,
7349 path: PathBuf::from(serialized_symbol.path).into(),
7350 };
7351
7352 let start = serialized_symbol
7353 .start
7354 .ok_or_else(|| anyhow!("invalid start"))?;
7355 let end = serialized_symbol
7356 .end
7357 .ok_or_else(|| anyhow!("invalid end"))?;
7358 Ok(CoreSymbol {
7359 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
7360 source_worktree_id,
7361 path,
7362 name: serialized_symbol.name,
7363 range: Unclipped(PointUtf16::new(start.row, start.column))
7364 ..Unclipped(PointUtf16::new(end.row, end.column)),
7365 kind,
7366 signature: serialized_symbol
7367 .signature
7368 .try_into()
7369 .map_err(|_| anyhow!("invalid signature"))?,
7370 })
7371 }
7372
7373 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
7374 proto::Completion {
7375 old_start: Some(serialize_anchor(&completion.old_range.start)),
7376 old_end: Some(serialize_anchor(&completion.old_range.end)),
7377 new_text: completion.new_text.clone(),
7378 server_id: completion.server_id.0 as u64,
7379 lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
7380 }
7381 }
7382
7383 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
7384 let old_start = completion
7385 .old_start
7386 .and_then(deserialize_anchor)
7387 .ok_or_else(|| anyhow!("invalid old start"))?;
7388 let old_end = completion
7389 .old_end
7390 .and_then(deserialize_anchor)
7391 .ok_or_else(|| anyhow!("invalid old end"))?;
7392 let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
7393
7394 Ok(CoreCompletion {
7395 old_range: old_start..old_end,
7396 new_text: completion.new_text,
7397 server_id: LanguageServerId(completion.server_id as usize),
7398 lsp_completion,
7399 })
7400 }
7401
7402 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
7403 proto::CodeAction {
7404 server_id: action.server_id.0 as u64,
7405 start: Some(serialize_anchor(&action.range.start)),
7406 end: Some(serialize_anchor(&action.range.end)),
7407 lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
7408 }
7409 }
7410
7411 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
7412 let start = action
7413 .start
7414 .and_then(deserialize_anchor)
7415 .ok_or_else(|| anyhow!("invalid start"))?;
7416 let end = action
7417 .end
7418 .and_then(deserialize_anchor)
7419 .ok_or_else(|| anyhow!("invalid end"))?;
7420 let lsp_action = serde_json::from_slice(&action.lsp_action)?;
7421 Ok(CodeAction {
7422 server_id: LanguageServerId(action.server_id as usize),
7423 range: start..end,
7424 lsp_action,
7425 })
7426 }
7427}
7428
7429impl EventEmitter<LspStoreEvent> for LspStore {}
7430
7431fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
7432 hover
7433 .contents
7434 .retain(|hover_block| !hover_block.text.trim().is_empty());
7435 if hover.contents.is_empty() {
7436 None
7437 } else {
7438 Some(hover)
7439 }
7440}
7441
7442async fn populate_labels_for_completions(
7443 mut new_completions: Vec<CoreCompletion>,
7444 language_registry: &Arc<LanguageRegistry>,
7445 language: Option<Arc<Language>>,
7446 lsp_adapter: Option<Arc<CachedLspAdapter>>,
7447 completions: &mut Vec<Completion>,
7448) {
7449 let lsp_completions = new_completions
7450 .iter_mut()
7451 .map(|completion| mem::take(&mut completion.lsp_completion))
7452 .collect::<Vec<_>>();
7453
7454 let labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
7455 lsp_adapter
7456 .labels_for_completions(&lsp_completions, language)
7457 .await
7458 .log_err()
7459 .unwrap_or_default()
7460 } else {
7461 Vec::new()
7462 };
7463
7464 for ((completion, lsp_completion), label) in new_completions
7465 .into_iter()
7466 .zip(lsp_completions)
7467 .zip(labels.into_iter().chain(iter::repeat(None)))
7468 {
7469 let documentation = if let Some(docs) = &lsp_completion.documentation {
7470 Some(prepare_completion_documentation(docs, language_registry, language.clone()).await)
7471 } else {
7472 None
7473 };
7474
7475 completions.push(Completion {
7476 old_range: completion.old_range,
7477 new_text: completion.new_text,
7478 label: label.unwrap_or_else(|| {
7479 CodeLabel::plain(
7480 lsp_completion.label.clone(),
7481 lsp_completion.filter_text.as_deref(),
7482 )
7483 }),
7484 server_id: completion.server_id,
7485 documentation,
7486 lsp_completion,
7487 confirm: None,
7488 })
7489 }
7490}
7491
7492#[derive(Debug)]
7493pub enum LanguageServerToQuery {
7494 Primary,
7495 Other(LanguageServerId),
7496}
7497
7498#[derive(Default)]
7499struct LanguageServerWatchedPaths {
7500 worktree_paths: HashMap<WorktreeId, GlobSet>,
7501 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
7502}
7503
7504#[derive(Default)]
7505struct LanguageServerWatchedPathsBuilder {
7506 worktree_paths: HashMap<WorktreeId, GlobSet>,
7507 abs_paths: HashMap<Arc<Path>, GlobSet>,
7508}
7509
7510impl LanguageServerWatchedPathsBuilder {
7511 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
7512 self.worktree_paths.insert(worktree_id, glob_set);
7513 }
7514 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
7515 self.abs_paths.insert(path, glob_set);
7516 }
7517 fn build(
7518 self,
7519 fs: Arc<dyn Fs>,
7520 language_server_id: LanguageServerId,
7521 cx: &mut ModelContext<LspStore>,
7522 ) -> Model<LanguageServerWatchedPaths> {
7523 let project = cx.weak_model();
7524
7525 cx.new_model(|cx| {
7526 let this_id = cx.entity_id();
7527 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
7528 let abs_paths = self
7529 .abs_paths
7530 .into_iter()
7531 .map(|(abs_path, globset)| {
7532 let task = cx.spawn({
7533 let abs_path = abs_path.clone();
7534 let fs = fs.clone();
7535
7536 let lsp_store = project.clone();
7537 |_, mut cx| async move {
7538 maybe!(async move {
7539 let mut push_updates =
7540 fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
7541 while let Some(update) = push_updates.0.next().await {
7542 let action = lsp_store
7543 .update(&mut cx, |this, cx| {
7544 let Some(local) = this.as_local() else {
7545 return ControlFlow::Break(());
7546 };
7547 let Some(watcher) = local
7548 .language_server_watched_paths
7549 .get(&language_server_id)
7550 else {
7551 return ControlFlow::Break(());
7552 };
7553 if watcher.entity_id() != this_id {
7554 // This watcher is no longer registered on the project, which means that we should
7555 // cease operations.
7556 return ControlFlow::Break(());
7557 }
7558 let (globs, _) = watcher
7559 .read(cx)
7560 .abs_paths
7561 .get(&abs_path)
7562 .expect(
7563 "Watched abs path is not registered with a watcher",
7564 );
7565 let matching_entries = update
7566 .into_iter()
7567 .filter(|event| globs.is_match(&event.path))
7568 .collect::<Vec<_>>();
7569 this.lsp_notify_abs_paths_changed(
7570 language_server_id,
7571 matching_entries,
7572 );
7573 ControlFlow::Continue(())
7574 })
7575 .ok()?;
7576
7577 if action.is_break() {
7578 break;
7579 }
7580 }
7581 Some(())
7582 })
7583 .await;
7584 }
7585 });
7586 (abs_path, (globset, task))
7587 })
7588 .collect();
7589 LanguageServerWatchedPaths {
7590 worktree_paths: self.worktree_paths,
7591 abs_paths,
7592 }
7593 })
7594 }
7595}
7596
7597struct LspBufferSnapshot {
7598 version: i32,
7599 snapshot: TextBufferSnapshot,
7600}
7601
7602/// A prompt requested by LSP server.
7603#[derive(Clone, Debug)]
7604pub struct LanguageServerPromptRequest {
7605 pub level: PromptLevel,
7606 pub message: String,
7607 pub actions: Vec<MessageActionItem>,
7608 pub lsp_name: String,
7609 pub(crate) response_channel: Sender<MessageActionItem>,
7610}
7611
7612impl LanguageServerPromptRequest {
7613 pub async fn respond(self, index: usize) -> Option<()> {
7614 if let Some(response) = self.actions.into_iter().nth(index) {
7615 self.response_channel.send(response).await.ok()
7616 } else {
7617 None
7618 }
7619 }
7620}
7621impl PartialEq for LanguageServerPromptRequest {
7622 fn eq(&self, other: &Self) -> bool {
7623 self.message == other.message && self.actions == other.actions
7624 }
7625}
7626
7627#[derive(Clone, Debug, PartialEq)]
7628pub enum LanguageServerLogType {
7629 Log(MessageType),
7630 Trace(Option<String>),
7631}
7632
7633pub enum LanguageServerState {
7634 Starting(Task<Option<Arc<LanguageServer>>>),
7635
7636 Running {
7637 language: LanguageName,
7638 adapter: Arc<CachedLspAdapter>,
7639 server: Arc<LanguageServer>,
7640 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
7641 },
7642}
7643
7644impl std::fmt::Debug for LanguageServerState {
7645 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7646 match self {
7647 LanguageServerState::Starting(_) => {
7648 f.debug_struct("LanguageServerState::Starting").finish()
7649 }
7650 LanguageServerState::Running { language, .. } => f
7651 .debug_struct("LanguageServerState::Running")
7652 .field("language", &language)
7653 .finish(),
7654 }
7655 }
7656}
7657
7658#[derive(Clone, Debug, Serialize)]
7659pub struct LanguageServerProgress {
7660 pub is_disk_based_diagnostics_progress: bool,
7661 pub is_cancellable: bool,
7662 pub title: Option<String>,
7663 pub message: Option<String>,
7664 pub percentage: Option<usize>,
7665 #[serde(skip_serializing)]
7666 pub last_update_at: Instant,
7667}
7668
7669#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
7670pub struct DiagnosticSummary {
7671 pub error_count: usize,
7672 pub warning_count: usize,
7673}
7674
7675impl DiagnosticSummary {
7676 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
7677 let mut this = Self {
7678 error_count: 0,
7679 warning_count: 0,
7680 };
7681
7682 for entry in diagnostics {
7683 if entry.diagnostic.is_primary {
7684 match entry.diagnostic.severity {
7685 DiagnosticSeverity::ERROR => this.error_count += 1,
7686 DiagnosticSeverity::WARNING => this.warning_count += 1,
7687 _ => {}
7688 }
7689 }
7690 }
7691
7692 this
7693 }
7694
7695 pub fn is_empty(&self) -> bool {
7696 self.error_count == 0 && self.warning_count == 0
7697 }
7698
7699 pub fn to_proto(
7700 &self,
7701 language_server_id: LanguageServerId,
7702 path: &Path,
7703 ) -> proto::DiagnosticSummary {
7704 proto::DiagnosticSummary {
7705 path: path.to_string_lossy().to_string(),
7706 language_server_id: language_server_id.0 as u64,
7707 error_count: self.error_count as u32,
7708 warning_count: self.warning_count as u32,
7709 }
7710 }
7711}
7712
7713fn glob_literal_prefix(glob: &str) -> &str {
7714 let is_absolute = glob.starts_with(path::MAIN_SEPARATOR);
7715
7716 let mut literal_end = is_absolute as usize;
7717 for (i, part) in glob.split(path::MAIN_SEPARATOR).enumerate() {
7718 if part.contains(['*', '?', '{', '}']) {
7719 break;
7720 } else {
7721 if i > 0 {
7722 // Account for separator prior to this part
7723 literal_end += path::MAIN_SEPARATOR.len_utf8();
7724 }
7725 literal_end += part.len();
7726 }
7727 }
7728 let literal_end = literal_end.min(glob.len());
7729 &glob[..literal_end]
7730}
7731
7732pub struct SshLspAdapter {
7733 name: LanguageServerName,
7734 binary: LanguageServerBinary,
7735 initialization_options: Option<String>,
7736 code_action_kinds: Option<Vec<CodeActionKind>>,
7737}
7738
7739impl SshLspAdapter {
7740 pub fn new(
7741 name: LanguageServerName,
7742 binary: LanguageServerBinary,
7743 initialization_options: Option<String>,
7744 code_action_kinds: Option<String>,
7745 ) -> Self {
7746 Self {
7747 name,
7748 binary,
7749 initialization_options,
7750 code_action_kinds: code_action_kinds
7751 .as_ref()
7752 .and_then(|c| serde_json::from_str(c).ok()),
7753 }
7754 }
7755}
7756
7757#[async_trait(?Send)]
7758impl LspAdapter for SshLspAdapter {
7759 fn name(&self) -> LanguageServerName {
7760 self.name.clone()
7761 }
7762
7763 async fn initialization_options(
7764 self: Arc<Self>,
7765 _: &Arc<dyn LspAdapterDelegate>,
7766 ) -> Result<Option<serde_json::Value>> {
7767 let Some(options) = &self.initialization_options else {
7768 return Ok(None);
7769 };
7770 let result = serde_json::from_str(options)?;
7771 Ok(result)
7772 }
7773
7774 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
7775 self.code_action_kinds.clone()
7776 }
7777
7778 async fn check_if_user_installed(
7779 &self,
7780 _: &dyn LspAdapterDelegate,
7781 _: &AsyncAppContext,
7782 ) -> Option<LanguageServerBinary> {
7783 Some(self.binary.clone())
7784 }
7785
7786 async fn cached_server_binary(
7787 &self,
7788 _: PathBuf,
7789 _: &dyn LspAdapterDelegate,
7790 ) -> Option<LanguageServerBinary> {
7791 None
7792 }
7793
7794 async fn fetch_latest_server_version(
7795 &self,
7796 _: &dyn LspAdapterDelegate,
7797 ) -> Result<Box<dyn 'static + Send + Any>> {
7798 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
7799 }
7800
7801 async fn fetch_server_binary(
7802 &self,
7803 _: Box<dyn 'static + Send + Any>,
7804 _: PathBuf,
7805 _: &dyn LspAdapterDelegate,
7806 ) -> Result<LanguageServerBinary> {
7807 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
7808 }
7809
7810 async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
7811 None
7812 }
7813}
7814pub fn language_server_settings<'a, 'b: 'a>(
7815 delegate: &'a dyn LspAdapterDelegate,
7816 language: &LanguageServerName,
7817 cx: &'b AppContext,
7818) -> Option<&'a LspSettings> {
7819 ProjectSettings::get(
7820 Some(SettingsLocation {
7821 worktree_id: delegate.worktree_id(),
7822 path: delegate.worktree_root_path(),
7823 }),
7824 cx,
7825 )
7826 .lsp
7827 .get(language)
7828}
7829
7830pub struct LocalLspAdapterDelegate {
7831 lsp_store: WeakModel<LspStore>,
7832 worktree: worktree::Snapshot,
7833 fs: Arc<dyn Fs>,
7834 http_client: Arc<dyn HttpClient>,
7835 language_registry: Arc<LanguageRegistry>,
7836 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
7837}
7838
7839impl LocalLspAdapterDelegate {
7840 fn for_local(
7841 lsp_store: &LspStore,
7842 worktree: &Model<Worktree>,
7843 cx: &mut ModelContext<LspStore>,
7844 ) -> Arc<Self> {
7845 let local = lsp_store
7846 .as_local()
7847 .expect("LocalLspAdapterDelegate cannot be constructed on a remote");
7848
7849 let http_client = local
7850 .http_client
7851 .clone()
7852 .unwrap_or_else(|| Arc::new(BlockedHttpClient));
7853
7854 Self::new(lsp_store, worktree, http_client, local.fs.clone(), cx)
7855 }
7856
7857 // fn for_ssh(
7858 // lsp_store: &LspStore,
7859 // worktree: &Model<Worktree>,
7860 // upstream_client: AnyProtoClient,
7861 // cx: &mut ModelContext<LspStore>,
7862 // ) -> Arc<Self> {
7863 // Self::new(
7864 // lsp_store,
7865 // worktree,
7866 // Arc::new(BlockedHttpClient),
7867 // None,
7868 // Some(upstream_client),
7869 // cx,
7870 // )
7871 // }
7872
7873 pub fn new(
7874 lsp_store: &LspStore,
7875 worktree: &Model<Worktree>,
7876 http_client: Arc<dyn HttpClient>,
7877 fs: Arc<dyn Fs>,
7878 cx: &mut ModelContext<LspStore>,
7879 ) -> Arc<Self> {
7880 let worktree_id = worktree.read(cx).id();
7881 let worktree_abs_path = worktree.read(cx).abs_path();
7882 let load_shell_env_task = if let Some(environment) =
7883 &lsp_store.as_local().map(|local| local.environment.clone())
7884 {
7885 environment.update(cx, |env, cx| {
7886 env.get_environment(Some(worktree_id), Some(worktree_abs_path), cx)
7887 })
7888 } else {
7889 Task::ready(None).shared()
7890 };
7891
7892 Arc::new(Self {
7893 lsp_store: cx.weak_model(),
7894 worktree: worktree.read(cx).snapshot(),
7895 fs,
7896 http_client,
7897 language_registry: lsp_store.languages.clone(),
7898 load_shell_env_task,
7899 })
7900 }
7901}
7902
7903#[async_trait]
7904impl LspAdapterDelegate for LocalLspAdapterDelegate {
7905 fn show_notification(&self, message: &str, cx: &mut AppContext) {
7906 self.lsp_store
7907 .update(cx, |_, cx| {
7908 cx.emit(LspStoreEvent::Notification(message.to_owned()))
7909 })
7910 .ok();
7911 }
7912
7913 fn http_client(&self) -> Arc<dyn HttpClient> {
7914 self.http_client.clone()
7915 }
7916
7917 fn worktree_id(&self) -> WorktreeId {
7918 self.worktree.id()
7919 }
7920
7921 fn worktree_root_path(&self) -> &Path {
7922 self.worktree.abs_path().as_ref()
7923 }
7924
7925 async fn shell_env(&self) -> HashMap<String, String> {
7926 let task = self.load_shell_env_task.clone();
7927 task.await.unwrap_or_default()
7928 }
7929
7930 #[cfg(not(target_os = "windows"))]
7931 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
7932 let worktree_abs_path = self.worktree.abs_path();
7933 let shell_path = self.shell_env().await.get("PATH").cloned();
7934 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
7935 }
7936
7937 #[cfg(target_os = "windows")]
7938 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
7939 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
7940 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
7941 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
7942 which::which(command).ok()
7943 }
7944
7945 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
7946 let working_dir = self.worktree_root_path();
7947 let output = smol::process::Command::new(&command.path)
7948 .args(command.arguments)
7949 .envs(command.env.clone().unwrap_or_default())
7950 .current_dir(working_dir)
7951 .output()
7952 .await?;
7953
7954 if output.status.success() {
7955 return Ok(());
7956 }
7957 Err(anyhow!(
7958 "{}, stdout: {:?}, stderr: {:?}",
7959 output.status,
7960 String::from_utf8_lossy(&output.stdout),
7961 String::from_utf8_lossy(&output.stderr)
7962 ))
7963 }
7964
7965 fn update_status(
7966 &self,
7967 server_name: LanguageServerName,
7968 status: language::LanguageServerBinaryStatus,
7969 ) {
7970 self.language_registry
7971 .update_lsp_status(server_name, status);
7972 }
7973
7974 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
7975 if self.worktree.entry_for_path(&path).is_none() {
7976 return Err(anyhow!("no such path {path:?}"));
7977 };
7978 self.fs.load(&path).await
7979 }
7980}
7981
7982struct SshLspAdapterDelegate {
7983 lsp_store: WeakModel<LspStore>,
7984 worktree: worktree::Snapshot,
7985 upstream_client: AnyProtoClient,
7986 language_registry: Arc<LanguageRegistry>,
7987}
7988
7989#[async_trait]
7990impl LspAdapterDelegate for SshLspAdapterDelegate {
7991 fn show_notification(&self, message: &str, cx: &mut AppContext) {
7992 self.lsp_store
7993 .update(cx, |_, cx| {
7994 cx.emit(LspStoreEvent::Notification(message.to_owned()))
7995 })
7996 .ok();
7997 }
7998
7999 fn http_client(&self) -> Arc<dyn HttpClient> {
8000 Arc::new(BlockedHttpClient)
8001 }
8002
8003 fn worktree_id(&self) -> WorktreeId {
8004 self.worktree.id()
8005 }
8006
8007 fn worktree_root_path(&self) -> &Path {
8008 self.worktree.abs_path().as_ref()
8009 }
8010
8011 async fn shell_env(&self) -> HashMap<String, String> {
8012 use rpc::proto::SSH_PROJECT_ID;
8013
8014 self.upstream_client
8015 .request(proto::ShellEnv {
8016 project_id: SSH_PROJECT_ID,
8017 worktree_id: self.worktree_id().to_proto(),
8018 })
8019 .await
8020 .map(|response| response.env.into_iter().collect())
8021 .unwrap_or_default()
8022 }
8023
8024 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
8025 use rpc::proto::SSH_PROJECT_ID;
8026
8027 self.upstream_client
8028 .request(proto::WhichCommand {
8029 project_id: SSH_PROJECT_ID,
8030 worktree_id: self.worktree_id().to_proto(),
8031 command: command.to_string_lossy().to_string(),
8032 })
8033 .await
8034 .log_err()
8035 .and_then(|response| response.path)
8036 .map(PathBuf::from)
8037 }
8038
8039 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
8040 self.upstream_client
8041 .request(proto::TryExec {
8042 project_id: rpc::proto::SSH_PROJECT_ID,
8043 worktree_id: self.worktree.id().to_proto(),
8044 binary: Some(proto::LanguageServerCommand {
8045 path: command.path.to_string_lossy().to_string(),
8046 arguments: command
8047 .arguments
8048 .into_iter()
8049 .map(|s| s.to_string_lossy().to_string())
8050 .collect(),
8051 env: command.env.unwrap_or_default().into_iter().collect(),
8052 }),
8053 })
8054 .await?;
8055 Ok(())
8056 }
8057
8058 fn update_status(
8059 &self,
8060 server_name: LanguageServerName,
8061 status: language::LanguageServerBinaryStatus,
8062 ) {
8063 self.language_registry
8064 .update_lsp_status(server_name, status);
8065 }
8066
8067 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
8068 self.upstream_client
8069 .request(proto::ReadTextFile {
8070 project_id: rpc::proto::SSH_PROJECT_ID,
8071 path: Some(proto::ProjectPath {
8072 worktree_id: self.worktree.id().to_proto(),
8073 path: path.to_string_lossy().to_string(),
8074 }),
8075 })
8076 .await
8077 .map(|r| r.text)
8078 }
8079}
8080
8081async fn populate_labels_for_symbols(
8082 symbols: Vec<CoreSymbol>,
8083 language_registry: &Arc<LanguageRegistry>,
8084 default_language: Option<LanguageName>,
8085 lsp_adapter: Option<Arc<CachedLspAdapter>>,
8086 output: &mut Vec<Symbol>,
8087) {
8088 #[allow(clippy::mutable_key_type)]
8089 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
8090
8091 let mut unknown_path = None;
8092 for symbol in symbols {
8093 let language = language_registry
8094 .language_for_file_path(&symbol.path.path)
8095 .await
8096 .ok()
8097 .or_else(|| {
8098 unknown_path.get_or_insert(symbol.path.path.clone());
8099 default_language.as_ref().and_then(|name| {
8100 language_registry
8101 .language_for_name(&name.0)
8102 .now_or_never()?
8103 .ok()
8104 })
8105 });
8106 symbols_by_language
8107 .entry(language)
8108 .or_default()
8109 .push(symbol);
8110 }
8111
8112 if let Some(unknown_path) = unknown_path {
8113 log::info!(
8114 "no language found for symbol path {}",
8115 unknown_path.display()
8116 );
8117 }
8118
8119 let mut label_params = Vec::new();
8120 for (language, mut symbols) in symbols_by_language {
8121 label_params.clear();
8122 label_params.extend(
8123 symbols
8124 .iter_mut()
8125 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
8126 );
8127
8128 let mut labels = Vec::new();
8129 if let Some(language) = language {
8130 let lsp_adapter = lsp_adapter.clone().or_else(|| {
8131 language_registry
8132 .lsp_adapters(&language.name())
8133 .first()
8134 .cloned()
8135 });
8136 if let Some(lsp_adapter) = lsp_adapter {
8137 labels = lsp_adapter
8138 .labels_for_symbols(&label_params, &language)
8139 .await
8140 .log_err()
8141 .unwrap_or_default();
8142 }
8143 }
8144
8145 for ((symbol, (name, _)), label) in symbols
8146 .into_iter()
8147 .zip(label_params.drain(..))
8148 .zip(labels.into_iter().chain(iter::repeat(None)))
8149 {
8150 output.push(Symbol {
8151 language_server_name: symbol.language_server_name,
8152 source_worktree_id: symbol.source_worktree_id,
8153 path: symbol.path,
8154 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
8155 name,
8156 kind: symbol.kind,
8157 range: symbol.range,
8158 signature: symbol.signature,
8159 });
8160 }
8161 }
8162}
8163
8164fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
8165 match server.capabilities().text_document_sync.as_ref()? {
8166 lsp::TextDocumentSyncCapability::Kind(kind) => match *kind {
8167 lsp::TextDocumentSyncKind::NONE => None,
8168 lsp::TextDocumentSyncKind::FULL => Some(true),
8169 lsp::TextDocumentSyncKind::INCREMENTAL => Some(false),
8170 _ => None,
8171 },
8172 lsp::TextDocumentSyncCapability::Options(options) => match options.save.as_ref()? {
8173 lsp::TextDocumentSyncSaveOptions::Supported(supported) => {
8174 if *supported {
8175 Some(true)
8176 } else {
8177 None
8178 }
8179 }
8180 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
8181 Some(save_options.include_text.unwrap_or(false))
8182 }
8183 },
8184 }
8185}
8186
8187#[cfg(test)]
8188#[test]
8189fn test_glob_literal_prefix() {
8190 assert_eq!(glob_literal_prefix("**/*.js"), "");
8191 assert_eq!(glob_literal_prefix("node_modules/**/*.js"), "node_modules");
8192 assert_eq!(glob_literal_prefix("foo/{bar,baz}.js"), "foo");
8193 assert_eq!(glob_literal_prefix("foo/bar/baz.js"), "foo/bar/baz.js");
8194}