Add a picker for jj bookmark list
(#30883)
This PR adds a new picker for viewing a list of jj bookmarks, like you would with `jj bookmark list`. This is an exploration around what it would look like to begin adding some dedicated jj features to Zed. This is behind the `jj-ui` feature flag. Release Notes: - N/A
This commit is contained in:
parent
122d6c9e4d
commit
dd3956eaf1
16 changed files with 1644 additions and 152 deletions
18
crates/jj/Cargo.toml
Normal file
18
crates/jj/Cargo.toml
Normal file
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "jj"
|
||||
version = "0.1.0"
|
||||
publish.workspace = true
|
||||
edition.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/jj.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
gpui.workspace = true
|
||||
jj-lib.workspace = true
|
||||
workspace-hack.workspace = true
|
1
crates/jj/LICENSE-GPL
Symbolic link
1
crates/jj/LICENSE-GPL
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE-GPL
|
5
crates/jj/src/jj.rs
Normal file
5
crates/jj/src/jj.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod jj_repository;
|
||||
mod jj_store;
|
||||
|
||||
pub use jj_repository::*;
|
||||
pub use jj_store::*;
|
72
crates/jj/src/jj_repository.rs
Normal file
72
crates/jj/src/jj_repository.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use gpui::SharedString;
|
||||
use jj_lib::config::StackedConfig;
|
||||
use jj_lib::repo::StoreFactories;
|
||||
use jj_lib::settings::UserSettings;
|
||||
use jj_lib::workspace::{self, DefaultWorkspaceLoaderFactory, WorkspaceLoaderFactory};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Bookmark {
|
||||
pub ref_name: SharedString,
|
||||
}
|
||||
|
||||
pub trait JujutsuRepository: Send + Sync {
|
||||
fn list_bookmarks(&self) -> Vec<Bookmark>;
|
||||
}
|
||||
|
||||
pub struct RealJujutsuRepository {
|
||||
repository: Arc<jj_lib::repo::ReadonlyRepo>,
|
||||
}
|
||||
|
||||
impl RealJujutsuRepository {
|
||||
pub fn new(cwd: &Path) -> Result<Self> {
|
||||
let workspace_loader_factory = DefaultWorkspaceLoaderFactory;
|
||||
let workspace_loader = workspace_loader_factory.create(Self::find_workspace_dir(cwd))?;
|
||||
|
||||
let config = StackedConfig::with_defaults();
|
||||
let settings = UserSettings::from_config(config)?;
|
||||
|
||||
let workspace = workspace_loader.load(
|
||||
&settings,
|
||||
&StoreFactories::default(),
|
||||
&workspace::default_working_copy_factories(),
|
||||
)?;
|
||||
|
||||
let repo_loader = workspace.repo_loader();
|
||||
let repository = repo_loader.load_at_head()?;
|
||||
|
||||
Ok(Self { repository })
|
||||
}
|
||||
|
||||
fn find_workspace_dir(cwd: &Path) -> &Path {
|
||||
cwd.ancestors()
|
||||
.find(|path| path.join(".jj").is_dir())
|
||||
.unwrap_or(cwd)
|
||||
}
|
||||
}
|
||||
|
||||
impl JujutsuRepository for RealJujutsuRepository {
|
||||
fn list_bookmarks(&self) -> Vec<Bookmark> {
|
||||
let bookmarks = self
|
||||
.repository
|
||||
.view()
|
||||
.bookmarks()
|
||||
.map(|(ref_name, _target)| Bookmark {
|
||||
ref_name: ref_name.as_str().to_string().into(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
bookmarks
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FakeJujutsuRepository {}
|
||||
|
||||
impl JujutsuRepository for FakeJujutsuRepository {
|
||||
fn list_bookmarks(&self) -> Vec<Bookmark> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
41
crates/jj/src/jj_store.rs
Normal file
41
crates/jj/src/jj_store.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use gpui::{App, Entity, Global, prelude::*};
|
||||
|
||||
use crate::{JujutsuRepository, RealJujutsuRepository};
|
||||
|
||||
/// Note: We won't ultimately be storing the jj store in a global, we're just doing this for exploration purposes.
|
||||
struct GlobalJujutsuStore(Entity<JujutsuStore>);
|
||||
|
||||
impl Global for GlobalJujutsuStore {}
|
||||
|
||||
pub struct JujutsuStore {
|
||||
repository: Arc<dyn JujutsuRepository>,
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
cx.set_global(GlobalJujutsuStore(jj_store));
|
||||
}
|
||||
|
||||
pub fn try_global(cx: &App) -> Option<Entity<Self>> {
|
||||
cx.try_global::<GlobalJujutsuStore>()
|
||||
.map(|global| global.0.clone())
|
||||
}
|
||||
|
||||
pub fn new(repository: Arc<dyn JujutsuRepository>, _cx: &mut Context<Self>) -> Self {
|
||||
Self { repository }
|
||||
}
|
||||
|
||||
pub fn repository(&self) -> &Arc<dyn JujutsuRepository> {
|
||||
&self.repository
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue