tty_string 0.1.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5cf9c99684d1bffc4b5238d85a0fbddc6c228a92
4
- data.tar.gz: 29daa63edffa32d87215419a32c0f3eb06511648
2
+ SHA256:
3
+ metadata.gz: b638ef2c66276f621f7ae5620e25af1ccfb1d79f634202aa59935e181baf53e2
4
+ data.tar.gz: ecce132aa8201f22a69c2c2a201143bb1f2775abf4ea0785553592a2f2615640
5
5
  SHA512:
6
- metadata.gz: c0184931cc63e842676e467f9cf1e3262f97a3e191f690bc100e075f389cdd54e3d94d09295da58a2e23a97b9f27836cd3eaf6772a67079184b1fc8030cd05ac
7
- data.tar.gz: 5804b7bcf35cb28a18feeb330662cac534b307badd16f2ebd5e138a772fcd8cf4743702181d33a208bf6b20f8d03013ac0f77fae7e1faba4eb1745bbb2687296
6
+ metadata.gz: 5799b2b9a14ecdb5d86cfd8d6af0d10f896c20de36dfed2801756172fe73afebb427d5cd5816a7bd18502a08640d5c9a691d6f65b2cde9cbf2e9932ca4ca55e8
7
+ data.tar.gz: 76d8856718792bcf2f4da207e6cb5aa69b8bf0cb81e9cc6e60aaf9ec1f8734ce0ca6abb4dca54ec04d97d95604badba2b9ba316ba7079fd3d6b198e34193c474
data/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # v1.1.0
2
+ - suppress bracketed paste mode codes
3
+
4
+ # v1.0.1
5
+ - test push to rubygems, no functional changes
6
+
7
+ # v1.0.0
8
+ - added TTYString.parse as a shortcut for .new#to_s
9
+ - added TTYString.to_proc for lols
10
+ - added jruby to travis matrix, fortunately it just works™
11
+
12
+ # v0.2.1
13
+ - fixed a bug with ignoring \a
14
+
15
+ # v0.2.0
16
+ - Stricter rendering because it turns out terminals are randomly permissive
17
+ - removed support for ruby 2.3
18
+ - added \e[S and \e[T handling
19
+
20
+ # v0.1.0
21
+ - Initial Release
data/Gemfile CHANGED
@@ -2,7 +2,5 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
-
7
5
  # Specify your gem's dependencies in tty_string.gemspec
8
6
  gemspec
data/README.md CHANGED
@@ -1,33 +1,49 @@
1
1
  # TTYString
2
2
 
3
- Render a string like your terminal does by parsing ANSI TTY codes.
4
- This is useful for testing CLI's
5
-
6
- Supported codes
7
-
8
- - \b
9
- - \e[A
10
- - \e[B
11
- - \e[C
12
- - \e[D
13
- - \e[E
14
- - \e[F
15
- - \e[G
16
- - \e[H
17
- - \e[J
18
- - \e[K
19
- - \e[f
20
- - \e[m
21
- - \n
22
- - \r
23
- - \t
3
+ [![Build Status](https://travis-ci.com/robotdana/tty_string.svg?branch=main)](https://travis-ci.com/robotdana/tty_string)
4
+ [![Gem Version](https://badge.fury.io/rb/tty_string.svg)](https://rubygems.org/gems/tty_string)
5
+
6
+ Render to a string like your terminal does by (narrowly) parsing ANSI TTY codes.
7
+ Intended for use in tests of command line interfaces.
8
+
9
+ ## Features
10
+
11
+ - supports ruby 2.4 - 3.0.0.preview1, and jruby
12
+ - has no dependencies outside ruby stdlib
13
+
14
+ ## Supported codes
15
+
16
+ | Code | Description | Default |
17
+ |------|-------------|---------|
18
+ | `\a` | bell: suppressed | |
19
+ | `\b` | backspace: clear the character to the left of the cursor and move the cursor back one column | |
20
+ | `\n` | newline: move the cursor to the start of the next line | |
21
+ | `\r` | return: move the cursor to the start of the current line | |
22
+ | `\t` | tab: move the cursor to the next multiple-of-8 column | |
23
+ | `\e[nA` | move the cursor up _n_ lines | _n_=`1` |
24
+ | `\e[nB` | move the cursor down _n_ lines | _n_=`1` |
25
+ | `\e[nC` | move the cursor right _n_ columns | _n_=`1` |
26
+ | `\e[nD` | move the cursor left _n_ columns | _n_=`1` |
27
+ | `\e[nE` | move the cursor down _n_ lines, and to the start of the line | _n_=`1` |
28
+ | `\e[nF` | move the cursor up _n_ lines, and to the start of the line | _n_=`1` |
29
+ | `\e[nG` | move the cursor to column _n_. `1` is left-most column | _n_=`1` |
30
+ | `\e[n;mH` <br> `\e[n;mf` | move the cursor to row _n_, column _m_. `1;1` is top left corner | _n_=`1` _m_=`1` |
31
+ | `\e[nJ` | _n_=`0`: clear the screen from the cursor forward <br>_n_=`1`: clear the screen from the cursor backward <br>_n_=`2` or _n_=`3`: clear the screen | _n_=`0` |
32
+ | `\e[nK` | _n_=`0`: clear the line from the cursor forward <br>_n_=`1`: clear the line from the cursor backward <br>_n_=`2`: clear the line | _n_=`0` |
33
+ | `\e[nS` | scroll up _n_ rows | _n_=`1` |
34
+ | `\e[nT` | scroll down _n_ rows | _n_=`1` |
35
+ | `\e[m` | styling codes: optionally suppressed with `clear_style: false` | |
36
+ | `\e[?2004h` | enabled bracketed paste: suppressed | |
37
+ | `\e[?2004l` | disable bracketed paste: suppressed | |
38
+ | `\e[200~` | bracketed paste start: suppressed | |
39
+ | `\e[201~` | bracketed paste end: suppressed | |
24
40
 
25
41
  ## Installation
26
42
 
27
43
  Add this line to your application's Gemfile:
28
44
 
29
45
  ```ruby
30
- gem 'tty_string'
46
+ gem 'tty_string', '~> 1.0'
31
47
  ```
32
48
 
33
49
  And then execute:
@@ -40,24 +56,41 @@ Or install it yourself as:
40
56
 
41
57
  ## Usage
42
58
 
43
- ```
44
- TTYString.new("th\ta string\e[3Gis is").to_s => "this is a string"
59
+ ```ruby
60
+ TTYString.parse("th\ta string\e[3Gis is")
61
+ => "this is a string"
45
62
  ```
46
63
 
47
64
  Styling information is suppressed by default:
48
- ```
49
- TTYString.new("th\ta \e[31mstring\e[0m\e[3Gis is", clear_style: false).to_s => "this is a string"
65
+ ```ruby
66
+ TTYString.parse("th\ta \e[31mstring\e[0m\e[3Gis is")
67
+ => "this is a string"
50
68
  ```
51
69
  But can be passed through:
70
+ ```ruby
71
+ TTYString.parse("th\ta \e[31mstring\e[0m\e[3Gis is", clear_style: false)
72
+ => "this is a \e[31mstring\e[0m"
52
73
  ```
53
- TTYString.new("th\ta \e[31mstring\e[0m\e[3Gis is", clear_style: false).to_s => "this is a \e[31mstring\e[0m"
74
+
75
+ Just for fun TTYString.to_proc provides the `parse` method as a lambda, so:
76
+ ```ruby
77
+ ["th\ta string\e[3Gis is"].each(&TTYString)
78
+ => ["this is a string"]
54
79
  ```
55
80
 
81
+ ## Limitations
82
+
83
+ - Various terminals are wildly variously permissive with what they accept,
84
+ so this doesn't even try to cover all possible cases,
85
+ instead it covers the narrowest possible case, and leaves the codes in place when unrecognized
86
+
87
+ - `clear_style: false` treats the style codes as regular text which may work differently when rendering codes that move the cursor.
88
+
56
89
  ## Development
57
90
 
58
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
91
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests and linters. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
59
92
 
60
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
93
+ To install this gem onto your local machine, run `bundle exec rake install`.
61
94
 
62
95
  ## Contributing
63
96
 
data/lib/tty_string.rb CHANGED
@@ -3,19 +3,28 @@
3
3
  require_relative 'tty_string/parser'
4
4
 
5
5
  # Renders a string taking into ANSI escape codes and \t\r\n etc
6
- # Usage: TTYString.new("this\r\e[Kthat").to_s => "that"
6
+ # Usage: TTYString.parse("This\r\e[KThat") => "That"
7
7
  class TTYString
8
+ class << self
9
+ def parse(input_string, clear_style: true)
10
+ new(input_string, clear_style: clear_style).to_s
11
+ end
12
+
13
+ def to_proc
14
+ method(:parse).to_proc
15
+ end
16
+ end
17
+
8
18
  def initialize(input_string, clear_style: true)
9
19
  @parser = Parser.new(input_string)
10
- @clear_style = clear_style
20
+ @parser.clear_style = clear_style
11
21
  end
12
22
 
13
23
  def to_s
14
- parser.render(clear_style: clear_style)
24
+ parser.render
15
25
  end
16
26
 
17
27
  private
18
28
 
19
- attr_reader :clear_style
20
- attr_reader :parser
29
+ attr_reader :clear_style, :parser
21
30
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TTYString
4
+ class Code
5
+ class << self
6
+ def descendants
7
+ @@descendants
8
+ end
9
+
10
+ def inherited(klass)
11
+ @@descendants ||= [] # rubocop:disable Style/ClassVars I want it to be shared between subclasses.
12
+ @@descendants << klass
13
+ @@descendants.uniq!
14
+
15
+ super
16
+ end
17
+
18
+ def render(parser)
19
+ return unless match?(parser)
20
+
21
+ new(parser).action(*args(parser))
22
+
23
+ true
24
+ end
25
+
26
+ def char(value = nil)
27
+ @char = value if value
28
+ @char ||= name.split('::').last
29
+ end
30
+
31
+ private
32
+
33
+ def re
34
+ @re ||= /#{char}/.freeze
35
+ end
36
+
37
+ def args(_scanner)
38
+ []
39
+ end
40
+
41
+ def match?(parser)
42
+ parser.skip(re)
43
+ end
44
+ end
45
+
46
+ def initialize(parser)
47
+ @parser = parser
48
+ end
49
+
50
+ def action; end
51
+
52
+ private
53
+
54
+ attr_reader :parser
55
+
56
+ def screen
57
+ parser.screen
58
+ end
59
+
60
+ def cursor
61
+ parser.cursor
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'code'
4
+ require_relative 'csi_code'
5
+
6
+ class TTYString
7
+ class Code
8
+ class SlashA < TTYString::Code # leftovers:allow
9
+ char "\a"
10
+ end
11
+
12
+ class SlashB < TTYString::Code # leftovers:allow
13
+ char "\b"
14
+
15
+ def self.match?(scanner)
16
+ # can't use `scan(/\b/)` because it matches everything
17
+ return false unless scanner.peek(1) == "\b"
18
+
19
+ scanner.pos += 1
20
+ true
21
+ end
22
+
23
+ def action
24
+ cursor.left
25
+ screen.clear_at_cursor
26
+ end
27
+ end
28
+
29
+ class SlashN < TTYString::Code # leftovers:allow
30
+ char "\n"
31
+
32
+ def action
33
+ cursor.down
34
+ cursor.col = 0
35
+ screen.write('')
36
+ end
37
+ end
38
+
39
+ class SlashR < TTYString::Code # leftovers:allow
40
+ char "\r"
41
+
42
+ def action
43
+ cursor.col = 0
44
+ end
45
+ end
46
+
47
+ class SlashT < TTYString::Code # leftovers:allow
48
+ char "\t"
49
+
50
+ def action
51
+ cursor.right(8 - (cursor.col % 8))
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'code'
4
+
5
+ class TTYString
6
+ class CSICode < TTYString::Code
7
+ class << self
8
+ def default_arg(value = nil)
9
+ @default_arg ||= value
10
+ @default_arg || 1
11
+ end
12
+
13
+ private
14
+
15
+ def match?(parser)
16
+ parser.scan(re)
17
+ end
18
+
19
+ def args(parser)
20
+ a = parser.matched.slice(2..-2).split(';')
21
+ a = a.slice(0, max_args) unless max_args == -1
22
+ a.map! { |n| n.empty? ? default_arg : n.to_i }
23
+ a
24
+ end
25
+
26
+ def re
27
+ @re ||= /\e\[#{args_re}#{char}/
28
+ end
29
+
30
+ def args_re # rubocop:disable Metrics/MethodLength
31
+ case max_args
32
+ when 0 then nil
33
+ when 1 then /#{arg_re}?/
34
+ when -1 then /(#{arg_re}?(;#{arg_re})*)?/
35
+ else /(#{arg_re}?(;#{arg_re}){0,#{max_args - 1}})?/
36
+ end
37
+ end
38
+
39
+ def arg_re
40
+ /\d*/
41
+ end
42
+
43
+ def max_args
44
+ @max_args ||= instance_method(:action).arity
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ TTYString::Code.descendants.pop
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'csi_code'
4
+
5
+ class TTYString
6
+ class CSICode
7
+ class A < TTYString::CSICode # leftovers:allow
8
+ def action(rows = 1)
9
+ cursor.up(rows)
10
+ end
11
+ end
12
+
13
+ class B < TTYString::CSICode # leftovers:allow
14
+ def action(rows = 1)
15
+ cursor.down(rows)
16
+ end
17
+ end
18
+
19
+ class C < TTYString::CSICode # leftovers:allow
20
+ def action(cols = 1)
21
+ cursor.right(cols)
22
+ end
23
+ end
24
+
25
+ class D < TTYString::CSICode # leftovers:allow
26
+ def action(cols = 1)
27
+ cursor.left(cols)
28
+ end
29
+ end
30
+
31
+ class E < TTYString::CSICode # leftovers:allow
32
+ def action(rows = 1)
33
+ cursor.down(rows)
34
+ cursor.col = 0
35
+ end
36
+ end
37
+
38
+ class F < TTYString::CSICode # leftovers:allow
39
+ def action(rows = 1)
40
+ cursor.up(rows)
41
+ cursor.col = 0
42
+ end
43
+ end
44
+
45
+ class G < TTYString::CSICode # leftovers:allow
46
+ def action(col = 1)
47
+ # cursor is zero indexed, arg is 1 indexed
48
+ cursor.col = col.to_i - 1
49
+ end
50
+ end
51
+
52
+ class H < TTYString::CSICode # leftovers:allow
53
+ def action(row = 1, col = 1)
54
+ # cursor is zero indexed, arg is 1 indexed
55
+ cursor.row = row.to_i - 1
56
+ cursor.col = col.to_i - 1
57
+ end
58
+ end
59
+
60
+ class LowH < TTYString::CSICode # leftovers:allow
61
+ char(/\?2004h/)
62
+ end
63
+
64
+ class LowF < TTYString::CSICode::H # leftovers:allow
65
+ char 'f'
66
+ end
67
+
68
+ class J < TTYString::CSICode # leftovers:allow
69
+ default_arg 0
70
+
71
+ def self.arg_re
72
+ /[0-3]?/
73
+ end
74
+
75
+ def action(mode = 0)
76
+ # :nocov: else won't ever be called. don't worry about it
77
+ case mode
78
+ # :nocov:
79
+ when 0 then screen.clear_forward
80
+ when 1 then screen.clear_backward
81
+ when 2, 3 then screen.clear
82
+ end
83
+ end
84
+ end
85
+
86
+ class K < TTYString::CSICode # leftovers:allow
87
+ default_arg 0
88
+
89
+ def self.arg_re
90
+ /[0-2]?/
91
+ end
92
+
93
+ def action(mode = 0)
94
+ # :nocov: else won't ever be called. don't worry about it
95
+ case mode
96
+ # :nocov:
97
+ when 0 then screen.clear_line_forward
98
+ when 1 then screen.clear_line_backward
99
+ when 2 then screen.clear_line
100
+ end
101
+ end
102
+ end
103
+
104
+ class LowL < TTYString::CSICode # leftovers:allow
105
+ char(/\?2004l/)
106
+ end
107
+
108
+ class LowM < TTYString::CSICode # leftovers:allow
109
+ char 'm'
110
+
111
+ def self.arg_re
112
+ # 0-255
113
+ /(?:\d|\d\d|1\d\d|2[0-4]\d|25[0-5])?/
114
+ end
115
+
116
+ def self.render(renderer)
117
+ super if renderer.clear_style
118
+ end
119
+
120
+ def action(*args); end
121
+ end
122
+
123
+ class S < TTYString::CSICode # leftovers:allow
124
+ def action(rows = 1)
125
+ rows.times { screen.scroll_up }
126
+ end
127
+ end
128
+
129
+ class T < TTYString::CSICode # leftovers:allow
130
+ def action(rows = 1)
131
+ rows.times { screen.scroll_down }
132
+ end
133
+ end
134
+
135
+ class Tilde < TTYString::CSICode # leftovers:allow
136
+ char(/(?:200|201)~/)
137
+ end
138
+ end
139
+ end
@@ -11,46 +11,33 @@ class TTYString
11
11
  end
12
12
 
13
13
  def row=(value)
14
- @row = value.to_i
14
+ @row = value
15
15
  @row = 0 if @row.negative?
16
16
  end
17
17
 
18
18
  def col=(value)
19
- @col = value.to_i
19
+ @col = value
20
20
  @col = 0 if @col.negative?
21
21
  end
22
22
 
23
23
  def left(count = 1)
24
- count = count.to_i
25
- raise ArgumentError if count.negative?
26
-
27
24
  self.col -= count
28
25
  end
29
26
 
30
27
  def up(count = 1)
31
- count = count.to_i
32
- raise ArgumentError if count.negative?
33
-
34
28
  self.row -= count
35
29
  end
36
30
 
37
31
  def down(count = 1)
38
- count = count.to_i
39
- raise ArgumentError unless count >= 0
40
-
41
32
  self.row += count
42
33
  end
43
34
 
44
35
  def right(count = 1)
45
- count = count.to_i
46
- raise ArgumentError unless count >= 0
47
-
48
36
  self.col += count
49
37
  end
50
38
 
51
39
  def to_ary
52
40
  [row, col]
53
41
  end
54
- alias to_a to_ary
55
42
  end
56
43
  end
@@ -1,82 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'strscan'
4
- require_relative 'renderer'
4
+ require_relative 'code_definitions'
5
+ require_relative 'csi_code_definitions'
6
+
7
+ require_relative 'screen'
5
8
 
6
9
  class TTYString
7
10
  # Reads the text string a
8
11
  class Parser < StringScanner
9
- def render(clear_style: true)
12
+ attr_accessor :clear_style
13
+ attr_reader :screen
14
+
15
+ def render
10
16
  reset
11
- @clear_style = clear_style
12
- @renderer = Renderer.new
17
+ @screen = Screen.new
13
18
  read until eos?
14
- renderer.to_s
19
+ screen.to_s
15
20
  end
16
21
 
17
- private
22
+ def cursor
23
+ screen.cursor
24
+ end
18
25
 
19
- attr_reader :renderer
20
- attr_reader :clear_style
26
+ private
21
27
 
22
28
  def write(string)
23
- renderer.write(string)
29
+ screen.write(string)
24
30
  end
25
31
 
26
32
  def read
27
- text || slash_n || slash_r || slash_t || slash_b || slash_e
28
- end
29
-
30
- def text
31
- write(matched) if scan(text_regexp)
32
- end
33
-
34
- def slash_n
35
- renderer.slash_n if skip(/\n/)
36
- end
37
-
38
- def slash_r
39
- renderer.slash_r if skip(/\r/)
40
- end
41
-
42
- def slash_t
43
- renderer.slash_t if skip(/\t/)
44
- end
45
-
46
- def slash_b
47
- # can't use `scan(/\b/)` because it matches everything
48
- return unless peek(1) == "\b"
49
-
50
- self.pos += 1
51
- renderer.slash_b
52
- end
53
-
54
- def slash_e
55
- return unless scan(csi_regexp)
56
-
57
- args = matched.slice(2..-2).split(';')
58
- command = matched.slice(-1)
59
- render_csi(:"csi_#{command}", *args)
60
- end
61
-
62
- def csi_regexp
63
- @csi_regexp ||= Regexp.new("\e#{csi_pattern}")
64
- end
65
-
66
- def csi_pattern
67
- "\\[(\\d+;?|;)*[ABCDEFGHJKf#{'m' if clear_style}]"
68
- end
69
-
70
- def text_regexp
71
- @text_regexp ||= Regexp.new("[^\b\t\r\n\e]|\e(?!#{csi_pattern})")
33
+ TTYString::Code.descendants.any? { |c| c.render(self) } || default
72
34
  end
73
35
 
74
- def render_csi(method, *args)
75
- method = renderer.method(method)
76
- params = method.parameters
77
- args = args.take(params.length) unless params.assoc(:rest)
78
- args = [] if args.all?(&:empty?)
79
- method.call(*args)
36
+ def default
37
+ write(getch)
80
38
  end
81
39
  end
82
40
  end
@@ -46,6 +46,16 @@ class TTYString
46
46
  @screen = []
47
47
  end
48
48
 
49
+ def scroll_up
50
+ screen.push([])
51
+ screen.shift
52
+ end
53
+
54
+ def scroll_down
55
+ screen.unshift([])
56
+ screen.pop
57
+ end
58
+
49
59
  def clear_lines_before
50
60
  screen.fill([], 0...row)
51
61
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class TTYString
4
- VERSION = '0.1.0'
4
+ VERSION = '1.1.0'
5
5
  end
data/tty_string.gemspec CHANGED
@@ -11,21 +11,35 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ['robot@dana.sh']
12
12
 
13
13
  spec.summary = 'Render a string using ANSI TTY codes'
14
- spec.homepage = "https://github.com/robotdana/tty_string"
14
+ spec.homepage = 'https://github.com/robotdana/tty_string'
15
15
  spec.license = 'MIT'
16
16
 
17
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
- f.match(%r{^(test|spec|features|\.?rubocop|\.travis|\.git|\.rspec)/})
17
+ if spec.respond_to?(:metadata)
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = spec.homepage
20
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
19
21
  end
20
- spec.bindir = 'exe'
21
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+
23
+ spec.files = Dir.glob('{lib}/**/*') + %w{
24
+ CHANGELOG.md
25
+ Gemfile
26
+ LICENSE.txt
27
+ README.md
28
+ tty_string.gemspec
29
+ }
30
+ spec.required_ruby_version = '>= 2.4'
22
31
  spec.require_paths = ['lib']
23
32
 
24
- spec.add_development_dependency 'bundler', '~> 1.16'
25
- spec.add_development_dependency 'pry', '~> 0.12.2'
26
- spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'bundler', '~> 2.0'
34
+ spec.add_development_dependency 'fast_ignore', '>= 0.15.1'
35
+ spec.add_development_dependency 'leftovers', '>= 0.2.0'
36
+ spec.add_development_dependency 'pry', '~> 0.12'
37
+ spec.add_development_dependency 'rake', '>= 12.3.3'
27
38
  spec.add_development_dependency 'rspec', '~> 3.0'
28
- spec.add_development_dependency 'rubocop', '~> 0.74.0'
29
- spec.add_development_dependency 'rubocop-performance', '~> 1.4.1'
30
- spec.add_development_dependency 'rubocop-rspec', '~> 1.35.0'
39
+ spec.add_development_dependency 'rubocop', '~> 0.93.1'
40
+ spec.add_development_dependency 'rubocop-performance', '~> 1.8.1'
41
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.44.1'
42
+ spec.add_development_dependency 'simplecov', '~> 0.18.5'
43
+ spec.add_development_dependency 'simplecov-console'
44
+ spec.add_development_dependency 'spellr', '>= 0.8.1'
31
45
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tty_string
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dana Sherson
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-21 00:00:00.000000000 Z
11
+ date: 2021-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,42 +16,70 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.16'
19
+ version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.16'
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fast_ignore
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.15.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.15.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: leftovers
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.0
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: pry
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
59
  - - "~>"
32
60
  - !ruby/object:Gem::Version
33
- version: 0.12.2
61
+ version: '0.12'
34
62
  type: :development
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
66
  - - "~>"
39
67
  - !ruby/object:Gem::Version
40
- version: 0.12.2
68
+ version: '0.12'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rake
43
71
  requirement: !ruby/object:Gem::Requirement
44
72
  requirements:
45
- - - "~>"
73
+ - - ">="
46
74
  - !ruby/object:Gem::Version
47
- version: '10.0'
75
+ version: 12.3.3
48
76
  type: :development
49
77
  prerelease: false
50
78
  version_requirements: !ruby/object:Gem::Requirement
51
79
  requirements:
52
- - - "~>"
80
+ - - ">="
53
81
  - !ruby/object:Gem::Version
54
- version: '10.0'
82
+ version: 12.3.3
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rspec
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -72,42 +100,84 @@ dependencies:
72
100
  requirements:
73
101
  - - "~>"
74
102
  - !ruby/object:Gem::Version
75
- version: 0.74.0
103
+ version: 0.93.1
76
104
  type: :development
77
105
  prerelease: false
78
106
  version_requirements: !ruby/object:Gem::Requirement
79
107
  requirements:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
- version: 0.74.0
110
+ version: 0.93.1
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: rubocop-performance
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
115
  - - "~>"
88
116
  - !ruby/object:Gem::Version
89
- version: 1.4.1
117
+ version: 1.8.1
90
118
  type: :development
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
93
121
  requirements:
94
122
  - - "~>"
95
123
  - !ruby/object:Gem::Version
96
- version: 1.4.1
124
+ version: 1.8.1
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: rubocop-rspec
99
127
  requirement: !ruby/object:Gem::Requirement
100
128
  requirements:
101
129
  - - "~>"
102
130
  - !ruby/object:Gem::Version
103
- version: 1.35.0
131
+ version: 1.44.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 1.44.1
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.18.5
104
146
  type: :development
105
147
  prerelease: false
106
148
  version_requirements: !ruby/object:Gem::Requirement
107
149
  requirements:
108
150
  - - "~>"
109
151
  - !ruby/object:Gem::Version
110
- version: 1.35.0
152
+ version: 0.18.5
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov-console
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: spellr
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: 0.8.1
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: 0.8.1
111
181
  description:
112
182
  email:
113
183
  - robot@dana.sh
@@ -115,29 +185,27 @@ executables: []
115
185
  extensions: []
116
186
  extra_rdoc_files: []
117
187
  files:
118
- - ".gitignore"
119
- - ".gitmodules"
120
- - ".rspec"
121
- - ".rubocop.yml"
122
- - ".travis.yml"
188
+ - CHANGELOG.md
123
189
  - Gemfile
124
- - Gemfile.lock
125
190
  - LICENSE.txt
126
191
  - README.md
127
- - Rakefile
128
- - bin/console
129
- - bin/setup
130
192
  - lib/tty_string.rb
193
+ - lib/tty_string/code.rb
194
+ - lib/tty_string/code_definitions.rb
195
+ - lib/tty_string/csi_code.rb
196
+ - lib/tty_string/csi_code_definitions.rb
131
197
  - lib/tty_string/cursor.rb
132
198
  - lib/tty_string/parser.rb
133
- - lib/tty_string/renderer.rb
134
199
  - lib/tty_string/screen.rb
135
200
  - lib/tty_string/version.rb
136
201
  - tty_string.gemspec
137
202
  homepage: https://github.com/robotdana/tty_string
138
203
  licenses:
139
204
  - MIT
140
- metadata: {}
205
+ metadata:
206
+ homepage_uri: https://github.com/robotdana/tty_string
207
+ source_code_uri: https://github.com/robotdana/tty_string
208
+ changelog_uri: https://github.com/robotdana/tty_string/blob/main/CHANGELOG.md
141
209
  post_install_message:
142
210
  rdoc_options: []
143
211
  require_paths:
@@ -146,15 +214,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
146
214
  requirements:
147
215
  - - ">="
148
216
  - !ruby/object:Gem::Version
149
- version: '0'
217
+ version: '2.4'
150
218
  required_rubygems_version: !ruby/object:Gem::Requirement
151
219
  requirements:
152
220
  - - ">="
153
221
  - !ruby/object:Gem::Version
154
222
  version: '0'
155
223
  requirements: []
156
- rubyforge_project:
157
- rubygems_version: 2.5.2.1
224
+ rubygems_version: 3.0.3
158
225
  signing_key:
159
226
  specification_version: 4
160
227
  summary: Render a string using ANSI TTY codes
data/.gitignore DELETED
@@ -1,11 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
data/.gitmodules DELETED
@@ -1,3 +0,0 @@
1
- [submodule "rubocop_yml"]
2
- path = rubocop_yml
3
- url = https://github.com/robotdana/rubocop_yml.git
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1 +0,0 @@
1
- rubocop_yml/rubocop.yml
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.5.1
5
- before_install: gem install bundler -v 1.16.0
data/Gemfile.lock DELETED
@@ -1,63 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- tty_string (0.1.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- ast (2.4.0)
10
- coderay (1.1.2)
11
- diff-lcs (1.3)
12
- jaro_winkler (1.5.3)
13
- method_source (0.9.2)
14
- parallel (1.17.0)
15
- parser (2.6.4.1)
16
- ast (~> 2.4.0)
17
- pry (0.12.2)
18
- coderay (~> 1.1.0)
19
- method_source (~> 0.9.0)
20
- rainbow (3.0.0)
21
- rake (10.5.0)
22
- rspec (3.8.0)
23
- rspec-core (~> 3.8.0)
24
- rspec-expectations (~> 3.8.0)
25
- rspec-mocks (~> 3.8.0)
26
- rspec-core (3.8.2)
27
- rspec-support (~> 3.8.0)
28
- rspec-expectations (3.8.4)
29
- diff-lcs (>= 1.2.0, < 2.0)
30
- rspec-support (~> 3.8.0)
31
- rspec-mocks (3.8.1)
32
- diff-lcs (>= 1.2.0, < 2.0)
33
- rspec-support (~> 3.8.0)
34
- rspec-support (3.8.2)
35
- rubocop (0.74.0)
36
- jaro_winkler (~> 1.5.1)
37
- parallel (~> 1.10)
38
- parser (>= 2.6)
39
- rainbow (>= 2.2.2, < 4.0)
40
- ruby-progressbar (~> 1.7)
41
- unicode-display_width (>= 1.4.0, < 1.7)
42
- rubocop-performance (1.4.1)
43
- rubocop (>= 0.71.0)
44
- rubocop-rspec (1.35.0)
45
- rubocop (>= 0.60.0)
46
- ruby-progressbar (1.10.1)
47
- unicode-display_width (1.6.0)
48
-
49
- PLATFORMS
50
- ruby
51
-
52
- DEPENDENCIES
53
- bundler (~> 1.16)
54
- pry (~> 0.12.2)
55
- rake (~> 10.0)
56
- rspec (~> 3.0)
57
- rubocop (~> 0.74.0)
58
- rubocop-performance (~> 1.4.1)
59
- rubocop-rspec (~> 1.35.0)
60
- tty_string!
61
-
62
- BUNDLED WITH
63
- 1.16.0
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- task default: :spec
data/bin/console DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'bundler/setup'
5
- require 'tty_string'
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
- require 'irb'
15
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'screen'
4
- class TTYString
5
- # turns the text string into screen instructions
6
- class Renderer
7
- attr_reader :screen
8
-
9
- def initialize
10
- @screen = Screen.new
11
- end
12
-
13
- def to_s
14
- screen.to_s
15
- end
16
-
17
- def write(string)
18
- screen.write(string)
19
- end
20
-
21
- # rubocop:disable Naming/MethodName
22
- def csi_A(rows = 1)
23
- cursor.up(rows)
24
- end
25
-
26
- def csi_B(rows = 1)
27
- cursor.down(rows)
28
- end
29
-
30
- def csi_C(cols = 1)
31
- cursor.right(cols)
32
- end
33
-
34
- def csi_D(cols = 1)
35
- cursor.left(cols)
36
- end
37
-
38
- def csi_E(rows = 1)
39
- cursor.down(rows)
40
- cursor.col = 0
41
- end
42
-
43
- def csi_F(rows = 1)
44
- cursor.up(rows)
45
- cursor.col = 0
46
- end
47
-
48
- def csi_G(col = 1)
49
- cursor.col = col.to_i - 1 # cursor is zero indexed, arg is 1 indexed
50
- end
51
-
52
- def csi_H(row = 1, col = 1)
53
- # cursor is zero indexed, arg is 1 indexed
54
- cursor.row = row.to_i - 1
55
- cursor.col = col.to_i - 1
56
- end
57
- alias csi_f csi_H
58
-
59
- def csi_J(mode = 0)
60
- case mode.to_i
61
- when 0 then screen.clear_forward
62
- when 1 then screen.clear_backward
63
- when 2, 3 then screen.clear
64
- end
65
- end
66
-
67
- def csi_K(mode = 0)
68
- case mode.to_i
69
- when 0 then screen.clear_line_forward
70
- when 1 then screen.clear_line_backward
71
- when 2 then screen.clear_line
72
- end
73
- end
74
-
75
- def csi_m(*args)
76
- end
77
- # rubocop:enable Naming/MethodName
78
-
79
- def slash_b
80
- cursor.left
81
- screen.clear_at_cursor
82
- end
83
-
84
- def slash_n
85
- cursor.down
86
- cursor.col = 0
87
- screen.write('')
88
- end
89
-
90
- def slash_r
91
- cursor.col = 0
92
- end
93
-
94
- def slash_t
95
- cursor.right(8 - (cursor.col % 8))
96
- end
97
-
98
- private
99
-
100
- def cursor
101
- screen.cursor
102
- end
103
- end
104
- end