Rust终端查询工具xterm-query的使用:高效处理终端输入与输出的插件库

Rust终端查询工具xterm-query的使用:高效处理终端输入与输出的插件库

介绍

xterm-query是一个低级别库,用于通过CSI序列查询终端并将结果作为字符串获取。

注意事项:

  • 终端必须已经处于原始模式(raw mode)
  • 不支持Windows系统(理论上可以通过WSAPoll实现,但需要贡献者提交PR)

MIT Latest Version docs

安装

在项目目录中运行以下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(())
}

注释说明:

  1. query函数发送CSI序列到终端并等待响应
  2. 示例中的CSI序列是专门用于查询Kitty图形协议支持的
  3. 响应将以字符串形式返回

更完整的示例

下面是一个更完整的示例,包含进入和退出原始模式的处理:

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(())
}

注释说明:

  1. 使用termion库处理原始模式
  2. into_raw_mode()进入原始模式
  3. 查询终端识别码(ESC [0c)
  4. 通过丢弃原始模式句柄恢复终端设置

完整示例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演示结束!");
}

注意事项

  1. 在Windows平台上可能需要启用ANSI支持
  2. 某些终端模拟器可能不支持所有查询功能
  3. 在复杂终端环境中建议添加错误处理
  4. 使用异步API时确保运行在正确的异步上下文中

xterm-query库通过提供简洁的API简化了终端交互编程,使得开发者可以专注于业务逻辑而不是底层终端协议的细节处理。

回到顶部