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
-
.ci? ⇒ Boolean
Check if running in a CI environment Common CI env vars: CI, CONTINUOUS_INTEGRATION, BUILD_NUMBER, GITHUB_ACTIONS, etc.
-
.colors_supported?(output = $stdout) ⇒ Boolean
Check if ANSI colors are supported on
output. -
.columns(output = $stdout, default: 80) ⇒ Integer
Get terminal columns (width).
-
.dimensions(output = $stdout) ⇒ Array<Integer>
Get terminal dimensions as [rows, columns].
-
.dumb_terminal? ⇒ Boolean
Check if running in a dumb terminal (no ANSI support).
-
.escape_timeout ⇒ Float
Escape-sequence detection timeout, in seconds.
-
.raw_mode_supported?(input = $stdin) ⇒ Boolean
Check if raw mode is supported for input.
-
.reset! ⇒ Object
Reset cached environment checks (useful for testing).
-
.rows(output = $stdout, default: 24) ⇒ Integer
Get terminal rows (height).
-
.tty?(output = $stdout) ⇒ Boolean
Check if stdout is a TTY (interactive terminal).
-
.windows? ⇒ Boolean
Check if running on Windows.
-
.windows_terminal? ⇒ Boolean
Check if running in Windows Terminal (modern).
Class Method Details
.ci? ⇒ Boolean
Check if running in a CI environment Common CI env vars: CI, CONTINUOUS_INTEGRATION, BUILD_NUMBER, GITHUB_ACTIONS, etc.
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 on output.
Resolution order, first match wins:
FORCE_COLOR=0orFORCE_COLOR=false(any case):falseNO_COLORset to a non-empty value:false(see https://no-color.org)FORCE_COLORset to any other non-empty value:true, even whenoutputis not a TTY orTERM=dumboutputis not a TTY:falseTERM=dumb:false- Otherwise
true
An empty NO_COLOR or FORCE_COLOR is treated as unset. The result is
not cached; every call re-reads the environment.
Colors.enabled?, Core::Cursor.enabled? and Symbols.unicode? all
delegate here, so these variables also control cursor escape sequences
and the Unicode/ASCII symbol set (unless CLACK_UNICODE overrides the
latter).
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/clack/environment.rb', line 81 def colors_supported?(output = $stdout) force = ENV["FORCE_COLOR"].to_s # The binary copy matters: ENV values carry the locale encoding, and # String#casecmp? raises ArgumentError on invalid bytes in that # encoding. Symbols calls this at require time, so a stray # FORCE_COLOR=$'\xff' would otherwise make `require "clack"` raise. return false if force == "0" || force.b.casecmp?("false") return false unless ENV["NO_COLOR"].to_s.empty? return true unless force.empty? 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)
102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/clack/environment.rb', line 102 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]
135 136 137 |
# File 'lib/clack/environment.rb', line 135 def dimensions(output = $stdout) [rows(output), columns(output)] end |
.dumb_terminal? ⇒ Boolean
Check if running in a dumb terminal (no ANSI support)
56 57 58 |
# File 'lib/clack/environment.rb', line 56 def dumb_terminal? ENV["TERM"] == "dumb" end |
.escape_timeout ⇒ Float
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.
170 171 172 173 174 175 176 177 178 |
# File 'lib/clack/environment.rb', line 170 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
142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/clack/environment.rb', line 142 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)
181 182 183 184 |
# File 'lib/clack/environment.rb', line 181 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)
119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/clack/environment.rb', line 119 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)
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
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)
50 51 52 |
# File 'lib/clack/environment.rb', line 50 def windows_terminal? windows? && ENV.key?("WT_SESSION") end |