1mod db;
2pub mod fs;
3mod ignore;
4mod lsp_command;
5pub mod search;
6pub mod worktree;
7
8#[cfg(test)]
9mod project_tests;
10
11use anyhow::{anyhow, Context, Result};
12use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
13use clock::ReplicaId;
14use collections::{hash_map, BTreeMap, HashMap, HashSet};
15use futures::{future::Shared, AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt};
16use gpui::{
17 AnyModelHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
18 MutableAppContext, Task, UpgradeModelHandle, WeakModelHandle,
19};
20use language::{
21 point_to_lsp,
22 proto::{
23 deserialize_anchor, deserialize_line_ending, deserialize_version, serialize_anchor,
24 serialize_version,
25 },
26 range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CharKind, CodeAction, CodeLabel,
27 Completion, Diagnostic, DiagnosticEntry, DiagnosticSet, Event as BufferEvent, File as _,
28 Language, LanguageRegistry, LanguageServerName, LineEnding, LocalFile, LspAdapter,
29 OffsetRangeExt, Operation, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
30 Transaction,
31};
32use lsp::{
33 DiagnosticSeverity, DiagnosticTag, DocumentHighlightKind, LanguageServer, LanguageString,
34 MarkedString,
35};
36use lsp_command::*;
37use parking_lot::Mutex;
38use postage::stream::Stream;
39use postage::watch;
40use rand::prelude::*;
41use search::SearchQuery;
42use serde::Serialize;
43use settings::Settings;
44use sha2::{Digest, Sha256};
45use similar::{ChangeTag, TextDiff};
46use std::{
47 cell::RefCell,
48 cmp::{self, Ordering},
49 convert::TryInto,
50 ffi::OsString,
51 hash::Hash,
52 mem,
53 num::NonZeroU32,
54 ops::Range,
55 os::unix::{ffi::OsStrExt, prelude::OsStringExt},
56 path::{Component, Path, PathBuf},
57 rc::Rc,
58 str,
59 sync::{
60 atomic::{AtomicUsize, Ordering::SeqCst},
61 Arc,
62 },
63 time::Instant,
64};
65use thiserror::Error;
66use util::{post_inc, ResultExt, TryFutureExt as _};
67
68pub use db::Db;
69pub use fs::*;
70pub use worktree::*;
71
72pub trait Item: Entity {
73 fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId>;
74}
75
76pub struct ProjectStore {
77 db: Arc<Db>,
78 projects: Vec<WeakModelHandle<Project>>,
79}
80
81// Language server state is stored across 3 collections:
82// language_servers =>
83// a mapping from unique server id to LanguageServerState which can either be a task for a
84// server in the process of starting, or a running server with adapter and language server arcs
85// language_server_ids => a mapping from worktreeId and server name to the unique server id
86// language_server_statuses => a mapping from unique server id to the current server status
87//
88// Multiple worktrees can map to the same language server for example when you jump to the definition
89// of a file in the standard library. So language_server_ids is used to look up which server is active
90// for a given worktree and language server name
91//
92// When starting a language server, first the id map is checked to make sure a server isn't already available
93// for that worktree. If there is one, it finishes early. Otherwise, a new id is allocated and and
94// the Starting variant of LanguageServerState is stored in the language_servers map.
95pub struct Project {
96 worktrees: Vec<WorktreeHandle>,
97 active_entry: Option<ProjectEntryId>,
98 languages: Arc<LanguageRegistry>,
99 language_servers: HashMap<usize, LanguageServerState>,
100 language_server_ids: HashMap<(WorktreeId, LanguageServerName), usize>,
101 language_server_statuses: BTreeMap<usize, LanguageServerStatus>,
102 language_server_settings: Arc<Mutex<serde_json::Value>>,
103 last_workspace_edits_by_language_server: HashMap<usize, ProjectTransaction>,
104 next_language_server_id: usize,
105 client: Arc<client::Client>,
106 next_entry_id: Arc<AtomicUsize>,
107 next_diagnostic_group_id: usize,
108 user_store: ModelHandle<UserStore>,
109 project_store: ModelHandle<ProjectStore>,
110 fs: Arc<dyn Fs>,
111 client_state: ProjectClientState,
112 collaborators: HashMap<PeerId, Collaborator>,
113 client_subscriptions: Vec<client::Subscription>,
114 _subscriptions: Vec<gpui::Subscription>,
115 opened_buffer: (Rc<RefCell<watch::Sender<()>>>, watch::Receiver<()>),
116 shared_buffers: HashMap<PeerId, HashSet<u64>>,
117 loading_buffers: HashMap<
118 ProjectPath,
119 postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
120 >,
121 loading_local_worktrees:
122 HashMap<Arc<Path>, Shared<Task<Result<ModelHandle<Worktree>, Arc<anyhow::Error>>>>>,
123 opened_buffers: HashMap<u64, OpenBuffer>,
124 buffer_snapshots: HashMap<u64, Vec<(i32, TextBufferSnapshot)>>,
125 nonce: u128,
126 initialized_persistent_state: bool,
127}
128
129#[derive(Error, Debug)]
130pub enum JoinProjectError {
131 #[error("host declined join request")]
132 HostDeclined,
133 #[error("host closed the project")]
134 HostClosedProject,
135 #[error("host went offline")]
136 HostWentOffline,
137 #[error("{0}")]
138 Other(#[from] anyhow::Error),
139}
140
141enum OpenBuffer {
142 Strong(ModelHandle<Buffer>),
143 Weak(WeakModelHandle<Buffer>),
144 Loading(Vec<Operation>),
145}
146
147enum WorktreeHandle {
148 Strong(ModelHandle<Worktree>),
149 Weak(WeakModelHandle<Worktree>),
150}
151
152enum ProjectClientState {
153 Local {
154 is_shared: bool,
155 remote_id_tx: watch::Sender<Option<u64>>,
156 remote_id_rx: watch::Receiver<Option<u64>>,
157 online_tx: watch::Sender<bool>,
158 online_rx: watch::Receiver<bool>,
159 _maintain_remote_id: Task<Option<()>>,
160 _maintain_online_status: Task<Option<()>>,
161 },
162 Remote {
163 sharing_has_stopped: bool,
164 remote_id: u64,
165 replica_id: ReplicaId,
166 _detect_unshare: Task<Option<()>>,
167 },
168}
169
170#[derive(Clone, Debug)]
171pub struct Collaborator {
172 pub user: Arc<User>,
173 pub peer_id: PeerId,
174 pub replica_id: ReplicaId,
175}
176
177#[derive(Clone, Debug, PartialEq, Eq)]
178pub enum Event {
179 ActiveEntryChanged(Option<ProjectEntryId>),
180 WorktreeAdded,
181 WorktreeRemoved(WorktreeId),
182 DiskBasedDiagnosticsStarted {
183 language_server_id: usize,
184 },
185 DiskBasedDiagnosticsFinished {
186 language_server_id: usize,
187 },
188 DiagnosticsUpdated {
189 path: ProjectPath,
190 language_server_id: usize,
191 },
192 RemoteIdChanged(Option<u64>),
193 CollaboratorLeft(PeerId),
194 ContactRequestedJoin(Arc<User>),
195 ContactCancelledJoinRequest(Arc<User>),
196}
197
198pub enum LanguageServerState {
199 Starting(Task<Option<Arc<LanguageServer>>>),
200 Running {
201 adapter: Arc<dyn LspAdapter>,
202 server: Arc<LanguageServer>,
203 },
204}
205
206#[derive(Serialize)]
207pub struct LanguageServerStatus {
208 pub name: String,
209 pub pending_work: BTreeMap<String, LanguageServerProgress>,
210 pub has_pending_diagnostic_updates: bool,
211 progress_tokens: HashSet<String>,
212}
213
214#[derive(Clone, Debug, Serialize)]
215pub struct LanguageServerProgress {
216 pub message: Option<String>,
217 pub percentage: Option<usize>,
218 #[serde(skip_serializing)]
219 pub last_update_at: Instant,
220}
221
222#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
223pub struct ProjectPath {
224 pub worktree_id: WorktreeId,
225 pub path: Arc<Path>,
226}
227
228#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
229pub struct DiagnosticSummary {
230 pub language_server_id: usize,
231 pub error_count: usize,
232 pub warning_count: usize,
233}
234
235#[derive(Debug, Clone)]
236pub struct Location {
237 pub buffer: ModelHandle<Buffer>,
238 pub range: Range<language::Anchor>,
239}
240
241#[derive(Debug, Clone)]
242pub struct LocationLink {
243 pub origin: Option<Location>,
244 pub target: Location,
245}
246
247#[derive(Debug)]
248pub struct DocumentHighlight {
249 pub range: Range<language::Anchor>,
250 pub kind: DocumentHighlightKind,
251}
252
253#[derive(Clone, Debug)]
254pub struct Symbol {
255 pub source_worktree_id: WorktreeId,
256 pub worktree_id: WorktreeId,
257 pub language_server_name: LanguageServerName,
258 pub path: PathBuf,
259 pub label: CodeLabel,
260 pub name: String,
261 pub kind: lsp::SymbolKind,
262 pub range: Range<PointUtf16>,
263 pub signature: [u8; 32],
264}
265
266#[derive(Clone, Debug, PartialEq)]
267pub struct HoverBlock {
268 pub text: String,
269 pub language: Option<String>,
270}
271
272impl HoverBlock {
273 fn try_new(marked_string: MarkedString) -> Option<Self> {
274 let result = match marked_string {
275 MarkedString::LanguageString(LanguageString { language, value }) => HoverBlock {
276 text: value,
277 language: Some(language),
278 },
279 MarkedString::String(text) => HoverBlock {
280 text,
281 language: None,
282 },
283 };
284 if result.text.is_empty() {
285 None
286 } else {
287 Some(result)
288 }
289 }
290}
291
292#[derive(Debug)]
293pub struct Hover {
294 pub contents: Vec<HoverBlock>,
295 pub range: Option<Range<language::Anchor>>,
296}
297
298#[derive(Default)]
299pub struct ProjectTransaction(pub HashMap<ModelHandle<Buffer>, language::Transaction>);
300
301impl DiagnosticSummary {
302 fn new<'a, T: 'a>(
303 language_server_id: usize,
304 diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>,
305 ) -> Self {
306 let mut this = Self {
307 language_server_id,
308 error_count: 0,
309 warning_count: 0,
310 };
311
312 for entry in diagnostics {
313 if entry.diagnostic.is_primary {
314 match entry.diagnostic.severity {
315 DiagnosticSeverity::ERROR => this.error_count += 1,
316 DiagnosticSeverity::WARNING => this.warning_count += 1,
317 _ => {}
318 }
319 }
320 }
321
322 this
323 }
324
325 pub fn is_empty(&self) -> bool {
326 self.error_count == 0 && self.warning_count == 0
327 }
328
329 pub fn to_proto(&self, path: &Path) -> proto::DiagnosticSummary {
330 proto::DiagnosticSummary {
331 path: path.to_string_lossy().to_string(),
332 language_server_id: self.language_server_id as u64,
333 error_count: self.error_count as u32,
334 warning_count: self.warning_count as u32,
335 }
336 }
337}
338
339#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
340pub struct ProjectEntryId(usize);
341
342impl ProjectEntryId {
343 pub const MAX: Self = Self(usize::MAX);
344
345 pub fn new(counter: &AtomicUsize) -> Self {
346 Self(counter.fetch_add(1, SeqCst))
347 }
348
349 pub fn from_proto(id: u64) -> Self {
350 Self(id as usize)
351 }
352
353 pub fn to_proto(&self) -> u64 {
354 self.0 as u64
355 }
356
357 pub fn to_usize(&self) -> usize {
358 self.0
359 }
360}
361
362impl Project {
363 pub fn init(client: &Arc<Client>) {
364 client.add_model_message_handler(Self::handle_request_join_project);
365 client.add_model_message_handler(Self::handle_add_collaborator);
366 client.add_model_message_handler(Self::handle_buffer_reloaded);
367 client.add_model_message_handler(Self::handle_buffer_saved);
368 client.add_model_message_handler(Self::handle_start_language_server);
369 client.add_model_message_handler(Self::handle_update_language_server);
370 client.add_model_message_handler(Self::handle_remove_collaborator);
371 client.add_model_message_handler(Self::handle_join_project_request_cancelled);
372 client.add_model_message_handler(Self::handle_update_project);
373 client.add_model_message_handler(Self::handle_unregister_project);
374 client.add_model_message_handler(Self::handle_project_unshared);
375 client.add_model_message_handler(Self::handle_update_buffer_file);
376 client.add_model_message_handler(Self::handle_update_buffer);
377 client.add_model_message_handler(Self::handle_update_diagnostic_summary);
378 client.add_model_message_handler(Self::handle_update_worktree);
379 client.add_model_request_handler(Self::handle_create_project_entry);
380 client.add_model_request_handler(Self::handle_rename_project_entry);
381 client.add_model_request_handler(Self::handle_copy_project_entry);
382 client.add_model_request_handler(Self::handle_delete_project_entry);
383 client.add_model_request_handler(Self::handle_apply_additional_edits_for_completion);
384 client.add_model_request_handler(Self::handle_apply_code_action);
385 client.add_model_request_handler(Self::handle_reload_buffers);
386 client.add_model_request_handler(Self::handle_format_buffers);
387 client.add_model_request_handler(Self::handle_get_code_actions);
388 client.add_model_request_handler(Self::handle_get_completions);
389 client.add_model_request_handler(Self::handle_lsp_command::<GetHover>);
390 client.add_model_request_handler(Self::handle_lsp_command::<GetDefinition>);
391 client.add_model_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
392 client.add_model_request_handler(Self::handle_lsp_command::<GetReferences>);
393 client.add_model_request_handler(Self::handle_lsp_command::<PrepareRename>);
394 client.add_model_request_handler(Self::handle_lsp_command::<PerformRename>);
395 client.add_model_request_handler(Self::handle_search_project);
396 client.add_model_request_handler(Self::handle_get_project_symbols);
397 client.add_model_request_handler(Self::handle_open_buffer_for_symbol);
398 client.add_model_request_handler(Self::handle_open_buffer_by_id);
399 client.add_model_request_handler(Self::handle_open_buffer_by_path);
400 client.add_model_request_handler(Self::handle_save_buffer);
401 }
402
403 pub fn local(
404 online: bool,
405 client: Arc<Client>,
406 user_store: ModelHandle<UserStore>,
407 project_store: ModelHandle<ProjectStore>,
408 languages: Arc<LanguageRegistry>,
409 fs: Arc<dyn Fs>,
410 cx: &mut MutableAppContext,
411 ) -> ModelHandle<Self> {
412 cx.add_model(|cx: &mut ModelContext<Self>| {
413 let (remote_id_tx, remote_id_rx) = watch::channel();
414 let _maintain_remote_id = cx.spawn_weak({
415 let mut status_rx = client.clone().status();
416 move |this, mut cx| async move {
417 while let Some(status) = status_rx.recv().await {
418 let this = this.upgrade(&cx)?;
419 if status.is_connected() {
420 this.update(&mut cx, |this, cx| this.register(cx))
421 .await
422 .log_err()?;
423 } else {
424 this.update(&mut cx, |this, cx| this.unregister(cx))
425 .await
426 .log_err();
427 }
428 }
429 None
430 }
431 });
432
433 let (online_tx, online_rx) = watch::channel_with(online);
434 let _maintain_online_status = cx.spawn_weak({
435 let mut online_rx = online_rx.clone();
436 move |this, mut cx| async move {
437 while let Some(online) = online_rx.recv().await {
438 let this = this.upgrade(&cx)?;
439 this.update(&mut cx, |this, cx| {
440 if !online {
441 this.unshared(cx);
442 }
443 this.metadata_changed(false, cx)
444 });
445 }
446 None
447 }
448 });
449
450 let handle = cx.weak_handle();
451 project_store.update(cx, |store, cx| store.add_project(handle, cx));
452
453 let (opened_buffer_tx, opened_buffer_rx) = watch::channel();
454 Self {
455 worktrees: Default::default(),
456 collaborators: Default::default(),
457 opened_buffers: Default::default(),
458 shared_buffers: Default::default(),
459 loading_buffers: Default::default(),
460 loading_local_worktrees: Default::default(),
461 buffer_snapshots: Default::default(),
462 client_state: ProjectClientState::Local {
463 is_shared: false,
464 remote_id_tx,
465 remote_id_rx,
466 online_tx,
467 online_rx,
468 _maintain_remote_id,
469 _maintain_online_status,
470 },
471 opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
472 client_subscriptions: Vec::new(),
473 _subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
474 active_entry: None,
475 languages,
476 client,
477 user_store,
478 project_store,
479 fs,
480 next_entry_id: Default::default(),
481 next_diagnostic_group_id: Default::default(),
482 language_servers: Default::default(),
483 language_server_ids: Default::default(),
484 language_server_statuses: Default::default(),
485 last_workspace_edits_by_language_server: Default::default(),
486 language_server_settings: Default::default(),
487 next_language_server_id: 0,
488 nonce: StdRng::from_entropy().gen(),
489 initialized_persistent_state: false,
490 }
491 })
492 }
493
494 pub async fn remote(
495 remote_id: u64,
496 client: Arc<Client>,
497 user_store: ModelHandle<UserStore>,
498 project_store: ModelHandle<ProjectStore>,
499 languages: Arc<LanguageRegistry>,
500 fs: Arc<dyn Fs>,
501 mut cx: AsyncAppContext,
502 ) -> Result<ModelHandle<Self>, JoinProjectError> {
503 client.authenticate_and_connect(true, &cx).await?;
504
505 let response = client
506 .request(proto::JoinProject {
507 project_id: remote_id,
508 })
509 .await?;
510
511 let response = match response.variant.ok_or_else(|| anyhow!("missing variant"))? {
512 proto::join_project_response::Variant::Accept(response) => response,
513 proto::join_project_response::Variant::Decline(decline) => {
514 match proto::join_project_response::decline::Reason::from_i32(decline.reason) {
515 Some(proto::join_project_response::decline::Reason::Declined) => {
516 Err(JoinProjectError::HostDeclined)?
517 }
518 Some(proto::join_project_response::decline::Reason::Closed) => {
519 Err(JoinProjectError::HostClosedProject)?
520 }
521 Some(proto::join_project_response::decline::Reason::WentOffline) => {
522 Err(JoinProjectError::HostWentOffline)?
523 }
524 None => Err(anyhow!("missing decline reason"))?,
525 }
526 }
527 };
528
529 let replica_id = response.replica_id as ReplicaId;
530
531 let mut worktrees = Vec::new();
532 for worktree in response.worktrees {
533 let worktree = cx
534 .update(|cx| Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx));
535 worktrees.push(worktree);
536 }
537
538 let (opened_buffer_tx, opened_buffer_rx) = watch::channel();
539 let this = cx.add_model(|cx: &mut ModelContext<Self>| {
540 let handle = cx.weak_handle();
541 project_store.update(cx, |store, cx| store.add_project(handle, cx));
542
543 let mut this = Self {
544 worktrees: Vec::new(),
545 loading_buffers: Default::default(),
546 opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
547 shared_buffers: Default::default(),
548 loading_local_worktrees: Default::default(),
549 active_entry: None,
550 collaborators: Default::default(),
551 languages,
552 user_store: user_store.clone(),
553 project_store,
554 fs,
555 next_entry_id: Default::default(),
556 next_diagnostic_group_id: Default::default(),
557 client_subscriptions: vec![client.add_model_for_remote_entity(remote_id, cx)],
558 _subscriptions: Default::default(),
559 client: client.clone(),
560 client_state: ProjectClientState::Remote {
561 sharing_has_stopped: false,
562 remote_id,
563 replica_id,
564 _detect_unshare: cx.spawn_weak(move |this, mut cx| {
565 async move {
566 let mut status = client.status();
567 let is_connected =
568 status.next().await.map_or(false, |s| s.is_connected());
569 // Even if we're initially connected, any future change of the status means we momentarily disconnected.
570 if !is_connected || status.next().await.is_some() {
571 if let Some(this) = this.upgrade(&cx) {
572 this.update(&mut cx, |this, cx| this.removed_from_project(cx))
573 }
574 }
575 Ok(())
576 }
577 .log_err()
578 }),
579 },
580 language_servers: Default::default(),
581 language_server_ids: Default::default(),
582 language_server_settings: Default::default(),
583 language_server_statuses: response
584 .language_servers
585 .into_iter()
586 .map(|server| {
587 (
588 server.id as usize,
589 LanguageServerStatus {
590 name: server.name,
591 pending_work: Default::default(),
592 has_pending_diagnostic_updates: false,
593 progress_tokens: Default::default(),
594 },
595 )
596 })
597 .collect(),
598 last_workspace_edits_by_language_server: Default::default(),
599 next_language_server_id: 0,
600 opened_buffers: Default::default(),
601 buffer_snapshots: Default::default(),
602 nonce: StdRng::from_entropy().gen(),
603 initialized_persistent_state: false,
604 };
605 for worktree in worktrees {
606 this.add_worktree(&worktree, cx);
607 }
608 this
609 });
610
611 let user_ids = response
612 .collaborators
613 .iter()
614 .map(|peer| peer.user_id)
615 .collect();
616 user_store
617 .update(&mut cx, |user_store, cx| user_store.get_users(user_ids, cx))
618 .await?;
619 let mut collaborators = HashMap::default();
620 for message in response.collaborators {
621 let collaborator = Collaborator::from_proto(message, &user_store, &mut cx).await?;
622 collaborators.insert(collaborator.peer_id, collaborator);
623 }
624
625 this.update(&mut cx, |this, _| {
626 this.collaborators = collaborators;
627 });
628
629 Ok(this)
630 }
631
632 #[cfg(any(test, feature = "test-support"))]
633 pub async fn test(
634 fs: Arc<dyn Fs>,
635 root_paths: impl IntoIterator<Item = &Path>,
636 cx: &mut gpui::TestAppContext,
637 ) -> ModelHandle<Project> {
638 if !cx.read(|cx| cx.has_global::<Settings>()) {
639 cx.update(|cx| cx.set_global(Settings::test(cx)));
640 }
641
642 let languages = Arc::new(LanguageRegistry::test());
643 let http_client = client::test::FakeHttpClient::with_404_response();
644 let client = client::Client::new(http_client.clone());
645 let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
646 let project_store = cx.add_model(|_| ProjectStore::new(Db::open_fake()));
647 let project = cx.update(|cx| {
648 Project::local(true, client, user_store, project_store, languages, fs, cx)
649 });
650 for path in root_paths {
651 let (tree, _) = project
652 .update(cx, |project, cx| {
653 project.find_or_create_local_worktree(path, true, cx)
654 })
655 .await
656 .unwrap();
657 tree.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
658 .await;
659 }
660 project
661 }
662
663 pub fn restore_state(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
664 if self.is_remote() {
665 return Task::ready(Ok(()));
666 }
667
668 let db = self.project_store.read(cx).db.clone();
669 let keys = self.db_keys_for_online_state(cx);
670 let online_by_default = cx.global::<Settings>().projects_online_by_default;
671 let read_online = cx.background().spawn(async move {
672 let values = db.read(keys)?;
673 anyhow::Ok(
674 values
675 .into_iter()
676 .all(|e| e.map_or(online_by_default, |e| e == [true as u8])),
677 )
678 });
679 cx.spawn(|this, mut cx| async move {
680 let online = read_online.await.log_err().unwrap_or(false);
681 this.update(&mut cx, |this, cx| {
682 this.initialized_persistent_state = true;
683 if let ProjectClientState::Local { online_tx, .. } = &mut this.client_state {
684 let mut online_tx = online_tx.borrow_mut();
685 if *online_tx != online {
686 *online_tx = online;
687 drop(online_tx);
688 this.metadata_changed(false, cx);
689 }
690 }
691 });
692 Ok(())
693 })
694 }
695
696 fn persist_state(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
697 if self.is_remote() || !self.initialized_persistent_state {
698 return Task::ready(Ok(()));
699 }
700
701 let db = self.project_store.read(cx).db.clone();
702 let keys = self.db_keys_for_online_state(cx);
703 let is_online = self.is_online();
704 cx.background().spawn(async move {
705 let value = &[is_online as u8];
706 db.write(keys.into_iter().map(|key| (key, value)))
707 })
708 }
709
710 fn on_settings_changed(&mut self, cx: &mut ModelContext<Self>) {
711 let settings = cx.global::<Settings>();
712
713 let mut language_servers_to_start = Vec::new();
714 for buffer in self.opened_buffers.values() {
715 if let Some(buffer) = buffer.upgrade(cx) {
716 let buffer = buffer.read(cx);
717 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language())
718 {
719 if settings.enable_language_server(Some(&language.name())) {
720 let worktree = file.worktree.read(cx);
721 language_servers_to_start.push((
722 worktree.id(),
723 worktree.as_local().unwrap().abs_path().clone(),
724 language.clone(),
725 ));
726 }
727 }
728 }
729 }
730
731 let mut language_servers_to_stop = Vec::new();
732 for language in self.languages.to_vec() {
733 if let Some(lsp_adapter) = language.lsp_adapter() {
734 if !settings.enable_language_server(Some(&language.name())) {
735 let lsp_name = lsp_adapter.name();
736 for (worktree_id, started_lsp_name) in self.language_server_ids.keys() {
737 if lsp_name == *started_lsp_name {
738 language_servers_to_stop.push((*worktree_id, started_lsp_name.clone()));
739 }
740 }
741 }
742 }
743 }
744
745 // Stop all newly-disabled language servers.
746 for (worktree_id, adapter_name) in language_servers_to_stop {
747 self.stop_language_server(worktree_id, adapter_name, cx)
748 .detach();
749 }
750
751 // Start all the newly-enabled language servers.
752 for (worktree_id, worktree_path, language) in language_servers_to_start {
753 self.start_language_server(worktree_id, worktree_path, language, cx);
754 }
755
756 cx.notify();
757 }
758
759 pub fn buffer_for_id(&self, remote_id: u64, cx: &AppContext) -> Option<ModelHandle<Buffer>> {
760 self.opened_buffers
761 .get(&remote_id)
762 .and_then(|buffer| buffer.upgrade(cx))
763 }
764
765 pub fn languages(&self) -> &Arc<LanguageRegistry> {
766 &self.languages
767 }
768
769 pub fn client(&self) -> Arc<Client> {
770 self.client.clone()
771 }
772
773 pub fn user_store(&self) -> ModelHandle<UserStore> {
774 self.user_store.clone()
775 }
776
777 pub fn project_store(&self) -> ModelHandle<ProjectStore> {
778 self.project_store.clone()
779 }
780
781 #[cfg(any(test, feature = "test-support"))]
782 pub fn check_invariants(&self, cx: &AppContext) {
783 if self.is_local() {
784 let mut worktree_root_paths = HashMap::default();
785 for worktree in self.worktrees(cx) {
786 let worktree = worktree.read(cx);
787 let abs_path = worktree.as_local().unwrap().abs_path().clone();
788 let prev_worktree_id = worktree_root_paths.insert(abs_path.clone(), worktree.id());
789 assert_eq!(
790 prev_worktree_id,
791 None,
792 "abs path {:?} for worktree {:?} is not unique ({:?} was already registered with the same path)",
793 abs_path,
794 worktree.id(),
795 prev_worktree_id
796 )
797 }
798 } else {
799 let replica_id = self.replica_id();
800 for buffer in self.opened_buffers.values() {
801 if let Some(buffer) = buffer.upgrade(cx) {
802 let buffer = buffer.read(cx);
803 assert_eq!(
804 buffer.deferred_ops_len(),
805 0,
806 "replica {}, buffer {} has deferred operations",
807 replica_id,
808 buffer.remote_id()
809 );
810 }
811 }
812 }
813 }
814
815 #[cfg(any(test, feature = "test-support"))]
816 pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &AppContext) -> bool {
817 let path = path.into();
818 if let Some(worktree) = self.worktree_for_id(path.worktree_id, cx) {
819 self.opened_buffers.iter().any(|(_, buffer)| {
820 if let Some(buffer) = buffer.upgrade(cx) {
821 if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
822 if file.worktree == worktree && file.path() == &path.path {
823 return true;
824 }
825 }
826 }
827 false
828 })
829 } else {
830 false
831 }
832 }
833
834 pub fn fs(&self) -> &Arc<dyn Fs> {
835 &self.fs
836 }
837
838 pub fn set_online(&mut self, online: bool, _: &mut ModelContext<Self>) {
839 if let ProjectClientState::Local { online_tx, .. } = &mut self.client_state {
840 let mut online_tx = online_tx.borrow_mut();
841 if *online_tx != online {
842 *online_tx = online;
843 }
844 }
845 }
846
847 pub fn is_online(&self) -> bool {
848 match &self.client_state {
849 ProjectClientState::Local { online_rx, .. } => *online_rx.borrow(),
850 ProjectClientState::Remote { .. } => true,
851 }
852 }
853
854 fn unregister(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
855 self.unshared(cx);
856 if let ProjectClientState::Local { remote_id_rx, .. } = &mut self.client_state {
857 if let Some(remote_id) = *remote_id_rx.borrow() {
858 let request = self.client.request(proto::UnregisterProject {
859 project_id: remote_id,
860 });
861 return cx.spawn(|this, mut cx| async move {
862 let response = request.await;
863
864 // Unregistering the project causes the server to send out a
865 // contact update removing this project from the host's list
866 // of online projects. Wait until this contact update has been
867 // processed before clearing out this project's remote id, so
868 // that there is no moment where this project appears in the
869 // contact metadata and *also* has no remote id.
870 this.update(&mut cx, |this, cx| {
871 this.user_store()
872 .update(cx, |store, _| store.contact_updates_done())
873 })
874 .await;
875
876 this.update(&mut cx, |this, cx| {
877 if let ProjectClientState::Local { remote_id_tx, .. } =
878 &mut this.client_state
879 {
880 *remote_id_tx.borrow_mut() = None;
881 }
882 this.client_subscriptions.clear();
883 this.metadata_changed(false, cx);
884 });
885 response.map(drop)
886 });
887 }
888 }
889 Task::ready(Ok(()))
890 }
891
892 fn register(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
893 if let ProjectClientState::Local {
894 remote_id_rx,
895 online_rx,
896 ..
897 } = &self.client_state
898 {
899 if remote_id_rx.borrow().is_some() {
900 return Task::ready(Ok(()));
901 }
902
903 let response = self.client.request(proto::RegisterProject {
904 online: *online_rx.borrow(),
905 });
906 cx.spawn(|this, mut cx| async move {
907 let remote_id = response.await?.project_id;
908 this.update(&mut cx, |this, cx| {
909 if let ProjectClientState::Local { remote_id_tx, .. } = &mut this.client_state {
910 *remote_id_tx.borrow_mut() = Some(remote_id);
911 }
912
913 this.metadata_changed(false, cx);
914 cx.emit(Event::RemoteIdChanged(Some(remote_id)));
915 this.client_subscriptions
916 .push(this.client.add_model_for_remote_entity(remote_id, cx));
917 Ok(())
918 })
919 })
920 } else {
921 Task::ready(Err(anyhow!("can't register a remote project")))
922 }
923 }
924
925 pub fn remote_id(&self) -> Option<u64> {
926 match &self.client_state {
927 ProjectClientState::Local { remote_id_rx, .. } => *remote_id_rx.borrow(),
928 ProjectClientState::Remote { remote_id, .. } => Some(*remote_id),
929 }
930 }
931
932 pub fn next_remote_id(&self) -> impl Future<Output = u64> {
933 let mut id = None;
934 let mut watch = None;
935 match &self.client_state {
936 ProjectClientState::Local { remote_id_rx, .. } => watch = Some(remote_id_rx.clone()),
937 ProjectClientState::Remote { remote_id, .. } => id = Some(*remote_id),
938 }
939
940 async move {
941 if let Some(id) = id {
942 return id;
943 }
944 let mut watch = watch.unwrap();
945 loop {
946 let id = *watch.borrow();
947 if let Some(id) = id {
948 return id;
949 }
950 watch.next().await;
951 }
952 }
953 }
954
955 pub fn shared_remote_id(&self) -> Option<u64> {
956 match &self.client_state {
957 ProjectClientState::Local {
958 remote_id_rx,
959 is_shared,
960 ..
961 } => {
962 if *is_shared {
963 *remote_id_rx.borrow()
964 } else {
965 None
966 }
967 }
968 ProjectClientState::Remote { remote_id, .. } => Some(*remote_id),
969 }
970 }
971
972 pub fn replica_id(&self) -> ReplicaId {
973 match &self.client_state {
974 ProjectClientState::Local { .. } => 0,
975 ProjectClientState::Remote { replica_id, .. } => *replica_id,
976 }
977 }
978
979 fn metadata_changed(&mut self, persist: bool, cx: &mut ModelContext<Self>) {
980 if let ProjectClientState::Local {
981 remote_id_rx,
982 online_rx,
983 ..
984 } = &self.client_state
985 {
986 // Broadcast worktrees only if the project is online.
987 let worktrees = if *online_rx.borrow() {
988 self.worktrees
989 .iter()
990 .filter_map(|worktree| {
991 worktree
992 .upgrade(&cx)
993 .map(|worktree| worktree.read(cx).as_local().unwrap().metadata_proto())
994 })
995 .collect()
996 } else {
997 Default::default()
998 };
999 if let Some(project_id) = *remote_id_rx.borrow() {
1000 let online = *online_rx.borrow();
1001 self.client
1002 .send(proto::UpdateProject {
1003 project_id,
1004 worktrees,
1005 online,
1006 })
1007 .log_err();
1008
1009 if online {
1010 let worktrees = self.visible_worktrees(cx).collect::<Vec<_>>();
1011 let scans_complete =
1012 futures::future::join_all(worktrees.iter().filter_map(|worktree| {
1013 Some(worktree.read(cx).as_local()?.scan_complete())
1014 }));
1015
1016 let worktrees = worktrees.into_iter().map(|handle| handle.downgrade());
1017 cx.spawn_weak(move |_, cx| async move {
1018 scans_complete.await;
1019 cx.read(|cx| {
1020 for worktree in worktrees {
1021 if let Some(worktree) = worktree
1022 .upgrade(cx)
1023 .and_then(|worktree| worktree.read(cx).as_local())
1024 {
1025 worktree.send_extension_counts(project_id);
1026 }
1027 }
1028 })
1029 })
1030 .detach();
1031 }
1032 }
1033
1034 self.project_store.update(cx, |_, cx| cx.notify());
1035 if persist {
1036 self.persist_state(cx).detach_and_log_err(cx);
1037 }
1038 cx.notify();
1039 }
1040 }
1041
1042 pub fn collaborators(&self) -> &HashMap<PeerId, Collaborator> {
1043 &self.collaborators
1044 }
1045
1046 pub fn worktrees<'a>(
1047 &'a self,
1048 cx: &'a AppContext,
1049 ) -> impl 'a + DoubleEndedIterator<Item = ModelHandle<Worktree>> {
1050 self.worktrees
1051 .iter()
1052 .filter_map(move |worktree| worktree.upgrade(cx))
1053 }
1054
1055 pub fn visible_worktrees<'a>(
1056 &'a self,
1057 cx: &'a AppContext,
1058 ) -> impl 'a + DoubleEndedIterator<Item = ModelHandle<Worktree>> {
1059 self.worktrees.iter().filter_map(|worktree| {
1060 worktree.upgrade(cx).and_then(|worktree| {
1061 if worktree.read(cx).is_visible() {
1062 Some(worktree)
1063 } else {
1064 None
1065 }
1066 })
1067 })
1068 }
1069
1070 pub fn worktree_root_names<'a>(&'a self, cx: &'a AppContext) -> impl Iterator<Item = &'a str> {
1071 self.visible_worktrees(cx)
1072 .map(|tree| tree.read(cx).root_name())
1073 }
1074
1075 fn db_keys_for_online_state(&self, cx: &AppContext) -> Vec<String> {
1076 self.worktrees
1077 .iter()
1078 .filter_map(|worktree| {
1079 let worktree = worktree.upgrade(&cx)?.read(cx);
1080 if worktree.is_visible() {
1081 Some(format!(
1082 "project-path-online:{}",
1083 worktree.as_local().unwrap().abs_path().to_string_lossy()
1084 ))
1085 } else {
1086 None
1087 }
1088 })
1089 .collect::<Vec<_>>()
1090 }
1091
1092 pub fn worktree_for_id(
1093 &self,
1094 id: WorktreeId,
1095 cx: &AppContext,
1096 ) -> Option<ModelHandle<Worktree>> {
1097 self.worktrees(cx)
1098 .find(|worktree| worktree.read(cx).id() == id)
1099 }
1100
1101 pub fn worktree_for_entry(
1102 &self,
1103 entry_id: ProjectEntryId,
1104 cx: &AppContext,
1105 ) -> Option<ModelHandle<Worktree>> {
1106 self.worktrees(cx)
1107 .find(|worktree| worktree.read(cx).contains_entry(entry_id))
1108 }
1109
1110 pub fn worktree_id_for_entry(
1111 &self,
1112 entry_id: ProjectEntryId,
1113 cx: &AppContext,
1114 ) -> Option<WorktreeId> {
1115 self.worktree_for_entry(entry_id, cx)
1116 .map(|worktree| worktree.read(cx).id())
1117 }
1118
1119 pub fn contains_paths(&self, paths: &[PathBuf], cx: &AppContext) -> bool {
1120 paths.iter().all(|path| self.contains_path(&path, cx))
1121 }
1122
1123 pub fn contains_path(&self, path: &Path, cx: &AppContext) -> bool {
1124 for worktree in self.worktrees(cx) {
1125 let worktree = worktree.read(cx).as_local();
1126 if worktree.map_or(false, |w| w.contains_abs_path(path)) {
1127 return true;
1128 }
1129 }
1130 false
1131 }
1132
1133 pub fn create_entry(
1134 &mut self,
1135 project_path: impl Into<ProjectPath>,
1136 is_directory: bool,
1137 cx: &mut ModelContext<Self>,
1138 ) -> Option<Task<Result<Entry>>> {
1139 let project_path = project_path.into();
1140 let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
1141 if self.is_local() {
1142 Some(worktree.update(cx, |worktree, cx| {
1143 worktree
1144 .as_local_mut()
1145 .unwrap()
1146 .create_entry(project_path.path, is_directory, cx)
1147 }))
1148 } else {
1149 let client = self.client.clone();
1150 let project_id = self.remote_id().unwrap();
1151 Some(cx.spawn_weak(|_, mut cx| async move {
1152 let response = client
1153 .request(proto::CreateProjectEntry {
1154 worktree_id: project_path.worktree_id.to_proto(),
1155 project_id,
1156 path: project_path.path.as_os_str().as_bytes().to_vec(),
1157 is_directory,
1158 })
1159 .await?;
1160 let entry = response
1161 .entry
1162 .ok_or_else(|| anyhow!("missing entry in response"))?;
1163 worktree
1164 .update(&mut cx, |worktree, cx| {
1165 worktree.as_remote_mut().unwrap().insert_entry(
1166 entry,
1167 response.worktree_scan_id as usize,
1168 cx,
1169 )
1170 })
1171 .await
1172 }))
1173 }
1174 }
1175
1176 pub fn copy_entry(
1177 &mut self,
1178 entry_id: ProjectEntryId,
1179 new_path: impl Into<Arc<Path>>,
1180 cx: &mut ModelContext<Self>,
1181 ) -> Option<Task<Result<Entry>>> {
1182 let worktree = self.worktree_for_entry(entry_id, cx)?;
1183 let new_path = new_path.into();
1184 if self.is_local() {
1185 worktree.update(cx, |worktree, cx| {
1186 worktree
1187 .as_local_mut()
1188 .unwrap()
1189 .copy_entry(entry_id, new_path, cx)
1190 })
1191 } else {
1192 let client = self.client.clone();
1193 let project_id = self.remote_id().unwrap();
1194
1195 Some(cx.spawn_weak(|_, mut cx| async move {
1196 let response = client
1197 .request(proto::CopyProjectEntry {
1198 project_id,
1199 entry_id: entry_id.to_proto(),
1200 new_path: new_path.as_os_str().as_bytes().to_vec(),
1201 })
1202 .await?;
1203 let entry = response
1204 .entry
1205 .ok_or_else(|| anyhow!("missing entry in response"))?;
1206 worktree
1207 .update(&mut cx, |worktree, cx| {
1208 worktree.as_remote_mut().unwrap().insert_entry(
1209 entry,
1210 response.worktree_scan_id as usize,
1211 cx,
1212 )
1213 })
1214 .await
1215 }))
1216 }
1217 }
1218
1219 pub fn rename_entry(
1220 &mut self,
1221 entry_id: ProjectEntryId,
1222 new_path: impl Into<Arc<Path>>,
1223 cx: &mut ModelContext<Self>,
1224 ) -> Option<Task<Result<Entry>>> {
1225 let worktree = self.worktree_for_entry(entry_id, cx)?;
1226 let new_path = new_path.into();
1227 if self.is_local() {
1228 worktree.update(cx, |worktree, cx| {
1229 worktree
1230 .as_local_mut()
1231 .unwrap()
1232 .rename_entry(entry_id, new_path, cx)
1233 })
1234 } else {
1235 let client = self.client.clone();
1236 let project_id = self.remote_id().unwrap();
1237
1238 Some(cx.spawn_weak(|_, mut cx| async move {
1239 let response = client
1240 .request(proto::RenameProjectEntry {
1241 project_id,
1242 entry_id: entry_id.to_proto(),
1243 new_path: new_path.as_os_str().as_bytes().to_vec(),
1244 })
1245 .await?;
1246 let entry = response
1247 .entry
1248 .ok_or_else(|| anyhow!("missing entry in response"))?;
1249 worktree
1250 .update(&mut cx, |worktree, cx| {
1251 worktree.as_remote_mut().unwrap().insert_entry(
1252 entry,
1253 response.worktree_scan_id as usize,
1254 cx,
1255 )
1256 })
1257 .await
1258 }))
1259 }
1260 }
1261
1262 pub fn delete_entry(
1263 &mut self,
1264 entry_id: ProjectEntryId,
1265 cx: &mut ModelContext<Self>,
1266 ) -> Option<Task<Result<()>>> {
1267 let worktree = self.worktree_for_entry(entry_id, cx)?;
1268 if self.is_local() {
1269 worktree.update(cx, |worktree, cx| {
1270 worktree.as_local_mut().unwrap().delete_entry(entry_id, cx)
1271 })
1272 } else {
1273 let client = self.client.clone();
1274 let project_id = self.remote_id().unwrap();
1275 Some(cx.spawn_weak(|_, mut cx| async move {
1276 let response = client
1277 .request(proto::DeleteProjectEntry {
1278 project_id,
1279 entry_id: entry_id.to_proto(),
1280 })
1281 .await?;
1282 worktree
1283 .update(&mut cx, move |worktree, cx| {
1284 worktree.as_remote_mut().unwrap().delete_entry(
1285 entry_id,
1286 response.worktree_scan_id as usize,
1287 cx,
1288 )
1289 })
1290 .await
1291 }))
1292 }
1293 }
1294
1295 fn share(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
1296 if !self.is_online() {
1297 return Task::ready(Err(anyhow!("can't share an offline project")));
1298 }
1299
1300 let project_id;
1301 if let ProjectClientState::Local {
1302 remote_id_rx,
1303 is_shared,
1304 ..
1305 } = &mut self.client_state
1306 {
1307 if *is_shared {
1308 return Task::ready(Ok(()));
1309 }
1310 *is_shared = true;
1311 if let Some(id) = *remote_id_rx.borrow() {
1312 project_id = id;
1313 } else {
1314 return Task::ready(Err(anyhow!("project hasn't been registered")));
1315 }
1316 } else {
1317 return Task::ready(Err(anyhow!("can't share a remote project")));
1318 };
1319
1320 for open_buffer in self.opened_buffers.values_mut() {
1321 match open_buffer {
1322 OpenBuffer::Strong(_) => {}
1323 OpenBuffer::Weak(buffer) => {
1324 if let Some(buffer) = buffer.upgrade(cx) {
1325 *open_buffer = OpenBuffer::Strong(buffer);
1326 }
1327 }
1328 OpenBuffer::Loading(_) => unreachable!(),
1329 }
1330 }
1331
1332 for worktree_handle in self.worktrees.iter_mut() {
1333 match worktree_handle {
1334 WorktreeHandle::Strong(_) => {}
1335 WorktreeHandle::Weak(worktree) => {
1336 if let Some(worktree) = worktree.upgrade(cx) {
1337 *worktree_handle = WorktreeHandle::Strong(worktree);
1338 }
1339 }
1340 }
1341 }
1342
1343 let mut tasks = Vec::new();
1344 for worktree in self.worktrees(cx).collect::<Vec<_>>() {
1345 worktree.update(cx, |worktree, cx| {
1346 let worktree = worktree.as_local_mut().unwrap();
1347 tasks.push(worktree.share(project_id, cx));
1348 });
1349 }
1350
1351 for (server_id, status) in &self.language_server_statuses {
1352 self.client
1353 .send(proto::StartLanguageServer {
1354 project_id,
1355 server: Some(proto::LanguageServer {
1356 id: *server_id as u64,
1357 name: status.name.clone(),
1358 }),
1359 })
1360 .log_err();
1361 }
1362
1363 cx.spawn(|this, mut cx| async move {
1364 for task in tasks {
1365 task.await?;
1366 }
1367 this.update(&mut cx, |_, cx| cx.notify());
1368 Ok(())
1369 })
1370 }
1371
1372 fn unshared(&mut self, cx: &mut ModelContext<Self>) {
1373 if let ProjectClientState::Local { is_shared, .. } = &mut self.client_state {
1374 if !*is_shared {
1375 return;
1376 }
1377
1378 *is_shared = false;
1379 self.collaborators.clear();
1380 self.shared_buffers.clear();
1381 for worktree_handle in self.worktrees.iter_mut() {
1382 if let WorktreeHandle::Strong(worktree) = worktree_handle {
1383 let is_visible = worktree.update(cx, |worktree, _| {
1384 worktree.as_local_mut().unwrap().unshare();
1385 worktree.is_visible()
1386 });
1387 if !is_visible {
1388 *worktree_handle = WorktreeHandle::Weak(worktree.downgrade());
1389 }
1390 }
1391 }
1392
1393 for open_buffer in self.opened_buffers.values_mut() {
1394 match open_buffer {
1395 OpenBuffer::Strong(buffer) => {
1396 *open_buffer = OpenBuffer::Weak(buffer.downgrade());
1397 }
1398 _ => {}
1399 }
1400 }
1401
1402 cx.notify();
1403 } else {
1404 log::error!("attempted to unshare a remote project");
1405 }
1406 }
1407
1408 pub fn respond_to_join_request(
1409 &mut self,
1410 requester_id: u64,
1411 allow: bool,
1412 cx: &mut ModelContext<Self>,
1413 ) {
1414 if let Some(project_id) = self.remote_id() {
1415 let share = if self.is_online() && allow {
1416 Some(self.share(cx))
1417 } else {
1418 None
1419 };
1420 let client = self.client.clone();
1421 cx.foreground()
1422 .spawn(async move {
1423 client.send(proto::RespondToJoinProjectRequest {
1424 requester_id,
1425 project_id,
1426 allow,
1427 })?;
1428 if let Some(share) = share {
1429 share.await?;
1430 }
1431 anyhow::Ok(())
1432 })
1433 .detach_and_log_err(cx);
1434 }
1435 }
1436
1437 fn removed_from_project(&mut self, cx: &mut ModelContext<Self>) {
1438 if let ProjectClientState::Remote {
1439 sharing_has_stopped,
1440 ..
1441 } = &mut self.client_state
1442 {
1443 *sharing_has_stopped = true;
1444 self.collaborators.clear();
1445 for worktree in &self.worktrees {
1446 if let Some(worktree) = worktree.upgrade(cx) {
1447 worktree.update(cx, |worktree, _| {
1448 if let Some(worktree) = worktree.as_remote_mut() {
1449 worktree.disconnected_from_host();
1450 }
1451 });
1452 }
1453 }
1454 cx.notify();
1455 }
1456 }
1457
1458 pub fn is_read_only(&self) -> bool {
1459 match &self.client_state {
1460 ProjectClientState::Local { .. } => false,
1461 ProjectClientState::Remote {
1462 sharing_has_stopped,
1463 ..
1464 } => *sharing_has_stopped,
1465 }
1466 }
1467
1468 pub fn is_local(&self) -> bool {
1469 match &self.client_state {
1470 ProjectClientState::Local { .. } => true,
1471 ProjectClientState::Remote { .. } => false,
1472 }
1473 }
1474
1475 pub fn is_remote(&self) -> bool {
1476 !self.is_local()
1477 }
1478
1479 pub fn create_buffer(
1480 &mut self,
1481 text: &str,
1482 language: Option<Arc<Language>>,
1483 cx: &mut ModelContext<Self>,
1484 ) -> Result<ModelHandle<Buffer>> {
1485 if self.is_remote() {
1486 return Err(anyhow!("creating buffers as a guest is not supported yet"));
1487 }
1488
1489 let buffer = cx.add_model(|cx| {
1490 Buffer::new(self.replica_id(), text, cx)
1491 .with_language(language.unwrap_or(language::PLAIN_TEXT.clone()), cx)
1492 });
1493 self.register_buffer(&buffer, cx)?;
1494 Ok(buffer)
1495 }
1496
1497 pub fn open_path(
1498 &mut self,
1499 path: impl Into<ProjectPath>,
1500 cx: &mut ModelContext<Self>,
1501 ) -> Task<Result<(ProjectEntryId, AnyModelHandle)>> {
1502 let task = self.open_buffer(path, cx);
1503 cx.spawn_weak(|_, cx| async move {
1504 let buffer = task.await?;
1505 let project_entry_id = buffer
1506 .read_with(&cx, |buffer, cx| {
1507 File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx))
1508 })
1509 .ok_or_else(|| anyhow!("no project entry"))?;
1510 Ok((project_entry_id, buffer.into()))
1511 })
1512 }
1513
1514 pub fn open_local_buffer(
1515 &mut self,
1516 abs_path: impl AsRef<Path>,
1517 cx: &mut ModelContext<Self>,
1518 ) -> Task<Result<ModelHandle<Buffer>>> {
1519 if let Some((worktree, relative_path)) = self.find_local_worktree(abs_path.as_ref(), cx) {
1520 self.open_buffer((worktree.read(cx).id(), relative_path), cx)
1521 } else {
1522 Task::ready(Err(anyhow!("no such path")))
1523 }
1524 }
1525
1526 pub fn open_buffer(
1527 &mut self,
1528 path: impl Into<ProjectPath>,
1529 cx: &mut ModelContext<Self>,
1530 ) -> Task<Result<ModelHandle<Buffer>>> {
1531 let project_path = path.into();
1532 let worktree = if let Some(worktree) = self.worktree_for_id(project_path.worktree_id, cx) {
1533 worktree
1534 } else {
1535 return Task::ready(Err(anyhow!("no such worktree")));
1536 };
1537
1538 // If there is already a buffer for the given path, then return it.
1539 let existing_buffer = self.get_open_buffer(&project_path, cx);
1540 if let Some(existing_buffer) = existing_buffer {
1541 return Task::ready(Ok(existing_buffer));
1542 }
1543
1544 let mut loading_watch = match self.loading_buffers.entry(project_path.clone()) {
1545 // If the given path is already being loaded, then wait for that existing
1546 // task to complete and return the same buffer.
1547 hash_map::Entry::Occupied(e) => e.get().clone(),
1548
1549 // Otherwise, record the fact that this path is now being loaded.
1550 hash_map::Entry::Vacant(entry) => {
1551 let (mut tx, rx) = postage::watch::channel();
1552 entry.insert(rx.clone());
1553
1554 let load_buffer = if worktree.read(cx).is_local() {
1555 self.open_local_buffer_internal(&project_path.path, &worktree, cx)
1556 } else {
1557 self.open_remote_buffer_internal(&project_path.path, &worktree, cx)
1558 };
1559
1560 cx.spawn(move |this, mut cx| async move {
1561 let load_result = load_buffer.await;
1562 *tx.borrow_mut() = Some(this.update(&mut cx, |this, _| {
1563 // Record the fact that the buffer is no longer loading.
1564 this.loading_buffers.remove(&project_path);
1565 let buffer = load_result.map_err(Arc::new)?;
1566 Ok(buffer)
1567 }));
1568 })
1569 .detach();
1570 rx
1571 }
1572 };
1573
1574 cx.foreground().spawn(async move {
1575 loop {
1576 if let Some(result) = loading_watch.borrow().as_ref() {
1577 match result {
1578 Ok(buffer) => return Ok(buffer.clone()),
1579 Err(error) => return Err(anyhow!("{}", error)),
1580 }
1581 }
1582 loading_watch.next().await;
1583 }
1584 })
1585 }
1586
1587 fn open_local_buffer_internal(
1588 &mut self,
1589 path: &Arc<Path>,
1590 worktree: &ModelHandle<Worktree>,
1591 cx: &mut ModelContext<Self>,
1592 ) -> Task<Result<ModelHandle<Buffer>>> {
1593 let load_buffer = worktree.update(cx, |worktree, cx| {
1594 let worktree = worktree.as_local_mut().unwrap();
1595 worktree.load_buffer(path, cx)
1596 });
1597 cx.spawn(|this, mut cx| async move {
1598 let buffer = load_buffer.await?;
1599 this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
1600 Ok(buffer)
1601 })
1602 }
1603
1604 fn open_remote_buffer_internal(
1605 &mut self,
1606 path: &Arc<Path>,
1607 worktree: &ModelHandle<Worktree>,
1608 cx: &mut ModelContext<Self>,
1609 ) -> Task<Result<ModelHandle<Buffer>>> {
1610 let rpc = self.client.clone();
1611 let project_id = self.remote_id().unwrap();
1612 let remote_worktree_id = worktree.read(cx).id();
1613 let path = path.clone();
1614 let path_string = path.to_string_lossy().to_string();
1615 cx.spawn(|this, mut cx| async move {
1616 let response = rpc
1617 .request(proto::OpenBufferByPath {
1618 project_id,
1619 worktree_id: remote_worktree_id.to_proto(),
1620 path: path_string,
1621 })
1622 .await?;
1623 let buffer = response.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
1624 this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
1625 .await
1626 })
1627 }
1628
1629 fn open_local_buffer_via_lsp(
1630 &mut self,
1631 abs_path: lsp::Url,
1632 language_server_id: usize,
1633 language_server_name: LanguageServerName,
1634 cx: &mut ModelContext<Self>,
1635 ) -> Task<Result<ModelHandle<Buffer>>> {
1636 cx.spawn(|this, mut cx| async move {
1637 let abs_path = abs_path
1638 .to_file_path()
1639 .map_err(|_| anyhow!("can't convert URI to path"))?;
1640 let (worktree, relative_path) = if let Some(result) =
1641 this.read_with(&cx, |this, cx| this.find_local_worktree(&abs_path, cx))
1642 {
1643 result
1644 } else {
1645 let worktree = this
1646 .update(&mut cx, |this, cx| {
1647 this.create_local_worktree(&abs_path, false, cx)
1648 })
1649 .await?;
1650 this.update(&mut cx, |this, cx| {
1651 this.language_server_ids.insert(
1652 (worktree.read(cx).id(), language_server_name),
1653 language_server_id,
1654 );
1655 });
1656 (worktree, PathBuf::new())
1657 };
1658
1659 let project_path = ProjectPath {
1660 worktree_id: worktree.read_with(&cx, |worktree, _| worktree.id()),
1661 path: relative_path.into(),
1662 };
1663 this.update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
1664 .await
1665 })
1666 }
1667
1668 pub fn open_buffer_by_id(
1669 &mut self,
1670 id: u64,
1671 cx: &mut ModelContext<Self>,
1672 ) -> Task<Result<ModelHandle<Buffer>>> {
1673 if let Some(buffer) = self.buffer_for_id(id, cx) {
1674 Task::ready(Ok(buffer))
1675 } else if self.is_local() {
1676 Task::ready(Err(anyhow!("buffer {} does not exist", id)))
1677 } else if let Some(project_id) = self.remote_id() {
1678 let request = self
1679 .client
1680 .request(proto::OpenBufferById { project_id, id });
1681 cx.spawn(|this, mut cx| async move {
1682 let buffer = request
1683 .await?
1684 .buffer
1685 .ok_or_else(|| anyhow!("invalid buffer"))?;
1686 this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
1687 .await
1688 })
1689 } else {
1690 Task::ready(Err(anyhow!("cannot open buffer while disconnected")))
1691 }
1692 }
1693
1694 pub fn save_buffer_as(
1695 &mut self,
1696 buffer: ModelHandle<Buffer>,
1697 abs_path: PathBuf,
1698 cx: &mut ModelContext<Project>,
1699 ) -> Task<Result<()>> {
1700 let worktree_task = self.find_or_create_local_worktree(&abs_path, true, cx);
1701 let old_path =
1702 File::from_dyn(buffer.read(cx).file()).and_then(|f| Some(f.as_local()?.abs_path(cx)));
1703 cx.spawn(|this, mut cx| async move {
1704 if let Some(old_path) = old_path {
1705 this.update(&mut cx, |this, cx| {
1706 this.unregister_buffer_from_language_server(&buffer, old_path, cx);
1707 });
1708 }
1709 let (worktree, path) = worktree_task.await?;
1710 worktree
1711 .update(&mut cx, |worktree, cx| {
1712 worktree
1713 .as_local_mut()
1714 .unwrap()
1715 .save_buffer_as(buffer.clone(), path, cx)
1716 })
1717 .await?;
1718 this.update(&mut cx, |this, cx| {
1719 this.assign_language_to_buffer(&buffer, cx);
1720 this.register_buffer_with_language_server(&buffer, cx);
1721 });
1722 Ok(())
1723 })
1724 }
1725
1726 pub fn get_open_buffer(
1727 &mut self,
1728 path: &ProjectPath,
1729 cx: &mut ModelContext<Self>,
1730 ) -> Option<ModelHandle<Buffer>> {
1731 let worktree = self.worktree_for_id(path.worktree_id, cx)?;
1732 self.opened_buffers.values().find_map(|buffer| {
1733 let buffer = buffer.upgrade(cx)?;
1734 let file = File::from_dyn(buffer.read(cx).file())?;
1735 if file.worktree == worktree && file.path() == &path.path {
1736 Some(buffer)
1737 } else {
1738 None
1739 }
1740 })
1741 }
1742
1743 fn register_buffer(
1744 &mut self,
1745 buffer: &ModelHandle<Buffer>,
1746 cx: &mut ModelContext<Self>,
1747 ) -> Result<()> {
1748 let remote_id = buffer.read(cx).remote_id();
1749 let open_buffer = if self.is_remote() || self.is_shared() {
1750 OpenBuffer::Strong(buffer.clone())
1751 } else {
1752 OpenBuffer::Weak(buffer.downgrade())
1753 };
1754
1755 match self.opened_buffers.insert(remote_id, open_buffer) {
1756 None => {}
1757 Some(OpenBuffer::Loading(operations)) => {
1758 buffer.update(cx, |buffer, cx| buffer.apply_ops(operations, cx))?
1759 }
1760 Some(OpenBuffer::Weak(existing_handle)) => {
1761 if existing_handle.upgrade(cx).is_some() {
1762 Err(anyhow!(
1763 "already registered buffer with remote id {}",
1764 remote_id
1765 ))?
1766 }
1767 }
1768 Some(OpenBuffer::Strong(_)) => Err(anyhow!(
1769 "already registered buffer with remote id {}",
1770 remote_id
1771 ))?,
1772 }
1773 cx.subscribe(buffer, |this, buffer, event, cx| {
1774 this.on_buffer_event(buffer, event, cx);
1775 })
1776 .detach();
1777
1778 self.assign_language_to_buffer(buffer, cx);
1779 self.register_buffer_with_language_server(buffer, cx);
1780 cx.observe_release(buffer, |this, buffer, cx| {
1781 if let Some(file) = File::from_dyn(buffer.file()) {
1782 if file.is_local() {
1783 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
1784 if let Some((_, server)) = this.language_server_for_buffer(buffer, cx) {
1785 server
1786 .notify::<lsp::notification::DidCloseTextDocument>(
1787 lsp::DidCloseTextDocumentParams {
1788 text_document: lsp::TextDocumentIdentifier::new(uri.clone()),
1789 },
1790 )
1791 .log_err();
1792 }
1793 }
1794 }
1795 })
1796 .detach();
1797
1798 Ok(())
1799 }
1800
1801 fn register_buffer_with_language_server(
1802 &mut self,
1803 buffer_handle: &ModelHandle<Buffer>,
1804 cx: &mut ModelContext<Self>,
1805 ) {
1806 let buffer = buffer_handle.read(cx);
1807 let buffer_id = buffer.remote_id();
1808 if let Some(file) = File::from_dyn(buffer.file()) {
1809 if file.is_local() {
1810 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
1811 let initial_snapshot = buffer.text_snapshot();
1812
1813 let mut language_server = None;
1814 let mut language_id = None;
1815 if let Some(language) = buffer.language() {
1816 let worktree_id = file.worktree_id(cx);
1817 if let Some(adapter) = language.lsp_adapter() {
1818 language_id = adapter.id_for_language(language.name().as_ref());
1819 language_server = self
1820 .language_server_ids
1821 .get(&(worktree_id, adapter.name()))
1822 .and_then(|id| self.language_servers.get(&id))
1823 .and_then(|server_state| {
1824 if let LanguageServerState::Running { server, .. } = server_state {
1825 Some(server.clone())
1826 } else {
1827 None
1828 }
1829 });
1830 }
1831 }
1832
1833 if let Some(local_worktree) = file.worktree.read(cx).as_local() {
1834 if let Some(diagnostics) = local_worktree.diagnostics_for_path(file.path()) {
1835 self.update_buffer_diagnostics(&buffer_handle, diagnostics, None, cx)
1836 .log_err();
1837 }
1838 }
1839
1840 if let Some(server) = language_server {
1841 server
1842 .notify::<lsp::notification::DidOpenTextDocument>(
1843 lsp::DidOpenTextDocumentParams {
1844 text_document: lsp::TextDocumentItem::new(
1845 uri,
1846 language_id.unwrap_or_default(),
1847 0,
1848 initial_snapshot.text(),
1849 ),
1850 }
1851 .clone(),
1852 )
1853 .log_err();
1854 buffer_handle.update(cx, |buffer, cx| {
1855 buffer.set_completion_triggers(
1856 server
1857 .capabilities()
1858 .completion_provider
1859 .as_ref()
1860 .and_then(|provider| provider.trigger_characters.clone())
1861 .unwrap_or(Vec::new()),
1862 cx,
1863 )
1864 });
1865 self.buffer_snapshots
1866 .insert(buffer_id, vec![(0, initial_snapshot)]);
1867 }
1868 }
1869 }
1870 }
1871
1872 fn unregister_buffer_from_language_server(
1873 &mut self,
1874 buffer: &ModelHandle<Buffer>,
1875 old_path: PathBuf,
1876 cx: &mut ModelContext<Self>,
1877 ) {
1878 buffer.update(cx, |buffer, cx| {
1879 buffer.update_diagnostics(Default::default(), cx);
1880 self.buffer_snapshots.remove(&buffer.remote_id());
1881 if let Some((_, language_server)) = self.language_server_for_buffer(buffer, cx) {
1882 language_server
1883 .notify::<lsp::notification::DidCloseTextDocument>(
1884 lsp::DidCloseTextDocumentParams {
1885 text_document: lsp::TextDocumentIdentifier::new(
1886 lsp::Url::from_file_path(old_path).unwrap(),
1887 ),
1888 },
1889 )
1890 .log_err();
1891 }
1892 });
1893 }
1894
1895 fn on_buffer_event(
1896 &mut self,
1897 buffer: ModelHandle<Buffer>,
1898 event: &BufferEvent,
1899 cx: &mut ModelContext<Self>,
1900 ) -> Option<()> {
1901 match event {
1902 BufferEvent::Operation(operation) => {
1903 if let Some(project_id) = self.shared_remote_id() {
1904 let request = self.client.request(proto::UpdateBuffer {
1905 project_id,
1906 buffer_id: buffer.read(cx).remote_id(),
1907 operations: vec![language::proto::serialize_operation(&operation)],
1908 });
1909 cx.background().spawn(request).detach_and_log_err(cx);
1910 } else if let Some(project_id) = self.remote_id() {
1911 let _ = self
1912 .client
1913 .send(proto::RegisterProjectActivity { project_id });
1914 }
1915 }
1916 BufferEvent::Edited { .. } => {
1917 let language_server = self
1918 .language_server_for_buffer(buffer.read(cx), cx)
1919 .map(|(_, server)| server.clone())?;
1920 let buffer = buffer.read(cx);
1921 let file = File::from_dyn(buffer.file())?;
1922 let abs_path = file.as_local()?.abs_path(cx);
1923 let uri = lsp::Url::from_file_path(abs_path).unwrap();
1924 let buffer_snapshots = self.buffer_snapshots.get_mut(&buffer.remote_id())?;
1925 let (version, prev_snapshot) = buffer_snapshots.last()?;
1926 let next_snapshot = buffer.text_snapshot();
1927 let next_version = version + 1;
1928
1929 let content_changes = buffer
1930 .edits_since::<(PointUtf16, usize)>(prev_snapshot.version())
1931 .map(|edit| {
1932 let edit_start = edit.new.start.0;
1933 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
1934 let new_text = next_snapshot
1935 .text_for_range(edit.new.start.1..edit.new.end.1)
1936 .collect();
1937 lsp::TextDocumentContentChangeEvent {
1938 range: Some(lsp::Range::new(
1939 point_to_lsp(edit_start),
1940 point_to_lsp(edit_end),
1941 )),
1942 range_length: None,
1943 text: new_text,
1944 }
1945 })
1946 .collect();
1947
1948 buffer_snapshots.push((next_version, next_snapshot));
1949
1950 language_server
1951 .notify::<lsp::notification::DidChangeTextDocument>(
1952 lsp::DidChangeTextDocumentParams {
1953 text_document: lsp::VersionedTextDocumentIdentifier::new(
1954 uri,
1955 next_version,
1956 ),
1957 content_changes,
1958 },
1959 )
1960 .log_err();
1961 }
1962 BufferEvent::Saved => {
1963 let file = File::from_dyn(buffer.read(cx).file())?;
1964 let worktree_id = file.worktree_id(cx);
1965 let abs_path = file.as_local()?.abs_path(cx);
1966 let text_document = lsp::TextDocumentIdentifier {
1967 uri: lsp::Url::from_file_path(abs_path).unwrap(),
1968 };
1969
1970 for (_, server) in self.language_servers_for_worktree(worktree_id) {
1971 server
1972 .notify::<lsp::notification::DidSaveTextDocument>(
1973 lsp::DidSaveTextDocumentParams {
1974 text_document: text_document.clone(),
1975 text: None,
1976 },
1977 )
1978 .log_err();
1979 }
1980
1981 // After saving a buffer, simulate disk-based diagnostics being finished for languages
1982 // that don't support a disk-based progress token.
1983 let (lsp_adapter, language_server) =
1984 self.language_server_for_buffer(buffer.read(cx), cx)?;
1985 if lsp_adapter
1986 .disk_based_diagnostics_progress_token()
1987 .is_none()
1988 {
1989 let server_id = language_server.server_id();
1990 self.disk_based_diagnostics_finished(server_id, cx);
1991 self.broadcast_language_server_update(
1992 server_id,
1993 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
1994 proto::LspDiskBasedDiagnosticsUpdated {},
1995 ),
1996 );
1997 }
1998 }
1999 _ => {}
2000 }
2001
2002 None
2003 }
2004
2005 fn language_servers_for_worktree(
2006 &self,
2007 worktree_id: WorktreeId,
2008 ) -> impl Iterator<Item = (&Arc<dyn LspAdapter>, &Arc<LanguageServer>)> {
2009 self.language_server_ids
2010 .iter()
2011 .filter_map(move |((language_server_worktree_id, _), id)| {
2012 if *language_server_worktree_id == worktree_id {
2013 if let Some(LanguageServerState::Running { adapter, server }) =
2014 self.language_servers.get(&id)
2015 {
2016 return Some((adapter, server));
2017 }
2018 }
2019 None
2020 })
2021 }
2022
2023 fn assign_language_to_buffer(
2024 &mut self,
2025 buffer: &ModelHandle<Buffer>,
2026 cx: &mut ModelContext<Self>,
2027 ) -> Option<()> {
2028 // If the buffer has a language, set it and start the language server if we haven't already.
2029 let full_path = buffer.read(cx).file()?.full_path(cx);
2030 let language = self.languages.select_language(&full_path)?;
2031 buffer.update(cx, |buffer, cx| {
2032 buffer.set_language(Some(language.clone()), cx);
2033 });
2034
2035 let file = File::from_dyn(buffer.read(cx).file())?;
2036 let worktree = file.worktree.read(cx).as_local()?;
2037 let worktree_id = worktree.id();
2038 let worktree_abs_path = worktree.abs_path().clone();
2039 self.start_language_server(worktree_id, worktree_abs_path, language, cx);
2040
2041 None
2042 }
2043
2044 fn start_language_server(
2045 &mut self,
2046 worktree_id: WorktreeId,
2047 worktree_path: Arc<Path>,
2048 language: Arc<Language>,
2049 cx: &mut ModelContext<Self>,
2050 ) {
2051 if !cx
2052 .global::<Settings>()
2053 .enable_language_server(Some(&language.name()))
2054 {
2055 return;
2056 }
2057
2058 let adapter = if let Some(adapter) = language.lsp_adapter() {
2059 adapter
2060 } else {
2061 return;
2062 };
2063 let key = (worktree_id, adapter.name());
2064
2065 self.language_server_ids
2066 .entry(key.clone())
2067 .or_insert_with(|| {
2068 let server_id = post_inc(&mut self.next_language_server_id);
2069 let language_server = self.languages.start_language_server(
2070 server_id,
2071 language.clone(),
2072 worktree_path,
2073 self.client.http_client(),
2074 cx,
2075 );
2076 self.language_servers.insert(
2077 server_id,
2078 LanguageServerState::Starting(cx.spawn_weak(|this, mut cx| async move {
2079 let language_server = language_server?.await.log_err()?;
2080 let language_server = language_server
2081 .initialize(adapter.initialization_options())
2082 .await
2083 .log_err()?;
2084 let this = this.upgrade(&cx)?;
2085 let disk_based_diagnostics_progress_token =
2086 adapter.disk_based_diagnostics_progress_token();
2087
2088 language_server
2089 .on_notification::<lsp::notification::PublishDiagnostics, _>({
2090 let this = this.downgrade();
2091 let adapter = adapter.clone();
2092 move |params, mut cx| {
2093 if let Some(this) = this.upgrade(&cx) {
2094 this.update(&mut cx, |this, cx| {
2095 this.on_lsp_diagnostics_published(
2096 server_id, params, &adapter, cx,
2097 );
2098 });
2099 }
2100 }
2101 })
2102 .detach();
2103
2104 language_server
2105 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
2106 let settings = this.read_with(&cx, |this, _| {
2107 this.language_server_settings.clone()
2108 });
2109 move |params, _| {
2110 let settings = settings.lock().clone();
2111 async move {
2112 Ok(params
2113 .items
2114 .into_iter()
2115 .map(|item| {
2116 if let Some(section) = &item.section {
2117 settings
2118 .get(section)
2119 .cloned()
2120 .unwrap_or(serde_json::Value::Null)
2121 } else {
2122 settings.clone()
2123 }
2124 })
2125 .collect())
2126 }
2127 }
2128 })
2129 .detach();
2130
2131 // Even though we don't have handling for these requests, respond to them to
2132 // avoid stalling any language server like `gopls` which waits for a response
2133 // to these requests when initializing.
2134 language_server
2135 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
2136 let this = this.downgrade();
2137 move |params, mut cx| async move {
2138 if let Some(this) = this.upgrade(&cx) {
2139 this.update(&mut cx, |this, _| {
2140 if let Some(status) =
2141 this.language_server_statuses.get_mut(&server_id)
2142 {
2143 if let lsp::NumberOrString::String(token) =
2144 params.token
2145 {
2146 status.progress_tokens.insert(token);
2147 }
2148 }
2149 });
2150 }
2151 Ok(())
2152 }
2153 })
2154 .detach();
2155 language_server
2156 .on_request::<lsp::request::RegisterCapability, _, _>(|_, _| async {
2157 Ok(())
2158 })
2159 .detach();
2160
2161 language_server
2162 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
2163 let this = this.downgrade();
2164 let adapter = adapter.clone();
2165 let language_server = language_server.clone();
2166 move |params, cx| {
2167 Self::on_lsp_workspace_edit(
2168 this,
2169 params,
2170 server_id,
2171 adapter.clone(),
2172 language_server.clone(),
2173 cx,
2174 )
2175 }
2176 })
2177 .detach();
2178
2179 language_server
2180 .on_notification::<lsp::notification::Progress, _>({
2181 let this = this.downgrade();
2182 move |params, mut cx| {
2183 if let Some(this) = this.upgrade(&cx) {
2184 this.update(&mut cx, |this, cx| {
2185 this.on_lsp_progress(
2186 params,
2187 server_id,
2188 disk_based_diagnostics_progress_token,
2189 cx,
2190 );
2191 });
2192 }
2193 }
2194 })
2195 .detach();
2196
2197 this.update(&mut cx, |this, cx| {
2198 // If the language server for this key doesn't match the server id, don't store the
2199 // server. Which will cause it to be dropped, killing the process
2200 if this
2201 .language_server_ids
2202 .get(&key)
2203 .map(|id| id != &server_id)
2204 .unwrap_or(false)
2205 {
2206 return None;
2207 }
2208
2209 // Update language_servers collection with Running variant of LanguageServerState
2210 // indicating that the server is up and running and ready
2211 this.language_servers.insert(
2212 server_id,
2213 LanguageServerState::Running {
2214 adapter: adapter.clone(),
2215 server: language_server.clone(),
2216 },
2217 );
2218 this.language_server_statuses.insert(
2219 server_id,
2220 LanguageServerStatus {
2221 name: language_server.name().to_string(),
2222 pending_work: Default::default(),
2223 has_pending_diagnostic_updates: false,
2224 progress_tokens: Default::default(),
2225 },
2226 );
2227 language_server
2228 .notify::<lsp::notification::DidChangeConfiguration>(
2229 lsp::DidChangeConfigurationParams {
2230 settings: this.language_server_settings.lock().clone(),
2231 },
2232 )
2233 .ok();
2234
2235 if let Some(project_id) = this.shared_remote_id() {
2236 this.client
2237 .send(proto::StartLanguageServer {
2238 project_id,
2239 server: Some(proto::LanguageServer {
2240 id: server_id as u64,
2241 name: language_server.name().to_string(),
2242 }),
2243 })
2244 .log_err();
2245 }
2246
2247 // Tell the language server about every open buffer in the worktree that matches the language.
2248 for buffer in this.opened_buffers.values() {
2249 if let Some(buffer_handle) = buffer.upgrade(cx) {
2250 let buffer = buffer_handle.read(cx);
2251 let file = if let Some(file) = File::from_dyn(buffer.file()) {
2252 file
2253 } else {
2254 continue;
2255 };
2256 let language = if let Some(language) = buffer.language() {
2257 language
2258 } else {
2259 continue;
2260 };
2261 if file.worktree.read(cx).id() != key.0
2262 || language.lsp_adapter().map(|a| a.name())
2263 != Some(key.1.clone())
2264 {
2265 continue;
2266 }
2267
2268 let file = file.as_local()?;
2269 let versions = this
2270 .buffer_snapshots
2271 .entry(buffer.remote_id())
2272 .or_insert_with(|| vec![(0, buffer.text_snapshot())]);
2273 let (version, initial_snapshot) = versions.last().unwrap();
2274 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
2275 let language_id =
2276 adapter.id_for_language(language.name().as_ref());
2277 language_server
2278 .notify::<lsp::notification::DidOpenTextDocument>(
2279 lsp::DidOpenTextDocumentParams {
2280 text_document: lsp::TextDocumentItem::new(
2281 uri,
2282 language_id.unwrap_or_default(),
2283 *version,
2284 initial_snapshot.text(),
2285 ),
2286 },
2287 )
2288 .log_err()?;
2289 buffer_handle.update(cx, |buffer, cx| {
2290 buffer.set_completion_triggers(
2291 language_server
2292 .capabilities()
2293 .completion_provider
2294 .as_ref()
2295 .and_then(|provider| {
2296 provider.trigger_characters.clone()
2297 })
2298 .unwrap_or(Vec::new()),
2299 cx,
2300 )
2301 });
2302 }
2303 }
2304
2305 cx.notify();
2306 Some(language_server)
2307 })
2308 })),
2309 );
2310
2311 server_id
2312 });
2313 }
2314
2315 // Returns a list of all of the worktrees which no longer have a language server and the root path
2316 // for the stopped server
2317 fn stop_language_server(
2318 &mut self,
2319 worktree_id: WorktreeId,
2320 adapter_name: LanguageServerName,
2321 cx: &mut ModelContext<Self>,
2322 ) -> Task<(Option<PathBuf>, Vec<WorktreeId>)> {
2323 let key = (worktree_id, adapter_name);
2324 if let Some(server_id) = self.language_server_ids.remove(&key) {
2325 // Remove other entries for this language server as well
2326 let mut orphaned_worktrees = vec![worktree_id];
2327 let other_keys = self.language_server_ids.keys().cloned().collect::<Vec<_>>();
2328 for other_key in other_keys {
2329 if self.language_server_ids.get(&other_key) == Some(&server_id) {
2330 self.language_server_ids.remove(&other_key);
2331 orphaned_worktrees.push(other_key.0);
2332 }
2333 }
2334
2335 self.language_server_statuses.remove(&server_id);
2336 cx.notify();
2337
2338 let server_state = self.language_servers.remove(&server_id);
2339 cx.spawn_weak(|this, mut cx| async move {
2340 let mut root_path = None;
2341
2342 let server = match server_state {
2343 Some(LanguageServerState::Starting(started_language_server)) => {
2344 started_language_server.await
2345 }
2346 Some(LanguageServerState::Running { server, .. }) => Some(server),
2347 None => None,
2348 };
2349
2350 if let Some(server) = server {
2351 root_path = Some(server.root_path().clone());
2352 if let Some(shutdown) = server.shutdown() {
2353 shutdown.await;
2354 }
2355 }
2356
2357 if let Some(this) = this.upgrade(&cx) {
2358 this.update(&mut cx, |this, cx| {
2359 this.language_server_statuses.remove(&server_id);
2360 cx.notify();
2361 });
2362 }
2363
2364 (root_path, orphaned_worktrees)
2365 })
2366 } else {
2367 Task::ready((None, Vec::new()))
2368 }
2369 }
2370
2371 pub fn restart_language_servers_for_buffers(
2372 &mut self,
2373 buffers: impl IntoIterator<Item = ModelHandle<Buffer>>,
2374 cx: &mut ModelContext<Self>,
2375 ) -> Option<()> {
2376 let language_server_lookup_info: HashSet<(WorktreeId, Arc<Path>, PathBuf)> = buffers
2377 .into_iter()
2378 .filter_map(|buffer| {
2379 let file = File::from_dyn(buffer.read(cx).file())?;
2380 let worktree = file.worktree.read(cx).as_local()?;
2381 let worktree_id = worktree.id();
2382 let worktree_abs_path = worktree.abs_path().clone();
2383 let full_path = file.full_path(cx);
2384 Some((worktree_id, worktree_abs_path, full_path))
2385 })
2386 .collect();
2387 for (worktree_id, worktree_abs_path, full_path) in language_server_lookup_info {
2388 let language = self.languages.select_language(&full_path)?;
2389 self.restart_language_server(worktree_id, worktree_abs_path, language, cx);
2390 }
2391
2392 None
2393 }
2394
2395 fn restart_language_server(
2396 &mut self,
2397 worktree_id: WorktreeId,
2398 fallback_path: Arc<Path>,
2399 language: Arc<Language>,
2400 cx: &mut ModelContext<Self>,
2401 ) {
2402 let adapter = if let Some(adapter) = language.lsp_adapter() {
2403 adapter
2404 } else {
2405 return;
2406 };
2407
2408 let server_name = adapter.name();
2409 let stop = self.stop_language_server(worktree_id, server_name.clone(), cx);
2410 cx.spawn_weak(|this, mut cx| async move {
2411 let (original_root_path, orphaned_worktrees) = stop.await;
2412 if let Some(this) = this.upgrade(&cx) {
2413 this.update(&mut cx, |this, cx| {
2414 // Attempt to restart using original server path. Fallback to passed in
2415 // path if we could not retrieve the root path
2416 let root_path = original_root_path
2417 .map(|path_buf| Arc::from(path_buf.as_path()))
2418 .unwrap_or(fallback_path);
2419
2420 this.start_language_server(worktree_id, root_path, language, cx);
2421
2422 // Lookup new server id and set it for each of the orphaned worktrees
2423 if let Some(new_server_id) = this
2424 .language_server_ids
2425 .get(&(worktree_id, server_name.clone()))
2426 .cloned()
2427 {
2428 for orphaned_worktree in orphaned_worktrees {
2429 this.language_server_ids.insert(
2430 (orphaned_worktree, server_name.clone()),
2431 new_server_id.clone(),
2432 );
2433 }
2434 }
2435 });
2436 }
2437 })
2438 .detach();
2439 }
2440
2441 fn on_lsp_diagnostics_published(
2442 &mut self,
2443 server_id: usize,
2444 mut params: lsp::PublishDiagnosticsParams,
2445 adapter: &Arc<dyn LspAdapter>,
2446 cx: &mut ModelContext<Self>,
2447 ) {
2448 adapter.process_diagnostics(&mut params);
2449 self.update_diagnostics(
2450 server_id,
2451 params,
2452 adapter.disk_based_diagnostic_sources(),
2453 cx,
2454 )
2455 .log_err();
2456 }
2457
2458 fn on_lsp_progress(
2459 &mut self,
2460 progress: lsp::ProgressParams,
2461 server_id: usize,
2462 disk_based_diagnostics_progress_token: Option<&str>,
2463 cx: &mut ModelContext<Self>,
2464 ) {
2465 let token = match progress.token {
2466 lsp::NumberOrString::String(token) => token,
2467 lsp::NumberOrString::Number(token) => {
2468 log::info!("skipping numeric progress token {}", token);
2469 return;
2470 }
2471 };
2472 let progress = match progress.value {
2473 lsp::ProgressParamsValue::WorkDone(value) => value,
2474 };
2475 let language_server_status =
2476 if let Some(status) = self.language_server_statuses.get_mut(&server_id) {
2477 status
2478 } else {
2479 return;
2480 };
2481
2482 if !language_server_status.progress_tokens.contains(&token) {
2483 return;
2484 }
2485
2486 match progress {
2487 lsp::WorkDoneProgress::Begin(report) => {
2488 if Some(token.as_str()) == disk_based_diagnostics_progress_token {
2489 language_server_status.has_pending_diagnostic_updates = true;
2490 self.disk_based_diagnostics_started(server_id, cx);
2491 self.broadcast_language_server_update(
2492 server_id,
2493 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
2494 proto::LspDiskBasedDiagnosticsUpdating {},
2495 ),
2496 );
2497 } else {
2498 self.on_lsp_work_start(
2499 server_id,
2500 token.clone(),
2501 LanguageServerProgress {
2502 message: report.message.clone(),
2503 percentage: report.percentage.map(|p| p as usize),
2504 last_update_at: Instant::now(),
2505 },
2506 cx,
2507 );
2508 self.broadcast_language_server_update(
2509 server_id,
2510 proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
2511 token,
2512 message: report.message,
2513 percentage: report.percentage.map(|p| p as u32),
2514 }),
2515 );
2516 }
2517 }
2518 lsp::WorkDoneProgress::Report(report) => {
2519 if Some(token.as_str()) != disk_based_diagnostics_progress_token {
2520 self.on_lsp_work_progress(
2521 server_id,
2522 token.clone(),
2523 LanguageServerProgress {
2524 message: report.message.clone(),
2525 percentage: report.percentage.map(|p| p as usize),
2526 last_update_at: Instant::now(),
2527 },
2528 cx,
2529 );
2530 self.broadcast_language_server_update(
2531 server_id,
2532 proto::update_language_server::Variant::WorkProgress(
2533 proto::LspWorkProgress {
2534 token,
2535 message: report.message,
2536 percentage: report.percentage.map(|p| p as u32),
2537 },
2538 ),
2539 );
2540 }
2541 }
2542 lsp::WorkDoneProgress::End(_) => {
2543 language_server_status.progress_tokens.remove(&token);
2544
2545 if Some(token.as_str()) == disk_based_diagnostics_progress_token {
2546 language_server_status.has_pending_diagnostic_updates = false;
2547 self.disk_based_diagnostics_finished(server_id, cx);
2548 self.broadcast_language_server_update(
2549 server_id,
2550 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
2551 proto::LspDiskBasedDiagnosticsUpdated {},
2552 ),
2553 );
2554 } else {
2555 self.on_lsp_work_end(server_id, token.clone(), cx);
2556 self.broadcast_language_server_update(
2557 server_id,
2558 proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
2559 token,
2560 }),
2561 );
2562 }
2563 }
2564 }
2565 }
2566
2567 fn on_lsp_work_start(
2568 &mut self,
2569 language_server_id: usize,
2570 token: String,
2571 progress: LanguageServerProgress,
2572 cx: &mut ModelContext<Self>,
2573 ) {
2574 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
2575 status.pending_work.insert(token, progress);
2576 cx.notify();
2577 }
2578 }
2579
2580 fn on_lsp_work_progress(
2581 &mut self,
2582 language_server_id: usize,
2583 token: String,
2584 progress: LanguageServerProgress,
2585 cx: &mut ModelContext<Self>,
2586 ) {
2587 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
2588 let entry = status
2589 .pending_work
2590 .entry(token)
2591 .or_insert(LanguageServerProgress {
2592 message: Default::default(),
2593 percentage: Default::default(),
2594 last_update_at: progress.last_update_at,
2595 });
2596 if progress.message.is_some() {
2597 entry.message = progress.message;
2598 }
2599 if progress.percentage.is_some() {
2600 entry.percentage = progress.percentage;
2601 }
2602 entry.last_update_at = progress.last_update_at;
2603 cx.notify();
2604 }
2605 }
2606
2607 fn on_lsp_work_end(
2608 &mut self,
2609 language_server_id: usize,
2610 token: String,
2611 cx: &mut ModelContext<Self>,
2612 ) {
2613 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
2614 status.pending_work.remove(&token);
2615 cx.notify();
2616 }
2617 }
2618
2619 async fn on_lsp_workspace_edit(
2620 this: WeakModelHandle<Self>,
2621 params: lsp::ApplyWorkspaceEditParams,
2622 server_id: usize,
2623 adapter: Arc<dyn LspAdapter>,
2624 language_server: Arc<LanguageServer>,
2625 mut cx: AsyncAppContext,
2626 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
2627 let this = this
2628 .upgrade(&cx)
2629 .ok_or_else(|| anyhow!("project project closed"))?;
2630 let transaction = Self::deserialize_workspace_edit(
2631 this.clone(),
2632 params.edit,
2633 true,
2634 adapter.clone(),
2635 language_server.clone(),
2636 &mut cx,
2637 )
2638 .await
2639 .log_err();
2640 this.update(&mut cx, |this, _| {
2641 if let Some(transaction) = transaction {
2642 this.last_workspace_edits_by_language_server
2643 .insert(server_id, transaction);
2644 }
2645 });
2646 Ok(lsp::ApplyWorkspaceEditResponse {
2647 applied: true,
2648 failed_change: None,
2649 failure_reason: None,
2650 })
2651 }
2652
2653 fn broadcast_language_server_update(
2654 &self,
2655 language_server_id: usize,
2656 event: proto::update_language_server::Variant,
2657 ) {
2658 if let Some(project_id) = self.shared_remote_id() {
2659 self.client
2660 .send(proto::UpdateLanguageServer {
2661 project_id,
2662 language_server_id: language_server_id as u64,
2663 variant: Some(event),
2664 })
2665 .log_err();
2666 }
2667 }
2668
2669 pub fn set_language_server_settings(&mut self, settings: serde_json::Value) {
2670 for server_state in self.language_servers.values() {
2671 if let LanguageServerState::Running { server, .. } = server_state {
2672 server
2673 .notify::<lsp::notification::DidChangeConfiguration>(
2674 lsp::DidChangeConfigurationParams {
2675 settings: settings.clone(),
2676 },
2677 )
2678 .ok();
2679 }
2680 }
2681 *self.language_server_settings.lock() = settings;
2682 }
2683
2684 pub fn language_server_statuses(
2685 &self,
2686 ) -> impl DoubleEndedIterator<Item = &LanguageServerStatus> {
2687 self.language_server_statuses.values()
2688 }
2689
2690 pub fn update_diagnostics(
2691 &mut self,
2692 language_server_id: usize,
2693 params: lsp::PublishDiagnosticsParams,
2694 disk_based_sources: &[&str],
2695 cx: &mut ModelContext<Self>,
2696 ) -> Result<()> {
2697 let abs_path = params
2698 .uri
2699 .to_file_path()
2700 .map_err(|_| anyhow!("URI is not a file"))?;
2701 let mut diagnostics = Vec::default();
2702 let mut primary_diagnostic_group_ids = HashMap::default();
2703 let mut sources_by_group_id = HashMap::default();
2704 let mut supporting_diagnostics = HashMap::default();
2705 for diagnostic in ¶ms.diagnostics {
2706 let source = diagnostic.source.as_ref();
2707 let code = diagnostic.code.as_ref().map(|code| match code {
2708 lsp::NumberOrString::Number(code) => code.to_string(),
2709 lsp::NumberOrString::String(code) => code.clone(),
2710 });
2711 let range = range_from_lsp(diagnostic.range);
2712 let is_supporting = diagnostic
2713 .related_information
2714 .as_ref()
2715 .map_or(false, |infos| {
2716 infos.iter().any(|info| {
2717 primary_diagnostic_group_ids.contains_key(&(
2718 source,
2719 code.clone(),
2720 range_from_lsp(info.location.range),
2721 ))
2722 })
2723 });
2724
2725 let is_unnecessary = diagnostic.tags.as_ref().map_or(false, |tags| {
2726 tags.iter().any(|tag| *tag == DiagnosticTag::UNNECESSARY)
2727 });
2728
2729 if is_supporting {
2730 supporting_diagnostics.insert(
2731 (source, code.clone(), range),
2732 (diagnostic.severity, is_unnecessary),
2733 );
2734 } else {
2735 let group_id = post_inc(&mut self.next_diagnostic_group_id);
2736 let is_disk_based = source.map_or(false, |source| {
2737 disk_based_sources.contains(&source.as_str())
2738 });
2739
2740 sources_by_group_id.insert(group_id, source);
2741 primary_diagnostic_group_ids
2742 .insert((source, code.clone(), range.clone()), group_id);
2743
2744 diagnostics.push(DiagnosticEntry {
2745 range,
2746 diagnostic: Diagnostic {
2747 code: code.clone(),
2748 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
2749 message: diagnostic.message.clone(),
2750 group_id,
2751 is_primary: true,
2752 is_valid: true,
2753 is_disk_based,
2754 is_unnecessary,
2755 },
2756 });
2757 if let Some(infos) = &diagnostic.related_information {
2758 for info in infos {
2759 if info.location.uri == params.uri && !info.message.is_empty() {
2760 let range = range_from_lsp(info.location.range);
2761 diagnostics.push(DiagnosticEntry {
2762 range,
2763 diagnostic: Diagnostic {
2764 code: code.clone(),
2765 severity: DiagnosticSeverity::INFORMATION,
2766 message: info.message.clone(),
2767 group_id,
2768 is_primary: false,
2769 is_valid: true,
2770 is_disk_based,
2771 is_unnecessary: false,
2772 },
2773 });
2774 }
2775 }
2776 }
2777 }
2778 }
2779
2780 for entry in &mut diagnostics {
2781 let diagnostic = &mut entry.diagnostic;
2782 if !diagnostic.is_primary {
2783 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
2784 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
2785 source,
2786 diagnostic.code.clone(),
2787 entry.range.clone(),
2788 )) {
2789 if let Some(severity) = severity {
2790 diagnostic.severity = severity;
2791 }
2792 diagnostic.is_unnecessary = is_unnecessary;
2793 }
2794 }
2795 }
2796
2797 self.update_diagnostic_entries(
2798 language_server_id,
2799 abs_path,
2800 params.version,
2801 diagnostics,
2802 cx,
2803 )?;
2804 Ok(())
2805 }
2806
2807 pub fn update_diagnostic_entries(
2808 &mut self,
2809 language_server_id: usize,
2810 abs_path: PathBuf,
2811 version: Option<i32>,
2812 diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
2813 cx: &mut ModelContext<Project>,
2814 ) -> Result<(), anyhow::Error> {
2815 let (worktree, relative_path) = self
2816 .find_local_worktree(&abs_path, cx)
2817 .ok_or_else(|| anyhow!("no worktree found for diagnostics"))?;
2818
2819 let project_path = ProjectPath {
2820 worktree_id: worktree.read(cx).id(),
2821 path: relative_path.into(),
2822 };
2823 if let Some(buffer) = self.get_open_buffer(&project_path, cx) {
2824 self.update_buffer_diagnostics(&buffer, diagnostics.clone(), version, cx)?;
2825 }
2826
2827 let updated = worktree.update(cx, |worktree, cx| {
2828 worktree
2829 .as_local_mut()
2830 .ok_or_else(|| anyhow!("not a local worktree"))?
2831 .update_diagnostics(
2832 language_server_id,
2833 project_path.path.clone(),
2834 diagnostics,
2835 cx,
2836 )
2837 })?;
2838 if updated {
2839 cx.emit(Event::DiagnosticsUpdated {
2840 language_server_id,
2841 path: project_path,
2842 });
2843 }
2844 Ok(())
2845 }
2846
2847 fn update_buffer_diagnostics(
2848 &mut self,
2849 buffer: &ModelHandle<Buffer>,
2850 mut diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
2851 version: Option<i32>,
2852 cx: &mut ModelContext<Self>,
2853 ) -> Result<()> {
2854 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2855 Ordering::Equal
2856 .then_with(|| b.is_primary.cmp(&a.is_primary))
2857 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2858 .then_with(|| a.severity.cmp(&b.severity))
2859 .then_with(|| a.message.cmp(&b.message))
2860 }
2861
2862 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx)?;
2863
2864 diagnostics.sort_unstable_by(|a, b| {
2865 Ordering::Equal
2866 .then_with(|| a.range.start.cmp(&b.range.start))
2867 .then_with(|| b.range.end.cmp(&a.range.end))
2868 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2869 });
2870
2871 let mut sanitized_diagnostics = Vec::new();
2872 let edits_since_save = Patch::new(
2873 snapshot
2874 .edits_since::<PointUtf16>(buffer.read(cx).saved_version())
2875 .collect(),
2876 );
2877 for entry in diagnostics {
2878 let start;
2879 let end;
2880 if entry.diagnostic.is_disk_based {
2881 // Some diagnostics are based on files on disk instead of buffers'
2882 // current contents. Adjust these diagnostics' ranges to reflect
2883 // any unsaved edits.
2884 start = edits_since_save.old_to_new(entry.range.start);
2885 end = edits_since_save.old_to_new(entry.range.end);
2886 } else {
2887 start = entry.range.start;
2888 end = entry.range.end;
2889 }
2890
2891 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2892 ..snapshot.clip_point_utf16(end, Bias::Right);
2893
2894 // Expand empty ranges by one character
2895 if range.start == range.end {
2896 range.end.column += 1;
2897 range.end = snapshot.clip_point_utf16(range.end, Bias::Right);
2898 if range.start == range.end && range.end.column > 0 {
2899 range.start.column -= 1;
2900 range.start = snapshot.clip_point_utf16(range.start, Bias::Left);
2901 }
2902 }
2903
2904 sanitized_diagnostics.push(DiagnosticEntry {
2905 range,
2906 diagnostic: entry.diagnostic,
2907 });
2908 }
2909 drop(edits_since_save);
2910
2911 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2912 buffer.update(cx, |buffer, cx| buffer.update_diagnostics(set, cx));
2913 Ok(())
2914 }
2915
2916 pub fn reload_buffers(
2917 &self,
2918 buffers: HashSet<ModelHandle<Buffer>>,
2919 push_to_history: bool,
2920 cx: &mut ModelContext<Self>,
2921 ) -> Task<Result<ProjectTransaction>> {
2922 let mut local_buffers = Vec::new();
2923 let mut remote_buffers = None;
2924 for buffer_handle in buffers {
2925 let buffer = buffer_handle.read(cx);
2926 if buffer.is_dirty() {
2927 if let Some(file) = File::from_dyn(buffer.file()) {
2928 if file.is_local() {
2929 local_buffers.push(buffer_handle);
2930 } else {
2931 remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
2932 }
2933 }
2934 }
2935 }
2936
2937 let remote_buffers = self.remote_id().zip(remote_buffers);
2938 let client = self.client.clone();
2939
2940 cx.spawn(|this, mut cx| async move {
2941 let mut project_transaction = ProjectTransaction::default();
2942
2943 if let Some((project_id, remote_buffers)) = remote_buffers {
2944 let response = client
2945 .request(proto::ReloadBuffers {
2946 project_id,
2947 buffer_ids: remote_buffers
2948 .iter()
2949 .map(|buffer| buffer.read_with(&cx, |buffer, _| buffer.remote_id()))
2950 .collect(),
2951 })
2952 .await?
2953 .transaction
2954 .ok_or_else(|| anyhow!("missing transaction"))?;
2955 project_transaction = this
2956 .update(&mut cx, |this, cx| {
2957 this.deserialize_project_transaction(response, push_to_history, cx)
2958 })
2959 .await?;
2960 }
2961
2962 for buffer in local_buffers {
2963 let transaction = buffer
2964 .update(&mut cx, |buffer, cx| buffer.reload(cx))
2965 .await?;
2966 buffer.update(&mut cx, |buffer, cx| {
2967 if let Some(transaction) = transaction {
2968 if !push_to_history {
2969 buffer.forget_transaction(transaction.id);
2970 }
2971 project_transaction.0.insert(cx.handle(), transaction);
2972 }
2973 });
2974 }
2975
2976 Ok(project_transaction)
2977 })
2978 }
2979
2980 pub fn format(
2981 &self,
2982 buffers: HashSet<ModelHandle<Buffer>>,
2983 push_to_history: bool,
2984 cx: &mut ModelContext<Project>,
2985 ) -> Task<Result<ProjectTransaction>> {
2986 let mut local_buffers = Vec::new();
2987 let mut remote_buffers = None;
2988 for buffer_handle in buffers {
2989 let buffer = buffer_handle.read(cx);
2990 if let Some(file) = File::from_dyn(buffer.file()) {
2991 if let Some(buffer_abs_path) = file.as_local().map(|f| f.abs_path(cx)) {
2992 if let Some((_, server)) = self.language_server_for_buffer(buffer, cx) {
2993 local_buffers.push((buffer_handle, buffer_abs_path, server.clone()));
2994 }
2995 } else {
2996 remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
2997 }
2998 } else {
2999 return Task::ready(Ok(Default::default()));
3000 }
3001 }
3002
3003 let remote_buffers = self.remote_id().zip(remote_buffers);
3004 let client = self.client.clone();
3005
3006 cx.spawn(|this, mut cx| async move {
3007 let mut project_transaction = ProjectTransaction::default();
3008
3009 if let Some((project_id, remote_buffers)) = remote_buffers {
3010 let response = client
3011 .request(proto::FormatBuffers {
3012 project_id,
3013 buffer_ids: remote_buffers
3014 .iter()
3015 .map(|buffer| buffer.read_with(&cx, |buffer, _| buffer.remote_id()))
3016 .collect(),
3017 })
3018 .await?
3019 .transaction
3020 .ok_or_else(|| anyhow!("missing transaction"))?;
3021 project_transaction = this
3022 .update(&mut cx, |this, cx| {
3023 this.deserialize_project_transaction(response, push_to_history, cx)
3024 })
3025 .await?;
3026 }
3027
3028 for (buffer, buffer_abs_path, language_server) in local_buffers {
3029 let (format_on_save, tab_size) = buffer.read_with(&cx, |buffer, cx| {
3030 let settings = cx.global::<Settings>();
3031 let language_name = buffer.language().map(|language| language.name());
3032 (
3033 settings.format_on_save(language_name.as_deref()),
3034 settings.tab_size(language_name.as_deref()),
3035 )
3036 });
3037
3038 let transaction = match format_on_save {
3039 settings::FormatOnSave::Off => continue,
3040 settings::FormatOnSave::LanguageServer => Self::format_via_lsp(
3041 &this,
3042 &buffer,
3043 &buffer_abs_path,
3044 &language_server,
3045 tab_size,
3046 &mut cx,
3047 )
3048 .await
3049 .context("failed to format via language server")?,
3050 settings::FormatOnSave::External { command, arguments } => {
3051 Self::format_via_external_command(
3052 &buffer,
3053 &buffer_abs_path,
3054 &command,
3055 &arguments,
3056 &mut cx,
3057 )
3058 .await
3059 .context(format!(
3060 "failed to format via external command {:?}",
3061 command
3062 ))?
3063 }
3064 };
3065
3066 if let Some(transaction) = transaction {
3067 if !push_to_history {
3068 buffer.update(&mut cx, |buffer, _| {
3069 buffer.forget_transaction(transaction.id)
3070 });
3071 }
3072 project_transaction.0.insert(buffer, transaction);
3073 }
3074 }
3075
3076 Ok(project_transaction)
3077 })
3078 }
3079
3080 async fn format_via_lsp(
3081 this: &ModelHandle<Self>,
3082 buffer: &ModelHandle<Buffer>,
3083 abs_path: &Path,
3084 language_server: &Arc<LanguageServer>,
3085 tab_size: NonZeroU32,
3086 cx: &mut AsyncAppContext,
3087 ) -> Result<Option<Transaction>> {
3088 let text_document =
3089 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(abs_path).unwrap());
3090 let capabilities = &language_server.capabilities();
3091 let lsp_edits = if capabilities
3092 .document_formatting_provider
3093 .as_ref()
3094 .map_or(false, |provider| *provider != lsp::OneOf::Left(false))
3095 {
3096 language_server
3097 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
3098 text_document,
3099 options: lsp::FormattingOptions {
3100 tab_size: tab_size.into(),
3101 insert_spaces: true,
3102 insert_final_newline: Some(true),
3103 ..Default::default()
3104 },
3105 work_done_progress_params: Default::default(),
3106 })
3107 .await?
3108 } else if capabilities
3109 .document_range_formatting_provider
3110 .as_ref()
3111 .map_or(false, |provider| *provider != lsp::OneOf::Left(false))
3112 {
3113 let buffer_start = lsp::Position::new(0, 0);
3114 let buffer_end =
3115 buffer.read_with(cx, |buffer, _| point_to_lsp(buffer.max_point_utf16()));
3116 language_server
3117 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
3118 text_document,
3119 range: lsp::Range::new(buffer_start, buffer_end),
3120 options: lsp::FormattingOptions {
3121 tab_size: tab_size.into(),
3122 insert_spaces: true,
3123 insert_final_newline: Some(true),
3124 ..Default::default()
3125 },
3126 work_done_progress_params: Default::default(),
3127 })
3128 .await?
3129 } else {
3130 None
3131 };
3132
3133 if let Some(lsp_edits) = lsp_edits {
3134 let edits = this
3135 .update(cx, |this, cx| {
3136 this.edits_from_lsp(&buffer, lsp_edits, None, cx)
3137 })
3138 .await?;
3139 buffer.update(cx, |buffer, cx| {
3140 buffer.finalize_last_transaction();
3141 buffer.start_transaction();
3142 for (range, text) in edits {
3143 buffer.edit([(range, text)], cx);
3144 }
3145 if buffer.end_transaction(cx).is_some() {
3146 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3147 Ok(Some(transaction))
3148 } else {
3149 Ok(None)
3150 }
3151 })
3152 } else {
3153 Ok(None)
3154 }
3155 }
3156
3157 async fn format_via_external_command(
3158 buffer: &ModelHandle<Buffer>,
3159 buffer_abs_path: &Path,
3160 command: &str,
3161 arguments: &[String],
3162 cx: &mut AsyncAppContext,
3163 ) -> Result<Option<Transaction>> {
3164 let working_dir_path = buffer.read_with(cx, |buffer, cx| {
3165 let file = File::from_dyn(buffer.file())?;
3166 let worktree = file.worktree.read(cx).as_local()?;
3167 let mut worktree_path = worktree.abs_path().to_path_buf();
3168 if worktree.root_entry()?.is_file() {
3169 worktree_path.pop();
3170 }
3171 Some(worktree_path)
3172 });
3173
3174 if let Some(working_dir_path) = working_dir_path {
3175 let mut child =
3176 smol::process::Command::new(command)
3177 .args(arguments.iter().map(|arg| {
3178 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
3179 }))
3180 .current_dir(&working_dir_path)
3181 .stdin(smol::process::Stdio::piped())
3182 .stdout(smol::process::Stdio::piped())
3183 .stderr(smol::process::Stdio::piped())
3184 .spawn()?;
3185 let stdin = child
3186 .stdin
3187 .as_mut()
3188 .ok_or_else(|| anyhow!("failed to acquire stdin"))?;
3189 let text = buffer.read_with(cx, |buffer, _| buffer.as_rope().clone());
3190 for chunk in text.chunks() {
3191 stdin.write_all(chunk.as_bytes()).await?;
3192 }
3193 stdin.flush().await?;
3194
3195 let output = child.output().await?;
3196 if !output.status.success() {
3197 return Err(anyhow!(
3198 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
3199 output.status.code(),
3200 String::from_utf8_lossy(&output.stdout),
3201 String::from_utf8_lossy(&output.stderr),
3202 ));
3203 }
3204
3205 let stdout = String::from_utf8(output.stdout)?;
3206 let diff = buffer
3207 .read_with(cx, |buffer, cx| buffer.diff(stdout, cx))
3208 .await;
3209 Ok(buffer.update(cx, |buffer, cx| buffer.apply_diff(diff, cx).cloned()))
3210 } else {
3211 Ok(None)
3212 }
3213 }
3214
3215 pub fn definition<T: ToPointUtf16>(
3216 &self,
3217 buffer: &ModelHandle<Buffer>,
3218 position: T,
3219 cx: &mut ModelContext<Self>,
3220 ) -> Task<Result<Vec<LocationLink>>> {
3221 let position = position.to_point_utf16(buffer.read(cx));
3222 self.request_lsp(buffer.clone(), GetDefinition { position }, cx)
3223 }
3224
3225 pub fn references<T: ToPointUtf16>(
3226 &self,
3227 buffer: &ModelHandle<Buffer>,
3228 position: T,
3229 cx: &mut ModelContext<Self>,
3230 ) -> Task<Result<Vec<Location>>> {
3231 let position = position.to_point_utf16(buffer.read(cx));
3232 self.request_lsp(buffer.clone(), GetReferences { position }, cx)
3233 }
3234
3235 pub fn document_highlights<T: ToPointUtf16>(
3236 &self,
3237 buffer: &ModelHandle<Buffer>,
3238 position: T,
3239 cx: &mut ModelContext<Self>,
3240 ) -> Task<Result<Vec<DocumentHighlight>>> {
3241 let position = position.to_point_utf16(buffer.read(cx));
3242
3243 self.request_lsp(buffer.clone(), GetDocumentHighlights { position }, cx)
3244 }
3245
3246 pub fn symbols(&self, query: &str, cx: &mut ModelContext<Self>) -> Task<Result<Vec<Symbol>>> {
3247 if self.is_local() {
3248 let mut requests = Vec::new();
3249 for ((worktree_id, _), server_id) in self.language_server_ids.iter() {
3250 let worktree_id = *worktree_id;
3251 if let Some(worktree) = self
3252 .worktree_for_id(worktree_id, cx)
3253 .and_then(|worktree| worktree.read(cx).as_local())
3254 {
3255 if let Some(LanguageServerState::Running { adapter, server }) =
3256 self.language_servers.get(server_id)
3257 {
3258 let adapter = adapter.clone();
3259 let worktree_abs_path = worktree.abs_path().clone();
3260 requests.push(
3261 server
3262 .request::<lsp::request::WorkspaceSymbol>(
3263 lsp::WorkspaceSymbolParams {
3264 query: query.to_string(),
3265 ..Default::default()
3266 },
3267 )
3268 .log_err()
3269 .map(move |response| {
3270 (
3271 adapter,
3272 worktree_id,
3273 worktree_abs_path,
3274 response.unwrap_or_default(),
3275 )
3276 }),
3277 );
3278 }
3279 }
3280 }
3281
3282 cx.spawn_weak(|this, cx| async move {
3283 let responses = futures::future::join_all(requests).await;
3284 let this = if let Some(this) = this.upgrade(&cx) {
3285 this
3286 } else {
3287 return Ok(Default::default());
3288 };
3289 this.read_with(&cx, |this, cx| {
3290 let mut symbols = Vec::new();
3291 for (adapter, source_worktree_id, worktree_abs_path, response) in responses {
3292 symbols.extend(response.into_iter().flatten().filter_map(|lsp_symbol| {
3293 let abs_path = lsp_symbol.location.uri.to_file_path().ok()?;
3294 let mut worktree_id = source_worktree_id;
3295 let path;
3296 if let Some((worktree, rel_path)) =
3297 this.find_local_worktree(&abs_path, cx)
3298 {
3299 worktree_id = worktree.read(cx).id();
3300 path = rel_path;
3301 } else {
3302 path = relativize_path(&worktree_abs_path, &abs_path);
3303 }
3304
3305 let label = this
3306 .languages
3307 .select_language(&path)
3308 .and_then(|language| {
3309 language.label_for_symbol(&lsp_symbol.name, lsp_symbol.kind)
3310 })
3311 .unwrap_or_else(|| CodeLabel::plain(lsp_symbol.name.clone(), None));
3312 let signature = this.symbol_signature(worktree_id, &path);
3313
3314 Some(Symbol {
3315 source_worktree_id,
3316 worktree_id,
3317 language_server_name: adapter.name(),
3318 name: lsp_symbol.name,
3319 kind: lsp_symbol.kind,
3320 label,
3321 path,
3322 range: range_from_lsp(lsp_symbol.location.range),
3323 signature,
3324 })
3325 }));
3326 }
3327 Ok(symbols)
3328 })
3329 })
3330 } else if let Some(project_id) = self.remote_id() {
3331 let request = self.client.request(proto::GetProjectSymbols {
3332 project_id,
3333 query: query.to_string(),
3334 });
3335 cx.spawn_weak(|this, cx| async move {
3336 let response = request.await?;
3337 let mut symbols = Vec::new();
3338 if let Some(this) = this.upgrade(&cx) {
3339 this.read_with(&cx, |this, _| {
3340 symbols.extend(
3341 response
3342 .symbols
3343 .into_iter()
3344 .filter_map(|symbol| this.deserialize_symbol(symbol).log_err()),
3345 );
3346 })
3347 }
3348 Ok(symbols)
3349 })
3350 } else {
3351 Task::ready(Ok(Default::default()))
3352 }
3353 }
3354
3355 pub fn open_buffer_for_symbol(
3356 &mut self,
3357 symbol: &Symbol,
3358 cx: &mut ModelContext<Self>,
3359 ) -> Task<Result<ModelHandle<Buffer>>> {
3360 if self.is_local() {
3361 let language_server_id = if let Some(id) = self.language_server_ids.get(&(
3362 symbol.source_worktree_id,
3363 symbol.language_server_name.clone(),
3364 )) {
3365 *id
3366 } else {
3367 return Task::ready(Err(anyhow!(
3368 "language server for worktree and language not found"
3369 )));
3370 };
3371
3372 let worktree_abs_path = if let Some(worktree_abs_path) = self
3373 .worktree_for_id(symbol.worktree_id, cx)
3374 .and_then(|worktree| worktree.read(cx).as_local())
3375 .map(|local_worktree| local_worktree.abs_path())
3376 {
3377 worktree_abs_path
3378 } else {
3379 return Task::ready(Err(anyhow!("worktree not found for symbol")));
3380 };
3381 let symbol_abs_path = worktree_abs_path.join(&symbol.path);
3382 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
3383 uri
3384 } else {
3385 return Task::ready(Err(anyhow!("invalid symbol path")));
3386 };
3387
3388 self.open_local_buffer_via_lsp(
3389 symbol_uri,
3390 language_server_id,
3391 symbol.language_server_name.clone(),
3392 cx,
3393 )
3394 } else if let Some(project_id) = self.remote_id() {
3395 let request = self.client.request(proto::OpenBufferForSymbol {
3396 project_id,
3397 symbol: Some(serialize_symbol(symbol)),
3398 });
3399 cx.spawn(|this, mut cx| async move {
3400 let response = request.await?;
3401 let buffer = response.buffer.ok_or_else(|| anyhow!("invalid buffer"))?;
3402 this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
3403 .await
3404 })
3405 } else {
3406 Task::ready(Err(anyhow!("project does not have a remote id")))
3407 }
3408 }
3409
3410 pub fn hover<T: ToPointUtf16>(
3411 &self,
3412 buffer: &ModelHandle<Buffer>,
3413 position: T,
3414 cx: &mut ModelContext<Self>,
3415 ) -> Task<Result<Option<Hover>>> {
3416 let position = position.to_point_utf16(buffer.read(cx));
3417 self.request_lsp(buffer.clone(), GetHover { position }, cx)
3418 }
3419
3420 pub fn completions<T: ToPointUtf16>(
3421 &self,
3422 source_buffer_handle: &ModelHandle<Buffer>,
3423 position: T,
3424 cx: &mut ModelContext<Self>,
3425 ) -> Task<Result<Vec<Completion>>> {
3426 let source_buffer_handle = source_buffer_handle.clone();
3427 let source_buffer = source_buffer_handle.read(cx);
3428 let buffer_id = source_buffer.remote_id();
3429 let language = source_buffer.language().cloned();
3430 let worktree;
3431 let buffer_abs_path;
3432 if let Some(file) = File::from_dyn(source_buffer.file()) {
3433 worktree = file.worktree.clone();
3434 buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
3435 } else {
3436 return Task::ready(Ok(Default::default()));
3437 };
3438
3439 let position = position.to_point_utf16(source_buffer);
3440 let anchor = source_buffer.anchor_after(position);
3441
3442 if worktree.read(cx).as_local().is_some() {
3443 let buffer_abs_path = buffer_abs_path.unwrap();
3444 let lang_server =
3445 if let Some((_, server)) = self.language_server_for_buffer(source_buffer, cx) {
3446 server.clone()
3447 } else {
3448 return Task::ready(Ok(Default::default()));
3449 };
3450
3451 cx.spawn(|_, cx| async move {
3452 let completions = lang_server
3453 .request::<lsp::request::Completion>(lsp::CompletionParams {
3454 text_document_position: lsp::TextDocumentPositionParams::new(
3455 lsp::TextDocumentIdentifier::new(
3456 lsp::Url::from_file_path(buffer_abs_path).unwrap(),
3457 ),
3458 point_to_lsp(position),
3459 ),
3460 context: Default::default(),
3461 work_done_progress_params: Default::default(),
3462 partial_result_params: Default::default(),
3463 })
3464 .await
3465 .context("lsp completion request failed")?;
3466
3467 let completions = if let Some(completions) = completions {
3468 match completions {
3469 lsp::CompletionResponse::Array(completions) => completions,
3470 lsp::CompletionResponse::List(list) => list.items,
3471 }
3472 } else {
3473 Default::default()
3474 };
3475
3476 source_buffer_handle.read_with(&cx, |this, _| {
3477 let snapshot = this.snapshot();
3478 let clipped_position = this.clip_point_utf16(position, Bias::Left);
3479 let mut range_for_token = None;
3480 Ok(completions
3481 .into_iter()
3482 .filter_map(|lsp_completion| {
3483 // For now, we can only handle additional edits if they are returned
3484 // when resolving the completion, not if they are present initially.
3485 if lsp_completion
3486 .additional_text_edits
3487 .as_ref()
3488 .map_or(false, |edits| !edits.is_empty())
3489 {
3490 return None;
3491 }
3492
3493 let (old_range, mut new_text) = match lsp_completion.text_edit.as_ref()
3494 {
3495 // If the language server provides a range to overwrite, then
3496 // check that the range is valid.
3497 Some(lsp::CompletionTextEdit::Edit(edit)) => {
3498 let range = range_from_lsp(edit.range);
3499 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
3500 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
3501 if start != range.start || end != range.end {
3502 log::info!("completion out of expected range");
3503 return None;
3504 }
3505 (
3506 snapshot.anchor_before(start)..snapshot.anchor_after(end),
3507 edit.new_text.clone(),
3508 )
3509 }
3510 // If the language server does not provide a range, then infer
3511 // the range based on the syntax tree.
3512 None => {
3513 if position != clipped_position {
3514 log::info!("completion out of expected range");
3515 return None;
3516 }
3517 let Range { start, end } = range_for_token
3518 .get_or_insert_with(|| {
3519 let offset = position.to_offset(&snapshot);
3520 let (range, kind) = snapshot.surrounding_word(offset);
3521 if kind == Some(CharKind::Word) {
3522 range
3523 } else {
3524 offset..offset
3525 }
3526 })
3527 .clone();
3528 let text = lsp_completion
3529 .insert_text
3530 .as_ref()
3531 .unwrap_or(&lsp_completion.label)
3532 .clone();
3533 (
3534 snapshot.anchor_before(start)..snapshot.anchor_after(end),
3535 text.clone(),
3536 )
3537 }
3538 Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
3539 log::info!("unsupported insert/replace completion");
3540 return None;
3541 }
3542 };
3543
3544 LineEnding::normalize(&mut new_text);
3545 Some(Completion {
3546 old_range,
3547 new_text,
3548 label: language
3549 .as_ref()
3550 .and_then(|l| l.label_for_completion(&lsp_completion))
3551 .unwrap_or_else(|| {
3552 CodeLabel::plain(
3553 lsp_completion.label.clone(),
3554 lsp_completion.filter_text.as_deref(),
3555 )
3556 }),
3557 lsp_completion,
3558 })
3559 })
3560 .collect())
3561 })
3562 })
3563 } else if let Some(project_id) = self.remote_id() {
3564 let rpc = self.client.clone();
3565 let message = proto::GetCompletions {
3566 project_id,
3567 buffer_id,
3568 position: Some(language::proto::serialize_anchor(&anchor)),
3569 version: serialize_version(&source_buffer.version()),
3570 };
3571 cx.spawn_weak(|_, mut cx| async move {
3572 let response = rpc.request(message).await?;
3573
3574 source_buffer_handle
3575 .update(&mut cx, |buffer, _| {
3576 buffer.wait_for_version(deserialize_version(response.version))
3577 })
3578 .await;
3579
3580 response
3581 .completions
3582 .into_iter()
3583 .map(|completion| {
3584 language::proto::deserialize_completion(completion, language.as_ref())
3585 })
3586 .collect()
3587 })
3588 } else {
3589 Task::ready(Ok(Default::default()))
3590 }
3591 }
3592
3593 pub fn apply_additional_edits_for_completion(
3594 &self,
3595 buffer_handle: ModelHandle<Buffer>,
3596 completion: Completion,
3597 push_to_history: bool,
3598 cx: &mut ModelContext<Self>,
3599 ) -> Task<Result<Option<Transaction>>> {
3600 let buffer = buffer_handle.read(cx);
3601 let buffer_id = buffer.remote_id();
3602
3603 if self.is_local() {
3604 let lang_server = if let Some((_, server)) = self.language_server_for_buffer(buffer, cx)
3605 {
3606 server.clone()
3607 } else {
3608 return Task::ready(Ok(Default::default()));
3609 };
3610
3611 cx.spawn(|this, mut cx| async move {
3612 let resolved_completion = lang_server
3613 .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
3614 .await?;
3615 if let Some(edits) = resolved_completion.additional_text_edits {
3616 let edits = this
3617 .update(&mut cx, |this, cx| {
3618 this.edits_from_lsp(&buffer_handle, edits, None, cx)
3619 })
3620 .await?;
3621 buffer_handle.update(&mut cx, |buffer, cx| {
3622 buffer.finalize_last_transaction();
3623 buffer.start_transaction();
3624 for (range, text) in edits {
3625 buffer.edit([(range, text)], cx);
3626 }
3627 let transaction = if buffer.end_transaction(cx).is_some() {
3628 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3629 if !push_to_history {
3630 buffer.forget_transaction(transaction.id);
3631 }
3632 Some(transaction)
3633 } else {
3634 None
3635 };
3636 Ok(transaction)
3637 })
3638 } else {
3639 Ok(None)
3640 }
3641 })
3642 } else if let Some(project_id) = self.remote_id() {
3643 let client = self.client.clone();
3644 cx.spawn(|_, mut cx| async move {
3645 let response = client
3646 .request(proto::ApplyCompletionAdditionalEdits {
3647 project_id,
3648 buffer_id,
3649 completion: Some(language::proto::serialize_completion(&completion)),
3650 })
3651 .await?;
3652
3653 if let Some(transaction) = response.transaction {
3654 let transaction = language::proto::deserialize_transaction(transaction)?;
3655 buffer_handle
3656 .update(&mut cx, |buffer, _| {
3657 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
3658 })
3659 .await;
3660 if push_to_history {
3661 buffer_handle.update(&mut cx, |buffer, _| {
3662 buffer.push_transaction(transaction.clone(), Instant::now());
3663 });
3664 }
3665 Ok(Some(transaction))
3666 } else {
3667 Ok(None)
3668 }
3669 })
3670 } else {
3671 Task::ready(Err(anyhow!("project does not have a remote id")))
3672 }
3673 }
3674
3675 pub fn code_actions<T: Clone + ToOffset>(
3676 &self,
3677 buffer_handle: &ModelHandle<Buffer>,
3678 range: Range<T>,
3679 cx: &mut ModelContext<Self>,
3680 ) -> Task<Result<Vec<CodeAction>>> {
3681 let buffer_handle = buffer_handle.clone();
3682 let buffer = buffer_handle.read(cx);
3683 let snapshot = buffer.snapshot();
3684 let relevant_diagnostics = snapshot
3685 .diagnostics_in_range::<usize, usize>(range.to_offset(&snapshot), false)
3686 .map(|entry| entry.to_lsp_diagnostic_stub())
3687 .collect();
3688 let buffer_id = buffer.remote_id();
3689 let worktree;
3690 let buffer_abs_path;
3691 if let Some(file) = File::from_dyn(buffer.file()) {
3692 worktree = file.worktree.clone();
3693 buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
3694 } else {
3695 return Task::ready(Ok(Default::default()));
3696 };
3697 let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
3698
3699 if worktree.read(cx).as_local().is_some() {
3700 let buffer_abs_path = buffer_abs_path.unwrap();
3701 let lang_server = if let Some((_, server)) = self.language_server_for_buffer(buffer, cx)
3702 {
3703 server.clone()
3704 } else {
3705 return Task::ready(Ok(Default::default()));
3706 };
3707
3708 let lsp_range = range_to_lsp(range.to_point_utf16(buffer));
3709 cx.foreground().spawn(async move {
3710 if !lang_server.capabilities().code_action_provider.is_some() {
3711 return Ok(Default::default());
3712 }
3713
3714 Ok(lang_server
3715 .request::<lsp::request::CodeActionRequest>(lsp::CodeActionParams {
3716 text_document: lsp::TextDocumentIdentifier::new(
3717 lsp::Url::from_file_path(buffer_abs_path).unwrap(),
3718 ),
3719 range: lsp_range,
3720 work_done_progress_params: Default::default(),
3721 partial_result_params: Default::default(),
3722 context: lsp::CodeActionContext {
3723 diagnostics: relevant_diagnostics,
3724 only: Some(vec![
3725 lsp::CodeActionKind::QUICKFIX,
3726 lsp::CodeActionKind::REFACTOR,
3727 lsp::CodeActionKind::REFACTOR_EXTRACT,
3728 lsp::CodeActionKind::SOURCE,
3729 ]),
3730 },
3731 })
3732 .await?
3733 .unwrap_or_default()
3734 .into_iter()
3735 .filter_map(|entry| {
3736 if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
3737 Some(CodeAction {
3738 range: range.clone(),
3739 lsp_action,
3740 })
3741 } else {
3742 None
3743 }
3744 })
3745 .collect())
3746 })
3747 } else if let Some(project_id) = self.remote_id() {
3748 let rpc = self.client.clone();
3749 let version = buffer.version();
3750 cx.spawn_weak(|_, mut cx| async move {
3751 let response = rpc
3752 .request(proto::GetCodeActions {
3753 project_id,
3754 buffer_id,
3755 start: Some(language::proto::serialize_anchor(&range.start)),
3756 end: Some(language::proto::serialize_anchor(&range.end)),
3757 version: serialize_version(&version),
3758 })
3759 .await?;
3760
3761 buffer_handle
3762 .update(&mut cx, |buffer, _| {
3763 buffer.wait_for_version(deserialize_version(response.version))
3764 })
3765 .await;
3766
3767 response
3768 .actions
3769 .into_iter()
3770 .map(language::proto::deserialize_code_action)
3771 .collect()
3772 })
3773 } else {
3774 Task::ready(Ok(Default::default()))
3775 }
3776 }
3777
3778 pub fn apply_code_action(
3779 &self,
3780 buffer_handle: ModelHandle<Buffer>,
3781 mut action: CodeAction,
3782 push_to_history: bool,
3783 cx: &mut ModelContext<Self>,
3784 ) -> Task<Result<ProjectTransaction>> {
3785 if self.is_local() {
3786 let buffer = buffer_handle.read(cx);
3787 let (lsp_adapter, lang_server) =
3788 if let Some((adapter, server)) = self.language_server_for_buffer(buffer, cx) {
3789 (adapter.clone(), server.clone())
3790 } else {
3791 return Task::ready(Ok(Default::default()));
3792 };
3793 let range = action.range.to_point_utf16(buffer);
3794
3795 cx.spawn(|this, mut cx| async move {
3796 if let Some(lsp_range) = action
3797 .lsp_action
3798 .data
3799 .as_mut()
3800 .and_then(|d| d.get_mut("codeActionParams"))
3801 .and_then(|d| d.get_mut("range"))
3802 {
3803 *lsp_range = serde_json::to_value(&range_to_lsp(range)).unwrap();
3804 action.lsp_action = lang_server
3805 .request::<lsp::request::CodeActionResolveRequest>(action.lsp_action)
3806 .await?;
3807 } else {
3808 let actions = this
3809 .update(&mut cx, |this, cx| {
3810 this.code_actions(&buffer_handle, action.range, cx)
3811 })
3812 .await?;
3813 action.lsp_action = actions
3814 .into_iter()
3815 .find(|a| a.lsp_action.title == action.lsp_action.title)
3816 .ok_or_else(|| anyhow!("code action is outdated"))?
3817 .lsp_action;
3818 }
3819
3820 if let Some(edit) = action.lsp_action.edit {
3821 if edit.changes.is_some() || edit.document_changes.is_some() {
3822 return Self::deserialize_workspace_edit(
3823 this,
3824 edit,
3825 push_to_history,
3826 lsp_adapter.clone(),
3827 lang_server.clone(),
3828 &mut cx,
3829 )
3830 .await;
3831 }
3832 }
3833
3834 if let Some(command) = action.lsp_action.command {
3835 this.update(&mut cx, |this, _| {
3836 this.last_workspace_edits_by_language_server
3837 .remove(&lang_server.server_id());
3838 });
3839 lang_server
3840 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
3841 command: command.command,
3842 arguments: command.arguments.unwrap_or_default(),
3843 ..Default::default()
3844 })
3845 .await?;
3846 return Ok(this.update(&mut cx, |this, _| {
3847 this.last_workspace_edits_by_language_server
3848 .remove(&lang_server.server_id())
3849 .unwrap_or_default()
3850 }));
3851 }
3852
3853 Ok(ProjectTransaction::default())
3854 })
3855 } else if let Some(project_id) = self.remote_id() {
3856 let client = self.client.clone();
3857 let request = proto::ApplyCodeAction {
3858 project_id,
3859 buffer_id: buffer_handle.read(cx).remote_id(),
3860 action: Some(language::proto::serialize_code_action(&action)),
3861 };
3862 cx.spawn(|this, mut cx| async move {
3863 let response = client
3864 .request(request)
3865 .await?
3866 .transaction
3867 .ok_or_else(|| anyhow!("missing transaction"))?;
3868 this.update(&mut cx, |this, cx| {
3869 this.deserialize_project_transaction(response, push_to_history, cx)
3870 })
3871 .await
3872 })
3873 } else {
3874 Task::ready(Err(anyhow!("project does not have a remote id")))
3875 }
3876 }
3877
3878 async fn deserialize_workspace_edit(
3879 this: ModelHandle<Self>,
3880 edit: lsp::WorkspaceEdit,
3881 push_to_history: bool,
3882 lsp_adapter: Arc<dyn LspAdapter>,
3883 language_server: Arc<LanguageServer>,
3884 cx: &mut AsyncAppContext,
3885 ) -> Result<ProjectTransaction> {
3886 let fs = this.read_with(cx, |this, _| this.fs.clone());
3887 let mut operations = Vec::new();
3888 if let Some(document_changes) = edit.document_changes {
3889 match document_changes {
3890 lsp::DocumentChanges::Edits(edits) => {
3891 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3892 }
3893 lsp::DocumentChanges::Operations(ops) => operations = ops,
3894 }
3895 } else if let Some(changes) = edit.changes {
3896 operations.extend(changes.into_iter().map(|(uri, edits)| {
3897 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3898 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3899 uri,
3900 version: None,
3901 },
3902 edits: edits.into_iter().map(lsp::OneOf::Left).collect(),
3903 })
3904 }));
3905 }
3906
3907 let mut project_transaction = ProjectTransaction::default();
3908 for operation in operations {
3909 match operation {
3910 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3911 let abs_path = op
3912 .uri
3913 .to_file_path()
3914 .map_err(|_| anyhow!("can't convert URI to path"))?;
3915
3916 if let Some(parent_path) = abs_path.parent() {
3917 fs.create_dir(parent_path).await?;
3918 }
3919 if abs_path.ends_with("/") {
3920 fs.create_dir(&abs_path).await?;
3921 } else {
3922 fs.create_file(&abs_path, op.options.map(Into::into).unwrap_or_default())
3923 .await?;
3924 }
3925 }
3926 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3927 let source_abs_path = op
3928 .old_uri
3929 .to_file_path()
3930 .map_err(|_| anyhow!("can't convert URI to path"))?;
3931 let target_abs_path = op
3932 .new_uri
3933 .to_file_path()
3934 .map_err(|_| anyhow!("can't convert URI to path"))?;
3935 fs.rename(
3936 &source_abs_path,
3937 &target_abs_path,
3938 op.options.map(Into::into).unwrap_or_default(),
3939 )
3940 .await?;
3941 }
3942 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3943 let abs_path = op
3944 .uri
3945 .to_file_path()
3946 .map_err(|_| anyhow!("can't convert URI to path"))?;
3947 let options = op.options.map(Into::into).unwrap_or_default();
3948 if abs_path.ends_with("/") {
3949 fs.remove_dir(&abs_path, options).await?;
3950 } else {
3951 fs.remove_file(&abs_path, options).await?;
3952 }
3953 }
3954 lsp::DocumentChangeOperation::Edit(op) => {
3955 let buffer_to_edit = this
3956 .update(cx, |this, cx| {
3957 this.open_local_buffer_via_lsp(
3958 op.text_document.uri,
3959 language_server.server_id(),
3960 lsp_adapter.name(),
3961 cx,
3962 )
3963 })
3964 .await?;
3965
3966 let edits = this
3967 .update(cx, |this, cx| {
3968 let edits = op.edits.into_iter().map(|edit| match edit {
3969 lsp::OneOf::Left(edit) => edit,
3970 lsp::OneOf::Right(edit) => edit.text_edit,
3971 });
3972 this.edits_from_lsp(
3973 &buffer_to_edit,
3974 edits,
3975 op.text_document.version,
3976 cx,
3977 )
3978 })
3979 .await?;
3980
3981 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3982 buffer.finalize_last_transaction();
3983 buffer.start_transaction();
3984 for (range, text) in edits {
3985 buffer.edit([(range, text)], cx);
3986 }
3987 let transaction = if buffer.end_transaction(cx).is_some() {
3988 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3989 if !push_to_history {
3990 buffer.forget_transaction(transaction.id);
3991 }
3992 Some(transaction)
3993 } else {
3994 None
3995 };
3996
3997 transaction
3998 });
3999 if let Some(transaction) = transaction {
4000 project_transaction.0.insert(buffer_to_edit, transaction);
4001 }
4002 }
4003 }
4004 }
4005
4006 Ok(project_transaction)
4007 }
4008
4009 pub fn prepare_rename<T: ToPointUtf16>(
4010 &self,
4011 buffer: ModelHandle<Buffer>,
4012 position: T,
4013 cx: &mut ModelContext<Self>,
4014 ) -> Task<Result<Option<Range<Anchor>>>> {
4015 let position = position.to_point_utf16(buffer.read(cx));
4016 self.request_lsp(buffer, PrepareRename { position }, cx)
4017 }
4018
4019 pub fn perform_rename<T: ToPointUtf16>(
4020 &self,
4021 buffer: ModelHandle<Buffer>,
4022 position: T,
4023 new_name: String,
4024 push_to_history: bool,
4025 cx: &mut ModelContext<Self>,
4026 ) -> Task<Result<ProjectTransaction>> {
4027 let position = position.to_point_utf16(buffer.read(cx));
4028 self.request_lsp(
4029 buffer,
4030 PerformRename {
4031 position,
4032 new_name,
4033 push_to_history,
4034 },
4035 cx,
4036 )
4037 }
4038
4039 pub fn search(
4040 &self,
4041 query: SearchQuery,
4042 cx: &mut ModelContext<Self>,
4043 ) -> Task<Result<HashMap<ModelHandle<Buffer>, Vec<Range<Anchor>>>>> {
4044 if self.is_local() {
4045 let snapshots = self
4046 .visible_worktrees(cx)
4047 .filter_map(|tree| {
4048 let tree = tree.read(cx).as_local()?;
4049 Some(tree.snapshot())
4050 })
4051 .collect::<Vec<_>>();
4052
4053 let background = cx.background().clone();
4054 let path_count: usize = snapshots.iter().map(|s| s.visible_file_count()).sum();
4055 if path_count == 0 {
4056 return Task::ready(Ok(Default::default()));
4057 }
4058 let workers = background.num_cpus().min(path_count);
4059 let (matching_paths_tx, mut matching_paths_rx) = smol::channel::bounded(1024);
4060 cx.background()
4061 .spawn({
4062 let fs = self.fs.clone();
4063 let background = cx.background().clone();
4064 let query = query.clone();
4065 async move {
4066 let fs = &fs;
4067 let query = &query;
4068 let matching_paths_tx = &matching_paths_tx;
4069 let paths_per_worker = (path_count + workers - 1) / workers;
4070 let snapshots = &snapshots;
4071 background
4072 .scoped(|scope| {
4073 for worker_ix in 0..workers {
4074 let worker_start_ix = worker_ix * paths_per_worker;
4075 let worker_end_ix = worker_start_ix + paths_per_worker;
4076 scope.spawn(async move {
4077 let mut snapshot_start_ix = 0;
4078 let mut abs_path = PathBuf::new();
4079 for snapshot in snapshots {
4080 let snapshot_end_ix =
4081 snapshot_start_ix + snapshot.visible_file_count();
4082 if worker_end_ix <= snapshot_start_ix {
4083 break;
4084 } else if worker_start_ix > snapshot_end_ix {
4085 snapshot_start_ix = snapshot_end_ix;
4086 continue;
4087 } else {
4088 let start_in_snapshot = worker_start_ix
4089 .saturating_sub(snapshot_start_ix);
4090 let end_in_snapshot =
4091 cmp::min(worker_end_ix, snapshot_end_ix)
4092 - snapshot_start_ix;
4093
4094 for entry in snapshot
4095 .files(false, start_in_snapshot)
4096 .take(end_in_snapshot - start_in_snapshot)
4097 {
4098 if matching_paths_tx.is_closed() {
4099 break;
4100 }
4101
4102 abs_path.clear();
4103 abs_path.push(&snapshot.abs_path());
4104 abs_path.push(&entry.path);
4105 let matches = if let Some(file) =
4106 fs.open_sync(&abs_path).await.log_err()
4107 {
4108 query.detect(file).unwrap_or(false)
4109 } else {
4110 false
4111 };
4112
4113 if matches {
4114 let project_path =
4115 (snapshot.id(), entry.path.clone());
4116 if matching_paths_tx
4117 .send(project_path)
4118 .await
4119 .is_err()
4120 {
4121 break;
4122 }
4123 }
4124 }
4125
4126 snapshot_start_ix = snapshot_end_ix;
4127 }
4128 }
4129 });
4130 }
4131 })
4132 .await;
4133 }
4134 })
4135 .detach();
4136
4137 let (buffers_tx, buffers_rx) = smol::channel::bounded(1024);
4138 let open_buffers = self
4139 .opened_buffers
4140 .values()
4141 .filter_map(|b| b.upgrade(cx))
4142 .collect::<HashSet<_>>();
4143 cx.spawn(|this, cx| async move {
4144 for buffer in &open_buffers {
4145 let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4146 buffers_tx.send((buffer.clone(), snapshot)).await?;
4147 }
4148
4149 let open_buffers = Rc::new(RefCell::new(open_buffers));
4150 while let Some(project_path) = matching_paths_rx.next().await {
4151 if buffers_tx.is_closed() {
4152 break;
4153 }
4154
4155 let this = this.clone();
4156 let open_buffers = open_buffers.clone();
4157 let buffers_tx = buffers_tx.clone();
4158 cx.spawn(|mut cx| async move {
4159 if let Some(buffer) = this
4160 .update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
4161 .await
4162 .log_err()
4163 {
4164 if open_buffers.borrow_mut().insert(buffer.clone()) {
4165 let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4166 buffers_tx.send((buffer, snapshot)).await?;
4167 }
4168 }
4169
4170 Ok::<_, anyhow::Error>(())
4171 })
4172 .detach();
4173 }
4174
4175 Ok::<_, anyhow::Error>(())
4176 })
4177 .detach_and_log_err(cx);
4178
4179 let background = cx.background().clone();
4180 cx.background().spawn(async move {
4181 let query = &query;
4182 let mut matched_buffers = Vec::new();
4183 for _ in 0..workers {
4184 matched_buffers.push(HashMap::default());
4185 }
4186 background
4187 .scoped(|scope| {
4188 for worker_matched_buffers in matched_buffers.iter_mut() {
4189 let mut buffers_rx = buffers_rx.clone();
4190 scope.spawn(async move {
4191 while let Some((buffer, snapshot)) = buffers_rx.next().await {
4192 let buffer_matches = query
4193 .search(snapshot.as_rope())
4194 .await
4195 .iter()
4196 .map(|range| {
4197 snapshot.anchor_before(range.start)
4198 ..snapshot.anchor_after(range.end)
4199 })
4200 .collect::<Vec<_>>();
4201 if !buffer_matches.is_empty() {
4202 worker_matched_buffers
4203 .insert(buffer.clone(), buffer_matches);
4204 }
4205 }
4206 });
4207 }
4208 })
4209 .await;
4210 Ok(matched_buffers.into_iter().flatten().collect())
4211 })
4212 } else if let Some(project_id) = self.remote_id() {
4213 let request = self.client.request(query.to_proto(project_id));
4214 cx.spawn(|this, mut cx| async move {
4215 let response = request.await?;
4216 let mut result = HashMap::default();
4217 for location in response.locations {
4218 let buffer = location.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
4219 let target_buffer = this
4220 .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
4221 .await?;
4222 let start = location
4223 .start
4224 .and_then(deserialize_anchor)
4225 .ok_or_else(|| anyhow!("missing target start"))?;
4226 let end = location
4227 .end
4228 .and_then(deserialize_anchor)
4229 .ok_or_else(|| anyhow!("missing target end"))?;
4230 result
4231 .entry(target_buffer)
4232 .or_insert(Vec::new())
4233 .push(start..end)
4234 }
4235 Ok(result)
4236 })
4237 } else {
4238 Task::ready(Ok(Default::default()))
4239 }
4240 }
4241
4242 fn request_lsp<R: LspCommand>(
4243 &self,
4244 buffer_handle: ModelHandle<Buffer>,
4245 request: R,
4246 cx: &mut ModelContext<Self>,
4247 ) -> Task<Result<R::Response>>
4248 where
4249 <R::LspRequest as lsp::request::Request>::Result: Send,
4250 {
4251 let buffer = buffer_handle.read(cx);
4252 if self.is_local() {
4253 let file = File::from_dyn(buffer.file()).and_then(File::as_local);
4254 if let Some((file, language_server)) = file.zip(
4255 self.language_server_for_buffer(buffer, cx)
4256 .map(|(_, server)| server.clone()),
4257 ) {
4258 let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
4259 return cx.spawn(|this, cx| async move {
4260 if !request.check_capabilities(&language_server.capabilities()) {
4261 return Ok(Default::default());
4262 }
4263
4264 let response = language_server
4265 .request::<R::LspRequest>(lsp_params)
4266 .await
4267 .context("lsp request failed")?;
4268 request
4269 .response_from_lsp(response, this, buffer_handle, cx)
4270 .await
4271 });
4272 }
4273 } else if let Some(project_id) = self.remote_id() {
4274 let rpc = self.client.clone();
4275 let message = request.to_proto(project_id, buffer);
4276 return cx.spawn(|this, cx| async move {
4277 let response = rpc.request(message).await?;
4278 request
4279 .response_from_proto(response, this, buffer_handle, cx)
4280 .await
4281 });
4282 }
4283 Task::ready(Ok(Default::default()))
4284 }
4285
4286 pub fn find_or_create_local_worktree(
4287 &mut self,
4288 abs_path: impl AsRef<Path>,
4289 visible: bool,
4290 cx: &mut ModelContext<Self>,
4291 ) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
4292 let abs_path = abs_path.as_ref();
4293 if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) {
4294 Task::ready(Ok((tree.clone(), relative_path.into())))
4295 } else {
4296 let worktree = self.create_local_worktree(abs_path, visible, cx);
4297 cx.foreground()
4298 .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
4299 }
4300 }
4301
4302 pub fn find_local_worktree(
4303 &self,
4304 abs_path: &Path,
4305 cx: &AppContext,
4306 ) -> Option<(ModelHandle<Worktree>, PathBuf)> {
4307 for tree in &self.worktrees {
4308 if let Some(tree) = tree.upgrade(cx) {
4309 if let Some(relative_path) = tree
4310 .read(cx)
4311 .as_local()
4312 .and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
4313 {
4314 return Some((tree.clone(), relative_path.into()));
4315 }
4316 }
4317 }
4318 None
4319 }
4320
4321 pub fn is_shared(&self) -> bool {
4322 match &self.client_state {
4323 ProjectClientState::Local { is_shared, .. } => *is_shared,
4324 ProjectClientState::Remote { .. } => false,
4325 }
4326 }
4327
4328 fn create_local_worktree(
4329 &mut self,
4330 abs_path: impl AsRef<Path>,
4331 visible: bool,
4332 cx: &mut ModelContext<Self>,
4333 ) -> Task<Result<ModelHandle<Worktree>>> {
4334 let fs = self.fs.clone();
4335 let client = self.client.clone();
4336 let next_entry_id = self.next_entry_id.clone();
4337 let path: Arc<Path> = abs_path.as_ref().into();
4338 let task = self
4339 .loading_local_worktrees
4340 .entry(path.clone())
4341 .or_insert_with(|| {
4342 cx.spawn(|project, mut cx| {
4343 async move {
4344 let worktree = Worktree::local(
4345 client.clone(),
4346 path.clone(),
4347 visible,
4348 fs,
4349 next_entry_id,
4350 &mut cx,
4351 )
4352 .await;
4353 project.update(&mut cx, |project, _| {
4354 project.loading_local_worktrees.remove(&path);
4355 });
4356 let worktree = worktree?;
4357
4358 let project_id = project.update(&mut cx, |project, cx| {
4359 project.add_worktree(&worktree, cx);
4360 project.shared_remote_id()
4361 });
4362
4363 if let Some(project_id) = project_id {
4364 worktree
4365 .update(&mut cx, |worktree, cx| {
4366 worktree.as_local_mut().unwrap().share(project_id, cx)
4367 })
4368 .await
4369 .log_err();
4370 }
4371
4372 Ok(worktree)
4373 }
4374 .map_err(|err| Arc::new(err))
4375 })
4376 .shared()
4377 })
4378 .clone();
4379 cx.foreground().spawn(async move {
4380 match task.await {
4381 Ok(worktree) => Ok(worktree),
4382 Err(err) => Err(anyhow!("{}", err)),
4383 }
4384 })
4385 }
4386
4387 pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
4388 self.worktrees.retain(|worktree| {
4389 if let Some(worktree) = worktree.upgrade(cx) {
4390 let id = worktree.read(cx).id();
4391 if id == id_to_remove {
4392 cx.emit(Event::WorktreeRemoved(id));
4393 false
4394 } else {
4395 true
4396 }
4397 } else {
4398 false
4399 }
4400 });
4401 self.metadata_changed(true, cx);
4402 cx.notify();
4403 }
4404
4405 fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
4406 cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
4407 if worktree.read(cx).is_local() {
4408 cx.subscribe(&worktree, |this, worktree, _, cx| {
4409 this.update_local_worktree_buffers(worktree, cx);
4410 })
4411 .detach();
4412 }
4413
4414 let push_strong_handle = {
4415 let worktree = worktree.read(cx);
4416 self.is_shared() || worktree.is_visible() || worktree.is_remote()
4417 };
4418 if push_strong_handle {
4419 self.worktrees
4420 .push(WorktreeHandle::Strong(worktree.clone()));
4421 } else {
4422 self.worktrees
4423 .push(WorktreeHandle::Weak(worktree.downgrade()));
4424 }
4425
4426 self.metadata_changed(true, cx);
4427 cx.observe_release(&worktree, |this, worktree, cx| {
4428 this.remove_worktree(worktree.id(), cx);
4429 cx.notify();
4430 })
4431 .detach();
4432
4433 cx.emit(Event::WorktreeAdded);
4434 cx.notify();
4435 }
4436
4437 fn update_local_worktree_buffers(
4438 &mut self,
4439 worktree_handle: ModelHandle<Worktree>,
4440 cx: &mut ModelContext<Self>,
4441 ) {
4442 let snapshot = worktree_handle.read(cx).snapshot();
4443 let mut buffers_to_delete = Vec::new();
4444 let mut renamed_buffers = Vec::new();
4445 for (buffer_id, buffer) in &self.opened_buffers {
4446 if let Some(buffer) = buffer.upgrade(cx) {
4447 buffer.update(cx, |buffer, cx| {
4448 if let Some(old_file) = File::from_dyn(buffer.file()) {
4449 if old_file.worktree != worktree_handle {
4450 return;
4451 }
4452
4453 let new_file = if let Some(entry) = old_file
4454 .entry_id
4455 .and_then(|entry_id| snapshot.entry_for_id(entry_id))
4456 {
4457 File {
4458 is_local: true,
4459 entry_id: Some(entry.id),
4460 mtime: entry.mtime,
4461 path: entry.path.clone(),
4462 worktree: worktree_handle.clone(),
4463 }
4464 } else if let Some(entry) =
4465 snapshot.entry_for_path(old_file.path().as_ref())
4466 {
4467 File {
4468 is_local: true,
4469 entry_id: Some(entry.id),
4470 mtime: entry.mtime,
4471 path: entry.path.clone(),
4472 worktree: worktree_handle.clone(),
4473 }
4474 } else {
4475 File {
4476 is_local: true,
4477 entry_id: None,
4478 path: old_file.path().clone(),
4479 mtime: old_file.mtime(),
4480 worktree: worktree_handle.clone(),
4481 }
4482 };
4483
4484 let old_path = old_file.abs_path(cx);
4485 if new_file.abs_path(cx) != old_path {
4486 renamed_buffers.push((cx.handle(), old_path));
4487 }
4488
4489 if let Some(project_id) = self.shared_remote_id() {
4490 self.client
4491 .send(proto::UpdateBufferFile {
4492 project_id,
4493 buffer_id: *buffer_id as u64,
4494 file: Some(new_file.to_proto()),
4495 })
4496 .log_err();
4497 }
4498 buffer.file_updated(Arc::new(new_file), cx).detach();
4499 }
4500 });
4501 } else {
4502 buffers_to_delete.push(*buffer_id);
4503 }
4504 }
4505
4506 for buffer_id in buffers_to_delete {
4507 self.opened_buffers.remove(&buffer_id);
4508 }
4509
4510 for (buffer, old_path) in renamed_buffers {
4511 self.unregister_buffer_from_language_server(&buffer, old_path, cx);
4512 self.assign_language_to_buffer(&buffer, cx);
4513 self.register_buffer_with_language_server(&buffer, cx);
4514 }
4515 }
4516
4517 pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
4518 let new_active_entry = entry.and_then(|project_path| {
4519 let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
4520 let entry = worktree.read(cx).entry_for_path(project_path.path)?;
4521 Some(entry.id)
4522 });
4523 if new_active_entry != self.active_entry {
4524 self.active_entry = new_active_entry;
4525 cx.emit(Event::ActiveEntryChanged(new_active_entry));
4526 }
4527 }
4528
4529 pub fn language_servers_running_disk_based_diagnostics<'a>(
4530 &'a self,
4531 ) -> impl 'a + Iterator<Item = usize> {
4532 self.language_server_statuses
4533 .iter()
4534 .filter_map(|(id, status)| {
4535 if status.has_pending_diagnostic_updates {
4536 Some(*id)
4537 } else {
4538 None
4539 }
4540 })
4541 }
4542
4543 pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
4544 let mut summary = DiagnosticSummary::default();
4545 for (_, path_summary) in self.diagnostic_summaries(cx) {
4546 summary.error_count += path_summary.error_count;
4547 summary.warning_count += path_summary.warning_count;
4548 }
4549 summary
4550 }
4551
4552 pub fn diagnostic_summaries<'a>(
4553 &'a self,
4554 cx: &'a AppContext,
4555 ) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
4556 self.visible_worktrees(cx).flat_map(move |worktree| {
4557 let worktree = worktree.read(cx);
4558 let worktree_id = worktree.id();
4559 worktree
4560 .diagnostic_summaries()
4561 .map(move |(path, summary)| (ProjectPath { worktree_id, path }, summary))
4562 })
4563 }
4564
4565 pub fn disk_based_diagnostics_started(
4566 &mut self,
4567 language_server_id: usize,
4568 cx: &mut ModelContext<Self>,
4569 ) {
4570 cx.emit(Event::DiskBasedDiagnosticsStarted { language_server_id });
4571 }
4572
4573 pub fn disk_based_diagnostics_finished(
4574 &mut self,
4575 language_server_id: usize,
4576 cx: &mut ModelContext<Self>,
4577 ) {
4578 cx.emit(Event::DiskBasedDiagnosticsFinished { language_server_id });
4579 }
4580
4581 pub fn active_entry(&self) -> Option<ProjectEntryId> {
4582 self.active_entry
4583 }
4584
4585 pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option<ProjectEntryId> {
4586 self.worktree_for_id(path.worktree_id, cx)?
4587 .read(cx)
4588 .entry_for_path(&path.path)
4589 .map(|entry| entry.id)
4590 }
4591
4592 pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &AppContext) -> Option<ProjectPath> {
4593 let worktree = self.worktree_for_entry(entry_id, cx)?;
4594 let worktree = worktree.read(cx);
4595 let worktree_id = worktree.id();
4596 let path = worktree.entry_for_id(entry_id)?.path.clone();
4597 Some(ProjectPath { worktree_id, path })
4598 }
4599
4600 // RPC message handlers
4601
4602 async fn handle_request_join_project(
4603 this: ModelHandle<Self>,
4604 message: TypedEnvelope<proto::RequestJoinProject>,
4605 _: Arc<Client>,
4606 mut cx: AsyncAppContext,
4607 ) -> Result<()> {
4608 let user_id = message.payload.requester_id;
4609 if this.read_with(&cx, |project, _| {
4610 project.collaborators.values().any(|c| c.user.id == user_id)
4611 }) {
4612 this.update(&mut cx, |this, cx| {
4613 this.respond_to_join_request(user_id, true, cx)
4614 });
4615 } else {
4616 let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
4617 let user = user_store
4618 .update(&mut cx, |store, cx| store.fetch_user(user_id, cx))
4619 .await?;
4620 this.update(&mut cx, |_, cx| cx.emit(Event::ContactRequestedJoin(user)));
4621 }
4622 Ok(())
4623 }
4624
4625 async fn handle_unregister_project(
4626 this: ModelHandle<Self>,
4627 _: TypedEnvelope<proto::UnregisterProject>,
4628 _: Arc<Client>,
4629 mut cx: AsyncAppContext,
4630 ) -> Result<()> {
4631 this.update(&mut cx, |this, cx| this.removed_from_project(cx));
4632 Ok(())
4633 }
4634
4635 async fn handle_project_unshared(
4636 this: ModelHandle<Self>,
4637 _: TypedEnvelope<proto::ProjectUnshared>,
4638 _: Arc<Client>,
4639 mut cx: AsyncAppContext,
4640 ) -> Result<()> {
4641 this.update(&mut cx, |this, cx| this.unshared(cx));
4642 Ok(())
4643 }
4644
4645 async fn handle_add_collaborator(
4646 this: ModelHandle<Self>,
4647 mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
4648 _: Arc<Client>,
4649 mut cx: AsyncAppContext,
4650 ) -> Result<()> {
4651 let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
4652 let collaborator = envelope
4653 .payload
4654 .collaborator
4655 .take()
4656 .ok_or_else(|| anyhow!("empty collaborator"))?;
4657
4658 let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
4659 this.update(&mut cx, |this, cx| {
4660 this.collaborators
4661 .insert(collaborator.peer_id, collaborator);
4662 cx.notify();
4663 });
4664
4665 Ok(())
4666 }
4667
4668 async fn handle_remove_collaborator(
4669 this: ModelHandle<Self>,
4670 envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
4671 _: Arc<Client>,
4672 mut cx: AsyncAppContext,
4673 ) -> Result<()> {
4674 this.update(&mut cx, |this, cx| {
4675 let peer_id = PeerId(envelope.payload.peer_id);
4676 let replica_id = this
4677 .collaborators
4678 .remove(&peer_id)
4679 .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
4680 .replica_id;
4681 for (_, buffer) in &this.opened_buffers {
4682 if let Some(buffer) = buffer.upgrade(cx) {
4683 buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
4684 }
4685 }
4686
4687 cx.emit(Event::CollaboratorLeft(peer_id));
4688 cx.notify();
4689 Ok(())
4690 })
4691 }
4692
4693 async fn handle_join_project_request_cancelled(
4694 this: ModelHandle<Self>,
4695 envelope: TypedEnvelope<proto::JoinProjectRequestCancelled>,
4696 _: Arc<Client>,
4697 mut cx: AsyncAppContext,
4698 ) -> Result<()> {
4699 let user = this
4700 .update(&mut cx, |this, cx| {
4701 this.user_store.update(cx, |user_store, cx| {
4702 user_store.fetch_user(envelope.payload.requester_id, cx)
4703 })
4704 })
4705 .await?;
4706
4707 this.update(&mut cx, |_, cx| {
4708 cx.emit(Event::ContactCancelledJoinRequest(user));
4709 });
4710
4711 Ok(())
4712 }
4713
4714 async fn handle_update_project(
4715 this: ModelHandle<Self>,
4716 envelope: TypedEnvelope<proto::UpdateProject>,
4717 client: Arc<Client>,
4718 mut cx: AsyncAppContext,
4719 ) -> Result<()> {
4720 this.update(&mut cx, |this, cx| {
4721 let replica_id = this.replica_id();
4722 let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
4723
4724 let mut old_worktrees_by_id = this
4725 .worktrees
4726 .drain(..)
4727 .filter_map(|worktree| {
4728 let worktree = worktree.upgrade(cx)?;
4729 Some((worktree.read(cx).id(), worktree))
4730 })
4731 .collect::<HashMap<_, _>>();
4732
4733 for worktree in envelope.payload.worktrees {
4734 if let Some(old_worktree) =
4735 old_worktrees_by_id.remove(&WorktreeId::from_proto(worktree.id))
4736 {
4737 this.worktrees.push(WorktreeHandle::Strong(old_worktree));
4738 } else {
4739 let worktree =
4740 Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx);
4741 this.add_worktree(&worktree, cx);
4742 }
4743 }
4744
4745 this.metadata_changed(true, cx);
4746 for (id, _) in old_worktrees_by_id {
4747 cx.emit(Event::WorktreeRemoved(id));
4748 }
4749
4750 Ok(())
4751 })
4752 }
4753
4754 async fn handle_update_worktree(
4755 this: ModelHandle<Self>,
4756 envelope: TypedEnvelope<proto::UpdateWorktree>,
4757 _: Arc<Client>,
4758 mut cx: AsyncAppContext,
4759 ) -> Result<()> {
4760 this.update(&mut cx, |this, cx| {
4761 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4762 if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4763 worktree.update(cx, |worktree, _| {
4764 let worktree = worktree.as_remote_mut().unwrap();
4765 worktree.update_from_remote(envelope.payload);
4766 });
4767 }
4768 Ok(())
4769 })
4770 }
4771
4772 async fn handle_create_project_entry(
4773 this: ModelHandle<Self>,
4774 envelope: TypedEnvelope<proto::CreateProjectEntry>,
4775 _: Arc<Client>,
4776 mut cx: AsyncAppContext,
4777 ) -> Result<proto::ProjectEntryResponse> {
4778 let worktree = this.update(&mut cx, |this, cx| {
4779 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4780 this.worktree_for_id(worktree_id, cx)
4781 .ok_or_else(|| anyhow!("worktree not found"))
4782 })?;
4783 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4784 let entry = worktree
4785 .update(&mut cx, |worktree, cx| {
4786 let worktree = worktree.as_local_mut().unwrap();
4787 let path = PathBuf::from(OsString::from_vec(envelope.payload.path));
4788 worktree.create_entry(path, envelope.payload.is_directory, cx)
4789 })
4790 .await?;
4791 Ok(proto::ProjectEntryResponse {
4792 entry: Some((&entry).into()),
4793 worktree_scan_id: worktree_scan_id as u64,
4794 })
4795 }
4796
4797 async fn handle_rename_project_entry(
4798 this: ModelHandle<Self>,
4799 envelope: TypedEnvelope<proto::RenameProjectEntry>,
4800 _: Arc<Client>,
4801 mut cx: AsyncAppContext,
4802 ) -> Result<proto::ProjectEntryResponse> {
4803 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4804 let worktree = this.read_with(&cx, |this, cx| {
4805 this.worktree_for_entry(entry_id, cx)
4806 .ok_or_else(|| anyhow!("worktree not found"))
4807 })?;
4808 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4809 let entry = worktree
4810 .update(&mut cx, |worktree, cx| {
4811 let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path));
4812 worktree
4813 .as_local_mut()
4814 .unwrap()
4815 .rename_entry(entry_id, new_path, cx)
4816 .ok_or_else(|| anyhow!("invalid entry"))
4817 })?
4818 .await?;
4819 Ok(proto::ProjectEntryResponse {
4820 entry: Some((&entry).into()),
4821 worktree_scan_id: worktree_scan_id as u64,
4822 })
4823 }
4824
4825 async fn handle_copy_project_entry(
4826 this: ModelHandle<Self>,
4827 envelope: TypedEnvelope<proto::CopyProjectEntry>,
4828 _: Arc<Client>,
4829 mut cx: AsyncAppContext,
4830 ) -> Result<proto::ProjectEntryResponse> {
4831 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4832 let worktree = this.read_with(&cx, |this, cx| {
4833 this.worktree_for_entry(entry_id, cx)
4834 .ok_or_else(|| anyhow!("worktree not found"))
4835 })?;
4836 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4837 let entry = worktree
4838 .update(&mut cx, |worktree, cx| {
4839 let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path));
4840 worktree
4841 .as_local_mut()
4842 .unwrap()
4843 .copy_entry(entry_id, new_path, cx)
4844 .ok_or_else(|| anyhow!("invalid entry"))
4845 })?
4846 .await?;
4847 Ok(proto::ProjectEntryResponse {
4848 entry: Some((&entry).into()),
4849 worktree_scan_id: worktree_scan_id as u64,
4850 })
4851 }
4852
4853 async fn handle_delete_project_entry(
4854 this: ModelHandle<Self>,
4855 envelope: TypedEnvelope<proto::DeleteProjectEntry>,
4856 _: Arc<Client>,
4857 mut cx: AsyncAppContext,
4858 ) -> Result<proto::ProjectEntryResponse> {
4859 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4860 let worktree = this.read_with(&cx, |this, cx| {
4861 this.worktree_for_entry(entry_id, cx)
4862 .ok_or_else(|| anyhow!("worktree not found"))
4863 })?;
4864 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4865 worktree
4866 .update(&mut cx, |worktree, cx| {
4867 worktree
4868 .as_local_mut()
4869 .unwrap()
4870 .delete_entry(entry_id, cx)
4871 .ok_or_else(|| anyhow!("invalid entry"))
4872 })?
4873 .await?;
4874 Ok(proto::ProjectEntryResponse {
4875 entry: None,
4876 worktree_scan_id: worktree_scan_id as u64,
4877 })
4878 }
4879
4880 async fn handle_update_diagnostic_summary(
4881 this: ModelHandle<Self>,
4882 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
4883 _: Arc<Client>,
4884 mut cx: AsyncAppContext,
4885 ) -> Result<()> {
4886 this.update(&mut cx, |this, cx| {
4887 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4888 if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4889 if let Some(summary) = envelope.payload.summary {
4890 let project_path = ProjectPath {
4891 worktree_id,
4892 path: Path::new(&summary.path).into(),
4893 };
4894 worktree.update(cx, |worktree, _| {
4895 worktree
4896 .as_remote_mut()
4897 .unwrap()
4898 .update_diagnostic_summary(project_path.path.clone(), &summary);
4899 });
4900 cx.emit(Event::DiagnosticsUpdated {
4901 language_server_id: summary.language_server_id as usize,
4902 path: project_path,
4903 });
4904 }
4905 }
4906 Ok(())
4907 })
4908 }
4909
4910 async fn handle_start_language_server(
4911 this: ModelHandle<Self>,
4912 envelope: TypedEnvelope<proto::StartLanguageServer>,
4913 _: Arc<Client>,
4914 mut cx: AsyncAppContext,
4915 ) -> Result<()> {
4916 let server = envelope
4917 .payload
4918 .server
4919 .ok_or_else(|| anyhow!("invalid server"))?;
4920 this.update(&mut cx, |this, cx| {
4921 this.language_server_statuses.insert(
4922 server.id as usize,
4923 LanguageServerStatus {
4924 name: server.name,
4925 pending_work: Default::default(),
4926 has_pending_diagnostic_updates: false,
4927 progress_tokens: Default::default(),
4928 },
4929 );
4930 cx.notify();
4931 });
4932 Ok(())
4933 }
4934
4935 async fn handle_update_language_server(
4936 this: ModelHandle<Self>,
4937 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
4938 _: Arc<Client>,
4939 mut cx: AsyncAppContext,
4940 ) -> Result<()> {
4941 let language_server_id = envelope.payload.language_server_id as usize;
4942 match envelope
4943 .payload
4944 .variant
4945 .ok_or_else(|| anyhow!("invalid variant"))?
4946 {
4947 proto::update_language_server::Variant::WorkStart(payload) => {
4948 this.update(&mut cx, |this, cx| {
4949 this.on_lsp_work_start(
4950 language_server_id,
4951 payload.token,
4952 LanguageServerProgress {
4953 message: payload.message,
4954 percentage: payload.percentage.map(|p| p as usize),
4955 last_update_at: Instant::now(),
4956 },
4957 cx,
4958 );
4959 })
4960 }
4961 proto::update_language_server::Variant::WorkProgress(payload) => {
4962 this.update(&mut cx, |this, cx| {
4963 this.on_lsp_work_progress(
4964 language_server_id,
4965 payload.token,
4966 LanguageServerProgress {
4967 message: payload.message,
4968 percentage: payload.percentage.map(|p| p as usize),
4969 last_update_at: Instant::now(),
4970 },
4971 cx,
4972 );
4973 })
4974 }
4975 proto::update_language_server::Variant::WorkEnd(payload) => {
4976 this.update(&mut cx, |this, cx| {
4977 this.on_lsp_work_end(language_server_id, payload.token, cx);
4978 })
4979 }
4980 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
4981 this.update(&mut cx, |this, cx| {
4982 this.disk_based_diagnostics_started(language_server_id, cx);
4983 })
4984 }
4985 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
4986 this.update(&mut cx, |this, cx| {
4987 this.disk_based_diagnostics_finished(language_server_id, cx)
4988 });
4989 }
4990 }
4991
4992 Ok(())
4993 }
4994
4995 async fn handle_update_buffer(
4996 this: ModelHandle<Self>,
4997 envelope: TypedEnvelope<proto::UpdateBuffer>,
4998 _: Arc<Client>,
4999 mut cx: AsyncAppContext,
5000 ) -> Result<()> {
5001 this.update(&mut cx, |this, cx| {
5002 let payload = envelope.payload.clone();
5003 let buffer_id = payload.buffer_id;
5004 let ops = payload
5005 .operations
5006 .into_iter()
5007 .map(|op| language::proto::deserialize_operation(op))
5008 .collect::<Result<Vec<_>, _>>()?;
5009 let is_remote = this.is_remote();
5010 match this.opened_buffers.entry(buffer_id) {
5011 hash_map::Entry::Occupied(mut e) => match e.get_mut() {
5012 OpenBuffer::Strong(buffer) => {
5013 buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
5014 }
5015 OpenBuffer::Loading(operations) => operations.extend_from_slice(&ops),
5016 OpenBuffer::Weak(_) => {}
5017 },
5018 hash_map::Entry::Vacant(e) => {
5019 assert!(
5020 is_remote,
5021 "received buffer update from {:?}",
5022 envelope.original_sender_id
5023 );
5024 e.insert(OpenBuffer::Loading(ops));
5025 }
5026 }
5027 Ok(())
5028 })
5029 }
5030
5031 async fn handle_update_buffer_file(
5032 this: ModelHandle<Self>,
5033 envelope: TypedEnvelope<proto::UpdateBufferFile>,
5034 _: Arc<Client>,
5035 mut cx: AsyncAppContext,
5036 ) -> Result<()> {
5037 this.update(&mut cx, |this, cx| {
5038 let payload = envelope.payload.clone();
5039 let buffer_id = payload.buffer_id;
5040 let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
5041 let worktree = this
5042 .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
5043 .ok_or_else(|| anyhow!("no such worktree"))?;
5044 let file = File::from_proto(file, worktree.clone(), cx)?;
5045 let buffer = this
5046 .opened_buffers
5047 .get_mut(&buffer_id)
5048 .and_then(|b| b.upgrade(cx))
5049 .ok_or_else(|| anyhow!("no such buffer"))?;
5050 buffer.update(cx, |buffer, cx| {
5051 buffer.file_updated(Arc::new(file), cx).detach();
5052 });
5053 Ok(())
5054 })
5055 }
5056
5057 async fn handle_save_buffer(
5058 this: ModelHandle<Self>,
5059 envelope: TypedEnvelope<proto::SaveBuffer>,
5060 _: Arc<Client>,
5061 mut cx: AsyncAppContext,
5062 ) -> Result<proto::BufferSaved> {
5063 let buffer_id = envelope.payload.buffer_id;
5064 let requested_version = deserialize_version(envelope.payload.version);
5065
5066 let (project_id, buffer) = this.update(&mut cx, |this, cx| {
5067 let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
5068 let buffer = this
5069 .opened_buffers
5070 .get(&buffer_id)
5071 .and_then(|buffer| buffer.upgrade(cx))
5072 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
5073 Ok::<_, anyhow::Error>((project_id, buffer))
5074 })?;
5075 buffer
5076 .update(&mut cx, |buffer, _| {
5077 buffer.wait_for_version(requested_version)
5078 })
5079 .await;
5080
5081 let (saved_version, fingerprint, mtime) =
5082 buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await?;
5083 Ok(proto::BufferSaved {
5084 project_id,
5085 buffer_id,
5086 version: serialize_version(&saved_version),
5087 mtime: Some(mtime.into()),
5088 fingerprint,
5089 })
5090 }
5091
5092 async fn handle_reload_buffers(
5093 this: ModelHandle<Self>,
5094 envelope: TypedEnvelope<proto::ReloadBuffers>,
5095 _: Arc<Client>,
5096 mut cx: AsyncAppContext,
5097 ) -> Result<proto::ReloadBuffersResponse> {
5098 let sender_id = envelope.original_sender_id()?;
5099 let reload = this.update(&mut cx, |this, cx| {
5100 let mut buffers = HashSet::default();
5101 for buffer_id in &envelope.payload.buffer_ids {
5102 buffers.insert(
5103 this.opened_buffers
5104 .get(buffer_id)
5105 .and_then(|buffer| buffer.upgrade(cx))
5106 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
5107 );
5108 }
5109 Ok::<_, anyhow::Error>(this.reload_buffers(buffers, false, cx))
5110 })?;
5111
5112 let project_transaction = reload.await?;
5113 let project_transaction = this.update(&mut cx, |this, cx| {
5114 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5115 });
5116 Ok(proto::ReloadBuffersResponse {
5117 transaction: Some(project_transaction),
5118 })
5119 }
5120
5121 async fn handle_format_buffers(
5122 this: ModelHandle<Self>,
5123 envelope: TypedEnvelope<proto::FormatBuffers>,
5124 _: Arc<Client>,
5125 mut cx: AsyncAppContext,
5126 ) -> Result<proto::FormatBuffersResponse> {
5127 let sender_id = envelope.original_sender_id()?;
5128 let format = this.update(&mut cx, |this, cx| {
5129 let mut buffers = HashSet::default();
5130 for buffer_id in &envelope.payload.buffer_ids {
5131 buffers.insert(
5132 this.opened_buffers
5133 .get(buffer_id)
5134 .and_then(|buffer| buffer.upgrade(cx))
5135 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
5136 );
5137 }
5138 Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
5139 })?;
5140
5141 let project_transaction = format.await?;
5142 let project_transaction = this.update(&mut cx, |this, cx| {
5143 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5144 });
5145 Ok(proto::FormatBuffersResponse {
5146 transaction: Some(project_transaction),
5147 })
5148 }
5149
5150 async fn handle_get_completions(
5151 this: ModelHandle<Self>,
5152 envelope: TypedEnvelope<proto::GetCompletions>,
5153 _: Arc<Client>,
5154 mut cx: AsyncAppContext,
5155 ) -> Result<proto::GetCompletionsResponse> {
5156 let position = envelope
5157 .payload
5158 .position
5159 .and_then(language::proto::deserialize_anchor)
5160 .ok_or_else(|| anyhow!("invalid position"))?;
5161 let version = deserialize_version(envelope.payload.version);
5162 let buffer = this.read_with(&cx, |this, cx| {
5163 this.opened_buffers
5164 .get(&envelope.payload.buffer_id)
5165 .and_then(|buffer| buffer.upgrade(cx))
5166 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
5167 })?;
5168 buffer
5169 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
5170 .await;
5171 let version = buffer.read_with(&cx, |buffer, _| buffer.version());
5172 let completions = this
5173 .update(&mut cx, |this, cx| this.completions(&buffer, position, cx))
5174 .await?;
5175
5176 Ok(proto::GetCompletionsResponse {
5177 completions: completions
5178 .iter()
5179 .map(language::proto::serialize_completion)
5180 .collect(),
5181 version: serialize_version(&version),
5182 })
5183 }
5184
5185 async fn handle_apply_additional_edits_for_completion(
5186 this: ModelHandle<Self>,
5187 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
5188 _: Arc<Client>,
5189 mut cx: AsyncAppContext,
5190 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
5191 let apply_additional_edits = this.update(&mut cx, |this, cx| {
5192 let buffer = this
5193 .opened_buffers
5194 .get(&envelope.payload.buffer_id)
5195 .and_then(|buffer| buffer.upgrade(cx))
5196 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
5197 let language = buffer.read(cx).language();
5198 let completion = language::proto::deserialize_completion(
5199 envelope
5200 .payload
5201 .completion
5202 .ok_or_else(|| anyhow!("invalid completion"))?,
5203 language,
5204 )?;
5205 Ok::<_, anyhow::Error>(
5206 this.apply_additional_edits_for_completion(buffer, completion, false, cx),
5207 )
5208 })?;
5209
5210 Ok(proto::ApplyCompletionAdditionalEditsResponse {
5211 transaction: apply_additional_edits
5212 .await?
5213 .as_ref()
5214 .map(language::proto::serialize_transaction),
5215 })
5216 }
5217
5218 async fn handle_get_code_actions(
5219 this: ModelHandle<Self>,
5220 envelope: TypedEnvelope<proto::GetCodeActions>,
5221 _: Arc<Client>,
5222 mut cx: AsyncAppContext,
5223 ) -> Result<proto::GetCodeActionsResponse> {
5224 let start = envelope
5225 .payload
5226 .start
5227 .and_then(language::proto::deserialize_anchor)
5228 .ok_or_else(|| anyhow!("invalid start"))?;
5229 let end = envelope
5230 .payload
5231 .end
5232 .and_then(language::proto::deserialize_anchor)
5233 .ok_or_else(|| anyhow!("invalid end"))?;
5234 let buffer = this.update(&mut cx, |this, cx| {
5235 this.opened_buffers
5236 .get(&envelope.payload.buffer_id)
5237 .and_then(|buffer| buffer.upgrade(cx))
5238 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
5239 })?;
5240 buffer
5241 .update(&mut cx, |buffer, _| {
5242 buffer.wait_for_version(deserialize_version(envelope.payload.version))
5243 })
5244 .await;
5245
5246 let version = buffer.read_with(&cx, |buffer, _| buffer.version());
5247 let code_actions = this.update(&mut cx, |this, cx| {
5248 Ok::<_, anyhow::Error>(this.code_actions(&buffer, start..end, cx))
5249 })?;
5250
5251 Ok(proto::GetCodeActionsResponse {
5252 actions: code_actions
5253 .await?
5254 .iter()
5255 .map(language::proto::serialize_code_action)
5256 .collect(),
5257 version: serialize_version(&version),
5258 })
5259 }
5260
5261 async fn handle_apply_code_action(
5262 this: ModelHandle<Self>,
5263 envelope: TypedEnvelope<proto::ApplyCodeAction>,
5264 _: Arc<Client>,
5265 mut cx: AsyncAppContext,
5266 ) -> Result<proto::ApplyCodeActionResponse> {
5267 let sender_id = envelope.original_sender_id()?;
5268 let action = language::proto::deserialize_code_action(
5269 envelope
5270 .payload
5271 .action
5272 .ok_or_else(|| anyhow!("invalid action"))?,
5273 )?;
5274 let apply_code_action = this.update(&mut cx, |this, cx| {
5275 let buffer = this
5276 .opened_buffers
5277 .get(&envelope.payload.buffer_id)
5278 .and_then(|buffer| buffer.upgrade(cx))
5279 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
5280 Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
5281 })?;
5282
5283 let project_transaction = apply_code_action.await?;
5284 let project_transaction = this.update(&mut cx, |this, cx| {
5285 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5286 });
5287 Ok(proto::ApplyCodeActionResponse {
5288 transaction: Some(project_transaction),
5289 })
5290 }
5291
5292 async fn handle_lsp_command<T: LspCommand>(
5293 this: ModelHandle<Self>,
5294 envelope: TypedEnvelope<T::ProtoRequest>,
5295 _: Arc<Client>,
5296 mut cx: AsyncAppContext,
5297 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
5298 where
5299 <T::LspRequest as lsp::request::Request>::Result: Send,
5300 {
5301 let sender_id = envelope.original_sender_id()?;
5302 let buffer_id = T::buffer_id_from_proto(&envelope.payload);
5303 let buffer_handle = this.read_with(&cx, |this, _| {
5304 this.opened_buffers
5305 .get(&buffer_id)
5306 .and_then(|buffer| buffer.upgrade(&cx))
5307 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))
5308 })?;
5309 let request = T::from_proto(
5310 envelope.payload,
5311 this.clone(),
5312 buffer_handle.clone(),
5313 cx.clone(),
5314 )
5315 .await?;
5316 let buffer_version = buffer_handle.read_with(&cx, |buffer, _| buffer.version());
5317 let response = this
5318 .update(&mut cx, |this, cx| {
5319 this.request_lsp(buffer_handle, request, cx)
5320 })
5321 .await?;
5322 this.update(&mut cx, |this, cx| {
5323 Ok(T::response_to_proto(
5324 response,
5325 this,
5326 sender_id,
5327 &buffer_version,
5328 cx,
5329 ))
5330 })
5331 }
5332
5333 async fn handle_get_project_symbols(
5334 this: ModelHandle<Self>,
5335 envelope: TypedEnvelope<proto::GetProjectSymbols>,
5336 _: Arc<Client>,
5337 mut cx: AsyncAppContext,
5338 ) -> Result<proto::GetProjectSymbolsResponse> {
5339 let symbols = this
5340 .update(&mut cx, |this, cx| {
5341 this.symbols(&envelope.payload.query, cx)
5342 })
5343 .await?;
5344
5345 Ok(proto::GetProjectSymbolsResponse {
5346 symbols: symbols.iter().map(serialize_symbol).collect(),
5347 })
5348 }
5349
5350 async fn handle_search_project(
5351 this: ModelHandle<Self>,
5352 envelope: TypedEnvelope<proto::SearchProject>,
5353 _: Arc<Client>,
5354 mut cx: AsyncAppContext,
5355 ) -> Result<proto::SearchProjectResponse> {
5356 let peer_id = envelope.original_sender_id()?;
5357 let query = SearchQuery::from_proto(envelope.payload)?;
5358 let result = this
5359 .update(&mut cx, |this, cx| this.search(query, cx))
5360 .await?;
5361
5362 this.update(&mut cx, |this, cx| {
5363 let mut locations = Vec::new();
5364 for (buffer, ranges) in result {
5365 for range in ranges {
5366 let start = serialize_anchor(&range.start);
5367 let end = serialize_anchor(&range.end);
5368 let buffer = this.serialize_buffer_for_peer(&buffer, peer_id, cx);
5369 locations.push(proto::Location {
5370 buffer: Some(buffer),
5371 start: Some(start),
5372 end: Some(end),
5373 });
5374 }
5375 }
5376 Ok(proto::SearchProjectResponse { locations })
5377 })
5378 }
5379
5380 async fn handle_open_buffer_for_symbol(
5381 this: ModelHandle<Self>,
5382 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
5383 _: Arc<Client>,
5384 mut cx: AsyncAppContext,
5385 ) -> Result<proto::OpenBufferForSymbolResponse> {
5386 let peer_id = envelope.original_sender_id()?;
5387 let symbol = envelope
5388 .payload
5389 .symbol
5390 .ok_or_else(|| anyhow!("invalid symbol"))?;
5391 let symbol = this.read_with(&cx, |this, _| {
5392 let symbol = this.deserialize_symbol(symbol)?;
5393 let signature = this.symbol_signature(symbol.worktree_id, &symbol.path);
5394 if signature == symbol.signature {
5395 Ok(symbol)
5396 } else {
5397 Err(anyhow!("invalid symbol signature"))
5398 }
5399 })?;
5400 let buffer = this
5401 .update(&mut cx, |this, cx| this.open_buffer_for_symbol(&symbol, cx))
5402 .await?;
5403
5404 Ok(proto::OpenBufferForSymbolResponse {
5405 buffer: Some(this.update(&mut cx, |this, cx| {
5406 this.serialize_buffer_for_peer(&buffer, peer_id, cx)
5407 })),
5408 })
5409 }
5410
5411 fn symbol_signature(&self, worktree_id: WorktreeId, path: &Path) -> [u8; 32] {
5412 let mut hasher = Sha256::new();
5413 hasher.update(worktree_id.to_proto().to_be_bytes());
5414 hasher.update(path.to_string_lossy().as_bytes());
5415 hasher.update(self.nonce.to_be_bytes());
5416 hasher.finalize().as_slice().try_into().unwrap()
5417 }
5418
5419 async fn handle_open_buffer_by_id(
5420 this: ModelHandle<Self>,
5421 envelope: TypedEnvelope<proto::OpenBufferById>,
5422 _: Arc<Client>,
5423 mut cx: AsyncAppContext,
5424 ) -> Result<proto::OpenBufferResponse> {
5425 let peer_id = envelope.original_sender_id()?;
5426 let buffer = this
5427 .update(&mut cx, |this, cx| {
5428 this.open_buffer_by_id(envelope.payload.id, cx)
5429 })
5430 .await?;
5431 this.update(&mut cx, |this, cx| {
5432 Ok(proto::OpenBufferResponse {
5433 buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
5434 })
5435 })
5436 }
5437
5438 async fn handle_open_buffer_by_path(
5439 this: ModelHandle<Self>,
5440 envelope: TypedEnvelope<proto::OpenBufferByPath>,
5441 _: Arc<Client>,
5442 mut cx: AsyncAppContext,
5443 ) -> Result<proto::OpenBufferResponse> {
5444 let peer_id = envelope.original_sender_id()?;
5445 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
5446 let open_buffer = this.update(&mut cx, |this, cx| {
5447 this.open_buffer(
5448 ProjectPath {
5449 worktree_id,
5450 path: PathBuf::from(envelope.payload.path).into(),
5451 },
5452 cx,
5453 )
5454 });
5455
5456 let buffer = open_buffer.await?;
5457 this.update(&mut cx, |this, cx| {
5458 Ok(proto::OpenBufferResponse {
5459 buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
5460 })
5461 })
5462 }
5463
5464 fn serialize_project_transaction_for_peer(
5465 &mut self,
5466 project_transaction: ProjectTransaction,
5467 peer_id: PeerId,
5468 cx: &AppContext,
5469 ) -> proto::ProjectTransaction {
5470 let mut serialized_transaction = proto::ProjectTransaction {
5471 buffers: Default::default(),
5472 transactions: Default::default(),
5473 };
5474 for (buffer, transaction) in project_transaction.0 {
5475 serialized_transaction
5476 .buffers
5477 .push(self.serialize_buffer_for_peer(&buffer, peer_id, cx));
5478 serialized_transaction
5479 .transactions
5480 .push(language::proto::serialize_transaction(&transaction));
5481 }
5482 serialized_transaction
5483 }
5484
5485 fn deserialize_project_transaction(
5486 &mut self,
5487 message: proto::ProjectTransaction,
5488 push_to_history: bool,
5489 cx: &mut ModelContext<Self>,
5490 ) -> Task<Result<ProjectTransaction>> {
5491 cx.spawn(|this, mut cx| async move {
5492 let mut project_transaction = ProjectTransaction::default();
5493 for (buffer, transaction) in message.buffers.into_iter().zip(message.transactions) {
5494 let buffer = this
5495 .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
5496 .await?;
5497 let transaction = language::proto::deserialize_transaction(transaction)?;
5498 project_transaction.0.insert(buffer, transaction);
5499 }
5500
5501 for (buffer, transaction) in &project_transaction.0 {
5502 buffer
5503 .update(&mut cx, |buffer, _| {
5504 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
5505 })
5506 .await;
5507
5508 if push_to_history {
5509 buffer.update(&mut cx, |buffer, _| {
5510 buffer.push_transaction(transaction.clone(), Instant::now());
5511 });
5512 }
5513 }
5514
5515 Ok(project_transaction)
5516 })
5517 }
5518
5519 fn serialize_buffer_for_peer(
5520 &mut self,
5521 buffer: &ModelHandle<Buffer>,
5522 peer_id: PeerId,
5523 cx: &AppContext,
5524 ) -> proto::Buffer {
5525 let buffer_id = buffer.read(cx).remote_id();
5526 let shared_buffers = self.shared_buffers.entry(peer_id).or_default();
5527 if shared_buffers.insert(buffer_id) {
5528 proto::Buffer {
5529 variant: Some(proto::buffer::Variant::State(buffer.read(cx).to_proto())),
5530 }
5531 } else {
5532 proto::Buffer {
5533 variant: Some(proto::buffer::Variant::Id(buffer_id)),
5534 }
5535 }
5536 }
5537
5538 fn deserialize_buffer(
5539 &mut self,
5540 buffer: proto::Buffer,
5541 cx: &mut ModelContext<Self>,
5542 ) -> Task<Result<ModelHandle<Buffer>>> {
5543 let replica_id = self.replica_id();
5544
5545 let opened_buffer_tx = self.opened_buffer.0.clone();
5546 let mut opened_buffer_rx = self.opened_buffer.1.clone();
5547 cx.spawn(|this, mut cx| async move {
5548 match buffer.variant.ok_or_else(|| anyhow!("missing buffer"))? {
5549 proto::buffer::Variant::Id(id) => {
5550 let buffer = loop {
5551 let buffer = this.read_with(&cx, |this, cx| {
5552 this.opened_buffers
5553 .get(&id)
5554 .and_then(|buffer| buffer.upgrade(cx))
5555 });
5556 if let Some(buffer) = buffer {
5557 break buffer;
5558 }
5559 opened_buffer_rx
5560 .next()
5561 .await
5562 .ok_or_else(|| anyhow!("project dropped while waiting for buffer"))?;
5563 };
5564 Ok(buffer)
5565 }
5566 proto::buffer::Variant::State(mut buffer) => {
5567 let mut buffer_worktree = None;
5568 let mut buffer_file = None;
5569 if let Some(file) = buffer.file.take() {
5570 this.read_with(&cx, |this, cx| {
5571 let worktree_id = WorktreeId::from_proto(file.worktree_id);
5572 let worktree =
5573 this.worktree_for_id(worktree_id, cx).ok_or_else(|| {
5574 anyhow!("no worktree found for id {}", file.worktree_id)
5575 })?;
5576 buffer_file =
5577 Some(Arc::new(File::from_proto(file, worktree.clone(), cx)?)
5578 as Arc<dyn language::File>);
5579 buffer_worktree = Some(worktree);
5580 Ok::<_, anyhow::Error>(())
5581 })?;
5582 }
5583
5584 let buffer = cx.add_model(|cx| {
5585 Buffer::from_proto(replica_id, buffer, buffer_file, cx).unwrap()
5586 });
5587
5588 this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
5589
5590 *opened_buffer_tx.borrow_mut().borrow_mut() = ();
5591 Ok(buffer)
5592 }
5593 }
5594 })
5595 }
5596
5597 fn deserialize_symbol(&self, serialized_symbol: proto::Symbol) -> Result<Symbol> {
5598 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
5599 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
5600 let start = serialized_symbol
5601 .start
5602 .ok_or_else(|| anyhow!("invalid start"))?;
5603 let end = serialized_symbol
5604 .end
5605 .ok_or_else(|| anyhow!("invalid end"))?;
5606 let kind = unsafe { mem::transmute(serialized_symbol.kind) };
5607 let path = PathBuf::from(serialized_symbol.path);
5608 let language = self.languages.select_language(&path);
5609 Ok(Symbol {
5610 source_worktree_id,
5611 worktree_id,
5612 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
5613 label: language
5614 .and_then(|language| language.label_for_symbol(&serialized_symbol.name, kind))
5615 .unwrap_or_else(|| CodeLabel::plain(serialized_symbol.name.clone(), None)),
5616 name: serialized_symbol.name,
5617 path,
5618 range: PointUtf16::new(start.row, start.column)..PointUtf16::new(end.row, end.column),
5619 kind,
5620 signature: serialized_symbol
5621 .signature
5622 .try_into()
5623 .map_err(|_| anyhow!("invalid signature"))?,
5624 })
5625 }
5626
5627 async fn handle_buffer_saved(
5628 this: ModelHandle<Self>,
5629 envelope: TypedEnvelope<proto::BufferSaved>,
5630 _: Arc<Client>,
5631 mut cx: AsyncAppContext,
5632 ) -> Result<()> {
5633 let version = deserialize_version(envelope.payload.version);
5634 let mtime = envelope
5635 .payload
5636 .mtime
5637 .ok_or_else(|| anyhow!("missing mtime"))?
5638 .into();
5639
5640 this.update(&mut cx, |this, cx| {
5641 let buffer = this
5642 .opened_buffers
5643 .get(&envelope.payload.buffer_id)
5644 .and_then(|buffer| buffer.upgrade(cx));
5645 if let Some(buffer) = buffer {
5646 buffer.update(cx, |buffer, cx| {
5647 buffer.did_save(version, envelope.payload.fingerprint, mtime, None, cx);
5648 });
5649 }
5650 Ok(())
5651 })
5652 }
5653
5654 async fn handle_buffer_reloaded(
5655 this: ModelHandle<Self>,
5656 envelope: TypedEnvelope<proto::BufferReloaded>,
5657 _: Arc<Client>,
5658 mut cx: AsyncAppContext,
5659 ) -> Result<()> {
5660 let payload = envelope.payload;
5661 let version = deserialize_version(payload.version);
5662 let line_ending = deserialize_line_ending(
5663 proto::LineEnding::from_i32(payload.line_ending)
5664 .ok_or_else(|| anyhow!("missing line ending"))?,
5665 );
5666 let mtime = payload
5667 .mtime
5668 .ok_or_else(|| anyhow!("missing mtime"))?
5669 .into();
5670 this.update(&mut cx, |this, cx| {
5671 let buffer = this
5672 .opened_buffers
5673 .get(&payload.buffer_id)
5674 .and_then(|buffer| buffer.upgrade(cx));
5675 if let Some(buffer) = buffer {
5676 buffer.update(cx, |buffer, cx| {
5677 buffer.did_reload(version, payload.fingerprint, line_ending, mtime, cx);
5678 });
5679 }
5680 Ok(())
5681 })
5682 }
5683
5684 fn edits_from_lsp(
5685 &mut self,
5686 buffer: &ModelHandle<Buffer>,
5687 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
5688 version: Option<i32>,
5689 cx: &mut ModelContext<Self>,
5690 ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
5691 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx);
5692 cx.background().spawn(async move {
5693 let snapshot = snapshot?;
5694 let mut lsp_edits = lsp_edits
5695 .into_iter()
5696 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
5697 .collect::<Vec<_>>();
5698 lsp_edits.sort_by_key(|(range, _)| range.start);
5699
5700 let mut lsp_edits = lsp_edits.into_iter().peekable();
5701 let mut edits = Vec::new();
5702 while let Some((mut range, mut new_text)) = lsp_edits.next() {
5703 // Combine any LSP edits that are adjacent.
5704 //
5705 // Also, combine LSP edits that are separated from each other by only
5706 // a newline. This is important because for some code actions,
5707 // Rust-analyzer rewrites the entire buffer via a series of edits that
5708 // are separated by unchanged newline characters.
5709 //
5710 // In order for the diffing logic below to work properly, any edits that
5711 // cancel each other out must be combined into one.
5712 while let Some((next_range, next_text)) = lsp_edits.peek() {
5713 if next_range.start > range.end {
5714 if next_range.start.row > range.end.row + 1
5715 || next_range.start.column > 0
5716 || snapshot.clip_point_utf16(
5717 PointUtf16::new(range.end.row, u32::MAX),
5718 Bias::Left,
5719 ) > range.end
5720 {
5721 break;
5722 }
5723 new_text.push('\n');
5724 }
5725 range.end = next_range.end;
5726 new_text.push_str(&next_text);
5727 lsp_edits.next();
5728 }
5729
5730 if snapshot.clip_point_utf16(range.start, Bias::Left) != range.start
5731 || snapshot.clip_point_utf16(range.end, Bias::Left) != range.end
5732 {
5733 return Err(anyhow!("invalid edits received from language server"));
5734 }
5735
5736 // For multiline edits, perform a diff of the old and new text so that
5737 // we can identify the changes more precisely, preserving the locations
5738 // of any anchors positioned in the unchanged regions.
5739 if range.end.row > range.start.row {
5740 let mut offset = range.start.to_offset(&snapshot);
5741 let old_text = snapshot.text_for_range(range).collect::<String>();
5742
5743 let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
5744 let mut moved_since_edit = true;
5745 for change in diff.iter_all_changes() {
5746 let tag = change.tag();
5747 let value = change.value();
5748 match tag {
5749 ChangeTag::Equal => {
5750 offset += value.len();
5751 moved_since_edit = true;
5752 }
5753 ChangeTag::Delete => {
5754 let start = snapshot.anchor_after(offset);
5755 let end = snapshot.anchor_before(offset + value.len());
5756 if moved_since_edit {
5757 edits.push((start..end, String::new()));
5758 } else {
5759 edits.last_mut().unwrap().0.end = end;
5760 }
5761 offset += value.len();
5762 moved_since_edit = false;
5763 }
5764 ChangeTag::Insert => {
5765 if moved_since_edit {
5766 let anchor = snapshot.anchor_after(offset);
5767 edits.push((anchor.clone()..anchor, value.to_string()));
5768 } else {
5769 edits.last_mut().unwrap().1.push_str(value);
5770 }
5771 moved_since_edit = false;
5772 }
5773 }
5774 }
5775 } else if range.end == range.start {
5776 let anchor = snapshot.anchor_after(range.start);
5777 edits.push((anchor.clone()..anchor, new_text));
5778 } else {
5779 let edit_start = snapshot.anchor_after(range.start);
5780 let edit_end = snapshot.anchor_before(range.end);
5781 edits.push((edit_start..edit_end, new_text));
5782 }
5783 }
5784
5785 Ok(edits)
5786 })
5787 }
5788
5789 fn buffer_snapshot_for_lsp_version(
5790 &mut self,
5791 buffer: &ModelHandle<Buffer>,
5792 version: Option<i32>,
5793 cx: &AppContext,
5794 ) -> Result<TextBufferSnapshot> {
5795 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
5796
5797 if let Some(version) = version {
5798 let buffer_id = buffer.read(cx).remote_id();
5799 let snapshots = self
5800 .buffer_snapshots
5801 .get_mut(&buffer_id)
5802 .ok_or_else(|| anyhow!("no snapshot found for buffer {}", buffer_id))?;
5803 let mut found_snapshot = None;
5804 snapshots.retain(|(snapshot_version, snapshot)| {
5805 if snapshot_version + OLD_VERSIONS_TO_RETAIN < version {
5806 false
5807 } else {
5808 if *snapshot_version == version {
5809 found_snapshot = Some(snapshot.clone());
5810 }
5811 true
5812 }
5813 });
5814
5815 found_snapshot.ok_or_else(|| {
5816 anyhow!(
5817 "snapshot not found for buffer {} at version {}",
5818 buffer_id,
5819 version
5820 )
5821 })
5822 } else {
5823 Ok((buffer.read(cx)).text_snapshot())
5824 }
5825 }
5826
5827 fn language_server_for_buffer(
5828 &self,
5829 buffer: &Buffer,
5830 cx: &AppContext,
5831 ) -> Option<(&Arc<dyn LspAdapter>, &Arc<LanguageServer>)> {
5832 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
5833 let worktree_id = file.worktree_id(cx);
5834 let key = (worktree_id, language.lsp_adapter()?.name());
5835
5836 if let Some(server_id) = self.language_server_ids.get(&key) {
5837 if let Some(LanguageServerState::Running { adapter, server }) =
5838 self.language_servers.get(&server_id)
5839 {
5840 return Some((adapter, server));
5841 }
5842 }
5843 }
5844
5845 None
5846 }
5847}
5848
5849impl ProjectStore {
5850 pub fn new(db: Arc<Db>) -> Self {
5851 Self {
5852 db,
5853 projects: Default::default(),
5854 }
5855 }
5856
5857 pub fn projects<'a>(
5858 &'a self,
5859 cx: &'a AppContext,
5860 ) -> impl 'a + Iterator<Item = ModelHandle<Project>> {
5861 self.projects
5862 .iter()
5863 .filter_map(|project| project.upgrade(cx))
5864 }
5865
5866 fn add_project(&mut self, project: WeakModelHandle<Project>, cx: &mut ModelContext<Self>) {
5867 if let Err(ix) = self
5868 .projects
5869 .binary_search_by_key(&project.id(), WeakModelHandle::id)
5870 {
5871 self.projects.insert(ix, project);
5872 }
5873 cx.notify();
5874 }
5875
5876 fn prune_projects(&mut self, cx: &mut ModelContext<Self>) {
5877 let mut did_change = false;
5878 self.projects.retain(|project| {
5879 if project.is_upgradable(cx) {
5880 true
5881 } else {
5882 did_change = true;
5883 false
5884 }
5885 });
5886 if did_change {
5887 cx.notify();
5888 }
5889 }
5890}
5891
5892impl WorktreeHandle {
5893 pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
5894 match self {
5895 WorktreeHandle::Strong(handle) => Some(handle.clone()),
5896 WorktreeHandle::Weak(handle) => handle.upgrade(cx),
5897 }
5898 }
5899}
5900
5901impl OpenBuffer {
5902 pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<Buffer>> {
5903 match self {
5904 OpenBuffer::Strong(handle) => Some(handle.clone()),
5905 OpenBuffer::Weak(handle) => handle.upgrade(cx),
5906 OpenBuffer::Loading(_) => None,
5907 }
5908 }
5909}
5910
5911pub struct PathMatchCandidateSet {
5912 pub snapshot: Snapshot,
5913 pub include_ignored: bool,
5914 pub include_root_name: bool,
5915}
5916
5917impl<'a> fuzzy::PathMatchCandidateSet<'a> for PathMatchCandidateSet {
5918 type Candidates = PathMatchCandidateSetIter<'a>;
5919
5920 fn id(&self) -> usize {
5921 self.snapshot.id().to_usize()
5922 }
5923
5924 fn len(&self) -> usize {
5925 if self.include_ignored {
5926 self.snapshot.file_count()
5927 } else {
5928 self.snapshot.visible_file_count()
5929 }
5930 }
5931
5932 fn prefix(&self) -> Arc<str> {
5933 if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
5934 self.snapshot.root_name().into()
5935 } else if self.include_root_name {
5936 format!("{}/", self.snapshot.root_name()).into()
5937 } else {
5938 "".into()
5939 }
5940 }
5941
5942 fn candidates(&'a self, start: usize) -> Self::Candidates {
5943 PathMatchCandidateSetIter {
5944 traversal: self.snapshot.files(self.include_ignored, start),
5945 }
5946 }
5947}
5948
5949pub struct PathMatchCandidateSetIter<'a> {
5950 traversal: Traversal<'a>,
5951}
5952
5953impl<'a> Iterator for PathMatchCandidateSetIter<'a> {
5954 type Item = fuzzy::PathMatchCandidate<'a>;
5955
5956 fn next(&mut self) -> Option<Self::Item> {
5957 self.traversal.next().map(|entry| {
5958 if let EntryKind::File(char_bag) = entry.kind {
5959 fuzzy::PathMatchCandidate {
5960 path: &entry.path,
5961 char_bag,
5962 }
5963 } else {
5964 unreachable!()
5965 }
5966 })
5967 }
5968}
5969
5970impl Entity for ProjectStore {
5971 type Event = ();
5972}
5973
5974impl Entity for Project {
5975 type Event = Event;
5976
5977 fn release(&mut self, cx: &mut gpui::MutableAppContext) {
5978 self.project_store.update(cx, ProjectStore::prune_projects);
5979
5980 match &self.client_state {
5981 ProjectClientState::Local { remote_id_rx, .. } => {
5982 if let Some(project_id) = *remote_id_rx.borrow() {
5983 self.client
5984 .send(proto::UnregisterProject { project_id })
5985 .log_err();
5986 }
5987 }
5988 ProjectClientState::Remote { remote_id, .. } => {
5989 self.client
5990 .send(proto::LeaveProject {
5991 project_id: *remote_id,
5992 })
5993 .log_err();
5994 }
5995 }
5996 }
5997
5998 fn app_will_quit(
5999 &mut self,
6000 _: &mut MutableAppContext,
6001 ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
6002 let shutdown_futures = self
6003 .language_servers
6004 .drain()
6005 .map(|(_, server_state)| async {
6006 match server_state {
6007 LanguageServerState::Running { server, .. } => server.shutdown()?.await,
6008 LanguageServerState::Starting(starting_server) => {
6009 starting_server.await?.shutdown()?.await
6010 }
6011 }
6012 })
6013 .collect::<Vec<_>>();
6014
6015 Some(
6016 async move {
6017 futures::future::join_all(shutdown_futures).await;
6018 }
6019 .boxed(),
6020 )
6021 }
6022}
6023
6024impl Collaborator {
6025 fn from_proto(
6026 message: proto::Collaborator,
6027 user_store: &ModelHandle<UserStore>,
6028 cx: &mut AsyncAppContext,
6029 ) -> impl Future<Output = Result<Self>> {
6030 let user = user_store.update(cx, |user_store, cx| {
6031 user_store.fetch_user(message.user_id, cx)
6032 });
6033
6034 async move {
6035 Ok(Self {
6036 peer_id: PeerId(message.peer_id),
6037 user: user.await?,
6038 replica_id: message.replica_id as ReplicaId,
6039 })
6040 }
6041 }
6042}
6043
6044impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
6045 fn from((worktree_id, path): (WorktreeId, P)) -> Self {
6046 Self {
6047 worktree_id,
6048 path: path.as_ref().into(),
6049 }
6050 }
6051}
6052
6053impl From<lsp::CreateFileOptions> for fs::CreateOptions {
6054 fn from(options: lsp::CreateFileOptions) -> Self {
6055 Self {
6056 overwrite: options.overwrite.unwrap_or(false),
6057 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6058 }
6059 }
6060}
6061
6062impl From<lsp::RenameFileOptions> for fs::RenameOptions {
6063 fn from(options: lsp::RenameFileOptions) -> Self {
6064 Self {
6065 overwrite: options.overwrite.unwrap_or(false),
6066 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6067 }
6068 }
6069}
6070
6071impl From<lsp::DeleteFileOptions> for fs::RemoveOptions {
6072 fn from(options: lsp::DeleteFileOptions) -> Self {
6073 Self {
6074 recursive: options.recursive.unwrap_or(false),
6075 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
6076 }
6077 }
6078}
6079
6080fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
6081 proto::Symbol {
6082 source_worktree_id: symbol.source_worktree_id.to_proto(),
6083 worktree_id: symbol.worktree_id.to_proto(),
6084 language_server_name: symbol.language_server_name.0.to_string(),
6085 name: symbol.name.clone(),
6086 kind: unsafe { mem::transmute(symbol.kind) },
6087 path: symbol.path.to_string_lossy().to_string(),
6088 start: Some(proto::Point {
6089 row: symbol.range.start.row,
6090 column: symbol.range.start.column,
6091 }),
6092 end: Some(proto::Point {
6093 row: symbol.range.end.row,
6094 column: symbol.range.end.column,
6095 }),
6096 signature: symbol.signature.to_vec(),
6097 }
6098}
6099
6100fn relativize_path(base: &Path, path: &Path) -> PathBuf {
6101 let mut path_components = path.components();
6102 let mut base_components = base.components();
6103 let mut components: Vec<Component> = Vec::new();
6104 loop {
6105 match (path_components.next(), base_components.next()) {
6106 (None, None) => break,
6107 (Some(a), None) => {
6108 components.push(a);
6109 components.extend(path_components.by_ref());
6110 break;
6111 }
6112 (None, _) => components.push(Component::ParentDir),
6113 (Some(a), Some(b)) if components.is_empty() && a == b => (),
6114 (Some(a), Some(b)) if b == Component::CurDir => components.push(a),
6115 (Some(a), Some(_)) => {
6116 components.push(Component::ParentDir);
6117 for _ in base_components {
6118 components.push(Component::ParentDir);
6119 }
6120 components.push(a);
6121 components.extend(path_components.by_ref());
6122 break;
6123 }
6124 }
6125 }
6126 components.iter().map(|c| c.as_os_str()).collect()
6127}
6128
6129impl Item for Buffer {
6130 fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId> {
6131 File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
6132 }
6133}