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)]