Module: Clack::Environment

Defined in:
lib/clack/environment.rb

Overview

Environment detection utilities for cross-platform compatibility and CI/terminal environment awareness.

Constant Summary collapse

DEFAULT_ESCAPE_TIMEOUT =

Default Escape-sequence detection timeout, in seconds.

0.05

Class Method Summary collapse

Class Method Details

.ci?Boolean

Check if running in a CI environment Common CI env vars: CI, CONTINUOUS_INTEGRATION, BUILD_NUMBER, GITHUB_ACTIONS, etc.

Returns:

  • (Boolean)


24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/clack/environment.rb', line 24

def ci?
  return @ci if defined?(@ci)

  @ci = ENV["CI"] == "true" ||
    ENV["CONTINUOUS_INTEGRATION"] == "true" ||
    ENV.key?("BUILD_NUMBER") ||
    ENV.key?("GITHUB_ACTIONS") ||
    ENV.key?("GITLAB_CI") ||
    ENV.key?("CIRCLECI") ||
    ENV.key?("TRAVIS") ||
    ENV.key?("JENKINS_URL") ||
    ENV.key?("TEAMCITY_VERSION") ||
    ENV.key?("BUILDKITE")
end

.colors_supported?(output = $stdout) ⇒ Boolean

Check if ANSI colors are supported

Parameters:

  • output (IO) (defaults to: $stdout)

    Output stream to check

Returns:

  • (Boolean)


63
64
65
66
67
68
69
70
71
72
# File 'lib/clack/environment.rb', line 63

def colors_supported?(output = $stdout)
  return false if ENV["NO_COLOR"]
  return true if ENV["FORCE_COLOR"]
  return false unless tty?(output)
  return false if dumb_terminal?

  # Windows: Modern Windows Terminal, ConEmu, ANSICON, or Windows 10 1511+
  # all support ANSI. We optimistically assume modern systems support it.
  true
end

.columns(output = $stdout, default: 80) ⇒ Integer

Get terminal columns (width)

Parameters:

  • output (IO) (defaults to: $stdout)

    Output stream (default: $stdout)

  • default (Integer) (defaults to: 80)

    Default if detection fails

Returns:

  • (Integer)


78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/clack/environment.rb', line 78

def columns(output = $stdout, default: 80)
  return default unless tty?(output)

  if output.respond_to?(:winsize)
    _, cols = output.winsize
    (cols > 0) ? cols : default
  else
    default
  end
rescue IOError, SystemCallError
  default
end

.dimensions(output = $stdout) ⇒ Array<Integer>

Get terminal dimensions as [rows, columns]

Parameters:

  • output (IO) (defaults to: $stdout)

    Output stream

Returns:

  • (Array<Integer>)
    rows, columns


111
112
113
# File 'lib/clack/environment.rb', line 111

def dimensions(output = $stdout)
  [rows(output), columns(output)]
end

.dumb_terminal?Boolean

Check if running in a dumb terminal (no ANSI support)

Returns:

  • (Boolean)


56
57
58
# File 'lib/clack/environment.rb', line 56

def dumb_terminal?
  ENV["TERM"] == "dumb"
end

.escape_timeoutFloat

Escape-sequence detection timeout, in seconds.

After an Escape byte arrives, the key reader waits this long for a follow-up byte to decide whether it’s a standalone Escape or the start of an arrow-key / CSI sequence. The 50ms default is fine locally but too tight over high-latency links (slow SSH, mosh), where the follow-up bytes lag and arrow keys get misread as a bare Escape (cancelling the prompt). Override with the CLACK_ESCAPE_TIMEOUT env var, in milliseconds, e.g. CLACK_ESCAPE_TIMEOUT=250 for a slow connection.

Invalid or non-positive values fall back to the default.

Returns:

  • (Float)

    timeout in seconds



146
147
148
149
150
151
152
153
154
# File 'lib/clack/environment.rb', line 146

def escape_timeout
  raw = ENV["CLACK_ESCAPE_TIMEOUT"]
  return DEFAULT_ESCAPE_TIMEOUT unless raw

  ms = Float(raw, exception: false)
  return DEFAULT_ESCAPE_TIMEOUT unless ms&.positive?

  ms / 1000.0
end

.raw_mode_supported?(input = $stdin) ⇒ Boolean

Check if raw mode is supported for input

Parameters:

  • input (IO) (defaults to: $stdin)

    Input stream (default: $stdin)

Returns:

  • (Boolean)


118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/clack/environment.rb', line 118

def raw_mode_supported?(input = $stdin)
  return false unless input.respond_to?(:raw)

  # On Windows without proper console, raw mode may fail
  if windows? && !windows_terminal?
    begin
      IO.console&.respond_to?(:raw)
    rescue IOError, SystemCallError
      false
    end
  else
    true
  end
end

.reset!Object

Reset cached environment checks (useful for testing)



157
158
159
160
# File 'lib/clack/environment.rb', line 157

def reset!
  remove_instance_variable(:@windows) if defined?(@windows)
  remove_instance_variable(:@ci) if defined?(@ci)
end

.rows(output = $stdout, default: 24) ⇒ Integer

Get terminal rows (height)

Parameters:

  • output (IO) (defaults to: $stdout)

    Output stream (default: $stdout)

  • default (Integer) (defaults to: 24)

    Default if detection fails

Returns:

  • (Integer)


95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/clack/environment.rb', line 95

def rows(output = $stdout, default: 24)
  return default unless tty?(output)

  if output.respond_to?(:winsize)
    rows, = output.winsize
    (rows > 0) ? rows : default
  else
    default
  end
rescue IOError, SystemCallError
  default
end

.tty?(output = $stdout) ⇒ Boolean

Check if stdout is a TTY (interactive terminal)

Parameters:

  • output (IO) (defaults to: $stdout)

    Output stream to check (default: $stdout)

Returns:

  • (Boolean)


42
43
44
45
46
# File 'lib/clack/environment.rb', line 42

def tty?(output = $stdout)
  output.respond_to?(:tty?) && output.tty?
rescue IOError
  false
end

.windows?Boolean

Check if running on Windows

Returns:

  • (Boolean)


15
16
17
18
19
# File 'lib/clack/environment.rb', line 15

def windows?
  return @windows if defined?(@windows)

  @windows = !!(RUBY_PLATFORM =~ /mswin|mingw|cygwin|bccwin/i)
end

.windows_terminal?Boolean

Check if running in Windows Terminal (modern)

Returns:

  • (Boolean)


50
51
52
# File 'lib/clack/environment.rb', line 50

def windows_terminal?
  windows? && ENV.key?("WT_SESSION")
end