vtparser 0.1.0 → 0.2.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
2
  SHA256:
3
- metadata.gz: d622edd5fbb0b4f47cb9831699c466aeabc3da9c6bed99370cc7d99d169c8c02
4
- data.tar.gz: 33eccc5b843d8c5d734a06d5b2b3d389462c23ea568bf9456ed55a38d6f1a50a
3
+ metadata.gz: b142e3d52113ff288e56ef70f3a948e71233e3dbf6dd52078c168b205c0f5c69
4
+ data.tar.gz: 5a76607662cc257ad2b963d2ea8d52d86c3f7e1e5176e9b289966c611d649cb0
5
5
  SHA512:
6
- metadata.gz: 0e5c6dd30582e24e0ad63b142446280b1be31d51cbae543b78c0019bf626ce2d477ea7bf002ab3707c7dd8056df886d33304eaa2a9509c30a9cac7ac6148e4b9
7
- data.tar.gz: ab1f60a0cdd8e079274bb8a7d6a285287b81a3fe1304462086ccdb71910fe09451faadaa4f3ce8935b6a63fdc579a856e069558e7183c8a7c659924e7ad32417
6
+ metadata.gz: e2861798a37ed651916d3bdd2c5a8c5e990ffc66a92c1e2b006bcfd75fe80e38288af7ca1118681a805573d2b9fb87f01bd1842f6e5232d7e599abc61d0c7255
7
+ data.tar.gz: 2f1b3fa73f48e839c818c0d433d2d42edc9caa1a9afff6eb4ea6e8e13fd0453405cf364a404b9605346e47a8a625f3c7bd38babe4c9434b629714aca8d331e9b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2024-10-03
4
+
5
+ - Add keyevent handling
6
+
3
7
  ## [0.1.0] - 2024-10-01
4
8
 
5
9
  - Initial release
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # VT 100 Parser Gem
2
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/.
3
+ This gem is a parser for VT100 terminal escape sequences. It is based on the C code from https://github.com/haberman/vtparse/ and implements the statemachine from https://www.vt100.net/emu/dec_ansi_parser.
4
+
5
+ The purpose of this Gem is to have a relatively easy way to filter/modify the output of child/sub-processes (for instance launched via `PTY::spawn`) which use animation or colors.
6
+
7
+ Uses keyboard mapping logic from https://github.com/vidarh/keyboard_map/
4
8
 
5
9
  ## Background on VT100 Escape Sequences
6
10
 
@@ -22,26 +26,39 @@ gem install vtparser
22
26
 
23
27
  ## Basic Usage
24
28
 
