How to Toggle Hiding of Targets with Filters Set to Off in tui-logger

Press the Space key (or programmatically invoke TuiWidgetEvent::SpaceKey) to toggle the visibility of log targets whose filter is set to LevelFilter::Off in the tui-logger widget.

The gin66/tui-logger crate provides interactive log filtering for Rust terminal user interfaces. When your application configures LevelFilter::Off for specific modules, you can declutter the target list by toggling the Hide Off flag, which removes those disabled entries from view without changing their underlying filter configuration.

How the Hide-Off Mechanism Works

tui-logger maintains two distinct visibility toggles. Hide Off controls whether targets with LevelFilter::Off appear in the list, while Hide Target collapses the entire target column.

Toggle Behavior Default Key
Hide Off Omits targets where LevelFilter == Off Space
Hide Target Hides the entire target column, showing only logs h (HideKey)

The Hide Off state is stored in the hide_off field of TuiWidgetInnerState. When you trigger a SpaceKey event, the state machine flips this boolean flag (self.hide_off ^= true). Both the standalone target widget and the composite smart widget read this flag during render to skip drawing filtered-off targets.

Implementation in the Source Code

The toggle logic spans three core files in src/widget/. Understanding these locations helps when customizing behavior or debugging visibility issues.

State Transition in src/widget/inner.rs

The TuiWidgetState handle processes input events in inner.rs. When it receives TuiWidgetEvent::SpaceKey, it toggles the internal flag:

// src/widget/inner.rs, lines 86-88
SpaceKey => {
    self.hide_off ^= true;
}

This mutation affects all widgets sharing the same state handle. The event enum itself is defined earlier in the same file at lines 45-58.

Target Widget Filtering in src/widget/target.rs

The TuiLoggerTargetWidget iterates through registered targets and applies the hide-off logic before rendering. If the flag is enabled and a target's filter equals LevelFilter::Off, the iterator skips that entry:

// src/widget/target.rs, lines 152-155
for (t, levelfilter) in targets.iter() {
    if hide_off && levelfilter == &LevelFilter::Off {
        continue;               // skip targets filtered Off
    }
    self.targets.push(t.clone());
}

This ensures the UI list stays synchronized with the toggle state.

Smart Widget Layout in src/widget/smart.rs

The composite smart widget also respects hide_off when calculating column widths. It filters the target list during layout to avoid allocating space for hidden entries:

// src/widget/smart.rs, lines 62-66
for (t, levelfilter) in targets.iter() {
    if hide_off && levelfilter == &LevelFilter::Off {
        continue;
    }
    width = width.max(t.graphemes(true).count())
}

This prevents layout jitter when toggling the visibility of off-filtered targets.

Practical Usage Examples

You can trigger the toggle either through built-in key handling or direct API calls.

Handling Keyboard Input

If you delegate input to tui-logger's state machine, map the Space key to TuiWidgetEvent::SpaceKey:

use tui_logger::{TuiWidgetState, TuiWidgetEvent};
use crossterm::event::{self, Event, KeyCode};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let state = TuiWidgetState::new();

    loop {
        if let Event::Key(key) = event::read()? {
            match key.code {
                KeyCode::Char(' ') => {
                    // Toggle hiding of Off-filtered targets
                    state.transition(TuiWidgetEvent::SpaceKey);
                }
                KeyCode::Char('h') => {
                    // Toggle visibility of the entire target column
                    state.transition(TuiWidgetEvent::HideKey);
                }
                _ => {}
            }
        }
        
        // Render widgets using the shared state...
    }
}

Programmatic Control

To toggle the setting without user input, invoke the transition directly on your TuiWidgetState instance:

let state = TuiWidgetState::new();

// Hide targets with LevelFilter::Off
state.transition(tui_logger::TuiWidgetEvent::SpaceKey);

// Show them again later
state.transition(tui_logger::TuiWidgetEvent::SpaceKey);

This approach works well when saving or restoring UI preferences from a configuration file.

Summary

  • The Space key toggles hide_off in TuiWidgetInnerState, controlling whether targets with LevelFilter::Off appear in the list.
  • The implementation resides in src/widget/inner.rs (state), src/widget/target.rs (rendering), and src/widget/smart.rs (layout).
  • Call state.transition(TuiWidgetEvent::SpaceKey) to trigger the toggle programmatically.
  • This feature is distinct from the Hide Target toggle (h key), which hides the entire column rather than filtering individual entries.

Frequently Asked Questions

What is the default keyboard shortcut to hide targets with filters set to Off?

The default shortcut is the Space bar. When the tui-logger widget has focus, pressing Space generates a TuiWidgetEvent::SpaceKey that flips the hide_off boolean flag, immediately hiding or showing targets where the filter equals LevelFilter::Off.

How do I toggle hiding of off-filtered targets without keyboard input?

Use the programmatic API. Obtain a TuiWidgetState handle and call state.transition(TuiWidgetEvent::SpaceKey). This mutates the internal hide_off flag exactly as if the user pressed Space, allowing you to control visibility from configuration files or automated UI states.

Does toggling Hide Off affect the smart widget's column layout?

Yes. The smart widget defined in src/widget/smart.rs checks hide_off during its width-calculation phase (lines 62-66). When the flag is enabled, the widget excludes off-filtered targets from the width calculation, preventing the layout from reserving space for invisible entries.

What is the difference between the Space key and the 'h' key in tui-logger?

The Space key toggles Hide Off, which filters the list to exclude individual targets with LevelFilter::Off. The 'h' key (mapped to HideKey) toggles Hide Target, which collapses the entire target column to show only the log output, regardless of individual filter settings.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →