vtparser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.bash_history +117 -0
- data/CHANGELOG.md +5 -0
- data/README.md +53 -0
- data/Rakefile +4 -0
- data/examples/indent_cli.rb +84 -0
- data/lib/vtparser/parser.rb +305 -0
- data/lib/vtparser/version.rb +5 -0
- data/lib/vtparser.rb +5 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d622edd5fbb0b4f47cb9831699c466aeabc3da9c6bed99370cc7d99d169c8c02
|
4
|
+
data.tar.gz: 33eccc5b843d8c5d734a06d5b2b3d389462c23ea568bf9456ed55a38d6f1a50a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0e5c6dd30582e24e0ad63b142446280b1be31d51cbae543b78c0019bf626ce2d477ea7bf002ab3707c7dd8056df886d33304eaa2a9509c30a9cac7ac6148e4b9
|
7
|
+
data.tar.gz: ab1f60a0cdd8e079274bb8a7d6a285287b81a3fe1304462086ccdb71910fe09451faadaa4f3ce8935b6a63fdc579a856e069558e7183c8a7c659924e7ad32417
|
data/.bash_history
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
rspec
|
2
|
+
rspec
|
3
|
+
rspec
|
4
|
+
rspec
|
5
|
+
rspec
|
6
|
+
rspec
|
7
|
+
rspec
|
8
|
+
rspec
|
9
|
+
rspec
|
10
|
+
rspec
|
11
|
+
rspec ./spec/vtparser_spec.rb:153
|
12
|
+
rspec ./spec/vtparser_spec.rb:153
|
13
|
+
rspec ./spec/vtparser_spec.rb:153
|
14
|
+
rspec ./spec/vtparser_spec.rb:153
|
15
|
+
rspec ./spec/vtparser_spec.rb:153
|
16
|
+
rspec ./spec/vtparser_spec.rb:153
|
17
|
+
rspec
|
18
|
+
rspec
|
19
|
+
rspec
|
20
|
+
rspec ./spec/vtparser_spec.rb:37
|
21
|
+
rspec ./spec/vtparser_spec.rb:37
|
22
|
+
rspec
|
23
|
+
rspec
|
24
|
+
rspec expect(output).to eq(input)
|
25
|
+
rspec ./spec/vtparser_spec.rb:156
|
26
|
+
rspec ./spec/vtparser_spec.rb:156
|
27
|
+
rspec ./spec/vtparser_spec.rb:156
|
28
|
+
rspec ./spec/vtparser_spec.rb:156
|
29
|
+
rspec
|
30
|
+
rspec
|
31
|
+
D
|
32
|
+
rspec ./spec/vtparser_spec.rb
|
33
|
+
rspec ./spec/vtparser_spec.rb:137
|
34
|
+
rspec ./spec/vtparser_spec.rb:137
|
35
|
+
rspec ./spec/vtparser_spec.rb:137
|
36
|
+
rspec ./spec/vtparser_spec.rb:137
|
37
|
+
rspec ./spec/vtparser_spec.rb:137
|
38
|
+
rspec ./spec/vtparser_spec.rb:137
|
39
|
+
rspec ./spec/vtparser_spec.rb:137
|
40
|
+
rspec ./spec/vtparser_spec.rb:137
|
41
|
+
rspec ./spec/vtparser_spec.rb
|
42
|
+
rspec ./spec/vtparser_spec.rb
|
43
|
+
rspec ./spec/vtparser_spec.rb
|
44
|
+
bundle
|
45
|
+
rspec ./spec/vtparser_spec.rb
|
46
|
+
rspec ./spec/vtparser_spec.rb
|
47
|
+
ruby lib/vtparser.rb 'yarn add --dev esbuild from "."'
|
48
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
49
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
50
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
51
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
52
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
53
|
+
bundle
|
54
|
+
bundle
|
55
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
56
|
+
irb
|
57
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
58
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
59
|
+
ruby lib/vtparser/parser.rb 'yarn add --dev esbuild from "."'
|
60
|
+
ruby lib/vtparser/parser.rb 'joe'
|
61
|
+
joe
|
62
|
+
ruby lib/vtparser/parser.rb 'vim'
|
63
|
+
vim
|
64
|
+
ruby example/indent_cli.rb 'vim'
|
65
|
+
ruby examples/indent_cli.rb 'vim'
|
66
|
+
ruby examples/indent_cli.rb 'vim'
|
67
|
+
ruby examples/indent_cli.rb 'vim'
|
68
|
+
ruby examples/indent_cli.rb 'joe'
|
69
|
+
ruby examples/indent_cli.rb 'joe'
|
70
|
+
ruby examples/indent_cli.rb 'joe'
|
71
|
+
lsss
|
72
|
+
less
|
73
|
+
less README.md
|
74
|
+
ls
|
75
|
+
exit
|
76
|
+
ls
|
77
|
+
ruby examples/indent_cli.rb 'less'
|
78
|
+
ruby examples/indent_cli.rb 'less README.md'
|
79
|
+
ruby examples/indent_cli.rb 'less README.md'
|
80
|
+
ruby examples/indent_cli.rb 'less README.md'
|
81
|
+
ruby examples/indent_cli.rb 'less README.md'
|
82
|
+
ruby examples/indent_cli.rb 'less README.md'
|
83
|
+
ruby examples/indent_cli.rb 'less README.md'
|
84
|
+
ruby examples/indent_cli.rb 'less README.md'
|
85
|
+
ruby examples/indent_cli.rb 'less README.md'
|
86
|
+
ruby examples/indent_cli.rb 'less README.md'
|
87
|
+
ruby examples/indent_cli.rb 'less README.md'
|
88
|
+
ruby examples/indent_cli.rb 'less README.md'
|
89
|
+
ruby examples/indent_cli.rb 'less README.md'
|
90
|
+
ruby examples/indent_cli.rb 'less README.md'
|
91
|
+
ruby examples/indent_cli.rb 'less README.md'
|
92
|
+
less README.md
|
93
|
+
ruby examples/indent_cli.rb 'less README.md'
|
94
|
+
ruby examples/indent_cli.rb 'less README.md'
|
95
|
+
ruby examples/indent_cli.rb 'less README.md'
|
96
|
+
ruby examples/indent_cli.rb 'less README.md'
|
97
|
+
ruby examples/indent_cli.rb 'less README.md'
|
98
|
+
ruby examples/indent_cli.rb 'less README.md'
|
99
|
+
ruby examples/indent_cli.rb 'less README.md'
|
100
|
+
ruby examples/indent_cli.rb 'less README.md'
|
101
|
+
ruby examples/indent_cli.rb 'less README.md'
|
102
|
+
ruby examples/indent_cli.rb 'less README.md'
|
103
|
+
ruby examples/test.rb
|
104
|
+
kkllllijjaaa
|
105
|
+
ruby examples/test.rb
|
106
|
+
ruby examples/test.rb
|
107
|
+
ruby examples/test.rb
|
108
|
+
ruby examples/test.rb
|
109
|
+
ruby examples/test.rb
|
110
|
+
ruby examples/test.rb
|
111
|
+
ruby examples/test.rb
|
112
|
+
ruby examples/test.rb
|
113
|
+
ruby examples/test.rb
|
114
|
+
ruby examples/test.rb
|
115
|
+
ruby examples/indent_cli.rb
|
116
|
+
ruby examples/indent_cli.rb 'bundle gem test17'
|
117
|
+
ruby examples/indent_cli.rb 'bundle gem test18'
|
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# VT 100 Parser Gem
|
2
|
+
|
3
|
+
This gem is a parser for VT100 terminal escape sequences. It is based on the C code from https://github.com/haberman/vtparse/.
|
4
|
+
|
5
|
+
## Background on VT100 Escape Sequences
|
6
|
+
|
7
|
+
See https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Install the gem and add to the application's Gemfile by executing:
|
12
|
+
|
13
|
+
```bash
|
14
|
+
bundle add vtparser
|
15
|
+
```
|
16
|
+
|
17
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
18
|
+
|
19
|
+
```bash
|
20
|
+
gem install vtparser
|
21
|
+
```
|
22
|
+
|
23
|
+
## Basic Usage
|
24
|
+
|
25
|
+
See the minimal example below and the [`examples`](https://github.com/coezbek/vtparser/examples) directory for more examples.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'vtparser'
|
29
|
+
|
30
|
+
# Instantiate the parser with a block to handle actions
|
31
|
+
parser = VTParser.new do |action, ch, intermediate_chars, params|
|
32
|
+
|
33
|
+
# For this minimal example, we'll just turn everything back strings to print
|
34
|
+
print VtParser::to_ansi(action, ch, intermediate_chars, params)
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
# Sample input containing ANSI escape sequences
|
39
|
+
input = "\e[31mHello, \e[1mWorld!\e[0m"
|
40
|
+
|
41
|
+
# Parse the input
|
42
|
+
parser.parse(input)
|
43
|
+
```
|
44
|
+
|
45
|
+
## Development
|
46
|
+
|
47
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
48
|
+
|
49
|
+
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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/coezbek/vtparser.
|
data/Rakefile
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'pty'
|
2
|
+
require "tty-prompt" # for winsize call below
|
3
|
+
require 'rainbow/refinement' # for colorizing output
|
4
|
+
using Rainbow
|
5
|
+
require_relative '../lib/vtparser'
|
6
|
+
|
7
|
+
# Get the command from ARGV
|
8
|
+
command = ARGV.join(' ')
|
9
|
+
if command.empty?
|
10
|
+
puts "Usage: ruby indent_cli.rb '<command>'"
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
line_indent = ' ▐ '.yellow
|
15
|
+
first_line = true
|
16
|
+
parser = VTParser.new do |action, ch, intermediate_chars, params|
|
17
|
+
print line_indent if first_line
|
18
|
+
first_line = false
|
19
|
+
|
20
|
+
to_output = VTParser::to_ansi(action, ch, intermediate_chars, params)
|
21
|
+
|
22
|
+
case action
|
23
|
+
when :print, :execute, :put, :osc_put
|
24
|
+
if ch == "\n" || ch == "\r"
|
25
|
+
print ch
|
26
|
+
print line_indent
|
27
|
+
next
|
28
|
+
end
|
29
|
+
when :csi_dispatch
|
30
|
+
if to_output == "\e[2K"
|
31
|
+
print "\e[2K"
|
32
|
+
print line_indent
|
33
|
+
next
|
34
|
+
else
|
35
|
+
if ch == 'G'
|
36
|
+
# puts "to_output: #{to_output.inspect} action: #{action} ch: #{ch.inspect}"
|
37
|
+
# && parser.params.size == 1
|
38
|
+
print "\e[#{parser.params[0] + 6}G"
|
39
|
+
|
40
|
+
next
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
print to_output
|
46
|
+
end
|
47
|
+
|
48
|
+
begin
|
49
|
+
PTY.spawn(command) do |stdout_and_stderr, stdin, pid|
|
50
|
+
|
51
|
+
Thread.new do
|
52
|
+
while pid != nil
|
53
|
+
stdin.write(STDIN.readpartial(1024)) # Requires user to press enter!
|
54
|
+
end
|
55
|
+
rescue => e
|
56
|
+
puts "Error: #{e}"
|
57
|
+
exit(0)
|
58
|
+
end
|
59
|
+
|
60
|
+
begin
|
61
|
+
stdout_and_stderr.winsize = $stdout.winsize
|
62
|
+
|
63
|
+
stdout_and_stderr.each_char do |char|
|
64
|
+
|
65
|
+
parser.parse(char)
|
66
|
+
|
67
|
+
end
|
68
|
+
rescue Errno::EIO
|
69
|
+
# End of output
|
70
|
+
end
|
71
|
+
|
72
|
+
# Wait for the child process to exit
|
73
|
+
Process.wait(pid)
|
74
|
+
pid = nil
|
75
|
+
exit_status = $?.exitstatus
|
76
|
+
result = exit_status == 0
|
77
|
+
|
78
|
+
# Clear the line, reset the cursor to the start of the line
|
79
|
+
print "\e[2K\e[1G"
|
80
|
+
end
|
81
|
+
|
82
|
+
rescue PTY::ChildExited => e
|
83
|
+
puts "The child process exited: #{e}"
|
84
|
+
end
|
@@ -0,0 +1,305 @@
|
|
1
|
+
class VTParser
|
2
|
+
attr_reader :intermediate_chars, :params
|
3
|
+
|
4
|
+
def initialize(&block)
|
5
|
+
@callback = block
|
6
|
+
@state = :GROUND
|
7
|
+
@intermediate_chars = ''
|
8
|
+
@params = []
|
9
|
+
@ignore_flagged = false
|
10
|
+
initialize_states
|
11
|
+
build_state_transitions
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(data)
|
15
|
+
data.each_char do |ch|
|
16
|
+
# ch = byte.chr
|
17
|
+
do_state_change(ch)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize_states
|
22
|
+
@states = {
|
23
|
+
:GROUND => {
|
24
|
+
(0x00..0x17) => :execute,
|
25
|
+
0x19 => :execute,
|
26
|
+
(0x1c..0x1f) => :execute,
|
27
|
+
(0x20..0x7f) => :print,
|
28
|
+
},
|
29
|
+
:ESCAPE => {
|
30
|
+
:on_entry => :clear,
|
31
|
+
(0x00..0x17) => :execute,
|
32
|
+
0x19 => :execute,
|
33
|
+
(0x1c..0x1f) => :execute,
|
34
|
+
0x7f => :ignore,
|
35
|
+
(0x20..0x2f) => [:collect, :ESCAPE_INTERMEDIATE],
|
36
|
+
(0x30..0x4f) => [:esc_dispatch, :GROUND],
|
37
|
+
(0x51..0x57) => [:esc_dispatch, :GROUND],
|
38
|
+
0x59 => [:esc_dispatch, :GROUND],
|
39
|
+
0x5a => [:esc_dispatch, :GROUND],
|
40
|
+
0x5c => [:esc_dispatch, :GROUND],
|
41
|
+
(0x60..0x7e) => [:esc_dispatch, :GROUND],
|
42
|
+
0x5b => :CSI_ENTRY,
|
43
|
+
0x5d => :OSC_STRING,
|
44
|
+
0x50 => :DCS_ENTRY,
|
45
|
+
0x58 => :SOS_PM_APC_STRING,
|
46
|
+
0x5e => :SOS_PM_APC_STRING,
|
47
|
+
0x5f => :SOS_PM_APC_STRING,
|
48
|
+
},
|
49
|
+
:ESCAPE_INTERMEDIATE => {
|
50
|
+
(0x00..0x17) => :execute,
|
51
|
+
0x19 => :execute,
|
52
|
+
(0x1c..0x1f) => :execute,
|
53
|
+
(0x20..0x2f) => :collect,
|
54
|
+
0x7f => :ignore,
|
55
|
+
(0x30..0x7e) => [:esc_dispatch, :GROUND],
|
56
|
+
},
|
57
|
+
:CSI_ENTRY => {
|
58
|
+
:on_entry => :clear,
|
59
|
+
(0x00..0x17) => :execute,
|
60
|
+
0x19 => :execute,
|
61
|
+
(0x1c..0x1f) => :execute,
|
62
|
+
0x7f => :ignore,
|
63
|
+
(0x20..0x2f) => [:collect, :CSI_INTERMEDIATE],
|
64
|
+
0x3a => :CSI_IGNORE,
|
65
|
+
(0x30..0x39) => [:param, :CSI_PARAM],
|
66
|
+
0x3b => [:param, :CSI_PARAM],
|
67
|
+
(0x3c..0x3f) => [:collect, :CSI_PARAM],
|
68
|
+
(0x40..0x7e) => [:csi_dispatch, :GROUND],
|
69
|
+
},
|
70
|
+
:CSI_PARAM => {
|
71
|
+
(0x00..0x17) => :execute,
|
72
|
+
0x19 => :execute,
|
73
|
+
(0x1c..0x1f) => :execute,
|
74
|
+
(0x30..0x39) => :param,
|
75
|
+
0x3b => :param,
|
76
|
+
0x7f => :ignore,
|
77
|
+
0x3a => :CSI_IGNORE,
|
78
|
+
(0x3c..0x3f) => :CSI_IGNORE,
|
79
|
+
(0x20..0x2f) => [:collect, :CSI_INTERMEDIATE],
|
80
|
+
(0x40..0x7e) => [:csi_dispatch, :GROUND],
|
81
|
+
},
|
82
|
+
:CSI_INTERMEDIATE => {
|
83
|
+
(0x00..0x17) => :execute,
|
84
|
+
0x19 => :execute,
|
85
|
+
(0x1c..0x1f) => :execute,
|
86
|
+
(0x20..0x2f) => :collect,
|
87
|
+
0x7f => :ignore,
|
88
|
+
(0x30..0x3f) => :CSI_IGNORE,
|
89
|
+
(0x40..0x7e) => [:csi_dispatch, :GROUND],
|
90
|
+
},
|
91
|
+
:CSI_IGNORE => {
|
92
|
+
(0x00..0x17) => :execute,
|
93
|
+
0x19 => :execute,
|
94
|
+
(0x1c..0x1f) => :execute,
|
95
|
+
(0x20..0x7f) => :ignore,
|
96
|
+
},
|
97
|
+
:DCS_ENTRY => {
|
98
|
+
:on_entry => :clear,
|
99
|
+
(0x00..0x17) => :ignore,
|
100
|
+
0x19 => :ignore,
|
101
|
+
(0x1c..0x1f) => :ignore,
|
102
|
+
0x7f => :ignore,
|
103
|
+
0x3a => :DCS_IGNORE,
|
104
|
+
(0x20..0x2f) => [:collect, :DCS_INTERMEDIATE],
|
105
|
+
(0x30..0x39) => [:param, :DCS_PARAM],
|
106
|
+
0x3b => [:param, :DCS_PARAM],
|
107
|
+
(0x3c..0x3f) => [:collect, :DCS_PARAM],
|
108
|
+
(0x40..0x7e) => [:collect, :DCS_PASSTHROUGH], # Changed CÖ so that the final character is collected
|
109
|
+
},
|
110
|
+
:DCS_PARAM => {
|
111
|
+
(0x00..0x17) => :ignore,
|
112
|
+
0x19 => :ignore,
|
113
|
+
(0x1c..0x1f) => :ignore,
|
114
|
+
(0x30..0x39) => :param,
|
115
|
+
0x3b => :param,
|
116
|
+
0x7f => :ignore,
|
117
|
+
0x3a => :DCS_IGNORE,
|
118
|
+
(0x3c..0x3f) => :DCS_IGNORE,
|
119
|
+
(0x20..0x2f) => [:collect, :DCS_INTERMEDIATE],
|
120
|
+
(0x40..0x7e) => [:collect, :DCS_PASSTHROUGH], # Changed CÖ so that the final character is collected
|
121
|
+
},
|
122
|
+
:DCS_INTERMEDIATE => {
|
123
|
+
(0x00..0x17) => :ignore,
|
124
|
+
0x19 => :ignore,
|
125
|
+
(0x1c..0x1f) => :ignore,
|
126
|
+
(0x20..0x2f) => :collect,
|
127
|
+
0x7f => :ignore,
|
128
|
+
(0x30..0x3f) => :DCS_IGNORE,
|
129
|
+
(0x40..0x7e) => [:collect, :DCS_PASSTHROUGH], # Changed CÖ so that the final character is collected
|
130
|
+
},
|
131
|
+
:DCS_PASSTHROUGH => {
|
132
|
+
:on_entry => :hook,
|
133
|
+
(0x00..0x17) => :put,
|
134
|
+
0x19 => :put,
|
135
|
+
(0x1c..0x1f) => :put,
|
136
|
+
(0x20..0x7e) => :put,
|
137
|
+
0x7f => :ignore,
|
138
|
+
:on_exit => :unhook,
|
139
|
+
},
|
140
|
+
:DCS_IGNORE => {
|
141
|
+
(0x00..0x17) => :ignore,
|
142
|
+
0x19 => :ignore,
|
143
|
+
(0x1c..0x1f) => :ignore,
|
144
|
+
(0x20..0x7f) => :ignore,
|
145
|
+
},
|
146
|
+
:OSC_STRING => {
|
147
|
+
:on_entry => :osc_start,
|
148
|
+
(0x00..0x17) => :ignore,
|
149
|
+
0x19 => :ignore,
|
150
|
+
(0x1c..0x1f) => :ignore,
|
151
|
+
(0x20..0x7f) => :osc_put,
|
152
|
+
:on_exit => :osc_end,
|
153
|
+
},
|
154
|
+
:SOS_PM_APC_STRING => {
|
155
|
+
(0x00..0x17) => :ignore,
|
156
|
+
0x19 => :ignore,
|
157
|
+
(0x1c..0x1f) => :ignore,
|
158
|
+
(0x20..0x7f) => :ignore,
|
159
|
+
},
|
160
|
+
}
|
161
|
+
|
162
|
+
@anywhere_transitions = {
|
163
|
+
0x18 => [:execute, :GROUND],
|
164
|
+
0x1a => [:execute, :GROUND],
|
165
|
+
(0x80..0x8f) => [:execute, :GROUND],
|
166
|
+
(0x91..0x97) => [:execute, :GROUND],
|
167
|
+
0x99 => [:execute, :GROUND],
|
168
|
+
0x9a => [:execute, :GROUND],
|
169
|
+
0x9c => :GROUND,
|
170
|
+
0x1b => :ESCAPE,
|
171
|
+
0x98 => :SOS_PM_APC_STRING,
|
172
|
+
0x9e => :SOS_PM_APC_STRING,
|
173
|
+
0x9f => :SOS_PM_APC_STRING,
|
174
|
+
0x90 => :DCS_ENTRY,
|
175
|
+
0x9d => :OSC_STRING,
|
176
|
+
0x9b => :CSI_ENTRY,
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
def build_state_transitions
|
181
|
+
@state_transitions = {}
|
182
|
+
@states.each do |state, transitions|
|
183
|
+
expanded_transitions = expand_transitions(transitions)
|
184
|
+
anywhere_transitions = expand_transitions(@anywhere_transitions)
|
185
|
+
merged_transitions = anywhere_transitions.merge(expanded_transitions) { |_, _, newval| newval }
|
186
|
+
on_entry = merged_transitions.delete(:on_entry)
|
187
|
+
on_exit = merged_transitions.delete(:on_exit)
|
188
|
+
@state_transitions[state] = {
|
189
|
+
transitions: merged_transitions,
|
190
|
+
on_entry: on_entry,
|
191
|
+
on_exit: on_exit,
|
192
|
+
}
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def expand_transitions(transitions)
|
197
|
+
expanded = {}
|
198
|
+
transitions.each do |key, value|
|
199
|
+
if key.is_a?(Range)
|
200
|
+
key.each do |k|
|
201
|
+
expanded[k] = value
|
202
|
+
end
|
203
|
+
else
|
204
|
+
expanded[key] = value
|
205
|
+
end
|
206
|
+
end
|
207
|
+
expanded
|
208
|
+
end
|
209
|
+
|
210
|
+
def do_state_change(ch)
|
211
|
+
|
212
|
+
state_info = @state_transitions[@state]
|
213
|
+
transitions = state_info[:transitions]
|
214
|
+
action_state = transitions[ch.ord]
|
215
|
+
|
216
|
+
action, new_state = nil, nil
|
217
|
+
|
218
|
+
if action_state
|
219
|
+
if action_state.is_a?(Array)
|
220
|
+
action = action_state[0]
|
221
|
+
new_state = action_state[1]
|
222
|
+
else
|
223
|
+
if @states.key?(action_state)
|
224
|
+
new_state = action_state
|
225
|
+
else
|
226
|
+
action = action_state
|
227
|
+
end
|
228
|
+
end
|
229
|
+
else
|
230
|
+
action = :ignore
|
231
|
+
end
|
232
|
+
# pp "before_state: #{@state} action_state: #{action_state} - ch: #{ch} ch0x: #{ch.ord.to_s(16)} - action: #{action} - new_state: #{new_state}"
|
233
|
+
# pp "action_state: #{action_state} - ch: #{ch}"
|
234
|
+
|
235
|
+
if new_state
|
236
|
+
on_exit = state_info[:on_exit]
|
237
|
+
handle_action(on_exit, nil) if on_exit
|
238
|
+
end
|
239
|
+
|
240
|
+
handle_action(action, ch) if action
|
241
|
+
|
242
|
+
if new_state
|
243
|
+
@state = new_state
|
244
|
+
new_state_info = @state_transitions[@state]
|
245
|
+
on_entry = new_state_info[:on_entry]
|
246
|
+
handle_action(on_entry, nil) if on_entry
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def handle_action(action, ch)
|
251
|
+
case action
|
252
|
+
when :execute, :print, :esc_dispatch, :csi_dispatch, :hook, :put, :unhook, :osc_start, :osc_put, :osc_end
|
253
|
+
@callback.call(action, ch, intermediate_chars, params) if @callback
|
254
|
+
when :ignore
|
255
|
+
# Do nothing
|
256
|
+
@callback.call(action, ch, intermediate_chars, params) if @callback
|
257
|
+
when :collect
|
258
|
+
unless @ignore_flagged
|
259
|
+
@intermediate_chars << ch
|
260
|
+
end
|
261
|
+
when :param
|
262
|
+
if ch == ';'
|
263
|
+
@params << 0
|
264
|
+
else
|
265
|
+
if @params.empty?
|
266
|
+
@params << 0
|
267
|
+
end
|
268
|
+
@params[-1] = @params[-1] * 10 + (ch.ord - '0'.ord)
|
269
|
+
end
|
270
|
+
when :clear
|
271
|
+
@intermediate_chars = ''
|
272
|
+
@params = []
|
273
|
+
@ignore_flagged = false
|
274
|
+
else
|
275
|
+
@callback.call(:error, ch, intermediate_chars, params) if @callback
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def self.to_ansi(action, ch, intermediate_chars, params)
|
280
|
+
|
281
|
+
case action
|
282
|
+
when :print, :execute, :put, :osc_put, :ignore
|
283
|
+
# Output the character
|
284
|
+
return ch if ch
|
285
|
+
when :hook
|
286
|
+
return "\eP#{intermediate_chars}"
|
287
|
+
when :esc_dispatch
|
288
|
+
return "\e#{intermediate_chars}#{ch}"
|
289
|
+
when :csi_dispatch
|
290
|
+
# Output ESC [ followed by parameters, intermediates, and final character
|
291
|
+
return "\e[#{params.join(';')}#{intermediate_chars}#{ch}"
|
292
|
+
when :osc_start
|
293
|
+
return "\e]"
|
294
|
+
when :osc_end
|
295
|
+
return "\x07" # BEL character to end OSC
|
296
|
+
when :unhook
|
297
|
+
return "" # \e must come from ESCAPE state
|
298
|
+
else
|
299
|
+
raise "Unknown action: #{action}"
|
300
|
+
end
|
301
|
+
|
302
|
+
raise
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|
data/lib/vtparser.rb
ADDED
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vtparser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Oezbek
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-10-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tty-prompt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rainbow
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: solargraph
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.40.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.40.0
|
69
|
+
description: A pure Ruby VT100 parser that can be used to parse ANSI escape sequences.
|
70
|
+
email:
|
71
|
+
- c.oezbek@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".bash_history"
|
77
|
+
- CHANGELOG.md
|
78
|
+
- README.md
|
79
|
+
- Rakefile
|
80
|
+
- examples/indent_cli.rb
|
81
|
+
- lib/vtparser.rb
|
82
|
+
- lib/vtparser/parser.rb
|
83
|
+
- lib/vtparser/version.rb
|
84
|
+
homepage: https://github.com/coezbek/vtparser
|
85
|
+
licenses: []
|
86
|
+
metadata:
|
87
|
+
allowed_push_host: https://rubygems.org
|
88
|
+
homepage_uri: https://github.com/coezbek/vtparser
|
89
|
+
source_code_uri: https://github.com/coezbek/vtparser
|
90
|
+
changelog_uri: https://github.com/coezbek/vtparser/CHANGELOG.md
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 3.0.0
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubygems_version: 3.4.19
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: Pure Ruby VT100 parser
|
110
|
+
test_files: []
|