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 Self::deserialize_workspace_edit(
3822 this,
3823 edit,
3824 push_to_history,
3825 lsp_adapter.clone(),
3826 lang_server.clone(),
3827 &mut cx,
3828 )
3829 .await
3830 } else if let Some(command) = action.lsp_action.command {
3831 this.update(&mut cx, |this, _| {
3832 this.last_workspace_edits_by_language_server
3833 .remove(&lang_server.server_id());
3834 });
3835 lang_server
3836 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
3837 command: command.command,
3838 arguments: command.arguments.unwrap_or_default(),
3839 ..Default::default()
3840 })
3841 .await?;
3842 Ok(this.update(&mut cx, |this, _| {
3843 this.last_workspace_edits_by_language_server
3844 .remove(&lang_server.server_id())
3845 .unwrap_or_default()
3846 }))
3847 } else {
3848 Ok(ProjectTransaction::default())
3849 }
3850 })
3851 } else if let Some(project_id) = self.remote_id() {
3852 let client = self.client.clone();
3853 let request = proto::ApplyCodeAction {
3854 project_id,
3855 buffer_id: buffer_handle.read(cx).remote_id(),
3856 action: Some(language::proto::serialize_code_action(&action)),
3857 };
3858 cx.spawn(|this, mut cx| async move {
3859 let response = client
3860 .request(request)
3861 .await?
3862 .transaction
3863 .ok_or_else(|| anyhow!("missing transaction"))?;
3864 this.update(&mut cx, |this, cx| {
3865 this.deserialize_project_transaction(response, push_to_history, cx)
3866 })
3867 .await
3868 })
3869 } else {
3870 Task::ready(Err(anyhow!("project does not have a remote id")))
3871 }
3872 }
3873
3874 async fn deserialize_workspace_edit(
3875 this: ModelHandle<Self>,
3876 edit: lsp::WorkspaceEdit,
3877 push_to_history: bool,
3878 lsp_adapter: Arc<dyn LspAdapter>,
3879 language_server: Arc<LanguageServer>,
3880 cx: &mut AsyncAppContext,
3881 ) -> Result<ProjectTransaction> {
3882 let fs = this.read_with(cx, |this, _| this.fs.clone());
3883 let mut operations = Vec::new();
3884 if let Some(document_changes) = edit.document_changes {
3885 match document_changes {
3886 lsp::DocumentChanges::Edits(edits) => {
3887 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3888 }
3889 lsp::DocumentChanges::Operations(ops) => operations = ops,
3890 }
3891 } else if let Some(changes) = edit.changes {
3892 operations.extend(changes.into_iter().map(|(uri, edits)| {
3893 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3894 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3895 uri,
3896 version: None,
3897 },
3898 edits: edits.into_iter().map(lsp::OneOf::Left).collect(),
3899 })
3900 }));
3901 }
3902
3903 let mut project_transaction = ProjectTransaction::default();
3904 for operation in operations {
3905 match operation {
3906 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3907 let abs_path = op
3908 .uri
3909 .to_file_path()
3910 .map_err(|_| anyhow!("can't convert URI to path"))?;
3911
3912 if let Some(parent_path) = abs_path.parent() {
3913 fs.create_dir(parent_path).await?;
3914 }
3915 if abs_path.ends_with("/") {
3916 fs.create_dir(&abs_path).await?;
3917 } else {
3918 fs.create_file(&abs_path, op.options.map(Into::into).unwrap_or_default())
3919 .await?;
3920 }
3921 }
3922 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3923 let source_abs_path = op
3924 .old_uri
3925 .to_file_path()
3926 .map_err(|_| anyhow!("can't convert URI to path"))?;
3927 let target_abs_path = op
3928 .new_uri
3929 .to_file_path()
3930 .map_err(|_| anyhow!("can't convert URI to path"))?;
3931 fs.rename(
3932 &source_abs_path,
3933 &target_abs_path,
3934 op.options.map(Into::into).unwrap_or_default(),
3935 )
3936 .await?;
3937 }
3938 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3939 let abs_path = op
3940 .uri
3941 .to_file_path()
3942 .map_err(|_| anyhow!("can't convert URI to path"))?;
3943 let options = op.options.map(Into::into).unwrap_or_default();
3944 if abs_path.ends_with("/") {
3945 fs.remove_dir(&abs_path, options).await?;
3946 } else {
3947 fs.remove_file(&abs_path, options).await?;
3948 }
3949 }
3950 lsp::DocumentChangeOperation::Edit(op) => {
3951 let buffer_to_edit = this
3952 .update(cx, |this, cx| {
3953 this.open_local_buffer_via_lsp(
3954 op.text_document.uri,
3955 language_server.server_id(),
3956 lsp_adapter.name(),
3957 cx,
3958 )
3959 })
3960 .await?;
3961
3962 let edits = this
3963 .update(cx, |this, cx| {
3964 let edits = op.edits.into_iter().map(|edit| match edit {
3965 lsp::OneOf::Left(edit) => edit,
3966 lsp::OneOf::Right(edit) => edit.text_edit,
3967 });
3968 this.edits_from_lsp(
3969 &buffer_to_edit,
3970 edits,
3971 op.text_document.version,
3972 cx,
3973 )
3974 })
3975 .await?;
3976
3977 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3978 buffer.finalize_last_transaction();
3979 buffer.start_transaction();
3980 for (range, text) in edits {
3981 buffer.edit([(range, text)], cx);
3982 }
3983 let transaction = if buffer.end_transaction(cx).is_some() {
3984 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3985 if !push_to_history {
3986 buffer.forget_transaction(transaction.id);
3987 }
3988 Some(transaction)
3989 } else {
3990 None
3991 };
3992
3993 transaction
3994 });
3995 if let Some(transaction) = transaction {
3996 project_transaction.0.insert(buffer_to_edit, transaction);
3997 }
3998 }
3999 }
4000 }
4001
4002 Ok(project_transaction)
4003 }
4004
4005 pub fn prepare_rename<T: ToPointUtf16>(
4006 &self,
4007 buffer: ModelHandle<Buffer>,
4008 position: T,
4009 cx: &mut ModelContext<Self>,
4010 ) -> Task<Result<Option<Range<Anchor>>>> {
4011 let position = position.to_point_utf16(buffer.read(cx));
4012 self.request_lsp(buffer, PrepareRename { position }, cx)
4013 }
4014
4015 pub fn perform_rename<T: ToPointUtf16>(
4016 &self,
4017 buffer: ModelHandle<Buffer>,
4018 position: T,
4019 new_name: String,
4020 push_to_history: bool,
4021 cx: &mut ModelContext<Self>,
4022 ) -> Task<Result<ProjectTransaction>> {
4023 let position = position.to_point_utf16(buffer.read(cx));
4024 self.request_lsp(
4025 buffer,
4026 PerformRename {
4027 position,
4028 new_name,
4029 push_to_history,
4030 },
4031 cx,
4032 )
4033 }
4034
4035 pub fn search(
4036 &self,
4037 query: SearchQuery,
4038 cx: &mut ModelContext<Self>,
4039 ) -> Task<Result<HashMap<ModelHandle<Buffer>, Vec<Range<Anchor>>>>> {
4040 if self.is_local() {
4041 let snapshots = self
4042 .visible_worktrees(cx)
4043 .filter_map(|tree| {
4044 let tree = tree.read(cx).as_local()?;
4045 Some(tree.snapshot())
4046 })
4047 .collect::<Vec<_>>();
4048
4049 let background = cx.background().clone();
4050 let path_count: usize = snapshots.iter().map(|s| s.visible_file_count()).sum();
4051 if path_count == 0 {
4052 return Task::ready(Ok(Default::default()));
4053 }
4054 let workers = background.num_cpus().min(path_count);
4055 let (matching_paths_tx, mut matching_paths_rx) = smol::channel::bounded(1024);
4056 cx.background()
4057 .spawn({
4058 let fs = self.fs.clone();
4059 let background = cx.background().clone();
4060 let query = query.clone();
4061 async move {
4062 let fs = &fs;
4063 let query = &query;
4064 let matching_paths_tx = &matching_paths_tx;
4065 let paths_per_worker = (path_count + workers - 1) / workers;
4066 let snapshots = &snapshots;
4067 background
4068 .scoped(|scope| {
4069 for worker_ix in 0..workers {
4070 let worker_start_ix = worker_ix * paths_per_worker;
4071 let worker_end_ix = worker_start_ix + paths_per_worker;
4072 scope.spawn(async move {
4073 let mut snapshot_start_ix = 0;
4074 let mut abs_path = PathBuf::new();
4075 for snapshot in snapshots {
4076 let snapshot_end_ix =
4077 snapshot_start_ix + snapshot.visible_file_count();
4078 if worker_end_ix <= snapshot_start_ix {
4079 break;
4080 } else if worker_start_ix > snapshot_end_ix {
4081 snapshot_start_ix = snapshot_end_ix;
4082 continue;
4083 } else {
4084 let start_in_snapshot = worker_start_ix
4085 .saturating_sub(snapshot_start_ix);
4086 let end_in_snapshot =
4087 cmp::min(worker_end_ix, snapshot_end_ix)
4088 - snapshot_start_ix;
4089
4090 for entry in snapshot
4091 .files(false, start_in_snapshot)
4092 .take(end_in_snapshot - start_in_snapshot)
4093 {
4094 if matching_paths_tx.is_closed() {
4095 break;
4096 }
4097
4098 abs_path.clear();
4099 abs_path.push(&snapshot.abs_path());
4100 abs_path.push(&entry.path);
4101 let matches = if let Some(file) =
4102 fs.open_sync(&abs_path).await.log_err()
4103 {
4104 query.detect(file).unwrap_or(false)
4105 } else {
4106 false
4107 };
4108
4109 if matches {
4110 let project_path =
4111 (snapshot.id(), entry.path.clone());
4112 if matching_paths_tx
4113 .send(project_path)
4114 .await
4115 .is_err()
4116 {
4117 break;
4118 }
4119 }
4120 }
4121
4122 snapshot_start_ix = snapshot_end_ix;
4123 }
4124 }
4125 });
4126 }
4127 })
4128 .await;
4129 }
4130 })
4131 .detach();
4132
4133 let (buffers_tx, buffers_rx) = smol::channel::bounded(1024);
4134 let open_buffers = self
4135 .opened_buffers
4136 .values()
4137 .filter_map(|b| b.upgrade(cx))
4138 .collect::<HashSet<_>>();
4139 cx.spawn(|this, cx| async move {
4140 for buffer in &open_buffers {
4141 let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4142 buffers_tx.send((buffer.clone(), snapshot)).await?;
4143 }
4144
4145 let open_buffers = Rc::new(RefCell::new(open_buffers));
4146 while let Some(project_path) = matching_paths_rx.next().await {
4147 if buffers_tx.is_closed() {
4148 break;
4149 }
4150
4151 let this = this.clone();
4152 let open_buffers = open_buffers.clone();
4153 let buffers_tx = buffers_tx.clone();
4154 cx.spawn(|mut cx| async move {
4155 if let Some(buffer) = this
4156 .update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
4157 .await
4158 .log_err()
4159 {
4160 if open_buffers.borrow_mut().insert(buffer.clone()) {
4161 let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4162 buffers_tx.send((buffer, snapshot)).await?;
4163 }
4164 }
4165
4166 Ok::<_, anyhow::Error>(())
4167 })
4168 .detach();
4169 }
4170
4171 Ok::<_, anyhow::Error>(())
4172 })
4173 .detach_and_log_err(cx);
4174
4175 let background = cx.background().clone();
4176 cx.background().spawn(async move {
4177 let query = &query;
4178 let mut matched_buffers = Vec::new();
4179 for _ in 0..workers {
4180 matched_buffers.push(HashMap::default());
4181 }
4182 background
4183 .scoped(|scope| {
4184 for worker_matched_buffers in matched_buffers.iter_mut() {
4185 let mut buffers_rx = buffers_rx.clone();
4186 scope.spawn(async move {
4187 while let Some((buffer, snapshot)) = buffers_rx.next().await {
4188 let buffer_matches = query
4189 .search(snapshot.as_rope())
4190 .await
4191 .iter()
4192 .map(|range| {
4193 snapshot.anchor_before(range.start)
4194 ..snapshot.anchor_after(range.end)
4195 })
4196 .collect::<Vec<_>>();
4197 if !buffer_matches.is_empty() {
4198 worker_matched_buffers
4199 .insert(buffer.clone(), buffer_matches);
4200 }
4201 }
4202 });
4203 }
4204 })
4205 .await;
4206 Ok(matched_buffers.into_iter().flatten().collect())
4207 })
4208 } else if let Some(project_id) = self.remote_id() {
4209 let request = self.client.request(query.to_proto(project_id));
4210 cx.spawn(|this, mut cx| async move {
4211 let response = request.await?;
4212 let mut result = HashMap::default();
4213 for location in response.locations {
4214 let buffer = location.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
4215 let target_buffer = this
4216 .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
4217 .await?;
4218 let start = location
4219 .start
4220 .and_then(deserialize_anchor)
4221 .ok_or_else(|| anyhow!("missing target start"))?;
4222 let end = location
4223 .end
4224 .and_then(deserialize_anchor)
4225 .ok_or_else(|| anyhow!("missing target end"))?;
4226 result
4227 .entry(target_buffer)
4228 .or_insert(Vec::new())
4229 .push(start..end)
4230 }
4231 Ok(result)
4232 })
4233 } else {
4234 Task::ready(Ok(Default::default()))
4235 }
4236 }
4237
4238 fn request_lsp<R: LspCommand>(
4239 &self,
4240 buffer_handle: ModelHandle<Buffer>,
4241 request: R,
4242 cx: &mut ModelContext<Self>,
4243 ) -> Task<Result<R::Response>>
4244 where
4245 <R::LspRequest as lsp::request::Request>::Result: Send,
4246 {
4247 let buffer = buffer_handle.read(cx);
4248 if self.is_local() {
4249 let file = File::from_dyn(buffer.file()).and_then(File::as_local);
4250 if let Some((file, language_server)) = file.zip(
4251 self.language_server_for_buffer(buffer, cx)
4252 .map(|(_, server)| server.clone()),
4253 ) {
4254 let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
4255 return cx.spawn(|this, cx| async move {
4256 if !request.check_capabilities(&language_server.capabilities()) {
4257 return Ok(Default::default());
4258 }
4259
4260 let response = language_server
4261 .request::<R::LspRequest>(lsp_params)
4262 .await
4263 .context("lsp request failed")?;
4264 request
4265 .response_from_lsp(response, this, buffer_handle, cx)
4266 .await
4267 });
4268 }
4269 } else if let Some(project_id) = self.remote_id() {
4270 let rpc = self.client.clone();
4271 let message = request.to_proto(project_id, buffer);
4272 return cx.spawn(|this, cx| async move {
4273 let response = rpc.request(message).await?;
4274 request
4275 .response_from_proto(response, this, buffer_handle, cx)
4276 .await
4277 });
4278 }
4279 Task::ready(Ok(Default::default()))
4280 }
4281
4282 pub fn find_or_create_local_worktree(
4283 &mut self,
4284 abs_path: impl AsRef<Path>,
4285 visible: bool,
4286 cx: &mut ModelContext<Self>,
4287 ) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
4288 let abs_path = abs_path.as_ref();
4289 if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) {
4290 Task::ready(Ok((tree.clone(), relative_path.into())))
4291 } else {
4292 let worktree = self.create_local_worktree(abs_path, visible, cx);
4293 cx.foreground()
4294 .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
4295 }
4296 }
4297
4298 pub fn find_local_worktree(
4299 &self,
4300 abs_path: &Path,
4301 cx: &AppContext,
4302 ) -> Option<(ModelHandle<Worktree>, PathBuf)> {
4303 for tree in &self.worktrees {
4304 if let Some(tree) = tree.upgrade(cx) {
4305 if let Some(relative_path) = tree
4306 .read(cx)
4307 .as_local()
4308 .and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
4309 {
4310 return Some((tree.clone(), relative_path.into()));
4311 }
4312 }
4313 }
4314 None
4315 }
4316
4317 pub fn is_shared(&self) -> bool {
4318 match &self.client_state {
4319 ProjectClientState::Local { is_shared, .. } => *is_shared,
4320 ProjectClientState::Remote { .. } => false,
4321 }
4322 }
4323
4324 fn create_local_worktree(
4325 &mut self,
4326 abs_path: impl AsRef<Path>,
4327 visible: bool,
4328 cx: &mut ModelContext<Self>,
4329 ) -> Task<Result<ModelHandle<Worktree>>> {
4330 let fs = self.fs.clone();
4331 let client = self.client.clone();
4332 let next_entry_id = self.next_entry_id.clone();
4333 let path: Arc<Path> = abs_path.as_ref().into();
4334 let task = self
4335 .loading_local_worktrees
4336 .entry(path.clone())
4337 .or_insert_with(|| {
4338 cx.spawn(|project, mut cx| {
4339 async move {
4340 let worktree = Worktree::local(
4341 client.clone(),
4342 path.clone(),
4343 visible,
4344 fs,
4345 next_entry_id,
4346 &mut cx,
4347 )
4348 .await;
4349 project.update(&mut cx, |project, _| {
4350 project.loading_local_worktrees.remove(&path);
4351 });
4352 let worktree = worktree?;
4353
4354 let project_id = project.update(&mut cx, |project, cx| {
4355 project.add_worktree(&worktree, cx);
4356 project.shared_remote_id()
4357 });
4358
4359 if let Some(project_id) = project_id {
4360 worktree
4361 .update(&mut cx, |worktree, cx| {
4362 worktree.as_local_mut().unwrap().share(project_id, cx)
4363 })
4364 .await
4365 .log_err();
4366 }
4367
4368 Ok(worktree)
4369 }
4370 .map_err(|err| Arc::new(err))
4371 })
4372 .shared()
4373 })
4374 .clone();
4375 cx.foreground().spawn(async move {
4376 match task.await {
4377 Ok(worktree) => Ok(worktree),
4378 Err(err) => Err(anyhow!("{}", err)),
4379 }
4380 })
4381 }
4382
4383 pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
4384 self.worktrees.retain(|worktree| {
4385 if let Some(worktree) = worktree.upgrade(cx) {
4386 let id = worktree.read(cx).id();
4387 if id == id_to_remove {
4388 cx.emit(Event::WorktreeRemoved(id));
4389 false
4390 } else {
4391 true
4392 }
4393 } else {
4394 false
4395 }
4396 });
4397 self.metadata_changed(true, cx);
4398 cx.notify();
4399 }
4400
4401 fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
4402 cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
4403 if worktree.read(cx).is_local() {
4404 cx.subscribe(&worktree, |this, worktree, _, cx| {
4405 this.update_local_worktree_buffers(worktree, cx);
4406 })
4407 .detach();
4408 }
4409
4410 let push_strong_handle = {
4411 let worktree = worktree.read(cx);
4412 self.is_shared() || worktree.is_visible() || worktree.is_remote()
4413 };
4414 if push_strong_handle {
4415 self.worktrees
4416 .push(WorktreeHandle::Strong(worktree.clone()));
4417 } else {
4418 self.worktrees
4419 .push(WorktreeHandle::Weak(worktree.downgrade()));
4420 }
4421
4422 self.metadata_changed(true, cx);
4423 cx.observe_release(&worktree, |this, worktree, cx| {
4424 this.remove_worktree(worktree.id(), cx);
4425 cx.notify();
4426 })
4427 .detach();
4428
4429 cx.emit(Event::WorktreeAdded);
4430 cx.notify();
4431 }
4432
4433 fn update_local_worktree_buffers(
4434 &mut self,
4435 worktree_handle: ModelHandle<Worktree>,
4436 cx: &mut ModelContext<Self>,
4437 ) {
4438 let snapshot = worktree_handle.read(cx).snapshot();
4439 let mut buffers_to_delete = Vec::new();
4440 let mut renamed_buffers = Vec::new();
4441 for (buffer_id, buffer) in &self.opened_buffers {
4442 if let Some(buffer) = buffer.upgrade(cx) {
4443 buffer.update(cx, |buffer, cx| {
4444 if let Some(old_file) = File::from_dyn(buffer.file()) {
4445 if old_file.worktree != worktree_handle {
4446 return;
4447 }
4448
4449 let new_file = if let Some(entry) = old_file
4450 .entry_id
4451 .and_then(|entry_id| snapshot.entry_for_id(entry_id))
4452 {
4453 File {
4454 is_local: true,
4455 entry_id: Some(entry.id),
4456 mtime: entry.mtime,
4457 path: entry.path.clone(),
4458 worktree: worktree_handle.clone(),
4459 }
4460 } else if let Some(entry) =
4461 snapshot.entry_for_path(old_file.path().as_ref())
4462 {
4463 File {
4464 is_local: true,
4465 entry_id: Some(entry.id),
4466 mtime: entry.mtime,
4467 path: entry.path.clone(),
4468 worktree: worktree_handle.clone(),
4469 }
4470 } else {
4471 File {
4472 is_local: true,
4473 entry_id: None,
4474 path: old_file.path().clone(),
4475 mtime: old_file.mtime(),
4476 worktree: worktree_handle.clone(),
4477 }
4478 };
4479
4480 let old_path = old_file.abs_path(cx);
4481 if new_file.abs_path(cx) != old_path {
4482 renamed_buffers.push((cx.handle(), old_path));
4483 }
4484
4485 if let Some(project_id) = self.shared_remote_id() {
4486 self.client
4487 .send(proto::UpdateBufferFile {
4488 project_id,
4489 buffer_id: *buffer_id as u64,
4490 file: Some(new_file.to_proto()),
4491 })
4492 .log_err();
4493 }
4494 buffer.file_updated(Arc::new(new_file), cx).detach();
4495 }
4496 });
4497 } else {
4498 buffers_to_delete.push(*buffer_id);
4499 }
4500 }
4501
4502 for buffer_id in buffers_to_delete {
4503 self.opened_buffers.remove(&buffer_id);
4504 }
4505
4506 for (buffer, old_path) in renamed_buffers {
4507 self.unregister_buffer_from_language_server(&buffer, old_path, cx);
4508 self.assign_language_to_buffer(&buffer, cx);
4509 self.register_buffer_with_language_server(&buffer, cx);
4510 }
4511 }
4512
4513 pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
4514 let new_active_entry = entry.and_then(|project_path| {
4515 let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
4516 let entry = worktree.read(cx).entry_for_path(project_path.path)?;
4517 Some(entry.id)
4518 });
4519 if new_active_entry != self.active_entry {
4520 self.active_entry = new_active_entry;
4521 cx.emit(Event::ActiveEntryChanged(new_active_entry));
4522 }
4523 }
4524
4525 pub fn language_servers_running_disk_based_diagnostics<'a>(
4526 &'a self,
4527 ) -> impl 'a + Iterator<Item = usize> {
4528 self.language_server_statuses
4529 .iter()
4530 .filter_map(|(id, status)| {
4531 if status.has_pending_diagnostic_updates {
4532 Some(*id)
4533 } else {
4534 None
4535 }
4536 })
4537 }
4538
4539 pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
4540 let mut summary = DiagnosticSummary::default();
4541 for (_, path_summary) in self.diagnostic_summaries(cx) {
4542 summary.error_count += path_summary.error_count;
4543 summary.warning_count += path_summary.warning_count;
4544 }
4545 summary
4546 }
4547
4548 pub fn diagnostic_summaries<'a>(
4549 &'a self,
4550 cx: &'a AppContext,
4551 ) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
4552 self.visible_worktrees(cx).flat_map(move |worktree| {
4553 let worktree = worktree.read(cx);
4554 let worktree_id = worktree.id();
4555 worktree
4556 .diagnostic_summaries()
4557 .map(move |(path, summary)| (ProjectPath { worktree_id, path }, summary))
4558 })
4559 }
4560
4561 pub fn disk_based_diagnostics_started(
4562 &mut self,
4563 language_server_id: usize,
4564 cx: &mut ModelContext<Self>,
4565 ) {
4566 cx.emit(Event::DiskBasedDiagnosticsStarted { language_server_id });
4567 }
4568
4569 pub fn disk_based_diagnostics_finished(
4570 &mut self,
4571 language_server_id: usize,
4572 cx: &mut ModelContext<Self>,
4573 ) {
4574 cx.emit(Event::DiskBasedDiagnosticsFinished { language_server_id });
4575 }
4576
4577 pub fn active_entry(&self) -> Option<ProjectEntryId> {
4578 self.active_entry
4579 }
4580
4581 pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option<ProjectEntryId> {
4582 self.worktree_for_id(path.worktree_id, cx)?
4583 .read(cx)
4584 .entry_for_path(&path.path)
4585 .map(|entry| entry.id)
4586 }
4587
4588 pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &AppContext) -> Option<ProjectPath> {
4589 let worktree = self.worktree_for_entry(entry_id, cx)?;
4590 let worktree = worktree.read(cx);
4591 let worktree_id = worktree.id();
4592 let path = worktree.entry_for_id(entry_id)?.path.clone();
4593 Some(ProjectPath { worktree_id, path })
4594 }
4595
4596 // RPC message handlers
4597
4598 async fn handle_request_join_project(
4599 this: ModelHandle<Self>,
4600 message: TypedEnvelope<proto::RequestJoinProject>,
4601 _: Arc<Client>,
4602 mut cx: AsyncAppContext,
4603 ) -> Result<()> {
4604 let user_id = message.payload.requester_id;
4605 if this.read_with(&cx, |project, _| {
4606 project.collaborators.values().any(|c| c.user.id == user_id)
4607 }) {
4608 this.update(&mut cx, |this, cx| {
4609 this.respond_to_join_request(user_id, true, cx)
4610 });
4611 } else {
4612 let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
4613 let user = user_store
4614 .update(&mut cx, |store, cx| store.fetch_user(user_id, cx))
4615 .await?;
4616 this.update(&mut cx, |_, cx| cx.emit(Event::ContactRequestedJoin(user)));
4617 }
4618 Ok(())
4619 }
4620
4621 async fn handle_unregister_project(
4622 this: ModelHandle<Self>,
4623 _: TypedEnvelope<proto::UnregisterProject>,
4624 _: Arc<Client>,
4625 mut cx: AsyncAppContext,
4626 ) -> Result<()> {
4627 this.update(&mut cx, |this, cx| this.removed_from_project(cx));
4628 Ok(())
4629 }
4630
4631 async fn handle_project_unshared(
4632 this: ModelHandle<Self>,
4633 _: TypedEnvelope<proto::ProjectUnshared>,
4634 _: Arc<Client>,
4635 mut cx: AsyncAppContext,
4636 ) -> Result<()> {
4637 this.update(&mut cx, |this, cx| this.unshared(cx));
4638 Ok(())
4639 }
4640
4641 async fn handle_add_collaborator(
4642 this: ModelHandle<Self>,
4643 mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
4644 _: Arc<Client>,
4645 mut cx: AsyncAppContext,
4646 ) -> Result<()> {
4647 let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
4648 let collaborator = envelope
4649 .payload
4650 .collaborator
4651 .take()
4652 .ok_or_else(|| anyhow!("empty collaborator"))?;
4653
4654 let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
4655 this.update(&mut cx, |this, cx| {
4656 this.collaborators
4657 .insert(collaborator.peer_id, collaborator);
4658 cx.notify();
4659 });
4660
4661 Ok(())
4662 }
4663
4664 async fn handle_remove_collaborator(
4665 this: ModelHandle<Self>,
4666 envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
4667 _: Arc<Client>,
4668 mut cx: AsyncAppContext,
4669 ) -> Result<()> {
4670 this.update(&mut cx, |this, cx| {
4671 let peer_id = PeerId(envelope.payload.peer_id);
4672 let replica_id = this
4673 .collaborators
4674 .remove(&peer_id)
4675 .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
4676 .replica_id;
4677 for (_, buffer) in &this.opened_buffers {
4678 if let Some(buffer) = buffer.upgrade(cx) {
4679 buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
4680 }
4681 }
4682
4683 cx.emit(Event::CollaboratorLeft(peer_id));
4684 cx.notify();
4685 Ok(())
4686 })
4687 }
4688
4689 async fn handle_join_project_request_cancelled(
4690 this: ModelHandle<Self>,
4691 envelope: TypedEnvelope<proto::JoinProjectRequestCancelled>,
4692 _: Arc<Client>,
4693 mut cx: AsyncAppContext,
4694 ) -> Result<()> {
4695 let user = this
4696 .update(&mut cx, |this, cx| {
4697 this.user_store.update(cx, |user_store, cx| {
4698 user_store.fetch_user(envelope.payload.requester_id, cx)
4699 })
4700 })
4701 .await?;
4702
4703 this.update(&mut cx, |_, cx| {
4704 cx.emit(Event::ContactCancelledJoinRequest(user));
4705 });
4706
4707 Ok(())
4708 }
4709
4710 async fn handle_update_project(
4711 this: ModelHandle<Self>,
4712 envelope: TypedEnvelope<proto::UpdateProject>,
4713 client: Arc<Client>,
4714 mut cx: AsyncAppContext,
4715 ) -> Result<()> {
4716 this.update(&mut cx, |this, cx| {
4717 let replica_id = this.replica_id();
4718 let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
4719
4720 let mut old_worktrees_by_id = this
4721 .worktrees
4722 .drain(..)
4723 .filter_map(|worktree| {
4724 let worktree = worktree.upgrade(cx)?;
4725 Some((worktree.read(cx).id(), worktree))
4726 })
4727 .collect::<HashMap<_, _>>();
4728
4729 for worktree in envelope.payload.worktrees {
4730 if let Some(old_worktree) =
4731 old_worktrees_by_id.remove(&WorktreeId::from_proto(worktree.id))
4732 {
4733 this.worktrees.push(WorktreeHandle::Strong(old_worktree));
4734 } else {
4735 let worktree =
4736 Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx);
4737 this.add_worktree(&worktree, cx);
4738 }
4739 }
4740
4741 this.metadata_changed(true, cx);
4742 for (id, _) in old_worktrees_by_id {
4743 cx.emit(Event::WorktreeRemoved(id));
4744 }
4745
4746 Ok(())
4747 })
4748 }
4749
4750 async fn handle_update_worktree(
4751 this: ModelHandle<Self>,
4752 envelope: TypedEnvelope<proto::UpdateWorktree>,
4753 _: Arc<Client>,
4754 mut cx: AsyncAppContext,
4755 ) -> Result<()> {
4756 this.update(&mut cx, |this, cx| {
4757 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4758 if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4759 worktree.update(cx, |worktree, _| {
4760 let worktree = worktree.as_remote_mut().unwrap();
4761 worktree.update_from_remote(envelope.payload);
4762 });
4763 }
4764 Ok(())
4765 })
4766 }
4767
4768 async fn handle_create_project_entry(
4769 this: ModelHandle<Self>,
4770 envelope: TypedEnvelope<proto::CreateProjectEntry>,
4771 _: Arc<Client>,
4772 mut cx: AsyncAppContext,
4773 ) -> Result<proto::ProjectEntryResponse> {
4774 let worktree = this.update(&mut cx, |this, cx| {
4775 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4776 this.worktree_for_id(worktree_id, cx)
4777 .ok_or_else(|| anyhow!("worktree not found"))
4778 })?;
4779 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4780 let entry = worktree
4781 .update(&mut cx, |worktree, cx| {
4782 let worktree = worktree.as_local_mut().unwrap();
4783 let path = PathBuf::from(OsString::from_vec(envelope.payload.path));
4784 worktree.create_entry(path, envelope.payload.is_directory, cx)
4785 })
4786 .await?;
4787 Ok(proto::ProjectEntryResponse {
4788 entry: Some((&entry).into()),
4789 worktree_scan_id: worktree_scan_id as u64,
4790 })
4791 }
4792
4793 async fn handle_rename_project_entry(
4794 this: ModelHandle<Self>,
4795 envelope: TypedEnvelope<proto::RenameProjectEntry>,
4796 _: Arc<Client>,
4797 mut cx: AsyncAppContext,
4798 ) -> Result<proto::ProjectEntryResponse> {
4799 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4800 let worktree = this.read_with(&cx, |this, cx| {
4801 this.worktree_for_entry(entry_id, cx)
4802 .ok_or_else(|| anyhow!("worktree not found"))
4803 })?;
4804 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4805 let entry = worktree
4806 .update(&mut cx, |worktree, cx| {
4807 let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path));
4808 worktree
4809 .as_local_mut()
4810 .unwrap()
4811 .rename_entry(entry_id, new_path, cx)
4812 .ok_or_else(|| anyhow!("invalid entry"))
4813 })?
4814 .await?;
4815 Ok(proto::ProjectEntryResponse {
4816 entry: Some((&entry).into()),
4817 worktree_scan_id: worktree_scan_id as u64,
4818 })
4819 }
4820
4821 async fn handle_copy_project_entry(
4822 this: ModelHandle<Self>,
4823 envelope: TypedEnvelope<proto::CopyProjectEntry>,
4824 _: Arc<Client>,
4825 mut cx: AsyncAppContext,
4826 ) -> Result<proto::ProjectEntryResponse> {
4827 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4828 let worktree = this.read_with(&cx, |this, cx| {
4829 this.worktree_for_entry(entry_id, cx)
4830 .ok_or_else(|| anyhow!("worktree not found"))
4831 })?;
4832 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4833 let entry = worktree
4834 .update(&mut cx, |worktree, cx| {
4835 let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path));
4836 worktree
4837 .as_local_mut()
4838 .unwrap()
4839 .copy_entry(entry_id, new_path, cx)
4840 .ok_or_else(|| anyhow!("invalid entry"))
4841 })?
4842 .await?;
4843 Ok(proto::ProjectEntryResponse {
4844 entry: Some((&entry).into()),
4845 worktree_scan_id: worktree_scan_id as u64,
4846 })
4847 }
4848
4849 async fn handle_delete_project_entry(
4850 this: ModelHandle<Self>,
4851 envelope: TypedEnvelope<proto::DeleteProjectEntry>,
4852 _: Arc<Client>,
4853 mut cx: AsyncAppContext,
4854 ) -> Result<proto::ProjectEntryResponse> {
4855 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4856 let worktree = this.read_with(&cx, |this, cx| {
4857 this.worktree_for_entry(entry_id, cx)
4858 .ok_or_else(|| anyhow!("worktree not found"))
4859 })?;
4860 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4861 worktree
4862 .update(&mut cx, |worktree, cx| {
4863 worktree
4864 .as_local_mut()
4865 .unwrap()
4866 .delete_entry(entry_id, cx)
4867 .ok_or_else(|| anyhow!("invalid entry"))
4868 })?
4869 .await?;
4870 Ok(proto::ProjectEntryResponse {
4871 entry: None,
4872 worktree_scan_id: worktree_scan_id as u64,
4873 })
4874 }
4875
4876 async fn handle_update_diagnostic_summary(
4877 this: ModelHandle<Self>,
4878 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
4879 _: Arc<Client>,
4880 mut cx: AsyncAppContext,
4881 ) -> Result<()> {
4882 this.update(&mut cx, |this, cx| {
4883 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4884 if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4885 if let Some(summary) = envelope.payload.summary {
4886 let project_path = ProjectPath {
4887 worktree_id,
4888 path: Path::new(&summary.path).into(),
4889 };
4890 worktree.update(cx, |worktree, _| {
4891 worktree
4892 .as_remote_mut()
4893 .unwrap()
4894 .update_diagnostic_summary(project_path.path.clone(), &summary);
4895 });
4896 cx.emit(Event::DiagnosticsUpdated {
4897 language_server_id: summary.language_server_id as usize,
4898 path: project_path,
4899 });
4900 }
4901 }
4902 Ok(())
4903 })
4904 }
4905
4906 async fn handle_start_language_server(
4907 this: ModelHandle<Self>,
4908 envelope: TypedEnvelope<proto::StartLanguageServer>,
4909 _: Arc<Client>,
4910 mut cx: AsyncAppContext,
4911 ) -> Result<()> {
4912 let server = envelope
4913 .payload
4914 .server
4915 .ok_or_else(|| anyhow!("invalid server"))?;
4916 this.update(&mut cx, |this, cx| {
4917 this.language_server_statuses.insert(
4918 server.id as usize,
4919 LanguageServerStatus {
4920 name: server.name,
4921 pending_work: Default::default(),
4922 has_pending_diagnostic_updates: false,
4923 progress_tokens: Default::default(),
4924 },
4925 );
4926 cx.notify();
4927 });
4928 Ok(())
4929 }
4930
4931 async fn handle_update_language_server(
4932 this: ModelHandle<Self>,
4933 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
4934 _: Arc<Client>,
4935 mut cx: AsyncAppContext,
4936 ) -> Result<()> {
4937 let language_server_id = envelope.payload.language_server_id as usize;
4938 match envelope
4939 .payload
4940 .variant
4941 .ok_or_else(|| anyhow!("invalid variant"))?
4942 {
4943 proto::update_language_server::Variant::WorkStart(payload) => {
4944 this.update(&mut cx, |this, cx| {
4945 this.on_lsp_work_start(
4946 language_server_id,
4947 payload.token,
4948 LanguageServerProgress {
4949 message: payload.message,
4950 percentage: payload.percentage.map(|p| p as usize),
4951 last_update_at: Instant::now(),
4952 },
4953 cx,
4954 );
4955 })
4956 }
4957 proto::update_language_server::Variant::WorkProgress(payload) => {
4958 this.update(&mut cx, |this, cx| {
4959 this.on_lsp_work_progress(
4960 language_server_id,
4961 payload.token,
4962 LanguageServerProgress {
4963 message: payload.message,
4964 percentage: payload.percentage.map(|p| p as usize),
4965 last_update_at: Instant::now(),
4966 },
4967 cx,
4968 );
4969 })
4970 }
4971 proto::update_language_server::Variant::WorkEnd(payload) => {
4972 this.update(&mut cx, |this, cx| {
4973 this.on_lsp_work_end(language_server_id, payload.token, cx);
4974 })
4975 }
4976 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
4977 this.update(&mut cx, |this, cx| {
4978 this.disk_based_diagnostics_started(language_server_id, cx);
4979 })
4980 }
4981 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
4982 this.update(&mut cx, |this, cx| {
4983 this.disk_based_diagnostics_finished(language_server_id, cx)
4984 });
4985 }
4986 }
4987
4988 Ok(())
4989 }
4990
4991 async fn handle_update_buffer(
4992 this: ModelHandle<Self>,
4993 envelope: TypedEnvelope<proto::UpdateBuffer>,
4994 _: Arc<Client>,
4995 mut cx: AsyncAppContext,
4996 ) -> Result<()> {
4997 this.update(&mut cx, |this, cx| {
4998 let payload = envelope.payload.clone();
4999 let buffer_id = payload.buffer_id;
5000 let ops = payload
5001 .operations
5002 .into_iter()
5003 .map(|op| language::proto::deserialize_operation(op))
5004 .collect::<Result<Vec<_>, _>>()?;
5005 let is_remote = this.is_remote();
5006 match this.opened_buffers.entry(buffer_id) {
5007 hash_map::Entry::Occupied(mut e) => match e.get_mut() {
5008 OpenBuffer::Strong(buffer) => {
5009 buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
5010 }
5011 OpenBuffer::Loading(operations) => operations.extend_from_slice(&ops),
5012 OpenBuffer::Weak(_) => {}
5013 },
5014 hash_map::Entry::Vacant(e) => {
5015 assert!(
5016 is_remote,
5017 "received buffer update from {:?}",
5018 envelope.original_sender_id
5019 );
5020 e.insert(OpenBuffer::Loading(ops));
5021 }
5022 }
5023 Ok(())
5024 })
5025 }
5026
5027 async fn handle_update_buffer_file(
5028 this: ModelHandle<Self>,
5029 envelope: TypedEnvelope<proto::UpdateBufferFile>,
5030 _: Arc<Client>,
5031 mut cx: AsyncAppContext,
5032 ) -> Result<()> {
5033 this.update(&mut cx, |this, cx| {
5034 let payload = envelope.payload.clone();
5035 let buffer_id = payload.buffer_id;
5036 let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
5037 let worktree = this
5038 .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
5039 .ok_or_else(|| anyhow!("no such worktree"))?;
5040 let file = File::from_proto(file, worktree.clone(), cx)?;
5041 let buffer = this
5042 .opened_buffers
5043 .get_mut(&buffer_id)
5044 .and_then(|b| b.upgrade(cx))
5045 .ok_or_else(|| anyhow!("no such buffer"))?;
5046 buffer.update(cx, |buffer, cx| {
5047 buffer.file_updated(Arc::new(file), cx).detach();
5048 });
5049 Ok(())
5050 })
5051 }
5052
5053 async fn handle_save_buffer(
5054 this: ModelHandle<Self>,
5055 envelope: TypedEnvelope<proto::SaveBuffer>,
5056 _: Arc<Client>,
5057 mut cx: AsyncAppContext,
5058 ) -> Result<proto::BufferSaved> {
5059 let buffer_id = envelope.payload.buffer_id;
5060 let requested_version = deserialize_version(envelope.payload.version);
5061
5062 let (project_id, buffer) = this.update(&mut cx, |this, cx| {
5063 let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
5064 let buffer = this
5065 .opened_buffers
5066 .get(&buffer_id)
5067 .and_then(|buffer| buffer.upgrade(cx))
5068 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
5069 Ok::<_, anyhow::Error>((project_id, buffer))
5070 })?;
5071 buffer
5072 .update(&mut cx, |buffer, _| {
5073 buffer.wait_for_version(requested_version)
5074 })
5075 .await;
5076
5077 let (saved_version, fingerprint, mtime) =
5078 buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await?;
5079 Ok(proto::BufferSaved {
5080 project_id,
5081 buffer_id,
5082 version: serialize_version(&saved_version),
5083 mtime: Some(mtime.into()),
5084 fingerprint,
5085 })
5086 }
5087
5088 async fn handle_reload_buffers(
5089 this: ModelHandle<Self>,
5090 envelope: TypedEnvelope<proto::ReloadBuffers>,
5091 _: Arc<Client>,
5092 mut cx: AsyncAppContext,
5093 ) -> Result<proto::ReloadBuffersResponse> {
5094 let sender_id = envelope.original_sender_id()?;
5095 let reload = this.update(&mut cx, |this, cx| {
5096 let mut buffers = HashSet::default();
5097 for buffer_id in &envelope.payload.buffer_ids {
5098 buffers.insert(
5099 this.opened_buffers
5100 .get(buffer_id)
5101 .and_then(|buffer| buffer.upgrade(cx))
5102 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
5103 );
5104 }
5105 Ok::<_, anyhow::Error>(this.reload_buffers(buffers, false, cx))
5106 })?;
5107
5108 let project_transaction = reload.await?;
5109 let project_transaction = this.update(&mut cx, |this, cx| {
5110 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5111 });
5112 Ok(proto::ReloadBuffersResponse {
5113 transaction: Some(project_transaction),
5114 })
5115 }
5116
5117 async fn handle_format_buffers(
5118 this: ModelHandle<Self>,
5119 envelope: TypedEnvelope<proto::FormatBuffers>,
5120 _: Arc<Client>,
5121 mut cx: AsyncAppContext,
5122 ) -> Result<proto::FormatBuffersResponse> {
5123 let sender_id = envelope.original_sender_id()?;
5124 let format = this.update(&mut cx, |this, cx| {
5125 let mut buffers = HashSet::default();
5126 for buffer_id in &envelope.payload.buffer_ids {
5127 buffers.insert(
5128 this.opened_buffers
5129 .get(buffer_id)
5130 .and_then(|buffer| buffer.upgrade(cx))
5131 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
5132 );
5133 }
5134 Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
5135 })?;
5136
5137 let project_transaction = format.await?;
5138 let project_transaction = this.update(&mut cx, |this, cx| {
5139 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5140 });
5141 Ok(proto::FormatBuffersResponse {
5142 transaction: Some(project_transaction),
5143 })
5144 }
5145
5146 async fn handle_get_completions(
5147 this: ModelHandle<Self>,
5148 envelope: TypedEnvelope<proto::GetCompletions>,
5149 _: Arc<Client>,
5150 mut cx: AsyncAppContext,
5151 ) -> Result<proto::GetCompletionsResponse> {
5152 let position = envelope
5153 .payload
5154 .position
5155 .and_then(language::proto::deserialize_anchor)
5156 .ok_or_else(|| anyhow!("invalid position"))?;
5157 let version = deserialize_version(envelope.payload.version);
5158 let buffer = this.read_with(&cx, |this, cx| {
5159 this.opened_buffers
5160 .get(&envelope.payload.buffer_id)
5161 .and_then(|buffer| buffer.upgrade(cx))
5162 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
5163 })?;
5164 buffer
5165 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
5166 .await;
5167 let version = buffer.read_with(&cx, |buffer, _| buffer.version());
5168 let completions = this
5169 .update(&mut cx, |this, cx| this.completions(&buffer, position, cx))
5170 .await?;
5171
5172 Ok(proto::GetCompletionsResponse {
5173 completions: completions
5174 .iter()
5175 .map(language::proto::serialize_completion)
5176 .collect(),
5177 version: serialize_version(&version),
5178 })
5179 }
5180
5181 async fn handle_apply_additional_edits_for_completion(
5182 this: ModelHandle<Self>,
5183 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
5184 _: Arc<Client>,
5185 mut cx: AsyncAppContext,
5186 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
5187 let apply_additional_edits = this.update(&mut cx, |this, cx| {
5188 let buffer = this
5189 .opened_buffers
5190 .get(&envelope.payload.buffer_id)
5191 .and_then(|buffer| buffer.upgrade(cx))
5192 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
5193 let language = buffer.read(cx).language();
5194 let completion = language::proto::deserialize_completion(
5195 envelope
5196 .payload
5197 .completion
5198 .ok_or_else(|| anyhow!("invalid completion"))?,
5199 language,
5200 )?;
5201 Ok::<_, anyhow::Error>(
5202 this.apply_additional_edits_for_completion(buffer, completion, false, cx),
5203 )
5204 })?;
5205
5206 Ok(proto::ApplyCompletionAdditionalEditsResponse {
5207 transaction: apply_additional_edits
5208 .await?
5209 .as_ref()
5210 .map(language::proto::serialize_transaction),
5211 })
5212 }
5213
5214 async fn handle_get_code_actions(
5215 this: ModelHandle<Self>,
5216 envelope: TypedEnvelope<proto::GetCodeActions>,
5217 _: Arc<Client>,
5218 mut cx: AsyncAppContext,
5219 ) -> Result<proto::GetCodeActionsResponse> {
5220 let start = envelope
5221 .payload
5222 .start
5223 .and_then(language::proto::deserialize_anchor)
5224 .ok_or_else(|| anyhow!("invalid start"))?;
5225 let end = envelope
5226 .payload
5227 .end
5228 .and_then(language::proto::deserialize_anchor)
5229 .ok_or_else(|| anyhow!("invalid end"))?;
5230 let buffer = this.update(&mut cx, |this, cx| {
5231 this.opened_buffers
5232 .get(&envelope.payload.buffer_id)
5233 .and_then(|buffer| buffer.upgrade(cx))
5234 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
5235 })?;
5236 buffer
5237 .update(&mut cx, |buffer, _| {
5238 buffer.wait_for_version(deserialize_version(envelope.payload.version))
5239 })
5240 .await;
5241
5242 let version = buffer.read_with(&cx, |buffer, _| buffer.version());
5243 let code_actions = this.update(&mut cx, |this, cx| {
5244 Ok::<_, anyhow::Error>(this.code_actions(&buffer, start..end, cx))
5245 })?;
5246
5247 Ok(proto::GetCodeActionsResponse {
5248 actions: code_actions
5249 .await?
5250 .iter()
5251 .map(language::proto::serialize_code_action)
5252 .collect(),
5253 version: serialize_version(&version),
5254 })
5255 }
5256
5257 async fn handle_apply_code_action(
5258 this: ModelHandle<Self>,
5259 envelope: TypedEnvelope<proto::ApplyCodeAction>,
5260 _: Arc<Client>,
5261 mut cx: AsyncAppContext,
5262 ) -> Result<proto::ApplyCodeActionResponse> {
5263 let sender_id = envelope.original_sender_id()?;
5264 let action = language::proto::deserialize_code_action(
5265 envelope
5266 .payload
5267 .action
5268 .ok_or_else(|| anyhow!("invalid action"))?,
5269 )?;
5270 let apply_code_action = this.update(&mut cx, |this, cx| {
5271 let buffer = this
5272 .opened_buffers
5273 .get(&envelope.payload.buffer_id)
5274 .and_then(|buffer| buffer.upgrade(cx))
5275 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
5276 Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
5277 })?;
5278
5279 let project_transaction = apply_code_action.await?;
5280 let project_transaction = this.update(&mut cx, |this, cx| {
5281 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5282 });
5283 Ok(proto::ApplyCodeActionResponse {
5284 transaction: Some(project_transaction),
5285 })
5286 }
5287
5288 async fn handle_lsp_command<T: LspCommand>(
5289 this: ModelHandle<Self>,
5290 envelope: TypedEnvelope<T::ProtoRequest>,
5291 _: Arc<Client>,
5292 mut cx: AsyncAppContext,
5293 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
5294 where
5295 <T::LspRequest as lsp::request::Request>::Result: Send,
5296 {
5297 let sender_id = envelope.original_sender_id()?;
5298 let buffer_id = T::buffer_id_from_proto(&envelope.payload);
5299 let buffer_handle = this.read_with(&cx, |this, _| {
5300 this.opened_buffers
5301 .get(&buffer_id)
5302 .and_then(|buffer| buffer.upgrade(&cx))
5303 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))
5304 })?;
5305 let request = T::from_proto(
5306 envelope.payload,
5307 this.clone(),
5308 buffer_handle.clone(),
5309 cx.clone(),
5310 )
5311 .await?;
5312 let buffer_version = buffer_handle.read_with(&cx, |buffer, _| buffer.version());
5313 let response = this
5314 .update(&mut cx, |this, cx| {
5315 this.request_lsp(buffer_handle, request, cx)
5316 })
5317 .await?;
5318 this.update(&mut cx, |this, cx| {
5319 Ok(T::response_to_proto(
5320 response,
5321 this,
5322 sender_id,
5323 &buffer_version,
5324 cx,
5325 ))
5326 })
5327 }
5328
5329 async fn handle_get_project_symbols(
5330 this: ModelHandle<Self>,
5331 envelope: TypedEnvelope<proto::GetProjectSymbols>,
5332 _: Arc<Client>,
5333 mut cx: AsyncAppContext,
5334 ) -> Result<proto::GetProjectSymbolsResponse> {
5335 let symbols = this
5336 .update(&mut cx, |this, cx| {
5337 this.symbols(&envelope.payload.query, cx)
5338 })
5339 .await?;
5340
5341 Ok(proto::GetProjectSymbolsResponse {
5342 symbols: symbols.iter().map(serialize_symbol).collect(),
5343 })
5344 }
5345
5346 async fn handle_search_project(
5347 this: ModelHandle<Self>,
5348 envelope: TypedEnvelope<proto::SearchProject>,
5349 _: Arc<Client>,
5350 mut cx: AsyncAppContext,
5351 ) -> Result<proto::SearchProjectResponse> {
5352 let peer_id = envelope.original_sender_id()?;
5353 let query = SearchQuery::from_proto(envelope.payload)?;
5354 let result = this
5355 .update(&mut cx, |this, cx| this.search(query, cx))
5356 .await?;
5357
5358 this.update(&mut cx, |this, cx| {
5359 let mut locations = Vec::new();
5360 for (buffer, ranges) in result {
5361 for range in ranges {
5362 let start = serialize_anchor(&range.start);
5363 let end = serialize_anchor(&range.end);
5364 let buffer = this.serialize_buffer_for_peer(&buffer, peer_id, cx);
5365 locations.push(proto::Location {
5366 buffer: Some(buffer),
5367 start: Some(start),
5368 end: Some(end),
5369 });
5370 }
5371 }
5372 Ok(proto::SearchProjectResponse { locations })
5373 })
5374 }
5375
5376 async fn handle_open_buffer_for_symbol(
5377 this: ModelHandle<Self>,
5378 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
5379 _: Arc<Client>,
5380 mut cx: AsyncAppContext,
5381 ) -> Result<proto::OpenBufferForSymbolResponse> {
5382 let peer_id = envelope.original_sender_id()?;
5383 let symbol = envelope
5384 .payload
5385 .symbol
5386 .ok_or_else(|| anyhow!("invalid symbol"))?;
5387 let symbol = this.read_with(&cx, |this, _| {
5388 let symbol = this.deserialize_symbol(symbol)?;
5389 let signature = this.symbol_signature(symbol.worktree_id, &symbol.path);
5390 if signature == symbol.signature {
5391 Ok(symbol)
5392 } else {
5393 Err(anyhow!("invalid symbol signature"))
5394 }
5395 })?;
5396 let buffer = this
5397 .update(&mut cx, |this, cx| this.open_buffer_for_symbol(&symbol, cx))
5398 .await?;
5399
5400 Ok(proto::OpenBufferForSymbolResponse {
5401 buffer: Some(this.update(&mut cx, |this, cx| {
5402 this.serialize_buffer_for_peer(&buffer, peer_id, cx)
5403 })),
5404 })
5405 }
5406
5407 fn symbol_signature(&self, worktree_id: WorktreeId, path: &Path) -> [u8; 32] {
5408 let mut hasher = Sha256::new();
5409 hasher.update(worktree_id.to_proto().to_be_bytes());
5410 hasher.update(path.to_string_lossy().as_bytes());
5411 hasher.update(self.nonce.to_be_bytes());
5412 hasher.finalize().as_slice().try_into().unwrap()
5413 }
5414
5415 async fn handle_open_buffer_by_id(
5416 this: ModelHandle<Self>,
5417 envelope: TypedEnvelope<proto::OpenBufferById>,
5418 _: Arc<Client>,
5419 mut cx: AsyncAppContext,
5420 ) -> Result<proto::OpenBufferResponse> {
5421 let peer_id = envelope.original_sender_id()?;
5422 let buffer = this
5423 .update(&mut cx, |this, cx| {
5424 this.open_buffer_by_id(envelope.payload.id, cx)
5425 })
5426 .await?;
5427 this.update(&mut cx, |this, cx| {
5428 Ok(proto::OpenBufferResponse {
5429 buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
5430 })
5431 })
5432 }
5433
5434 async fn handle_open_buffer_by_path(
5435 this: ModelHandle<Self>,
5436 envelope: TypedEnvelope<proto::OpenBufferByPath>,
5437 _: Arc<Client>,
5438 mut cx: AsyncAppContext,
5439 ) -> Result<proto::OpenBufferResponse> {
5440 let peer_id = envelope.original_sender_id()?;
5441 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
5442 let open_buffer = this.update(&mut cx, |this, cx| {
5443 this.open_buffer(
5444 ProjectPath {
5445 worktree_id,
5446 path: PathBuf::from(envelope.payload.path).into(),
5447 },
5448 cx,
5449 )
5450 });
5451
5452 let buffer = open_buffer.await?;
5453 this.update(&mut cx, |this, cx| {
5454 Ok(proto::OpenBufferResponse {
5455 buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
5456 })
5457 })
5458 }
5459
5460 fn serialize_project_transaction_for_peer(
5461 &mut self,
5462 project_transaction: ProjectTransaction,
5463 peer_id: PeerId,
5464 cx: &AppContext,
5465 ) -> proto::ProjectTransaction {
5466 let mut serialized_transaction = proto::ProjectTransaction {
5467 buffers: Default::default(),
5468 transactions: Default::default(),
5469 };
5470 for (buffer, transaction) in project_transaction.0 {
5471 serialized_transaction
5472 .buffers
5473 .push(self.serialize_buffer_for_peer(&buffer, peer_id, cx));
5474 serialized_transaction
5475 .transactions
5476 .push(language::proto::serialize_transaction(&transaction));
5477 }
5478 serialized_transaction
5479 }
5480
5481 fn deserialize_project_transaction(
5482 &mut self,
5483 message: proto::ProjectTransaction,
5484 push_to_history: bool,
5485 cx: &mut ModelContext<Self>,
5486 ) -> Task<Result<ProjectTransaction>> {
5487 cx.spawn(|this, mut cx| async move {
5488 let mut project_transaction = ProjectTransaction::default();
5489 for (buffer, transaction) in message.buffers.into_iter().zip(message.transactions) {
5490 let buffer = this
5491 .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
5492 .await?;
5493 let transaction = language::proto::deserialize_transaction(transaction)?;
5494 project_transaction.0.insert(buffer, transaction);
5495 }
5496
5497 for (buffer, transaction) in &project_transaction.0 {
5498 buffer
5499 .update(&mut cx, |buffer, _| {
5500 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
5501 })
5502 .await;
5503
5504 if push_to_history {
5505 buffer.update(&mut cx, |buffer, _| {
5506 buffer.push_transaction(transaction.clone(), Instant::now());
5507 });
5508 }
5509 }
5510
5511 Ok(project_transaction)
5512 })
5513 }
5514
5515 fn serialize_buffer_for_peer(
5516 &mut self,
5517 buffer: &ModelHandle<Buffer>,
5518 peer_id: PeerId,
5519 cx: &AppContext,
5520 ) -> proto::Buffer {
5521 let buffer_id = buffer.read(cx).remote_id();
5522 let shared_buffers = self.shared_buffers.entry(peer_id).or_default();
5523 if shared_buffers.insert(buffer_id) {
5524 proto::Buffer {
5525 variant: Some(proto::buffer::Variant::State(buffer.read(cx).to_proto())),
5526 }
5527 } else {
5528 proto::Buffer {
5529 variant: Some(proto::buffer::Variant::Id(buffer_id)),
5530 }
5531 }
5532 }
5533
5534 fn deserialize_buffer(
5535 &mut self,
5536 buffer: proto::Buffer,
5537 cx: &mut ModelContext<Self>,
5538 ) -> Task<Result<ModelHandle<Buffer>>> {
5539 let replica_id = self.replica_id();
5540
5541 let opened_buffer_tx = self.opened_buffer.0.clone();
5542 let mut opened_buffer_rx = self.opened_buffer.1.clone();
5543 cx.spawn(|this, mut cx| async move {
5544 match buffer.variant.ok_or_else(|| anyhow!("missing buffer"))? {
5545 proto::buffer::Variant::Id(id) => {
5546 let buffer = loop {
5547 let buffer = this.read_with(&cx, |this, cx| {
5548 this.opened_buffers
5549 .get(&id)
5550 .and_then(|buffer| buffer.upgrade(cx))
5551 });
5552 if let Some(buffer) = buffer {
5553 break buffer;
5554 }
5555 opened_buffer_rx
5556 .next()
5557 .await
5558 .ok_or_else(|| anyhow!("project dropped while waiting for buffer"))?;
5559 };
5560 Ok(buffer)
5561 }
5562 proto::buffer::Variant::State(mut buffer) => {
5563 let mut buffer_worktree = None;
5564 let mut buffer_file = None;
5565 if let Some(file) = buffer.file.take() {
5566 this.read_with(&cx, |this, cx| {
5567 let worktree_id = WorktreeId::from_proto(file.worktree_id);
5568 let worktree =
5569 this.worktree_for_id(worktree_id, cx).ok_or_else(|| {
5570 anyhow!("no worktree found for id {}", file.worktree_id)
5571 })?;
5572 buffer_file =
5573 Some(Arc::new(File::from_proto(file, worktree.clone(), cx)?)
5574 as Arc<dyn language::File>);
5575 buffer_worktree = Some(worktree);
5576 Ok::<_, anyhow::Error>(())
5577 })?;
5578 }
5579
5580 let buffer = cx.add_model(|cx| {
5581 Buffer::from_proto(replica_id, buffer, buffer_file, cx).unwrap()
5582 });
5583
5584 this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
5585
5586 *opened_buffer_tx.borrow_mut().borrow_mut() = ();
5587 Ok(buffer)
5588 }
5589 }
5590 })
5591 }
5592
5593 fn deserialize_symbol(&self, serialized_symbol: proto::Symbol) -> Result<Symbol> {
5594 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
5595 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
5596 let start = serialized_symbol
5597 .start
5598 .ok_or_else(|| anyhow!("invalid start"))?;
5599 let end = serialized_symbol
5600 .end
5601 .ok_or_else(|| anyhow!("invalid end"))?;
5602 let kind = unsafe { mem::transmute(serialized_symbol.kind) };
5603 let path = PathBuf::from(serialized_symbol.path);
5604 let language = self.languages.select_language(&path);
5605 Ok(Symbol {
5606 source_worktree_id,
5607 worktree_id,
5608 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
5609 label: language
5610 .and_then(|language| language.label_for_symbol(&serialized_symbol.name, kind))
5611 .unwrap_or_else(|| CodeLabel::plain(serialized_symbol.name.clone(), None)),
5612 name: serialized_symbol.name,
5613 path,
5614 range: PointUtf16::new(start.row, start.column)..PointUtf16::new(end.row, end.column),
5615 kind,
5616 signature: serialized_symbol
5617 .signature
5618 .try_into()
5619 .map_err(|_| anyhow!("invalid signature"))?,
5620 })
5621 }
5622
5623 async fn handle_buffer_saved(
5624 this: ModelHandle<Self>,
5625 envelope: TypedEnvelope<proto::BufferSaved>,
5626 _: Arc<Client>,
5627 mut cx: AsyncAppContext,
5628 ) -> Result<()> {
5629 let version = deserialize_version(envelope.payload.version);
5630 let mtime = envelope
5631 .payload
5632 .mtime
5633 .ok_or_else(|| anyhow!("missing mtime"))?
5634 .into();
5635
5636 this.update(&mut cx, |this, cx| {
5637 let buffer = this
5638 .opened_buffers
5639 .get(&envelope.payload.buffer_id)
5640 .and_then(|buffer| buffer.upgrade(cx));
5641 if let Some(buffer) = buffer {
5642 buffer.update(cx, |buffer, cx| {
5643 buffer.did_save(version, envelope.payload.fingerprint, mtime, None, cx);
5644 });
5645 }
5646 Ok(())
5647 })
5648 }
5649
5650 async fn handle_buffer_reloaded(
5651 this: ModelHandle<Self>,
5652 envelope: TypedEnvelope<proto::BufferReloaded>,
5653 _: Arc<Client>,
5654 mut cx: AsyncAppContext,
5655 ) -> Result<()> {
5656 let payload = envelope.payload;
5657 let version = deserialize_version(payload.version);
5658 let line_ending = deserialize_line_ending(
5659 proto::LineEnding::from_i32(payload.line_ending)
5660 .ok_or_else(|| anyhow!("missing line ending"))?,
5661 );
5662 let mtime = payload
5663 .mtime
5664 .ok_or_else(|| anyhow!("missing mtime"))?
5665 .into();
5666 this.update(&mut cx, |this, cx| {
5667 let buffer = this
5668 .opened_buffers
5669 .get(&payload.buffer_id)
5670 .and_then(|buffer| buffer.upgrade(cx));
5671 if let Some(buffer) = buffer {
5672 buffer.update(cx, |buffer, cx| {
5673 buffer.did_reload(version, payload.fingerprint, line_ending, mtime, cx);
5674 });
5675 }
5676 Ok(())
5677 })
5678 }
5679
5680 fn edits_from_lsp(
5681 &mut self,
5682 buffer: &ModelHandle<Buffer>,
5683 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
5684 version: Option<i32>,
5685 cx: &mut ModelContext<Self>,
5686 ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
5687 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx);
5688 cx.background().spawn(async move {
5689 let snapshot = snapshot?;
5690 let mut lsp_edits = lsp_edits
5691 .into_iter()
5692 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
5693 .collect::<Vec<_>>();
5694 lsp_edits.sort_by_key(|(range, _)| range.start);
5695
5696 let mut lsp_edits = lsp_edits.into_iter().peekable();
5697 let mut edits = Vec::new();
5698 while let Some((mut range, mut new_text)) = lsp_edits.next() {
5699 // Combine any LSP edits that are adjacent.
5700 //
5701 // Also, combine LSP edits that are separated from each other by only
5702 // a newline. This is important because for some code actions,
5703 // Rust-analyzer rewrites the entire buffer via a series of edits that
5704 // are separated by unchanged newline characters.
5705 //
5706 // In order for the diffing logic below to work properly, any edits that
5707 // cancel each other out must be combined into one.
5708 while let Some((next_range, next_text)) = lsp_edits.peek() {
5709 if next_range.start > range.end {
5710 if next_range.start.row > range.end.row + 1
5711 || next_range.start.column > 0
5712 || snapshot.clip_point_utf16(
5713 PointUtf16::new(range.end.row, u32::MAX),
5714 Bias::Left,
5715 ) > range.end
5716 {
5717 break;
5718 }
5719 new_text.push('\n');
5720 }
5721 range.end = next_range.end;
5722 new_text.push_str(&next_text);
5723 lsp_edits.next();
5724 }
5725
5726 if snapshot.clip_point_utf16(range.start, Bias::Left) != range.start
5727 || snapshot.clip_point_utf16(range.end, Bias::Left) != range.end
5728 {
5729 return Err(anyhow!("invalid edits received from language server"));
5730 }
5731
5732 // For multiline edits, perform a diff of the old and new text so that
5733 // we can identify the changes more precisely, preserving the locations
5734 // of any anchors positioned in the unchanged regions.
5735 if range.end.row > range.start.row {
5736 let mut offset = range.start.to_offset(&snapshot);
5737 let old_text = snapshot.text_for_range(range).collect::<String>();
5738
5739 let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
5740 let mut moved_since_edit = true;
5741 for change in diff.iter_all_changes() {
5742 let tag = change.tag();
5743 let value = change.value();
5744 match tag {
5745 ChangeTag::Equal => {
5746 offset += value.len();
5747 moved_since_edit = true;
5748 }
5749 ChangeTag::Delete => {
5750 let start = snapshot.anchor_after(offset);
5751 let end = snapshot.anchor_before(offset + value.len());
5752 if moved_since_edit {
5753 edits.push((start..end, String::new()));
5754 } else {
5755 edits.last_mut().unwrap().0.end = end;
5756 }
5757 offset += value.len();
5758 moved_since_edit = false;
5759 }
5760 ChangeTag::Insert => {
5761 if moved_since_edit {
5762 let anchor = snapshot.anchor_after(offset);
5763 edits.push((anchor.clone()..anchor, value.to_string()));
5764 } else {
5765 edits.last_mut().unwrap().1.push_str(value);
5766 }
5767 moved_since_edit = false;
5768 }
5769 }
5770 }
5771 } else if range.end == range.start {
5772 let anchor = snapshot.anchor_after(range.start);
5773 edits.push((anchor.clone()..anchor, new_text));
5774 } else {
5775 let edit_start = snapshot.anchor_after(range.start);
5776 let edit_end = snapshot.anchor_before(range.end);
5777 edits.push((edit_start..edit_end, new_text));
5778 }
5779 }
5780
5781 Ok(edits)
5782 })
5783 }
5784
5785 fn buffer_snapshot_for_lsp_version(
5786 &mut self,
5787 buffer: &ModelHandle<Buffer>,
5788 version: Option<i32>,
5789 cx: &AppContext,
5790 ) -> Result<TextBufferSnapshot> {
5791 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
5792
5793 if let Some(version) = version {
5794 let buffer_id = buffer.read(cx).remote_id();
5795 let snapshots = self
5796 .buffer_snapshots
5797 .get_mut(&buffer_id)
5798 .ok_or_else(|| anyhow!("no snapshot found for buffer {}", buffer_id))?;
5799 let mut found_snapshot = None;
5800 snapshots.retain(|(snapshot_version, snapshot)| {
5801 if snapshot_version + OLD_VERSIONS_TO_RETAIN < version {
5802 false
5803 } else {
5804 if *snapshot_version == version {
5805 found_snapshot = Some(snapshot.clone());
5806 }
5807 true
5808 }
5809 });
5810
5811 found_snapshot.ok_or_else(|| {
5812 anyhow!(
5813 "snapshot not found for buffer {} at version {}",
5814 buffer_id,
5815 version
5816 )
5817 })
5818 } else {
5819 Ok((buffer.read(cx)).text_snapshot())
5820 }
5821 }
5822
5823 fn language_server_for_buffer(
5824 &self,
5825 buffer: &Buffer,
5826 cx: &AppContext,
5827 ) -> Option<(&Arc<dyn LspAdapter>, &Arc<LanguageServer>)> {
5828 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
5829 let worktree_id = file.worktree_id(cx);
5830 let key = (worktree_id, language.lsp_adapter()?.name());
5831
5832 if let Some(server_id) = self.language_server_ids.get(&key) {
5833 if let Some(LanguageServerState::Running { adapter, server }) =
5834 self.language_servers.get(&server_id)
5835 {
5836 return Some((adapter, server));
5837 }
5838 }
5839 }
5840
5841 None
5842 }
5843}
5844
5845impl ProjectStore {
5846 pub fn new(db: Arc<Db>) -> Self {
5847 Self {
5848 db,
5849 projects: Default::default(),
5850 }
5851 }
5852
5853 pub fn projects<'a>(
5854 &'a self,
5855 cx: &'a AppContext,
5856 ) -> impl 'a + Iterator<Item = ModelHandle<Project>> {
5857 self.projects
5858 .iter()
5859 .filter_map(|project| project.upgrade(cx))
5860 }
5861
5862 fn add_project(&mut self, project: WeakModelHandle<Project>, cx: &mut ModelContext<Self>) {
5863 if let Err(ix) = self
5864 .projects
5865 .binary_search_by_key(&project.id(), WeakModelHandle::id)
5866 {
5867 self.projects.insert(ix, project);
5868 }
5869 cx.notify();
5870 }
5871
5872 fn prune_projects(&mut self, cx: &mut ModelContext<Self>) {
5873 let mut did_change = false;
5874 self.projects.retain(|project| {
5875 if project.is_upgradable(cx) {
5876 true
5877 } else {
5878 did_change = true;
5879 false
5880 }
5881 });
5882 if did_change {
5883 cx.notify();
5884 }
5885 }
5886}
5887
5888impl WorktreeHandle {
5889 pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
5890 match self {
5891 WorktreeHandle::Strong(handle) => Some(handle.clone()),
5892 WorktreeHandle::Weak(handle) => handle.upgrade(cx),
5893 }
5894 }
5895}
5896
5897impl OpenBuffer {
5898 pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<Buffer>> {
5899 match self {
5900 OpenBuffer::Strong(handle) => Some(handle.clone()),
5901 OpenBuffer::Weak(handle) => handle.upgrade(cx),
5902 OpenBuffer::Loading(_) => None,
5903 }
5904 }
5905}
5906
5907pub struct PathMatchCandidateSet {
5908 pub snapshot: Snapshot,
5909 pub include_ignored: bool,
5910 pub include_root_name: bool,
5911}
5912
5913impl<'a> fuzzy::PathMatchCandidateSet<'a> for PathMatchCandidateSet {
5914 type Candidates = PathMatchCandidateSetIter<'a>;
5915
5916 fn id(&self) -> usize {
5917 self.snapshot.id().to_usize()
5918 }
5919
5920 fn len(&self) -> usize {
5921 if self.include_ignored {
5922 self.snapshot.file_count()
5923 } else {
5924 self.snapshot.visible_file_count()
5925 }
5926 }
5927
5928 fn prefix(&self) -> Arc<str> {
5929 if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
5930 self.snapshot.root_name().into()
5931 } else if self.include_root_name {
5932 format!("{}/", self.snapshot.root_name()).into()
5933 } else {
5934 "".into()
5935 }
5936 }
5937
5938 fn candidates(&'a self, start: usize) -> Self::Candidates {
5939 PathMatchCandidateSetIter {
5940 traversal: self.snapshot.files(self.include_ignored, start),
5941 }
5942 }
5943}
5944
5945pub struct PathMatchCandidateSetIter<'a> {
5946 traversal: Traversal<'a>,
5947}
5948
5949impl<'a> Iterator for PathMatchCandidateSetIter<'a> {
5950 type Item = fuzzy::PathMatchCandidate<'a>;
5951
5952 fn next(&mut self) -> Option<Self::Item> {
5953 self.traversal.next().map(|entry| {
5954 if let EntryKind::File(char_bag) = entry.kind {
5955 fuzzy::PathMatchCandidate {
5956 path: &entry.path,
5957 char_bag,
5958 }
5959 } else {
5960 unreachable!()
5961 }
5962 })
5963 }
5964}
5965
5966impl Entity for ProjectStore {
5967 type Event = ();
5968}
5969
5970impl Entity for Project {
5971 type Event = Event;
5972
5973 fn release(&mut self, cx: &mut gpui::MutableAppContext) {
5974 self.project_store.update(cx, ProjectStore::prune_projects);
5975
5976 match &self.client_state {
5977 ProjectClientState::Local { remote_id_rx, .. } => {
5978 if let Some(project_id) = *remote_id_rx.borrow() {
5979 self.client
5980 .send(proto::UnregisterProject { project_id })
5981 .log_err();
5982 }
5983 }
5984 ProjectClientState::Remote { remote_id, .. } => {
5985 self.client
5986 .send(proto::LeaveProject {
5987 project_id: *remote_id,
5988 })
5989 .log_err();
5990 }
5991 }
5992 }
5993
5994 fn app_will_quit(
5995 &mut self,
5996 _: &mut MutableAppContext,
5997 ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
5998 let shutdown_futures = self
5999 .language_servers
6000 .drain()
6001 .map(|(_, server_state)| async {
6002 match server_state {
6003 LanguageServerState::Running { server, .. } => server.shutdown()?.await,
6004 LanguageServerState::Starting(starting_server) => {
6005 starting_server.await?.shutdown()?.await
6006 }
6007 }
6008 })
6009 .collect::<Vec<_>>();
6010
6011 Some(
6012 async move {
6013 futures::future::join_all(shutdown_futures).await;
6014 }
6015 .boxed(),
6016 )
6017 }
6018}
6019
6020impl Collaborator {
6021 fn from_proto(
6022 message: proto::Collaborator,
6023 user_store: &ModelHandle<UserStore>,
6024 cx: &mut AsyncAppContext,
6025 ) -> impl Future<Output = Result<Self>> {
6026 let user = user_store.update(cx, |user_store, cx| {
6027 user_store.fetch_user(message.user_id, cx)
6028 });
6029
6030 async move {
6031 Ok(Self {
6032 peer_id: PeerId(message.peer_id),
6033 user: user.await?,
6034 replica_id: message.replica_id as ReplicaId,
6035 })
6036 }
6037 }
6038}
6039
6040impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
6041 fn from((worktree_id, path): (WorktreeId, P)) -> Self {
6042 Self {
6043 worktree_id,
6044 path: path.as_ref().into(),
6045 }
6046 }
6047}
6048
6049impl From<lsp::CreateFileOptions> for fs::CreateOptions {
6050 fn from(options: lsp::CreateFileOptions) -> Self {
6051 Self {
6052 overwrite: options.overwrite.unwrap_or(false),
6053 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6054 }
6055 }
6056}
6057
6058impl From<lsp::RenameFileOptions> for fs::RenameOptions {
6059 fn from(options: lsp::RenameFileOptions) -> Self {
6060 Self {
6061 overwrite: options.overwrite.unwrap_or(false),
6062 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6063 }
6064 }
6065}
6066
6067impl From<lsp::DeleteFileOptions> for fs::RemoveOptions {
6068 fn from(options: lsp::DeleteFileOptions) -> Self {
6069 Self {
6070 recursive: options.recursive.unwrap_or(false),
6071 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
6072 }
6073 }
6074}
6075
6076fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
6077 proto::Symbol {
6078 source_worktree_id: symbol.source_worktree_id.to_proto(),
6079 worktree_id: symbol.worktree_id.to_proto(),
6080 language_server_name: symbol.language_server_name.0.to_string(),
6081 name: symbol.name.clone(),
6082 kind: unsafe { mem::transmute(symbol.kind) },
6083 path: symbol.path.to_string_lossy().to_string(),
6084 start: Some(proto::Point {
6085 row: symbol.range.start.row,
6086 column: symbol.range.start.column,
6087 }),
6088 end: Some(proto::Point {
6089 row: symbol.range.end.row,
6090 column: symbol.range.end.column,
6091 }),
6092 signature: symbol.signature.to_vec(),
6093 }
6094}
6095
6096fn relativize_path(base: &Path, path: &Path) -> PathBuf {
6097 let mut path_components = path.components();
6098 let mut base_components = base.components();
6099 let mut components: Vec<Component> = Vec::new();
6100 loop {
6101 match (path_components.next(), base_components.next()) {
6102 (None, None) => break,
6103 (Some(a), None) => {
6104 components.push(a);
6105 components.extend(path_components.by_ref());
6106 break;
6107 }
6108 (None, _) => components.push(Component::ParentDir),
6109 (Some(a), Some(b)) if components.is_empty() && a == b => (),
6110 (Some(a), Some(b)) if b == Component::CurDir => components.push(a),
6111 (Some(a), Some(_)) => {
6112 components.push(Component::ParentDir);
6113 for _ in base_components {
6114 components.push(Component::ParentDir);
6115 }
6116 components.push(a);
6117 components.extend(path_components.by_ref());
6118 break;
6119 }
6120 }
6121 }
6122 components.iter().map(|c| c.as_os_str()).collect()
6123}
6124
6125impl Item for Buffer {
6126 fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId> {
6127 File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
6128 }
6129}