jj: improve initialization process

This commit is contained in:
akar1ngo 2025-08-23 06:54:47 +00:00
parent 19764794b7
commit a83c935d7c
No known key found for this signature in database
5 changed files with 106 additions and 19 deletions

2
Cargo.lock generated
View file

@ -8724,7 +8724,9 @@ dependencies = [
"anyhow",
"gpui",
"jj-lib",
"project",
"workspace-hack",
"worktree",
]
[[package]]

View file

@ -15,4 +15,6 @@ path = "src/jj.rs"
anyhow.workspace = true
gpui.workspace = true
jj-lib.workspace = true
project.workspace = true
workspace-hack.workspace = true
worktree.workspace = true

View file

@ -1,7 +1,9 @@
use std::path::Path;
use std::collections::HashMap;
use std::sync::Arc;
use gpui::{App, Entity, Global, prelude::*};
use gpui::{App, Context, Entity, EventEmitter, Global, Subscription, prelude::*};
use project::worktree_store::{WorktreeStore, WorktreeStoreEvent};
use worktree::{Worktree, WorktreeId};
use crate::{JujutsuRepository, RealJujutsuRepository};
@ -11,18 +13,22 @@ struct GlobalJujutsuStore(Entity<JujutsuStore>);
impl Global for GlobalJujutsuStore {}
pub struct JujutsuStore {
repository: Arc<dyn JujutsuRepository>,
active_repository: Option<WorktreeId>,
repositories: HashMap<WorktreeId, Arc<dyn JujutsuRepository>>,
_subscriptions: Vec<Subscription>,
}
pub enum JujutsuStoreEvent {
ActiveRepositoryChanged(Option<WorktreeId>),
RepositoryAdded(WorktreeId),
RepositoryRemoved(WorktreeId),
}
impl EventEmitter<JujutsuStoreEvent> for JujutsuStore {}
impl JujutsuStore {
pub fn init_global(cx: &mut App) {
let Some(repository) = RealJujutsuRepository::new(Path::new(".")).ok() else {
return;
};
let repository = Arc::new(repository);
let jj_store = cx.new(|cx| JujutsuStore::new(repository, cx));
pub fn init_global(cx: &mut App, worktree_store: Entity<WorktreeStore>) {
let jj_store = cx.new(|cx| JujutsuStore::new(worktree_store, cx));
cx.set_global(GlobalJujutsuStore(jj_store));
}
@ -31,11 +37,84 @@ impl JujutsuStore {
.map(|global| global.0.clone())
}
pub fn new(repository: Arc<dyn JujutsuRepository>, _cx: &mut Context<Self>) -> Self {
Self { repository }
pub fn new(worktree_store: Entity<WorktreeStore>, cx: &mut Context<Self>) -> Self {
let _subscriptions = vec![cx.subscribe(&worktree_store, Self::on_worktree_store_event)];
let mut store = JujutsuStore {
active_repository: None,
repositories: HashMap::default(),
_subscriptions,
};
let existing_worktrees: Vec<_> = worktree_store.read(cx).worktrees().collect();
for worktree in existing_worktrees {
store.scan_worktree_for_jj_repo(&worktree, cx);
}
store
}
pub fn repository(&self) -> &Arc<dyn JujutsuRepository> {
&self.repository
fn on_worktree_store_event(
&mut self,
_worktree_store: Entity<WorktreeStore>,
event: &WorktreeStoreEvent,
cx: &mut Context<Self>,
) {
match event {
WorktreeStoreEvent::WorktreeAdded(worktree) => {
self.scan_worktree_for_jj_repo(worktree, cx);
}
WorktreeStoreEvent::WorktreeRemoved(_, worktree_id) => {
if self.repositories.remove(worktree_id).is_some() {
cx.emit(JujutsuStoreEvent::RepositoryRemoved(*worktree_id));
if self.active_repository == Some(*worktree_id) {
self.active_repository = None;
cx.emit(JujutsuStoreEvent::ActiveRepositoryChanged(None));
}
}
}
_ => {}
}
}
fn scan_worktree_for_jj_repo(&mut self, worktree: &Entity<Worktree>, cx: &mut Context<Self>) {
let worktree = worktree.read(cx);
let worktree_id = worktree.id();
let root_path = worktree.abs_path();
match RealJujutsuRepository::new(&root_path) {
Ok(repository) => {
let repository = Arc::new(repository);
self.repositories.insert(worktree_id, repository);
cx.emit(JujutsuStoreEvent::RepositoryAdded(worktree_id));
if self.active_repository.is_none() {
self.active_repository = Some(worktree_id);
cx.emit(JujutsuStoreEvent::ActiveRepositoryChanged(Some(
worktree_id,
)));
}
}
Err(_) => {}
}
}
pub fn repository_for_worktree(
&self,
worktree_id: WorktreeId,
) -> Option<&Arc<dyn JujutsuRepository>> {
self.repositories.get(&worktree_id)
}
pub fn active_repository(&self) -> Option<&Arc<dyn JujutsuRepository>> {
self.active_repository
.and_then(|id| self.repositories.get(&id))
}
pub fn repository(&self) -> Option<&Arc<dyn JujutsuRepository>> {
self.active_repository()
}
}

View file

@ -81,7 +81,11 @@ impl BookmarkPickerDelegate {
jj_store: Entity<JujutsuStore>,
cx: &mut Context<BookmarkPicker>,
) -> Self {
let bookmarks = jj_store.read(cx).repository().list_bookmarks();
let bookmarks = jj_store
.read(cx)
.repository()
.map(|repo| repo.list_bookmarks())
.unwrap_or_default();
Self {
picker,

View file

@ -7,9 +7,9 @@ use jj::JujutsuStore;
use workspace::Workspace;
pub fn init(cx: &mut App) {
JujutsuStore::init_global(cx);
cx.observe_new(|workspace: &mut Workspace, _window, _cx| {
cx.observe_new(|workspace: &mut Workspace, _window, cx| {
let worktree_store = workspace.project().read(cx).worktree_store();
JujutsuStore::init_global(cx, worktree_store);
bookmark_picker::register(workspace);
})
.detach();