Add automatic update checking (#555)
* Add automatic update checking * Add setting to opt out of update checks * Document options * no * no * also no * Make clippy happy * Update atuin-client/src/settings.rs Co-authored-by: Conrad Ludgate <conradludgate@gmail.com> * fix features Co-authored-by: Conrad Ludgate <conradludgate@gmail.com> Co-authored-by: Conrad Ludgate <conrad.ludgate@truelayer.com>
This commit is contained in:
parent
62aafc3537
commit
f03f6e9ad7
13 changed files with 191 additions and 43 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -100,6 +100,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"rpassword",
|
"rpassword",
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"termion",
|
"termion",
|
||||||
|
@ -133,6 +134,7 @@ dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
@ -1635,6 +1637,12 @@ dependencies = [
|
||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.144"
|
version = "1.0.144"
|
||||||
|
|
|
@ -71,6 +71,7 @@ clap_complete = "3.1.4"
|
||||||
fs-err = "2.7"
|
fs-err = "2.7"
|
||||||
whoami = "1.1.2"
|
whoami = "1.1.2"
|
||||||
rpassword = "6.0"
|
rpassword = "6.0"
|
||||||
|
semver = "1.0.14"
|
||||||
|
|
||||||
[dependencies.tracing-subscriber]
|
[dependencies.tracing-subscriber]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
|
|
|
@ -63,6 +63,7 @@ sha2 = { version = "0.10", optional = true }
|
||||||
rmp-serde = { version = "1.0.0", optional = true }
|
rmp-serde = { version = "1.0.0", optional = true }
|
||||||
base64 = { version = "0.13.0", optional = true }
|
base64 = { version = "0.13.0", optional = true }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
semver = "1.0.14"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
## enable or disable automatic sync
|
## enable or disable automatic sync
|
||||||
# auto_sync = true
|
# auto_sync = true
|
||||||
|
|
||||||
|
## enable or disable automatic update checks
|
||||||
|
# update_check = true
|
||||||
|
|
||||||
## how often to sync history. note that this is only triggered when a command
|
## how often to sync history. note that this is only triggered when a command
|
||||||
## is ran, so sync intervals may well be longer
|
## is ran, so sync intervals may well be longer
|
||||||
## set it to 0 to sync after every command
|
## set it to 0 to sync after every command
|
||||||
|
|
|
@ -9,9 +9,10 @@ use reqwest::{
|
||||||
use sodiumoxide::crypto::secretbox;
|
use sodiumoxide::crypto::secretbox;
|
||||||
|
|
||||||
use atuin_common::api::{
|
use atuin_common::api::{
|
||||||
AddHistoryRequest, CountResponse, ErrorResponse, LoginRequest, LoginResponse, RegisterResponse,
|
AddHistoryRequest, CountResponse, ErrorResponse, IndexResponse, LoginRequest, LoginResponse,
|
||||||
SyncHistoryResponse,
|
RegisterResponse, SyncHistoryResponse,
|
||||||
};
|
};
|
||||||
|
use semver::Version;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
encryption::{decode_key, decrypt},
|
encryption::{decode_key, decrypt},
|
||||||
|
@ -86,6 +87,27 @@ pub async fn login(address: &str, req: LoginRequest) -> Result<LoginResponse> {
|
||||||
Ok(session)
|
Ok(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn latest_version() -> Result<Version> {
|
||||||
|
let url = "https://api.atuin.sh";
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
let resp = client
|
||||||
|
.get(url)
|
||||||
|
.header(USER_AGENT, APP_USER_AGENT)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if resp.status() != reqwest::StatusCode::OK {
|
||||||
|
let error = resp.json::<ErrorResponse>().await?;
|
||||||
|
bail!("failed to check latest version: {}", error.reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = resp.json::<IndexResponse>().await?;
|
||||||
|
let version = Version::parse(index.version.as_str())?;
|
||||||
|
|
||||||
|
Ok(version)
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Client<'a> {
|
impl<'a> Client<'a> {
|
||||||
pub fn new(sync_addr: &'a str, session_token: &'a str, key: String) -> Result<Self> {
|
pub fn new(sync_addr: &'a str, session_token: &'a str, key: String) -> Result<Self> {
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
|
|
|
@ -8,9 +8,13 @@ use config::{Config, Environment, File as ConfigFile, FileFormat};
|
||||||
use eyre::{eyre, Context, Result};
|
use eyre::{eyre, Context, Result};
|
||||||
use fs_err::{create_dir_all, File};
|
use fs_err::{create_dir_all, File};
|
||||||
use parse_duration::parse;
|
use parse_duration::parse;
|
||||||
|
use semver::Version;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
pub const HISTORY_PAGE_SIZE: i64 = 100;
|
pub const HISTORY_PAGE_SIZE: i64 = 100;
|
||||||
|
pub const LAST_SYNC_FILENAME: &str = "last_sync_time";
|
||||||
|
pub const LAST_VERSION_CHECK_FILENAME: &str = "last_version_check_time";
|
||||||
|
pub const LATEST_VERSION_FILENAME: &str = "latest_version";
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Copy)]
|
#[derive(Clone, Debug, Deserialize, Copy)]
|
||||||
pub enum SearchMode {
|
pub enum SearchMode {
|
||||||
|
@ -86,6 +90,7 @@ pub struct Settings {
|
||||||
pub dialect: Dialect,
|
pub dialect: Dialect,
|
||||||
pub style: Style,
|
pub style: Style,
|
||||||
pub auto_sync: bool,
|
pub auto_sync: bool,
|
||||||
|
pub update_check: bool,
|
||||||
pub sync_address: String,
|
pub sync_address: String,
|
||||||
pub sync_frequency: String,
|
pub sync_frequency: String,
|
||||||
pub db_path: String,
|
pub db_path: String,
|
||||||
|
@ -99,31 +104,65 @@ pub struct Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
pub fn save_sync_time() -> Result<()> {
|
fn save_to_data_dir(filename: &str, value: &str) -> Result<()> {
|
||||||
let data_dir = atuin_common::utils::data_dir();
|
let data_dir = atuin_common::utils::data_dir();
|
||||||
let data_dir = data_dir.as_path();
|
let data_dir = data_dir.as_path();
|
||||||
|
|
||||||
let sync_time_path = data_dir.join("last_sync_time");
|
let path = data_dir.join(filename);
|
||||||
|
|
||||||
fs_err::write(sync_time_path, Utc::now().to_rfc3339())?;
|
fs_err::write(path, value)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last_sync() -> Result<chrono::DateTime<Utc>> {
|
fn read_from_data_dir(filename: &str) -> Option<String> {
|
||||||
let data_dir = atuin_common::utils::data_dir();
|
let data_dir = atuin_common::utils::data_dir();
|
||||||
let data_dir = data_dir.as_path();
|
let data_dir = data_dir.as_path();
|
||||||
|
|
||||||
let sync_time_path = data_dir.join("last_sync_time");
|
let path = data_dir.join(filename);
|
||||||
|
|
||||||
if !sync_time_path.exists() {
|
if !path.exists() {
|
||||||
return Ok(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0));
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let time = fs_err::read_to_string(sync_time_path)?;
|
let value = fs_err::read_to_string(path);
|
||||||
let time = chrono::DateTime::parse_from_rfc3339(time.as_str())?;
|
|
||||||
|
|
||||||
Ok(time.with_timezone(&Utc))
|
value.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_current_time(filename: &str) -> Result<()> {
|
||||||
|
Settings::save_to_data_dir(filename, Utc::now().to_rfc3339().as_str())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_time_from_file(filename: &str) -> Result<chrono::DateTime<Utc>> {
|
||||||
|
let value = Settings::read_from_data_dir(filename);
|
||||||
|
|
||||||
|
match value {
|
||||||
|
Some(v) => {
|
||||||
|
let time = chrono::DateTime::parse_from_rfc3339(v.as_str())?;
|
||||||
|
|
||||||
|
Ok(time.with_timezone(&Utc))
|
||||||
|
}
|
||||||
|
None => Ok(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_sync_time() -> Result<()> {
|
||||||
|
Settings::save_current_time(LAST_SYNC_FILENAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_version_check_time() -> Result<()> {
|
||||||
|
Settings::save_current_time(LAST_VERSION_CHECK_FILENAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last_sync() -> Result<chrono::DateTime<Utc>> {
|
||||||
|
Settings::load_time_from_file(LAST_SYNC_FILENAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last_version_check() -> Result<chrono::DateTime<Utc>> {
|
||||||
|
Settings::load_time_from_file(LAST_VERSION_CHECK_FILENAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_sync(&self) -> Result<bool> {
|
pub fn should_sync(&self) -> Result<bool> {
|
||||||
|
@ -142,6 +181,67 @@ impl Settings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn needs_update_check(&self) -> Result<bool> {
|
||||||
|
let last_check = Settings::last_version_check()?;
|
||||||
|
let diff = Utc::now() - last_check;
|
||||||
|
|
||||||
|
// Check a max of once per hour
|
||||||
|
Ok(diff.num_hours() >= 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn latest_version(&self) -> Result<Version> {
|
||||||
|
// Default to the current version, and if that doesn't parse, a version so high it's unlikely to ever
|
||||||
|
// suggest upgrading.
|
||||||
|
let current =
|
||||||
|
Version::parse(env!("CARGO_PKG_VERSION")).unwrap_or(Version::new(100000, 0, 0));
|
||||||
|
|
||||||
|
if !self.needs_update_check()? {
|
||||||
|
// Worst case, we don't want Atuin to fail to start because something funky is going on with
|
||||||
|
// version checking.
|
||||||
|
let version = match Settings::read_from_data_dir(LATEST_VERSION_FILENAME) {
|
||||||
|
Some(v) => Version::parse(&v).unwrap_or(current),
|
||||||
|
None => current,
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
let latest = crate::api_client::latest_version().await.unwrap_or(current);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
let latest = current;
|
||||||
|
|
||||||
|
Settings::save_version_check_time()?;
|
||||||
|
Settings::save_to_data_dir(LATEST_VERSION_FILENAME, latest.to_string().as_str())?;
|
||||||
|
|
||||||
|
Ok(latest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return Some(latest version) if an update is needed. Otherwise, none.
|
||||||
|
pub async fn needs_update(&self) -> Option<Version> {
|
||||||
|
if !self.update_check {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current =
|
||||||
|
Version::parse(env!("CARGO_PKG_VERSION")).unwrap_or(Version::new(100000, 0, 0));
|
||||||
|
|
||||||
|
let latest = self.latest_version().await;
|
||||||
|
|
||||||
|
if latest.is_err() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let latest = latest.unwrap();
|
||||||
|
|
||||||
|
if latest > current {
|
||||||
|
return Some(latest);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Result<Self> {
|
||||||
let config_dir = atuin_common::utils::config_dir();
|
let config_dir = atuin_common::utils::config_dir();
|
||||||
|
|
||||||
|
@ -172,6 +272,7 @@ impl Settings {
|
||||||
.set_default("session_path", session_path.to_str())?
|
.set_default("session_path", session_path.to_str())?
|
||||||
.set_default("dialect", "us")?
|
.set_default("dialect", "us")?
|
||||||
.set_default("auto_sync", true)?
|
.set_default("auto_sync", true)?
|
||||||
|
.set_default("update_check", true)?
|
||||||
.set_default("sync_frequency", "1h")?
|
.set_default("sync_frequency", "1h")?
|
||||||
.set_default("sync_address", "https://api.atuin.sh")?
|
.set_default("sync_address", "https://api.atuin.sh")?
|
||||||
.set_default("search_mode", "prefix")?
|
.set_default("search_mode", "prefix")?
|
||||||
|
|
|
@ -59,3 +59,9 @@ pub struct SyncHistoryResponse {
|
||||||
pub struct ErrorResponse<'a> {
|
pub struct ErrorResponse<'a> {
|
||||||
pub reason: Cow<'a, str>,
|
pub reason: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct IndexResponse {
|
||||||
|
pub homage: String,
|
||||||
|
pub version: String,
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,11 @@
|
||||||
use atuin_common::api::ErrorResponse;
|
use atuin_common::api::{ErrorResponse, IndexResponse};
|
||||||
use axum::{response::IntoResponse, Json};
|
use axum::{response::IntoResponse, Json};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub mod history;
|
pub mod history;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct IndexResponse {
|
|
||||||
pub homage: String,
|
|
||||||
pub version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn index() -> Json<IndexResponse> {
|
pub async fn index() -> Json<IndexResponse> {
|
||||||
let homage = r#""Through the fathomless deeps of space swims the star turtle Great A'Tuin, bearing on its back the four giant elephants who carry on their shoulders the mass of the Discworld." -- Sir Terry Pratchett"#;
|
let homage = r#""Through the fathomless deeps of space swims the star turtle Great A'Tuin, bearing on its back the four giant elephants who carry on their shoulders the mass of the Discworld." -- Sir Terry Pratchett"#;
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,15 @@ true
|
||||||
auto_sync = true/false
|
auto_sync = true/false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `update_check`
|
||||||
|
|
||||||
|
Configures whether or not to automatically check for updates. Defaults to
|
||||||
|
true.
|
||||||
|
|
||||||
|
```
|
||||||
|
auto_sync = true/false
|
||||||
|
```
|
||||||
|
|
||||||
### `sync_address`
|
### `sync_address`
|
||||||
|
|
||||||
The address of the server to sync with! Defaults to `https://api.atuin.sh`.
|
The address of the server to sync with! Defaults to `https://api.atuin.sh`.
|
||||||
|
|
|
@ -15,6 +15,7 @@ use atuin_client::{
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
use atuin_client::sync;
|
use atuin_client::sync;
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
use super::search::format_duration;
|
use super::search::format_duration;
|
||||||
|
|
||||||
|
|
|
@ -63,14 +63,7 @@ pub struct Cmd {
|
||||||
impl Cmd {
|
impl Cmd {
|
||||||
pub async fn run(self, db: &mut impl Database, settings: &Settings) -> Result<()> {
|
pub async fn run(self, db: &mut impl Database, settings: &Settings) -> Result<()> {
|
||||||
if self.interactive {
|
if self.interactive {
|
||||||
let item = interactive::history(
|
let item = interactive::history(&self.query, settings, db).await?;
|
||||||
&self.query,
|
|
||||||
settings.search_mode,
|
|
||||||
settings.filter_mode,
|
|
||||||
settings.style,
|
|
||||||
db,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
eprintln!("{}", item);
|
eprintln!("{}", item);
|
||||||
} else {
|
} else {
|
||||||
let list_mode = ListMode::from_flags(self.human, self.cmd_only);
|
let list_mode = ListMode::from_flags(self.human, self.cmd_only);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::io::stdout;
|
use std::io::stdout;
|
||||||
|
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
use semver::Version;
|
||||||
use termion::{
|
use termion::{
|
||||||
event::Event as TermEvent, event::Key, event::MouseButton, event::MouseEvent,
|
event::Event as TermEvent, event::Key, event::MouseButton, event::MouseEvent,
|
||||||
input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen,
|
input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen,
|
||||||
|
@ -20,7 +21,7 @@ use atuin_client::{
|
||||||
database::Context,
|
database::Context,
|
||||||
database::Database,
|
database::Database,
|
||||||
history::History,
|
history::History,
|
||||||
settings::{FilterMode, SearchMode},
|
settings::{FilterMode, SearchMode, Settings},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -36,6 +37,7 @@ struct State {
|
||||||
filter_mode: FilterMode,
|
filter_mode: FilterMode,
|
||||||
results_state: ListState,
|
results_state: ListState,
|
||||||
context: Context,
|
context: Context,
|
||||||
|
update_needed: Option<Version>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
@ -143,10 +145,19 @@ impl State {
|
||||||
.constraints([Constraint::Length(1); 3])
|
.constraints([Constraint::Length(1); 3])
|
||||||
.split(top_chunks[1]);
|
.split(top_chunks[1]);
|
||||||
|
|
||||||
let title = Paragraph::new(Text::from(Span::styled(
|
let title = if self.update_needed.is_some() {
|
||||||
format!(" Atuin v{VERSION}"),
|
let version = self.update_needed.clone().unwrap();
|
||||||
Style::default().add_modifier(Modifier::BOLD),
|
|
||||||
)));
|
Paragraph::new(Text::from(Span::styled(
|
||||||
|
format!(" Atuin v{VERSION} - UPDATE AVAILABLE {version}"),
|
||||||
|
Style::default().add_modifier(Modifier::BOLD).fg(Color::Red),
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Paragraph::new(Text::from(Span::styled(
|
||||||
|
format!(" Atuin v{VERSION}"),
|
||||||
|
Style::default().add_modifier(Modifier::BOLD),
|
||||||
|
)))
|
||||||
|
};
|
||||||
|
|
||||||
let help = vec![
|
let help = vec![
|
||||||
Span::raw(" Press "),
|
Span::raw(" Press "),
|
||||||
|
@ -277,9 +288,7 @@ impl State {
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
pub async fn history(
|
pub async fn history(
|
||||||
query: &[String],
|
query: &[String],
|
||||||
search_mode: SearchMode,
|
settings: &Settings,
|
||||||
filter_mode: FilterMode,
|
|
||||||
style: atuin_client::settings::Style,
|
|
||||||
db: &mut impl Database,
|
db: &mut impl Database,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
let stdout = stdout().into_raw_mode()?;
|
let stdout = stdout().into_raw_mode()?;
|
||||||
|
@ -294,15 +303,19 @@ pub async fn history(
|
||||||
let mut input = Cursor::from(query.join(" "));
|
let mut input = Cursor::from(query.join(" "));
|
||||||
// Put the cursor at the end of the query by default
|
// Put the cursor at the end of the query by default
|
||||||
input.end();
|
input.end();
|
||||||
|
|
||||||
|
let update_needed = settings.needs_update().await;
|
||||||
|
|
||||||
let mut app = State {
|
let mut app = State {
|
||||||
history_count: db.history_count().await?,
|
history_count: db.history_count().await?,
|
||||||
input,
|
input,
|
||||||
results_state: ListState::default(),
|
results_state: ListState::default(),
|
||||||
context: current_context(),
|
context: current_context(),
|
||||||
filter_mode,
|
filter_mode: settings.filter_mode,
|
||||||
|
update_needed,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut results = app.query_results(search_mode, db).await?;
|
let mut results = app.query_results(settings.search_mode, db).await?;
|
||||||
|
|
||||||
let index = 'render: loop {
|
let index = 'render: loop {
|
||||||
let initial_input = app.input.as_str().to_owned();
|
let initial_input = app.input.as_str().to_owned();
|
||||||
|
@ -323,10 +336,10 @@ pub async fn history(
|
||||||
}
|
}
|
||||||
|
|
||||||
if initial_input != app.input.as_str() || initial_filter_mode != app.filter_mode {
|
if initial_input != app.input.as_str() || initial_filter_mode != app.filter_mode {
|
||||||
results = app.query_results(search_mode, db).await?;
|
results = app.query_results(settings.search_mode, db).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let compact = match style {
|
let compact = match settings.style {
|
||||||
atuin_client::settings::Style::Auto => {
|
atuin_client::settings::Style::Auto => {
|
||||||
terminal.size().map(|size| size.height < 14).unwrap_or(true)
|
terminal.size().map(|size| size.height < 14).unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,6 @@
|
||||||
use clap::{AppSettings, Parser};
|
use clap::{AppSettings, Parser};
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
|
|
||||||
use command::AtuinCmd;
|
use command::AtuinCmd;
|
||||||
mod command;
|
mod command;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue