zjstatus

repository·main·Indexed 21 days ago

https://github.com/dj95/zjstatus

A highly configurable and themable statusbar for the Zellij terminal multiplexer featuring a modular widget system. It includes zjstatus for statusbar rendering and zjframes, a companion tool for conditional pane frame management based on session state such as search, fullscreen, or scroll modes.

Tokens
7.9K
Snippets
16
Records
32
Agent score
76%

What's inside zjstatus

  1. Quick Start for zjframes

    main

    zjframes is used to toggle pane frames based on specific conditions (like search or fullscreen) even without loading the full zjstatus statusbar.

    Unlike zjstatus, zjframes should be loaded in the load_plugins section of your Zellij config.kdl so that it runs in the background.

    Example configuration for config.kdl:

    // Plugins to load in the background when a new session starts
    load_plugins {
        "file:~/path/to/zjframes.wasm" {
            hide_frame_for_single_pane       "true"
            hide_frame_except_for_search     "true"
            hide_frame_except_for_scroll     "true"
            hide_frame_except_for_fullscreen "true"
        }
    }
  2. Install zjstatus and zjframes

    main

    Manual Installation

    Download the latest .wasm binary from the GitHub releases. Place the file in a location accessible by Zellij.

    Note: It is highly recommended to download the file locally and use a file: URI (e.g., file:~/path/to/zjstatus.wasm) rather than an https: URL for stability.

    Nix Installation

    Add the repository to your Nix flake inputs and use the following overlay to install it via pkgs.zjstatus:

      inputs = {
        zjstatus = {
          url = "github:dj95/zjstatus";
        };
      };
    
      outputs = { self, nixpkgs, zjstatus, ... }@inputs: {
        # ...
        overlays = [ 
          (final: prev: {
            zjstatus = zjstatus.packages.${prev.system}.default;
          })
        ];
      };

    When templating your Zellij config, you can refer to the binaries at:

    • ${pkgs.zjstatus}/bin/zjstatus.wasm
    • ${pkgs.zjstatus}/bin/zjframes.wasm (if using only zjframes)

    Troubleshooting

    If you experience crashes or issues (especially after updating plugins), clear the Zellij cache:

    • Linux: $HOME/.cache/zellij/
    • macOS: $HOME/Library/Caches/org.Zellij-Contributors.Zellij/

    Warning: Clearing the cache will also clear running sessions and revoke granted plugin permissions.

    # No single command, but follow the manual or Nix steps above.
  3. Quick Start for zjstatus

    main

    To use zjstatus as a statusbar, you must include it in a Zellij layout file (e.g., ~/.config/zellij/layouts/default.kdl).

    Important Requirements:

    1. Permissions: Upon starting Zellij with the new layout, you must grant the plugin permission by navigating to the pane and pressing y.
    2. Layout Overriding: Using zjstatus involves creating new layouts and overriding the default one. If you use 'swap layouts' in Zellij, ensure they are configured correctly to work with zjstatus by following the swap-layouts documentation.
    3. Borders: If you want to hide borders, ensure hide_frame_for_single_pane is set to false or removed; otherwise, zjstatus may toggle frame borders even if they are hidden in your main Zellij config.

    Example configuration for a layout file:

    layout {
        default_tab_template {
            children
            pane size=1 borderless=true {
                plugin location="file:~/path/to/zjstatus.wasm" {
                    format_left   "{mode} #[fg=#89B4FA,bold]{session}"
                    format_center "{tabs}"
                    format_right  "{command_git_branch} {datetime}"
                    format_space  ""
    
                    border_enabled  "false"
                    border_char     "─"
                    border_format   "#[fg=#6C7086]{char}"
                    border_position "top"
    
                    hide_frame_for_single_pane "true"
    
                    mode_normal  "#[bg=blue] "
                    mode_tmux    "#[bg=#ffc387] "
    
                    tab_normal   "#[fg=#6C7086] {name} "
                    tab_active   "#[fg=#9399B2,bold,italic] {name} "
    
                    command_git_branch_command     "git rev-parse --abbrev-ref HEAD"
                    command_git_branch_format      "#[fg=blue] {stdout} "
                    command_git_branch_interval    "10"
                    command_git_branch_rendermode  "static"
                    command_git_branch_cwd         "{focused_pane_cwd}"
    
                    datetime        "#[fg=#6C7086,bold] {format} "
                    datetime_format "%A, %d %b %Y %H:%M"
                    datetime_timezone "Europe/Berlin"
                }
            }
        }
    }
  4. Set Command render modes

    main

    The rendermode configuration option determines how the command output is processed and displayed:

    • static: Uses the provided format string and applies formatting to the content.
    • dynamic: Applies dynamic formatting (likely color/style) to the formatted content.
    • raw: Displays the raw stdout of the command directly, ignoring the format string.
  5. The zjstatus line protocol format

    main

    zjstatus uses a specific line protocol to receive commands and updates. Commands must follow the format:

    zjstatus::command_name::args (or zjstatus::command_name::args::extra_args for the pipe command).

    All lines must start with the zjstatus prefix to be recognized by the parser.

    Available Commands

    CommandFormatDescription
    rerunzjstatus::rerun::command_nameForces a command (as defined in your config) to re-run by invalidating its cached result.
    notifyzjstatus::notify::messageTriggers a notification in the UI with the provided message string.
    pipezjstatus::pipe::name::contentUpdates a specific pipe result in the state with new content.
    zjstatus::rerun::command_1
    zjstatus::notify::Hello World
    zjstatus::pipe::my_pipe::some_content
  6. Use the {name} placeholder in Mode widget formats

    main
    When defining format strings for the ModeWidget, you can use the {name} placeholder. This placeholder will be replaced by the name of the current Zellij mode (e.g., Normal, Locked, Pane) during rendering.
  7. How zjstatus works as a Zellij plugin

    main

    zjstatus is designed to run as a Zellij plugin. It implements the ZellijPlugin trait and manages its own state, including Zellij session information (tabs, panes, modes), user configuration, and a collection of widgets.

    Key lifecycle and behavior details:

    • Permissions: The plugin requests ReadApplicationState, ChangeApplicationState, and RunCommands permissions to function correctly (e.g., to receive mode updates or run commands in floating windows).
    • Event Subscription: It subscribes to various Zellij events such as Mouse, ModeUpdate, PaneUpdate, TabUpdate, SessionUpdate, and CwdChanged to trigger re-renders.
    • Rendering: The plugin renders the status bar by using a ModuleConfig to process the current ZellijState and a map of registered widgets.
    • Communication: It supports a pipe mechanism, allowing it to receive messages from the CLI, other plugins, or keybindings to update its internal state via a specific protocol.
  8. How zjframes works as a Zellij plugin

    main

    zjframes is a Zellij plugin designed to conditionally hide or show pane frames based on the session state (modes, panes, tabs, and session updates).

    Permissions Required

    To function correctly, the plugin requests the following permissions:

    • ReadApplicationState: Required to receive ModeUpdate and TabUpdate events.
    • ChangeApplicationState: Required for state management.

    Behavior

    The plugin subscribes to several event types to trigger frame updates:

    • ModeUpdate: Triggers when the user changes Zellij modes.
    • PaneUpdate: Triggers when panes are added, removed, or resized.
    • TabUpdate: Triggers when tabs are modified.
    • SessionUpdate: Triggers when the overall session state changes.

    When an event occurs, the plugin uses frames::hide_frames_conditionally to evaluate the current FrameConfig against the current state of tabs, panes, and mode to decide whether to show or hide frames.

  9. Define environment variables for commands using KDL

    main

    To provide environment variables to a command, use the command_<name>_env key with a KDL-formatted string. Each node in the KDL document represents an environment variable where the node name is the key and the child value is the value.

    VAR_NAME "value"
    ANOTHER_VAR "something_else"
  10. Configure zjframes plugin options

    main

    The zjframes plugin can be configured via a BTreeMap<String, String> (passed during the load phase in Zellij). These configuration keys allow you to toggle conditional frame hiding based on the current state of the Zellij session.

    Available configuration keys:

    • hide_frame_for_single_pane: If set to "true", hides frames when only a single pane is present.
    • hide_frame_except_for_search: If set to "true", ensures frames are shown when the search mode is active, even if other hiding conditions are met.
    • hide_frame_except_for_fullscreen: If set to "true", ensures frames are shown when a pane is in fullscreen mode.
    • hide_frame_except_for_scroll: If set to "true", ensures frames are shown when a pane is in scroll mode.
  11. Untitled record

    main

    The ModuleConfig struct defines how the status bar is laid out and rendered. It manages the content for the left, center, and right sections, as well as visual properties like borders and visibility toggles.

    Configuration Keys

    When initializing ModuleConfig from a configuration map (BTreeMap<String, String>), the following keys are supported:

    KeyTypeDefaultDescription
    format_leftString""The format string for the left section.
    format_centerString""The format string for the center section.
    format_rightString""The format string for the right section.
    format_spaceString""The format string used for spacer/padding areas.
    format_precedenceString"lcr"A string of characters (l, c, r) defining the priority order for content when parts overlap.
    format_hide_on_overlengthBooleanfalseIf true, parts that cause overlap will be trimmed/hidden based on precedence.
    hide_frame_for_single_paneBooleanfalseHides the status bar frame when only one pane is present.
    hide_frame_except_for_searchBooleanfalseHides the frame unless a search is active.
    hide_frame_except_for_fullscreenBooleanfalseHides the frame unless in fullscreen mode.
    hide_frame_except_for_scrollBooleanfalseHides the frame unless scrolling.

    Format String Syntax

    Format strings support widget placeholders in the form {widget_name} and styling metadata using the #[...] syntax (e.g., #[fg=#ff0000,bold]text).

    // Example of how ModuleConfig is initialized from a config map
    let mut config = BTreeMap::new();
    config.insert("format_left".to_string(), "#[fg=#ff0000]{command}".to_string());
    config.insert("format_center".to_string(), "{mode}".to_string());
    config.insert("format_right".to_string(), "{datetime}".to_string());
    config.insert("format_hide_on_overlength".to_string(), "true".to_string());
    
    let module_config = ModuleConfig::new(&config).unwrap();