Enhance tool documentation and add new features

- Added module-level documentation for memory tools (`remember`, `recall`, `forget`) to clarify their purpose.
- Improved documentation in `recall.rs` and `remember.rs` to describe the functionality and flow of memory entry operations.
- Updated `mod.rs` to include descriptions for the tool trait and execution context.
- Enhanced `plan.rs` with detailed comments on plan-mode signaling tools.
- Documented text search tools in `search.rs` to explain their functionality.
- Improved sequential-thinking tool documentation in `seqthink.rs`.
- Added safety filter documentation in `shell_filter` for credential and git operations.
- Enhanced utility tools documentation, including `cd`, `dir_cache_update`, and `todowrite`.
- Improved rendering documentation in view modules (`chat`, `markdown`, `status`, `workflow`) to clarify rendering flows and purposes.
This commit is contained in:
asepharyana
2026-07-12 11:28:39 +07:00
parent 7158d362fd
commit 2efd40ca88
124 changed files with 2379 additions and 19 deletions
+49
View File
@@ -1,26 +1,33 @@
//! Application-level "miscellaneous" state: scroll, input buffer,
//! overlay stack, toasts, editor, and autocomplete.
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::RwLock;
use super::types::Overlay;
/// A shared, async-writable cache of directory entries, used to avoid
/// re-reading a directory every render frame.
#[derive(Clone)]
pub struct DirCache {
entries: Arc<RwLock<Vec<PathBuf>>>,
}
impl DirCache {
/// Create an empty `DirCache`.
pub fn new() -> Self {
DirCache {
entries: Arc::new(RwLock::new(Vec::new())),
}
}
/// Replace the cached entries (async write).
pub async fn set(&self, paths: Vec<PathBuf>) {
let mut w = self.entries.write().await;
*w = paths;
}
}
/// Manages the viewport scroll offset.
#[derive(Debug, Clone)]
pub struct ScrollState {
pub offset: usize,
@@ -28,6 +35,7 @@ pub struct ScrollState {
}
impl ScrollState {
/// Create a `ScrollState` with zero offset and 30 rows visible.
pub fn new() -> Self {
ScrollState {
offset: 0,
@@ -35,19 +43,25 @@ impl ScrollState {
}
}
/// Scroll the viewport up by `amount` lines (increasing the offset).
/// Scroll the viewport up by `amount` lines (increasing the offset).
pub fn scroll_up(&mut self, amount: usize) {
self.offset = self.offset.saturating_add(amount);
}
/// Scroll the viewport down by `amount` lines (decreasing the offset).
pub fn scroll_down(&mut self, amount: usize) {
self.offset = self.offset.saturating_sub(amount);
}
/// Update the maximum number of visible lines.
pub fn set_max_visible(&mut self, max: usize) {
self.max_visible = max;
}
}
/// The user's input buffer, cursor position, history, and autocomplete
/// state for the chat prompt.
#[derive(Debug, Clone)]
pub struct InputState {
pub buffer: String,
@@ -81,6 +95,8 @@ const COMMANDS: &[&str] = &[
];
impl InputState {
/// Create an empty input state with no buffer, no history, and no
/// autocomplete.
pub fn new() -> Self {
InputState {
buffer: String::new(),
@@ -94,6 +110,7 @@ impl InputState {
}
}
/// Hide the autocomplete dropdown and clear its state.
pub fn close_autocomplete(&mut self) {
self.autocomplete_visible = false;
self.autocomplete_candidates.clear();
@@ -101,6 +118,12 @@ impl InputState {
self.autocomplete_idx = 0;
}
/// Open or refresh the autocomplete dropdown by filtering `COMMANDS`
/// against the current buffer prefix.
///
/// Flow: if buffer is empty or doesn't start with `/`, close and return
/// → filter `COMMANDS` by prefix match → store candidates → set
/// `autocomplete_visible` if any candidates found.
pub fn open_autocomplete(&mut self) {
let trimmed = self.buffer.trim().to_string();
if trimmed.is_empty() || !trimmed.starts_with('/') {
@@ -119,6 +142,8 @@ impl InputState {
self.autocomplete_visible = !self.autocomplete_candidates.is_empty();
}
/// Move the autocomplete selection up (forward=false) or down (forward=true).
/// Wraps around at the boundaries.
pub fn cycle_autocomplete(&mut self, forward: bool) {
let n = self.autocomplete_candidates.len();
if n == 0 { return; }
@@ -129,6 +154,10 @@ impl InputState {
}
}
/// Accept the currently selected autocomplete candidate, placing it
/// in the buffer and closing the dropdown.
///
/// Return: `true` if a candidate was selected, `false` if none existed.
pub fn select_autocomplete(&mut self) -> bool {
if let Some(candidate) = self.autocomplete_candidates.get(self.autocomplete_idx) {
self.buffer = candidate.clone();
@@ -140,6 +169,8 @@ impl InputState {
}
}
/// Legacy inline tab-complete — opens the dropdown on first Tab press,
/// then cycles forward on subsequent presses.
pub fn tab_complete(&mut self) {
// Legacy inline tab-complete — used as a fallback when the dropdown
// isn't visible yet. Opens the dropdown on the first Tab press.
@@ -150,23 +181,27 @@ impl InputState {
}
}
/// Move the cursor left by one character (if not at the start).
pub fn char_left(&mut self) {
if self.cursor > 0 {
self.cursor -= 1;
}
}
/// Move the cursor right by one character (if not at the end).
pub fn char_right(&mut self) {
if self.cursor < self.buffer.len() {
self.cursor += 1;
}
}
/// Insert a character at the cursor position.
pub fn insert(&mut self, c: char) {
self.buffer.insert(self.cursor, c);
self.cursor += 1;
}
/// Delete the character to the left of the cursor (backspace).
pub fn delete_left(&mut self) {
if self.cursor > 0 {
self.cursor -= 1;
@@ -174,12 +209,17 @@ impl InputState {
}
}
/// Delete the character at the cursor position (forward delete).
pub fn delete_right(&mut self) {
if self.cursor < self.buffer.len() {
self.buffer.remove(self.cursor);
}
}
/// Submit the current buffer: push it to history, clear the buffer,
/// and return the submitted text.
///
/// Return: the text that was in the buffer before clearing.
pub fn submit(&mut self) -> String {
let result = self.buffer.clone();
if !result.is_empty() {
@@ -191,6 +231,7 @@ impl InputState {
result
}
/// Navigate backward through input history.
pub fn history_up(&mut self) {
if self.history.is_empty() {
return;
@@ -205,6 +246,7 @@ impl InputState {
self.cursor = self.buffer.len();
}
/// Navigate forward through input history (back toward the newest entry).
pub fn history_down(&mut self) {
match self.history_idx {
Some(i) if i < self.history.len() - 1 => {
@@ -223,6 +265,8 @@ impl InputState {
}
}
/// The "miscellaneous" slice of app state: which overlay is showing,
/// toasts, thinking/connected flags, effort level, editor state, and tick.
#[derive(Debug, Clone)]
pub struct MiscState {
pub overlay: Overlay,
@@ -237,6 +281,8 @@ pub struct MiscState {
}
impl MiscState {
/// Create a fresh `MiscState` with no overlay, no toasts, and default
/// effort level 1.
pub fn new() -> Self {
MiscState {
overlay: Overlay::None,
@@ -255,6 +301,9 @@ impl MiscState {
self.toasts.push(toast);
}
/// Remove and return all toasts whose lifetime has expired at `now_ms`.
///
/// Return: the expired toasts (after removal).
pub fn drain_expired_toasts(&mut self, now_ms: i64) -> Vec<super::types::Toast> {
let expired: Vec<_> = self.toasts.iter().filter(|t| t.expired(now_ms)).cloned().collect();
self.toasts.retain(|t| !t.expired(now_ms));