| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 02:59:35 +02:00
										 |  |  | # Various helper functions for interacting with TTYs. | 
					
						
							| 
									
										
										
										
											2016-08-26 16:04:47 +02:00
										 |  |  | module Tty | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |   @stream = T.let($stdout, T.nilable(T.any(IO, StringIO))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   COLOR_CODES = T.let( | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       red:     31, | 
					
						
							|  |  |  |       green:   32, | 
					
						
							|  |  |  |       yellow:  33, | 
					
						
							|  |  |  |       blue:    34, | 
					
						
							|  |  |  |       magenta: 35, | 
					
						
							|  |  |  |       cyan:    36, | 
					
						
							|  |  |  |       default: 39, | 
					
						
							|  |  |  |     }.freeze, | 
					
						
							|  |  |  |     T::Hash[Symbol, Integer], | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   STYLE_CODES = T.let( | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       reset:         0, | 
					
						
							|  |  |  |       bold:          1, | 
					
						
							|  |  |  |       italic:        3, | 
					
						
							|  |  |  |       underline:     4, | 
					
						
							|  |  |  |       strikethrough: 9, | 
					
						
							|  |  |  |       no_underline:  24, | 
					
						
							|  |  |  |     }.freeze, | 
					
						
							|  |  |  |     T::Hash[Symbol, Integer], | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SPECIAL_CODES = T.let( | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       up:         "1A", | 
					
						
							|  |  |  |       down:       "1B", | 
					
						
							|  |  |  |       right:      "1C", | 
					
						
							|  |  |  |       left:       "1D", | 
					
						
							|  |  |  |       erase_line: "K", | 
					
						
							|  |  |  |       erase_char: "P", | 
					
						
							|  |  |  |     }.freeze, | 
					
						
							|  |  |  |     T::Hash[Symbol, String], | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CODES = T.let(COLOR_CODES.merge(STYLE_CODES).freeze, T::Hash[Symbol, Integer]) | 
					
						
							| 
									
										
										
										
											2023-03-05 23:57:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |   class << self | 
					
						
							|  |  |  |     sig { params(stream: T.any(IO, StringIO), _block: T.proc.params(arg0: T.any(IO, StringIO)).void).void } | 
					
						
							|  |  |  |     def with(stream, &_block) | 
					
						
							|  |  |  |       previous_stream = @stream | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |       @stream = T.let(stream, T.nilable(T.any(IO, StringIO))) | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       yield stream | 
					
						
							|  |  |  |     ensure | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |       @stream = T.let(previous_stream, T.nilable(T.any(IO, StringIO))) | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { params(string: String).returns(String) } | 
					
						
							|  |  |  |     def strip_ansi(string) | 
					
						
							|  |  |  |       string.gsub(/\033\[\d+(;\d+)*m/, "") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-14 21:41:01 +02:00
										 |  |  |     sig { params(line_count: Integer).returns(String) } | 
					
						
							|  |  |  |     def move_cursor_up(line_count) | 
					
						
							|  |  |  |       "\033[#{line_count}A" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-21 23:01:48 +02:00
										 |  |  |     sig { params(line_count: Integer).returns(String) } | 
					
						
							|  |  |  |     def move_cursor_up_beginning(line_count) | 
					
						
							|  |  |  |       "\033[#{line_count}F" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-01 15:24:11 +01:00
										 |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def move_cursor_beginning | 
					
						
							|  |  |  |       "\033[0G" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-14 21:41:01 +02:00
										 |  |  |     sig { params(line_count: Integer).returns(String) } | 
					
						
							|  |  |  |     def move_cursor_down(line_count) | 
					
						
							|  |  |  |       "\033[#{line_count}B" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def clear_to_end | 
					
						
							|  |  |  |       "\033[K" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-15 16:31:21 -04:00
										 |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def hide_cursor | 
					
						
							|  |  |  |       "\033[?25l" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def show_cursor | 
					
						
							|  |  |  |       "\033[?25h" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(T.nilable([Integer, Integer])) } | 
					
						
							|  |  |  |     def size | 
					
						
							| 
									
										
										
										
											2024-07-15 21:09:26 -04:00
										 |  |  |       return @size if defined?(@size) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       height, width = `/bin/stty size 2>/dev/null`.presence&.split&.map(&:to_i) | 
					
						
							|  |  |  |       return if height.nil? || width.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |       @size = T.let([height, width], T.nilable([Integer, Integer])) | 
					
						
							| 
									
										
										
										
											2024-07-15 16:31:21 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(Integer) } | 
					
						
							|  |  |  |     def height | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |       @height ||= T.let(size&.first || `/usr/bin/tput lines 2>/dev/null`.presence&.to_i || 40, T.nilable(Integer)) | 
					
						
							| 
									
										
										
										
											2024-07-15 16:31:21 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |     sig { returns(Integer) } | 
					
						
							|  |  |  |     def width | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |       @width ||= T.let(size&.second || `/usr/bin/tput cols 2>/dev/null`.presence&.to_i || 80, T.nilable(Integer)) | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { params(string: String).returns(String) } | 
					
						
							|  |  |  |     def truncate(string) | 
					
						
							|  |  |  |       (w = width).zero? ? string.to_s : (string.to_s[0, w - 4] || "") | 
					
						
							| 
									
										
										
										
											2018-06-14 22:14:46 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def current_escape_sequence | 
					
						
							|  |  |  |       return "" if @escape_sequence.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       "\033[#{@escape_sequence.join(";")}m" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { void } | 
					
						
							|  |  |  |     def reset_escape_sequence! | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |       @escape_sequence = T.let(nil, T.nilable(T::Array[Integer])) | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CODES.each do |name, code| | 
					
						
							|  |  |  |       define_method(name) do | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |         @escape_sequence ||= T.let([], T.nilable(T::Array[Integer])) | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |         @escape_sequence << code | 
					
						
							|  |  |  |         self | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-26 16:04:47 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     SPECIAL_CODES.each do |name, code| | 
					
						
							|  |  |  |       define_method(name) do | 
					
						
							| 
									
										
										
										
											2025-01-11 21:36:59 +00:00
										 |  |  |         @stream = T.let($stdout, T.nilable(T.any(IO, StringIO))) | 
					
						
							|  |  |  |         if @stream&.tty? | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |           "\033[#{code}" | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           "" | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def to_s | 
					
						
							|  |  |  |       return "" unless color? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |       current_escape_sequence | 
					
						
							|  |  |  |     ensure | 
					
						
							|  |  |  |       reset_escape_sequence! | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2019-10-04 09:17:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |     sig { returns(T::Boolean) } | 
					
						
							|  |  |  |     def color? | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  |       require "env_config" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |       return false if Homebrew::EnvConfig.no_color? | 
					
						
							|  |  |  |       return true if Homebrew::EnvConfig.color? | 
					
						
							| 
									
										
										
										
											2025-01-15 23:34:23 +00:00
										 |  |  |       return false if @stream.blank? | 
					
						
							| 
									
										
										
										
											2019-10-04 09:17:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-15 23:34:23 +00:00
										 |  |  |       @stream.tty? | 
					
						
							| 
									
										
										
										
											2020-10-10 17:53:31 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2023-02-24 13:50:07 +00:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-08-26 16:04:47 +02:00
										 |  |  | end |