<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          高手過招不用鼠標(biāo),一款超好用的跨平臺命令行界面庫

          共 7037字,需瀏覽 15分鐘

           ·

          2022-03-11 19:27

          e23662e2b3e0014d671937748bde492f.webp

          作者:HelloGitHub-Anthony

          命令行工具是程序員的秘密武器,它們安裝簡單、啟動速度快、界面簡潔,一條指令或者快捷鍵即可完成操作,用完即走深藏不露。

          0db35c53c7d71909be4741b4802fcb9e.webp

          而最趁手的莫過于自己親手打造的!本期 《講解開源項目》 就介紹一個讓你快速擁有完美命令行界面的跨平臺庫—— tui.rs

          ebf4defb1239c41a84ab5fbc9cc6ba0b.webp

          項目地址:https://github.com/fdehau/tui-rs

          官方文檔:https://docs.rs/tui/latest/tui/index.html

          你一定有過這樣的糾結(jié):我的程序需要一個界面,但使用諸如 Qt 等框架又比較繁瑣?,F(xiàn)在 tui.rs 來了,它是 Rust 下的命令行 UI 庫,不僅上手方便內(nèi)置多種組件,而且效果炫酷支持跨平臺使用。

          8ddf86116108b5ac36f5ba7dcc327d77.webp

          輕松實現(xiàn)一份代碼可以無縫運(yùn)行在 Linux/Windows/Mac 之上!

          接下來你不僅可以快速上手 tui.rs,還會收獲多款基于它構(gòu)建的神兵利器!

          一、安裝

          tui.rs 采用 Rust 語言編寫,和所有其他 Rust 依賴的安裝方法一樣,直接在 cargo.toml 中添加依賴即可:

          [dependencies]
          tui = "0.17"
          crossterm = "0.22"

          如果需要官方示例,則直接 clone 官方倉庫:

          $?git?clone?http://github.com/fdehau/tui-rs.git
          $?cd?tui-rs
          $?cargo?run?--example?demo

          二、快速入門

          2.1 一覽芳容

          我們主要使用 tui.rs 提供的以下模塊進(jìn)行 UI 編寫(所有 UI 元素都實現(xiàn)了 WidgetStatefuWidget Trait):

          • bakend ?用于生成管理命令行的后端
          • layout 用于管理 UI 組件的布局
          • style 用于為 UI 添加樣式
          • symbols 描述繪制散點(diǎn)圖時所用點(diǎn)的樣式
          • text 用于描述帶樣式的文本
          • widgets 包含預(yù)定義的 UI 組件

          如下代碼就可以實現(xiàn)一個很簡單的 tui 界面:

          use?crossterm::{
          ????event::{self,?DisableMouseCapture,?EnableMouseCapture,?Event,?KeyCode},
          ????execute,
          ????terminal::{disable_raw_mode,?enable_raw_mode,?EnterAlternateScreen,?LeaveAlternateScreen},
          };
          use?std::{io,?time::Duration};
          use?tui::{
          ????backend::{Backend,?CrosstermBackend},
          ????layout::{Alignment,?Constraint,?Direction,?Layout},
          ????style::{Color,?Modifier,?Style},
          ????text::{Span,?Spans,?Text},
          ????widgets::{Block,?Borders,?Paragraph,?Widget},
          ????Frame,?Terminal,
          };

          struct?App?{
          ????url:?String,?//?存放一些數(shù)據(jù)或者?UI?狀態(tài)
          }
          fn?main()?->?Result<(),?io::Error>?{
          ????//?初始化終端
          ????enable_raw_mode()?;
          ????let?mut?stdout?=?io::stdout();
          ????execute!(stdout,?EnterAlternateScreen,?EnableMouseCapture)?;
          ????let?backend?=?CrosstermBackend::new(stdout);
          ????let?mut?terminal?=?Terminal::new(backend)?;
          ????let?mut?app?=?App?{
          ????????url:?String::from(r"https://hellogithub.com/"),
          ????};
          ????//?渲染界面
          ????run_app(&mut?terminal,?app)?;
          ????//?恢復(fù)終端
          ????disable_raw_mode()?;
          ????execute!(
          ????????terminal.backend_mut(),
          ????????LeaveAlternateScreen,
          ????????DisableMouseCapture
          ????)?;
          ????terminal.show_cursor()?;

          ????Ok(())
          }

          fn?run_app(terminal:?&mut?Terminal,?mut?app:?App)?->?io::Result<()>?{
          ????loop?{
          ????????terminal.draw(|f|?ui(f,?&mut?app))?;
          ????????//?處理按鍵事件
          ????????if?crossterm::event::poll(Duration::from_secs(1))??{
          ????????????if?let?Event::Key(key)?=?event::read()??{
          ????????????????match?key.code?{
          ????????????????????KeyCode::Char(ch)?=>?{
          ????????????????????????if?'q'?==?ch?{
          ????????????????????????????break;
          ????????????????????????}
          ????????????????????}
          ????????????????????_?=>?{}
          ????????????????}
          ????????????}
          ????????}
          ????????//?處理其他邏輯
          ????}
          ????Ok(())
          }
          fn?ui(f:?&mut?Frame,?app:?&mut?App)?{
          ????//
          ????let?chunks?=?Layout::default()?//?首先獲取默認(rèn)構(gòu)造
          ????????.constraints([Constraint::Length(3),?Constraint::Min(3)].as_ref())?//?按照?3?行?和?最小?3?行的規(guī)則分割區(qū)域
          ????????.direction(Direction::Vertical)?//?垂直分割
          ????????.split(f.size());?//?分割整塊?Terminal?區(qū)域
          ????let?paragraph?=?Paragraph::new(Span::styled(
          ????????app.url.as_str(),
          ????????Style::default().add_modifier(Modifier::BOLD),
          ????))
          ????.block(Block::default().borders(Borders::ALL).title("HelloGitHub"))
          ????.alignment(tui::layout::Alignment::Left);
          ????f.render_widget(paragraph,?chunks[0]);

          ????let?paragraph?=?Paragraph::new("分享?GitHub?上有趣、入門級的開源項目")
          ????????.style(Style::default().bg(Color::White).fg(Color::Black))
          ????????.block(Block::default().borders(Borders::ALL).title("宗旨"))
          ????????.alignment(Alignment::Center);
          ????f.render_widget(paragraph,?chunks[1]);
          }
          f07d67f7164255bc754c0ac2e10b0b8d.webp

          這些代碼可能看起來不少,但大部分都是固定的模板,不需要我們每次的重新構(gòu)思。下面,就讓我們來詳細(xì)了解其中的細(xì)節(jié)。

          2.2 創(chuàng)作模板

          官方通過 example 給出了使用 tui.rs 進(jìn)行設(shè)計的模板,我希望各位讀者在使用時也能遵守這套模板以保證程序的可讀性。

          一個使用 tui.rs 程序的一生大概是這樣的:

          2cf811812a4ec5c47d595087c0239c74.webp

          其模塊可以大致分為:

          • app.rs 實現(xiàn) App 結(jié)構(gòu)體,用于處理 UI 邏輯,保存 UI 狀態(tài)
          • ui.rs ? 實現(xiàn) UI 渲染功能

          但對于小型程序來講,也可以都寫在 main.rs 之中。

          首先來看開始和結(jié)束部分關(guān)于 Terminal 的操作,每次運(yùn)行都會保存原始 Terminal 界面內(nèi)容并在一個新的窗體上運(yùn)行,在結(jié)束后又會恢復(fù)到原來的 Terminal 窗體中,有效地防止了搞亂原來的窗口內(nèi)容。這部分代碼模板官方已經(jīng)給出,基本無需修改

          fn?main()?->?Result<(),?io::Error>?{
          ????//?配置?Terminal
          ????enable_raw_mode()?;?//?啟動命令行的?raw?模式
          ????let?mut?stdout?=?io::stdout();
          ????execute!(stdout,?EnterAlternateScreen,?EnableMouseCapture)?;?//?在一個新的界面上運(yùn)行?UI,保存原終端內(nèi)容,并開啟鼠標(biāo)捕獲
          ????let?backend?=?CrosstermBackend::new(stdout);
          ????let?mut?terminal?=?Terminal::new(backend)?;
          ????//?初始化?app?資源
          ????let?mut?app?=?App?{
          ????????url:?String::from(r"https://hellogithub.com/"),
          ????};
          ??//?程序主要邏輯循環(huán)?……?//
          ????run_app(&mut?terminal,?app)?;
          ????//?恢復(fù)?Terminal
          ????disable_raw_mode()?;?//?禁用?raw?模式
          ????execute!(
          ????????terminal.backend_mut(),
          ????????LeaveAlternateScreen,?//?恢復(fù)到原來的命令行窗口
          ????????DisableMouseCapture??//?禁用鼠標(biāo)捕獲
          ????)?;
          ????terminal.show_cursor()?;?//?顯示光標(biāo)

          ????Ok(())
          }

          接下來是處理 UI 邏輯的 run_app 函數(shù),我們在此處理諸如 用戶按鍵、UI 狀態(tài)更改等邏輯

          fn?run_app(terminal:?&mut?Terminal,?mut?app:?App)?->?io::Result<()>?{
          ????loop?{
          ????????//?渲染?UI
          ????????terminal.draw(|f|?ui(f,?&mut?app))?;
          ????????//?處理按鍵事件
          ????????if?crossterm::event::poll(Duration::from_secs(1))??{?//?poll?方法非阻塞輪詢
          ????????????if?let?Event::Key(key)?=?event::read()??{?//?直接?read?如果沒有事件到來則會阻塞等待
          ????????????????match?key.code?{?//?判斷用戶按鍵
          ????????????????????KeyCode::Char(ch)?=>?{
          ????????????????????????if?'q'?==?ch?{
          ????????????????????????????break;
          ????????????????????????}
          ????????????????????}
          ????????????????????_?=>?{}
          ????????????????}
          ????????????}
          ????????}
          ????????//?處理其他邏輯
          ????}
          ????Ok(())
          }

          對于功能簡單的界面來講,這個函數(shù)作用不大。但如果我們的程序需要更新一些組件狀態(tài)(比如列表選中項、用戶輸入、外界數(shù)據(jù)交互等)則應(yīng)在此統(tǒng)一處理。

          之后,我們會使用 terminal.draw() 方法繪制界面,其接受一個閉包:

          fn?ui(f:?&mut?Frame,?app:?&mut?App)?{
          ????//?獲取分割后的窗口
          ????let?chunks?=?Layout::default()?//?首先獲取默認(rèn)構(gòu)造
          ????????.constraints([Constraint::Length(3),?Constraint::Min(3)].as_ref())?//?按照?3?行?和?最小?3?行的規(guī)則分割區(qū)域
          ????????.direction(Direction::Vertical)?//?垂直方向分割
          ????????.split(f.size());?//?分割整塊?Terminal?區(qū)域
          ????let?paragraph?=?Paragraph::new(Span::styled(
          ????????app.url.as_str(),
          ????????Style::default().add_modifier(Modifier::BOLD),
          ????))
          ????.block(Block::default().borders(Borders::ALL).title("HelloGitHub"))
          ????.alignment(tui::layout::Alignment::Left);
          ????f.render_widget(paragraph,?chunks[0]);

          ????let?paragraph?=?Paragraph::new("分享?GitHub?上有趣、入門級的開源項目")
          ????????.style(Style::default().bg(Color::White).fg(Color::Black))
          ????????.block(Block::default().borders(Borders::ALL).title("宗旨"))
          ????????.alignment(Alignment::Center);
          ????f.render_widget(paragraph,?chunks[1]);
          }

          在這里,有如下流程:

          1. 使用 Layout 按照需求給定 Constraint 切分窗體,獲取 chunks,每個 chunk 也可以利用 Layout 繼續(xù)進(jìn)行分割
          2. 實例化組件,每個組件都實現(xiàn)了 default 方法,在使用時我們應(yīng)該先使用 xxx::default() 獲取默認(rèn)對象,再利用默認(rèn)對象更新組件樣式。例如 Block::default().borders(Borders::ALL) 、Style::default().bg(Color::White) 等。這也是官方推薦做法。
          3. 使用 f.render_widget 渲染組件到窗體上,對于類似 列表 等存在狀態(tài)(比如當(dāng)前選中元素)的組件,則使用 f.render_stateful_widget 進(jìn)行渲染

          關(guān)于 tui.rs 其他內(nèi)置組件的使用方法,可以查看官方的 example 文件,編寫套路是一樣的,可以根據(jù)需要直接復(fù)制粘貼

          需要注意到是,在此我們只關(guān)心 UI 組件的顯示方式和內(nèi)容,有關(guān)程序邏輯的內(nèi)容應(yīng)放在 run_app 中處理以免打亂程序架構(gòu)或影響 UI 繪制效果(你總不希望 UI 繪制到一半的時候因為進(jìn)行了某些 IO 操作而卡住了對吧?)

          到這里對于 tui.rs 的介紹就結(jié)束了,實際上使用 tui.rs 編寫 UI 界面很簡單,只要根據(jù)創(chuàng)作模板結(jié)合官方例子一步步構(gòu)建,任何人都可以很快上手。

          三、更多實用工具

          下面將介紹介紹幾款基于 tui.rs 構(gòu)建的流行開源項目,它們無一例外是命令行工具里的“神兵利器“!

          3.1 實時股票數(shù)據(jù)

          支持查看不同時間維度以及交易量等數(shù)據(jù),股票實時數(shù)據(jù)來自雅虎。

          5a04aa079c266e9efc1a8225ae17a85b.webp

          地址:https://github.com/tarkah/tickrs

          3.2 文件傳輸工具

          支持 SCP/SFTP/FTP/S3 功能豐富的終端文件傳輸工具。

          1631e6c3c0aca5f08cf9c28a090a71cd.webp

          地址:https://github.com/veeso/termscp

          3.3 網(wǎng)絡(luò)監(jiān)控工具

          用于按進(jìn)程、連接、遠(yuǎn)程 IP、主機(jī)名顯示當(dāng)前網(wǎng)絡(luò)利用率。

          e5dba251327d637561d4fc9fae5da804.webp

          地址:https://github.com/imsnif/bandwhich

          限于篇幅這里就不介紹其它開源項目了,感興趣的小伙伴可以去項目首頁尋找。

          四、最后

          以上就是本文的所有內(nèi)容,希望您從中有所收獲。

          最后,感謝您的閱讀?。?!

          這里是 HelloGitHub 分享 GitHub 上有趣、入門級的開源項目。您的每個點(diǎn)贊、留言、分享都是對我們最大的鼓勵!

          ?? 關(guān)注「HelloGitHub」第一時間收到更新??

          瀏覽 87
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    亚洲 欧美 中文字幕 | 亚洲污网 | 人人操人人操人人操人人操 | 青娱乐精品在线观看视频 | 免费一区二区三区四区 |