文章目录
- demo程序
- 1 terminal_size
- 2 term_grid
- 3 crossterm
- 3.1 style
- 4 lscolors
- 准备内容
- 4.1 LsColors
- 5 users
- 5.1 获取用户/用户组信息
- 5.2 通过缓存获取
demo程序
综合demo
各个库使用demo
1 terminal_size
一个获取终端界面大小的库,支持linux、macos、windows。该库比较简洁,只有2个结构体和2个方法
// 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)>
使用示例
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/
示例:
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)字段:
contents:String //需要显示的内容 width:Width //字符串长度
-
GridOption
传递给
Grid::new()
网格试图的用户可分配选项1)字段
direction:Direction // 单元格写入方向 filling:Filling // 单元格之间的空格数
direction
:LeftToRight(从左到右) TopToBottpm(从上到下)
Filling
:Spaces(Width) 空格宽度 Text(String) 字符串
-
gird
使用网格选项来格式化单元格所需的一切
1)方法:
// 创建新的网格视图 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
-
使用示例
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)模块
- 光标模块(cursor):一个处理终端游标的模块
- 可见性
- 外貌
- 位置
- 事件模块(envent):读取事件的模块。
- 键盘事件
- 鼠标事件
- 风格模块(style):一个在文本上应用属性和颜色的模块。(主要使用的模块)
- 颜色
- 属性
- 终端模块(terminal):一个与终端一起工作的模块。
- 滚动
- 各种各样
- 备用个屏幕
2)命令执行方式
- 惰性执行:将字节刷新到终端缓冲区是一项反锁的系统调用。如果我们使用终端执行大量操作,我们希望定期执行此操作(例如使用 TUI 编辑器),以便我们可以同时将更多数据刷新到终端缓冲区
- 直接执行:直接刷新缓冲区
3.1 style
用到的三个模块
contentStyle
:可以放在内容上的样式。
Colors
:颜色 可以解析ANSI格式
attribues
:属性
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格式显示)。 -
示例:
echo -e "\e[37;44;3;1mLYL\e[0m"
\e
:开始ANSI[
:转移序列开始字符37;44;3;1
:已;
分割,37(前景色) 44(背景色) 3(斜体) 1(加粗)m
:结束控制符序列LYL
:显示的内容\e[0m
:重置文本样式执行结果:
-
颜色列表
https://blog.csdn.net/linux_rm/article/details/129477692
-
ANSI转义码:https://en.wikipedia.org/wiki/ANSI_escape_code
4.1 LsColors
根据环境变量为路径着色
保存着如何为不同文件系统着色/设置样式的信息
-
初始化LsColors方法
fn empty()->Self // 创建一个空的LsColors fn from_env()->Option<Self> // 从LS_COLORS环境变量创建一个新的LsColors实例 fn from_string(input:&str)->Self // 从字符串创建一个LsColors
-
获取style(ANSI字体风格)方法
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 样式
-
简单使用示例
-
通过indicator设置颜色
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字符串 } }
-
通过文件类型显示不同颜色
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有问题
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_namelet 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_namelet group_name = get_current_username().unwrap();println!("当前用户组为:{}", group_name.into_string().unwrap())
}
5.2 通过缓存获取
由于users表更改的频率非常低,因此对于短时间运行的程序来说,通常会缓存结果,而不是每次都获取最新的条目。UsersCache类型对此有所帮助,它提供了与此crate中的其他方法具有相同名称的方法,只有它们存储结果。
// 通过缓存方式获取
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);
}