")
284 | line.gsub!(/\[ALIGN=left\]/i, "")
285 | line.gsub!(/\[\/ALIGN\]/i, "")
286 |
287 | ## QUOTE
288 | quote+=1 if line =~ /\[QUOTE\]/i
289 | quote-=1 if (line =~ /\[\/QUOTE\]/i) && (quote > -1)
290 | line.gsub!(/\[QUOTE\]/i, "\n")
291 | line.gsub!(/\[\/QUOTE\]/i, "
\n")
292 | line.gsub!(/^/, ">"*quote) if quote > 0
293 |
294 | ## EMAIL
295 | line.gsub!(/\[EMAIL\](.*?)\[\/EMAIL\]/i, "\\1")
296 |
297 | ## LIST (TODO: LIST=1, LIST=A)
298 | line.gsub!(/\[LIST(?:=(.*?))?\]/i, "\n\n")
299 | line.gsub!(/\[\/LIST\]/i, "\n
\n")
300 | line.gsub!(/\[\*\]/i, "\n")
301 |
302 | ## FONT => font ??????
303 | ## ?BLUR?, FADE?
304 |
305 | result << sprintf("%s
\n", line)
306 | end
307 |
308 | return result
309 | end
310 |
311 |
312 | # -- Transitive methods ---------------
313 |
314 | # Converts an ANSI string to one with HTML markup.
315 | # Returns the string with ANSI code sequences converted to XHTML markup.
316 | def BBCode.ansi_to_html(string)
317 | bbcoded = BBCode.ansi_to_bbcode(string )
318 | htmled = BBCode.bbcode_to_html(bbcoded)
319 |
320 | return htmled
321 | end
322 |
323 | # Returns the (X)HTML markup code as ANSI sequences
324 | def BBCode.html_to_ansi(string)
325 | bbcoded = BBCode.html_to_bbcode(string )
326 | ansied = BBCode.bbcode_to_ansi(bbcoded)
327 |
328 | return ansied
329 | end
330 |
331 | end #module BBCode
332 |
333 | end
334 |
335 |
--------------------------------------------------------------------------------
/lib/ansi/chain.rb:
--------------------------------------------------------------------------------
1 | require 'ansi/code'
2 |
3 | module ANSI
4 |
5 | # ANSI::Chain was inspired by Kazuyoshi Tlacaelel's Isna library.
6 | #
7 | class Chain
8 |
9 | #
10 | def initialize(string)
11 | @string = string.to_s
12 | @codes = []
13 | end
14 |
15 | #
16 | attr :string
17 |
18 | #
19 | attr :codes
20 |
21 | #
22 | def method_missing(s, *a, &b)
23 | if ANSI::CHART.key?(s)
24 | @codes << s
25 | self
26 | else
27 | super(s, *a, &b)
28 | end
29 | end
30 |
31 | #
32 | def to_s
33 | if codes.empty?
34 | result = @string
35 | else
36 | result = Code.ansi(@string, *codes)
37 | codes.clear
38 | end
39 | result
40 | end
41 |
42 | #
43 | def to_str
44 | to_s
45 | end
46 |
47 | end
48 |
49 | end
50 |
51 |
--------------------------------------------------------------------------------
/lib/ansi/chart.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | # Table of codes used throughout the system.
4 | #
5 | # @see http://en.wikipedia.org/wiki/ANSI_escape_code
6 | CHART = {
7 | :clear => 0,
8 | :reset => 0,
9 | :bright => 1,
10 | :bold => 1,
11 | :faint => 2,
12 | :dark => 2,
13 | :italic => 3,
14 | :underline => 4,
15 | :underscore => 4,
16 | :blink => 5,
17 | :slow_blink => 5,
18 | :rapid => 6,
19 | :rapid_blink => 6,
20 | :invert => 7,
21 | :inverse => 7,
22 | :reverse => 7,
23 | :negative => 7,
24 | :swap => 7,
25 | :conceal => 8,
26 | :concealed => 8,
27 | :hide => 9,
28 | :strike => 9,
29 |
30 | :default_font => 10,
31 | :font_default => 10,
32 | :font0 => 10,
33 | :font1 => 11,
34 | :font2 => 12,
35 | :font3 => 13,
36 | :font4 => 14,
37 | :font5 => 15,
38 | :font6 => 16,
39 | :font7 => 17,
40 | :font8 => 18,
41 | :font9 => 19,
42 | :fraktur => 20,
43 | :bright_off => 21,
44 | :bold_off => 21,
45 | :double_underline => 21,
46 | :clean => 22,
47 | :italic_off => 23,
48 | :fraktur_off => 23,
49 | :underline_off => 24,
50 | :blink_off => 25,
51 | :inverse_off => 26,
52 | :positive => 26,
53 | :conceal_off => 27,
54 | :show => 27,
55 | :reveal => 27,
56 | :crossed_off => 29,
57 | :crossed_out_off => 29,
58 |
59 | :black => 30,
60 | :red => 31,
61 | :green => 32,
62 | :yellow => 33,
63 | :blue => 34,
64 | :magenta => 35,
65 | :cyan => 36,
66 | :white => 37,
67 |
68 | :on_black => 40,
69 | :on_red => 41,
70 | :on_green => 42,
71 | :on_yellow => 43,
72 | :on_blue => 44,
73 | :on_magenta => 45,
74 | :on_cyan => 46,
75 | :on_white => 47,
76 |
77 | :frame => 51,
78 | :encircle => 52,
79 | :overline => 53,
80 | :frame_off => 54,
81 | :encircle_off => 54,
82 | :overline_off => 55,
83 | }
84 |
85 | #
86 | SPECIAL_CHART = {
87 | :save => "\e[s", # Save current cursor positon.
88 | :restore => "\e[u", # Restore saved cursor positon.
89 | :clear_eol => "\e[K", # Clear to the end of the current line.
90 | :clr => "\e[K", # Clear to the end of the current line.
91 | :clear_right => "\e[0K", # Clear to the end of the current line.
92 | :clear_left => "\e[1K", # Clear to the start of the current line.
93 | :clear_line => "\e[2K", # Clear the entire current line.
94 | :clear_screen => "\e[2J", # Clear the screen and move cursor to home.
95 | :cls => "\e[2J", # Clear the screen and move cursor to home.
96 | :cursor_hide => "\e[?25l", # Hide the cursor.
97 | :cursor_show => "\e[?25h" # Show the cursor.
98 | }
99 |
100 | end
101 |
--------------------------------------------------------------------------------
/lib/ansi/code.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | # Global variable can be used to prevent ANSI codes
4 | # from being used in ANSI's methods that do so to string.
5 | #
6 | # NOTE: This has no effect on methods that return ANSI codes.
7 | $ansi = true
8 |
9 | if RUBY_PLATFORM =~ /(win32|w32)/
10 | begin
11 | require 'Win32/Console/ANSI'
12 | rescue LoadError
13 | warn "ansi: 'gem install win32console' to use color on Windows"
14 | $ansi = false
15 | end
16 | end
17 |
18 | require 'ansi/constants'
19 |
20 | # TODO: up, down, right, left, etc could have yielding methods too?
21 |
22 | # ANSI Codes
23 | #
24 | # Ansi::Code module makes it very easy to use ANSI codes.
25 | # These are especially nice for beautifying shell output.
26 | #
27 | # Ansi::Code.red + "Hello" + Ansi::Code.blue + "World"
28 | # => "\e[31mHello\e[34mWorld"
29 | #
30 | # Ansi::Code.red{ "Hello" } + Ansi::Code.blue{ "World" }
31 | # => "\e[31mHello\e[0m\e[34mWorld\e[0m"
32 | #
33 | # IMPORTANT! Do not mixin Ansi::Code, instead use {ANSI::Mixin}.
34 | #
35 | # See {ANSI::CHART} for list of all supported codes.
36 | #
37 | module Code
38 | extend self
39 |
40 | # include ANSI Constants
41 | include Constants
42 |
43 | # Regexp for matching most ANSI codes.
44 | PATTERN = /\e\[(\d+)m/
45 |
46 | # ANSI clear code.
47 | ENDCODE = "\e[0m"
48 |
49 | # List of primary styles.
50 | def self.styles
51 | %w{bold dark italic underline underscore blink rapid reverse negative concealed strike}
52 | end
53 |
54 | # List of primary colors.
55 | def self.colors
56 | %w{black red green yellow blue magenta cyan white}
57 | end
58 |
59 | # Return ANSI code given a list of symbolic names.
60 | def [](*codes)
61 | code(*codes)
62 | end
63 |
64 | # Dynamically create color on color methods.
65 | #
66 | # @deprecated
67 | #
68 | colors.each do |color|
69 | colors.each do |on_color|
70 | module_eval <<-END, __FILE__, __LINE__
71 | def #{color}_on_#{on_color}(string=nil)
72 | if string
73 | return string unless $ansi
74 | #warn "use ANSI block notation for future versions"
75 | return #{color.upcase} + ON_#{color.upcase} + string + ENDCODE
76 | end
77 | if block_given?
78 | return yield unless $ansi
79 | #{color.upcase} + ON_#{on_color.upcase} + yield.to_s + ENDCODE
80 | else
81 | #{color.upcase} + ON_#{on_color.upcase}
82 | end
83 | end
84 | END
85 | end
86 | end
87 |
88 | # Use method missing to dispatch ANSI code methods.
89 | def method_missing(code, *args, &blk)
90 | esc = nil
91 |
92 | if CHART.key?(code)
93 | esc = "\e[#{CHART[code]}m"
94 | elsif SPECIAL_CHART.key?(code)
95 | esc = SPECIAL_CHART[code]
96 | end
97 |
98 | if esc
99 | if string = args.first
100 | return string unless $ansi
101 | #warn "use ANSI block notation for future versions"
102 | return "#{esc}#{string}#{ENDCODE}"
103 | end
104 | if block_given?
105 | return yield unless $ansi
106 | return "#{esc}#{yield}#{ENDCODE}"
107 | end
108 | esc
109 | else
110 | super(code, *args, &blk)
111 | end
112 | end
113 |
114 | # TODO: How to deal with position codes when $ansi is false?
115 | # Should we raise an error or just not push the codes?
116 | # For now, we will leave this it as is.
117 |
118 | # Like +move+ but returns to original position after
119 | # yielding the block.
120 | def display(line, column=0) #:yield:
121 | result = "\e[s"
122 | result << "\e[#{line.to_i};#{column.to_i}H"
123 | if block_given?
124 | result << yield
125 | result << "\e[u"
126 | #elsif string
127 | # result << string
128 | # result << "\e[u"
129 | end
130 | result
131 | end
132 |
133 | # Move cursor to line and column.
134 | def move(line, column=0)
135 | "\e[#{line.to_i};#{column.to_i}H"
136 | end
137 |
138 | # Move cursor up a specified number of spaces.
139 | def up(spaces=1)
140 | "\e[#{spaces.to_i}A"
141 | end
142 |
143 | # Move cursor down a specified number of spaces.
144 | def down(spaces=1)
145 | "\e[#{spaces.to_i}B"
146 | end
147 |
148 | # Move cursor left a specified number of spaces.
149 | def left(spaces=1)
150 | "\e[#{spaces.to_i}D"
151 | end
152 | alias :back :left
153 |
154 | # Move cursor right a specified number of spaces.
155 | def right(spaces=1)
156 | "\e[#{spaces.to_i}C"
157 | end
158 | alias :forward :right
159 |
160 | ##
161 | #def position
162 | # "\e[#;#R"
163 | #end
164 |
165 | # Apply ANSI codes to a first argument or block value.
166 | #
167 | # @example
168 | # ansi("Valentine", :red, :on_white)
169 | #
170 | # @example
171 | # ansi(:red, :on_white){ "Valentine" }
172 | #
173 | # @return [String]
174 | # String wrapped ANSI code.
175 | #
176 | def ansi(*codes) #:yield:
177 | if block_given?
178 | string = yield.to_s
179 | else
180 | # first argument must be the string
181 | string = codes.shift.to_s
182 | end
183 |
184 | return string unless $ansi
185 |
186 | c = code(*codes)
187 |
188 | c + string.gsub(ENDCODE, ENDCODE + c) + ENDCODE
189 | end
190 |
191 | # TODO: Allow selective removal using *codes argument?
192 |
193 | # Remove ANSI codes from string or block value.
194 | #
195 | # @param [String] string
196 | # String from which to remove ANSI codes.
197 | #
198 | # @return [String]
199 | # String wrapped ANSI code.
200 | #
201 | def unansi(string=nil) #:yield:
202 | if block_given?
203 | string = yield.to_s
204 | else
205 | string = string.to_s
206 | end
207 | string.gsub(PATTERN, '')
208 | end
209 |
210 | # Alias for #ansi method.
211 | #
212 | # @deprecated
213 | # Here for backward compatibility.
214 | alias_method :style, :ansi
215 |
216 | # Alias for #unansi method.
217 | #
218 | # @deprecated
219 | # Here for backwards compatibility.
220 | alias_method :unstyle, :unansi
221 |
222 | # Alternate term for #ansi.
223 | #
224 | # @deprecated
225 | # May change in future definition.
226 | alias_method :color, :ansi
227 |
228 | # Alias for unansi.
229 | #
230 | # @deprecated
231 | # May change in future definition.
232 | alias_method :uncolor, :unansi
233 |
234 | # Look-up code from chart, or if Integer simply pass through.
235 | # Also resolves :random and :on_random.
236 | #
237 | # @param codes [Array 255
341 | v
342 | end
343 |
344 | end
345 |
346 | #
347 | extend Code
348 | end
349 |
350 |
--------------------------------------------------------------------------------
/lib/ansi/columns.rb:
--------------------------------------------------------------------------------
1 | require 'ansi/terminal'
2 |
3 | module ANSI
4 |
5 | #
6 | class Columns
7 |
8 | # Create a column-based layout.
9 | #
10 | # @param [String,Array] list
11 | # Multiline String or Array of strings to columnize.
12 | #
13 | # @param [Hash] options
14 | # Options to customize columnization.
15 | #
16 | # @option options [Fixnum] :columns
17 | # Number of columns.
18 | #
19 | # @option options [Symbol] :align
20 | # Column alignment, either :left, :right or :center.
21 | #
22 | # @option options [String,Fixnum] :padding
23 | # String or number or spaces to append to each column.
24 | #
25 | # The +format+ block MUST return ANSI codes.
26 | def initialize(list, options={}, &format)
27 | self.list = list
28 |
29 | self.columns = options[:columns] || options[:cols]
30 | self.padding = options[:padding] || 1
31 | self.align = options[:align] || :left
32 | #self.ansi = options[:ansi]
33 | self.format = format
34 |
35 | #@columns = nil if @columns == 0
36 | end
37 |
38 | #
39 | def inspect
40 | "#<#{self.class}:#{object_id} #{list.inspect} x #{columns}>"
41 | end
42 |
43 | # List layout into columns. Each new line is taken to be
44 | # a row-column cell.
45 | attr :list
46 |
47 | def list=(list)
48 | case list
49 | when ::String
50 | @list = list.lines.to_a.map{ |e| e.chomp("\n") }
51 | when ::Array
52 | @list = list.map{ |e| e.to_s }
53 | end
54 | end
55 |
56 | # Default number of columns to display. If nil then the number
57 | # of coumns is estimated from the size of the terminal.
58 | attr :columns
59 |
60 | # Set column count ensuring value is either an integer or nil.
61 | # The the value given is zero, it will be taken to mean the same
62 | # as nil, which means fit-to-screen.
63 | def columns=(integer)
64 | integer = integer.to_i
65 | @columns = (integer.zero? ? nil : integer)
66 | end
67 |
68 | # Padding size to apply to cells.
69 | attr :padding
70 |
71 | # Set padding to string or number (of spaces).
72 | def padding=(pad)
73 | case pad
74 | when Numeric
75 | @padding = ' ' * pad.to_i
76 | else
77 | @padding = pad.to_s
78 | end
79 | end
80 |
81 | # Alignment to apply to cells.
82 | attr :align
83 |
84 | # Set alignment ensuring value is a symbol.
85 | #
86 | # @param [#to_sym] symbol
87 | # Either `:right`, `:left` or `:center`.
88 | #
89 | # @return [Symbol] The given symbol.
90 | def align=(symbol)
91 | symbol = symbol.to_sym
92 | raise ArgumentError, "invalid alignment -- #{symbol.inspect}" \
93 | unless [:left, :right, :center].include?(symbol)
94 | @align = symbol
95 | end
96 |
97 | # Formating to apply to cells.
98 | attr :format
99 |
100 | # Set formatting procedure. The procedure must return
101 | # ANSI codes, suitable for passing to String#ansi method.
102 | def format=(procedure)
103 | @format = procedure ? procedure.to_proc : nil
104 | end
105 |
106 | # TODO: Should #to_s also take options and formatting block?
107 | # Maybe instead have hoin take all these and leave #to_s bare.
108 |
109 | # Return string in column layout. The number of columns is determined
110 | # by the `columns` property or overriden by +cols+ argument.
111 | def to_s(cols=nil)
112 | to_s_columns(cols || columns)
113 | end
114 |
115 | #
116 | def join(cols=nil)
117 | to_s_columns(cols || columns)
118 | end
119 |
120 | private
121 |
122 | # Layout string lines into columns.
123 | #
124 | # @todo Put in empty strings for blank cells.
125 | # @todo Centering look like it's off by one to the right.
126 | #
127 | def to_s_columns(columns=nil)
128 | lines = list.to_a
129 | count = lines.size
130 | max = lines.map{ |l| l.size }.max
131 |
132 | if columns.nil?
133 | width = Terminal.terminal_width
134 | columns = (width / (max + padding.size)).to_i
135 | end
136 |
137 | rows = []
138 | mod = (count / columns.to_f).to_i
139 | mod += 1 if count % columns != 0
140 |
141 | lines.each_with_index do |line, index|
142 | (rows[index % mod] ||=[]) << line.strip
143 | end
144 |
145 | pad = padding
146 | tmp = template(max, pad)
147 | str = ""
148 | rows.each_with_index do |row, ri|
149 | row.each_with_index do |cell, ci|
150 | ansi_codes = ansi_formatting(cell, ci, ri)
151 | if ansi_codes.empty?
152 | str << (tmp % cell)
153 | else
154 | str << (tmp % cell).ansi(*ansi_codes)
155 | end
156 | end
157 | str.rstrip!
158 | str << "\n"
159 | end
160 | str
161 | end
162 |
163 | # Aligns the cell left or right.
164 | def template(max, pad)
165 | case align
166 | when :center, 'center'
167 | offset = " " * (max / 2)
168 | "#{offset}%#{max}s#{offset}#{pad}"
169 | when :right, 'right'
170 | "%#{max}s#{pad}"
171 | else
172 | "%-#{max}s#{pad}"
173 | end
174 | end
175 |
176 | # Used to apply ANSI formatting to each cell.
177 | def ansi_formatting(cell, col, row)
178 | if @format
179 | case @format.arity
180 | when 0
181 | f = @format[]
182 | when 1
183 | f = @format[cell]
184 | when 2
185 | f = @format[col, row]
186 | else
187 | f = @format[cell, col, row]
188 | end
189 | else
190 | f = nil
191 | end
192 | [f].flatten.compact
193 | end
194 |
195 | end
196 |
197 | end
198 |
--------------------------------------------------------------------------------
/lib/ansi/constants.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | require 'ansi/chart'
4 |
5 | # Converts {CHART} and {SPECIAL_CHART} entries into constants.
6 | # So for example, the CHART entry for :red becomes:
7 | #
8 | # ANSI::Constants::RED #=> "\e[31m"
9 | #
10 | # The ANSI Constants are include into ANSI::Code and can be included
11 | # any where will they would be of use.
12 | #
13 | module Constants
14 |
15 | CHART.each do |name, code|
16 | const_set(name.to_s.upcase, "\e[#{code}m")
17 | end
18 |
19 | SPECIAL_CHART.each do |name, code|
20 | const_set(name.to_s.upcase, code)
21 | end
22 |
23 | end
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/lib/ansi/core.rb:
--------------------------------------------------------------------------------
1 | require 'ansi/code'
2 | require 'ansi/chain'
3 |
4 | class ::String
5 |
6 | #
7 | def ansi(*codes)
8 | if codes.empty?
9 | ANSI::Chain.new(self)
10 | else
11 | ANSI::Code.ansi(self, *codes)
12 | end
13 | end
14 |
15 | #
16 | def ansi!(*codes)
17 | replace(ansi(*codes))
18 | end
19 |
20 | #
21 | def unansi
22 | ANSI::Code.unansi(self)
23 | end
24 |
25 | #
26 | def unansi!
27 | replace(unansi)
28 | end
29 | end
30 |
31 |
--------------------------------------------------------------------------------
/lib/ansi/diff.rb:
--------------------------------------------------------------------------------
1 | require 'ansi/code'
2 |
3 | module ANSI
4 |
5 | # Diff produces colorized differences of two string or objects.
6 | #
7 | class Diff
8 |
9 | # Highlights the differnce between two strings.
10 | #
11 | # This class method is equivalent to calling:
12 | #
13 | # ANSI::Diff.new(object1, object2).to_a
14 | #
15 | def self.diff(object1, object2, options={})
16 | new(object1, object2, options={}).to_a
17 | end
18 |
19 | # Setup new Diff object. If the objects given are not Strings
20 | # and do not have `#to_str` defined to coerce them to such, then
21 | # their `#inspect` methods are used to convert them to strings
22 | # for comparison.
23 | #
24 | # @param [Object] object1
25 | # First object to compare.
26 | #
27 | # @param [Object] object2
28 | # Second object to compare.
29 | #
30 | # @param [Hash] options
31 | # Options for contoller the way difference is shown. (Not yet used.)
32 | #
33 | def initialize(object1, object2, options={})
34 | @object1 = convert(object1)
35 | @object2 = convert(object2)
36 |
37 | @diff1, @diff2 = diff_string(@object1, @object2)
38 | end
39 |
40 | # Returns the first object's difference string.
41 | def diff1
42 | @diff1
43 | end
44 |
45 | # Returns the second object's difference string.
46 | def diff2
47 | @diff2
48 | end
49 |
50 | # Returns both first and second difference strings separated by a
51 | # new line character.
52 | #
53 | # @todo Should we use `$/` record separator instead?
54 | #
55 | # @return [String] Joined difference strings.
56 | def to_s
57 | "#{@diff1}\n#{@diff2}"
58 | end
59 |
60 | # Returns both first and second difference strings separated by a
61 | # the given `separator`. The default is `$/`, the record separator.
62 | #
63 | # @param [String] separator
64 | # The string to use as the separtor between the difference strings.
65 | #
66 | # @return [String] Joined difference strings.
67 | def join(separator=$/)
68 | "#{@diff1}#{separator}#{@diff2}"
69 | end
70 |
71 | # Returns the first and second difference strings in an array.
72 | #
73 | # @return [Array] Both difference strings.
74 | def to_a
75 | [diff1, diff2]
76 | end
77 |
78 | private
79 |
80 | # Take two plain strings and produce colorized
81 | # versions of each highlighting their differences.
82 | #
83 | # @param [String] string1
84 | # First string to compare.
85 | #
86 | # @param [String] string2
87 | # Second string to compare.
88 | #
89 | # @return [Array] The two difference strings.
90 | def diff_string(string1, string2)
91 | compare(string1, string2)
92 | end
93 |
94 | # Ensure the object of comparison is a string. If +object+ is not
95 | # an instance of String then it wll be converted to one by calling
96 | # either #to_str, if the object responds to it, or #inspect.
97 | def convert(object)
98 | if String === object
99 | object
100 | elsif object.respond_to?(:to_str)
101 | object.to_str
102 | else
103 | object.inspect
104 | end
105 | end
106 |
107 | # Rotation of colors for diff output.
108 | COLORS = [:red, :yellow, :magenta]
109 |
110 | # Take two plain strings and produce colorized
111 | # versions of each highlighting their differences.
112 | #
113 | # @param [String] x
114 | # First string to compare.
115 | #
116 | # @param [String] y
117 | # Second string to compare.
118 | #
119 | # @return [Array] The two difference strings.
120 | def compare(x, y)
121 | c = common(x, y)
122 | a = x.dup
123 | b = y.dup
124 | oi = 0
125 | oj = 0
126 | c.each_with_index do |m, q|
127 | i = a.index(m, oi)
128 | j = b.index(m, oj)
129 | a[i,m.size] = ANSI.ansi(m, COLORS[q%3]) if i
130 | b[j,m.size] = ANSI.ansi(m, COLORS[q%3]) if j
131 | oi = i + m.size if i
132 | oj = j + m.size if j
133 | end
134 | return a, b
135 | end
136 |
137 | # Oh, I should have documented this will I knew what the
138 | # hell it was doing ;)
139 | def common(x,y)
140 | c = lcs(x, y)
141 |
142 | i = x.index(c)
143 | j = y.index(c)
144 |
145 | ix = i + c.size
146 | jx = j + c.size
147 |
148 | if i == 0
149 | l = y[0...j]
150 | elsif j == 0
151 | l = x[0...i]
152 | else
153 | l = common(x[0...i], y[0...j])
154 | end
155 |
156 | if ix == x.size - 1
157 | r = y[jx..-1]
158 | elsif jx = y.size - 1
159 | r = x[ix..-1]
160 | else
161 | r = common(x[ix..-1], y[jx..-1])
162 | end
163 |
164 | [l, c, r].flatten.reject{ |s| s.empty? }
165 | end
166 |
167 | # Least common string.
168 | def lcs(s1, s2)
169 | res=""
170 | num=Array.new(s1.size){Array.new(s2.size)}
171 | len,ans=0
172 | lastsub=0
173 | s1.scan(/./).each_with_index do |l1,i |
174 | s2.scan(/./).each_with_index do |l2,j |
175 | unless l1==l2
176 | num[i][j]=0
177 | else
178 | (i==0 || j==0)? num[i][j]=1 : num[i][j]=1 + num[i-1][j-1]
179 | if num[i][j] > len
180 | len = ans = num[i][j]
181 | thissub = i
182 | thissub -= num[i-1][j-1] unless num[i-1][j-1].nil?
183 | if lastsub==thissub
184 | res+=s1[i,1]
185 | else
186 | lastsub=thissub
187 | res=s1[lastsub, (i+1)-lastsub]
188 | end
189 | end
190 | end
191 | end
192 | end
193 | res
194 | end
195 |
196 | # Hmm... is this even useful?
197 | def lcs_size(s1, s2)
198 | num=Array.new(s1.size){Array.new(s2.size)}
199 | len,ans=0,0
200 | s1.scan(/./).each_with_index do |l1,i |
201 | s2.scan(/./).each_with_index do |l2,j |
202 | unless l1==l2
203 | num[i][j]=0
204 | else
205 | (i==0 || j==0)? num[i][j]=1 : num[i][j]=1 + num[i-1][j-1]
206 | len = ans = num[i][j] if num[i][j] > len
207 | end
208 | end
209 | end
210 | ans
211 | end
212 |
213 | end
214 |
215 | end
216 |
--------------------------------------------------------------------------------
/lib/ansi/hexdump.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | require 'ansi/code'
4 |
5 | # TODO: split dump method into two parts, the first should create a hex table
6 | # then the second, #dump method, will print it out.
7 |
8 | # Create a colorized hex dump of byte string.
9 | #
10 | # Output looks something like the following, but colorized.
11 | #
12 | # 000352c0: ed 33 8c 85 6e cc f6 f7 72 79 1c e3 3a b4 c2 c6 |.3..n...ry..:...|
13 | # 000352d0: c8 8d d6 ee 3e 68 a1 a5 ae b2 b7 97 a4 1d 5f a7 |....>h........_.|
14 | # 000352e0: d8 7d 28 db f6 8a e7 8a 7b 8d 0b bd 35 7d 25 3c |.}(.....{...5}%<|
15 | # 000352f0: 8b 3c c8 9d ec 04 85 54 92 a0 f7 a8 ed cf 05 7d |.<.....T.......}|
16 | # 00035300: b5 e3 9e 35 f0 79 9f 51 74 e3 60 ee 0f 03 8e 3f |...5.y.Qt.`....?|
17 | # 00035310: 05 5b 91 87 e6 48 48 ee a3 77 ae ad 5e 2a 56 a2 |.[...HH..w..^*V.|
18 | # 00035320: b6 96 86 f3 3c 92 b3 c8 62 4a 6f 96 10 5c 9c bb |....<...bJo..\..|
19 | #
20 | # In the future, we will make the colorization more customizable and
21 | # allow the groupings to be selectable at 2, 4, 8 or 16.
22 | #
23 | class HexDump
24 |
25 | # Printable ASCII codes.
26 | ASCII_PRINTABLE = (33..126)
27 |
28 | #
29 | def initialize(options={})
30 | @offset = 0
31 |
32 | options.each do |k,v|
33 | __send__("#{k}=", v)
34 | end
35 |
36 | @color = true if color.nil?
37 | end
38 |
39 | # Use color?
40 | attr_accessor :color
41 |
42 | # Show index?
43 | attr_accessor :index
44 |
45 | # Offset byte count.
46 | attr_accessor :offset
47 |
48 | # Dump data string as colorized hex table.
49 | #
50 | # @param data [String]
51 | # String to convert to hex and display.
52 | #
53 | def dump(data)
54 | lines = data.to_s.scan(/.{1,16}/m)
55 | max_offset = (offset + data.size) / 256 #16 * 16
56 | max_offset_width = max_offset.to_s.size + 1
57 | max_hex_width = 49 #3 * 16 + 1
58 |
59 | out = template()
60 | off = offset()
61 |
62 | if index?
63 | puts((' ' * max_offset_width) + " 0 1 2 3 4 5 6 7 8 9 A B C D E F\n")
64 | end
65 |
66 | lines.each_with_index do |line, n|
67 | offset = off + n * 16
68 | bytes = line.unpack("C*")
69 | hex = bytes.map{ |c| "%0.2x" % c }.insert(8, '').join(' ')
70 |
71 | plain = bytes.map do |c|
72 | if ASCII_PRINTABLE.include?(c)
73 | c = c.chr
74 | else
75 | color ? Code::WHITE + Code::STRIKE + '.' + Code::CLEAR : '.'
76 | end
77 | end.join('')
78 |
79 | fill = [offset.to_s.rjust(max_offset_width), hex.ljust(max_hex_width), plain]
80 |
81 | puts(out % fill)
82 | end
83 | end
84 |
85 | # Hex dump a random string.
86 | #
87 | def dump_random(size=64)
88 | data = (0..size).map{ rand(255).chr }.join('')
89 | dump(data)
90 | end
91 |
92 | #
93 | def index?
94 | @index
95 | end
96 |
97 | private
98 |
99 | # Hex dump line template.
100 | #
101 | # @return [String] hex dump line template
102 | def template
103 | if color
104 | Code::CYAN +
105 | "%s: " +
106 | Code::YELLOW +
107 | "%s " +
108 | Code::BLUE +
109 | "|" +
110 | Code::CLEAR +
111 | "%s" +
112 | Code::BLUE +
113 | "|" +
114 | Code::CLEAR
115 | else
116 | "%s: %s |%s|"
117 | end
118 | end
119 |
120 | end
121 |
122 | end
123 |
--------------------------------------------------------------------------------
/lib/ansi/logger.rb:
--------------------------------------------------------------------------------
1 | # Ansi::Logger
2 | # Copyright (c) 2009 Thomas Sawyer
3 | # Copyright (c) 2005 George Moschovitis
4 |
5 | require "logger"
6 | require "time"
7 | require "ansi/code"
8 |
9 | # = ANSI::Logger
10 | #
11 | # Extended variation of Ruby's standard Logger library that supports
12 | # color output.
13 | #
14 | # log = ANSI::Logger.new
15 | #
16 | # log.formatter do |severity, timestamp, progname, msg|
17 | # ANSI::Logger::SIMPLE_FORMAT % [severity, msg]
18 | # end
19 | #
20 | #--
21 | # TODO: What's all this about then?
22 | #
23 | # When using debug level logger messages always append 'if $DBG'
24 | # at the end. This hack is needed because Ruby does not support
25 | # lazy evaluation (lisp macros).
26 | #++
27 | class ANSI::Logger < Logger
28 |
29 | # Some available logging formats.
30 | SIMPLE_FORMAT = "%5s: %s\n"
31 | DETAILED_FORMAT = "%s %5s: %s\n"
32 |
33 | # TODO: Not sure I like this approach.
34 | class ::Logger #:nodoc:
35 | class LogDevice #:nodoc:
36 | attr_writer :ansicolor
37 |
38 | def ansicolor?
39 | @ansicolor.nil? ? true : @ansicolor
40 | end
41 | end
42 | end
43 |
44 | #
45 | def ansicolor?
46 | @logdev.ansicolor?
47 | end
48 |
49 | #
50 | def ansicolor=(on)
51 | @logdev.ansicolor = on
52 | end
53 |
54 | # Dictate the way in which this logger should format the
55 | # messages it displays. This method requires a block. The
56 | # block should return formatted strings given severity,
57 | # timestamp, progname and msg.
58 | #
59 | # === Example
60 | #
61 | # logger = ANSI::Logger.new
62 | #
63 | # logger.formatter do |severity, timestamp, progname, msg|
64 | # "#{progname}@#{timestamp} - #{severity}::#{msg}"
65 | # end
66 | #
67 | def formatter(&block)
68 | self.formatter = block if block
69 | super
70 | end
71 |
72 | def styles(options=nil)
73 | @styles ||= {
74 | :info => [],
75 | :warn => [:yellow],
76 | :debug => [:cyan],
77 | :error => [:red],
78 | :fatal => [:bold, :red]
79 | }
80 | @styles.merge!(options) if options
81 | @styles
82 | end
83 |
84 | #
85 | def info(progname=nil, &block)
86 | return unless info?
87 | @logdev.ansicolor? ? info_with_color{ super } : super
88 | end
89 |
90 | #
91 | def warn(progname=nil, &block)
92 | return unless warn?
93 | @logdev.ansicolor? ? warn_with_color{ super } : super
94 | end
95 |
96 | #
97 | def debug(progname=nil, &block)
98 | return unless debug?
99 | @logdev.ansicolor? ? debug_with_color{ super } : super
100 | end
101 |
102 | #
103 | def error(progname=nil, &block)
104 | return unless error?
105 | @logdev.ansicolor? ? error_with_color{ super } : super
106 | end
107 |
108 | #
109 | def fatal(progname=nil, &block)
110 | return unless error?
111 | @logdev.ansicolor? ? fatal_with_color{ super } : super
112 | end
113 |
114 | private
115 |
116 | def info_with_color #:yield:
117 | styles[:info].each{ |s| self << ANSI::Code.send(s) }
118 | yield
119 | self << ANSI::Code.clear
120 | end
121 |
122 | def warn_with_color #:yield:
123 | styles[:warn].each{ |s| self << ANSI::Code.send(s) }
124 | yield
125 | self << ANSI::Code.clear
126 | end
127 |
128 | def error_with_color #:yield:
129 | styles[:error].each{ |s| self << ANSI::Code.send(s) }
130 | yield
131 | self << ANSI::Code.clear
132 | end
133 |
134 | def debug_with_color #:yield:
135 | styles[:debug].each{ |s| self << ANSI::Code.send(s) }
136 | yield
137 | self << ANSI::Code.clear
138 | end
139 |
140 | def fatal_with_color #:yield:
141 | styles[:fatal].each{ |s| self << ANSI::Code.send(s) }
142 | yield
143 | self << ANSI::Code.clear
144 | end
145 |
146 | end
147 |
148 |
149 | # NOTE: trace is deprecated b/c binding of caller is no longer possible.
150 | =begin
151 | # Prints a trace message to DEBUGLOG (at debug level).
152 | # Useful for emitting the value of variables, etc. Use
153 | # like this:
154 | #
155 | # x = y = 5
156 | # trace 'x' # -> 'x = 5'
157 | # trace 'x ** y' # -> 'x ** y = 3125'
158 | #
159 | # If you have a more complicated value, like an array of
160 | # hashes, then you'll probably want to use an alternative
161 | # output format. For instance:
162 | #
163 | # trace 'value', :yaml
164 | #
165 | # Valid output format values (the _style_ parameter) are:
166 | #
167 | # :p :inspect
168 | # :pp (pretty-print, using 'pp' library)
169 | # :s :to_s
170 | # :y :yaml :to_yaml (using the 'yaml' library')
171 | #
172 | # The default is :p.
173 | #
174 | # CREDITS:
175 | #
176 | # This code comes straight from the dev-utils Gem.
177 | # Author: Gavin Sinclair
178 |
179 | def trace(expr, style=:p)
180 | unless expr.respond_to? :to_str
181 | warn "trace: Can't evaluate the given value: #{caller.first}"
182 | else
183 | raise "FACETS: binding/or_caller is no longer possible"
184 | require "facets/core/binding/self/of_caller"
185 |
186 | Binding.of_caller do |b|
187 | value = b.eval(expr.to_str)
188 | formatter = TRACE_STYLES[style] || :inspect
189 | case formatter
190 | when :pp then require 'pp'
191 | when :y, :yaml, :to_yaml then require 'yaml'
192 | end
193 | value_s = value.send(formatter)
194 | message = "#{expr} = #{value_s}"
195 | lines = message.split(/\n/)
196 | indent = " "
197 | debug(lines.shift)
198 | lines.each do |line|
199 | debug(indent + line)
200 | end
201 | end
202 | end
203 | end
204 |
205 | TRACE_STYLES = {} # :nodoc:
206 | TRACE_STYLES.update(
207 | :pp => :pp_s, :s => :to_s, :p => :inspect,
208 | :y => :to_yaml, :yaml => :to_yaml,
209 | :inspect => :inspect, :to_yaml => :to_yaml
210 | )
211 | =end
212 |
--------------------------------------------------------------------------------
/lib/ansi/mixin.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 | require 'ansi/code'
3 |
4 | # This module is designed specifically for mixing into
5 | # String-like classes or extending String-like objects.
6 | #
7 | # Generally speaking the String#ansi method is the more
8 | # elegant approach to modifying a string with codes
9 | # via a method call. But in some cases this Mixin's design
10 | # might be preferable. Indeed, it original intent was
11 | # as a compatability layer for the +colored+ gem.
12 |
13 | module Mixin
14 |
15 | def bold ; ANSI::Code.bold { to_s } ; end
16 | def dark ; ANSI::Code.dark { to_s } ; end
17 | def italic ; ANSI::Code.italic { to_s } ; end
18 | def underline ; ANSI::Code.underline { to_s } ; end
19 | def underscore ; ANSI::Code.underscore { to_s } ; end
20 | def blink ; ANSI::Code.blink { to_s } ; end
21 | def rapid ; ANSI::Code.rapid { to_s } ; end
22 | def reverse ; ANSI::Code.reverse { to_s } ; end
23 | def negative ; ANSI::Code.negative { to_s } ; end
24 | def concealed ; ANSI::Code.concealed { to_s } ; end
25 | def strike ; ANSI::Code.strike { to_s } ; end
26 |
27 | def black ; ANSI::Code.black { to_s } ; end
28 | def red ; ANSI::Code.red { to_s } ; end
29 | def green ; ANSI::Code.green { to_s } ; end
30 | def yellow ; ANSI::Code.yellow { to_s } ; end
31 | def blue ; ANSI::Code.blue { to_s } ; end
32 | def magenta ; ANSI::Code.magenta { to_s } ; end
33 | def cyan ; ANSI::Code.cyan { to_s } ; end
34 | def white ; ANSI::Code.white { to_s } ; end
35 |
36 | def on_black ; ANSI::Code.on_black { to_s } ; end
37 | def on_red ; ANSI::Code.on_red { to_s } ; end
38 | def on_green ; ANSI::Code.on_green { to_s } ; end
39 | def on_yellow ; ANSI::Code.on_yellow { to_s } ; end
40 | def on_blue ; ANSI::Code.on_blue { to_s } ; end
41 | def on_magenta ; ANSI::Code.on_magenta { to_s } ; end
42 | def on_cyan ; ANSI::Code.on_cyan { to_s } ; end
43 | def on_white ; ANSI::Code.on_white { to_s } ; end
44 |
45 | def black_on_red ; ANSI::Code.black_on_red { to_s } ; end
46 | def black_on_green ; ANSI::Code.black_on_green { to_s } ; end
47 | def black_on_yellow ; ANSI::Code.black_on_yellow { to_s } ; end
48 | def black_on_blue ; ANSI::Code.black_on_blue { to_s } ; end
49 | def black_on_magenta ; ANSI::Code.black_on_magenta { to_s } ; end
50 | def black_on_cyan ; ANSI::Code.black_on_cyan { to_s } ; end
51 | def black_on_white ; ANSI::Code.black_on_white { to_s } ; end
52 |
53 | def red_on_black ; ANSI::Code.red_on_black { to_s } ; end
54 | def red_on_green ; ANSI::Code.red_on_green { to_s } ; end
55 | def red_on_yellow ; ANSI::Code.red_on_yellow { to_s } ; end
56 | def red_on_blue ; ANSI::Code.red_on_blue { to_s } ; end
57 | def red_on_magenta ; ANSI::Code.red_on_magenta { to_s } ; end
58 | def red_on_cyan ; ANSI::Code.red_on_cyan { to_s } ; end
59 | def red_on_white ; ANSI::Code.red_on_white { to_s } ; end
60 |
61 | def green_on_black ; ANSI::Code.green_on_black { to_s } ; end
62 | def green_on_red ; ANSI::Code.green_on_red { to_s } ; end
63 | def green_on_yellow ; ANSI::Code.green_on_yellow { to_s } ; end
64 | def green_on_blue ; ANSI::Code.green_on_blue { to_s } ; end
65 | def green_on_magenta ; ANSI::Code.green_on_magenta { to_s } ; end
66 | def green_on_cyan ; ANSI::Code.green_on_cyan { to_s } ; end
67 | def green_on_white ; ANSI::Code.green_on_white { to_s } ; end
68 |
69 | def yellow_on_black ; ANSI::Code.yellow_on_black { to_s } ; end
70 | def yellow_on_red ; ANSI::Code.yellow_on_red { to_s } ; end
71 | def yellow_on_green ; ANSI::Code.yellow_on_green { to_s } ; end
72 | def yellow_on_blue ; ANSI::Code.yellow_on_blue { to_s } ; end
73 | def yellow_on_magenta ; ANSI::Code.yellow_on_magenta { to_s } ; end
74 | def yellow_on_cyan ; ANSI::Code.yellow_on_cyan { to_s } ; end
75 | def yellow_on_white ; ANSI::Code.yellow_on_white { to_s } ; end
76 |
77 | def blue_on_black ; ANSI::Code.blue_on_black { to_s } ; end
78 | def blue_on_red ; ANSI::Code.blue_on_red { to_s } ; end
79 | def blue_on_green ; ANSI::Code.blue_on_green { to_s } ; end
80 | def blue_on_yellow ; ANSI::Code.blue_on_yellow { to_s } ; end
81 | def blue_on_magenta ; ANSI::Code.blue_on_magenta { to_s } ; end
82 | def blue_on_cyan ; ANSI::Code.blue_on_cyan { to_s } ; end
83 | def blue_on_white ; ANSI::Code.blue_on_white { to_s } ; end
84 |
85 | def magenta_on_black ; ANSI::Code.magenta_on_black { to_s } ; end
86 | def magenta_on_red ; ANSI::Code.magenta_on_red { to_s } ; end
87 | def magenta_on_green ; ANSI::Code.magenta_on_green { to_s } ; end
88 | def magenta_on_yellow ; ANSI::Code.magenta_on_yellow { to_s } ; end
89 | def magenta_on_blue ; ANSI::Code.magenta_on_blue { to_s } ; end
90 | def magenta_on_cyan ; ANSI::Code.magenta_on_cyan { to_s } ; end
91 | def magenta_on_white ; ANSI::Code.magenta_on_white { to_s } ; end
92 |
93 | def cyan_on_black ; ANSI::Code.cyan_on_black { to_s } ; end
94 | def cyan_on_red ; ANSI::Code.cyan_on_red { to_s } ; end
95 | def cyan_on_green ; ANSI::Code.cyan_on_green { to_s } ; end
96 | def cyan_on_yellow ; ANSI::Code.cyan_on_yellow { to_s } ; end
97 | def cyan_on_blue ; ANSI::Code.cyan_on_blue { to_s } ; end
98 | def cyan_on_magenta ; ANSI::Code.cyan_on_magenta { to_s } ; end
99 | def cyan_on_white ; ANSI::Code.cyan_on_white { to_s } ; end
100 |
101 | def white_on_black ; ANSI::Code.white_on_black { to_s } ; end
102 | def white_on_red ; ANSI::Code.white_on_red { to_s } ; end
103 | def white_on_green ; ANSI::Code.white_on_green { to_s } ; end
104 | def white_on_yellow ; ANSI::Code.white_on_yellow { to_s } ; end
105 | def white_on_blue ; ANSI::Code.white_on_blue { to_s } ; end
106 | def white_on_magenta ; ANSI::Code.white_on_magenta { to_s } ; end
107 | def white_on_cyan ; ANSI::Code.white_on_cyan { to_s } ; end
108 |
109 | # Move cursor to line and column, insert +self.to_s+ and return to
110 | # original positon.
111 | def display(line, column=0)
112 | result = "\e[s"
113 | result << "\e[#{line.to_i};#{column.to_i}H"
114 | result << to_s
115 | result << "\e[u"
116 | result
117 | end
118 |
119 | end
120 |
121 | end
122 |
--------------------------------------------------------------------------------
/lib/ansi/progressbar.rb:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2009 Thomas Sawyer
2 | #
3 | # This library is based on the original ProgressBar
4 | # by Satoru Takabayashi.
5 | #
6 | # ProgressBar Copyright (C) 2001 Satoru Takabayashi
7 |
8 | require 'ansi/code'
9 |
10 | module ANSI
11 |
12 | # = Progressbar
13 | #
14 | # Progressbar is a text-based progressbar library.
15 | #
16 | # pbar = Progressbar.new( "Demo", 100 )
17 | # 100.times { pbar.inc }
18 | # pbar.finish
19 | #
20 | class ProgressBar
21 | #
22 | def initialize(title, total, out=STDERR)
23 | @title = title
24 | @total = total
25 | @out = out
26 |
27 | @bar_length = 80
28 | @bar_mark = "|"
29 | @total_overflow = true
30 | @current = 0
31 | @previous = 0
32 | @is_finished = false
33 | @start_time = Time.now
34 | @format = "%-14s %3d%% %s %s"
35 | @format_arguments = [:title, :percentage, :bar, :stat]
36 | @styles = {}
37 | #
38 | yield self if block_given?
39 | #
40 | show_progress
41 | end
42 |
43 | public
44 |
45 | attr_accessor :format
46 | attr_accessor :format_arguments
47 | attr_accessor :styles
48 |
49 | #
50 | def title=(str)
51 | @title = str
52 | end
53 | #
54 | def bar_mark=(mark)
55 | @bar_mark = String(mark)[0..0]
56 | end
57 | alias_method :barmark=, :bar_mark=
58 | alias_method :mark=, :bar_mark=
59 |
60 | def total_overflow=(boolv)
61 | @total_overflow = boolv ? true : false
62 | end
63 |
64 | # Get rid of warning about Kenrel method being redefined.
65 | remove_method :format
66 |
67 | # Set format and format arguments.
68 | def format(format, *arguments)
69 | @format = format
70 | @format_arguments = *arguments unless arguments.empty?
71 | end
72 |
73 | # Set ANSI styling options.
74 | def style(options)
75 | @styles = options
76 | end
77 |
78 | #
79 | def standard_mode
80 | @format = "%-14s %3d%% %s %s"
81 | @format_arguments = [:title, :percentage, :bar, :stat]
82 | end
83 |
84 | #
85 | def transfer_mode
86 | @format = "%-14s %3d%% %s %s"
87 | @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
88 | end
89 |
90 | # For backward compatability
91 | alias_method :file_transfer_mode, :transfer_mode
92 |
93 | def finish
94 | @current = @total
95 | @is_finished = true
96 | show_progress
97 | end
98 |
99 | def flush
100 | @out.flush
101 | end
102 |
103 | def halt
104 | @is_finished = true
105 | show_progress
106 | end
107 |
108 | def set(count)
109 | if count < 0
110 | raise "invalid count less than zero: #{count}"
111 | elsif count > @total
112 | if @total_overflow
113 | @total = count + 1
114 | else
115 | raise "invalid count greater than total: #{count}"
116 | end
117 | end
118 | @current = count
119 | show_progress
120 | @previous = @current
121 | end
122 |
123 | #
124 | def reset
125 | @current = 0
126 | @is_finished = false
127 | end
128 |
129 | #
130 | def inc(step = 1)
131 | @current += step
132 | @current = @total if @current > @total
133 | show_progress
134 | @previous = @current
135 | end
136 |
137 | #
138 | def clear
139 | @out.print(" " * get_width + eol)
140 | end
141 |
142 | def inspect
143 | "(ProgressBar: #{@current}/#{@total})"
144 | end
145 |
146 | private
147 |
148 | #
149 | def convert_bytes(bytes)
150 | if bytes < 1024
151 | sprintf("%6dB", bytes)
152 | elsif bytes < 1024 * 1000 # 1000kb
153 | sprintf("%5.1fKB", bytes.to_f / 1024)
154 | elsif bytes < 1024 * 1024 * 1000 # 1000mb
155 | sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
156 | else
157 | sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
158 | end
159 | end
160 | #
161 | def transfer_rate
162 | bytes_per_second = @current.to_f / (Time.now - @start_time)
163 | sprintf("%s/s", convert_bytes(bytes_per_second))
164 | end
165 | #
166 | def bytes
167 | convert_bytes(@current)
168 | end
169 | #
170 | def format_time(t)
171 | t = t.to_i
172 | sec = t % 60
173 | min = (t / 60) % 60
174 | hour = t / 3600
175 | sprintf("%02d:%02d:%02d", hour, min, sec);
176 | end
177 | #
178 | # ETA stands for Estimated Time of Arrival.
179 | def eta
180 | if @current == 0
181 | "ETA: --:--:--"
182 | else
183 | elapsed = Time.now - @start_time
184 | eta = elapsed * @total / @current - elapsed;
185 | sprintf("ETA: %s", format_time(eta))
186 | end
187 | end
188 | #
189 | def elapsed
190 | elapsed = Time.now - @start_time
191 | sprintf("Time: %s", format_time(elapsed))
192 | end
193 | #
194 | def stat
195 | if @is_finished then elapsed else eta end
196 | end
197 | #
198 | def stat_for_file_transfer
199 | if @is_finished then
200 | sprintf("%s %s %s", bytes, transfer_rate, elapsed)
201 | else
202 | sprintf("%s %s %s", bytes, transfer_rate, eta)
203 | end
204 | end
205 | #
206 | def eol
207 | if @is_finished then "\n" else "\r" end
208 | end
209 | #
210 | def bar
211 | len = percentage * @bar_length / 100
212 | sprintf("|%s%s|", @bar_mark * len, " " * (@bar_length - len))
213 | end
214 | #
215 | def percentage
216 | if @total.zero?
217 | 100
218 | else
219 | @current * 100 / @total
220 | end
221 | end
222 | #
223 | def title
224 | @title[0,13] + ":"
225 | end
226 |
227 | # TODO: Use Terminal.terminal_width instead.
228 | def get_width
229 | # FIXME: I don't know how portable it is.
230 | default_width = 80
231 | begin
232 | tiocgwinsz = 0x5413
233 | data = [0, 0, 0, 0].pack("SSSS")
234 | if @out.ioctl(tiocgwinsz, data) >= 0 then
235 | #rows, cols, xpixels, ypixels = data.unpack("SSSS")
236 | cols = data.unpack("SSSS")[1]
237 | if cols >= 0 then cols else default_width end
238 | else
239 | default_width
240 | end
241 | rescue Exception
242 | default_width
243 | end
244 | end
245 |
246 | #
247 | def show
248 | arguments = @format_arguments.map do |method|
249 | colorize(send(method), styles[method])
250 | end
251 | line = sprintf(@format, *arguments)
252 | width = get_width
253 | length = ANSI::Code.uncolor{line}.length
254 | if length == width - 1
255 | @out.print(line + eol)
256 | elsif length >= width
257 | @bar_length = [@bar_length - (length - width + 1), 0].max
258 | @bar_length == 0 ? @out.print(line + eol) : show
259 | else #line.length < width - 1
260 | @bar_length += width - length + 1
261 | show
262 | end
263 | end
264 |
265 | #
266 | def show_progress
267 | if @total.zero?
268 | cur_percentage = 100
269 | prev_percentage = 0
270 | else
271 | cur_percentage = (@current * 100 / @total).to_i
272 | prev_percentage = (@previous * 100 / @total).to_i
273 | end
274 | if cur_percentage > prev_percentage || @is_finished
275 | show
276 | end
277 | end
278 |
279 | #
280 | def colorize(part, style)
281 | return part unless style
282 | #[style].flatten.inject(part){ |pt, st| ANSI::Code.ansi(pt, *st) }
283 | ANSI::Code.ansi(part, *style)
284 | end
285 |
286 | end
287 |
288 | #
289 | Progressbar = ProgressBar #:nodoc:
290 |
291 | end
292 |
293 |
--------------------------------------------------------------------------------
/lib/ansi/string.rb:
--------------------------------------------------------------------------------
1 | require 'ansi/code'
2 | #require 'ansi/layout/split'
3 |
4 | # Create a new Ansi::String object.
5 | def ANSI.string(str)
6 | ANSI::String.new(str)
7 | end
8 |
9 | # IMPORTANT! ANSI::String is experimental!!!
10 | #
11 | # ANSI::String stores a regular string (`@text`) and an associative
12 | # array that ties a character index to an ANSI code (`marks`).
13 | # For example is we have the string:
14 | #
15 | # "Big Apple"
16 | #
17 | # And applied the color red to it, the marks list would be:
18 | #
19 | # [[0, :red], [9, :clear]]
20 | #
21 | # TODO: In the future we may be able to subclass String,
22 | # instead of delegating via @text, but not until it is more
23 | # compatible.
24 | #
25 | class ANSI::String
26 |
27 | CLR = ANSI::Code::CLEAR
28 |
29 | attr :text
30 | attr :marks
31 |
32 | # New Ansi::String
33 | def initialize(text=nil, marks=nil)
34 | @text = (text || '').to_s
35 | @marks = marks || []
36 | yield(self) if block_given?
37 | end
38 |
39 | # Convert Ansi::String object to normal String.
40 | # This converts the intental markup codes to ANSI codes.
41 | def to_s
42 | s = text.dup
43 | m = marks.sort do |a,b|
44 | v = b[0] <=> a[0]
45 | if v == 0
46 | (b[1] == :clear or b[1] == :reset) ? -1 : 1
47 | else
48 | v
49 | end
50 | end
51 | m.each do |(index, code)|
52 | s.insert(index, ANSI::Code.__send__(code))
53 | end
54 | #s << CLR unless s =~ /#{Regexp.escape(CLR)}$/ # always end with a clear
55 | s
56 | end
57 |
58 | # ANSI::String is a type of String.
59 | alias_method :to_str, :to_s
60 |
61 | # The size of the base text.
62 | def size ; text.size ; end
63 |
64 | # Upcase the string.
65 | def upcase ; self.class.new(text.upcase, marks) ; end
66 | def upcase! ; text.upcase! ; end
67 |
68 | # Downcase the string.
69 | def downcase ; self.class.new(text.downcase, marks) ; end
70 | def downcase! ; text.upcase! ; end
71 |
72 | # Add one String to another, or to a regular String.
73 | def +(other)
74 | case other
75 | when ANSI::String
76 | ntext = text + other.text
77 | nmarks = marks.dup
78 | omarks = shift_marks(0, text.size, other.marks)
79 | omarks.each{ |(i, c)| nmarks << [i,c] }
80 | else
81 | ntext = text + other.to_s
82 | nmarks = marks.dup
83 | end
84 | self.class.new(ntext, nmarks)
85 | end
86 |
87 | #
88 | #def |(other)
89 | # Split.new(self, other)
90 | #end
91 |
92 | #
93 | #def lr(other, options={})
94 | # Split.new(self, other, options)
95 | #end
96 |
97 | # slice
98 | def slice(*args)
99 | if args.size == 2
100 | index, len = *args
101 | endex = index+len
102 | new_text = text[index, len]
103 | new_marks = []
104 | marks.each do |(i, v)|
105 | new_marks << [i, v] if i >= index && i < endex
106 | end
107 | self.class.new(new_text, new_marks)
108 | elsif args.size == 1
109 | rng = args.first
110 | case rng
111 | when Range
112 | index, endex = rng.begin, rng.end
113 | new_text = text[rng]
114 | new_marks = []
115 | marks.each do |(i, v)|
116 | new_marks << [i, v] if i >= index && i < endex
117 | end
118 | self.class.new(new_text, new_marks)
119 | else
120 | nm = marks.select do |(i, v)|
121 | #marks[0] == rng or ( marks[0] == rng + 1 && [:clear, :reset].include?(marks[1]) )
122 | i == rng or ( i == rng + 1 && [:clear, :reset].include?(v) )
123 | end
124 | self.class.new(text[rng,1], nm)
125 | end
126 | else
127 | raise ArgumentError
128 | end
129 | end
130 |
131 | #
132 | alias_method :[], :slice
133 |
134 | # This is more limited than the normal String method.
135 | # It does not yet support a block, and +replacement+
136 | # won't substitue for \1, \2, etc.
137 | #
138 | # TODO: block support.
139 | def sub!(pattern, replacement=nil, &block)
140 | mark_changes = []
141 | text = @text.sub(pattern) do |s|
142 | index = $~.begin(0)
143 | replacement = block.call(s) if block_given?
144 | delta = (replacement.size - s.size)
145 | mark_changes << [index, delta]
146 | replacement
147 | end
148 | marks = @marks
149 | mark_changes.each do |index, delta|
150 | marks = shift_marks(index, delta, marks)
151 | end
152 | @text = text
153 | @marks = marks
154 | self
155 | end
156 |
157 | # See #sub!.
158 | def sub(pattern,replacement=nil, &block)
159 | dup.sub!(pattern, replacement, &block)
160 | end
161 |
162 | #
163 | def gsub!(pattern, replacement=nil, &block)
164 | mark_changes = []
165 | mark_additions = []
166 | text = @text.gsub(pattern) do |s|
167 | index = $~.begin(0)
168 | replacement = block.call(self.class.new(s)) if block_given?
169 | if self.class===replacement
170 | adj_marks = replacement.marks.map{ |(i,c)| [i+index,c] }
171 | mark_additions.concat(adj_marks)
172 | replacement = replacement.text
173 | end
174 | delta = (replacement.size - s.size)
175 | mark_changes << [index, delta]
176 | replacement
177 | end
178 | marks = @marks
179 | mark_changes.each do |(index, delta)|
180 | marks = shift_marks(index, delta, marks)
181 | end
182 | marks.concat(mark_additions)
183 | @text = text
184 | @marks = marks
185 | self
186 | end
187 |
188 | # See #gsub!.
189 | def gsub(pattern, replacement=nil, &block)
190 | dup.gsub!(pattern, replacement, &block)
191 | end
192 |
193 | #
194 | def ansi(code)
195 | m = marks.dup
196 | m.unshift([0, code])
197 | m.push([size, :clear])
198 | self.class.new(text, m)
199 | end
200 |
201 | alias_method :color, :ansi
202 |
203 | #
204 | def ansi!(code)
205 | marks.unshift([0, code])
206 | marks.push([size, :clear])
207 | end
208 |
209 | alias_method :color!, :ansi!
210 |
211 | def red ; color(:red) ; end
212 | def green ; color(:green) ; end
213 | def blue ; color(:blue) ; end
214 | def black ; color(:black) ; end
215 | def magenta ; color(:magenta) ; end
216 | def yellow ; color(:yellow) ; end
217 | def cyan ; color(:cyan) ; end
218 |
219 | def bold ; ansi(:bold) ; end
220 | def underline ; ansi(:underline) ; end
221 |
222 | def red! ; color!(:red) ; end
223 | def green! ; color!(:green) ; end
224 | def blue! ; color!(:blue) ; end
225 | def black! ; color!(:black) ; end
226 | def magenta! ; color!(:magenta) ; end
227 | def yellow! ; color!(:yellow) ; end
228 | def cyan! ; color!(:cyan) ; end
229 |
230 | def bold! ; ansi!(:bold) ; end
231 | def underline! ; ansi!(:underline) ; end
232 |
233 | private
234 |
235 | #
236 | def shift_marks(index, delta, marks=nil)
237 | new_marks = []
238 | (marks || @marks).each do |(i, c)|
239 | case i <=> index
240 | when -1
241 | new_marks << [i, c]
242 | when 0, 1
243 | new_marks << [i+delta, c]
244 | end
245 | end
246 | new_marks
247 | end
248 |
249 | #
250 | def shift_marks!(index, delta)
251 | @marks.replace(shift_marks(index, delta))
252 | end
253 |
254 | end
255 |
--------------------------------------------------------------------------------
/lib/ansi/table.rb:
--------------------------------------------------------------------------------
1 | require 'ansi/core'
2 | require 'ansi/terminal'
3 |
4 | module ANSI
5 |
6 | class Table
7 |
8 | # The Table class can be used to output nicely formatted
9 | # tables with division lines and alignment.
10 | #
11 | # table - array of array
12 | #
13 | # options[:align] - align :left or :right
14 | # options[:padding] - space to add to each cell
15 | # options[:fit] - fit to screen width
16 | # options[:border] -
17 | #
18 | # The +format+ block must return ANSI codes to apply
19 | # to each cell.
20 | #
21 | # Other Implementations:
22 | #
23 | # * http://github.com/visionmedia/terminal-table
24 | # * http://github.com/aptinio/text-table
25 | #
26 | # TODO: Support for table headers and footers.
27 | def initialize(table, options={}, &format)
28 | @table = table
29 | @padding = options[:padding] || 0
30 | @align = options[:align]
31 | @fit = options[:fit]
32 | @border = options[:border]
33 | #@ansi = [options[:ansi]].flatten
34 | @format = format
35 |
36 | @pad = " " * @padding
37 | end
38 |
39 | #
40 | attr_accessor :table
41 |
42 | # Fit to scree width.
43 | attr_accessor :fit
44 |
45 | #
46 | attr_accessor :padding
47 |
48 | #
49 | attr_accessor :align
50 |
51 | #
52 | attr_accessor :format
53 |
54 | #
55 | attr_accessor :border
56 |
57 | #
58 | def to_s #(fit=false)
59 | #row_count = table.size
60 | #col_count = table[0].size
61 |
62 | max = max_columns(fit)
63 |
64 | div = dividing_line
65 | top = div #.gsub('+', ".")
66 | bot = div #.gsub('+', "'")
67 |
68 | body = []
69 | table.each_with_index do |row, r|
70 | body_row = []
71 | row.each_with_index do |cell, c|
72 | t = cell_template(max[c])
73 | s = t % cell.to_s
74 | body_row << apply_format(s, cell, c, r)
75 | end
76 | body << "| " + body_row.join(' | ') + " |"
77 | end
78 |
79 | if border
80 | body = body.join("\n#{div}\n")
81 | else
82 | body = body.join("\n")
83 | end
84 |
85 | "#{top}\n#{body}\n#{bot}\n"
86 | end
87 |
88 | private
89 |
90 | # TODO: look at the lines and figure out how many columns will fit
91 | def fit_width
92 | width = Terminal.terminal_width
93 | ((width.to_f / column_size) - (padding + 3)).to_i
94 | end
95 |
96 | # Calculate the maximun column sizes.
97 | #
98 | # @return [Array] maximum size for each column
99 | def max_columns(fit=false)
100 | max = Array.new(column_size, 0)
101 | table.each do |row|
102 | row.each_with_index do |col, index|
103 | col = col.to_s
104 | col = col.unansi
105 | if fit
106 | max[index] = [max[index], col.size, fit_width].max
107 | else
108 | max[index] = [max[index], col.size].max
109 | end
110 | end
111 | end
112 | max
113 | end
114 |
115 | # Number of columns based on the first row of table.
116 | #
117 | # @return [Integer] number of columns
118 | def column_size
119 | table.first.size
120 | end
121 |
122 | #
123 | def cell_template(max)
124 | case align
125 | when :right, 'right'
126 | "#{@pad}%#{max}s"
127 | else
128 | "%-#{max}s#{@pad}"
129 | end
130 | end
131 |
132 | # TODO: make more efficient
133 | def dividing_line
134 | tmp = max_columns(fit).map{ |m| "%#{m}s" }.join(" | ")
135 | tmp = "| #{tmp} |"
136 | lin = (tmp % (['-'] * column_size)).gsub(/[^\|]/, '-').gsub('|', '+')
137 | lin
138 | end
139 |
140 | #def dividing_line_top
141 | # dividing_line.gsub('+', '.')
142 | #end
143 |
144 | #def dividing_line_bottom
145 | # dividing_line.gsub('+', "'")
146 | #end
147 |
148 | #
149 | def apply_format(str, cell, col, row)
150 | if @format
151 | str.ansi(*ansi_formating(cell, col, row))
152 | else
153 | str
154 | end
155 | end
156 |
157 | #
158 | def ansi_formating(cell, col, row)
159 | if @format
160 | case @format.arity
161 | when 0
162 | f = @format[]
163 | when 1
164 | f = @format[cell]
165 | when 2
166 | f = @format[row, col]
167 | else
168 | f = @format[cell, row, col]
169 | end
170 | else
171 | f = nil
172 | end
173 | [f].flatten.compact
174 | end
175 |
176 | end
177 |
178 | end
179 |
180 |
--------------------------------------------------------------------------------
/lib/ansi/terminal.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | # = Terminal
4 | #
5 | # This library is based of HighLine's SystemExtensions
6 | # by James Edward Gray II.
7 | #
8 | # Copyright 2006 Gray Productions
9 | #
10 | # Distributed under the tems of the
11 | # {Ruby software license}[http://www.ruby-lang.org/en/LICENSE.txt].
12 |
13 | module Terminal
14 |
15 | module_function
16 |
17 | modes = %w{win32 termios curses stty}
18 |
19 | # This section builds character reading and terminal size functions
20 | # to suit the proper platform we're running on.
21 | #
22 | # Be warned: Here be dragons!
23 | #
24 | begin
25 | require 'ansi/terminal/' + (mode = modes.shift)
26 | CHARACTER_MODE = mode
27 | rescue LoadError
28 | retry
29 | end
30 |
31 | # Get the width of the terminal window.
32 | def terminal_width
33 | terminal_size.first
34 | end
35 |
36 | # Get the height of the terminal window.
37 | def terminal_height
38 | terminal_size.last
39 | end
40 |
41 | end
42 |
43 | end
44 |
45 |
--------------------------------------------------------------------------------
/lib/ansi/terminal/curses.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | module Terminal
4 | require 'curses'
5 |
6 | module_function
7 |
8 | #CHARACTER_MODE = "curses" # For Debugging purposes only.
9 |
10 | #
11 | # Curses savvy getc().
12 | #
13 | def get_character(input = STDIN)
14 | Curses.getch()
15 | end
16 |
17 | def terminal_size
18 | Curses.init_screen
19 | w, r = Curses.cols, Curses.lines
20 | Curses.close_screen
21 | return w, r
22 | end
23 |
24 | end
25 |
26 | end
27 |
--------------------------------------------------------------------------------
/lib/ansi/terminal/stty.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | module Terminal
4 | module_function
5 |
6 | #COLS_FALLBACK = 80
7 | #ROWS_FALLBACK = 25
8 |
9 | #CHARACTER_MODE = "stty" # For Debugging purposes only.
10 |
11 | #
12 | # Unix savvy getc(). (second choice)
13 | #
14 | # *WARNING*: This method requires the external "stty" program!
15 | #
16 | def get_character(input = STDIN)
17 | raw_no_echo_mode
18 |
19 | begin
20 | input.getc
21 | ensure
22 | restore_mode
23 | end
24 | end
25 |
26 | #
27 | # Switched the input mode to raw and disables echo.
28 | #
29 | # *WARNING*: This method requires the external "stty" program!
30 | #
31 | def raw_no_echo_mode
32 | @state = `stty -g`
33 | system "stty raw -echo cbreak isig"
34 | end
35 |
36 | #
37 | # Restores a previously saved input mode.
38 | #
39 | # *WARNING*: This method requires the external "stty" program!
40 | #
41 | def restore_mode
42 | system "stty #{@state}"
43 | end
44 |
45 | # A Unix savvy method to fetch the console columns, and rows.
46 | def terminal_size
47 | if /solaris/ =~ RUBY_PLATFORM && (`stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/)
48 | w, r = [$2, $1]
49 | else
50 | w, r = `stty size`.split.reverse
51 | end
52 | w = `tput cols` unless w # last ditch effort to at least get width
53 |
54 | w = w.to_i if w
55 | r = r.to_i if r
56 |
57 | return w, r
58 | end
59 |
60 | end
61 |
62 | end
63 |
--------------------------------------------------------------------------------
/lib/ansi/terminal/termios.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | module Terminal
4 | require "termios" # Unix, first choice.
5 |
6 | module_function
7 |
8 | #CHARACTER_MODE = "termios" # For Debugging purposes only.
9 |
10 | #
11 | # Unix savvy getc(). (First choice.)
12 | #
13 | # *WARNING*: This method requires the "termios" library!
14 | #
15 | def get_character( input = STDIN )
16 | old_settings = Termios.getattr(input)
17 |
18 | new_settings = old_settings.dup
19 | new_settings.c_lflag &= ~(Termios::ECHO | Termios::ICANON)
20 | new_settings.c_cc[Termios::VMIN] = 1
21 |
22 | begin
23 | Termios.setattr(input, Termios::TCSANOW, new_settings)
24 | input.getc
25 | ensure
26 | Termios.setattr(input, Termios::TCSANOW, old_settings)
27 | end
28 | end
29 |
30 | # A Unix savvy method to fetch the console columns, and rows.
31 | def terminal_size
32 | if /solaris/ =~ RUBY_PLATFORM && (`stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/)
33 | w, r = [$2, $1]
34 | else
35 | w, r = `stty size`.split.reverse
36 | end
37 | w = `tput cols` unless w # last ditch effort to at least get width
38 |
39 | w = w.to_i if w
40 | r = r.to_i if r
41 |
42 | return w, r
43 | end
44 |
45 | # Console screen width (taken from progress bar)
46 | #
47 | # NOTE: Don't know how portable #screen_width is.
48 | # TODO: How to fit into system?
49 | #
50 | def screen_width(out=STDERR)
51 | default_width = ENV['COLUMNS'] || 76
52 | begin
53 | tiocgwinsz = 0x5413
54 | data = [0, 0, 0, 0].pack("SSSS")
55 | if out.ioctl(tiocgwinsz, data) >= 0 then
56 | rows, cols, xpixels, ypixels = data.unpack("SSSS")
57 | if cols >= 0 then cols else default_width end
58 | else
59 | default_width
60 | end
61 | rescue Exception
62 | default_width
63 | end
64 | end
65 |
66 | end
67 |
68 | end
69 |
--------------------------------------------------------------------------------
/lib/ansi/terminal/win32.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 |
3 | module Terminal
4 | # Cygwin will look like Windows, but we want to treat it like a Posix OS:
5 | raise LoadError, "Cygwin is a Posix OS." if RUBY_PLATFORM =~ /\bcygwin\b/i
6 |
7 | require "Win32API" # See if we're on Windows.
8 |
9 | module_function
10 |
11 | #CHARACTER_MODE = "Win32API" # For Debugging purposes only.
12 |
13 | #
14 | # Windows savvy getc().
15 | #
16 | #
17 | def get_character( input = STDIN )
18 | @stdin_handle ||= GetStdHandle(STD_INPUT_HANDLE)
19 |
20 | begin
21 | SetConsoleEcho(@stdin_handle, false)
22 | input.getc
23 | ensure
24 | SetConsoleEcho(@stdin_handle, true)
25 | end
26 | end
27 |
28 | # A Windows savvy method to fetch the console columns, and rows.
29 | def terminal_size
30 | stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE)
31 |
32 | bufx, bufy, curx, cury, wattr, left, top, right, bottom, maxx, maxy =
33 | GetConsoleScreenBufferInfo(stdout_handle)
34 | return right - left + 1, bottom - top + 1
35 | end
36 |
37 | # windows savvy console echo toggler
38 | def SetConsoleEcho( console_handle, on )
39 | mode = GetConsoleMode(console_handle)
40 |
41 | # toggle the console echo bit
42 | if on
43 | mode |= ENABLE_ECHO_INPUT
44 | else
45 | mode &= ~ENABLE_ECHO_INPUT
46 | end
47 |
48 | ok = SetConsoleMode(console_handle, mode)
49 | end
50 |
51 | # win32 console APIs
52 |
53 | STD_INPUT_HANDLE = -10
54 | STD_OUTPUT_HANDLE = -11
55 | STD_ERROR_HANDLE = -12
56 |
57 | ENABLE_PROCESSED_INPUT = 0x0001
58 | ENABLE_LINE_INPUT = 0x0002
59 | ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
60 | ENABLE_ECHO_INPUT = 0x0004
61 | ENABLE_WINDOW_INPUT = 0x0008
62 | ENABLE_MOUSE_INPUT = 0x0010
63 | ENABLE_INSERT_MODE = 0x0020
64 | ENABLE_QUICK_EDIT_MODE = 0x0040
65 |
66 | @@apiGetStdHandle = nil
67 | @@apiGetConsoleMode = nil
68 | @@apiSetConsoleMode = nil
69 | @@apiGetConsoleScreenBufferInfo = nil
70 |
71 | def GetStdHandle( handle_type )
72 | @@apiGetStdHandle ||= Win32API.new( "kernel32", "GetStdHandle",
73 | ['L'], 'L' )
74 |
75 | @@apiGetStdHandle.call( handle_type )
76 | end
77 |
78 | def GetConsoleMode( console_handle )
79 | @@apiGetConsoleMode ||= Win32API.new( "kernel32", "GetConsoleMode",
80 | ['L', 'P'], 'I' )
81 |
82 | mode = ' ' * 4
83 | @@apiGetConsoleMode.call(console_handle, mode)
84 | mode.unpack('L')[0]
85 | end
86 |
87 | def SetConsoleMode( console_handle, mode )
88 | @@apiSetConsoleMode ||= Win32API.new( "kernel32", "SetConsoleMode",
89 | ['L', 'L'], 'I' )
90 |
91 | @@apiSetConsoleMode.call(console_handle, mode) != 0
92 | end
93 |
94 | def GetConsoleScreenBufferInfo( console_handle )
95 | @@apiGetConsoleScreenBufferInfo ||=
96 | Win32API.new( "kernel32", "GetConsoleScreenBufferInfo",
97 | ['L', 'P'], 'L' )
98 |
99 | format = 'SSSSSssssSS'
100 | buf = ([0] * format.size).pack(format)
101 | @@apiGetConsoleScreenBufferInfo.call(console_handle, buf)
102 | buf.unpack(format)
103 | end
104 |
105 | end
106 |
107 | end
108 |
--------------------------------------------------------------------------------
/lib/ansi/version.rb:
--------------------------------------------------------------------------------
1 | module ANSI
2 | # Returns Hash table of project metadata.
3 | def self.metadata
4 | @spec ||= (
5 | require 'yaml'
6 | YAML.load(File.new(File.dirname(__FILE__) + '/../ansi.yml'))
7 | )
8 | end
9 |
10 | # Check metadata for missing constants.
11 | def self.const_missing(name)
12 | metadata[name.to_s.downcase] || super(name)
13 | end
14 | end
15 |
16 |
--------------------------------------------------------------------------------
/test/case_ansicode.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | require 'ansi/code'
3 |
4 | testcase ANSI::Code do
5 |
6 | method :red do
7 | test do
8 | str = ANSI::Code.red
9 | out = "\e[31m"
10 | out.assert == str
11 | end
12 |
13 | test "with block notation" do
14 | str = ANSI::Code.red { "Hello" }
15 | out = "\e[31mHello\e[0m"
16 | out.assert == str
17 | end
18 | end
19 |
20 | method :blue do
21 | test do
22 | str = ANSI::Code.blue
23 | out = "\e[34m"
24 | out.assert == str
25 | end
26 |
27 | test "with block notation" do
28 | str = ANSI::Code.blue { "World" }
29 | out = "\e[34mWorld\e[0m"
30 | out.assert == str
31 | end
32 | end
33 |
34 | method :hex do
35 | test do
36 | str = ANSI::Code.hex("#000000")
37 | out = "0"
38 | out.assert == str
39 | end
40 | end
41 |
42 | end
43 |
44 |
--------------------------------------------------------------------------------
/test/case_bbcode.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | require 'ansi/bbcode'
3 |
4 | testcase ANSI::BBCode do
5 |
6 | class_method :bbcode_to_ansi do
7 | test do
8 | str = "this is [COLOR=red]red[/COLOR], this is [B]bold[/B]"
9 | out = "this is \e[0;31mred\e[0m, this is \e[1mbold\e[0m\n"
10 | out.assert == ANSI::BBCode.bbcode_to_ansi(str)
11 | end
12 | end
13 |
14 | class_method :bbcode_to_html do
15 | test do
16 | str = "this is [COLOR=red]red[/COLOR], this is [B]bold[/B]"
17 | out = "this is red, this is bold
\n"
18 | out.assert == ANSI::BBCode.bbcode_to_html(str)
19 | end
20 | end
21 |
22 | class_method :ansi_to_html do
23 | test do
24 | str = "this is \e[0;31mred\e[0m, this is \e[1mbold\e[0m\n" +
25 | "this is a line without any ansi code\n" +
26 | "this is \e[0;31mred\e[0m, this is \e[1mbold\e[0m\n"
27 | out = "this is red, this is bold
\n" +
28 | "this is a line without any ansi code
\n" +
29 | "this is red, this is bold
\n"
30 | out.assert == ANSI::BBCode.ansi_to_html(str)
31 | end
32 | end
33 |
34 | end
35 |
36 |
--------------------------------------------------------------------------------
/test/case_mixin.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | require 'ansi/mixin'
3 |
4 | testcase ANSI::Mixin do
5 |
6 | # TODO: subclass
7 | class ::String
8 | include ANSI::Mixin
9 | end
10 |
11 | method :red do
12 | test do
13 | str = "Hello".red
14 | out = "\e[31mHello\e[0m"
15 | out.assert == str
16 | end
17 | end
18 |
19 | method :blue do
20 | test do
21 | str = "World".blue
22 | out = "\e[34mWorld\e[0m"
23 | out.assert == str
24 | end
25 | end
26 |
27 | method :display do
28 | test do
29 | str = "Hello".display(4,10)
30 | out = "\e[s\e[4;10HHello\e[u"
31 | out.assert == str
32 | end
33 | end
34 |
35 | end
36 |
--------------------------------------------------------------------------------
/test/case_progressbar.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | require 'stringio'
3 | require 'ansi/progressbar'
4 |
5 | testcase ANSI::Progressbar do
6 |
7 | method :initialize do
8 | test do
9 | stio = StringIO.new
10 | pbar = ANSI::Progressbar.new("Test Bar", 10, stio) do |b|
11 | b.style(:title => [:red], :bar=>[:blue])
12 | end
13 | 10.times do |i|
14 | sleep 0.1
15 | pbar.inc
16 | end
17 | true
18 | end
19 | end
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | require 'lemon'
2 | require 'ae'
3 |
4 |
--------------------------------------------------------------------------------
/work/NOTES.md:
--------------------------------------------------------------------------------
1 | = DEVELOPMENT NOTES
2 |
3 | == Tweaks Branch
4 |
5 | The `tweaks` branch needs to be merged into master.
6 |
7 |
--------------------------------------------------------------------------------
/work/benchmarks/string_vs_block.rb:
--------------------------------------------------------------------------------
1 | require 'benchmark'
2 | require 'ansi/code'
3 |
4 | n = 50000
5 | Benchmark.bmbm(10) do |x|
6 | x.report("string:"){ n.times{|i| ANSI::Code.red(i.to_s) } }
7 | x.report("block :"){ n.times{|i| ANSI::Code.red{i.to_s} } }
8 | end
9 |
10 |
--------------------------------------------------------------------------------
/work/consider/highlight.rb:
--------------------------------------------------------------------------------
1 | require 'ansi/code'
2 |
3 | file = ARGV.first
4 | text = File.read(file)
5 |
6 | close = ANSI::Code.clear
7 |
8 | def uncolored(str)
9 | ANSI::Code.uncolored(str)
10 | end
11 |
12 | colors = {
13 | :dot => ANSI::Code.red,
14 | :cash => ANSI::Code.green,
15 | :at => ANSI::Code.cyan,
16 | :fn => ANSI::Code.bold + ANSI::Code.blue,
17 | :cap => ANSI::Code.blue,
18 | :sharp => ANSI::Code.white,
19 | :quote => ANSI::Code.red,
20 | }
21 |
22 | work = text.dup
23 |
24 | # xxx(
25 | text.gsub!(/(\W)(\w+?)(?=\()/){ $1 + colors[:fn] + $2 + close }
26 |
27 | # .xxx
28 | text.gsub!(/\.(\w+?)(?=\W)/){ colors[:dot] + '.' + $1 + close }
29 |
30 | # $xxx
31 | text.gsub!(/(\$\w+?)(?=\W)/){ colors[:cash] + $1 + close }
32 |
33 | # @xxx
34 | text.gsub!(/(\$\w+?)(?=\W)/){ colors[:at] + $1 + close }
35 |
36 | # #xxx
37 | text.gsub!(/\#(.*?)$/){ colors[:sharp] + '#' + uncolored($1) + close }
38 |
39 | # XXX
40 | text.gsub!(/([A-Z_]+?)(?=\W)/){ colors[:cap] + $1 + close }
41 |
42 | # 'xxx'
43 | text.gsub!(/(['"].*?["'])/){ colors[:quote] + uncolored($1) + close }
44 |
45 | # #xxx
46 | text.gsub!(/^(\s+)(\#.*?)$/){ $1 + colors[:sharp] + '#' + uncolored($2) + close }
47 |
48 |
49 | $stdout << text
50 |
51 |
--------------------------------------------------------------------------------
/work/consider/string.rd:
--------------------------------------------------------------------------------
1 | = Clio::String
2 |
3 | This is a unit test specification for the Clio::String class.
4 | This class is intended to provide a very convenient way to
5 | output colorful and aligned text to a shell console.
6 |
7 | Require the Clio String library.
8 |
9 | require 'clio/string'
10 |
11 | Define a few regular strings for comparison.
12 |
13 | @s1 = "Hi how are you."
14 | @s2 = "Fine thanks."
15 |
16 | Define the equivalent Clio strings.
17 |
18 | @c1 = Clio.string("Hi how are you.")
19 | @c2 = Clio.string("Fine thanks.")
20 |
21 | Clio::String#ansi is used to wrap the current string in an
22 | ANSI code *bracket*, ie. prepending with the given ANSI code
23 | and appending with the ANSI escape code.
24 |
25 | y = @c1.ansi(:red)
26 | x = "\e[31mHi how are you.\e[0m"
27 | y.to_s.should == x
28 |
29 | Some methods are delegated directly to the underying string,
30 | as they do not effect any ANSI codes have been applied.
31 |
32 | y = @c1.ansi(:red).upcase
33 | x = "\e[31mHI HOW ARE YOU.\e[0m"
34 | y.to_s.should == x
35 |
36 | Shortcut methods are provided for most ANSI Codes, such as
37 | Clio::String#red.
38 |
39 | y = @c1.red
40 | x = "\e[31mHi how are you.\e[0m"
41 | y.to_s.should == x
42 |
43 | Clio::String#[] will return the character at a gven index.
44 | This works like Ruby 1.9, so no size parameter is needed.
45 |
46 | y = @c1[0]
47 | x = @s1[0,1]
48 | y.to_s.should == x
49 |
50 | But the size parameter can be given too.
51 |
52 | y = @c1[0,3]
53 | x = @s1[0,3]
54 | y.to_s.should == x
55 |
56 | A Range works too.
57 |
58 | y = @c1[0..3]
59 | x = @s1[0..3]
60 | y.to_s.should == x
61 |
62 | Clio::String#+ works just like a regular String.
63 |
64 | y = @c1 + @c2
65 | x = @s1 + @s2
66 | y.to_s.should == x
67 |
68 | Complex cases with ANSI codes work as expected.
69 |
70 | s1 = Clio.string("a").red
71 | s2 = Clio.string("b").blue
72 | y = s1 + s2
73 | x = "\e[31ma\e[0m\e[34mb\e[0m"
74 | y.to_s.should == x
75 |
76 | Method #sub can replace a substring.
77 |
78 | y = @c1.sub('Hi', 'Hello')
79 | x = "Hello how are you."
80 | y.to_s.assert == x
81 |
82 | Method #gsub! can replace many substrings.
83 |
84 | s1 = Clio.string("axax").red
85 | s2 = Clio.string("axax").blue
86 | y = s1 + s2
87 | y.to_s.assert == "\e[31maxax\e[0m\e[34maxax\e[0m"
88 | y.gsub!('x', 'y')
89 | y.to_s.assert == "\e[31mayay\e[0m\e[34mayay\e[0m"
90 |
91 | This specification is not complete, but it is a good start.
92 |
93 |
--------------------------------------------------------------------------------
/work/deprecated/ansi.rbz:
--------------------------------------------------------------------------------
1 | # ANSI Module provides a Bezel interface as follows:
2 | #
3 | # ANSI = lib('ansi', '1.2.6')
4 | #
5 | # module MyAPP
6 | # include ANSI
7 | # end
8 | #
9 | # Examples
10 | #
11 | # def hello_world
12 | # puts ansi("Hello World", :red)
13 | # end
14 | #
15 | # # automatically included with ANSI 1.3.
16 | # def ansi(string, *codes)
17 | # ANSI::Code.ansi(string, *codes)
18 | # end
19 | #
20 | # Or
21 | #
22 | # def hello_world
23 | # puts "Hello World".ansi(:red)
24 | # end
25 | #
26 | # NOTE: Core extensions need stable interfaces!
27 | #
28 | module ANSI; end
29 |
30 | import 'ansi/code'
31 | import 'ansi/bbcode'
32 | import 'ansi/columns'
33 | import 'ansi/diff'
34 | import 'ansi/logger'
35 | import 'ansi/mixin'
36 | import 'ansi/progressbar'
37 | import 'ansi/string'
38 | import 'ansi/table'
39 | import 'ansi/terminal'
40 |
41 |
--------------------------------------------------------------------------------
/work/deprecated/task/demo.ergo:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | desc "run demos"
4 |
5 | rule "demo/*.md" => :run_demo
6 | rule "lib/**/*.rb" => :run_all
7 |
8 | def run_demo(*demos)
9 | shell "bundle exec qed -Ilib " + demos.join(' ')
10 | end
11 |
12 | def run_all
13 | shell "bundle exec qed -Ilib demo/*.md"
14 | end
15 |
16 | #task("demo") { shell "qed -Ilib qed/" }
17 |
18 |
--------------------------------------------------------------------------------
/work/deprecated/task/index.ergo:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | desc "update index file"
4 |
5 | rule 'Index.yml' do
6 | shell "index -u Index.yml"
7 | end
8 |
9 |
--------------------------------------------------------------------------------
/work/deprecated/task/syckle-hooks/pre-generate.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | file = "lib/#{project.metadata.name}/version.rb"
3 |
4 | line = []
5 | line << "module ANSI"
6 | line << " VERSION = '#{project.version}'"
7 | line << " DATE = '#{Time.new.strftime("%Y-%m-%d")}'"
8 |
9 | #project.profile.to_h.each do |key, value|
10 | # next if key == "manifest"
11 | # line << " #{key.upcase} = #{value.inspect}"
12 | #end
13 |
14 | line << "end"
15 |
16 | text = line.join("\n")
17 |
18 | if !exist?(file) || read(file) != text
19 | write(file, text)
20 | report "Updated #{file}"
21 | else
22 | report "Already current #{file}"
23 | end
24 |
25 |
--------------------------------------------------------------------------------
/work/deprecated/task/test.ergo:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | desc "run unit tests"
4 |
5 | rule 'test/helper.rb' => :test_all
6 | rule 'test/case_*.rb' => :test
7 | rule /^lib\/(.*?)\.rb$/ => :test_match
8 | rule /^lib\/ansi\/(.*?)\.rb$/ => :test_match
9 |
10 | def test_all
11 | test *Dir['test/test_*.rb']
12 | end
13 |
14 | def test_match(m)
15 | test "test/case_#{m[1]}"
16 | end
17 |
18 | def test(*paths)
19 | shell "bundle exec rubytest #{gem_opt} -Ilib:test " + paths.flatten.join(' ')
20 | end
21 |
22 | def gem_opt
23 | defined?(::Gem) ? "-rubygems" : ""
24 | end
25 |
26 | #Signal.trap('QUIT') { test tests } # Ctrl-\
27 | #Signal.trap('INT' ) { abort("\n") } # Ctrl-C
28 |
29 |
--------------------------------------------------------------------------------
/work/deprecated/task/test.watchr:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | watch( '^test.*/test_.*\.rb' ) { |m| test m[0] }
4 | watch( '^lib/(.*)\.rb' ) { |m| test "test/case_#{m[1]}.rb" }
5 | watch( '^lib/ansi/(.*)\.rb' ) { |m| test "test/case_#{m[1]}.rb" }
6 | watch( '^test/test_helper\.rb' ) { test tests }
7 |
8 | Signal.trap('QUIT') { test tests } # Ctrl-\
9 | Signal.trap('INT' ) { abort("\n") } # Ctrl-C
10 |
11 | def test(*paths)
12 | run "ruby-test #{gem_opt} -Ilib:test #{paths.flatten.join(' ')}"
13 | end
14 |
15 | def tests
16 | Dir['test/**/case_*.rb']
17 | end
18 |
19 | def run(cmd)
20 | puts cmd
21 | system cmd
22 | end
23 |
24 | def gem_opt
25 | defined?(Gem) ? "-rubygems" : ""
26 | end
27 |
28 |
--------------------------------------------------------------------------------
/work/reference/ansicode.rb:
--------------------------------------------------------------------------------
1 | # = ANSICode
2 | #
3 | # Module which makes it very easy to use ANSI codes.
4 | # These are esspecially nice for beautifying shell output.
5 | #
6 | # include ANSICode
7 | #
8 | # p red, "Hello", blue, "World"
9 | # => "\e[31mHello\e[34mWorld"
10 | #
11 | # p red { "Hello" } + blue { "World" }
12 | # => "\e[31mHello\e[0m\e[34mWorld\e[0m"
13 | #
14 | # == Supported ANSI Comands
15 | #
16 | # The following is a list of supported codes.
17 | #
18 | # save
19 | # restore
20 | # clear_screen
21 | # cls # synonym for :clear_screen
22 | # clear_line
23 | # clr # synonym for :clear_line
24 | # move
25 | # up
26 | # down
27 | # left
28 | # right
29 | # display
30 | #
31 | # clear
32 | # reset # synonym for :clear
33 | # bold
34 | # dark
35 | # italic # not widely implemented
36 | # underline
37 | # underscore # synonym for :underline
38 | # blink
39 | # rapid_blink # not widely implemented
40 | # negative # no reverse because of String#reverse
41 | # concealed
42 | # strikethrough # not widely implemented
43 | #
44 | # black
45 | # red
46 | # green
47 | # yellow
48 | # blue
49 | # magenta
50 | # cyan
51 | # white
52 | #
53 | # on_black
54 | # on_red
55 | # on_green
56 | # on_yellow
57 | # on_blue
58 | # on_magenta
59 | # on_cyan
60 | # on_white
61 | #
62 | # == Authors
63 | #
64 | # * Florian Frank
65 | # * Thomas Sawyer
66 | #
67 | # == Speical Thanks
68 | #
69 | # Special thanks to Florian Frank. ANSICode is a partial adaptation
70 | # of ANSIColor, Copyright (c) 2002 Florian Frank, LGPL.
71 | #
72 | # == Todo
73 | #
74 | # * Need to add rest of ANSI codes. Include modes?
75 | # * Re-evaluate how color/yielding methods are defined.
76 | # * Maybe up, down, right, left should have yielding methods too?
77 | #
78 | # == Copying
79 | #
80 | # Copyright (c) 2004 Florian Frank, Thomas Sawyer
81 | #
82 | # Ruby License
83 | #
84 | # This module is free software. You may use, modify, and/or redistribute this
85 | # software under the same terms as Ruby.
86 | #
87 | # This program is distributed in the hope that it will be useful, but WITHOUT
88 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
89 | # FOR A PARTICULAR PURPOSE.
90 |
91 |
92 | # = ANSICode
93 | #
94 | # Module which makes it very easy to use ANSI codes.
95 | # These are esspecially nice for beautifying shell output.
96 | #
97 | # include ANSICode
98 | #
99 | # p red, "Hello", blue, "World"
100 | # => "\e[31mHello\e[34mWorld"
101 | #
102 | # p red { "Hello" } + blue { "World" }
103 | # => "\e[31mHello\e[0m\e[34mWorld\e[0m"
104 | #
105 | # == Supported ANSI Comands
106 | #
107 | # The following is a list of supported codes.
108 | #
109 | # save
110 | # restore
111 | # clear_screen
112 | # cls # synonym for :clear_screen
113 | # clear_line
114 | # clr # synonym for :clear_line
115 | # move
116 | # up
117 | # down
118 | # left
119 | # right
120 | # display
121 | #
122 | # clear
123 | # reset # synonym for :clear
124 | # bold
125 | # dark
126 | # italic # not widely implemented
127 | # underline
128 | # underscore # synonym for :underline
129 | # blink
130 | # rapid_blink # not widely implemented
131 | # negative # no reverse because of String#reverse
132 | # concealed
133 | # strikethrough # not widely implemented
134 | #
135 | # black
136 | # red
137 | # green
138 | # yellow
139 | # blue
140 | # magenta
141 | # cyan
142 | # white
143 | #
144 | # on_black
145 | # on_red
146 | # on_green
147 | # on_yellow
148 | # on_blue
149 | # on_magenta
150 | # on_cyan
151 | # on_white
152 | #
153 | module ANSICode
154 |
155 | extend self
156 |
157 | # Save current cursor positon.
158 |
159 | def save
160 | "\e[s"
161 | end
162 |
163 | # Restore saved cursor positon.
164 |
165 | def restore
166 | "\e[u"
167 | end
168 |
169 | # Clear the screen and move cursor to home.
170 |
171 | def clear_screen
172 | "\e[2J"
173 | end
174 | alias_method :cls, :clear_screen
175 |
176 | # Clear to the end of the current line.
177 |
178 | def clear_line
179 | "\e[K"
180 | end
181 | alias_method :clr, :clear_line
182 |
183 | #--
184 | #def position
185 | # "\e[#;#R"
186 | #end
187 | #++
188 |
189 | # Move curose to line and column.
190 |
191 | def move( line, column=0 )
192 | "\e[#{line.to_i};#{column.to_i}H"
193 | end
194 |
195 | # Move cursor up a specificed number of spaces.
196 |
197 | def up( spaces=1 )
198 | "\e[#{spaces.to_i}A"
199 | end
200 |
201 | # Move cursor down a specificed number of spaces.
202 |
203 | def down( spaces=1 )
204 | "\e[#{spaces.to_i}B"
205 | end
206 |
207 | # Move cursor left a specificed number of spaces.
208 |
209 | def left( spaces=1 )
210 | "\e[#{spaces.to_i}D"
211 | end
212 |
213 | # Move cursor right a specificed number of spaces.
214 |
215 | def right( spaces=1 )
216 | "\e[#{spaces.to_i}C"
217 | end
218 |
219 | # Like +move+ but returns to original positon
220 | # after yielding block or adding string argument.
221 |
222 | def display( line, column=0, string=nil ) #:yield:
223 | result = "\e[s"
224 | result << "\e[#{line.to_i};#{column.to_i}H"
225 | if block_given?
226 | result << yield
227 | result << "\e[u"
228 | elsif string
229 | result << string
230 | result << "\e[u"
231 | elsif respond_to?(:to_str)
232 | result << self
233 | result << "\e[u"
234 | end
235 | return result
236 | end
237 |
238 | # Define color codes.
239 |
240 | def self.define_ansicolor_method(name,code)
241 | class_eval <<-HERE
242 | def #{name.to_s}(string = nil)
243 | result = "\e[#{code}m"
244 | if block_given?
245 | result << yield
246 | result << "\e[0m"
247 | elsif string
248 | result << string
249 | result << "\e[0m"
250 | elsif respond_to?(:to_str)
251 | result << self
252 | result << "\e[0m"
253 | end
254 | return result
255 | end
256 | HERE
257 | end
258 |
259 | @@colors = [
260 | [ :clear , 0 ],
261 | [ :reset , 0 ], # synonym for :clear
262 | [ :bold , 1 ],
263 | [ :dark , 2 ],
264 | [ :italic , 3 ], # not widely implemented
265 | [ :underline , 4 ],
266 | [ :underscore , 4 ], # synonym for :underline
267 | [ :blink , 5 ],
268 | [ :rapid_blink , 6 ], # not widely implemented
269 | [ :negative , 7 ], # no reverse because of String#reverse
270 | [ :concealed , 8 ],
271 | [ :strikethrough, 9 ], # not widely implemented
272 | [ :black , 30 ],
273 | [ :red , 31 ],
274 | [ :green , 32 ],
275 | [ :yellow , 33 ],
276 | [ :blue , 34 ],
277 | [ :magenta , 35 ],
278 | [ :cyan , 36 ],
279 | [ :white , 37 ],
280 | [ :on_black , 40 ],
281 | [ :on_red , 41 ],
282 | [ :on_green , 42 ],
283 | [ :on_yellow , 43 ],
284 | [ :on_blue , 44 ],
285 | [ :on_magenta , 45 ],
286 | [ :on_cyan , 46 ],
287 | [ :on_white , 47 ],
288 | ]
289 |
290 | @@colors.each do |c, v|
291 | define_ansicolor_method(c, v)
292 | end
293 |
294 | ColoredRegexp = /\e\[([34][0-7]|[0-9])m/
295 |
296 | def uncolored(string = nil)
297 | if block_given?
298 | yield.gsub(ColoredRegexp, '')
299 | elsif string
300 | string.gsub(ColoredRegexp, '')
301 | elsif respond_to?(:to_str)
302 | gsub(ColoredRegexp, '')
303 | else
304 | ''
305 | end
306 | end
307 |
308 | module_function
309 |
310 | def colors
311 | @@colors.map { |c| c[0] }
312 | end
313 |
314 | end
315 |
316 |
--------------------------------------------------------------------------------
/work/reference/console/.gitignore:
--------------------------------------------------------------------------------
1 | doc
2 |
--------------------------------------------------------------------------------
/work/reference/console/Console.rdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubyworks/ansi/17002348d45ce9298a1a4017dc43d3cf65151bd4/work/reference/console/Console.rdoc
--------------------------------------------------------------------------------
/work/reference/console/Console_ANSI.rdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubyworks/ansi/17002348d45ce9298a1a4017dc43d3cf65151bd4/work/reference/console/Console_ANSI.rdoc
--------------------------------------------------------------------------------
/work/reference/console/HISTORY.txt:
--------------------------------------------------------------------------------
1 | v1.0 - Added .dup to _printString function to avoid mangling outside
2 | string references. Removed the other (later) .dup call.
3 | Turned of some exceptions that were conflicting with using
4 | the module with pipes or redirections.
5 | v0.8 - Fixed bugs in reading routines, added ruby docs, and
6 | sample test suite.
7 | v0.5 - First public release.
8 |
--------------------------------------------------------------------------------
/work/reference/console/INSTALL.txt:
--------------------------------------------------------------------------------
1 |
2 | To compile and install:
3 |
4 |
5 | Open a windows console.
6 | > vcvars32.bat # to set up microsoft's compiling environment
7 | # this is located in the bin/ directory of the MSVC compiler
8 | > ruby extconf.rb # to create a Makefile
9 | > nmake # to compile
10 | > nmake install # to install
11 |
12 |
13 | To test:
14 |
15 | > cd test
16 | > dir # to see available samples
17 | > ruby [anysample]
18 |
19 |
--------------------------------------------------------------------------------
/work/reference/console/Makefile:
--------------------------------------------------------------------------------
1 |
2 | SHELL = /bin/sh
3 |
4 | #### Start of system configuration section. ####
5 |
6 | srcdir = C:/ruby/visualc/Console
7 | topdir = $(rubylibdir)/$(arch)
8 | hdrdir = $(rubylibdir)/$(arch)
9 | VPATH = $(srcdir)
10 |
11 | DESTDIR = c:
12 | prefix = $(DESTDIR)/ruby
13 | exec_prefix = $(prefix)
14 | bindir = $(exec_prefix)/bin
15 | sitelibdir = $(sitedir)/$(ruby_version)
16 | datadir = $(prefix)/share
17 | sitedir = $(prefix)/lib/ruby/site_ruby
18 | sharedstatedir = $(DESTDIR)/etc
19 | archdir = $(rubylibdir)/$(arch)
20 | localstatedir = $(DESTDIR)/var
21 | infodir = $(prefix)/info
22 | oldincludedir = $(DESTDIR)/usr/include
23 | libexecdir = $(exec_prefix)/libexec
24 | compile_dir = $(DESTDIR)/WINDOWS/Escritorio/Programacion/ruby/win32
25 | sbindir = $(exec_prefix)/sbin
26 | includedir = $(prefix)/include
27 | sysconfdir = $(prefix)/etc
28 | sitearchdir = $(sitelibdir)/$(sitearch)
29 | mandir = $(prefix)/man
30 | libdir = $(exec_prefix)/lib
31 | rubylibdir = $(libdir)/ruby/$(ruby_version)
32 |
33 | CC = cl -nologo
34 | LIBRUBY = $(RUBY_SO_NAME).lib
35 | LIBRUBY_A = $(RUBY_SO_NAME)-static.lib
36 | LIBRUBYARG_SHARED = $(LIBRUBY)
37 | LIBRUBYARG_STATIC = $(LIBRUBY_A)
38 |
39 | CFLAGS = -MD -Zi -O2b2xg- -G6
40 | CPPFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir) -I. -I./.. -I./../missing
41 | CXXFLAGS = $(CFLAGS)
42 | DLDFLAGS = -link -incremental:no -debug -opt:ref -opt:icf -dll $(LIBPATH) -def:$(DEFFILE)
43 | LDSHARED = cl -nologo -LD
44 | AR = lib -nologo
45 | EXEEXT = .exe
46 |
47 | RUBY_INSTALL_NAME = ruby
48 | RUBY_SO_NAME = msvcrt-ruby18
49 | arch = i386-mswin32
50 | sitearch = i386-msvcrt
51 | ruby_version = 1.8
52 | RUBY = ruby
53 | RM = $(RUBY) -run -e rm -- -f
54 | MAKEDIRS = $(RUBY) -run -e mkdir -- -p
55 | INSTALL_PROG = $(RUBY) -run -e install -- -vpm 0755
56 | INSTALL_DATA = $(RUBY) -run -e install -- -vpm 0644
57 |
58 | #### End of system configuration section. ####
59 |
60 |
61 | LIBPATH = -libpath:"$(libdir)"
62 | DEFFILE = $(TARGET)-$(arch).def
63 |
64 | CLEANFILES =
65 | DISTCLEANFILES = $(DEFFILE)
66 |
67 | target_prefix =
68 | LOCAL_LIBS =
69 | LIBS = $(LIBRUBYARG_SHARED) oldnames.lib user32.lib advapi32.lib wsock32.lib
70 | OBJS = Console.obj
71 | TARGET = Console
72 | DLLIB = $(TARGET).so
73 | STATIC_LIB = $(TARGET).lib
74 |
75 | RUBYCOMMONDIR = $(sitedir)$(target_prefix)
76 | RUBYLIBDIR = $(sitelibdir)$(target_prefix)
77 | RUBYARCHDIR = $(sitearchdir)$(target_prefix)
78 |
79 | CLEANLIBS = "$(TARGET).{lib,exp,il?,tds,map}" $(DLLIB)
80 | CLEANOBJS = "*.{obj,lib,s[ol],pdb,bak}"
81 |
82 | all: $(DLLIB)
83 | static: $(STATIC_LIB)
84 |
85 | clean:
86 | @$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
87 |
88 | distclean: clean
89 | @$(RM) Makefile extconf.h conftest.* mkmf.log
90 | @$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
91 |
92 | realclean: distclean
93 | install: $(RUBYARCHDIR)
94 | install: $(RUBYARCHDIR)/$(DLLIB)
95 | $(RUBYARCHDIR)/$(DLLIB): $(DLLIB) $(RUBYARCHDIR)
96 | @$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
97 | install: $(RUBYLIBDIR)/Win32
98 | install: $(RUBYLIBDIR)/Win32/Console.rb
99 | $(RUBYLIBDIR)/Win32/Console.rb: $(srcdir)/lib/Win32/Console.rb $(RUBYLIBDIR)/Win32
100 | @$(INSTALL_DATA) $(srcdir)/lib/Win32/Console.rb $(RUBYLIBDIR)/Win32
101 | install: $(RUBYLIBDIR)/Win32/Console
102 | install: $(RUBYLIBDIR)/Win32/Console/ANSI.rb
103 | $(RUBYLIBDIR)/Win32/Console/ANSI.rb: $(srcdir)/lib/Win32/Console/ANSI.rb $(RUBYLIBDIR)/Win32/Console
104 | @$(INSTALL_DATA) $(srcdir)/lib/Win32/Console/ANSI.rb $(RUBYLIBDIR)/Win32/Console
105 | install: $(RUBYLIBDIR)/Term
106 | install: $(RUBYLIBDIR)/Term/ansicolor.rb
107 | $(RUBYLIBDIR)/Term/ansicolor.rb: $(srcdir)/lib/Term/ansicolor.rb $(RUBYLIBDIR)/Term
108 | @$(INSTALL_DATA) $(srcdir)/lib/Term/ansicolor.rb $(RUBYLIBDIR)/Term
109 | $(RUBYARCHDIR):
110 | @$(MAKEDIRS) $(RUBYARCHDIR)
111 | $(RUBYLIBDIR)/Win32:
112 | @$(MAKEDIRS) $(RUBYLIBDIR)/Win32
113 | $(RUBYLIBDIR)/Win32/Console:
114 | @$(MAKEDIRS) $(RUBYLIBDIR)/Win32/Console
115 | $(RUBYLIBDIR)/Term:
116 | @$(MAKEDIRS) $(RUBYLIBDIR)/Term
117 |
118 | site-install: install
119 |
120 | .SUFFIXES: .c .cc .m .cxx .cpp .C .obj
121 |
122 | {$(srcdir)}.cc{}.obj:
123 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -Tp$(<:\=/)
124 |
125 | .cc.obj:
126 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -Tp$(<:\=/)
127 |
128 | {$(srcdir)}.cpp{}.obj:
129 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -Tp$(<:\=/)
130 |
131 | .cpp.obj:
132 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -Tp$(<:\=/)
133 |
134 | {$(srcdir)}.cxx{}.obj:
135 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -Tp$(<:\=/)
136 |
137 | .cxx.obj:
138 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -Tp$(<:\=/)
139 |
140 | {$(srcdir)}.C{}.obj:
141 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -Tp$(<:\=/)
142 |
143 | .C.obj:
144 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -Tp$(<:\=/)
145 |
146 | {$(srcdir)}.c{}.obj:
147 | $(CC) $(CFLAGS) $(CPPFLAGS) -c -Tc$(<:\=/)
148 |
149 | .c.obj:
150 | $(CC) $(CFLAGS) $(CPPFLAGS) -c -Tc$(<:\=/)
151 |
152 | $(DLLIB): $(OBJS) $(DEFFILE)
153 | @-$(RM) $@
154 | @-$(RM) $(TARGET).lib
155 | $(LDSHARED) -Fe$(@) $(OBJS) $(LIBS) $(LOCAL_LIBS) $(DLDFLAGS)
156 |
157 | $(STATIC_LIB): $(OBJS)
158 | $(AR) -machine:x86 -out:$@ $(OBJS)
159 |
160 | $(DEFFILE):
161 | $(RUBY) -e "puts 'EXPORTS', 'Init_$(TARGET)'" > $@
162 |
163 |
--------------------------------------------------------------------------------
/work/reference/console/README.txt:
--------------------------------------------------------------------------------
1 |
2 | This file implements a port of Perl's Win32::Console
3 | and Win32::Console::ANSI modules.
4 |
5 | Win32::Console allows controling the windows command line terminal
6 | thru an OO-interface. This allows you to query the terminal (find
7 | its size, characters, attributes, etc). The interface and functionality
8 | should be identical to Perl's.
9 |
10 | Win32::Console consists of a Ruby .rb interface.
11 | For best performance, this library has been also ported to C.
12 | If you lack a C compiler, you can still use the class thru the ruby
13 | interface. If you can compile it, then the ruby interface is not
14 | used and the C functions are called instead.
15 |
16 | Win32::Console::ANSI is a class derived from IO that seamlessly
17 | translates ANSI Esc control character codes into Windows' command.exe
18 | or cmd.exe equivalents.
19 |
20 | These modules allow you to develop command-line tools that can take
21 | advantage of the unix terminal functions while still being portable.
22 | One of the most common uses for this is to allow to color your
23 | output.
24 | The modules are disted with Term/ansicolor.rb, too, as it is a nice
25 | thing to verify it is working properly.
26 |
27 |
--------------------------------------------------------------------------------
/work/reference/console/extconf.rb:
--------------------------------------------------------------------------------
1 | #################################################################
2 | #
3 | # To compile and install, do this:
4 | #
5 | # Make sure your compiling environment is in your path.
6 | # In the case of MSVC, this involves running vcvars32.bat first
7 | # which is located in the bin directory of MS Visual C++.
8 | #
9 | # Then:
10 | #
11 | # > ruby extconf.rb
12 | # > nmake Makefile
13 | # > nmake install
14 | #
15 | #
16 | ##################################################################
17 | require 'mkmf'
18 | create_makefile('Console')
19 |
--------------------------------------------------------------------------------
/work/reference/console/lib/Term/ansicolor.rb:
--------------------------------------------------------------------------------
1 | module Term
2 |
3 | module ANSIColor
4 |
5 | @@attributes = [
6 | [ :clear , 0 ],
7 | [ :reset , 0 ], # synonym for :clear
8 | [ :bold , 1 ],
9 | [ :dark , 2 ],
10 | [ :italic , 3 ], # not widely implemented
11 | [ :underline , 4 ],
12 | [ :underscore , 4 ], # synonym for :underline
13 | [ :blink , 5 ],
14 | [ :rapid_blink , 6 ], # not widely implemented
15 | [ :negative , 7 ], # no reverse because of String#reverse
16 | [ :concealed , 8 ],
17 | [ :strikethrough, 9 ], # not widely implemented
18 | [ :black , 30 ],
19 | [ :red , 31 ],
20 | [ :green , 32 ],
21 | [ :yellow , 33 ],
22 | [ :blue , 34 ],
23 | [ :magenta , 35 ],
24 | [ :cyan , 36 ],
25 | [ :white , 37 ],
26 | [ :on_black , 40 ],
27 | [ :on_red , 41 ],
28 | [ :on_green , 42 ],
29 | [ :on_yellow , 43 ],
30 | [ :on_blue , 44 ],
31 | [ :on_magenta , 45 ],
32 | [ :on_cyan , 46 ],
33 | [ :on_white , 47 ],
34 | ]
35 |
36 | @@attributes.each do |c, v|
37 | eval %Q{
38 | def #{c.to_s}(string = nil)
39 | result = "\e[#{v}m"
40 | if block_given?
41 | result << yield
42 | result << "\e[0m"
43 | elsif string
44 | result << string
45 | result << "\e[0m"
46 | elsif respond_to?(:to_str)
47 | result << self
48 | result << "\e[0m"
49 | end
50 | return result
51 | end
52 | }
53 | end
54 |
55 | ColoredRegexp = /\e\[([34][0-7]|[0-9])m/
56 | def uncolored(string = nil)
57 | if block_given?
58 | yield.gsub(ColoredRegexp, '')
59 | elsif string
60 | string.gsub(ColoredRegexp, '')
61 | elsif respond_to?(:to_str)
62 | gsub(ColoredRegexp, '')
63 | else
64 | ''
65 | end
66 | end
67 |
68 | def attributes
69 | @@attributes.map { |c| c[0] }
70 | end
71 | module_function :attributes
72 |
73 | end
74 |
75 | end
76 | # vim: set cin sw=4 ts=4:
77 |
--------------------------------------------------------------------------------
/work/reference/console/lib/Win32/Console.rb:
--------------------------------------------------------------------------------
1 | # Win32::Console: an object implementing the Win32 API Console functions
2 | # Copyright (C) 2003 Gonzalo Garramuno (ggarramuno@aol.com)
3 | #
4 | # Original Win32API_Console was:
5 | # Copyright (C) 2001 Michael L. Semon (mlsemon@sega.net)
6 |
7 | begin
8 | # If Console.so is available, use that. Otherwise, we define
9 | # equivalent functions in ruby (a tad slower)
10 | # That dll should define everything in an identical interface
11 | # to all the ruby code that the rescue below defines.
12 | require "Console.so"
13 | STDERR.print "Using faster, DLL Console.so\n" if $DEBUG
14 |
15 | rescue Exception
16 |
17 | STDERR.print "Using slower, non-DLL Console.rb\n" if $DEBUG
18 |
19 | module Win32
20 | class Console
21 | end
22 | end
23 |
24 | # The WINDOWS constants
25 | module Win32::Console::Constants
26 | STD_INPUT_HANDLE = 0xFFFFFFF6
27 | STD_OUTPUT_HANDLE = 0xFFFFFFF5
28 | STD_ERROR_HANDLE = 0xFFFFFFF4
29 | INVALID_HANDLE_VALUE = 0xFFFFFFFF
30 | GENERIC_READ = 0x80000000
31 | GENERIC_WRITE = 0x40000000
32 | FILE_SHARE_READ = 0x00000001
33 | FILE_SHARE_WRITE = 0x00000002
34 | CONSOLE_TEXTMODE_BUFFER = 0x00000001
35 |
36 | FOREGROUND_BLUE = 0x0001
37 | FOREGROUND_GREEN = 0x0002
38 | FOREGROUND_RED = 0x0004
39 | FOREGROUND_INTENSITY = 0x0008
40 | BACKGROUND_BLUE = 0x0010
41 | BACKGROUND_GREEN = 0x0020
42 | BACKGROUND_RED = 0x0040
43 | BACKGROUND_INTENSITY = 0x0080
44 |
45 | ENABLE_PROCESSED_INPUT = 0x0001
46 | ENABLE_LINE_INPUT = 0x0002
47 | ENABLE_ECHO_INPUT = 0x0004
48 | ENABLE_WINDOW_INPUT = 0x0008
49 | ENABLE_MOUSE_INPUT = 0x0010
50 | ENABLE_PROCESSED_OUTPUT = 0x0001
51 | ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
52 |
53 | KEY_EVENT = 0x0001
54 | MOUSE_EVENT = 0x0002
55 | WINDOW_BUFFER_SIZE_EVENT = 0x0004
56 | MENU_EVENT = 0x0008
57 | FOCUS_EVENT = 0x0010
58 |
59 | CAPSLOCK_ON = 0x0080
60 | ENHANCED_KEY = 0x0100
61 | NUMLOCK_ON = 0x0020
62 | SHIFT_PRESSED = 0x0010
63 | LEFT_CTRL_PRESSED = 0x0008
64 | RIGHT_CTRL_PRESSED = 0x0004
65 | LEFT_ALT_PRESSED = 0x0002
66 | RIGHT_ALT_PRESSED = 0x0001
67 | SCROLLLOCK_ON = 0x0040
68 |
69 | MOUSE_WHEELED = 0x0004
70 | DOUBLE_CLICK = 0x0002
71 | MOUSE_MOVED = 0x0001
72 |
73 | FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001
74 | FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004
75 | FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008
76 | FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010
77 | RIGHTMOST_BUTTON_PRESSED = 0x0002
78 |
79 | CTRL_C_EVENT = 0x0000
80 | CTRL_BREAK_EVENT = 0x0001
81 | CTRL_CLOSE_EVENT = 0x0002
82 | CTRL_LOGOFF_EVENT = 0x0005
83 | CTRL_SHUTDOWN_EVENT = 0x0006
84 | end
85 |
86 | # The actual api to access windows functions
87 | class Win32::Console::API
88 | require 'Win32API'
89 |
90 | private
91 | # This is a class-wide cache that will hold Win32API objects. As each
92 | # Win32API object is about 920 bytes, I didn't want to initialize all of
93 | # them at one time. That would waste about 42 kB for this object because
94 | # it has 47 functions. However, to not have a cache at all would reduce
95 | # the speed of this object by 164%.
96 | @@m_AllocConsole = nil
97 | @@m_CreateConsoleScreenBuffer = nil
98 | @@m_FillConsoleOutputAttribute = nil
99 | @@m_FillConsoleOutputCharacter = nil
100 | @@m_FlushConsoleInputBuffer = nil
101 | @@m_FreeConsole = nil
102 | @@m_GenerateConsoleCtrlEvent = nil
103 | @@m_GetConsoleCP = nil
104 | @@m_GetConsoleCursorInfo = nil
105 | @@m_GetConsoleMode = nil
106 | @@m_GetConsoleOutputCP = nil
107 | @@m_GetConsoleScreenBufferInfo = nil
108 | @@m_GetConsoleTitle = nil
109 | @@m_GetConsoleWindow = nil
110 | @@m_GetLargestConsoleWindowSize = nil
111 | @@m_GetNumberOfConsoleInputEvents = nil
112 | @@m_GetNumberOfConsoleMouseButtons = nil
113 | @@m_GetStdHandle = nil
114 | @@m_PeekConsoleInput = nil
115 | @@m_ReadConsole = nil
116 | @@m_ReadConsoleInput = nil
117 | @@m_ReadConsoleOutput = nil
118 | @@m_ReadConsoleOutputAttribute = nil
119 | @@m_ReadConsoleOutputCharacter = nil
120 | @@m_ScrollConsoleScreenBuffer = nil
121 | @@m_SetConsoleActiveScreenBuffer = nil
122 | @@m_SetConsoleCP = nil
123 | @@m_SetConsoleCursorInfo = nil
124 | @@m_SetConsoleCursorPosition = nil
125 | @@m_SetConsoleMode = nil
126 | @@m_SetConsoleOutputCP = nil
127 | @@m_SetConsoleScreenBufferSize = nil
128 | @@m_SetConsoleTextAttribute = nil
129 | @@m_SetConsoleTitle = nil
130 | @@m_SetConsoleWindowInfo = nil
131 | @@m_SetStdHandle = nil
132 | @@m_WriteConsole = nil
133 | @@m_WriteConsoleInput = nil
134 | @@m_WriteConsoleOutput = nil
135 | @@m_WriteConsoleOutputAttribute = nil
136 | @@m_WriteConsoleOutputCharacter = nil
137 |
138 | public
139 |
140 | class << self
141 |
142 |
143 | def constant(t)
144 | begin
145 | eval "return Win32::Console::Constants::#{t}"
146 | rescue
147 | return nil
148 | end
149 | end
150 |
151 |
152 | def AllocConsole()
153 | if @@m_AllocConsole == nil
154 | @@m_AllocConsole = Win32API.new( "kernel32", "AllocConsole",
155 | [], 'l' )
156 | end
157 | @@m_AllocConsole.call()
158 | end
159 |
160 | def CreateConsoleScreenBuffer( dwDesiredAccess, dwShareMode, dwFlags )
161 | if @@m_CreateConsoleScreenBuffer == nil
162 | @@m_CreateConsoleScreenBuffer = Win32API.new( "kernel32", "CreateConsoleScreenBuffer", ['l', 'l', 'p', 'l', 'p'], 'l' )
163 | end
164 | @@m_CreateConsoleScreenBuffer.call( dwDesiredAccess, dwShareMode,
165 | nil, dwFlags, nil )
166 | end
167 |
168 |
169 |
170 | def FillConsoleOutputAttribute( hConsoleOutput, wAttribute, nLength,
171 | col, row )
172 | if @@m_FillConsoleOutputAttribute == nil
173 | @@m_FillConsoleOutputAttribute = Win32API.new( "kernel32", "FillConsoleOutputAttribute", ['l', 'i', 'l', 'l', 'p'], 'l' )
174 | end
175 | dwWriteCoord = (row << 16) + col
176 | lpNumberOfAttrsWritten = ' ' * 4
177 | @@m_FillConsoleOutputAttribute.call( hConsoleOutput, wAttribute,
178 | nLength, dwWriteCoord,
179 | lpNumberOfAttrsWritten )
180 | return lpNumberOfAttrsWritten.unpack('L')
181 | end
182 |
183 |
184 |
185 | def FillConsoleOutputCharacter( hConsoleOutput, cCharacter, nLength,
186 | col, row )
187 | if @@m_FillConsoleOutputCharacter == nil
188 | @@m_FillConsoleOutputCharacter = Win32API.new( "kernel32", "FillConsoleOutputCharacter", ['l', 'i', 'l', 'l', 'p'], 'l' )
189 | end
190 | dwWriteCoord = (row << 16) + col
191 | lpNumberOfAttrsWritten = ' ' * 4
192 | @@m_FillConsoleOutputCharacter.call( hConsoleOutput, cCharacter,
193 | nLength, dwWriteCoord,
194 | lpNumberOfAttrsWritten )
195 | return lpNumberOfAttrsWritten.unpack('L')
196 | end
197 |
198 |
199 | def FlushConsoleInputBuffer( hConsoleInput )
200 | if @@m_FlushConsoleInputBuffer == nil
201 | @@m_FlushConsoleInputBuffer = Win32API.new( "kernel32",
202 | "FillConsoleInputBuffer",
203 | ['l'], 'l' )
204 | end
205 | @@m_FlushConsoleInputBuffer.call( hConsoleInput )
206 | end
207 |
208 |
209 | def FreeConsole()
210 | if @@m_FreeConsole == nil
211 | @@m_FreeConsole = Win32API.new( "kernel32", "FreeConsole", [], 'l' )
212 | end
213 | @@m_FreeConsole.call()
214 | end
215 |
216 |
217 | def GenerateConsoleCtrlEvent( dwCtrlEvent, dwProcessGroupId )
218 | if @@m_GenerateConsoleCtrlEvent == nil
219 | @@m_GenerateConsoleCtrlEvent = Win32API.new( "kernel32", "GenerateConsoleCtrlEvent", ['l', 'l'], 'l' )
220 | end
221 | @@m_GenerateConsoleCtrlEvent.call( dwCtrlEvent, dwProcessGroupId )
222 | end
223 |
224 | def GetConsoleCP()
225 | if @@m_GetConsoleCP == nil
226 | @@m_GetConsoleCP = Win32API.new( "kernel32", "GetConsoleCP",
227 | [], 'l' )
228 | end
229 | @@m_GetConsoleCP.call()
230 | end
231 |
232 | def GetConsoleCursorInfo( hConsoleOutput )
233 | if @@m_GetConsoleCursorInfo == nil
234 | @@m_GetConsoleCursorInfo = Win32API.new( "kernel32",
235 | "GetConsoleCursorInfo",
236 | ['l', 'p'], 'l' )
237 | end
238 | lpConsoleCursorInfo = ' ' * 8
239 | @@m_GetConsoleCursorInfo.call( hConsoleOutput, lpConsoleCursorInfo )
240 | return lpConsoleCursorInfo.unpack('LL')
241 | end
242 |
243 | def GetConsoleMode( hConsoleHandle )
244 | if @@m_GetConsoleMode == nil
245 | @@m_GetConsoleMode = Win32API.new( "kernel32", "GetConsoleMode",
246 | ['l', 'p'], 'l' )
247 | end
248 | lpMode = ' ' * 4
249 | @@m_GetConsoleMode.call( hConsoleHandle, lpMode )
250 | return lpMode.unpack('L')
251 | end
252 |
253 | def GetConsoleOutputCP()
254 | if @@m_GetConsoleOutputCP == nil
255 | @@m_GetConsoleOutputCP = Win32API.new( "kernel32",
256 | "GetConsoleOutputCP", [], 'l' )
257 | end
258 | @@m_GetConsoleOutputCP.call()
259 | end
260 |
261 | def GetConsoleScreenBufferInfo( hConsoleOutput )
262 | if @@m_GetConsoleScreenBufferInfo == nil
263 | @@m_GetConsoleScreenBufferInfo = Win32API.new( "kernel32", "GetConsoleScreenBufferInfo", ['l', 'p'], 'l' )
264 | end
265 | lpBuffer = ' ' * 22
266 | @@m_GetConsoleScreenBufferInfo.call( hConsoleOutput, lpBuffer )
267 | return lpBuffer.unpack('SSSSSssssSS')
268 | end
269 |
270 | def GetConsoleTitle()
271 | if @@m_GetConsoleTitle == nil
272 | @@m_GetConsoleTitle = Win32API.new( "kernel32", "GetConsoleTitle",
273 | ['p', 'l'], 'l' )
274 | end
275 | nSize = 120
276 | lpConsoleTitle = ' ' * nSize
277 | @@m_GetConsoleTitle.call( lpConsoleTitle, nSize )
278 | return lpConsoleTitle.strip
279 | end
280 |
281 | def GetConsoleWindow()
282 | if @@m_GetConsoleWindow == nil
283 | @@m_GetConsoleWindow = Win32API.new( "kernel32", "GetConsoleWindow",
284 | [], 'l' )
285 | end
286 | @@m_GetConsoleWindow.call()
287 | end
288 |
289 | def GetLargestConsoleWindowSize( hConsoleOutput )
290 | if @@m_GetLargestConsoleWindowSize == nil
291 | @@m_GetLargestConsoleWindowSize = Win32API.new( "kernel32", "GetLargestConsoleWindowSize", ['l'], 'l' )
292 | end
293 | coord = @@m_GetLargestConsoleWindowSize.call( hConsoleOutput )
294 | x = coord >> 16
295 | y = coord & 0x0000ffff
296 | return [x,y]
297 | end
298 |
299 | def GetNumberOfConsoleInputEvents( hConsoleInput )
300 | if @@m_GetNumberOfConsoleInputEvents == nil
301 | @@m_GetNumberOfConsoleInputEvents = Win32API.new( "kernel32", "GetNumberOfConsoleInputEvents", ['l', 'p'], 'l' )
302 | end
303 | lpcNumberOfEvents = 0
304 | @@m_GetNumberOfConsoleInputEvents.call( hConsoleInput,
305 | lpcNumberOfEvents )
306 | return lpcNumberOfEvents
307 | end
308 |
309 | def GetNumberOfConsoleMouseButtons( )
310 | if @@m_GetNumberOfConsoleMouseButtons == nil
311 | @@m_GetNumberOfConsoleMouseButtons = Win32API.new( "kernel32", "GetNumberOfConsoleMouseButtons", ['p'], 'l' )
312 | end
313 | lpNumberOfMouseButtons = 0
314 | @@m_GetNumberOfConsoleMouseButtons.call( lpNumberOfMouseButtons )
315 | return lpNumberOfMouseButtons
316 | end
317 |
318 | def GetStdHandle( nStdHandle )
319 | if @@m_GetStdHandle == nil
320 | @@m_GetStdHandle = Win32API.new( "kernel32", "GetStdHandle",
321 | ['l'], 'l' )
322 | end
323 | @@m_GetStdHandle.call( nStdHandle )
324 | end
325 |
326 | # <> : This is not an actual API function, just a concept description in the SDK.
327 |
328 | def PeekConsoleInput( hConsoleInput )
329 | if @@m_PeekConsoleInput == nil
330 | @@m_PeekConsoleInput = Win32API.new( "kernel32", "PeekConsoleInput",
331 | ['l', 'p', 'l', 'p'], 'l' )
332 | end
333 | lpNumberOfEventsRead = ' ' * 4
334 | lpBuffer = ' ' * 20
335 | nLength = 20
336 | @@m_PeekConsoleInput.call( hConsoleInput, lpBuffer, nLength,
337 | lpNumberOfEventsRead )
338 | type = lpBuffer.unpack('s')[0]
339 |
340 | case type
341 | when KEY_EVENT
342 | return lpBuffer.unpack('sSSSSCS')
343 | when MOUSE_EVENT
344 | return lpBuffer.unpack('sSSSS')
345 | when WINDOW_BUFFER_SIZE_EVENT
346 | return lpBuffer.unpack('sS')
347 | when MENU_EVENT
348 | return lpBuffer.unpack('sS')
349 | when FOCUS_EVENT
350 | return lpBuffer.unpack('sS')
351 | else
352 | return []
353 | end
354 | end
355 |
356 | def ReadConsole( hConsoleInput, lpBuffer, nNumberOfCharsToRead )
357 | if @@m_ReadConsole == nil
358 | @@m_ReadConsole = Win32API.new( "kernel32", "ReadConsole",
359 | ['l', 'p', 'l', 'p', 'p'], 'l' )
360 | end
361 | lpBuffer = ' ' * nNumberOfCharsToRead unless lpBuffer
362 | lpNumberOfCharsRead = ' ' * 4
363 | lpReserved = ' ' * 4
364 | @@m_ReadConsole.call( hConsoleInput, lpBuffer, nNumberOfCharsToRead,
365 | lpNumberOfCharsRead, lpReserved )
366 | return lpNumberOfCharsRead.unpack('L')
367 | end
368 |
369 | def ReadConsoleInput( hConsoleInput )
370 | if @@m_ReadConsoleInput == nil
371 | @@m_ReadConsoleInput = Win32API.new( "kernel32", "ReadConsoleInput",
372 | ['l', 'p', 'l', 'p'], 'l' )
373 | end
374 | lpNumberOfEventsRead = ' ' * 4
375 | lpBuffer = ' ' * 20
376 | nLength = 20
377 | @@m_ReadConsoleInput.call( hConsoleInput, lpBuffer, nLength,
378 | lpNumberOfEventsRead )
379 | type = lpBuffer.unpack('s')[0]
380 |
381 | case type
382 | when KEY_EVENT
383 | return lpBuffer.unpack('sSSSSCS')
384 | when MOUSE_EVENT
385 | return lpBuffer.unpack('sSSSS')
386 | when WINDOW_BUFFER_SIZE_EVENT
387 | return lpBuffer.unpack('sS')
388 | when MENU_EVENT
389 | return lpBuffer.unpack('sS')
390 | when FOCUS_EVENT
391 | return lpBuffer.unpack('sS')
392 | else
393 | return []
394 | end
395 | end
396 |
397 | def ReadConsoleOutput( hConsoleOutput, lpBuffer, cols, rows,
398 | bufx, bufy, left, top, right, bottom )
399 | if @@m_ReadConsoleOutput == nil
400 | @@m_ReadConsoleOutput = Win32API.new( "kernel32",
401 | "ReadConsoleOutput",
402 | ['l', 'p', 'l', 'l', 'p'], 'l' )
403 | end
404 | dwBufferSize = cols * rows * 4
405 | lpBuffer = ' ' * dwBufferSize
406 | dwBufferCoord = (bufy << 16) + bufx
407 | lpReadRegion = [ left, top, right, bottom ].pack('ssss')
408 | @@m_ReadConsoleOutput.call( hConsoleOutput, lpBuffer, dwBufferSize,
409 | dwBufferCoord, lpReadRegion )
410 | end
411 |
412 | def ReadConsoleOutputAttribute( hConsoleOutput, nLength, col, row )
413 | if @@m_ReadConsoleOutputAttribute == nil
414 | @@m_ReadConsoleOutputAttribute = Win32API.new( "kernel32", "ReadConsoleOutputAttribute", ['l', 'p', 'l', 'l', 'p'], 'l' )
415 | end
416 | lpAttribute = ' ' * nLength
417 | dwReadCoord = (row << 16) + col
418 | lpNumberOfAttrsRead = ' ' * 4
419 | @@m_ReadConsoleOutputAttribute.call( hConsoleOutput, lpAttribute,
420 | nLength, dwReadCoord,
421 | lpNumberOfAttrsRead )
422 | return lpAttribute
423 | end
424 |
425 | def ReadConsoleOutputCharacter( hConsoleOutput, lpCharacter, nLength,
426 | col, row )
427 | if @@m_ReadConsoleOutputCharacter == nil
428 | @@m_ReadConsoleOutputCharacter = Win32API.new( "kernel32", "ReadConsoleOutputCharacter", ['l', 'p', 'l', 'l', 'p'], 'l' )
429 | end
430 | dwReadCoord = (row << 16) + col
431 | lpNumberOfCharsRead = ' ' * 4
432 | @@m_ReadConsoleOutputCharacter.call( hConsoleOutput, lpCharacter,
433 | nLength, dwReadCoord,
434 | lpNumberOfCharsRead )
435 | return lpNumberOfCharsRead.unpack('L')
436 | end
437 |
438 | def ScrollConsoleScreenBuffer( hConsoleOutput,
439 | left1, top1, right1, bottom1,
440 | col, row, char, attr,
441 | left2, top2, right2, bottom2 )
442 | if @@m_ScrollConsoleScreenBuffer == nil
443 | @@m_ScrollConsoleScreenBuffer = Win32API.new( "kernel32", "ScrollConsoleScreenBuffer", ['l', 'p', 'p', 'l', 'p'], 'l' )
444 | end
445 | lpScrollRectangle = [left1, top1, right1, bottom1].pack('ssss')
446 | lpClipRectangle = [left2, top2, right2, bottom2].pack('ssss')
447 | dwDestinationOrigin = (row << 16) + col
448 | lpFill = [char, attr].pack('ss')
449 | @@m_ScrollConsoleScreenBuffer.call( hConsoleOutput, lpScrollRectangle,
450 | lpClipRectangle,
451 | dwDestinationOrigin, lpFill )
452 | end
453 |
454 | def SetConsoleActiveScreenBuffer( hConsoleOutput )
455 | if @@m_SetConsoleActiveScreenBuffer == nil
456 | @@m_SetConsoleActiveScreenBuffer = Win32API.new( "kernel32", "SetConsoleActiveScreenBuffer", ['l'], 'l' )
457 | end
458 | @@m_SetConsoleActiveScreenBuffer.call( hConsoleOutput )
459 | end
460 |
461 | # <>: Will probably not be implemented.
462 |
463 | def SetConsoleCP( wCodePageID )
464 | if @@m_SetConsoleCP == nil
465 | @@m_SetConsoleCP = Win32API.new( "kernel32", "SetConsoleCP",
466 | ['l'], 'l' )
467 | end
468 | @@m_SetConsoleCP.call( wCodePageID )
469 | end
470 |
471 | def SetConsoleCursorInfo( hConsoleOutput, col, row )
472 | if @@m_SetConsoleCursorInfo == nil
473 | @@m_SetConsoleCursorInfo = Win32API.new( "kernel32",
474 | "SetConsoleCursorInfo",
475 | ['l', 'p'], 'l' )
476 | end
477 | lpConsoleCursorInfo = [size,visi].pack('LL')
478 | @@m_SetConsoleCursorInfo.call( hConsoleOutput, lpConsoleCursorInfo )
479 | end
480 |
481 | def SetConsoleCursorPosition( hConsoleOutput, col, row )
482 | if @@m_SetConsoleCursorPosition == nil
483 | @@m_SetConsoleCursorPosition = Win32API.new( "kernel32", "SetConsoleCursorPosition", ['l', 'p'], 'l' )
484 | end
485 | dwCursorPosition = (row << 16) + col
486 | @@m_SetConsoleCursorPosition.call( hConsoleOutput, dwCursorPosition )
487 | end
488 |
489 | def SetConsoleMode( hConsoleHandle, lpMode )
490 | if @@m_SetConsoleMode == nil
491 | @@m_SetConsoleMode = Win32API.new( "kernel32", "SetConsoleMode",
492 | ['l', 'p'], 'l' )
493 | end
494 | @@m_SetConsoleMode.call( hConsoleHandle, lpMode )
495 | end
496 |
497 | def SetConsoleOutputCP( wCodePageID )
498 | if @@m_SetConsoleOutputCP == nil
499 | @@m_SetConsoleOutputCP = Win32API.new( "kernel32",
500 | "GetConsoleOutputCP",
501 | ['l'], 'l' )
502 | end
503 | @@m_SetConsoleOutputCP.call( wCodePageID )
504 | end
505 |
506 | def SetConsoleScreenBufferSize( hConsoleOutput, col, row )
507 | if @@m_SetConsoleScreenBufferSize == nil
508 | @@m_SetConsoleScreenBufferSize = Win32API.new( "kernel32", "SetConsoleScreenBufferSize", ['l', 'l'], 'l' )
509 | end
510 | dwSize = (row << 16) + col
511 | @@m_SetConsoleScreenBufferSize.call( hConsoleOutput, dwSize )
512 | end
513 |
514 | def SetConsoleTextAttribute( hConsoleOutput, wAttributes )
515 | if @@m_SetConsoleTextAttribute == nil
516 | @@m_SetConsoleTextAttribute = Win32API.new( "kernel32", "SetConsoleTextAttribute", ['l', 'i'], 'l' )
517 | end
518 | @@m_SetConsoleTextAttribute.call( hConsoleOutput, wAttributes )
519 | end
520 |
521 | def SetConsoleTitle( lpConsoleTitle )
522 | if @@m_SetConsoleTitle == nil
523 | @@m_SetConsoleTitle = Win32API.new( "kernel32", "SetConsoleTitle",
524 | ['p'], 'l' )
525 | end
526 | @@m_SetConsoleTitle.call( lpConsoleTitle )
527 | end
528 |
529 | def SetConsoleWindowInfo( hConsoleOutput, bAbsolute,
530 | left, top, right, bottom )
531 | if @@m_SetConsoleWindowInfo == nil
532 | @@m_SetConsoleWindowInfo = Win32API.new( "kernel32",
533 | "SetConsoleWindowInfo",
534 | ['l', 'l', 'p'], 'l' )
535 | end
536 | lpConsoleWindow = [ left, top, right, bottom ].pack('ssss')
537 | @@m_SetConsoleWindowInfo.call( hConsoleOutput, bAbsolute,
538 | lpConsoleWindow )
539 | end
540 |
541 | def SetStdHandle( nStdHandle, hHandle )
542 | if @@m_SetStdHandle == nil
543 | @@m_SetStdHandle = Win32API.new( "kernel32", "SetStdHandle",
544 | ['l', 'l'], 'l' )
545 | end
546 | @@m_SetStdHandle.call( nStdHandle, hHandle )
547 | end
548 |
549 | def WriteConsole( hConsoleOutput, lpBuffer )
550 | if @@m_WriteConsole == nil
551 | @@m_WriteConsole = Win32API.new( "kernel32", "WriteConsole",
552 | ['l', 'p', 'l', 'p', 'p'], 'l' )
553 | end
554 | nNumberOfCharsToWrite = lpBuffer.length()
555 | lpNumberOfCharsWritten = ' ' * 4
556 | lpReserved = ' ' * 4
557 | @@m_WriteConsole.call( hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
558 | lpNumberOfCharsWritten, lpReserved )
559 | return lpNumberOfCharsWritten
560 | end
561 |
562 | def WriteConsoleInput( hConsoleInput, lpBuffer )
563 | if @@m_WriteConsoleInput == nil
564 | @@m_WriteConsoleInput = Win32API.new( "kernel32", "WriteConsoleInput", ['l', 'p', 'l', 'p'], 'l' )
565 | end
566 | @@m_WriteConsoleInput.call( hConsoleInput, lpBuffer, nLength,
567 | lpNumberOfEventsWritten )
568 | end
569 |
570 | # @@ Todo: Test this
571 | def WriteConsoleOutput( hConsoleOutput, buffer, cols, rows,
572 | bufx, bufy, left, top, right, bottom )
573 | if @@m_WriteConsoleOutput == nil
574 | @@m_WriteConsoleOutput = Win32API.new( "kernel32", "WriteConsoleOutput", ['l', 'p', 'l', 'l', 'p'], 'l' )
575 | end
576 | lpBuffer = buffer.flatten.pack('ss' * buffer.length() * 2)
577 | dwBufferSize = (buffer.length() << 16) + 2
578 | dwBufferCoord = (row << 16) + col
579 | lpWriteRegion = [ left, top, right, bottom ].pack('ssss')
580 | @@m_WriteConsoleOutput.call( hConsoleOutput, lpBuffer, dwBufferSize,
581 | dwBufferCoord, lpWriteRegion )
582 | end
583 |
584 | def WriteConsoleOutputAttribute( hConsoleOutput, lpAttribute, col, row )
585 | if @@m_WriteConsoleOutputAttribute == nil
586 | @@m_WriteConsoleOutputAttribute = Win32API.new( "kernel32", "WriteConsoleOutputAttribute", ['l', 'p', 'l', 'l', 'p'], 'l' )
587 | end
588 | nLength = lpAttribute.length()
589 | dwWriteCoord = (row << 16) + col
590 | lpNumberOfAttrsWritten = ' ' * 4
591 | @@m_WriteConsoleOutputAttribute.call( hConsoleOutput, lpAttribute,
592 | nLength, dwWriteCoord,
593 | lpNumberOfAttrsWritten )
594 | return lpNumberOfAttrsWritten.unpack('L')
595 | end
596 |
597 | def WriteConsoleOutputCharacter( hConsoleOutput, lpCharacter, col, row )
598 | if @@m_WriteConsoleOutputCharacter == nil
599 | @@m_WriteConsoleOutputCharacter = Win32API.new( "kernel32", "WriteConsoleOutputCharacter", ['l', 'p', 'l', 'l', 'p'], 'l' )
600 | end
601 | nLength = lpCharacter.length()
602 | dwWriteCoord = (row << 16) + col
603 | lpNumberOfCharsWritten = ' ' * 4
604 | @@m_WriteConsoleOutputCharacter.call( hConsoleOutput, lpCharacter,
605 | nLength, dwWriteCoord,
606 | lpNumberOfCharsWritten )
607 | return lpNumberOfCharsWritten.unpack('L')
608 | end
609 |
610 | end
611 | end
612 |
613 | end # rescue
614 |
615 |
616 |
617 | module Win32
618 | class Console
619 |
620 | VERSION = '1.0'
621 |
622 | include Win32::Console::Constants
623 |
624 | def initialize( t = nil )
625 | if t and ( t == STD_INPUT_HANDLE or t == STD_OUTPUT_HANDLE or
626 | t == STD_ERROR_HANDLE )
627 | @handle = API.GetStdHandle( t )
628 | else
629 | param1 = GENERIC_READ | GENERIC_WRITE
630 | param2 = FILE_SHARE_READ | FILE_SHARE_WRITE
631 | @handle = API.CreateConsoleScreenBuffer( param1, param2,
632 | CONSOLE_TEXTMODE_BUFFER )
633 | end
634 | end
635 |
636 |
637 | def Display
638 | return API.SetConsoleActiveScreenBuffer(@handle)
639 | end
640 |
641 | def Select(type)
642 | return API.SetStdHandle(type,@handle)
643 | end
644 |
645 | def Title(title = nil)
646 | if title
647 | return API.SetConsoleTitle(title)
648 | else
649 | return API.GetConsoleTitle()
650 | end
651 | end
652 |
653 | def WriteChar(s, col, row)
654 | API.WriteConsoleOutputCharacter( @handle, s, col, row )
655 | end
656 |
657 | def ReadChar(size, col, row)
658 | buffer = ' ' * size
659 | if API.ReadConsoleOutputCharacter( @handle, buffer, size, col, row )
660 | return buffer
661 | else
662 | return nil
663 | end
664 | end
665 |
666 | def WriteAttr(attr, col, row)
667 | API.WriteConsoleOutputAttribute( @handle, attr, col, row )
668 | end
669 |
670 | def ReadAttr(size, col, row)
671 | x = API.ReadConsoleOutputAttribute( @handle, size, col, row )
672 | return x.unpack('c'*size)
673 | end
674 |
675 |
676 | def Cursor(*t)
677 | col, row, size, visi = t
678 | if col
679 | row = -1 if !row
680 | if col < 0 or row < 0
681 | curr_col, curr_row = API.GetConsoleScreenBufferInfo(@handle)
682 | col = curr_col if col < 0
683 | row = curr_row if row < 0
684 | end
685 | API.SetConsoleCursorPosition( @handle, col, row )
686 | if size and visi
687 | curr_size, curr_visi = API.GetConsoleCursorInfo( @handle )
688 | size = curr_size if size < 0
689 | visi = curr_visi if visi < 0
690 | size = 1 if size < 1
691 | size = 99 if size > 99
692 | API.SetConsoleCursorInfo( @handle, size, visi )
693 | end
694 | else
695 | d, d, curr_col, curr_row = API.GetConsoleScreenBufferInfo(@handle)
696 | curr_size, curr_visi = API.GetConsoleCursorInfo( @handle )
697 | return [ curr_col, curr_row, curr_size, curr_visi ]
698 | end
699 | end
700 |
701 | def Write(s)
702 | API.WriteConsole( @handle, s )
703 | end
704 |
705 | def ReadRect( left, top, right, bottom )
706 | col = right - left + 1
707 | row = bottom - top + 1
708 | size = col * row
709 | buffer = ' ' * size * 4
710 | if API.ReadConsoleOutput( @handle, buffer, col, row, 0, 0,
711 | left, top, right, bottom )
712 | #return buffer.unpack('US'*size) # for unicode
713 | return buffer.unpack('axS'*size) # for ascii
714 | else
715 | return nil
716 | end
717 | end
718 |
719 | def WriteRect( buffer, left, top, right, bottom )
720 | col = right - left + 1
721 | row = bottom - top + 1
722 | API.WriteConsoleOutput( @handle, buffer, col, row, 0, 0,
723 | left, top, right, bottom )
724 | end
725 |
726 |
727 |
728 | def Scroll( left1, top1, right1, bottom1,
729 | col, row, char, attr,
730 | left2, top2, right2, bottom2 )
731 | API.ScrollConsoleScreenBuffer(@handle, left1, top1, right1, bottom1,
732 | col, row, char, attr,
733 | left2, top2, right2, bottom2)
734 | end
735 |
736 |
737 | def MaxWindow(flag = nil)
738 | if !flag
739 | info = API.GetConsoleScreenBufferInfo(@handle)
740 | return info[9], info[10]
741 | else
742 | return API.GetLargestConsoleWindowSize(@handle)
743 | end
744 | end
745 |
746 |
747 | def Info()
748 | return API.GetConsoleScreenBufferInfo( @handle )
749 | end
750 |
751 |
752 | def GetEvents()
753 | return API.GetNumberOfConsoleInputEvents(@handle)
754 | end
755 |
756 |
757 | def Flush()
758 | return API.FlushConsoleInputBuffer(@handle)
759 | end
760 |
761 | def InputChar(number = nil)
762 | number = 1 unless number
763 | buffer = ' ' * number
764 | if API.ReadConsole(@handle, buffer, number) == number
765 | return buffer
766 | else
767 | return nil
768 | end
769 | end
770 |
771 |
772 | def Input()
773 | API.ReadConsoleInput(@handle)
774 | end
775 |
776 |
777 | def PeekInput()
778 | API.PeekConsoleInput(@handle)
779 | end
780 |
781 |
782 | def Mode(mode = nil)
783 | if mode
784 | mode = mode.pack('L') if mode === Array
785 | API.SetConsoleMode(@handle, mode)
786 | else
787 | return API.GetConsoleMode(@handle)
788 | end
789 | end
790 |
791 | def WriteInput(*t)
792 | API.WriteConsoleInput(@handle, *t)
793 | end
794 |
795 | def Attr(*attr)
796 | if attr.size > 0
797 | API.SetConsoleTextAttribute( @handle, attr[0] )
798 | else
799 | info = API.GetConsoleScreenBufferInfo( @handle )
800 | return info[4]
801 | end
802 | end
803 |
804 |
805 | def Size(*t)
806 | if t.size == 0
807 | col, row = API.GetConsoleScreenBufferInfo(@handle )
808 | return [col, row]
809 | else
810 | row = -1 if !t[1]
811 | col = -1 if !t[0]
812 | if col < 0 or row < 0
813 | curr_col, curr_row = Size()
814 | col = curr_col if col < 0
815 | row = curr_row if row < 0
816 | end
817 | API.SetConsoleScreenBufferSize(@handle, row, col)
818 | end
819 | end
820 |
821 | def Window(*t)
822 | if t.size != 5
823 | info = API.GetConsoleScreenBufferInfo( @handle )
824 | return info[5..8]
825 | else
826 | API.SetConsoleWindowInfo(@handle, t[0], t[1], t[2], t[3], t[4])
827 | end
828 | end
829 |
830 | def FillAttr(attr, number = 1, col = -1, row = -1)
831 | if col < 0 or row < 0
832 | d, d, curr_col, curr_row = API.GetConsoleScreenBufferInfo(@handle)
833 | col = curr_col if col < 0
834 | row = curr_row if row < 0
835 | end
836 | API.FillConsoleOutputAttribute(@handle, attr, number, col, row)
837 | end
838 |
839 | def FillChar(char, number, col = -1, row = -1)
840 | if col < 0 or row < 0
841 | d, d, curr_col, curr_row = API.GetConsoleScreenBufferInfo(@handle)
842 | col = curr_col if col < 0
843 | row = curr_row if row < 0
844 | end
845 | API.FillConsoleOutputCharacter(@handle, char[0], number, col, row)
846 | end
847 |
848 | def Cls()
849 | attr = ATTR_NORMAL
850 | x, y = Size()
851 | left, top, right , bottom = Window()
852 | vx = right - left
853 | vy = bottom - top
854 | FillChar(' ', x*y, 0, 0)
855 | FillAttr(attr, x*y, 0, 0)
856 | Cursor(0,0)
857 | Window(1,0,0,vx,vy)
858 | end
859 |
860 | def Console.Free()
861 | API.FreeConsole()
862 | end
863 |
864 | def Console.Alloc()
865 | API.AllocConsole()
866 | end
867 |
868 | def Console.MouseButtons()
869 | API.GetNumberOfConsoleMouseButtons()
870 | end
871 |
872 | def Console.InputCP(codepage=nil)
873 | if codepage
874 | API.SetConsoleCP(codepage)
875 | else
876 | return API.GetConsoleCP()
877 | end
878 | end
879 |
880 | def Console.OutputCP(codepage=nil)
881 | if codepage
882 | API.SetConsoleOutputCP(codepage)
883 | else
884 | return API.GetConsoleOutputCP()
885 | end
886 | end
887 |
888 | def Console.GenerateCtrlEvent( type=nil, pid=nil )
889 | type = API.constant('CTRL_C_EVENT') if type == nil
890 | pid = 0 if pid == nil
891 | API.GenerateConsoleCtrlEvent(type, pid)
892 | end
893 |
894 | end
895 | end
896 |
897 |
898 |
899 |
900 |
901 | FG_BLACK = 0
902 | FG_BLUE = Win32::Console::API.constant("FOREGROUND_BLUE")
903 | FG_LIGHTBLUE = Win32::Console::API.constant("FOREGROUND_BLUE")|
904 | Win32::Console::API.constant("FOREGROUND_INTENSITY")
905 | FG_RED = Win32::Console::API.constant("FOREGROUND_RED")
906 | FG_LIGHTRED = Win32::Console::API.constant("FOREGROUND_RED")|
907 | Win32::Console::API.constant("FOREGROUND_INTENSITY")
908 | FG_GREEN = Win32::Console::API.constant("FOREGROUND_GREEN")
909 | FG_LIGHTGREEN = Win32::Console::API.constant("FOREGROUND_GREEN")|
910 | Win32::Console::API.constant("FOREGROUND_INTENSITY")
911 | FG_MAGENTA = Win32::Console::API.constant("FOREGROUND_RED")|
912 | Win32::Console::API.constant("FOREGROUND_BLUE")
913 | FG_LIGHTMAGENTA = Win32::Console::API.constant("FOREGROUND_RED")|
914 | Win32::Console::API.constant("FOREGROUND_BLUE")|
915 | Win32::Console::API.constant("FOREGROUND_INTENSITY")
916 | FG_CYAN = Win32::Console::API.constant("FOREGROUND_GREEN")|
917 | Win32::Console::API.constant("FOREGROUND_BLUE")
918 | FG_LIGHTCYAN = Win32::Console::API.constant("FOREGROUND_GREEN")|
919 | Win32::Console::API.constant("FOREGROUND_BLUE")|
920 | Win32::Console::API.constant("FOREGROUND_INTENSITY")
921 | FG_BROWN = Win32::Console::API.constant("FOREGROUND_RED")|
922 | Win32::Console::API.constant("FOREGROUND_GREEN")
923 | FG_YELLOW = Win32::Console::API.constant("FOREGROUND_RED")|
924 | Win32::Console::API.constant("FOREGROUND_GREEN")|
925 | Win32::Console::API.constant("FOREGROUND_INTENSITY")
926 | FG_GRAY = Win32::Console::API.constant("FOREGROUND_RED")|
927 | Win32::Console::API.constant("FOREGROUND_GREEN")|
928 | Win32::Console::API.constant("FOREGROUND_BLUE")
929 | FG_WHITE = Win32::Console::API.constant("FOREGROUND_RED")|
930 | Win32::Console::API.constant("FOREGROUND_GREEN")|
931 | Win32::Console::API.constant("FOREGROUND_BLUE")|
932 | Win32::Console::API.constant("FOREGROUND_INTENSITY")
933 |
934 | BG_BLACK = 0
935 | BG_BLUE = Win32::Console::API.constant("BACKGROUND_BLUE")
936 | BG_LIGHTBLUE = Win32::Console::API.constant("BACKGROUND_BLUE")|
937 | Win32::Console::API.constant("BACKGROUND_INTENSITY")
938 | BG_RED = Win32::Console::API.constant("BACKGROUND_RED")
939 | BG_LIGHTRED = Win32::Console::API.constant("BACKGROUND_RED")|
940 | Win32::Console::API.constant("BACKGROUND_INTENSITY")
941 | BG_GREEN = Win32::Console::API.constant("BACKGROUND_GREEN")
942 | BG_LIGHTGREEN = Win32::Console::API.constant("BACKGROUND_GREEN")|
943 | Win32::Console::API.constant("BACKGROUND_INTENSITY")
944 | BG_MAGENTA = Win32::Console::API.constant("BACKGROUND_RED")|
945 | Win32::Console::API.constant("BACKGROUND_BLUE")
946 | BG_LIGHTMAGENTA = Win32::Console::API.constant("BACKGROUND_RED")|
947 | Win32::Console::API.constant("BACKGROUND_BLUE")|
948 | Win32::Console::API.constant("BACKGROUND_INTENSITY")
949 | BG_CYAN = Win32::Console::API.constant("BACKGROUND_GREEN")|
950 | Win32::Console::API.constant("BACKGROUND_BLUE")
951 | BG_LIGHTCYAN = Win32::Console::API.constant("BACKGROUND_GREEN")|
952 | Win32::Console::API.constant("BACKGROUND_BLUE")|
953 | Win32::Console::API.constant("BACKGROUND_INTENSITY")
954 | BG_BROWN = Win32::Console::API.constant("BACKGROUND_RED")|
955 | Win32::Console::API.constant("BACKGROUND_GREEN")
956 | BG_YELLOW = Win32::Console::API.constant("BACKGROUND_RED")|
957 | Win32::Console::API.constant("BACKGROUND_GREEN")|
958 | Win32::Console::API.constant("BACKGROUND_INTENSITY")
959 | BG_GRAY = Win32::Console::API.constant("BACKGROUND_RED")|
960 | Win32::Console::API.constant("BACKGROUND_GREEN")|
961 | Win32::Console::API.constant("BACKGROUND_BLUE")
962 | BG_WHITE = Win32::Console::API.constant("BACKGROUND_RED")|
963 | Win32::Console::API.constant("BACKGROUND_GREEN")|
964 | Win32::Console::API.constant("BACKGROUND_BLUE")|
965 | Win32::Console::API.constant("BACKGROUND_INTENSITY")
966 |
967 | ATTR_NORMAL = FG_GRAY | BG_BLACK
968 | ATTR_INVERSE = FG_BLACK | BG_GRAY
969 |
970 | include Win32::Console::Constants
971 |
--------------------------------------------------------------------------------
/work/reference/console/lib/Win32/Console/ANSI.rb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubyworks/ansi/17002348d45ce9298a1a4017dc43d3cf65151bd4/work/reference/console/lib/Win32/Console/ANSI.rb
--------------------------------------------------------------------------------
/work/reference/console/test/test_cursor.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "Win32/Console"
4 |
5 |
6 | a = Win32::Console.new(STD_OUTPUT_HANDLE)
7 |
8 | puts "Setting cursor to visible and 100% fat"
9 | a.Cursor(-1,-1,100,1)
10 |
--------------------------------------------------------------------------------
/work/reference/console/test/test_mouse.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "Win32/Console"
4 |
5 | a = Win32::Console.new()
6 | puts "# of Mouse buttons: #{Win32::Console.MouseButtons}"
7 |
--------------------------------------------------------------------------------
/work/reference/console/test/test_readinput.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "Win32/Console"
4 |
5 | include Win32::Console::Constants
6 | a = Win32::Console.new(STD_INPUT_HANDLE)
7 |
8 | puts "InputChar: Type a phrase then ENTER, please:"
9 |
10 | x1 = a.InputChar(1)
11 | puts "Your phrase starts with the character #{x1}"
12 |
13 |
14 | fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT
15 |
16 | a.Mode(fdwMode)
17 |
18 | puts
19 | puts "PeekInput: Type a character without ENTER or do something, please:"
20 |
21 | while (x1 = a.PeekInput()).size < 1
22 | end
23 |
24 | if x1[0] == KEY_EVENT
25 | puts "You typed #{x1[5]}='#{x1[5].chr}'"
26 | else
27 | print "You did not typed, but "
28 | case x1[0]
29 | when MOUSE_EVENT
30 | puts "used mouse"
31 | when WINDOW_BUFFER_SIZE_EVENT
32 | puts "resize window"
33 | when MENU_EVENT
34 | puts "called menu"
35 | when FOCUS_EVENT
36 | puts "changed focus"
37 | else
38 | puts "...should never get here"
39 | end
40 | end
41 |
42 | puts
43 | puts "Input (as PeekInput keeps event, this reuses PeekInput value):"
44 | x1 = a.Input()
45 | if x1[0] == KEY_EVENT
46 | puts "You typed #{x1[5]}='#{x1[5].chr}'"
47 | else
48 | print "You did not typed, but "
49 | case x1[0]
50 | when MOUSE_EVENT
51 | puts "used mouse"
52 | when WINDOW_BUFFER_SIZE_EVENT
53 | puts "resize window"
54 | when MENU_EVENT
55 | puts "called menu"
56 | when FOCUS_EVENT
57 | puts "changed focus"
58 | else
59 | puts "...should never get here"
60 | end
61 | end
62 |
63 |
--------------------------------------------------------------------------------
/work/reference/console/test/test_readoutput.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "Win32/Console"
4 |
5 | include Win32::Console::Constants
6 | a = Win32::Console.new(STD_OUTPUT_HANDLE)
7 |
8 | puts <<'EOF'
9 | This is a simple
10 | test of test to grab
11 | from the console.
12 | Hopefully this will work
13 | easily and merrily.
14 | This is a simple
15 | test of test to grab
16 | from the console.
17 | Hopefully this will work
18 | easily and merrily.
19 | This is a simple
20 | test of test to grab
21 | from the console.
22 | Hopefully this will work
23 | easily and merrily.
24 | EOF
25 |
26 | x1 = a.ReadChar(10,10,10)
27 | x2 = a.ReadAttr(10,10,10)
28 | x3 = a.ReadRect(10,10,20,10)
29 | puts "ReadChar .#{x1}."
30 | puts x2.class, x2.size
31 | print "ReadAttr ."
32 | for i in x2
33 | print "#{i}|"
34 | end
35 | print "\nReadRect ."
36 |
37 | i = 0
38 | while i < x3.length-1
39 | print "#{x3[i]}"
40 | i += 2
41 | end
42 | print "\n "
43 | i = 1
44 | while i < x3.length-1
45 | print "#{x3[i]}|"
46 | i += 2
47 | end
48 | print "\n"
49 |
50 | #puts "read=",x1
51 | #print "Attributes:",x2
52 |
53 |
--------------------------------------------------------------------------------
/work/reference/console/test/test_sendevent.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "Win32/Console"
4 |
5 |
6 | i = 0
7 | begin
8 | while i < 99
9 | if i == 10
10 | Win32::Console::GenerateCtrlEvent()
11 | end
12 | i = i.next
13 | end
14 | rescue Exception
15 | end
16 |
17 | puts "if i=10, then OK! i=#{i}"
18 |
--------------------------------------------------------------------------------
/work/reference/console/test/test_title.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "Win32/Console"
4 |
5 | a = Win32::Console.new()
6 |
7 | title = a.Title()
8 | puts "Old title: \"#{title}\""
9 |
10 | a.Title("This is a new title")
11 | title = a.Title()
12 | puts "I just changed the title to '#{title}'"
13 |
14 | sleep(5)
15 |
--------------------------------------------------------------------------------
/work/reference/console/test/test_write.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | if $0 == __FILE__
4 | require "Term/ANSIColor"
5 | include Term::ANSIColor
6 |
7 | require "benchmark"
8 | include Benchmark
9 |
10 | require "Win32/Console/ANSI"
11 |
12 | bm do |x|
13 | num = 100
14 | x.report("#{num} times") {
15 | 0.upto(num) {
16 | print "\e[2J"
17 |
18 | print red, bold, "Usage as constants:", reset, "\n"
19 |
20 | print clear, "clear", reset, reset, "reset", reset,
21 | bold, "bold", reset, dark, "dark", reset,
22 | underscore, "underscore", reset, blink, "blink", reset,
23 | negative, "negative", reset, concealed, "concealed", reset, "|\n",
24 | black, "black", reset, red, "red", reset, green, "green", reset,
25 | yellow, "yellow", reset, blue, "blue", reset, magenta, "magenta", reset,
26 | cyan, "cyan", reset, white, "white", reset, "|\n",
27 | on_black, "on_black", reset, on_red, "on_red", reset,
28 | on_green, "on_green", reset, on_yellow, "on_yellow", reset,
29 | on_blue, "on_blue", reset, on_magenta, "on_magenta", reset,
30 | on_cyan, "on_cyan", reset, on_white, "on_white", reset, "|\n\n"
31 | print "\e[s\e[20P.................."
32 | }
33 | }
34 | end
35 | end
36 |
37 |
--------------------------------------------------------------------------------
/work/reference/heuristics.rb:
--------------------------------------------------------------------------------
1 | def guess_color_availability
2 | return false unless @output.tty?
3 | case ENV["TERM"]
4 | when /term(?:-color)?\z/, "screen"
5 | true
6 | else
7 | return true if ENV["EMACS"] == "t"
8 | false
9 | end
10 | end
11 |
12 | def guess_progress_row_max
13 | term_width = guess_term_width
14 | if term_width.zero?
15 | if ENV["EMACS"] == "t"
16 | -1
17 | else
18 | 79
19 | end
20 | else
21 | term_width
22 | end
23 | end
24 |
25 | def guess_term_width
26 | Integer(ENV["COLUMNS"] || ENV["TERM_WIDTH"] || 0)
27 | rescue ArgumentError
28 | 0
29 | end
30 |
31 |
--------------------------------------------------------------------------------