Welcome screen with recent repositories and a folder picker when gites starts outside a repository
This commit is contained in:
+43
-1
@@ -1,5 +1,5 @@
|
||||
use serde::Serialize;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -130,3 +130,45 @@ pub fn load(dir: &Path) -> Result<RepoData, String> {
|
||||
|
||||
Ok(RepoData { root, commits, refs, head_ref, head })
|
||||
}
|
||||
|
||||
/// The repository to open at start: the path given on the command line, or else the
|
||||
/// current folder if it is inside a repository. `None` means gites starts with its
|
||||
/// welcome screen. A path given on the command line is used even if it is not a
|
||||
/// repository, so the window can say what is wrong with it.
|
||||
pub fn start_dir(arg: Option<PathBuf>, cwd: PathBuf) -> Option<PathBuf> {
|
||||
arg.or_else(|| git(&cwd, &["rev-parse", "--git-dir"]).ok().map(|_| cwd))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn temp_dir(name: &str) -> PathBuf {
|
||||
let dir = std::env::temp_dir().join(format!("gites-start-{name}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
dir
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opens_the_path_given_on_the_command_line_even_if_it_is_not_a_repository() {
|
||||
let given = PathBuf::from("/no/such/folder");
|
||||
assert_eq!(start_dir(Some(given.clone()), temp_dir("arg")), Some(given));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opens_the_current_folder_when_it_is_inside_a_repository() {
|
||||
let dir = temp_dir("repo");
|
||||
git(&dir, &["init", "-q"]).unwrap();
|
||||
std::fs::create_dir_all(dir.join("sub")).unwrap();
|
||||
assert_eq!(start_dir(None, dir.join("sub")), Some(dir.join("sub")));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opens_nothing_when_the_current_folder_is_not_in_a_repository() {
|
||||
let dir = temp_dir("plain");
|
||||
assert_eq!(start_dir(None, dir.clone()), None);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-14
@@ -7,32 +7,36 @@ mod settings;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// The open repository folder. It starts as the first command line argument, or the
|
||||
/// current folder, and changes when the user opens another one.
|
||||
struct RepoDir(Mutex<PathBuf>);
|
||||
/// The open repository folder, from `git::start_dir`; it changes when the user opens
|
||||
/// another one. `None` until a repository is open: the window shows its welcome screen.
|
||||
struct RepoDir(Mutex<Option<PathBuf>>);
|
||||
|
||||
impl RepoDir {
|
||||
fn get(&self) -> PathBuf {
|
||||
self.0.lock().unwrap_or_else(|e| e.into_inner()).clone()
|
||||
fn get(&self) -> Result<PathBuf, String> {
|
||||
self.0.lock().unwrap_or_else(|e| e.into_inner()).clone().ok_or_else(|| "no repository is open".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// The open repository, or `None` when there is none yet.
|
||||
#[tauri::command]
|
||||
fn load_repo(dir: tauri::State<RepoDir>) -> Result<git::RepoData, String> {
|
||||
git::load(&dir.get())
|
||||
fn load_repo(dir: tauri::State<RepoDir>) -> Result<Option<git::RepoData>, String> {
|
||||
match dir.get() {
|
||||
Ok(d) => git::load(&d).map(Some),
|
||||
Err(_) => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Switches to another repository. The current one stays open if `path` is not a repository.
|
||||
#[tauri::command]
|
||||
fn open_repo(dir: tauri::State<RepoDir>, path: String) -> Result<git::RepoData, String> {
|
||||
let data = git::load(&PathBuf::from(&path))?;
|
||||
*dir.0.lock().unwrap_or_else(|e| e.into_inner()) = PathBuf::from(&path);
|
||||
*dir.0.lock().unwrap_or_else(|e| e.into_inner()) = Some(PathBuf::from(&path));
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn commit_details(dir: tauri::State<RepoDir>, hash: String) -> Result<details::CommitDetails, String> {
|
||||
details::load(&dir.get(), &hash)
|
||||
details::load(&dir.get()?, &hash)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -43,7 +47,7 @@ fn file_diff(
|
||||
old_path: Option<String>,
|
||||
force: bool,
|
||||
) -> Result<diff::FileDiff, String> {
|
||||
diff::load(&dir.get(), &hash, &path, old_path.as_deref(), force)
|
||||
diff::load(&dir.get()?, &hash, &path, old_path.as_deref(), force)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -68,10 +72,9 @@ fn save_settings(value: serde_json::Value) -> Result<(), String> {
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let path = std::env::args_os()
|
||||
.nth(1)
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
|
||||
let arg = std::env::args_os().nth(1).map(PathBuf::from);
|
||||
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
|
||||
let path = git::start_dir(arg, cwd);
|
||||
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
|
||||
Reference in New Issue
Block a user