use tracing::instrument;
use uuid::Uuid;
use super::IntelliShellService;
use crate::{
errors::{Result, UserFacingError},
model::{CATEGORY_USER, CATEGORY_WORKSPACE, Command, SearchCommandsFilter, SearchMode},
utils::{extract_tags_and_cleaned_text, extract_tags_with_editing_and_cleaned_text, get_working_dir},
};
type Tag = (String, u64, bool);
impl IntelliShellService {
#[instrument(skip_all)]
pub async fn is_storage_empty(&self) -> Result<bool> {
self.storage.is_empty().await
}
#[instrument(skip_all)]
pub async fn insert_command(&self, command: Command) -> Result<Command> {
if command.cmd.is_empty() {
return Err(UserFacingError::EmptyCommand.into());
}
tracing::info!("Bookmarking command: {}", command.cmd);
self.storage.insert_command(command).await
}
#[instrument(skip_all)]
pub async fn update_command(&self, command: Command) -> Result<Command> {
if command.cmd.is_empty() {
return Err(UserFacingError::EmptyCommand.into());
}
tracing::info!("Updating command '{}': {}", command.id, command.cmd);
self.storage.update_command(command).await
}
#[instrument(skip_all)]
pub async fn increment_command_usage(&self, command_id: Uuid) -> Result<i32> {
tracing::info!("Increasing usage for command '{command_id}'");
self.storage
.increment_command_usage(command_id, get_working_dir())
.await
}
#[instrument(skip_all)]
pub async fn delete_command(&self, id: Uuid) -> Result<()> {
tracing::info!("Deleting command: {}", id);
self.storage.delete_command(id).await
}
#[instrument(skip_all)]
pub async fn search_tags(
&self,
mode: SearchMode,
user_only: bool,
query: &str,
cursor_pos: usize,
) -> Result<Option<Vec<Tag>>> {
let Some((editing_tag, other_tags, cleaned_text)) =
extract_tags_with_editing_and_cleaned_text(query, cursor_pos)
else {
return Ok(None);
};
tracing::info!(
"Searching for tags{} [{mode:?}]: {query}",
if user_only { " (user only)" } else { "" }
);
tracing::trace!("Editing: {editing_tag} Other: {other_tags:?}");
let filter = SearchCommandsFilter {
category: user_only.then(|| vec![CATEGORY_USER.to_string()]),
source: None,
tags: Some(other_tags),
search_mode: mode,
search_term: Some(cleaned_text),
};
Ok(Some(
self.storage
.find_tags(filter, Some(editing_tag), &self.tuning.commands)
.await?,
))
}
#[instrument(skip_all)]
pub async fn search_commands(
&self,
mode: SearchMode,
user_only: bool,
query: &str,
) -> Result<(Vec<Command>, bool)> {
tracing::info!(
"Searching for commands{} [{mode:?}]: {query}",
if user_only { " (user only)" } else { "" }
);
let query = query.trim();
let filter = if query.is_empty() {
SearchCommandsFilter {
category: Some(if user_only {
vec![CATEGORY_USER.to_string()]
} else {
vec![CATEGORY_USER.to_string(), CATEGORY_WORKSPACE.to_string()]
}),
search_mode: mode,
..Default::default()
}
} else {
let (tags, search_term) = match extract_tags_and_cleaned_text(query) {
Some((tags, cleaned_query)) => (Some(tags), Some(cleaned_query)),
None => (None, Some(query.to_string())),
};
SearchCommandsFilter {
category: user_only.then(|| vec![CATEGORY_USER.to_string()]),
source: None,
tags,
search_mode: mode,
search_term,
}
};
self.storage
.find_commands(filter, get_working_dir(), &self.tuning.commands)
.await
}
}