25
- See the minimal example below and the [`examples`](https://github.com/coezbek/vtparser/examples) directory for more examples.
29
+ See the minimal example below:
26
30
 
27
31
  ```ruby
28
- require 'vtparser'
32
+ require_relative '../lib/vtparser'
29
33
 
30
34
  # Instantiate the parser with a block to handle actions
31
35
  parser = VTParser.new do |action, ch, intermediate_chars, params|
32
36
 
33
37
  # For this minimal example, we'll just turn everything back strings to print
34
- print VtParser::to_ansi(action, ch, intermediate_chars, params)
38
+ print VTParser::to_ansi(action, ch, intermediate_chars, params)
35
39
 
36
40
  end
37
41
 
38
- # Sample input containing ANSI escape sequences
39
- input = "\e[31mHello, \e[1mWorld!\e[0m"
42
+ # Sample input containing ANSI escape sequences (red text, bold text)
43
+ input = "\e[31mHello, \e[1mWorld!\e[0m\n"
40
44
 
41
45
  # Parse the input
42
46
  parser.parse(input)
43
47
  ```
44
48
 
49
+ Further samples in the [`examples directory`](https://github.com/coezbek/vtparser/tree/main/examples):
50
+
51
+ - [`echo_keys.rb`](https://github.com/coezbek/vtparser/tree/main/examples/echo_keys.rb): Echoes the keys pressed by the user
52
+ - [`indent_cli.rb`](https://github.com/coezbek/vtparser/tree/main/examples/indent_cli.rb): Indents the output of simple command line tools
53
+
54
+ ## Limitations
55
+
56
+ - The parser is based on the implementation https://github.com/haberman/vtparse/ and based on a state machine which precedes Unicode. As such it does not have state transitions for Unicode characters. Rather, it will output them as `:ignore` actions. In case unicode characters are used inside escape sequences, the parser will likely not be able to handle them correctly.
57
+
58
+ - The state machine does not expose all input characters to the implementation in relationship to the `DSC` (Device Control String) sequences. In particular the "Final Character" is swallowed by the statemachine from https://www.vt100.net/emu/dec_ansi_parser. To circumvent this limitation, I have modified the parser to expose the final character as intermediate_chars to the `:hook` action.
59
+
60
+ - The parser only outputs full `actions`. So triggering an event for the `ESC` key doesn't work (as expected).
61
+
45
62
  ## Development
46
63
 
47
64
  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.
@@ -0,0 +1,27 @@
1
+ require 'io/console'
2
+ require_relative '../lib/vtparser'
3
+
4
+ #
5
+ # Example for how to switch to raw mode to output infos about each keypress
6
+ #
7
+ STDIN.raw do |io|
8
+
9
+ parser = VTParser.new do |action, ch, intermediate_chars, params|
10
+
11
+ puts " New VTParser action: #{action}, ch: #{ch.inspect}, ch0x: #{ch.ord.to_s(16)}, intermediate_chars: #{intermediate_chars}, params: #{params}\r\n"
12
+
13
+ parser.to_key(action, ch, intermediate_chars, params) do |event|
14
+
15
+ puts " Keyevent: #{event.to_sym.inspect} #{event.inspect}\r\n"
16
+ exit(1) if event.to_sym == :ctrl_c
17
+
18
+ end
19
+ end
20
+
21
+ loop do
22
+ ch = $stdin.getch
23
+
24
+ puts "Getch: #{ch.inspect}\r\n"
25
+ parser.parse ch
26
+ end
27
+ end
@@ -4,6 +4,19 @@ require 'rainbow/refinement' # for colorizing output
4
4
  using Rainbow
5
5
  require_relative '../lib/vtparser'
6
6
 
7
+ #
8
+ # 'indent_cli.rb' - Example for vtparser
9
+ #
10
+ # This example demonstrates how to use the VTParser to indent the output of simple (!) tty programs
11
+ # with colorized or animated output.
12
+ #
13
+ # Run with `ruby indent_cli.rb <command>`` where <command> is the command you want to run.
14
+ #
15
+ # Two simple examples are included:
16
+ # - A simple spinner animation is included in `examples/spinner.rb`: `ruby indent_cli.rb 'ruby spinner.rb'`
17
+ # - A simple progress bar animation is included in `examples/progress.rb`: `ruby indent_cli.rb 'ruby progress.rb'`
18
+ #
19
+
7
20
  # Get the command from ARGV
8
21
  command = ARGV.join(' ')
9
22
  if command.empty?
@@ -12,13 +25,22 @@ if command.empty?
12
25
  end
13
26
 
14
27
  line_indent = ' ▐ '.yellow
28
+ line_indent_length = 6
29
+
30
+ #
31
+ # Use VTParser to process the VT100 escape sequences outputted by nested program and prepend the line_indent text.
32
+ #
15
33
  first_line = true
16
34
  parser = VTParser.new do |action, ch, intermediate_chars, params|
17
35
  print line_indent if first_line
18
36
  first_line = false
19
37
 
38
+ if $DEBUG && (action != :print || !(ch =~ /\P{Cc}/))
39
+ puts "action: #{action}, ch: #{ch.inspect}, ch0x: 0x#{ "%02x" % ch.ord}, intermediate_chars: #{intermediate_chars}, params: #{params}"
40
+ end
20
41
  to_output = VTParser::to_ansi(action, ch, intermediate_chars, params)
21
42
 
43
+ # Handle newlines, carriage returns, and cursor movement
22
44
  case action
23
45
  when :print, :execute, :put, :osc_put
24
46
  if ch == "\n" || ch == "\r"
@@ -27,16 +49,13 @@ parser = VTParser.new do |action, ch, intermediate_chars, params|
27
49
  next
28
50
  end
29
51
  when :csi_dispatch
30
- if to_output == "\e[2K"
52
+ if to_output == "\e[2K" # Clear line
31
53
  print "\e[2K"
32
54
  print line_indent
33
55
  next
34
56
  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
-
57
+ if ch == 'G' # Cursor movement to column
58
+ print "\e[#{parser.params[0] + line_indent_length}G"
40
59
  next
41
60
  end
42
61
  end
@@ -45,9 +64,13 @@ parser = VTParser.new do |action, ch, intermediate_chars, params|
45
64
  print to_output
46
65
  end
47
66
 
67
+ #
68
+ # Spawn the given command using PTY::spawn, and connect pipes.
69
+ #
48
70
  begin
49
71
  PTY.spawn(command) do |stdout_and_stderr, stdin, pid|
50
72
 
73
+ # Start separate thread to pipe stdin to the child process
51
74
  Thread.new do
52
75
  while pid != nil
53
76
  stdin.write(STDIN.readpartial(1024)) # Requires user to press enter!
@@ -57,8 +80,12 @@ begin
57
80
  exit(0)
58
81
  end
59
82
 
83
+ # Pipe stdout and stderr to the parser
60
84
  begin
61
- stdout_and_stderr.winsize = $stdout.winsize
85
+ # Ensure the child process has the proper window size, because
86
+ # - tools such as yarn use it to identify tty mode
87
+ # - some tools use it to determine the width of the terminal for formatting
88
+ stdout_and_stderr.winsize = [$stdout.winsize.first, $stdout.winsize.last - line_indent_length]
62
89
 
63
90
  stdout_and_stderr.each_char do |char|
64
91
 
@@ -73,7 +100,7 @@ begin
73
100
  Process.wait(pid)
74
101
  pid = nil
75
102
  exit_status = $?.exitstatus
76
- result = exit_status == 0
103
+ # result = exit_status == 0
77
104
 
78
105
  # Clear the line, reset the cursor to the start of the line
79
106
  print "\e[2K\e[1G"
@@ -0,0 +1,15 @@
1
+ require_relative '../lib/vtparser'
2
+
3
+ # Instantiate the parser with a block to handle actions
4
+ parser = VTParser.new do |action, ch, intermediate_chars, params|
5
+
6
+ # For this minimal example, we'll just turn everything back strings to print
7
+ print VTParser::to_ansi(action, ch, intermediate_chars, params)
8
+
9
+ end
10
+
11
+ # Sample input containing ANSI escape sequences (red text, bold text)
12
+ input = "\e[31mHello, \e[1mWorld!\e[0m\n"
13
+
14
+ # Parse the input
15
+ parser.parse(input)
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Helper script to be used to demonstrate `indent_cli.rb`. It displays a full-width animated progress bar.
5
+ #
6
+
7
+ require 'ruby-progressbar'
8
+
9
+ loop do
10
+ progressbar = ProgressBar.create
11
+ 99.times {
12
+ progressbar.increment
13
+ sleep 0.02
14
+ }
15
+ print "\r"
16
+ end
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Helper script to be used to demonstrate `indent_cli.rb`
5
+ #
6
+
7
+ # See: https://github.com/sindresorhus/cli-spinners/blob/main/spinners.json
8
+ frames = [
9
+ "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"
10
+ ]
11
+ interval = 0.08 # 80 milliseconds
12
+
13
+ # Infinite loop to display the animation until interrupted
14
+ loop do
15
+ frames.each do |frame|
16
+ print "\r #{frame} " # "\r" moves the cursor back to the start of the line
17
+ sleep(interval)
18
+ end
19
+ end
@@ -0,0 +1,177 @@
1
+ require 'set'
2
+
3
+ #
4
+ # Logic taken from vidarh/keyboard_map gem
5
+ #
6
+ # https://github.com/vidarh/keyboard_map
7
+ #
8
+ # See examples/keymap.rb for usage
9
+ #
10
+
11
+ class KeyEvent
12
+ attr_reader :modifiers, :key, :args
13
+
14
+ def initialize(key, *modifiers, args: nil)
15
+ @key = key
16
+ @args = args
17
+ @modifiers = modifiers.map(&:to_sym).to_set
18
+ end
19
+
20
+ def to_s
21
+ (modifiers.to_a.sort << key).join('_')
22
+ end
23
+
24
+ def to_sym
25
+ to_s.to_sym
26
+ end
27
+
28
+ def ==(other)
29
+ case other
30
+ when KeyEvent
31
+ self.modifiers == other.modifiers && self.key == other.key
32
+ when Symbol
33
+ self.to_sym == other
34
+ else
35
+ self.to_s == other
36
+ end
37
+ end
38
+ end
39
+
40
+ module Keymap
41
+
42
+ SINGLE_KEY_EVENT = {
43
+ "\t" => :tab,
44
+ "\r" => :enter,
45
+ "\n" => :enter,
46
+ "\u007F" => :backspace
47
+ }.freeze
48
+
49
+ CSI_BASIC_MAP = {
50
+ "A" => :up,
51
+ "B" => :down,
52
+ "C" => :right,
53
+ "D" => :left,
54
+ "E" => :keypad_5,
55
+ "F" => :end,
56
+ "H" => :home,
57
+ }.freeze
58
+
59
+ CSI_TILDE_MAP = {
60
+ "1" => :home,
61
+ "2" => :insert,
62
+ "3" => :delete,
63
+ "4" => :end,
64
+ "5" => :page_up,
65
+ "6" => :page_down,
66
+ "15" => :f5,
67
+ "17" => :f6,
68
+ "18" => :f7,
69
+ "19" => :f8,
70
+ "20" => :f9,
71
+ "21" => :f10,
72
+ "23" => :f11,
73
+ "24" => :f12,
74
+ }.freeze
75
+
76
+ SS3_KEY_MAP = {
77
+ "P" => :f1,
78
+ "Q" => :f2,
79
+ "R" => :f3,
80
+ "S" => :f4,
81
+ }.freeze
82
+
83
+ def map_modifiers(mod)
84
+ return [] if mod.nil? || mod < 2
85
+ modifiers = []
86
+ mod = mod - 1 # Subtract 1 to align with modifier bits
87
+ modifiers << :shift if mod & 1 != 0
88
+ modifiers << :alt if mod & 2 != 0
89
+ modifiers << :ctrl if mod & 4 != 0
90
+ modifiers
91
+ end
92
+
93
+ def to_key(action, ch, intermediate_chars, params, &block)
94
+
95
+ case action
96
+ when :execute, :print, :ignore
97
+ # Control characters (e.g., Ctrl+C)
98
+ key = map_control_character(ch)
99
+ yield key if key
100
+ #when :print, :ignore
101
+ # Regular printable characters
102
+ #yield KeyboardEvent.new(ch)
103
+ when :esc_dispatch
104
+ # ESC sequences without intermediates
105
+ if intermediate_chars == ''
106
+ key = process_esc_sequence(ch)
107
+ yield key if key
108
+ else
109
+ # Handle other ESC sequences if necessary
110
+ end
111
+ when :csi_dispatch
112
+ key = process_csi_sequence(params, intermediate_chars, ch)
113
+ yield key if key
114
+ when :collect, :param, :clear
115
+ # Handled internally; no action needed here
116
+ else
117
+ # Handle other actions if necessary
118
+ end
119
+ end
120
+
121
+ def map_control_character(ch)
122
+ if SINGLE_KEY_EVENT.key?(ch)
123
+ return KeyboardEvent.new(SINGLE_KEY_EVENT[ch])
124
+ elsif ch.ord.between?(0x01, 0x1A)
125
+ # Ctrl+A to Ctrl+Z
126
+ key = (ch.ord + 96).chr
127
+ return KeyboardEvent.new(key, :ctrl)
128
+ else
129
+ return KeyboardEvent.new(ch)
130
+ end
131
+ end
132
+
133
+ def process_esc_sequence(final_char)
134
+ case final_char
135
+ when 'Z'
136
+ # Shift+Tab
137
+ return KeyboardEvent.new(:tab, :shift)
138
+ when "\e"
139
+ # Double ESC
140
+ return KeyboardEvent.new(:esc)
141
+ else
142
+ # Meta key (Alt) combinations
143
+ if final_char.ord.between?(0x20, 0x7E)
144
+ return KeyboardEvent.new(final_char, :meta)
145
+ else
146
+ # Handle other ESC sequences if necessary
147
+ end
148
+ end
149
+ end
150
+
151
+ def process_csi_sequence(params, intermediate_chars, final_char)
152
+ key = nil
153
+ modifiers = []
154
+ params = params.map(&:to_i)
155
+
156
+ if intermediate_chars == ''
157
+ if final_char == '~'
158
+ # Sequences like ESC [ 1 ~
159
+ key = CSI_TILDE_MAP[params[0].to_s]
160
+ modifiers = map_modifiers(params[1]) if params.size > 1
161
+ else
162
+ # Sequences like ESC [ A
163
+ key = CSI_BASIC_MAP[final_char]
164
+ modifiers = map_modifiers(params[0]) if params.size > 0
165
+ end
166
+ else
167
+ # Handle intermediates if necessary
168
+ end
169
+
170
+ if key
171
+ return KeyboardEvent.new(key, *modifiers)
172
+ else
173
+ # Handle unrecognized sequences
174
+ end
175
+ end
176
+
177
+ end
@@ -1,6 +1,10 @@
1
+ require_relative "keymap"
2
+
1
3
  class VTParser
2
4
  attr_reader :intermediate_chars, :params
3
5
 
6
+ include Keymap
7
+
4
8
  def initialize(&block)
5
9
  @callback = block
6
10
  @state = :GROUND
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vtparser
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vtparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Oezbek
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-01 00:00:00.000000000 Z
11
+ date: 2024-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-prompt
@@ -58,14 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.40.0
61
+ version: '0.40'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.40.0
68
+ version: '0.40'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ruby-progressbar
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: A pure Ruby VT100 parser that can be used to parse ANSI escape sequences.
70
84
  email:
71
85
  - c.oezbek@gmail.com
@@ -73,12 +87,16 @@ executables: []
73
87
  extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
76
- - ".bash_history"
77
90
  - CHANGELOG.md
78
91
  - README.md
79
92
  - Rakefile
93
+ - examples/echo_keys.rb
80
94
  - examples/indent_cli.rb
95
+ - examples/minimal.rb
96
+ - examples/progress.rb
97
+ - examples/spinner.rb
81
98
  - lib/vtparser.rb
99
+ - lib/vtparser/keymap.rb
82
100
  - lib/vtparser/parser.rb
83
101
  - lib/vtparser/version.rb
84
102
  homepage: https://github.com/coezbek/vtparser
@@ -103,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
121
  - !ruby/object:Gem::Version
104
122
  version: '0'
105
123
  requirements: []
106
- rubygems_version: 3.4.19
124
+ rubygems_version: 3.5.20
107
125
  signing_key:
108
126
  specification_version: 4
109
127
  summary: Pure Ruby VT100 parser
data/.bash_history DELETED
@@ -1,117 +0,0 @@
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'