vw-cli 0.2.7

Rust-first autonomous agent runtime CLI
Documentation
//! TUI(终端用户界面)实用工具模块
//!
//! 本模块提供了用于终端用户界面的辅助工具函数,主要支持 CLI 交互式界面的渲染和显示。
//!
//! # 主要功能
//!
//! - **光标位置计算**:根据文本内容和光标索引计算光标在多行文本中的行列位置
//! - **视觉效果生成**:提供霓虹呼吸效果的颜色循环,用于动态视觉反馈
//!
//! # 使用场景
//!
//! 这些工具函数主要用于增强 TUI 界面的用户体验,例如:
//! - 在交互式输入框中正确定位光标
//! - 为状态指示器提供动态颜色效果

use ratatui::style::Color;
use unicode_width::UnicodeWidthChar;

/// 根据文本内容和光标索引计算光标的行列位置
///
/// 此函数遍历输入文本的前 `cursor_idx` 个字符,计算光标在多行文本中的
/// 逻辑位置(行号和列号)。支持 Unicode 字符的正确宽度计算。
///
/// # 参数
///
/// - `input`:输入的文本内容
/// - `cursor_idx`:光标在文本中的字符索引位置(基于字符,而非字节)
///
/// # 返回值
///
/// 返回一个元组 `(row, col)`:
/// - `row`:光标所在的行号(从 0 开始)
/// - `col`:光标所在的列号(从 0 开始,考虑 Unicode 字符宽度)
///
/// # 示例
///
/// ```ignore
/// let text = "Hello\nWorld";
/// let pos = cursor_position(text, 7); // 指向 'W'
/// assert_eq!(pos, (1, 0)); // 第 2 行,第 0 列
/// ```
///
/// # 注意事项
///
/// - 换行符 `\n` 会将列号重置为 0,并将行号加 1
/// - 使用 `unicode_width` 计算字符的显示宽度,正确处理中文等宽字符
/// - 使用饱和运算避免溢出
pub(crate) fn cursor_position(input: &str, cursor_idx: usize) -> (u16, u16) {
    let mut row: u16 = 0;
    let mut col: u16 = 0;

    // 遍历光标位置之前的所有字符,计算行列位置
    for ch in input.chars().take(cursor_idx) {
        if ch == '\n' {
            // 遇到换行符:行号加 1,列号重置
            row = row.saturating_add(1);
            col = 0;
        } else {
            // 普通字符:根据 Unicode 宽度增加列号
            let width = u16::try_from(ch.width().unwrap_or(0)).unwrap_or(u16::MAX);
            col = col.saturating_add(width);
        }
    }

    (row, col)
}

/// 根据呼吸动画的阶段返回对应的霓虹色
///
/// 此函数实现了一个循环的霓虹呼吸效果,通过预定义的颜色调色板
/// 产生平滑的颜色过渡,用于创建动态视觉反馈效果。
///
/// # 参数
///
/// - `phase`:呼吸动画的当前阶段索引(通常随时间递增)
///
/// # 返回值
///
/// 返回调色板中对应阶段的 `Color` 值
///
/// # 颜色循环
///
/// 调色板包含 8 种颜色,从深蓝到青色再回到深蓝:
/// 1. 深蓝色 (0, 170, 220)
/// 2. 亮蓝色 (0, 200, 240)
/// 3. 浅蓝色 (20, 230, 255)
/// 4. 青色 (60, 255, 245) - 最亮点
/// 5. 浅蓝色 (20, 230, 255)
/// 6. 亮蓝色 (0, 200, 240)
/// 7. 深蓝色 (0, 170, 220)
/// 8. 暗蓝色 (0, 145, 205) - 最暗点
///
/// # 示例
///
/// ```ignore
/// for phase in 0..16 {
///     let color = neon_breath_color(phase);
///     // 颜色会在调色板中循环
/// }
/// ```
///
/// # 使用场景
///
/// 常用于:
/// - 状态指示器的动态颜色
/// - 加载动画的视觉效果
/// - 用户交互反馈
pub(crate) fn neon_breath_color(phase: usize) -> Color {
    /// 霓虹呼吸效果的调色板
    ///
    /// 包含 8 种颜色,形成一个完整的呼吸周期:
    /// - 前 4 色从暗到亮(吸气)
    /// - 后 4 色从亮到暗(呼气)
    const PALETTE: [Color; 8] = [
        Color::Rgb(0, 170, 220),  // 深蓝色
        Color::Rgb(0, 200, 240),  // 亮蓝色
        Color::Rgb(20, 230, 255), // 浅蓝色
        Color::Rgb(60, 255, 245), // 青色(峰值)
        Color::Rgb(20, 230, 255), // 浅蓝色
        Color::Rgb(0, 200, 240),  // 亮蓝色
        Color::Rgb(0, 170, 220),  // 深蓝色
        Color::Rgb(0, 145, 205),  // 暗蓝色(谷值)
    ];

    // 使用模运算实现无限循环
    PALETTE[phase % PALETTE.len()]
}