文章目录
- 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)
-
- 准备内容
- [4.1 LsColors](#4.1 LsColors)
- [5 users](#5 users)
-
- [5.1 获取用户/用户组信息](#5.1 获取用户/用户组信息)
- [5.2 通过缓存获取](#5.2 通过缓存获取)
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()); // 显示,设置屏幕宽度 还有一种方式是设置显示列数
}
-
Cell
1)字段:
rustcontents:String //需要显示的内容 width:Width //字符串长度
-
GridOption
传递给
Grid::new()
网格试图的用户可分配选项1)字段
rustdirection:Direction // 单元格写入方向 filling:Filling // 单元格之间的空格数
direction
:LeftToRight(从左到右) TopToBottpm(从上到下)
Filling
:Spaces(Width) 空格宽度 Text(String) 字符串
-
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
-
使用示例
rustuse 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)模块
- 光标模块(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环境变量为路径着色的库。
准备内容
-
ANSI
ANSI
转义码是一组控制码,用于再文本中添加格式化和颜色,这些码已ESC
字符为开头,通常是\x1b
、\033
、\e
开始(都是exc), 后面紧跟一系列参数和指令。在ANSI
标准中,这些码通常用于控制终端的文本输出。是否支持ANSI格式显示 和显示终端有关(putty就可以支持ANSI格式显示)。 -
示例:
bashecho -e "\e[37;44;3;1mLYL\e[0m"
\e
:开始ANSI[
:转移序列开始字符37;44;3;1
:已;
分割,37(前景色) 44(背景色) 3(斜体) 1(加粗)m
:结束控制符序列LYL
:显示的内容\e[0m
:重置文本样式执行结果:
-
颜色列表
4.1 LsColors
根据环境变量为路径着色
保存着如何为不同文件系统着色/设置样式的信息
-
初始化LsColors方法
rustfn empty()->Self // 创建一个空的LsColors fn from_env()->Option<Self> // 从LS_COLORS环境变量创建一个新的LsColors实例 fn from_string(input:&str)->Self // 从字符串创建一个LsColors
-
获取style(ANSI字体风格)方法
rustfn 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 样式
-
简单使用示例
-
通过indicator设置颜色
rustuse 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字符串 } }
-
通过文件类型显示不同颜色
rustpub 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);
}