Module: RatatuiRuby::OutputGuard

Included in:
RatatuiRuby
Defined in:
lib/ratatui_ruby/output_guard.rb

Overview

Output protection for TUI sessions and batch/CLI mode.

This module provides mechanisms to prevent accidental output to stdout/stderr during TUI sessions and to support headless (batch/CLI) mode for applications that can run with or without a TUI.

See Also:

Defined Under Namespace

Classes: NullIO

Instance Method Summary collapse

Instance Method Details

#guard_ioObject

Guards a block from stdout/stderr output.

During a TUI session, writes to $stdout or $stderr corrupt the display. Wrap code that might produce output (e.g., chatty gems) in this block.

This temporarily replaces $stdout and $stderr with a NullIO object that discards all output. The original streams are restored when the block exits, even if an exception occurs.

Behavior by mode

  • **TUI session active**: Output is swallowed (guarded)

  • **Headless mode**: Silent no-op (output flows normally)

  • Neither: Warns and yields (catches potential mistakes)

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

RatatuiRuby.run do |tui|
  RatatuiRuby.guard_io do
    SomeChattyGem.do_something  # Any puts/warn calls are swallowed
  end
end

– SPDX-SnippetEnd ++

See Also:



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/ratatui_ruby/output_guard.rb', line 150

def guard_io
  # TUI active: guard the output
  if terminal_active?
    $stdout = NullIO.new
    $stderr = NullIO.new
    begin
      return yield
    ensure
      $stdout = Object::STDOUT
      $stderr = Object::STDERR
    end
  end

  # Headless mode: silent no-op
  return yield if is_headless?

  # Neither: warn about potential mistake
  warn "guard_io called outside TUI session. If this is intentional (batch/CLI mode), call RatatuiRuby.headless! at startup to silence this warning."
  yield
end

#headless!Object

Enables headless (batch/CLI) mode.

Call this at app startup when running in batch/CLI mode (e.g., --no-tui). This tells RatatuiRuby that you intentionally don’t want a TUI session.

When headless mode is active:

Headless mode and TUI sessions are mutually exclusive. Calling this while a TUI session is active raises Error::Invariant.

Why there is no exit_headless!

Headless mode is a startup-time decision for the entire app run. If you need to temporarily exit TUI mode for user interaction (like lazygit does when editing a commit message), use TerminalLifecycle#restore_terminal and TerminalLifecycle#init_terminal instead:

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

RatatuiRuby.restore_terminal
puts "Press enter to continue..."
gets
RatatuiRuby.init_terminal

– SPDX-SnippetEnd ++

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

if ARGV.include?("--no-tui")
  RatatuiRuby.headless!
  process_batch_work  # guard_io calls are silent no-ops
else
  RatatuiRuby.run do |tui|  # This branch only runs in TUI mode
    # ... TUI code ...
  end
end

– SPDX-SnippetEnd ++ Note: Calling TerminalLifecycle#run or TerminalLifecycle#init_terminal after #headless! raises Error::Invariant. The block is never executed.

Raises:

See Also:



110
111
112
113
114
115
# File 'lib/ratatui_ruby/output_guard.rb', line 110

def headless!
  if @tui_session_active
    raise Error::Invariant, "Cannot enable headless mode: TUI session already active"
  end
  @headless_mode = true
end

#is_headless?Boolean

Whether headless (batch/pipeline/CLI) mode is enabled.

When headless mode is active:

Use this when your app has a --no-tui or --batch flag and you want the same code to work in both TUI and non-TUI modes.

Returns:

  • (Boolean)

See Also:



48
49
50
# File 'lib/ratatui_ruby/output_guard.rb', line 48

def is_headless?
  @headless_mode
end