rust 终端显示综合例程

文章目录

  • demo程序
  • [1 terminal_size](#1 terminal_size)
  • [2 term_grid](#2 term_grid)
  • [3 crossterm](#3 crossterm)
    • [3.1 style](#3.1 style)
  • [4 lscolors](#4 lscolors)
  • [5 users](#5 users)
    • [5.1 获取用户/用户组信息](#5.1 获取用户/用户组信息)
    • [5.2 通过缓存获取](#5.2 通过缓存获取)

demo程序

综合demo
各个库使用demo

1 terminal_size

一个获取终端界面大小的库,支持linux、macos、windows。该库比较简洁,只有2个结构体和2个方法

rust 复制代码
// Height
pub struct Height(pub u16);

// Width
pub struct Width(pub u16);

// terminal_size
pub fn terminal_size() -> Option<(Width, Height)>

// terminal_size_using_fd
// 如果可用,则使用给定的文件描述符返回终端的大小。
// 如果给定的文件描述符不是 tty,则返回None
pub fn terminal_size_using_fd(fd: RawFd) -> Option<(Width, Height)>

使用示例

rust 复制代码
use terminal_size::{Width, Height, terminal_size};

pub fn terminal_size_test(){
    let size = terminal_size();
    if let Some((Width(w), Height(h))) = size {
        println!("Your terminal is {} cols wide and {} lines tall", w, h);
    } else {
        println!("Unable to get terminal size");
    }
}

参考链接

2 term_grid

该库以适合固定宽度字体的网格格式排列文本数据,并使用算法最小化所需空间

参考链接:https://docs.rs/term_grid/latest/term_grid/

示例:

rust 复制代码
use term_grid::{Grid, GridOptions, Direction, Filling, Cell};

pub fn term_grid_test(){
    let mut grid = Grid::new(GridOptions {
        filling:    Filling::Spaces(1),             // 列与列之间的分隔
        direction:  Direction::LeftToRight,         // 方向
    });

    for s in &["one", "two", "three", "four", "five", "six", "seven",
            "eight", "nine", "ten", "eleven", "twelve"]
    {
        grid.add(Cell::from(*s));   // 添加显示内容
    }

    println!("{}", grid.fit_into_width(24).unwrap());   // 显示,设置屏幕宽度 还有一种方式是设置显示列数
}
  1. Cell

    1)字段:

    rust 复制代码
    contents:String //需要显示的内容
    width:Width		//字符串长度
  2. GridOption

    传递给Grid::new()网格试图的用户可分配选项

    1)字段

    rust 复制代码
    direction:Direction	// 单元格写入方向
    filling:Filling		// 单元格之间的空格数

    direction:LeftToRight(从左到右)

    ​ TopToBottpm(从上到下)

    Filling:Spaces(Width) 空格宽度

    ​ Text(String) 字符串

  3. gird

    使用网格选项来格式化单元格所需的一切

    1)方法:

    rust 复制代码
    // 创建新的网格视图
    fn new(options: GridOptions) -> Self
    
    // 在向量中保留空间以容纳要添加的给定数量的额外单元
    fn reserve(&mut self, additional: usize)
    
    // 讲一个单元格添加至向量
    fn add(&mut self, cell: Cell)
    
    // 返回可现实的网格,该网格已被打包以适合给定的宽度和最少的行数。
    // None如果任何单元格的宽度大于最大宽度,则返回。
    fn fit_into_width(&self, maximum_width: Width) -> Option<Display>
    
    // 返回具有给定列数且没有最大宽度的可显示网格。
    fn fit_into_columns(&self, num_columns: usize) -> Display
  4. 使用示例

    rust 复制代码
    use term_grid::{Grid, GridOptions, Direction, Filling, Cell};
    
    pub fn term_grid_test(){
        let mut grid = Grid::new(GridOptions {
            filling:    Filling::Spaces(2),             // 列与列之间的分隔
            direction:  Direction::LeftToRight,         // 方向
        });
    
        for s in &["one", "two", "three", "four", "five", "six", "seven",
                "eight", "nine", "ten", "eleven", "twelve", "111", "222","333", 
                "444","555", "666", "777", "888", "999","aaa"]
        {
            grid.add(Cell::from(*s));   // 添加显示内容
        }
    
        // 显示,设置屏幕宽度 还有一种方式是设置显示列数
        let print_str = grid.fit_into_columns(1);		// 设置显示列数
        // let print_str = grid.fit_into_width(14).unwrap();	// 设置显示宽度
        println!("{}", print_str);
    }
    
    // 通过ansi形式显示,可以带颜色显示
    pub fn term_grid_ansi(){
        let mut grid = Grid::new(GridOptions {
            filling:    Filling::Spaces(1),             // 列与列之间的分隔
            direction:  Direction::LeftToRight,         // 方向
        });
    
        let cell: Cell = Cell{
            width:20,        // 预先计算的字符串宽度
            contents:String::from("\u{1b}[38;5;105m\u{f001} tests\u{1b}[39m"),
        };
        let cell2: Cell = Cell{
            width:20,        // 预先计算的字符串宽度
            contents:String::from("\u{1b}[38;5;105m\u{f001} hello\u{1b}[39m"),
        };
    
    
        grid.add(cell);   // 添加显示内容
        grid.add(cell2);
    
        // println!("{}", grid.fit_into_width(14).unwrap());   // 显示,设置屏幕宽度 还有一种方式是设置显示列数
        let print_str = grid.fit_into_columns(1).to_string();
        println!("{}", print_str);
    }

3 crossterm

跨平台终端操作库,纯rust库,可以编写跨平台的基于文本的界面。

参考链接:https://docs.rs/crossterm/latest/crossterm/style/index.html

主要作用:

  1. 可以设置终端显示颜色

1)模块

  • 光标模块(cursor):一个处理终端游标的模块
    • 可见性
    • 外貌
    • 位置
  • 事件模块(envent):读取事件的模块。
    • 键盘事件
    • 鼠标事件
  • 风格模块(style):一个在文本上应用属性和颜色的模块。(主要使用的模块)
    • 颜色
    • 属性
  • 终端模块(terminal):一个与终端一起工作的模块。
    • 滚动
    • 各种各样
    • 备用个屏幕

2)命令执行方式

  • 惰性执行:将字节刷新到终端缓冲区是一项反锁的系统调用。如果我们使用终端执行大量操作,我们希望定期执行此操作(例如使用 TUI 编辑器),以便我们可以同时将更多数据刷新到终端缓冲区
  • 直接执行:直接刷新缓冲区

3.1 style

用到的三个模块

contentStyle:可以放在内容上的样式。

Colors :颜色 可以解析ANSI格式

attribues:属性

rust 复制代码
use crossterm::style::{style, Attribute, Attributes, Color, ContentStyle, StyledContent, Stylize};
use crossterm::style::Color::AnsiValue;

// 设置显示内容的背景色
pub fn display_color() {
    let styled = "Hello there"
    .with(Color::Yellow)        // 文本颜色
    .on(Color::Blue)            // 背景颜色
    .attribute(Attribute::Dim);     // 降低文本强度 加强文本就是给显示内容加粗

    println!("{}", styled);
}

// 使用apply方法
pub fn termial_apply() {
    let style = ContentStyle{
        foreground_color: Some(Color::Yellow),
        background_color:Some(Color::Blue),
        ..ContentStyle::default()
    };
    let hello = style.apply("hello world");
    println!("{}", hello);
}

// 字符串转换成ansi格式
pub fn str_to_ansi() {
    let mut strings: Vec<String> = Vec::new();
    let mut block = Vec::new();

    let style = ContentStyle {
                foreground_color: Some(AnsiValue(105)),
                background_color: None,
                underline_color: None,
                // attributes: Attributes(0),
                attributes:Attributes::default(),
            };
    let hello = style.apply(String::from("\u{f0668} tests"));
    println!("{:#?}", hello.to_string());   // 转换为ansi格式


    block.push(hello);

    strings.push(
        block
            .into_iter()
            .map(|s| s.to_string())
            .collect::<Vec<String>>()
            .join(""),
    );

    println!("string {:?}", strings);
}

4 lscolors

根据LS_COLORS环境变量为路径着色的库。

参考链接

准备内容

  1. ANSI

    ANSI转义码是一组控制码,用于再文本中添加格式化和颜色,这些码已ESC字符为开头,通常是\x1b\033\e开始(都是exc), 后面紧跟一系列参数和指令。在ANSI标准中,这些码通常用于控制终端的文本输出。是否支持ANSI格式显示 和显示终端有关(putty就可以支持ANSI格式显示)。

  2. 示例:

    bash 复制代码
    echo -e "\e[37;44;3;1mLYL\e[0m"

    \e:开始ANSI

    [:转移序列开始字符

    37;44;3;1:已;分割,37(前景色) 44(背景色) 3(斜体) 1(加粗)

    m:结束控制符序列

    LYL:显示的内容

    \e[0m:重置文本样式

    执行结果:

  3. 颜色列表

    https://blog.csdn.net/linux_rm/article/details/129477692

  4. ANSI转义码:https://en.wikipedia.org/wiki/ANSI_escape_code

4.1 LsColors

根据环境变量为路径着色

保存着如何为不同文件系统着色/设置样式的信息

  1. 初始化LsColors方法

    rust 复制代码
    fn empty()->Self	// 创建一个空的LsColors
    fn from_env()->Option<Self>		// 从LS_COLORS环境变量创建一个新的LsColors实例
    fn from_string(input:&str)->Self	// 从字符串创建一个LsColors
  2. 获取style(ANSI字体风格)方法

    rust 复制代码
    fn style_for_path <P:AsRef <Path>> ( &self,path:P) -> Option <& Style >			// 获取给定路径的ANSI样式
    fn style_for<F: Colorable>(&self, file: &F) -> Option<&Style>	// 获取可着色路径的ANSI样式
    fn style_for_str(&self, file_str: &str) -> Option<&Style>		//获取字符串的 ANSI 样式。
    fn style_for_path_with_metadata<P: AsRef<Path>>(
        &self,
        path: P,
        metadata: Option<&Metadata>
    ) -> Option<&Style>				// 给定相应的结构,获取路径的 ANSI 样式Metadata。
    fn style_for_path_components<'a>(
        &'a self,
        path: &'a Path
    ) -> StyledComponents<'a> 		// 获取给定路径的每个组件的 ANSI 样式。组件已包含路径分隔符(如果需要)。对于类似这样的路径foo/bar/test.md,这将返回三个路径组件的三对迭代器foo/,bar/以及test.md 它们各自的样式。
    fn style_for_indicator(&self, indicator: Indicator) -> Option<&Style>		// 获取某个Indicator(常规文件、目录、符号链接等)的 ANSI 样式
  3. 简单使用示例

    1. 通过indicator设置颜色

      rust 复制代码
      use lscolors::{LsColors, Indicator, Style}; // 假设的库和模块路径  
      
      pub fn lscolor_indicator() {  
          // 初始化 Lscolors 实例,通常从环境变量或配置文件中加载  
          let lscolors = LsColors::from_env().unwrap_or_default();  
        
          // 假设我们有一些指示器(通常是文件名的一部分或属性)  
          let indicators = ["di", "ln", "so", "pi", "ex", "bd", "cd", "su", "sg", "tw", "ow", "st", "ow", "*"];  
        
          // 遍历指示器并打印相应的颜色样式  
          for indicator in indicators { 
              let indr= lscolors::Indicator::from(indicator).unwrap();  
              let style = lscolors.style_for_indicator(indr);     // 设置前景色、背景色、下划线、字体样式  不同风格的系统颜色不同,字体样式也不相同
              // println!("Indicator: {}, Style: {:#?}", indicator, style);  
        
              // 如果我们有一个字符串想要应用这个样式,可以这样做(这里仅示例,实际可能需要一个库来处理 ANSI 样式)  
              let sample_text = "Sample Text";  
              // let styled_text = format!("\x1b[{:#?}m{}\x1b[0m", style, sample_text);  
              // print!("{}", styled_text); // 注意:在某些环境中可能需要特殊处理才能看到颜色  
      
              let ansi_style = style.map(Style::to_nu_ansi_term_style).unwrap_or_default();   // 转换成nu_ansi_term库中的风格
              println!("{}  {}", indicator,ansi_style.paint(sample_text));    // 绘制给定文本 返回ansi字符串     
          }  
      }
    2. 通过文件类型显示不同颜色

      rust 复制代码
      pub fn lscolor_path() {
          let lscolors = LsColors::from_env().unwrap_or_default();
      
          // let path = "some/folder/archive.zip";
          // let path = "some/folder/archive.txt";
          let path = "some/folder/archive.rs";
          let style = lscolors.style_for_path(path);
      
          // If you want to use `nu_ansi_term`:
          let ansi_style = style.map(Style::to_nu_ansi_term_style).unwrap_or_default();
          println!("{}", ansi_style.paint(path));
      
      }

5 users

这是一个用于获取Unix用户和组信息的库。它支持获取系统用户

在Unix中,每个用户都有一个单独的用户ID,每个进程都有一个有效的用户ID,表明它正在使用哪个用户的权限。此外,用户可以是组的成员,组也有名称和id。

此功能在C标准库libc中公开,但作为不安全的Rust接口。这个包装器库提供了一个安全的接口,使用User和Group类型和函数,如get_user_by_uid,而不是低级指针和字符串。它还提供基本的缓存功能。它(还)提供编辑功能;返回值为只读。

参考链接

5.1 获取用户/用户组信息

要是用0.11.3版本,0.11.0 版本的group有问题

rust 复制代码
pub fn get_user_name() {
    // 方式1
    // let user = get_user_by_uid(get_current_uid()).unwrap();
    // println!("当前用户为 {}", user.name().to_string_lossy());

    // 方式2
    // 使用get_current_user_name
    let user_name = get_current_username().unwrap();
    println!("当前用户为:{}", user_name.into_string().unwrap())
}

pub fn get_group_name() {
    // let group = get_group_by_gid(get_current_gid()).unwrap();
    // println!("当前用户组为 {}", group.name().to_string_lossy());

    // 使用get_current_user_name
    let group_name = get_current_username().unwrap();
    println!("当前用户组为:{}", group_name.into_string().unwrap())
}

5.2 通过缓存获取

由于users表更改的频率非常低,因此对于短时间运行的程序来说,通常会缓存结果,而不是每次都获取最新的条目。UsersCache类型对此有所帮助,它提供了与此crate中的其他方法具有相同名称的方法,只有它们存储结果。

rust 复制代码
// 通过缓存方式获取
pub struct Cache {
    user:UsersCache,
    group:UsersCache,
}

impl Cache {
    fn new() -> Self{
        let user = UsersCache::new();
        let group = UsersCache::new();

        Self{
            user,
            group,
        }
    }
}

pub fn get_ug_name() {
    let name= Cache::new();

    let user = name.user.get_user_by_uid(get_current_uid()).unwrap();
    let group = name.group.get_group_by_gid(get_current_gid()).unwrap();

    let user_name = user.name().to_string_lossy();
    let group_name = group.name().to_string_lossy();

    println!("user name:{}", user_name);
    println!("group name:{}", group_name);
}
相关推荐
电饭叔1 小时前
《python程序语言设计》2018版第5章第52题利用turtle绘制sin函数
开发语言·python
weixin_452600691 小时前
如何为老化的汽车铅酸电池充电
开发语言·单片机·安全·汽车·电机·电源模块·充电桩
Java资深爱好者2 小时前
如何在std::map中查找元素
开发语言·c++
YCCX_XFF212 小时前
ImportError: DLL load failed while importing _imaging: 操作系统无法运行 %1
开发语言·python
哥廷根数学学派3 小时前
基于Maximin的异常检测方法(MATLAB)
开发语言·人工智能·深度学习·机器学习
杰哥在此4 小时前
Java面试题:讨论持续集成/持续部署的重要性,并描述如何在项目中实施CI/CD流程
java·开发语言·python·面试·编程
Unity打怪升级4 小时前
Laravel: 优雅构建PHP应用的现代框架
开发语言·php·laravel
C.C5 小时前
java IO流(1)
java·开发语言
爱分享的码瑞哥5 小时前
Rust 进阶教程
开发语言·windows·rust
Struggle to dream5 小时前
Python编译器的选择
开发语言·python