├── .gitignore ├── .index ├── .travis.yml ├── .yardopts ├── Assembly ├── DEMO.md ├── Ergofile ├── Gemfile ├── HISTORY.md ├── INDEX.yml ├── LICENSE.txt ├── MANIFEST ├── NOTICE.md ├── README.md ├── Rakefile ├── ansi.gemspec ├── demo ├── 01_ansicode.md ├── 02_core.md ├── 03_logger.md ├── 04_progressbar.md ├── 05_mixin.md ├── 06_string.md ├── 07_columns.md ├── 08_table.md ├── 09_diff.md ├── 10_bbcode.md ├── 11_terminal.md └── applique │ ├── ae.rb │ └── output.rb ├── etc └── qed.rb ├── lib ├── ansi.rb ├── ansi.yml └── ansi │ ├── bbcode.rb │ ├── chain.rb │ ├── chart.rb │ ├── code.rb │ ├── columns.rb │ ├── constants.rb │ ├── core.rb │ ├── diff.rb │ ├── hexdump.rb │ ├── logger.rb │ ├── mixin.rb │ ├── progressbar.rb │ ├── string.rb │ ├── table.rb │ ├── terminal.rb │ ├── terminal │ ├── curses.rb │ ├── stty.rb │ ├── termios.rb │ └── win32.rb │ └── version.rb ├── test ├── case_ansicode.rb ├── case_bbcode.rb ├── case_mixin.rb ├── case_progressbar.rb └── test_helper.rb └── work ├── NOTES.md ├── benchmarks └── string_vs_block.rb ├── consider ├── highlight.rb └── string.rd ├── deprecated ├── ansi.rbz └── task │ ├── demo.ergo │ ├── index.ergo │ ├── syckle-hooks │ └── pre-generate.rb │ ├── test.ergo │ └── test.watchr └── reference ├── ansicode.rb ├── console ├── .gitignore ├── Console.cpp ├── Console.rdoc ├── Console_ANSI.rdoc ├── HISTORY.txt ├── INSTALL.txt ├── Makefile ├── README.txt ├── extconf.rb ├── lib │ ├── Term │ │ └── ansicolor.rb │ └── Win32 │ │ ├── Console.rb │ │ └── Console │ │ └── ANSI.rb └── test │ ├── .CODE.rb │ ├── test_cursor.rb │ ├── test_mouse.rb │ ├── test_readinput.rb │ ├── test_readoutput.rb │ ├── test_sendevent.rb │ ├── test_title.rb │ └── test_write.rb └── heuristics.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .reap/digest 2 | .rdoc 3 | .yardoc 4 | log 5 | pkg 6 | tmp 7 | doc 8 | web 9 | *.lock 10 | *.gem 11 | -------------------------------------------------------------------------------- /.index: -------------------------------------------------------------------------------- 1 | --- 2 | revision: 2013 3 | type: ruby 4 | sources: 5 | - INDEX.yml 6 | authors: 7 | - name: Thomas Sawyer 8 | email: transfire@gmail.com 9 | - name: Florian Frank 10 | organizations: [] 11 | requirements: 12 | - groups: 13 | - build 14 | development: true 15 | name: mast 16 | - groups: 17 | - build 18 | development: true 19 | name: indexer 20 | - groups: 21 | - build 22 | development: true 23 | name: ergo 24 | - groups: 25 | - test 26 | development: true 27 | name: qed 28 | - groups: 29 | - test 30 | development: true 31 | name: ae 32 | - groups: 33 | - test 34 | development: true 35 | name: lemon 36 | conflicts: [] 37 | alternatives: [] 38 | resources: 39 | - type: home 40 | uri: http://rubyworks.github.com/ansi 41 | label: Homepage 42 | - type: docs 43 | uri: http://rubydoc.info/gems/ansi/frames 44 | label: Documentation 45 | - type: code 46 | uri: http://github.com/rubyworks/ansi 47 | label: Source Code 48 | - type: bugs 49 | uri: http://github.com/rubyworks/ansi/issues 50 | label: Issue Tracker 51 | - type: mail 52 | uri: http://groups.google.com/group/rubyworks-mailinglist 53 | label: Mailing List 54 | repositories: 55 | - name: upstream 56 | scm: git 57 | uri: git://github.com/rubyworks/ansi.git 58 | categories: [] 59 | copyrights: 60 | - holder: Rubyworks 61 | year: '2009' 62 | license: BSD-2-Clause 63 | customs: [] 64 | paths: 65 | lib: 66 | - lib 67 | name: ansi 68 | title: ANSI 69 | version: 1.5.0 70 | summary: ANSI at your fingertips! 71 | description: The ANSI project is a superlative collection of ANSI escape code related 72 | libraries eabling ANSI colorization and stylization of console output. Byte for 73 | byte ANSI is the best ANSI code library available for the Ruby programming language. 74 | orgranizations: 75 | - Rubyworks 76 | created: '2009-08-01' 77 | date: '2015-01-16' 78 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: ruby 3 | script: "bundle exec qed" 4 | rvm: 5 | - 2.1.0 6 | - 2.0.0 7 | - 1.9.3 8 | - rbx 9 | - jruby 10 | matrix: 11 | allow_failures: 12 | - rvm: rbx 13 | cache: bundler 14 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --title ANSI 2 | --protected 3 | --private 4 | lib 5 | - 6 | QED.rdoc 7 | [A-Z]*.* 8 | 9 | -------------------------------------------------------------------------------- /Assembly: -------------------------------------------------------------------------------- 1 | --- 2 | gem: 3 | active: true 4 | 5 | github: 6 | folder: web 7 | 8 | email: 9 | mailto: 10 | - rubyworks-mailinglist@googlegroups.com 11 | - ruby-talk@ruby-lang.org 12 | 13 | qed: 14 | files : demo/ 15 | 16 | qedoc: 17 | files : demo/ 18 | title : Ruby ANSI 19 | output : DEMO.md 20 | 21 | minitest: 22 | tests : ~ 23 | exclude : ~ 24 | loadpath : ~ 25 | requires : ~ 26 | live : false 27 | active : false 28 | 29 | dnote: 30 | files : lib/**/*.rb 31 | title : Source Notes 32 | output : log/notes.html 33 | 34 | yard: 35 | yardopts : true 36 | priority : 2 # do last 37 | 38 | vclog: 39 | output: 40 | - log/history.html 41 | - log/changes.html 42 | active: false 43 | 44 | -------------------------------------------------------------------------------- /DEMO.md: -------------------------------------------------------------------------------- 1 | # ANSI::Code 2 | 3 | Require the library. 4 | 5 | require 'ansi/code' 6 | 7 | ANSI::Code can be used as a functions module. 8 | 9 | str = ANSI::Code.red + "Hello" + ANSI::Code.blue + "World" 10 | str.assert == "\e[31mHello\e[34mWorld" 11 | 12 | If a block is supplied to each method then yielded value will 13 | be wrapped in the ANSI code and clear code. 14 | 15 | str = ANSI::Code.red{ "Hello" } + ANSI::Code.blue{ "World" } 16 | str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m" 17 | 18 | More conveniently the ANSI::Code module extends ANSI itself. 19 | 20 | str = ANSI.red + "Hello" + ANSI.blue + "World" 21 | str.assert == "\e[31mHello\e[34mWorld" 22 | 23 | str = ANSI.red{ "Hello" } + ANSI.blue{ "World" } 24 | str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m" 25 | 26 | In the appropriate context the ANSI::Code module can also be 27 | included, making its methods directly accessible. 28 | 29 | include ANSI::Code 30 | 31 | str = red + "Hello" + blue + "World" 32 | str.assert == "\e[31mHello\e[34mWorld" 33 | 34 | str = red{ "Hello" } + blue{ "World" } 35 | str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m" 36 | 37 | Along with the single font colors, the library include background colors. 38 | 39 | str = on_red + "Hello" 40 | str.assert == "\e[41mHello" 41 | 42 | As well as combined color methods. 43 | 44 | str = white_on_red + "Hello" 45 | str.assert == "\e[37m\e[41mHello" 46 | 47 | The ANSI::Code module supports most standard ANSI codes, though 48 | not all platforms support every code, so YMMV. 49 | 50 | 51 | # String Extensions 52 | 53 | In addition the library offers an extension to String class 54 | called #ansi, which allows some of the ANSI::Code methods 55 | to be called in a more object-oriented fashion. 56 | 57 | require 'ansi/core' 58 | 59 | str = "Hello".ansi(:red) + "World".ansi(:blue) 60 | str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m" 61 | 62 | 63 | # ANSI::Logger 64 | 65 | Require the ANSI::Logger library. 66 | 67 | require 'ansi/logger' 68 | 69 | Create a new ANSI::Logger 70 | 71 | log = ANSI::Logger.new(STDOUT) 72 | 73 | Info logging appears normal. 74 | 75 | log.info{"Info logs are green.\n"} 76 | 77 | Warn logging appears yellow. 78 | 79 | log.warn{"Warn logs are yellow.\n"} 80 | 81 | Debug logging appears cyan. 82 | 83 | log.debug{"Debug logs are cyan.\n"} 84 | 85 | Error logging appears red. 86 | 87 | log.error{"Error logs are red.\n"} 88 | 89 | Fatal logging appears bright red. 90 | 91 | log.fatal{"Fatal logs are bold red!\n"} 92 | 93 | 94 | # ANSI::Progressbar 95 | 96 | Pretty progress bars are easy to construct. 97 | 98 | require 'ansi/progressbar' 99 | 100 | pbar = ANSI::Progressbar.new("Test Bar", 100) 101 | 102 | Running the bar simply requires calling the #inc method during 103 | a loop and calling #finish when done. 104 | 105 | 100.times do |i| 106 | sleep 0.01 107 | pbar.inc 108 | end 109 | pbar.finish 110 | 111 | We will use this same rountine in all the examples below, so lets 112 | make a quick macro for it. Notice we have to use #reset first 113 | before reusing the same progress bar. 114 | 115 | def run(pbar) 116 | pbar.reset 117 | 100.times do |i| 118 | sleep 0.01 119 | pbar.inc 120 | end 121 | pbar.finish 122 | puts 123 | end 124 | 125 | The progress bar can be stylized in almost any way. 126 | The #format setter provides control over the parts 127 | that appear on the line. For example, by default the 128 | format is: 129 | 130 | pbar.format("%-14s %3d%% %s %s", :title, :percentage, :bar, :stat) 131 | 132 | So lets vary it up to demonstrate the case. 133 | 134 | pbar.format("%-14s %3d%% %s %s", :title, :percentage, :stat, :bar) 135 | run(pbar) 136 | 137 | The progress bar has an extra build in format intended for use with 138 | file downloads called #transer_mode. 139 | 140 | pbar.transfer_mode 141 | run(pbar) 142 | 143 | Calling this methods is the same as calling: 144 | 145 | pbar.format("%-14s %3d%% %s %s",:title, :percentage, :bar, :stat_for_file_transfer) 146 | run(pbar) 147 | 148 | The #style setter allows each part of the line be modified with ANSI codes. And the 149 | #bar_mark writer can be used to change the character used to make the bar. 150 | 151 | pbar.standard_mode 152 | pbar.style(:title => [:red], :bar=>[:blue]) 153 | pbar.bar_mark = "=" 154 | run(pbar) 155 | 156 | 157 | # ANSI::Mixin 158 | 159 | The ANSI::Mixin module is design for including into 160 | String-like classes. It will support any class that defines 161 | a #to_s method. 162 | 163 | require 'ansi/mixin' 164 | 165 | In this demonstration we will simply include it in the 166 | core String class. 167 | 168 | class ::String 169 | include ANSI::Mixin 170 | end 171 | 172 | Now all strings will have access to ANSI's style and color 173 | codes via simple method calls. 174 | 175 | "roses".red.assert == "\e[31mroses\e[0m" 176 | 177 | "violets".blue.assert == "\e[34mviolets\e[0m" 178 | 179 | "sugar".italic.assert == "\e[3msugar\e[0m" 180 | 181 | The method can be combined, of course. 182 | 183 | "you".italic.bold.assert == "\e[1m\e[3myou\e[0m\e[0m" 184 | 185 | The mixin also supports background methods. 186 | 187 | "envy".on_green.assert == "\e[42menvy\e[0m" 188 | 189 | And it also supports the combined foreground-on-background 190 | methods. 191 | 192 | "b&w".white_on_black.assert == "\e[37m\e[40mb&w\e[0m" 193 | 194 | 195 | # ANSI::String 196 | 197 | The ANSI::String class is a very sophisticated implementation 198 | of Ruby's standard String class, but one that can handle 199 | ANSI codes seamlessly. 200 | 201 | require 'ansi/string' 202 | 203 | flower1 = ANSI::String.new("Roses") 204 | flower2 = ANSI::String.new("Violets") 205 | 206 | Like any other string. 207 | 208 | flower1.to_s.assert == "Roses" 209 | flower2.to_s.assert == "Violets" 210 | 211 | Bet now we can add color. 212 | 213 | flower1.red! 214 | flower2.blue! 215 | 216 | flower1.to_s.assert == "\e[31mRoses\e[0m" 217 | flower2.to_s.assert == "\e[34mViolets\e[0m" 218 | 219 | Despite that the string representation now contains ANSI codes, 220 | we can still manipulate the string in much the same way that 221 | we manipulate an ordinary string. 222 | 223 | flower1.size.assert == 5 224 | flower2.size.assert == 7 225 | 226 | Like ordinary strings we can concatenate the two strings 227 | 228 | flowers = flower1 + ' ' + flower2 229 | flowers.to_s.assert == "\e[31mRoses\e[0m \e[34mViolets\e[0m" 230 | 231 | flowers.size.assert == 13 232 | 233 | Standard case conversion such as #upcase and #downcase work. 234 | 235 | flower1.upcase.to_s.assert == "\e[31mROSES\e[0m" 236 | flower1.downcase.to_s.assert == "\e[31mroses\e[0m" 237 | 238 | Some of the most difficult methods to re-implement were the 239 | substitution methods such as #sub and #gsub. They are still 240 | somewhat more limited than the original string methods, but 241 | their primary functionality should work. 242 | 243 | flower1.gsub('s', 'z').to_s.assert == "\e[31mRozez\e[0m" 244 | 245 | There are still a number of methods that need implementation. 246 | ANSI::String is currently a very partial implementation. But 247 | as you can see from the methods it does currently support, 248 | is it already useful. 249 | 250 | 251 | # ANSI::Columns 252 | 253 | The +Columns+ class makes it easy to create nice looking text columns, 254 | sorted from top to bottom, right to left (as opposed to the other way 255 | around). 256 | 257 | require 'ansi/columns' 258 | 259 | list = %w{a b c d e f g h i j k l} 260 | 261 | columns = ANSI::Columns.new(list) 262 | 263 | columns.to_s(4) 264 | 265 | The output will be: 266 | 267 | a d g j 268 | b e h k 269 | c f i l 270 | 271 | Besides an array of elements, Columns.new can take a string in which 272 | the elements are divided by newlines characters. The default column 273 | size can also be given to the initializer. 274 | 275 | list = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl" 276 | 277 | columns = ANSI::Columns.new(list, :columns=>6) 278 | 279 | columns.to_s 280 | 281 | The output will be: 282 | 283 | a c e g i k 284 | b d f h j l 285 | 286 | If the column count is +nil+, then the number of columns will be calculated 287 | as a best fit for the current terminal window. 288 | 289 | ## Padding 290 | 291 | Columns can adjust the padding between cells. 292 | 293 | list = %w{a b c d e f g h i j k l} 294 | 295 | columns = ANSI::Columns.new(list, :padding=>2) 296 | 297 | columns.to_s(4) 298 | 299 | The output will be: 300 | 301 | a d g j 302 | b e h k 303 | c f i l 304 | 305 | ## Alignment 306 | 307 | Columns can also be aligned either left or right. 308 | 309 | list = %w{xx xx xx yy y yy z zz z} 310 | 311 | columns = ANSI::Columns.new(list, :align=>:right) 312 | 313 | columns.to_s(3) 314 | 315 | The output will be: 316 | 317 | xx yy z 318 | xx y zz 319 | xx yy z 320 | 321 | ## Format 322 | 323 | Lastly, columns can be augmented with ANSI codes. This is done through 324 | a formatting block. The block can take up to three parameters, the cell 325 | content, the column and row numbers, or the cell and the column and row 326 | numbers. 327 | 328 | list = %w{a b c d e f g h i j k l} 329 | 330 | columns = ANSI::Columns.new(list){ |c,r| r % 2 == 0 ? :red : :blue } 331 | 332 | out = columns.to_s(4) 333 | 334 | out.assert == ( 335 | "\e[31ma \e[0m\e[31md \e[0m\e[31mg \e[0m\e[31mj \e[0m\n" + 336 | "\e[34mb \e[0m\e[34me \e[0m\e[34mh \e[0m\e[34mk \e[0m\n" + 337 | "\e[31mc \e[0m\e[31mf \e[0m\e[31mi \e[0m\e[31ml \e[0m\n" 338 | ) 339 | 340 | 341 | # ANSI::Table 342 | 343 | The ANSI::Table class can be used to output tabular data with nicely 344 | formated ASCII cell borders. 345 | 346 | require 'ansi/table' 347 | 348 | The constructor takes an 2-dimensional array. 349 | 350 | data = [ 351 | [ 10, 20, 30 ], 352 | [ 20, 10, 20 ], 353 | [ 50, 40, 20 ] 354 | ] 355 | 356 | table = ANSI::Table.new(data) 357 | 358 | table.to_s 359 | 360 | The output will be: 361 | 362 | +----+----+----+ 363 | | 10 | 20 | 30 | 364 | | 20 | 10 | 20 | 365 | | 50 | 40 | 20 | 366 | +----+----+----+ 367 | 368 | 369 | 370 | # ANSI::Diff 371 | 372 | require 'ansi/diff' 373 | 374 | a = 'abcYefg' 375 | b = 'abcXefg' 376 | 377 | diff = ANSI::Diff.new(a,b) 378 | 379 | diff.to_s.assert == "\e[31mabc\e[0m\e[33mYefg\e[0m\n\e[31mabc\e[0mXefg" 380 | 381 | Try another. 382 | 383 | a = 'abc' 384 | b = 'abcdef' 385 | 386 | diff = ANSI::Diff.new(a,b) 387 | 388 | diff.to_s.assert == "\e[31mabc\e[0m\n\e[31mabc\e[0mdef" 389 | 390 | And another. 391 | 392 | a = 'abcXXXghi' 393 | b = 'abcdefghi' 394 | 395 | diff = ANSI::Diff.new(a,b) 396 | 397 | diff.to_s.assert == "\e[31mabc\e[0m\e[33mXXXghi\e[0m\n\e[31mabc\e[0mdefghi" 398 | 399 | And another. 400 | 401 | a = 'abcXXXdefghi' 402 | b = 'abcdefghi' 403 | 404 | diff = ANSI::Diff.new(a,b) 405 | 406 | diff.to_s.assert == "\e[31mabc\e[0m\e[33mXXX\e[0m\e[35mdefghi\e[0m\n\e[31mabc\e[0m\e[35mdefghi\e[0m" 407 | 408 | Comparison that is mostly different. 409 | 410 | a = 'abcpppz123' 411 | b = 'abcxyzzz43' 412 | 413 | diff = ANSI::Diff.new(a,b) 414 | 415 | diff.to_s.assert == "\e[31mabc\e[0m\e[33mpppz123\e[0m\n\e[31mabc\e[0mxyzzz43" 416 | 417 | 418 | # ANSI::BBCode 419 | 420 | The BBCode module provides methods for converting between 421 | BBCodes, basic HTML and ANSI codes. 422 | 423 | require 'ansi/bbcode' 424 | 425 | BBCodes are color and style codes in square brackets, quite 426 | popular with on line forums. 427 | 428 | bbcode = "this is [COLOR=red]red[/COLOR], this is [B]bold[/B]" 429 | 430 | We can convert this to ANSI code simply enough: 431 | 432 | ansi = ANSI::BBCode.bbcode_to_ansi(bbcode) 433 | 434 | ansi.assert == "this is \e[0;31mred\e[0m, this is \e[1mbold\e[0m\n" 435 | 436 | In addition the BBCode module supports conversion to simple HTML. 437 | 438 | html = ANSI::BBCode.bbcode_to_html(bbcode) 439 | 440 | html.assert == "this is red, this is bold
\n" 441 | 442 | 443 | # ANSI::Terminal 444 | 445 | We should be ables to get the terminal width via the `terminal_width` method. 446 | 447 | width = ANSI::Terminal.terminal_width 448 | 449 | Fixnum.assert === width 450 | 451 | 452 | -------------------------------------------------------------------------------- /Ergofile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ignore 'doc', 'site', 'log' 4 | 5 | ############################################################################# 6 | # 7 | # Default 8 | # 9 | ############################################################################# 10 | book :default => [:demo] 11 | 12 | ############################################################################# 13 | # 14 | # Run QED demos 15 | # 16 | ############################################################################# 17 | book :demo do 18 | desc "run demos" 19 | 20 | rule "demo/*.md" => :run_demo 21 | rule "lib/**/*.rb" => :run_all 22 | 23 | def run_demo(*demos) 24 | shell "bundle exec qed -Ilib " + demos.join(' ') 25 | end 26 | 27 | def run_all 28 | shell "bundle exec qed -Ilib demo/*.md" 29 | end 30 | 31 | #task("demo") { shell "qed -Ilib qed/" } 32 | end 33 | 34 | ############################################################################# 35 | # 36 | # Run unit tests 37 | # 38 | ############################################################################# 39 | book :test do 40 | desc "run unit tests" 41 | 42 | rule 'test/helper.rb' => :test_all 43 | rule 'test/case_*.rb' => :test 44 | rule /^lib\/(.*?)\.rb$/ => :test_match 45 | rule /^lib\/ansi\/(.*?)\.rb$/ => :test_match 46 | 47 | def test_all 48 | test *Dir['test/test_*.rb'] 49 | end 50 | 51 | def test_match(m) 52 | test "test/case_#{m[1]}" 53 | end 54 | 55 | def test(*paths) 56 | shell "bundle exec rubytest #{gem_opt} -Ilib:test " + paths.flatten.join(' ') 57 | end 58 | 59 | def gem_opt 60 | defined?(::Gem) ? "-rubygems" : "" 61 | end 62 | 63 | #Signal.trap('QUIT') { test_all } # Ctrl-\ 64 | end 65 | 66 | ############################################################################# 67 | # 68 | # Update .index file 69 | # 70 | ############################################################################# 71 | book :index do 72 | desc "update index file" 73 | 74 | rule 'INDEX.yml' do 75 | shell "index -u INDEX.yml" 76 | end 77 | end 78 | 79 | #Signal.trap('INT' ) { abort("\n") } # Ctrl-C 80 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gemspec 3 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # RELEASE HISTORY 2 | 3 | ## 1.5.0 | 2015-01-16 4 | 5 | ANSI 1.5 introduces one change that is not backward compatiable. The 6 | `:clear_line` code no longer clears to the end of the line. Instead it 7 | clears the entire line. If you have used this in the past you 8 | will need to update your code to use `:clear_eol` or `:clear_right` 9 | instead. In addition this release finally fixes some long time issues 10 | with Windows compatability, and a few other bugs. Yeah! 11 | 12 | Changes: 13 | 14 | * Alias `:right` and `:left` as `:forward` and `:back` respectively. 15 | * Change `:clear_line` to clear whole line, not just to the end of line. 16 | * Add `:cursor_hide` and `:cursor_show` codes. 17 | * Fix and adjust #rgb method to work as one would expect. 18 | * Fix Windows compatability (old code was alwasy using stty). 19 | * Fix duplicated hash key in chart.rb. 20 | 21 | 22 | ## 1.4.3 | 2012-06-26 23 | 24 | This release bring two small changes. The first improves support 25 | for Windows by only rescuing LoadError when 'win32console' fails 26 | to load. The second improves the heuritstics used for determining 27 | the current terminal screen width. 28 | 29 | Changes: 30 | 31 | * Only rescue LoadError on windows require. (#9) [bug] 32 | * Improvements for getting proper screen width. 33 | 34 | 35 | ## 1.4.2 | 2012-01-29 36 | 37 | ANSI chains are a new feature inspired by Kazuyoshi Tlacaelel's Isna project. 38 | It is a fluid notation for the String#ansi method, e.g. `"foo".red.on_white`. 39 | Also, ASNI now supports "smart codes", preventing previously applied codes 40 | from undermining the applicaiton of additional codes --a subtle issue that 41 | most other ANSI libraries overlook. Plus a few other improvements including 42 | that of the API documentation. 43 | 44 | Changes: 45 | 46 | * Add ANSI::Chains, extending String#ansi method. 47 | * Support smart code application. 48 | * Add Diff#to_a and shortcut to it via Diff.diff(). 49 | * Improve #colorize method in ProgressBar. 50 | * Change ProgressBar's default mark to `|` instead of `o`. 51 | * Fix Curses return order of screen cols and rows. 52 | * Support center alignment in Columns. 53 | * Support custom padding for Columns. 54 | 55 | 56 | ## 1.4.1 | 2011-11-09 57 | 58 | This release simply fixes a documentation issue, to make sure 59 | QED.rdoc appears in the YARD docs. And a shout-out to Chad Perrin 60 | for submitting some doc fixes for this project and a few other 61 | Rubyworks projects. 62 | 63 | Changes: 64 | 65 | * Adjust .yardopts file. 66 | * Documentation fixes. 67 | 68 | 69 | ## 1.4.0 | 2011-11-05 70 | 71 | New release adds a HexDump class for colorized byte string dumps 72 | and fixes some minor cell size issues with the Table class. 73 | This release also modernizes the build config and changes the 74 | license to BSD-2-Clause. 75 | 76 | Changes: 77 | 78 | * Add HexDump class. 79 | * Fix cell size of tables when ANSI codes are used. 80 | * Fix extra ansi codes in tables without format. 81 | * Modernize build configuration. 82 | * Switch to BSD-2-Clause license. 83 | 84 | 85 | ## 1.3.0 | 2011-06-30 86 | 87 | This release cleans up the Code module. It adds support for x-term 88 | 256 color codes. Also, the Diff class is now awesome, making use of 89 | an LCS algorithm. But the most important difference with this release 90 | is that the String core extensions are in their own file, core.rb. 91 | If you want to use them you will need to require `ansi` or `ansi/core`. 92 | 93 | Changes: 94 | 95 | * Clean-up Code module. 96 | * Utilize common chart for Code methods. 97 | * Constants now have their own module. 98 | * Move core methods to `ansi/core.rb`. 99 | * Add XTerm 256 color code support. 100 | * Improved Diff class with LCS algorithm. 101 | 102 | 103 | ## 1.2.5 | 2011-05-03 104 | 105 | This release introduces a preliminary rendition of a Diff class 106 | for getting colorized comparisons of strings and other objects. 107 | It's not officially supported yet, so this is only a point release. 108 | 109 | Changes: 110 | 111 | * Added Diff class for colorized comparisons. 112 | * Fixed minor issue with Columns format block; col comes before row. 113 | 114 | 115 | ## 1.2.4 | 2011-04-29 116 | 117 | This release improves to the ANSI::Columns class. In particular the 118 | layout is more consistent with intended functionality. 119 | 120 | Changes: 121 | 122 | * Improved ANSI::Columns to give more consistent output. 123 | * ANSI::Columns#to_s can override number of columns. 124 | * ANSI::Columns can take a String or Array list. 125 | 126 | 127 | ## 1.2.3 | 2011-04-08 128 | 129 | Minor release to add #clear method to ProgressBar and provide bug 130 | fix to BBCode.ansi_to_bbcode. Big thanks goes to Junegunn Choi 131 | for this fix. 132 | 133 | Changes: 134 | 135 | * Add ProgressBar#clear method. 136 | * Fixed ANSI::BBCode.ansi_to_bbcode and ansi_to_html from omitting lines 137 | without any ansi code (Junegunn Choi). 138 | 139 | ## 1.2.2 | 2010-06-12 140 | 141 | This release removes warnings about string arguments for certain 142 | ANSI::Code methods. While the string form is considered deprecated, 143 | for a few methods there is no use for any argument, so the string 144 | form can remain. In addition, String#unansi has been added to 145 | compliment String#ansi. Lastly, this release also adds the #display 146 | method to ANSI::Mixin. 147 | 148 | Changes: 149 | 150 | * Remove string argument warnings. 151 | * Add String#unansi and String#unansi! 152 | * Add ANSI::Mixin#display. 153 | 154 | 155 | ## 1.2.1 | 2010-05-10 156 | 157 | This release was simply a quick fix to remove the incorrect embedded 158 | version number, until it gets fixed. 159 | 160 | 161 | ## 1.2.0 | 2010-05-10 162 | 163 | This release entails numerous improvements. First and foremost 164 | the Code module is transitioning to a block interface only 165 | and phasing out the string argument interface. Admittedly this 166 | is mildly unconventional, but it allows the arguments to be used 167 | as options with common defaults more elegantly. 168 | 169 | Another important change is that ANSI::Code no longer provides 170 | String extension methods when included. For this use the new 171 | ANSI::Mixin. 172 | 173 | Other improvements include a String extension, #ansi, added to 174 | code.rb, which makes it even easier to apply ANSI codes to strings. 175 | Also, the ANSI::String class has been fixed (a few bugs crept 176 | it with the last release) and continues to improve. On top of all 177 | this testing has substantially improved thanks to QED. 178 | 179 | Changes: 180 | 181 | * Support string argument for now but with warning 182 | * Bug fixes for ANSI::String 183 | * Add mixin.rb for alternate mixin. 184 | * Many new tests and QED documents. 185 | 186 | 187 | ## 1.1.0 | 2009-10-04 188 | 189 | This release is the first toward making the ANSI library 190 | more widely usable. 191 | 192 | Changes: 193 | 194 | * Add bbcode.rb for conversion between BBCode/ANSI/HTML. 195 | * ProgressBar and Progressbar are the same. 196 | * Other minor underthehood improvements. 197 | 198 | 199 | ## 1.0.1 | 2009-08-15 200 | 201 | The release fixes a single bug that should allow Ruby 1.9 202 | to use the ANSI library. 203 | 204 | Changes: 205 | 206 | * Renamed PLATFORM to RUBY_PLATFORM 207 | 208 | 209 | ## 1.0.0 | 2009-08-15 210 | 211 | This is the initial stand-alone release of ANSI, a collection 212 | of ANSI based classes spun-off from Ruby Facets. 213 | 214 | Changes: 215 | 216 | * Happy Birthday! 217 | 218 | -------------------------------------------------------------------------------- /INDEX.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 3 | ansi 4 | 5 | version: 6 | 1.5.0 7 | 8 | title: 9 | ANSI 10 | 11 | summary: 12 | ANSI at your fingertips! 13 | 14 | description: 15 | The ANSI project is a superlative collection of ANSI escape code related 16 | libraries eabling ANSI colorization and stylization of console output. 17 | Byte for byte ANSI is the best ANSI code library available for the Ruby 18 | programming language. 19 | 20 | requirements: 21 | - mast (build) 22 | - indexer (build) 23 | - ergo (build) 24 | - qed (test) 25 | - ae (test) 26 | - lemon (test) 27 | 28 | resources: 29 | home: http://rubyworks.github.com/ansi 30 | docs: http://rubydoc.info/gems/ansi/frames 31 | code: http://github.com/rubyworks/ansi 32 | bugs: http://github.com/rubyworks/ansi/issues 33 | mail: http://groups.google.com/group/rubyworks-mailinglist 34 | 35 | repositories: 36 | upstream: git://github.com/rubyworks/ansi.git 37 | 38 | authors: 39 | - Thomas Sawyer 40 | - Florian Frank 41 | 42 | orgranizations: 43 | - Rubyworks 44 | 45 | copyrights: 46 | - 2009 Rubyworks (BSD-2-Clause) 47 | 48 | created: 49 | 2009-08-01 50 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD-2-Clause License (http://spdx.org/licenses/BSD-2-Clause) 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 16 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | 24 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | #!mast .index .yardopts bin lib man demo test *.md *.txt 2 | .index 3 | .yardopts 4 | lib/ansi/bbcode.rb 5 | lib/ansi/chain.rb 6 | lib/ansi/chart.rb 7 | lib/ansi/code.rb 8 | lib/ansi/columns.rb 9 | lib/ansi/constants.rb 10 | lib/ansi/core.rb 11 | lib/ansi/diff.rb 12 | lib/ansi/hexdump.rb 13 | lib/ansi/logger.rb 14 | lib/ansi/mixin.rb 15 | lib/ansi/progressbar.rb 16 | lib/ansi/string.rb 17 | lib/ansi/table.rb 18 | lib/ansi/terminal/curses.rb 19 | lib/ansi/terminal/stty.rb 20 | lib/ansi/terminal/termios.rb 21 | lib/ansi/terminal/win32.rb 22 | lib/ansi/terminal.rb 23 | lib/ansi/version.rb 24 | lib/ansi.rb 25 | lib/ansi.yml 26 | demo/01_ansicode.md 27 | demo/02_core.md 28 | demo/03_logger.md 29 | demo/04_progressbar.md 30 | demo/05_mixin.md 31 | demo/06_string.md 32 | demo/07_columns.md 33 | demo/08_table.md 34 | demo/09_diff.md 35 | demo/10_bbcode.md 36 | demo/11_terminal.md 37 | demo/applique/ae.rb 38 | demo/applique/output.rb 39 | test/case_ansicode.rb 40 | test/case_bbcode.rb 41 | test/case_mixin.rb 42 | test/case_progressbar.rb 43 | test/test_helper.rb 44 | NOTICE.md 45 | README.md 46 | HISTORY.md 47 | DEMO.md 48 | LICENSE.txt 49 | -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | # COPYRIGHT NOTICES 2 | 3 | ## ANSI 4 | 5 | Copyright © 2009 [Rubyworks](http://rubyworks.github.com) · 6 | License [BSD-2-Clause](http://spdx.org/licenses/BSD-2-Clause) · 7 | Website http://rubyworks.github.com/ansi 8 | 9 | Copyright 2009 Rubyworks. 10 | 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without modification, are 14 | permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this list of 17 | conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 20 | of conditions and the following disclaimer in the documentation and/or other materials 21 | provided with the distribution. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED 24 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 25 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 26 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | (https://raw.github.com/rubyworks/ansi/master/LICENSE.txt) 34 | 35 | 36 | ## ProgressBar 37 | 38 | Copyright © 2001 *Satoru Takabayashi* · 39 | License [Ruby](http://spdx.org/licenses/Ruby) · 40 | Website http://0xcc.net/ruby-progressbar 41 | 42 | ProgressBar class is based on the original ProgressBar by Satoru Takabayashi. 43 | 44 | Ruby/ProgressBar - a text progress bar library 45 | 46 | Copyright (C) 2001-2005 Satoru Takabayashi 47 | All rights reserved. 48 | This is free software with ABSOLUTELY NO WARRANTY. 49 | 50 | You can redistribute it and/or modify it under the terms 51 | of Ruby's license. 52 | 53 | 54 | ## HighLine (Terminal Extensions) 55 | 56 | Copyright © 2006 *Gray Productions* · 57 | License [Ruby](http://spdx.org/licenses/Ruby) · 58 | Website http://highline.rubyforge.org 59 | 60 | The terminal extensions are based on HighLine's SystemExtensions 61 | by James Edward Gray II. 62 | 63 | Copyright 2006 Gray Productions 64 | 65 | Distributed under the user's choice of the {GPL Version 2}[http://www.gnu.org/licenses/old-licenses/gpl-2.0.html] 66 | (see GPL-2.0.txt for details) or the {Ruby software license}[http://www.ruby-lang.org/en/LICENSE.txt] 67 | by James Edward Gray II and Greg Brown. 68 | 69 | Please email James[mailto:james@grayproductions.net] with any questions. 70 | 71 | (https://github.com/JEG2/highline/blob/master/LICENSE) 72 | 73 | 74 | ## BBCode 75 | 76 | Copyright © 2002 *Thomas-Ivo Heinen* · 77 | License [Ruby](http://spdx.org/licenses/Ruby) 78 | 79 | BBCode module is a derivative of BBCode by Thomas-Ivo Heinen. 80 | 81 | Copyright (c) 2002 Thomas-Ivo Heinen 82 | 83 | This module is free software. You may use, modify, and/or redistribute this 84 | software under the same terms as Ruby. 85 | 86 | This program is distributed in the hope that it will be useful, but WITHOUT 87 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 88 | FOR A PARTICULAR PURPOSE. 89 | 90 | 91 | ## Rainbow (XTerm Color Support) 92 | 93 | Copyright © *Marcin Kulik* · 94 | License [MIT](http://spdx.org/licenses/MIT) · 95 | Website http://github.com/sickill/rainbow 96 | 97 | Rainbox provided the bases for building the XTerm 256 color code 98 | support into the ANSI::Code module. 99 | 100 | Copyright (c) Marcin Kulik 101 | 102 | Permission is hereby granted, free of charge, to any person obtaining 103 | a copy of this software and associated documentation files (the 104 | "Software"), to deal in the Software without restriction, including 105 | without limitation the rights to use, copy, modify, merge, publish, 106 | distribute, sublicense, and/or sell copies of the Software, and to 107 | permit persons to whom the Software is furnished to do so, subject to 108 | the following conditions: 109 | 110 | The above copyright notice and this permission notice shall be 111 | included in all copies or substantial portions of the Software. 112 | 113 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 114 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 115 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 116 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 117 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 118 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 119 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 120 | 121 | (https://raw.github.com/sickill/rainbow/master/LICENSE) 122 | 123 | 124 | ## Paint (ANSI Code Names) 125 | 126 | Copyright © 2011 *Jan Lelis* · 127 | License [MIT](http://spdx.org/licenses/MIT) · 128 | Website https://github.com/janlelis/paint 129 | 130 | Some of the latest ANSI code names, and inspiration to check out Rainbow 131 | and include XTerm 256 color codes, came from Paint. 132 | 133 | Copyright (c) 2011 Jan Lelis 134 | 135 | Permission is hereby granted, free of charge, to any person obtaining 136 | a copy of this software and associated documentation files (the 137 | "Software"), to deal in the Software without restriction, including 138 | without limitation the rights to use, copy, modify, merge, publish, 139 | distribute, sublicense, and/or sell copies of the Software, and to 140 | permit persons to whom the Software is furnished to do so, subject to 141 | the following conditions: 142 | 143 | The above copyright notice and this permission notice shall be 144 | included in all copies or substantial portions of the Software. 145 | 146 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 147 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 148 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 149 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 150 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 151 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 152 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 153 | 154 | (https://raw.github.com/janlelis/paint/master/LICENSE.txt) 155 | 156 | 157 | ## ANSIColor 158 | 159 | _Acknowlegement_ 160 | 161 | Copyright © 2002 *Florian Frank* · 162 | Website http://flori.github.com/term-ansicolor 163 | 164 | Albeit the code no long bares much, if any, resemblance to it, the ANSI Code 165 | module (and subsequently the Constants module) originated with the 166 | ANSIColor library by Florian Frank. 167 | 168 | Copyright (c) 2002 Florian Frank 169 | 170 | 171 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ANSI 2 | 3 | [HOME](http://rubyworks.github.com/ansi) · 4 | [API](http://rubydoc.info/gems/ansi/frames) · 5 | [ISSUES](http://github.com/rubyworks/ansi/issues) · 6 | [SOURCE](http://github.com/rubyworks/ansi) 7 | 8 | [![Build Status](https://secure.travis-ci.org/rubyworks/ansi.png)](http://travis-ci.org/rubyworks/ansi) 9 | 10 |
11 | 12 | The ANSI project is a collection of ANSI escape code related libraries 13 | enabling ANSI code based colorization and stylization of output. 14 | It is very nice for beautifying shell output. 15 | 16 | This collection is based on a set of scripts spun-off from 17 | Ruby Facets. Included are Code (used to be ANSICode), Logger, 18 | ProgressBar and String. In addition the library includes 19 | Terminal which provides information about the current output 20 | device. 21 | 22 | 23 | ## Features 24 | 25 | * ANSI::Code provides ANSI codes as module functions. 26 | * String#ansi makes common usage very easy and elegant. 27 | * ANSI::Mixin provides an alternative mixin (like +colored+ gem). 28 | * Very Good coverage of standard ANSI codes. 29 | * Additional clases for colorized columns, tables, loggers and more. 30 | 31 | 32 | ## Synopsis 33 | 34 | There are a number of modules and classes provided by the ANSI 35 | package. To get a good understanding of them it is best to pursue 36 | the [QED documents](http://github.com/rubyworks/ansi/tree/master/qed/) 37 | or the [API documentation](http://rubyworks.github.com/ansi/api/index.html). 38 | 39 | At the heart of all the provided libraries lies the ANSI::Code module 40 | which defines ANSI codes as constants and methods. For example: 41 | 42 | require 'ansi/code' 43 | 44 | ANSI.red + "Hello" + ANSI.blue + "World" 45 | => "\e[31mHello\e[34mWorld" 46 | 47 | Or in block form. 48 | 49 | ANSI.red{ "Hello" } + ANSI.blue{ "World" } 50 | => "\e[31mHello\e[0m\e[34mWorld\e[0m" 51 | 52 | The methods defined by this module are used throughout the rest of 53 | the system. 54 | 55 | 56 | ## Installation 57 | 58 | ### Bundler 59 | 60 | Add the usual `gem` line to your project's `Gemfile`. 61 | 62 | gem 'ansi' 63 | 64 | And run then `bundle` command. 65 | 66 | ### RubyGems 67 | 68 | To install with RubyGems simply open a console and type: 69 | 70 | $ sudo gem install ansi 71 | 72 | ### Setup.rb (not recommended) 73 | 74 | Local installation requires Setup.rb (gem install setup), 75 | then [download](http://github.com/rubyworks/ansi/download) the tarball package and type: 76 | 77 | $ tar -xvzf ansi-1.0.0.tgz 78 | $ cd ansi-1.0.0 79 | $ sudo setup.rb all 80 | 81 | Windows users use 'ruby setup.rb all'. 82 | 83 | 84 | ## Release Notes 85 | 86 | Please see HISTORY.md file. 87 | 88 | 89 | ## License & Copyrights 90 | 91 | Copyright (c) 2009 Rubyworks 92 | 93 | This program is redistributable under the terms of the *FreeBSD* license. 94 | 95 | Some pieces of the code are copyrighted by others. 96 | 97 | See LICENSE.txt and NOTICE.md files for details. 98 | 99 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #/usr/bin/env ruby 2 | 3 | task :default => [:demo] 4 | 5 | desc "run demos" 6 | task :demo do 7 | sh "bundle exec qed" 8 | end 9 | 10 | desc "run unit tests" 11 | task :test do 12 | sh "bundle exec rubytest" 13 | end 14 | 15 | -------------------------------------------------------------------------------- /ansi.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'yaml' 4 | require 'pathname' 5 | 6 | module Indexer 7 | 8 | # Convert index data into a gemspec. 9 | # 10 | # Notes: 11 | # * Assumes all executables are in bin/. 12 | # * Does not yet handle default_executable setting. 13 | # * Does not yet handle platform setting. 14 | # * Does not yet handle required_ruby_version. 15 | # * Support for rdoc entries is weak. 16 | # 17 | class GemspecExporter 18 | 19 | # File globs to include in package --unless a manifest file exists. 20 | FILES = ".index .yardopts alt bin data demo ext features lib man spec test try* [A-Z]*.*" unless defined?(FILES) 21 | 22 | # File globs to omit from FILES. 23 | OMIT = "Config.rb" unless defined?(OMIT) 24 | 25 | # Standard file patterns. 26 | PATTERNS = { 27 | :root => '{.index,Gemfile}', 28 | :bin => 'bin/*', 29 | :lib => 'lib/{**/}*', #.rb', 30 | :ext => 'ext/{**/}extconf.rb', 31 | :doc => '*.{txt,rdoc,md,markdown,tt,textile}', 32 | :test => '{test,spec}/{**/}*.rb' 33 | } unless defined?(PATTERNS) 34 | 35 | # For which revision of indexer spec is this converter intended? 36 | REVISION = 2013 unless defined?(REVISION) 37 | 38 | # 39 | def self.gemspec 40 | new.to_gemspec 41 | end 42 | 43 | # 44 | attr :metadata 45 | 46 | # 47 | def initialize(metadata=nil) 48 | @root_check = false 49 | 50 | if metadata 51 | root_dir = metadata.delete(:root) 52 | if root_dir 53 | @root = root_dir 54 | @root_check = true 55 | end 56 | metadata = nil if metadata.empty? 57 | end 58 | 59 | @metadata = metadata || YAML.load_file(root + '.index') 60 | 61 | if @metadata['revision'].to_i != REVISION 62 | warn "This gemspec exporter was not designed for this revision of index metadata." 63 | end 64 | end 65 | 66 | # 67 | def has_root? 68 | root ? true : false 69 | end 70 | 71 | # 72 | def root 73 | return @root if @root || @root_check 74 | @root_check = true 75 | @root = find_root 76 | end 77 | 78 | # 79 | def manifest 80 | return nil unless root 81 | @manifest ||= Dir.glob(root + 'manifest{,.txt}', File::FNM_CASEFOLD).first 82 | end 83 | 84 | # 85 | def scm 86 | return nil unless root 87 | @scm ||= %w{git hg}.find{ |m| (root + ".#{m}").directory? }.to_sym 88 | end 89 | 90 | # 91 | def files 92 | return [] unless root 93 | @files ||= \ 94 | if manifest 95 | File.readlines(manifest). 96 | map{ |line| line.strip }. 97 | reject{ |line| line.empty? || line[0,1] == '#' } 98 | else 99 | list = [] 100 | Dir.chdir(root) do 101 | FILES.split(/\s+/).each do |pattern| 102 | list.concat(glob(pattern)) 103 | end 104 | OMIT.split(/\s+/).each do |pattern| 105 | list = list - glob(pattern) 106 | end 107 | end 108 | list 109 | end.select{ |path| File.file?(path) }.uniq 110 | end 111 | 112 | # 113 | def glob_files(pattern) 114 | return [] unless root 115 | Dir.chdir(root) do 116 | Dir.glob(pattern).select do |path| 117 | File.file?(path) && files.include?(path) 118 | end 119 | end 120 | end 121 | 122 | def patterns 123 | PATTERNS 124 | end 125 | 126 | def executables 127 | @executables ||= \ 128 | glob_files(patterns[:bin]).map do |path| 129 | File.basename(path) 130 | end 131 | end 132 | 133 | def extensions 134 | @extensions ||= \ 135 | glob_files(patterns[:ext]).map do |path| 136 | File.basename(path) 137 | end 138 | end 139 | 140 | def name 141 | metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_') 142 | end 143 | 144 | def homepage 145 | page = ( 146 | metadata['resources'].find{ |r| r['type'] =~ /^home/i } || 147 | metadata['resources'].find{ |r| r['name'] =~ /^home/i } || 148 | metadata['resources'].find{ |r| r['name'] =~ /^web/i } 149 | ) 150 | page ? page['uri'] : false 151 | end 152 | 153 | def licenses 154 | metadata['copyrights'].map{ |c| c['license'] }.compact 155 | end 156 | 157 | def require_paths 158 | paths = metadata['paths'] || {} 159 | paths['load'] || ['lib'] 160 | end 161 | 162 | # 163 | # Convert to gemnspec. 164 | # 165 | def to_gemspec 166 | if has_root? 167 | Gem::Specification.new do |gemspec| 168 | to_gemspec_data(gemspec) 169 | to_gemspec_paths(gemspec) 170 | end 171 | else 172 | Gem::Specification.new do |gemspec| 173 | to_gemspec_data(gemspec) 174 | to_gemspec_paths(gemspec) 175 | end 176 | end 177 | end 178 | 179 | # 180 | # Convert pure data settings. 181 | # 182 | def to_gemspec_data(gemspec) 183 | gemspec.name = name 184 | gemspec.version = metadata['version'] 185 | gemspec.summary = metadata['summary'] 186 | gemspec.description = metadata['description'] 187 | 188 | metadata['authors'].each do |author| 189 | gemspec.authors << author['name'] 190 | 191 | if author.has_key?('email') 192 | if gemspec.email 193 | gemspec.email << author['email'] 194 | else 195 | gemspec.email = [author['email']] 196 | end 197 | end 198 | end 199 | 200 | gemspec.licenses = licenses 201 | 202 | requirements = metadata['requirements'] || [] 203 | requirements.each do |req| 204 | next if req['optional'] 205 | next if req['external'] 206 | 207 | name = req['name'] 208 | groups = req['groups'] || [] 209 | 210 | version = gemify_version(req['version']) 211 | 212 | if groups.empty? or groups.include?('runtime') 213 | # populate runtime dependencies 214 | if gemspec.respond_to?(:add_runtime_dependency) 215 | gemspec.add_runtime_dependency(name,*version) 216 | else 217 | gemspec.add_dependency(name,*version) 218 | end 219 | else 220 | # populate development dependencies 221 | if gemspec.respond_to?(:add_development_dependency) 222 | gemspec.add_development_dependency(name,*version) 223 | else 224 | gemspec.add_dependency(name,*version) 225 | end 226 | end 227 | end 228 | 229 | # convert external dependencies into gemspec requirements 230 | requirements.each do |req| 231 | next unless req['external'] 232 | gemspec.requirements << ("%s-%s" % req.values_at('name', 'version')) 233 | end 234 | 235 | gemspec.homepage = homepage 236 | gemspec.require_paths = require_paths 237 | gemspec.post_install_message = metadata['install_message'] 238 | end 239 | 240 | # 241 | # Set gemspec settings that require a root directory path. 242 | # 243 | def to_gemspec_paths(gemspec) 244 | gemspec.files = files 245 | gemspec.extensions = extensions 246 | gemspec.executables = executables 247 | 248 | if Gem::VERSION < '1.7.' 249 | gemspec.default_executable = gemspec.executables.first 250 | end 251 | 252 | gemspec.test_files = glob_files(patterns[:test]) 253 | 254 | unless gemspec.files.include?('.document') 255 | gemspec.extra_rdoc_files = glob_files(patterns[:doc]) 256 | end 257 | end 258 | 259 | # 260 | # Return a copy of this file. This is used to generate a local 261 | # .gemspec file that can automatically read the index file. 262 | # 263 | def self.source_code 264 | File.read(__FILE__) 265 | end 266 | 267 | private 268 | 269 | def find_root 270 | root_files = patterns[:root] 271 | if Dir.glob(root_files).first 272 | Pathname.new(Dir.pwd) 273 | elsif Dir.glob("../#{root_files}").first 274 | Pathname.new(Dir.pwd).parent 275 | else 276 | #raise "Can't find root of project containing `#{root_files}'." 277 | warn "Can't find root of project containing `#{root_files}'." 278 | nil 279 | end 280 | end 281 | 282 | def glob(pattern) 283 | if File.directory?(pattern) 284 | Dir.glob(File.join(pattern, '**', '*')) 285 | else 286 | Dir.glob(pattern) 287 | end 288 | end 289 | 290 | def gemify_version(version) 291 | case version 292 | when /^(.*?)\+$/ 293 | ">= #{$1}" 294 | when /^(.*?)\-$/ 295 | "< #{$1}" 296 | when /^(.*?)\~$/ 297 | "~> #{$1}" 298 | else 299 | version 300 | end 301 | end 302 | 303 | end 304 | 305 | end 306 | 307 | Indexer::GemspecExporter.gemspec -------------------------------------------------------------------------------- /demo/01_ansicode.md: -------------------------------------------------------------------------------- 1 | # ANSI::Code 2 | 3 | Require the library. 4 | 5 | require 'ansi/code' 6 | 7 | ANSI::Code can be used as a functions module. 8 | 9 | str = ANSI::Code.red + "Hello" + ANSI::Code.blue + "World" 10 | str.assert == "\e[31mHello\e[34mWorld" 11 | 12 | If a block is supplied to each method then yielded value will 13 | be wrapped in the ANSI code and clear code. 14 | 15 | str = ANSI::Code.red{ "Hello" } + ANSI::Code.blue{ "World" } 16 | str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m" 17 | 18 | More conveniently the ANSI::Code module extends ANSI itself. 19 | 20 | str = ANSI.red + "Hello" + ANSI.blue + "World" 21 | str.assert == "\e[31mHello\e[34mWorld" 22 | 23 | str = ANSI.red{ "Hello" } + ANSI.blue{ "World" } 24 | str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m" 25 | 26 | ANSI also supports XTerm 256 color mode using red, blue and green values 27 | with the `#rgb` method. 28 | 29 | str = ANSI::Code.rgb(0, 255, 0) 30 | str.assert == "\e[38;5;46m" 31 | 32 | Or using CSS style hex codes as well. 33 | 34 | str = ANSI::Code.rgb("#00FF00") 35 | str.assert == "\e[38;5;46m" 36 | 37 | Both of these methods can take blocks to wrap text in the color and clear codes. 38 | 39 | str = ANSI::Code.rgb("#00FF00"){ "Hello" } 40 | str.assert == "\e[38;5;46mHello\e[0m" 41 | 42 | In the appropriate context the ANSI::Code module can also be 43 | included, making its methods directly accessible. 44 | 45 | include ANSI::Code 46 | 47 | str = red + "Hello" + blue + "World" 48 | str.assert == "\e[31mHello\e[34mWorld" 49 | 50 | str = red{ "Hello" } + blue{ "World" } 51 | str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m" 52 | 53 | Along with the single font colors, the library include background colors. 54 | 55 | str = on_red + "Hello" 56 | str.assert == "\e[41mHello" 57 | 58 | As well as combined color methods. 59 | 60 | str = white_on_red + "Hello" 61 | str.assert == "\e[37m\e[41mHello" 62 | 63 | The ANSI::Code module supports most standard ANSI codes, though 64 | not all platforms support every code, so YMMV. 65 | 66 | -------------------------------------------------------------------------------- /demo/02_core.md: -------------------------------------------------------------------------------- 1 | # String Extensions 2 | 3 | In addition the library offers an extension to String class 4 | called #ansi, which allows some of the ANSI::Code methods 5 | to be called in a more object-oriented fashion. 6 | 7 | require 'ansi/core' 8 | 9 | str = "Hello".ansi(:red) + "World".ansi(:blue) 10 | str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m" 11 | 12 | -------------------------------------------------------------------------------- /demo/03_logger.md: -------------------------------------------------------------------------------- 1 | # ANSI::Logger 2 | 3 | Require the ANSI::Logger library. 4 | 5 | require 'ansi/logger' 6 | 7 | Create a new ANSI::Logger 8 | 9 | log = ANSI::Logger.new(STDOUT) 10 | 11 | Info logging appears normal. 12 | 13 | log.info{"Info logs are green.\n"} 14 | 15 | Warn logging appears yellow. 16 | 17 | log.warn{"Warn logs are yellow.\n"} 18 | 19 | Debug logging appears cyan. 20 | 21 | log.debug{"Debug logs are cyan.\n"} 22 | 23 | Error logging appears red. 24 | 25 | log.error{"Error logs are red.\n"} 26 | 27 | Fatal logging appears bright red. 28 | 29 | log.fatal{"Fatal logs are bold red!\n"} 30 | 31 | -------------------------------------------------------------------------------- /demo/04_progressbar.md: -------------------------------------------------------------------------------- 1 | # ANSI::Progressbar 2 | 3 | Pretty progress bars are easy to construct. 4 | 5 | require 'ansi/progressbar' 6 | 7 | pbar = ANSI::Progressbar.new("Test Bar", 100) 8 | 9 | Running the bar simply requires calling the #inc method during 10 | a loop and calling `#finish` when done. 11 | 12 | 100.times do |i| 13 | sleep 0.01 14 | pbar.inc 15 | end 16 | pbar.finish 17 | 18 | We will use this same rountine in all the examples below, so lets 19 | make a quick macro for it. Notice we have to use `#reset` first 20 | before reusing the same progress bar. 21 | 22 | def run(pbar) 23 | pbar.reset 24 | 100.times do |i| 25 | sleep 0.01 26 | pbar.inc 27 | end 28 | pbar.finish 29 | puts 30 | end 31 | 32 | The progress bar can be stylized in almost any way. 33 | The `#format` setter provides control over the parts 34 | that appear on the line. For example, by default the 35 | format is: 36 | 37 | pbar.format("%-14s %3d%% %s %s", :title, :percentage, :bar, :stat) 38 | 39 | So lets vary it up to demonstrate the case. 40 | 41 | pbar.format("%-14s %3d%% %s %s", :title, :percentage, :stat, :bar) 42 | run(pbar) 43 | 44 | The progress bar has an extra build in format intended for use with 45 | file downloads called `#transer_mode`. 46 | 47 | pbar.transfer_mode 48 | run(pbar) 49 | 50 | Calling this methods is the same as calling: 51 | 52 | pbar.format("%-14s %3d%% %s %s",:title, :percentage, :bar, :stat_for_file_transfer) 53 | run(pbar) 54 | 55 | The `#style` setter allows each part of the line be modified with ANSI codes. 56 | And the `#bar_mark` writer can be used to change the character used to make the bar. 57 | 58 | pbar.standard_mode 59 | pbar.style(:title => [:red], :bar=>[:blue]) 60 | pbar.bar_mark = "=" 61 | run(pbar) 62 | 63 | -------------------------------------------------------------------------------- /demo/05_mixin.md: -------------------------------------------------------------------------------- 1 | # ANSI::Mixin 2 | 3 | The ANSI::Mixin module is design for including into 4 | String-like classes. It will support any class that defines 5 | a #to_s method. 6 | 7 | require 'ansi/mixin' 8 | 9 | In this demonstration we will simply include it in the 10 | core String class. 11 | 12 | class ::String 13 | include ANSI::Mixin 14 | end 15 | 16 | Now all strings will have access to ANSI's style and color 17 | codes via simple method calls. 18 | 19 | "roses".red.assert == "\e[31mroses\e[0m" 20 | 21 | "violets".blue.assert == "\e[34mviolets\e[0m" 22 | 23 | "sugar".italic.assert == "\e[3msugar\e[0m" 24 | 25 | The method can be combined, of course. 26 | 27 | "you".italic.bold.assert == "\e[1m\e[3myou\e[0m\e[0m" 28 | 29 | The mixin also supports background methods. 30 | 31 | "envy".on_green.assert == "\e[42menvy\e[0m" 32 | 33 | And it also supports the combined foreground-on-background 34 | methods. 35 | 36 | "b&w".white_on_black.assert == "\e[37m\e[40mb&w\e[0m" 37 | 38 | -------------------------------------------------------------------------------- /demo/06_string.md: -------------------------------------------------------------------------------- 1 | # ANSI::String 2 | 3 | The ANSI::String class is a very sophisticated implementation 4 | of Ruby's standard String class, but one that can handle 5 | ANSI codes seamlessly. 6 | 7 | require 'ansi/string' 8 | 9 | flower1 = ANSI::String.new("Roses") 10 | flower2 = ANSI::String.new("Violets") 11 | 12 | Like any other string. 13 | 14 | flower1.to_s.assert == "Roses" 15 | flower2.to_s.assert == "Violets" 16 | 17 | Bet now we can add color. 18 | 19 | flower1.red! 20 | flower2.blue! 21 | 22 | flower1.to_s.assert == "\e[31mRoses\e[0m" 23 | flower2.to_s.assert == "\e[34mViolets\e[0m" 24 | 25 | Despite that the string representation now contains ANSI codes, 26 | we can still manipulate the string in much the same way that 27 | we manipulate an ordinary string. 28 | 29 | flower1.size.assert == 5 30 | flower2.size.assert == 7 31 | 32 | Like ordinary strings we can concatenate the two strings 33 | 34 | flowers = flower1 + ' ' + flower2 35 | flowers.to_s.assert == "\e[31mRoses\e[0m \e[34mViolets\e[0m" 36 | 37 | flowers.size.assert == 13 38 | 39 | Standard case conversion such as #upcase and #downcase work. 40 | 41 | flower1.upcase.to_s.assert == "\e[31mROSES\e[0m" 42 | flower1.downcase.to_s.assert == "\e[31mroses\e[0m" 43 | 44 | Some of the most difficult methods to re-implement were the 45 | substitution methods such as #sub and #gsub. They are still 46 | somewhat more limited than the original string methods, but 47 | their primary functionality should work. 48 | 49 | flower1.gsub('s', 'z').to_s.assert == "\e[31mRozez\e[0m" 50 | 51 | There are still a number of methods that need implementation. 52 | ANSI::String is currently a very partial implementation. But 53 | as you can see from the methods it does currently support, 54 | is it already useful. 55 | 56 | 57 | -------------------------------------------------------------------------------- /demo/07_columns.md: -------------------------------------------------------------------------------- 1 | # ANSI::Columns 2 | 3 | The +Columns+ class makes it easy to create nice looking text columns, 4 | sorted from top to bottom, right to left (as opposed to the other way 5 | around). 6 | 7 | require 'ansi/columns' 8 | 9 | list = %w{a b c d e f g h i j k l} 10 | 11 | columns = ANSI::Columns.new(list) 12 | 13 | columns.to_s(4) 14 | 15 | The output will be: 16 | 17 | a d g j 18 | b e h k 19 | c f i l 20 | 21 | Besides an array of elements, Columns.new can take a string in which 22 | the elements are divided by newlines characters. The default column 23 | size can also be given to the initializer. 24 | 25 | list = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl" 26 | 27 | columns = ANSI::Columns.new(list, :columns=>6) 28 | 29 | columns.to_s 30 | 31 | The output will be: 32 | 33 | a c e g i k 34 | b d f h j l 35 | 36 | If the column count is +nil+, then the number of columns will be calculated 37 | as a best fit for the current terminal window. 38 | 39 | ## Padding 40 | 41 | Columns can adjust the padding between cells. 42 | 43 | list = %w{a b c d e f g h i j k l} 44 | 45 | columns = ANSI::Columns.new(list, :padding=>2) 46 | 47 | columns.to_s(4) 48 | 49 | The output will be: 50 | 51 | a d g j 52 | b e h k 53 | c f i l 54 | 55 | ## Alignment 56 | 57 | Columns can also be aligned either left or right. 58 | 59 | list = %w{xx xx xx yy y yy z zz z} 60 | 61 | columns = ANSI::Columns.new(list, :align=>:right) 62 | 63 | columns.to_s(3) 64 | 65 | The output will be: 66 | 67 | xx yy z 68 | xx y zz 69 | xx yy z 70 | 71 | ## Format 72 | 73 | Lastly, columns can be augmented with ANSI codes. This is done through 74 | a formatting block. The block can take up to three parameters, the cell 75 | content, the column and row numbers, or the cell and the column and row 76 | numbers. 77 | 78 | list = %w{a b c d e f g h i j k l} 79 | 80 | columns = ANSI::Columns.new(list){ |c,r| r % 2 == 0 ? :red : :blue } 81 | 82 | out = columns.to_s(4) 83 | 84 | out.assert == ( 85 | "\e[31ma \e[0m\e[31md \e[0m\e[31mg \e[0m\e[31mj \e[0m\n" + 86 | "\e[34mb \e[0m\e[34me \e[0m\e[34mh \e[0m\e[34mk \e[0m\n" + 87 | "\e[31mc \e[0m\e[31mf \e[0m\e[31mi \e[0m\e[31ml \e[0m\n" 88 | ) 89 | 90 | -------------------------------------------------------------------------------- /demo/08_table.md: -------------------------------------------------------------------------------- 1 | # ANSI::Table 2 | 3 | The ANSI::Table class can be used to output tabular data with nicely 4 | formated ASCII cell borders. 5 | 6 | require 'ansi/table' 7 | 8 | The constructor takes an 2-dimensional array. 9 | 10 | data = [ 11 | [ 10, 20, 30 ], 12 | [ 20, 10, 20 ], 13 | [ 50, 40, 20 ] 14 | ] 15 | 16 | table = ANSI::Table.new(data) 17 | 18 | table.to_s 19 | 20 | The output will be: 21 | 22 | +----+----+----+ 23 | | 10 | 20 | 30 | 24 | | 20 | 10 | 20 | 25 | | 50 | 40 | 20 | 26 | +----+----+----+ 27 | 28 | 29 | -------------------------------------------------------------------------------- /demo/09_diff.md: -------------------------------------------------------------------------------- 1 | # ANSI::Diff 2 | 3 | require 'ansi/diff' 4 | 5 | a = 'abcYefg' 6 | b = 'abcXefg' 7 | 8 | diff = ANSI::Diff.new(a,b) 9 | 10 | diff.to_s.assert == "\e[31mabc\e[0m\e[33mYefg\e[0m\n\e[31mabc\e[0mXefg" 11 | 12 | Try another. 13 | 14 | a = 'abc' 15 | b = 'abcdef' 16 | 17 | diff = ANSI::Diff.new(a,b) 18 | 19 | diff.to_s.assert == "\e[31mabc\e[0m\n\e[31mabc\e[0mdef" 20 | 21 | And another. 22 | 23 | a = 'abcXXXghi' 24 | b = 'abcdefghi' 25 | 26 | diff = ANSI::Diff.new(a,b) 27 | 28 | diff.to_s.assert == "\e[31mabc\e[0m\e[33mXXXghi\e[0m\n\e[31mabc\e[0mdefghi" 29 | 30 | And another. 31 | 32 | a = 'abcXXXdefghi' 33 | b = 'abcdefghi' 34 | 35 | diff = ANSI::Diff.new(a,b) 36 | 37 | diff.to_s.assert == "\e[31mabc\e[0m\e[33mXXX\e[0m\e[35mdefghi\e[0m\n\e[31mabc\e[0m\e[35mdefghi\e[0m" 38 | 39 | Comparison that is mostly different. 40 | 41 | a = 'abcpppz123' 42 | b = 'abcxyzzz43' 43 | 44 | diff = ANSI::Diff.new(a,b) 45 | 46 | diff.to_s.assert == "\e[31mabc\e[0m\e[33mpppz123\e[0m\n\e[31mabc\e[0mxyzzz43" 47 | 48 | -------------------------------------------------------------------------------- /demo/10_bbcode.md: -------------------------------------------------------------------------------- 1 | # ANSI::BBCode 2 | 3 | The BBCode module provides methods for converting between 4 | BBCodes, basic HTML and ANSI codes. 5 | 6 | require 'ansi/bbcode' 7 | 8 | BBCodes are color and style codes in square brackets, quite 9 | popular with on line forums. 10 | 11 | bbcode = "this is [COLOR=red]red[/COLOR], this is [B]bold[/B]" 12 | 13 | We can convert this to ANSI code simply enough: 14 | 15 | ansi = ANSI::BBCode.bbcode_to_ansi(bbcode) 16 | 17 | ansi.assert == "this is \e[0;31mred\e[0m, this is \e[1mbold\e[0m\n" 18 | 19 | In addition the BBCode module supports conversion to simple HTML. 20 | 21 | html = ANSI::BBCode.bbcode_to_html(bbcode) 22 | 23 | html.assert == "this is red, this is bold
\n" 24 | 25 | -------------------------------------------------------------------------------- /demo/11_terminal.md: -------------------------------------------------------------------------------- 1 | # ANSI::Terminal 2 | 3 | We should be ables to get the terminal width via the `terminal_width` method. 4 | 5 | width = ANSI::Terminal.terminal_width 6 | 7 | Fixnum.assert === width 8 | 9 | -------------------------------------------------------------------------------- /demo/applique/ae.rb: -------------------------------------------------------------------------------- 1 | require 'ae' 2 | -------------------------------------------------------------------------------- /demo/applique/output.rb: -------------------------------------------------------------------------------- 1 | When "output will be" do |text| 2 | # how to get result of last block? 3 | @_.strip.assert == text.strip 4 | end 5 | 6 | -------------------------------------------------------------------------------- /etc/qed.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | QED.configure 'cov' do 4 | require 'simplecov' 5 | SimpleCov.command_name 'qed' 6 | SimpleCov.start do 7 | add_filter '/demo/' 8 | coverage_dir 'log/coverage' 9 | #add_group "Label", "lib/qed/directory" 10 | end 11 | end 12 | 13 | -------------------------------------------------------------------------------- /lib/ansi.rb: -------------------------------------------------------------------------------- 1 | # ANSI namespace module contains all the ANSI related classes. 2 | module ANSI 3 | end 4 | 5 | require 'ansi/version' 6 | require 'ansi/core' 7 | require 'ansi/code' 8 | require 'ansi/bbcode' 9 | require 'ansi/columns' 10 | require 'ansi/diff' 11 | require 'ansi/logger' 12 | require 'ansi/mixin' 13 | require 'ansi/progressbar' 14 | require 'ansi/string' 15 | require 'ansi/table' 16 | require 'ansi/terminal' 17 | 18 | # Kernel method 19 | def ansi(string, *codes) 20 | ANSI::Code.ansi(string, *codes) 21 | end 22 | 23 | -------------------------------------------------------------------------------- /lib/ansi.yml: -------------------------------------------------------------------------------- 1 | ../.index -------------------------------------------------------------------------------- /lib/ansi/bbcode.rb: -------------------------------------------------------------------------------- 1 | # BBCode 2 | # 3 | # Copyright (c) 2002 Thomas-Ivo Heinen 4 | # 5 | # This module is free software. You may use, modify, and/or redistribute this 6 | # software under the same terms as Ruby. 7 | # 8 | # This program is distributed in the hope that it will be useful, but WITHOUT 9 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | # FOR A PARTICULAR PURPOSE. 11 | 12 | # 13 | module ANSI 14 | 15 | # TODO: Integrate BBCode with Code module. 16 | 17 | # The BBCode module helps ease the separation of core and frontend with the 18 | # core (or submodules) being still able to say, what colors shall be used 19 | # in it's responses. This is achieved by encoding formatting information 20 | # using the BBCode tokens. This enables you to "pipe" layout information 21 | # such as colors, style, font, size and alignment through the core to 22 | # the frontend. 23 | # 24 | # Additionally it converts markups/codes between ANSI, HTML and BBCode 25 | # almost freely ;) 26 | # 27 | # # Converting a bbcode string to ANSI and XHTML 28 | # str = "this is [COLOR=red]red[/COLOR], this is [B]bold[/B]" 29 | # print( BBCode.bbcode_to_ansi(str) ) 30 | # print( BBCode.bbcode_to_html(str) ) 31 | # 32 | module BBCode 33 | 34 | ## ANSIname => ANSIcode LUT 35 | ANSINAME2CODE= { "reset" => "\e[0m", "bold" => "\e[1m", 36 | "underline" => "\e[4m", "blink" => "\e[5m", 37 | "reverse" => "\e[7m", "invisible" => "\e[8m", 38 | "black" => "\e[0;30m", "darkgrey" => "\e[1;30m", 39 | "red" => "\e[0;31m", "lightred" => "\e[1;31m", 40 | "green" => "\e[0;32m", "lightgreen" => "\e[1;32m", 41 | "brown" => "\e[0;33m", "yellow" => "\e[1;33m", 42 | "blue" => "\e[0;34m", "lightblue" => "\e[1;34m", 43 | "purple" => "\e[0;35m", "magenta" => "\e[1;35m", 44 | "cyan" => "\e[1;36m", "lightcyan" => "\e[1;36m", 45 | "grey" => "\e[0;37m", "white" => "\e[1;37m", 46 | "bgblack" => "\e[40m", "bgred" => "\e[41m", 47 | "bggreen" => "\e[42m", "bgyellow" => "\e[43m", 48 | "bgblue" => "\e[44m", "bgmagenta" => "\e[45m", 49 | "bgcyan" => "\e[46m", "bgwhite" => "\e[47m" 50 | } 51 | 52 | ## BBColor => ANSIname LUT 53 | BBCOLOR2ANSI = { "skyblue" => "blue", "royalblue" => "blue", 54 | "blue" => "blue", "darkblue" => "blue", 55 | "orange" => "red", "orangered" => "red", 56 | "crimson" => "red", "red" => "lightred", 57 | "firebrick" => "red", "darkred" => "red", 58 | "green" => "green", "limegreen" => "green", 59 | "seagreen" => "green", "darkgreen" => "green", 60 | "deeppink" => "magenta", "tomato" => "red", 61 | "coral" => "cyan", "purple" => "purple", 62 | "indigo" => "blue", "burlywood" => "red", 63 | "sandybrown"=> "red", "sierra" => "sierra", 64 | "chocolate" => "brown", "teal" => "teal", 65 | "silver" => "white", 66 | "black" => "black", "yellow" => "yellow", 67 | "magenta" => "magenta", "cyan" => "cyan", 68 | "white" => "white" 69 | } 70 | 71 | ## ANSInames => BBCode LUT 72 | ANSINAME2BBCODE = { "bold" => "B", "underline" => "U", "reverse" => "I", 73 | 74 | "red" => "COLOR=red", "blue" => "COLOR=blue", 75 | "green" => "COLOR=green", "cyan" => "COLOR=cyan", 76 | "magenta"=> "COLOR=deeppink", "purple" => "COLOR=purple", 77 | "black" => "COLOR=black", "white" => "COLOR=white", 78 | "yellow" => "COLOR=yellow", "brown" => "COLOR=chocolate" 79 | } 80 | 81 | ## Needed for alignments 82 | @@width = 80 83 | 84 | 85 | # --------------------------- 86 | 87 | # Returns the ANSI sequence for given color, if existant 88 | def BBCode.ansi(colorname) 89 | colorname.strip! 90 | return ANSINAME2CODE[ colorname.downcase ] 91 | end 92 | 93 | # --- strip_bbcode( string ) 94 | # Will strip any BBCode tags from the given string. 95 | def BBCode.strip_bbcode(string) 96 | string.strip! 97 | return string.gsub(/\[[A-Za-z0-9\/=]+\]/, "") 98 | end 99 | 100 | # Returns the string with all ansi escape sequences converted to BBCodes 101 | def BBCode.ansi_to_bbcode(string) 102 | return "" if string.nil? || string.to_s.strip.empty? 103 | result = "" 104 | tagstack = [] 105 | 106 | ## Iterate over input lines 107 | string.split("\n").each do |line| 108 | ## Iterate over found ansi sequences 109 | line.scan(/\e\[[0-9;]+m/).each do |seq| 110 | ansiname = ANSINAME2CODE.invert["#{seq}"] 111 | 112 | ## Pop last tag and form closing tag 113 | if ansiname == "reset" 114 | lasttag = tagstack.pop 115 | bbname = "/" + String.new( lasttag.split("=")[0] ) 116 | 117 | ## Get corresponding BBCode tag + Push to stack 118 | else 119 | bbname = ANSINAME2BBCODE[ansiname] 120 | tagstack.push(bbname) 121 | end 122 | 123 | ## Replace ansi sequence by BBCode tag 124 | replace = sprintf("[%s]", bbname) 125 | line.sub!(seq, replace) 126 | end 127 | 128 | ## Append converted line 129 | result << sprintf("%s\n", line) 130 | end 131 | 132 | 133 | ## Some tags are unclosed 134 | while !tagstack.empty? 135 | result << sprintf("[/%s]", String.new(tagstack.pop.split("=")[0]) ) 136 | end 137 | 138 | return result 139 | end 140 | 141 | # Converts a BBCode string to one with ANSI sequences. 142 | # Returns the string with all formatting instructions in BBCodes converted 143 | # to ANSI code sequences / aligned with spaces to specified width. 144 | def BBCode.bbcode_to_ansi(string, usecolors = true) 145 | return "" if string.nil? || string.to_s.strip.empty? 146 | result = "" 147 | 148 | return BBCode.strip_bbcode(string) if !usecolors 149 | 150 | ## Iterate over lines 151 | string.split("\n").each do |line| 152 | 153 | ## TODO: stacking? other styles! 154 | ANSINAME2BBCODE.each do |key,val| 155 | line.gsub!(/\[#{val}\]/, ANSINAME2CODE[key]) 156 | line.gsub!(/\[\/#{val}\]/, ANSINAME2CODE["reset"]) 157 | end 158 | 159 | ## Fonttypes and sizes not available 160 | line.gsub!(/\[SIZE=\d\]/, "") 161 | line.gsub!(/\[\/SIZE\]/, "") 162 | line.gsub!(/\[FONT=[^\]]*\]/, "") 163 | line.gsub!(/\[\/FONT\]/, "") 164 | 165 | ## Color-mapping 166 | colors = line.scan(/\[COLOR=(.*?)\]/i) 167 | colors = colors.collect{|s| s[0].to_s} if !colors.nil? 168 | colors.each do |col| 169 | name = BBCOLOR2ANSI[col.downcase] 170 | name = BBCOLOR2ANSI["white"] if name.nil? 171 | code = ANSINAME2CODE[name] 172 | 173 | line.gsub!(/\[COLOR=#{col}\]/i, code) 174 | end 175 | line.gsub!(/\[\/COLOR\]/, ANSINAME2CODE["reset"]) 176 | 177 | ## TODO: Alignment 178 | ## TODO: IMGs 179 | ## TODO: EMAILs 180 | ## TODO: URLs 181 | ## TODO: QUOTEs 182 | ## TODO: LISTs 183 | 184 | result << sprintf("%s\n", line) 185 | end 186 | 187 | return result 188 | end 189 | 190 | # Converts a HTML string into one with BBCode markup (TODO) 191 | # Returns the (X)HTML markup string as BBCode 192 | def BBCode.html_to_bbcode(string) 193 | return "" if string.nil? || string.to_s.strip.empty? 194 | result = "" 195 | 196 | ## Iterate over lines 197 | string.split(/
/i).each do |line| 198 | styles = { "strong" => "b", "b" => "b", 199 | "em" => "i", "i" => "i", 200 | "u" => "u" } 201 | 202 | ## preserve B, I, U 203 | styles.each do |html,code| 204 | line.gsub!(/<#{html}>/i, "[#{code.upcase}]") 205 | line.gsub!(/<\/#{html}>/i, "[/#{code.upcase}]") 206 | end 207 | 208 | ## TODO: COLORs 209 | ## TODO: SIZEs 210 | ## TODO: FONTs 211 | 212 | ## EMAIL 213 | line.gsub!(/.*?<\/a>/i, "[EMAIL]\\1[/EMAIL]") 214 | 215 | ## URL 216 | line.gsub!(/(.*?)<\/a>/i, "[URL=\\1]\\2[/URL]") 217 | 218 | ## Other refs + closing tags => throw away 219 | line.gsub!(//i, "") 220 | line.gsub!(/<\/a>/i, "") 221 | 222 | ## IMG 223 | #line.gsub!(//i, "[IMG=\\1]") 224 | line.gsub!(//i, "[IMG]\\1[/IMG]") 225 | 226 | ## CENTER (right/left??) 227 | line.gsub!(/
/i, "[ALIGN=center]") 228 | line.gsub!(/<\/center>/i, "[/ALIGN]") 229 | 230 | ## QUOTE 231 | line.gsub!(/<(?:xmp|pre)>/i, "[QUOTE]") 232 | line.gsub!(/<\/(?:xmp|pre)>/i, "[/QUOTE]") 233 | 234 | ## LIST 235 | line.gsub!(/
    /i, "\n[LIST]\n") 236 | line.gsub!(/<\/ul>/i, "\n[/LIST]\n") 237 | line.gsub!(/
  • */i, "\n[*] ") 238 | 239 | ## Unkown tags => throw away 240 | line.gsub!(/<.*? *\/?>/, "") 241 | 242 | result << sprintf("%s
    \n", line) 243 | end 244 | 245 | return result.gsub!(/
    /i, "\n") 246 | end 247 | 248 | # Converts a BBCode string to one with HTML markup. 249 | # Returns the string with all formatting instructions in 250 | # BBCodes converted to XHTML markups. 251 | def BBCode.bbcode_to_html(string) 252 | return "" if string.nil? || string.to_s.strip.empty? 253 | result = "" 254 | quote = 0 255 | 256 | ## Iterate over lines 257 | string.split("\n").each do |line| 258 | styles = { "b" => "strong", "i" => "em", "u" => "u" } 259 | 260 | ## preserve B, I, U 261 | styles.each do |code,html| 262 | line.gsub!(/\[#{code}\]/i, "<#{html}>") 263 | line.gsub!(/\[\/#{code}\]/i, "") 264 | end 265 | 266 | ## COLOR => font color=... (TODO: should be numeric!) 267 | line.gsub!(/\[COLOR=(.*?)\]/i, "") 268 | line.gsub!(/\[\/COLOR\]/i, "") 269 | 270 | ## SIZE => font size=... 271 | line.gsub!(/\[SIZE=(.*?)\]/i, "") 272 | line.gsub!(/\[\/SIZE\]/i, "") 273 | 274 | ## URL 275 | line.gsub!(/\[URL\]([^\[]+?)\[\/URL\]/i, "
    \\1") 276 | line.gsub!(/\[URL=(.*?)\](.+?)\[\/URL\]/i, "\\2") 277 | 278 | ## IMG 279 | line.gsub!(/\[IMG=(.*?)\]/i, "") 280 | 281 | ## ALIGN=center (TODO: right, left) 282 | line.gsub!(/\[ALIGN=center\]/i, "
    ") 283 | line.gsub!(/\[ALIGN=right\]/i, "
    ") 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 | --------------------------------------------------------------------------------