鏈接:https://github.com/sharkdp/bat
前文傳送:
- 【探索Linux命令行】從基礎指令到高級管道操作的介紹與實踐
- 【Linux命令行】從時間管理->文件查找壓縮的指令詳解
- 【Linux】1w詳解如何實現一個簡單的shell
docs:bat
bat
是一個**命令行文件查看器
**,能夠美化代碼和文本文件。
它的工作原理是接收原始輸入,智能地檢測編程語言,然后應用生動的語法高亮和其他視覺裝飾(如行號或 Git 變更)。
最終,增強后的輸出會*直接顯示或通過分頁器(如 less
)*輸出,從而提供更好的查看體驗。
可視化
章節
- 控制器
- 輸入管理
- 輸出處理
- 配置 (Config)
- 高亮資源
- 語法映射
- 行范圍處理
- 打印器
第一章:控制器
歡迎來到 bat
🐻???
如果你想通過漂亮的語法高亮、行號等功能讓你的代碼和文本文件更加清晰,那么你來對地方了ovo。
在這第一章中,我們將介紹“控制器”,它是 bat
強大顯示功能背后的核心大腦。
控制器解決了什么問題?
假設我們有一個純文本文件,比如一個 Python 腳本,我們想在屏幕上顯示它。不僅僅是原始文本,而是帶有各種裝飾效果:不同關鍵詞的鮮艷顏色、清晰的行號,甚至可能還有版本控制中的變更標記。如何從一個簡單的文本文件變成這樣豐富、視覺上吸引人的輸出呢?
這就是控制器的作用!它就像是整個顯示操作的項目經理。我們告訴它想要顯示哪些文件以及如何顯示(我們的“配置”),然后控制器負責確保一切正確執行。
本章的目標是理解控制器如何協調這一過程,將一個簡單的文件準備好,以便進行漂亮的顯示。
控制器:我們的項目經理
控制器本身并不直接執行高亮或行號添加。相反,它協調所有其他專業化的組件。可以將其視為:
- 協調者:確保從讀取文件到最終顯示的每一步都按正確順序進行。
- 指揮官:根據我們的設置告訴其他組件該做什么。
- 錯誤處理者:如果出現問題(例如文件無法找到),控制器會捕獲錯誤。
使用控制器
雖然 bat
提供了一個用戶友好的 PrettyPrinter
來處理常見任務,但直接理解 Controller
有助于掌握核心邏輯。讓我們看一個基本示例,展示如何使用 bat
的 Controller
來顯示一個簡單的 Rust 文件。
以下是一個最小化的代碼片段,靈感來自 bat
的示例,直接使用 Controller
將文件內容(這里是 examples/buffer.rs
本身)打印到一個字符串緩沖區:
use bat::{assets::HighlightingAssets, // 管理語法定義和主題config::Config, // 我們的顯示偏好controller::Controller, // 協調者!output::OutputHandle, // 輸出目標Input, // 表示輸入文件
};fn main() {let mut buffer = String::new(); // 輸出將存儲在這里let config = Config {colored_output: true, // 是的,我們需要顏色!..Default::default()};let assets = HighlightingAssets::from_binary(); // 加載內置的高亮信息let controller = Controller::new(&config, &assets); // 創建控制器// 為當前文件創建輸入let input = Input::from_file(file!());// 運行控制器處理并打印輸入controller.run(vec![input.into()], // 提供輸入文件Some(OutputHandle::FmtWrite(&mut buffer)), // 告訴它寫入字符串緩沖區).unwrap();println!("{buffer}"); // 最終打印緩沖區中的結果
}
說明:
- 我們設置了一個名為
buffer
的String
,用于存儲高亮后的輸出。 - 我們創建了一個
Config
對象,其中包含所有偏好設置,比如是否需要彩色輸出。..Default::default()
為其他設置填充默認值。 HighlightingAssets::from_binary()
加載所有內置的語法定義(例如如何高亮 Rust、Python 等)和顏色主題。- 然后,我們使用
Controller::new(&config, &assets)
創建控制器。我們提供偏好設置(config
)和高亮規則(assets
)。 - 我們定義要顯示的內容為
Input
。這里,Input::from_file(file!())
表示我們要求bat
處理包含這段代碼的 Rust 文件! - 最后,
controller.run(...)
是魔法發生的地方。我們給控制器提供input
(要處理的文件),并告訴它將輸出寫入buffer
通過OutputHandle
。
運行這段代碼時,bat
會處理 examples/buffer.rs
文件,根據 Rust 規則和默認主題應用語法高亮,并將格式化后的輸出存儲在 buffer
中,然后打印到控制臺。
控制器內部工作原理
讓我們揭開控制器的面紗,看看調用 controller.run()
時發生了什么。控制器作為我們的項目經理,與多個專業團隊協調完成任務。
以下是簡化的步驟分解:
- 接收請求:我們(程序員)告訴控制器處理一組文件,并提供特定配置。
- 準備輸入:對于每個文件,控制器要求輸入管理團隊讀取其內容。該團隊負責打開文件、從標準輸入讀取,甚至處理字節數組。
- 收集設置:控制器使用我們提供的
Config
(即配置)。Config
包含所有指令:“使用這個顏色主題”、“顯示行號”、“換行長行”等。 - 加載高亮信息:控制器查詢
HighlightingAssets
以找到正確的語法定義(例如,“這是一個 Rust 文件,這是它的關鍵詞和結構”)和選擇的顏色主題。 - 啟動打印機:對于每個輸入文件的每一行,控制器將原始行連同所有配置和高亮規則交給打印機團隊。打印機是實際應用顏色、添加行號并格式化文本的藝術家。
- 定向輸出:打印機的格式化輸出隨后發送到輸出處理。這可能意味著直接寫入終端,或通過分頁程序(如
less
)以便于瀏覽大文件。 - 處理錯誤:如果任何團隊遇到問題(例如文件不可讀),控制器會捕獲并報告。
以下是描述這一流程的序列圖:
深入代碼
讓我們看看 bat
源代碼中控制器的結構。
首先是 Controller
結構體本身(來自 src/controller.rs
):
// src/controller.rs
pub struct Controller<'a> {config: &'a Config<'a>,assets: &'a HighlightingAssets,// ... 其他字段(用于 lessopen 特性的預處理器)
}
說明:
config: &'a Config<'a>
:這是對配置對象的引用,包含用戶的所有偏好設置。控制器需要這些指令來知道如何顯示文件。assets: &'a HighlightingAssets
:這是對HighlightingAssets
的引用,包含所有語法定義和主題。這告訴控制器應用哪些高亮規則和顏色。
接下來是控制器的構造函數(new
)和主要的 run
方法:
// src/controller.rs
impl Controller<'_> {pub fn new<'a>(config: &'a Config, assets: &'a HighlightingAssets) -> Controller<'a> {Controller {config,assets,// ... 初始化其他字段}}pub fn run(&self, inputs: Vec<Input>, output_handle: Option<OutputHandle<'_>>) -> Result<bool> {// ... 設置輸出 ...let mut no_errors: bool = true;for (index, input) in inputs.into_iter().enumerate() {let result = if input.is_stdin() {// 處理標準輸入self.print_input(input, &mut writer, io::stdin().lock(), identifier, is_first)} else {// 處理文件輸入self.print_input(input, &mut writer, io::empty(), identifier, is_first)};if let Err(error) = result {// ... 錯誤處理 ...no_errors = false;}}Ok(no_errors)}fn print_input<R: BufRead>(&self,input: Input,writer: &mut OutputHandle,stdin: R,stdout_identifier: Option<&Identifier>,is_first: bool,) -> Result<()> {let mut opened_input = input.open(stdin, stdout_identifier)?;// ... 可能獲取 git diff ...let mut printer: Box<dyn Printer> = /* ... 創建 InteractivePrinter 或 SimplePrinter ... */;self.print_file(&mut *printer,writer,&mut opened_input,!is_first,// ... line_changes ...)}// ... 其他輔助方法如 print_file, print_file_ranges ...
}
說明:
Controller::new
:這是創建控制器的方式。只需傳遞Config
和HighlightingAssets
。Controller::run
:這是啟動處理的主要方法。- 它準備
output_type
,確定輸出去向(例如直接到終端或通過分頁程序)。這將在輸出處理中進一步討論。 - 然后遍歷每個提供的
Input
文件或流。 - 對于每個輸入,調用
self.print_input
。
- 它準備
Controller::print_input
:此方法處理單個輸入的流程:- 使用輸入管理組件
open
輸入,使其內容可讀。 - 創建一個
printer
(SimplePrinter
或InteractivePrinter
)。printer
是實際根據Config
和HighlightingAssets
對原始文本應用樣式的組件。我們將在打印機章節深入探討。 - 最后調用
self.print_file
,將逐行打印的實際工作委托給選定的printer
。
- 使用輸入管理組件
這表明控制器確實是核心樞紐,將 Config
、HighlightingAssets
、輸入管理、輸出處理和打印機結合在一起完成任務。
結論
在本章中,我們了解到控制器是 bat
項目的核心協調者。
它像項目經理一樣,接收我們的配置和文件列表,然后指導其他專業組件讀取、處理、高亮并漂亮地顯示代碼。雖然它不直接執行細節工作,但其協調角色對 bat
的功能至關重要。
現在我們已經理解了控制器在顯示流程中的協調作用,下一步是了解 bat
如何處理我們想要顯示的文件。在下一章中,我們將深入探討輸入管理,學習 bat
如何高效讀取文件和其他數據源。
下一章:輸入管理