2
0

refactor: remove unused completer and status modules with rustyline/terminal_size deps

This commit is contained in:
2026-03-24 14:59:48 +09:00
parent e8c71d739d
commit a3065415f7
4 changed files with 0 additions and 239 deletions

View File

@@ -14,10 +14,8 @@ name = "aishell"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
rustyline = "14.0"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
terminal_size = "0.4"
libc = "0.2" libc = "0.2"
notify = { version = "7", features = ["macos_fsevent"] } notify = { version = "7", features = ["macos_fsevent"] }
ratatui = "0.29" ratatui = "0.29"

View File

@@ -1,170 +0,0 @@
use std::env;
use std::fs;
use std::path::Path;
use rustyline::completion::{Completer, Pair};
use rustyline::highlight::Highlighter;
use rustyline::hint::{Hinter, HistoryHinter};
use rustyline::validate::Validator;
use rustyline::Helper;
use rustyline::Context;
pub struct ShellHelper {
hinter: HistoryHinter,
}
impl ShellHelper {
pub fn new() -> Self {
Self {
hinter: HistoryHinter::new(),
}
}
}
impl Helper for ShellHelper {}
impl Validator for ShellHelper {}
impl Highlighter for ShellHelper {
fn highlight_hint<'h>(&self, hint: &'h str) -> std::borrow::Cow<'h, str> {
// Gray color for hints
std::borrow::Cow::Owned(format!("\x1b[90m{}\x1b[0m", hint))
}
}
impl Hinter for ShellHelper {
type Hint = String;
fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<String> {
self.hinter.hint(line, pos, ctx)
}
}
impl Completer for ShellHelper {
type Candidate = Pair;
fn complete(
&self,
line: &str,
pos: usize,
_ctx: &Context<'_>,
) -> rustyline::Result<(usize, Vec<Pair>)> {
let (start, word) = extract_word(line, pos);
// If first word → command completion
// Otherwise → file path completion
let is_first_word = line[..start].trim().is_empty();
let candidates = if is_first_word {
let mut results = complete_commands(word);
// Also include files in current dir for ./script style
results.extend(complete_path(word));
results
} else {
complete_path(word)
};
Ok((start, candidates))
}
}
/// Extract the current word being completed
fn extract_word(line: &str, pos: usize) -> (usize, &str) {
let bytes = &line.as_bytes()[..pos];
let start = bytes.iter().rposition(|&b| b == b' ').map(|i| i + 1).unwrap_or(0);
(start, &line[start..pos])
}
/// Complete commands from PATH
fn complete_commands(prefix: &str) -> Vec<Pair> {
if prefix.is_empty() {
return Vec::new();
}
let path_var = match env::var("PATH") {
Ok(p) => p,
Err(_) => return Vec::new(),
};
let mut seen = std::collections::HashSet::new();
let mut results = Vec::new();
for dir in path_var.split(':') {
let entries = match fs::read_dir(dir) {
Ok(e) => e,
Err(_) => continue,
};
for entry in entries.flatten() {
let name = entry.file_name();
let name = name.to_string_lossy();
if name.starts_with(prefix) && !seen.contains(name.as_ref()) {
seen.insert(name.to_string());
results.push(Pair {
display: name.to_string(),
replacement: name.to_string(),
});
}
}
}
results.sort_by(|a, b| a.display.cmp(&b.display));
results
}
/// Complete file/directory paths
fn complete_path(prefix: &str) -> Vec<Pair> {
let (dir, file_prefix) = if prefix.contains('/') {
let p = Path::new(prefix);
let dir = p.parent().unwrap_or(Path::new("."));
let file = p.file_name().map(|f| f.to_string_lossy().to_string()).unwrap_or_default();
// Expand ~
let dir_str = dir.to_string_lossy();
let expanded = if dir_str.starts_with('~') {
if let Ok(home) = env::var("HOME") {
Path::new(&dir_str.replacen('~', &home, 1)).to_path_buf()
} else {
dir.to_path_buf()
}
} else {
dir.to_path_buf()
};
(expanded, file)
} else {
(std::env::current_dir().unwrap_or_default(), prefix.to_string())
};
let entries = match fs::read_dir(&dir) {
Ok(e) => e,
Err(_) => return Vec::new(),
};
let mut results = Vec::new();
for entry in entries.flatten() {
let name = entry.file_name();
let name = name.to_string_lossy().to_string();
if name.starts_with(&file_prefix) {
let is_dir = entry.file_type().map(|t| t.is_dir()).unwrap_or(false);
let replacement = if prefix.contains('/') {
let parent = Path::new(prefix).parent().unwrap_or(Path::new(""));
let mut r = format!("{}/{}", parent.display(), name);
if is_dir {
r.push('/');
}
r
} else {
let mut r = name.clone();
if is_dir {
r.push('/');
}
r
};
let display = if is_dir {
format!("{}/", name)
} else {
name
};
results.push(Pair { display, replacement });
}
}
results.sort_by(|a, b| a.display.cmp(&b.display));
results
}

View File

@@ -3,8 +3,6 @@ pub mod config;
pub mod judge; pub mod judge;
pub mod executor; pub mod executor;
pub mod ai; pub mod ai;
pub mod status;
pub mod completer;
pub mod agent; pub mod agent;
pub mod tui; pub mod tui;
pub mod headless; pub mod headless;

View File

@@ -1,65 +0,0 @@
use std::io::{Write, stdout};
use terminal_size::{terminal_size, Width, Height};
pub struct StatusBar {
message: String,
cleaned: bool,
}
impl StatusBar {
pub fn new() -> Self {
let sb = Self {
message: "idle".to_string(),
cleaned: false,
};
sb.setup();
sb
}
fn term_size(&self) -> (u16, u16) {
terminal_size()
.map(|(Width(w), Height(h))| (w, h))
.unwrap_or((80, 24))
}
fn setup(&self) {
let (_, rows) = self.term_size();
let mut out = stdout();
write!(out, "\x1b[1;{}r", rows - 1).ok();
write!(out, "\x1b[1;1H").ok();
out.flush().ok();
self.render();
}
pub fn set(&mut self, msg: &str) {
self.message = msg.to_string();
self.render();
}
fn render(&self) {
let (cols, rows) = self.term_size();
let status = format!("{}", self.message);
let padded = format!("{:<width$}", status, width = cols as usize);
let mut out = stdout();
write!(out, "\x1b7\x1b[{};1H\x1b[7m{}\x1b[0m\x1b8", rows, padded).ok();
out.flush().ok();
}
pub fn cleanup(&mut self) {
if self.cleaned {
return;
}
self.cleaned = true;
let (_, rows) = self.term_size();
let mut out = stdout();
write!(out, "\x1b[r").ok();
write!(out, "\x1b[{};1H\x1b[2K", rows).ok();
out.flush().ok();
}
}
impl Drop for StatusBar {
fn drop(&mut self) {
self.cleanup();
}
}