aboutsummaryrefslogtreecommitdiffstats
path: root/crates/turtle/src/atuin_daemon
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-12 17:16:19 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-12 17:16:19 +0200
commit2ca7dd57b12861e8c9bbc9238cda612e0ff22ff3 (patch)
tree302a644f6a50d60cc8304c4498fe6bbb72ddaaa9 /crates/turtle/src/atuin_daemon
parentfeat(server): Really make users stateless (with tests) (diff)
downloadatuin-2ca7dd57b12861e8c9bbc9238cda612e0ff22ff3.zip
chore(treewide): Cleanup themes
Diffstat (limited to 'crates/turtle/src/atuin_daemon')
-rw-r--r--crates/turtle/src/atuin_daemon/client.rs83
-rw-r--r--crates/turtle/src/atuin_daemon/daemon.rs28
-rw-r--r--crates/turtle/src/atuin_daemon/mod.rs3
-rw-r--r--crates/turtle/src/atuin_daemon/search/index.rs29
4 files changed, 18 insertions, 125 deletions
diff --git a/crates/turtle/src/atuin_daemon/client.rs b/crates/turtle/src/atuin_daemon/client.rs
index a0a27741..325b21b8 100644
--- a/crates/turtle/src/atuin_daemon/client.rs
+++ b/crates/turtle/src/atuin_daemon/client.rs
@@ -29,8 +29,7 @@ use crate::atuin_daemon::search::{
search_client::SearchClient as SearchServiceClient,
};
use crate::atuin_daemon::semantic::{
- CommandCapture, CommandOutputReply, CommandOutputRequest, OutputRange, RecordCommandsReply,
- semantic_client::SemanticClient as SemanticServiceClient,
+ CommandCapture, RecordCommandsReply, semantic_client::SemanticClient as SemanticServiceClient,
};
pub(crate) struct HistoryClient {
@@ -112,7 +111,7 @@ impl HistoryClient {
duration: u64,
exit: i64,
) -> Result<EndHistoryReply> {
- let req = EndHistoryRequest { id, duration, exit };
+ let req = EndHistoryRequest { id, exit, duration };
Ok(self.client.end_history(req).await?.into_inner())
}
@@ -255,22 +254,6 @@ impl SemanticClient {
let stream = tokio_stream::iter(captures);
Ok(self.client.record_commands(stream).await?.into_inner())
}
-
- pub(crate) async fn command_output(
- &mut self,
- history_id: String,
- ranges: Vec<(i64, i64)>,
- ) -> Result<CommandOutputReply> {
- let request = CommandOutputRequest {
- history_id,
- ranges: ranges
- .into_iter()
- .map(|(start, end)| OutputRange { start, end })
- .collect(),
- };
-
- Ok(self.client.command_output(request).await?.into_inner())
- }
}
// ============================================================================
@@ -354,65 +337,3 @@ fn daemon_event_to_proto(
}
}
}
-
-// ============================================================================
-// Convenience Functions
-// ============================================================================
-
-/// Emit an event to the daemon.
-///
-/// This is a fire-and-forget helper for sending events to the daemon from
-/// external processes like CLI commands. If the daemon isn't running, this
-/// will silently succeed (returns Ok).
-///
-/// # Example
-///
-/// ```ignore
-/// // After pruning history
-/// emit_event(DaemonEvent::HistoryPruned).await?;
-///
-/// // After deleting specific history items
-/// emit_event(DaemonEvent::HistoryDeleted { ids: vec![...] }).await?;
-///
-/// // Request immediate sync
-/// emit_event(DaemonEvent::ForceSync).await?;
-/// ```
-pub(crate) async fn emit_event(event: DaemonEvent) -> Result<()> {
- emit_event_with_settings(event, None).await
-}
-
-/// Emit an event to the daemon with explicit settings.
-///
-/// If settings are not provided, they will be loaded from the default location.
-/// If the daemon isn't running, this will silently succeed.
-pub(crate) async fn emit_event_with_settings(
- event: DaemonEvent,
- settings: Option<&Settings>,
-) -> Result<()> {
- // Load settings if not provided
- let owned_settings;
- let settings = match settings {
- Some(s) => s,
- None => {
- owned_settings = Settings::new()?;
- &owned_settings
- }
- };
-
- // Try to connect - if daemon isn't running, that's fine
- let mut client = match ControlClient::from_settings(settings).await {
- Ok(c) => c,
- Err(e) => {
- tracing::debug!(?e, "daemon not running, skipping event emission");
- return Ok(());
- }
- };
-
- // Send the event
- if let Err(e) = client.send_event(event).await {
- tracing::debug!(?e, "failed to send event to daemon");
- // Don't fail - this is fire-and-forget
- }
-
- Ok(())
-}
diff --git a/crates/turtle/src/atuin_daemon/daemon.rs b/crates/turtle/src/atuin_daemon/daemon.rs
index 7583c197..80aaeef8 100644
--- a/crates/turtle/src/atuin_daemon/daemon.rs
+++ b/crates/turtle/src/atuin_daemon/daemon.rs
@@ -113,17 +113,7 @@ impl DaemonHandle {
self.state.settings.read().await
}
- /// Reload settings from disk and emit a SettingsReloaded event.
- ///
- /// Components listening for `SettingsReloaded` can then re-read settings
- /// via `handle.settings()` to pick up the changes.
- pub(crate) async fn reload_settings(&self) -> Result<()> {
- let new_settings = Settings::new()?;
- self.apply_settings(new_settings).await;
- Ok(())
- }
-
- /// Apply already-loaded settings and emit a SettingsReloaded event.
+ /// Apply already-loaded settings and emit a [`SettingsReloaded`] event.
///
/// Use this when settings have already been loaded (e.g., from a file watcher)
/// to avoid parsing the config file twice.
@@ -292,7 +282,7 @@ impl Daemon {
/// Run the daemon event loop.
///
- /// This processes events until a ShutdownRequested event is received.
+ /// This processes events until a [`ShutdownRequested`] event is received.
/// Components must be started first via `start_components()`.
pub(crate) async fn run_event_loop(&mut self) -> Result<()> {
let mut event_rx = self.handle.subscribe();
@@ -338,18 +328,6 @@ impl Daemon {
tracing::info!("all components stopped");
}
- /// Run the daemon.
- ///
- /// This is a convenience method that starts components, runs the event loop,
- /// and handles shutdown. It does not return until the daemon is shut down.
- pub(crate) async fn run(mut self) -> Result<()> {
- self.start_components().await?;
- self.run_event_loop().await?;
- self.stop_components().await;
- tracing::info!("daemon stopped");
- Ok(())
- }
-
async fn dispatch_event(&mut self, event: &DaemonEvent) {
for component in &mut self.components {
if let Err(e) = component.handle_event(event).await {
@@ -424,7 +402,7 @@ impl DaemonBuilder {
/// Build the daemon.
///
/// This loads the encryption key and creates the daemon state.
- pub(crate) async fn build(self) -> Result<Daemon> {
+ pub(crate) fn build(self) -> Result<Daemon> {
let store = self.store.ok_or_else(|| eyre::eyre!("store is required"))?;
let history_db = self
.history_db
diff --git a/crates/turtle/src/atuin_daemon/mod.rs b/crates/turtle/src/atuin_daemon/mod.rs
index 6037b5a8..b161b0cc 100644
--- a/crates/turtle/src/atuin_daemon/mod.rs
+++ b/crates/turtle/src/atuin_daemon/mod.rs
@@ -52,8 +52,7 @@ pub(crate) async fn boot(
.component(search_component)
.component(semantic_component)
.component(sync_component)
- .build()
- .await?;
+ .build()?;
// Get a handle for the control service and gRPC server shutdown
let handle = daemon.handle();
diff --git a/crates/turtle/src/atuin_daemon/search/index.rs b/crates/turtle/src/atuin_daemon/search/index.rs
index a23b3133..197a8c1b 100644
--- a/crates/turtle/src/atuin_daemon/search/index.rs
+++ b/crates/turtle/src/atuin_daemon/search/index.rs
@@ -90,7 +90,7 @@ impl FrecencyData {
};
// Frequency boost: more uses = higher score (with diminishing returns)
- let frequency_score = ((self.count as f64).ln() * 20.0).min(100.0);
+ let frequency_score = (f64::from(self.count).ln() * 20.0).min(100.0);
// Apply multipliers and combine scores, then round to u32
((recency_score * recency_mul) + (frequency_score * frequency_mul)).round() as u32
@@ -117,7 +117,7 @@ pub(crate) struct CommandData {
}
impl CommandData {
- /// Create a new CommandData from a history entry.
+ /// Create a new [`CommandData`] from a history entry.
/// Returns None if the history entry has invalid UUIDs.
pub(crate) fn new(history: &History, interner: &ThreadedRodeo) -> Option<Self> {
let history_id = parse_uuid_bytes(&history.id.0)?;
@@ -237,9 +237,13 @@ pub(crate) enum IndexFilterMode {
/// Context for search queries.
#[derive(Debug, Clone, Default)]
pub(crate) struct QueryContext {
+ #[expect(dead_code)]
pub(crate) cwd: Option<String>,
+ #[expect(dead_code)]
pub(crate) git_root: Option<String>,
+ #[expect(dead_code)]
pub(crate) hostname: Option<String>,
+ #[expect(dead_code)]
pub(crate) session_id: Option<String>,
}
@@ -325,21 +329,21 @@ impl SearchIndex {
self.commands.len()
}
- /// Get the number of items in Nucleo (should match command_count).
- pub(crate) async fn nucleo_item_count(&self) -> u32 {
- self.nucleo.read().await.snapshot().item_count()
- }
-
/// Search for commands matching a query.
///
/// Returns a list of history IDs (most recent invocation per command).
/// Uses precomputed global frecency for scoring if available.
#[instrument(skip_all, level = tracing::Level::TRACE, name = "index_search", fields(query = %query))]
+ #[expect(
+ clippy::significant_drop_tightening,
+ reason = "The nucleo early drop is a false-positive"
+ )]
pub(crate) async fn search(
&self,
query: &str,
filter_mode: IndexFilterMode,
- _context: &QueryContext,
+ // TODO(@bpeetz): Use the query context here <2026-06-12>
+ #[expect(unused)] context: &QueryContext,
limit: u32,
) -> Vec<String> {
let mut nucleo = self.nucleo.write().await;
@@ -480,15 +484,6 @@ mod tests {
use super::*;
use time::macros::datetime;
- fn make_history(command: &str, cwd: &str, timestamp: OffsetDateTime) -> History {
- History::import()
- .timestamp(timestamp)
- .command(command)
- .cwd(cwd)
- .build()
- .into()
- }
-
#[test]
fn frecency_data_compute() {
let now = 1_000_000i64;