vtparser 0.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 +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: []
|