Rust终端查询工具xterm-query的使用:高效处理终端输入与输出的插件库
Rust终端查询工具xterm-query的使用:高效处理终端输入与输出的插件库
介绍
xterm-query是一个低级别库,用于通过CSI序列查询终端并将结果作为字符串获取。
注意事项:
- 终端必须已经处于原始模式(raw mode)
- 不支持Windows系统(理论上可以通过WSAPoll实现,但需要贡献者提交PR)
安装
在项目目录中运行以下Cargo命令:
cargo add xterm-query
或者在Cargo.toml中添加以下行:
xterm-query = "0.5.2"
示例代码
以下是查询终端是否支持Kitty图形协议的完整示例:
use std::io::{self, Write};
use xterm-query::{query, Error};
fn main() -> Result<(), Error> {
// 查询终端是否支持Kitty图形协议
let response = query("\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\")?;
// 打印响应
println!("Terminal response: {}", response);
Ok(())
}
注释说明:
query
函数发送CSI序列到终端并等待响应- 示例中的CSI序列是专门用于查询Kitty图形协议支持的
- 响应将以字符串形式返回
更完整的示例
下面是一个更完整的示例,包含进入和退出原始模式的处理:
use std::io::{self, Write};
use termion::raw::IntoRawMode;
use xterm_query::{query, Error};
fn main() -> Result<(), Error> {
// 进入原始模式
let stdout = io::stdout();
let mut stdout = stdout.lock().into_raw_mode()?;
// 查询终端特性
let response = query("\x1b[0c")?; // 查询终端识别码
// 退出原始模式
drop(stdout); // 这将自动恢复终端模式
// 处理响应
println!("Terminal identification: {}", response);
Ok(())
}
注释说明:
- 使用termion库处理原始模式
into_raw_mode()
进入原始模式- 查询终端识别码(ESC [0c)
- 通过丢弃原始模式句柄恢复终端设置
完整示例demo
下面是一个更详细的完整示例,包含错误处理和多个查询:
use std::io::{self, Write};
use termion::raw::IntoRawMode;
use xterm_query::{query, Error};
fn main() -> Result<(), Error> {
// 进入原始模式
let stdout = io::stdout();
let mut stdout = stdout.lock().into_raw_mode()?;
// 查询终端识别码
match query("\x1b[0c") {
Ok(response) => println!("Terminal ID: {}", response),
Err(e) => eprintln!("Failed to query terminal ID: {}", e),
}
// 查询终端尺寸
match query("\x1b[18t") {
Ok(response) => println!("Terminal size: {}", response),
Err(e) => eprintln!("Failed to query terminal size: {}", e),
}
// 查询Kitty图形协议支持
match query("\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\") {
Ok(response) => println!("Kitty protocol support: {}", response),
Err(e) => eprintln!("Failed to query Kitty protocol: {}", e),
}
// 退出原始模式
drop(stdout);
Ok(())
}
1 回复
Rust终端查询工具xterm-query的使用指南
介绍
xterm-query是一个用于高效处理终端输入与输出的Rust插件库,它提供了简洁的API来与终端交互,特别适合需要自动化终端操作或构建终端应用程序的场景。
主要特性
- 跨平台支持(Linux/macOS/Windows)
- 异步和非阻塞IO操作
- 支持ANSI转义码解析
- 终端属性查询功能
- 简洁易用的API设计
安装方法
在Cargo.toml中添加依赖:
[dependencies]
xterm-query = "0.3.0" # 请使用最新版本
基本使用方法
1. 初始化终端查询器
use xterm_query::TerminalQuery;
let term_query = TerminalQuery::new();
2. 查询终端尺寸
match term_query.get_terminal_size() {
Ok((cols, rows)) => println!("终端尺寸: {}列 x {}行", cols, rows),
Err(e) => eprintln!("获取终端尺寸失败: {}", e),
}
3. 获取光标位置
match term_query.get_cursor_position() {
Ok((x, y)) => println!("光标位置: (列:{}, 行:{})", x, y),
Err(e) => eprintln!("获取光标位置失败: {}", e),
}
4. 设置光标位置
// 将光标移动到第5列第10行
if let Err(e) = term_query.set_cursor_position(5, 10) {
eprintln!("设置光标位置失败: {}", e);
}
高级用法
1. 异步查询终端属性
use xterm_query::AsyncTerminalQuery;
use tokio::runtime::Runtime;
let rt = Runtime::new().unwrap();
let async_query = AsyncTerminalQuery::new();
rt.block_on(async {
match async_query.get_terminal_size().await {
Ok((cols, rows)) => println!("异步获取终端尺寸: {}x{}", cols, rows),
Err(e) => eprintln!("错误: {}", e),
}
});
2. 检测终端功能支持
match term_query.supports_truecolor() {
Ok(true) => println!("终端支持真彩色"),
Ok(false) => println!("终端不支持真彩色"),
Err(e) => eprintln!("检测失败: {}", e),
}
3. 处理ANSI转义序列
use xterm_query::ansi::AnsiParser;
let parser = AnsiParser::new();
let output = "\x1b[32mHello\x1b[0m \x1b[1;31mWorld!\x1b[0m";
for event in parser.parse(output) {
match event {
xterm_query::ansi::AnsiEvent::Text(text) => print!("{}", text),
xterm_query::ansi::AnsiEvent::ControlSeq(seq) => {
println!("检测到控制序列: {:?}", seq)
},
}
}
实际应用示例
构建一个简单的终端进度条
use xterm_query::TerminalQuery;
use std::time::Duration;
use std::thread;
fn progress_bar(term_query: &TerminalQuery, length: usize) {
if let Ok((width, _)) = term_query.get_terminal_size() {
let bar_length = width as usize - 10; // 留出空间给百分比
for i in 0..=100 {
let progress = (bar_length * i / 100).max(1);
let bar = "=".repeat(progress) + &" ".repeat(bar_length - progress);
print!("\r[{}] {:3}%", bar, i);
thread::sleep(Duration::from_millis(50));
}
println!();
}
}
fn main() {
let term_query = TerminalQuery::new();
progress_bar(&term_query, 100);
}
完整示例demo
下面是一个综合使用xterm-query功能的完整示例,展示了如何创建终端应用:
use xterm_query::{TerminalQuery, AsyncTerminalQuery};
use xterm_query::ansi::AnsiParser;
use tokio::runtime::Runtime;
use std::time::Duration;
use std::thread;
fn main() {
// 同步API示例
let term_query = TerminalQuery::new();
// 1. 获取终端信息
match term_query.get_terminal_size() {
Ok((cols, rows)) => println!("当前终端大小: {}x{}", cols, rows),
Err(e) => eprintln!("错误: {}", e),
}
// 2. 检测终端功能
match term_query.supports_truecolor() {
Ok(true) => println!("终端支持真彩色"),
Ok(false) => println!("终端不支持真彩色"),
Err(e) => eprintln!("检测失败: {}", e),
}
// 3. 显示进度条
println!("即将显示进度条...");
thread::sleep(Duration::from_secs(1));
fn progress_bar(term_query: &TerminalQuery, length: usize) {
if let Ok((width, _)) = term_query.get_terminal_size() {
let bar_length = width as usize - 10;
for i in 0..=100 {
let progress = (bar_length * i / 100).max(1);
let bar = "=".repeat(progress) + &" ".repeat(bar_length - progress);
print!("\r[{}] {:3}%", bar, i);
thread::sleep(Duration::from_millis(50));
}
println!();
}
}
progress_bar(&term_query, 100);
// 异步API示例
let rt = Runtime::new().unwrap();
let async_query = AsyncTerminalQuery::new();
rt.block_on(async {
// 4. 异步获取光标位置
match async_query.get_cursor_position().await {
Ok((x, y)) => println!("\n当前光标位置: ({}, {})", x, y),
Err(e) => eprintln!("错误: {}", e),
}
// 5. 解析ANSI转义序列
let parser = AnsiParser::new();
let colored_text = "\x1b[32m绿色\x1b[0m \x1b[1;34m加粗蓝色\x1b[0m";
println!("\n解析ANSI转义序列:");
for event in parser.parse(colored_text) {
match event {
xterm_query::ansi::AnsiEvent::Text(text) => print!("{}", text),
xterm_query::ansi::AnsiEvent::ControlSeq(seq) => {
print!("[ANSI控制序列]");
},
}
}
println!();
});
println!("\n演示结束!");
}
注意事项
- 在Windows平台上可能需要启用ANSI支持
- 某些终端模拟器可能不支持所有查询功能
- 在复杂终端环境中建议添加错误处理
- 使用异步API时确保运行在正确的异步上下文中
xterm-query库通过提供简洁的API简化了终端交互编程,使得开发者可以专注于业务逻辑而不是底层终端协议的细节处理。