aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@elliehuxtable.com>2023-07-14 20:58:20 +0100
committerGitHub <noreply@github.com>2023-07-14 19:58:20 +0000
commit465faca6d1255cb630de00e374a1675be25aa547 (patch)
treee8977ac6c11fadceb2a7140bafd42bafca353c37
parentDelete the count cache row when a user is deleted (#1103) (diff)
downloadatuin-465faca6d1255cb630de00e374a1675be25aa547.zip
Add workspace mode, enable if in git repo (#1053)
* Add workspace mode, enable if in git repo * Fix tests * Should now be good * Page filter modes correctly if in workspace
-rw-r--r--atuin-client/src/database.rs19
-rw-r--r--atuin-client/src/settings.rs6
-rw-r--r--atuin-common/src/utils.rs25
-rw-r--r--atuin/src/command/client/search.rs11
-rw-r--r--atuin/src/command/client/search/interactive.rs34
-rw-r--r--atuin/src/command/client/stats.rs1
6 files changed, 83 insertions, 13 deletions
diff --git a/atuin-client/src/database.rs b/atuin-client/src/database.rs
index 218c1d6e..e37eb2b8 100644
--- a/atuin-client/src/database.rs
+++ b/atuin-client/src/database.rs
@@ -1,4 +1,8 @@
-use std::{env, path::Path, str::FromStr};
+use std::{
+ env,
+ path::{Path, PathBuf},
+ str::FromStr,
+};
use async_trait::async_trait;
use atuin_common::utils;
@@ -25,6 +29,7 @@ pub struct Context {
pub cwd: String,
pub hostname: String,
pub host_id: String,
+ pub git_root: Option<PathBuf>,
}
#[derive(Default, Clone)]
@@ -52,11 +57,13 @@ pub fn current_context() -> Context {
);
let cwd = utils::get_current_dir();
let host_id = Settings::host_id().expect("failed to load host ID");
+ let git_root = utils::in_git_repo(cwd.as_str());
Context {
session,
hostname,
cwd,
+ git_root,
host_id: host_id.0.as_simple().to_string(),
}
}
@@ -261,6 +268,7 @@ impl Database for Sqlite {
FilterMode::Host => query.and_where_eq("hostname", quote(&context.hostname)),
FilterMode::Session => query.and_where_eq("session", quote(&context.session)),
FilterMode::Directory => query.and_where_eq("cwd", quote(&context.cwd)),
+ FilterMode::Workspace => query.and_where_like_any("cwd", context.cwd.clone()),
};
if unique {
@@ -380,11 +388,18 @@ impl Database for Sqlite {
sql.order_desc("timestamp");
}
+ let git_root = if let Some(git_root) = context.git_root.clone() {
+ git_root.to_str().unwrap_or("/").to_string()
+ } else {
+ context.cwd.clone()
+ };
+
match filter {
FilterMode::Global => &mut sql,
FilterMode::Host => sql.and_where_eq("hostname", quote(&context.hostname)),
FilterMode::Session => sql.and_where_eq("session", quote(&context.session)),
FilterMode::Directory => sql.and_where_eq("cwd", quote(&context.cwd)),
+ FilterMode::Workspace => sql.and_where_like_left("cwd", git_root),
};
let orig_query = query;
@@ -556,6 +571,7 @@ mod test {
session: "beepboopiamasession".to_string(),
cwd: "/home/ellie".to_string(),
host_id: "test-host".to_string(),
+ git_root: None,
};
let results = db
@@ -765,6 +781,7 @@ mod test {
session: "beepboopiamasession".to_string(),
cwd: "/home/ellie".to_string(),
host_id: "test-host".to_string(),
+ git_root: None,
};
let mut db = Sqlite::new("sqlite::memory:").await.unwrap();
diff --git a/atuin-client/src/settings.rs b/atuin-client/src/settings.rs
index bb41a890..3bcb2705 100644
--- a/atuin-client/src/settings.rs
+++ b/atuin-client/src/settings.rs
@@ -72,6 +72,9 @@ pub enum FilterMode {
#[serde(rename = "directory")]
Directory = 3,
+
+ #[serde(rename = "workspace")]
+ Workspace = 4,
}
impl FilterMode {
@@ -81,6 +84,7 @@ impl FilterMode {
FilterMode::Host => "HOST",
FilterMode::Session => "SESSION",
FilterMode::Directory => "DIRECTORY",
+ FilterMode::Workspace => "WORKSPACE",
}
}
}
@@ -163,6 +167,7 @@ pub struct Settings {
pub history_filter: RegexSet,
#[serde(with = "serde_regex", default = "RegexSet::empty")]
pub cwd_filter: RegexSet,
+ pub workspaces: bool,
// This is automatically loaded when settings is created. Do not set in
// config! Keep secrets and settings apart.
@@ -374,6 +379,7 @@ impl Settings {
.set_default("scroll_context_lines", 1)?
.set_default("shell_up_key_binding", false)?
.set_default("session_token", "")?
+ .set_default("workspaces", false)?
.add_source(
Environment::with_prefix("atuin")
.prefix_separator("_")
diff --git a/atuin-common/src/utils.rs b/atuin-common/src/utils.rs
index 776a63de..d2db3acf 100644
--- a/atuin-common/src/utils.rs
+++ b/atuin-common/src/utils.rs
@@ -46,6 +46,31 @@ pub fn uuid_v4() -> String {
Uuid::new_v4().as_simple().to_string()
}
+pub fn has_git_dir(path: &str) -> bool {
+ let mut gitdir = PathBuf::from(path);
+ gitdir.push(".git");
+
+ gitdir.exists()
+}
+
+// detect if any parent dir has a git repo in it
+// I really don't want to bring in libgit for something simple like this
+// If we start to do anything more advanced, then perhaps
+pub fn in_git_repo(path: &str) -> Option<PathBuf> {
+ let mut gitdir = PathBuf::from(path);
+
+ while gitdir.parent().is_some() && !has_git_dir(gitdir.to_str().unwrap()) {
+ gitdir.pop();
+ }
+
+ // No parent? then we hit root, finding no git
+ if gitdir.parent().is_some() {
+ return Some(gitdir);
+ }
+
+ None
+}
+
// TODO: more reliable, more tested
// I don't want to use ProjectDirs, it puts config in awkward places on
// mac. Data too. Seems to be more intended for GUI apps.
diff --git a/atuin/src/command/client/search.rs b/atuin/src/command/client/search.rs
index ff7511d7..95e92fda 100644
--- a/atuin/src/command/client/search.rs
+++ b/atuin/src/command/client/search.rs
@@ -194,14 +194,21 @@ async fn run_non_interactive(
let context = current_context();
let opt_filter = OptFilters {
- cwd: dir,
+ cwd: dir.clone(),
..filter_options
};
+ let dir = dir.unwrap_or_else(|| "/".to_string());
+ let filter_mode = if settings.workspaces && utils::has_git_dir(dir.as_str()) {
+ FilterMode::Workspace
+ } else {
+ settings.filter_mode
+ };
+
let results = db
.search(
settings.search_mode,
- settings.filter_mode,
+ filter_mode,
&context,
query.join(" ").as_str(),
opt_filter,
diff --git a/atuin/src/command/client/search/interactive.rs b/atuin/src/command/client/search/interactive.rs
index eec7ac8d..401dafec 100644
--- a/atuin/src/command/client/search/interactive.rs
+++ b/atuin/src/command/client/search/interactive.rs
@@ -184,15 +184,27 @@ impl State {
}
KeyCode::Char('u') if ctrl => self.search.input.clear(),
KeyCode::Char('r') if ctrl => {
- pub static FILTER_MODES: [FilterMode; 4] = [
- FilterMode::Global,
- FilterMode::Host,
- FilterMode::Session,
- FilterMode::Directory,
- ];
+ let filter_modes = if settings.workspaces && self.search.context.git_root.is_some()
+ {
+ vec![
+ FilterMode::Global,
+ FilterMode::Host,
+ FilterMode::Session,
+ FilterMode::Directory,
+ FilterMode::Workspace,
+ ]
+ } else {
+ vec![
+ FilterMode::Global,
+ FilterMode::Host,
+ FilterMode::Session,
+ FilterMode::Directory,
+ ]
+ };
+
let i = self.search.filter_mode as usize;
- let i = (i + 1) % FILTER_MODES.len();
- self.search.filter_mode = FILTER_MODES[i];
+ let i = (i + 1) % filter_modes.len();
+ self.search.filter_mode = filter_modes[i];
}
KeyCode::Char('s') if ctrl => {
self.switched_search_mode = true;
@@ -586,14 +598,16 @@ pub async fn history(
search_mode: settings.search_mode,
search: SearchState {
input,
- context,
- filter_mode: if settings.shell_up_key_binding {
+ filter_mode: if settings.workspaces && context.git_root.is_some() {
+ FilterMode::Workspace
+ } else if settings.shell_up_key_binding {
settings
.filter_mode_shell_up_key_binding
.unwrap_or(settings.filter_mode)
} else {
settings.filter_mode
},
+ context,
},
engine: engines::engine(settings.search_mode),
results_len: 0,
diff --git a/atuin/src/command/client/stats.rs b/atuin/src/command/client/stats.rs
index 5134f22f..cbb56820 100644
--- a/atuin/src/command/client/stats.rs
+++ b/atuin/src/command/client/stats.rs
@@ -80,6 +80,7 @@ impl Cmd {
} else {
self.period.join(" ")
};
+
let history = if words.as_str() == "all" {
db.list(FilterMode::Global, &context, None, false).await?
} else if words.trim() == "today" {