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