diff --git a/README.md b/README.md index 799d928..b40a0f1 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,10 @@ The intent is to show the output of Nushell commands in a GUI. - `src/color_utils.rs`: shared color/style helper utilities. - `src/table_data.rs`: shared table model passed between conversion and GUI layers. - `src/value_conv/`: Nushell value conversion pipeline. - - `mod.rs`: public conversion API and tests. - - `closure.rs`: closure source extraction/highlighting helpers. - - `stringify.rs`: value-to-display-string conversion. - - `table.rs`: table-shaping logic from incoming pipeline data. + - `mod.rs`: public conversion API and tests. + - `closure.rs`: closure source extraction/highlighting helpers. + - `stringify.rs`: value-to-display-string conversion. + - `table.rs`: table-shaping logic from incoming pipeline data. - `src/gui.rs`: primary GUI view/delegate, interactions, and app runtime glue. - `src/gui_ansi.rs`: ANSI segment parsing for colored text rendering in cells. - `src/window_sizing.rs`: initial window-size calculation logic. @@ -52,35 +52,51 @@ The intent is to show the output of Nushell commands in a GUI. ```mermaid flowchart TD - A["Nushell pipeline input
example command: ls | to gui"] --> B[src/main.rs
serve plugin] - B --> C[src/plugin_command.rs
ToGuiCommand::run] - - C --> D[src/value_conv/table.rs
values_to_table_*] - C --> E[src/value_conv/stringify.rs
value_to_string_with_engine] - C --> F[src/value_conv/closure.rs
collect_closure_sources_*] - C --> G[src/color_config.rs
build_runtime_color_config] - - D --> H[src/table_data.rs
TableData] - E --> H - F --> I[closure source cache] - G --> J[ColorConfig] - - H --> K[src/gui.rs
run_table_gui] - I --> K - J --> K - - K --> L[src/window_sizing.rs
ideal_window_size] - K --> M[src/gui_ansi.rs
parse_ansi_segments] - K --> N[Interactive table window] - - N --> O[Sort / filter / copy cell] - N --> P[Double-click nested values] - P --> D - N --> Q[Save as JSON] + A["Nushell pipeline input
example command: ls | to gui"] --> B[src/main.rs
serve plugin] + B --> C[src/plugin_command.rs
ToGuiCommand::run] + + C --> D[src/value_conv/table.rs
values_to_table_*] + C --> E[src/value_conv/stringify.rs
value_to_string_with_engine] + C --> F[src/value_conv/closure.rs
collect_closure_sources_*] + C --> G[src/color_config.rs
build_runtime_color_config] + + D --> H[src/table_data.rs
TableData] + E --> H + F --> I[closure source cache] + G --> J[ColorConfig] + + H --> K[src/gui.rs
run_table_gui] + I --> K + J --> K + + K --> L[src/window_sizing.rs
ideal_window_size] + K --> M[src/gui_ansi.rs
parse_ansi_segments] + K --> N[Interactive table window] + + N --> O[Sort / filter / copy cell] + N --> P[Double-click nested values] + P --> D + N --> Q[Save as JSON] ``` ## Getting Started +### Nerd Font support + +If any Nerd Font is installed on your system, glyph icons from tools like `eza` or `lsd` will render automatically with no configuration needed. We prefer `font-symbols-only-nerd-font` as it is the lightest option and only contains the symbols. + +Installation commands: + +- **macOS:** `brew install --cask font-symbols-only-nerd-font` +- **Windows (Scoop, user install, no admin required):** + + ```powershell + scoop bucket add nerd-fonts + scoop install nerd-fonts/NerdFontsSymbolsOnly + ``` + +- **Linux:** Install via your distro package manager or download from [https://www.nerdfonts.com/font-downloads](https://www.nerdfonts.com/font-downloads). + ### Platform prerequisites #### Linux @@ -90,21 +106,23 @@ On Linux and FreeBSD, the build performs an early dependency check and reports m If both `WAYLAND_DISPLAY` and `DISPLAY` are present and Wayland initialization fails, `to gui` automatically retries with X11. Set `TO_GUI_FORCE_WAYLAND=1` to disable this fallback. - install development packages for XCB and XKB before building. - - Debian/Ubuntu: `sudo apt install libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev` - - Fedora: `sudo dnf install libxcb-devel libxkbcommon-devel libxkbcommon-x11-devel` - - Arch: `sudo pacman -S libxcb libxkbcommon xorg-xkbcommon` + - Debian/Ubuntu: `sudo apt install libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev` + - Fedora: `sudo dnf install libxcb-devel libxkbcommon-devel libxkbcommon-x11-devel` + - Arch: `sudo pacman -S libxcb libxkbcommon xorg-xkbcommon` #### MacOS On macOS, this project enables `gpui` runtime shader compilation (`runtime_shaders`) to avoid requiring the separate Metal Toolchain component during `cargo build`. - - Install Xcode Command Line Tools: `xcode-select --install` - - If prompted, open Xcode once and accept the license. +- Install Xcode Command Line Tools: `xcode-select --install` +- If prompted, open Xcode once and accept the license. #### Windows + - use the MSVC Rust target (`x86_64-pc-windows-msvc`) with Visual Studio Build Tools. ### Building + 1. Clone the repository and ensure you have Rust installed (edition 2024). 2. Run `cargo build` to compile the project or `cargo install --path .`. Dependencies are fetched from the Nushell GitHub repo. 3. Register the plugin with `plugin add /path/to/nu_plugin_to_gui`. @@ -115,5 +133,4 @@ On macOS, this project enables `gpui` runtime shader compilation (`runtime_shade _Note:_ the project is in early development and primarily intended for internal tooling or experimentation. - Feel free to open issues or contribute enhancements. diff --git a/src/gui.rs b/src/gui.rs index d328737..d0746fc 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -158,6 +158,8 @@ pub struct NushellTableDelegate { right_clicked_col: Option, /// Last clicked column index (used by double-click drilldown without forcing table scroll). last_clicked_col: Option, + /// Nerd Font family to use for fallback rendering. + nerd_font_family: Option, } impl NushellTableDelegate { @@ -166,6 +168,7 @@ impl NushellTableDelegate { autosize: bool, color_config: ColorConfig, column_filter_inputs: Vec>, + nerd_font_family: Option, ) -> Self { let num_cols = data.columns.len(); let count = data.rows.len(); @@ -217,6 +220,7 @@ impl NushellTableDelegate { column_filter_inputs, right_clicked_col: None, last_clicked_col: None, + nerd_font_family, } } @@ -490,6 +494,15 @@ impl TableDelegate for NushellTableDelegate { let mut has_ansi_segments = false; let mut div = gpui::div().size_full(); + + // Apply Nerd Font fallbacks if available + if let Some(ref font_family) = self.nerd_font_family { + div = div.font(gpui::Font { + fallbacks: Some(gpui::FontFallbacks::from_fonts(vec![font_family.clone()])), + ..gpui::font(".SystemUIFont") + }); + } + if let Some(segments) = parse_ansi_segments(&text) { has_ansi_segments = true; let mut text_row = gpui::div().h_flex().gap_0().w_full(); @@ -609,6 +622,7 @@ struct ViewSettings { closure_sources: Arc>, table_config: Arc, rfc3339: bool, + nerd_font_family: Option, } impl ToGuiView { @@ -622,7 +636,11 @@ impl ToGuiView { closure_sources, table_config, rfc3339, + nerd_font_family, } = launch; + let nerd_font_family = nerd_font_family.or_else(|| { + crate::nerd_glyphs::find_nerd_font_family(&cx.text_system().all_font_names()) + }); let root_data = table_data.clone(); let closure_sources = Arc::new(closure_sources); @@ -633,6 +651,7 @@ impl ToGuiView { closure_sources: closure_sources.clone(), table_config: table_config.clone(), rfc3339, + nerd_font_family, }); let (fi, ts) = Self::build_page(window, cx, &table_data, initial_filter, &settings); @@ -754,6 +773,7 @@ impl ToGuiView { settings.autosize, settings.color_config.clone(), col_inputs, + settings.nerd_font_family.clone(), ); let ts = cx.new(|cx| { @@ -1242,6 +1262,7 @@ pub fn run_table_gui(launch: GuiLaunch) -> Result<()> { closure_sources, table_config, rfc3339, + nerd_font_family, } = launch; let app = build_app()?; @@ -1251,6 +1272,11 @@ pub fn run_table_gui(launch: GuiLaunch) -> Result<()> { app.run(move |cx| { gpui_component::init(cx); + + let nerd_font_family2 = nerd_font_family.clone(); + if let Some(ref name) = nerd_font_family2 { + eprintln!("to-gui: using Nerd Font family: {name}"); + } Theme::change(ThemeMode::Dark, None, cx); cx.activate(true); @@ -1382,20 +1408,21 @@ pub fn run_table_gui(launch: GuiLaunch) -> Result<()> { let cc = color_config.clone(); let save_dir = save_dir.clone(); let view = cx.new(|cx| { - ToGuiView::new( - window, - cx, - GuiLaunch { - table: table.clone(), - initial_filter: initial_filter.clone(), - autosize, - color_config: cc, - save_dir, - closure_sources: closure_sources2, - table_config: table_config2, - rfc3339: rfc3339_2, - }, - ) + ToGuiView::new( + window, + cx, + GuiLaunch { + table: table.clone(), + initial_filter: initial_filter.clone(), + autosize, + color_config: cc, + save_dir, + closure_sources: closure_sources2, + table_config: table_config2, + rfc3339: rfc3339_2, + nerd_font_family: nerd_font_family2, + }, + ) }); cx.new(|cx| Root::new(view, window, cx)) })?; diff --git a/src/gui_dispatch.rs b/src/gui_dispatch.rs index 6f87e03..a36b92a 100644 --- a/src/gui_dispatch.rs +++ b/src/gui_dispatch.rs @@ -17,6 +17,7 @@ pub struct GuiLaunch { pub closure_sources: HashMap, pub table_config: Config, pub rfc3339: bool, + pub nerd_font_family: Option, } static GUI_REQUEST_TX: OnceLock> = OnceLock::new(); diff --git a/src/lib.rs b/src/lib.rs index b8367fa..f4d99e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod gui; pub mod gui_ansi; #[cfg(not(test))] pub mod gui_dispatch; +pub mod nerd_glyphs; pub mod plugin_command; pub mod table_data; pub mod value_conv; diff --git a/src/nerd_glyphs.rs b/src/nerd_glyphs.rs new file mode 100644 index 0000000..30d162f --- /dev/null +++ b/src/nerd_glyphs.rs @@ -0,0 +1,14 @@ +pub fn find_nerd_font_family(font_names: &[String]) -> Option { + let priorities: &[&str] = &[ + "Symbols Nerd Font Mono", + "Symbols Nerd Font", + "Nerd Font Mono", + "Nerd Font", + ]; + for pattern in priorities { + if let Some(name) = font_names.iter().find(|n| n.contains(pattern)) { + return Some(name.clone()); + } + } + None +} diff --git a/src/plugin_command.rs b/src/plugin_command.rs index 100cf39..b5aadb5 100644 --- a/src/plugin_command.rs +++ b/src/plugin_command.rs @@ -88,6 +88,7 @@ impl PluginCommand for ToGuiCommand { closure_sources, table_config: (*nu_config).clone(), rfc3339, + nerd_font_family: None, }; #[cfg(test)]