yap-shell 0.4.11 → 0.5.1

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
  SHA1:
3
- metadata.gz: ee4c5a9db5dfeed5f41bd1290156f31f8ca44e4b
4
- data.tar.gz: 1ed5589d2dcdca412258a4f6fdda94a0fdb07d5c
3
+ metadata.gz: 0dd93a58914bed99609652e05c82c3f90fb11af3
4
+ data.tar.gz: 685276b3f2f829e8252c82490c30cb443bde61b9
5
5
  SHA512:
6
- metadata.gz: 169bcecab87f1ad1f7e96faa6609659272952d08e75a055ad207bd7bf806b85a0607115800733b2ee8ddb9a3271b550b363b1c1f4a7036969d41dd6447cb0a28
7
- data.tar.gz: 6204437dd12169220a819d23528f8f0b77eb87133157da2211a5a65af9514230913b66e6f2d9ef0d6bed14db64542fdba567e82a694523bd88e228c7bd9f0a6a
6
+ metadata.gz: 580220fe950fbc8cb393f1b783315a2af677177907951851b0d9c44ef7d9e7dd05f6dc0fea2aec3b436e2f187d0e27ca96a3b28449781c99a92689d405b90108
7
+ data.tar.gz: d037e820050e596a596891133b1bf18736ea9953850978d736505f6f32eee67e1b6e017d529a2dd9860ca69373b7b4006faa09aa953c18fd72816a4d80b4265e
data/Gemfile CHANGED
@@ -2,7 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in yap.gemspec
4
4
  gemspec
5
+ # gem 'terminal-layout', path: "../terminal-layout"
5
6
  # gem 'yap-shell-parser', path: "../yap-shell-parser"
6
7
  # gem 'yap-shell-parser', git: 'git@github.com:zdennis/yap-shell-parser.git'
7
- # gem "rawline", git: 'git@github.com:zdennis/rawline.git', branch: 'issues/input-issues'
8
- # gem "rawline", path: '/Users/zdennis/source/opensource_projects/rawline'
8
+ # gem "yap-rawline", path: '/Users/zdennis/source/opensource_projects/rawline'
9
+ # gem "terminal-layout", path: '/Users/zdennis/source/playground/terminal-layout'
@@ -0,0 +1,193 @@
1
+ class HistorySearch < Addon
2
+ attr_reader :editor
3
+
4
+ def initialize_world(world)
5
+ @editor = world.editor
6
+ end
7
+
8
+ def prompt_user_to_search
9
+ label_text = "(reverse-search): "
10
+ search_label = ::TerminalLayout::Box.new(
11
+ content: label_text,
12
+ style: {
13
+ display: :inline,
14
+ height: 1
15
+ }
16
+ )
17
+ search_box = ::TerminalLayout::InputBox.new(
18
+ content: "",
19
+ style: {
20
+ display: :inline,
21
+ height: 1
22
+ }
23
+ )
24
+ search_box.name = "focused-input-box"
25
+
26
+ Treefell['shell'].puts "editor.content_box.children: #{editor.content_box.children.inspect}"
27
+ history_search_env = editor.new_env
28
+ history_search = Search.new(editor.history,
29
+ line: ::RawLine::LineEditor.new(::RawLine::Line.new, sync_with: -> { search_box }),
30
+ keys: history_search_env.keys,
31
+ search: -> (term:, result:){
32
+ # when there is no match, result will be nil, #to_s clears out the content
33
+ editor.input_box.content = result.to_s
34
+ },
35
+ done: -> (execute:, result:){
36
+ editor.content_box.children = []
37
+ editor.pop_env
38
+ editor.focus_input_box(editor.input_box)
39
+ editor.overwrite_line(result.to_s)
40
+ editor.process_line if execute
41
+ }
42
+ )
43
+
44
+ editor.push_env history_search_env
45
+ editor.push_keyboard_input_processor(history_search)
46
+
47
+ editor.content_box.children = [search_label, search_box]
48
+ editor.focus_input_box(search_box)
49
+ end
50
+
51
+ class Search
52
+ attr_reader :keys
53
+
54
+ def initialize(history, keys:, line:, search:, done:)
55
+ @history = history
56
+ @keys = keys
57
+ @line = line
58
+ @search_proc = search || -> {}
59
+ @done_proc = done || -> {}
60
+
61
+ initialize_key_bindings
62
+ end
63
+
64
+ def initialize_key_bindings
65
+ @keys.bind(:return){ execute }
66
+ @keys.bind(:ctrl_j){ accept }
67
+ @keys.bind(:ctrl_r){ search_again_backward }
68
+ @keys.bind(:ctrl_n){ search_again_forward }
69
+ @keys.bind(:ctrl_a){ @line.move_to_beginning_of_input }
70
+ @keys.bind(:ctrl_e){ @line.move_to_end_of_input }
71
+ @keys.bind(:backspace) do
72
+ @line.delete_left_character
73
+ perform_search(type: @last_search_was)
74
+ end
75
+ @keys.bind(:escape){ cancel }
76
+ @keys.bind(:ctrl_c){ cancel }
77
+ end
78
+
79
+ def read_bytes(bytes)
80
+ if bytes.any?
81
+ Treefell['shell'].puts "history search found bytes: #{bytes.inspect}"
82
+
83
+ # [1,2,3] => try 1,2,3 first ,then 1,2, then 1, then move on
84
+ nbytes = bytes.dup
85
+ search_bytes = []
86
+ loop do
87
+ if nbytes.empty?
88
+ break
89
+ elsif @keys[nbytes]
90
+ Treefell['shell'].puts "history search found key-binding for bytes=#{nbytes.inspect}"
91
+ @keys[nbytes].call
92
+ nbytes = search_bytes
93
+ search_bytes = []
94
+ else
95
+ search_bytes.unshift nbytes[-1]
96
+ nbytes = nbytes[0..-2]
97
+ end
98
+ end
99
+
100
+ if search_bytes.any?
101
+ Treefell['shell'].puts "history searching with bytes=#{bytes.inspect}"
102
+ search_with_bytes(bytes)
103
+ end
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ def accept
110
+ @done_proc.call(execute: false, result: result)
111
+ end
112
+
113
+ def cancel
114
+ @done_proc.call(execute: false, result: result)
115
+ end
116
+
117
+ def execute
118
+ @done_proc.call(execute: true, result: result)
119
+ end
120
+
121
+ def found_match(result:)
122
+ @search_proc.call(term: @line.text, result: result)
123
+ end
124
+
125
+ def no_match_found
126
+ @last_match_index = nil
127
+ @search_proc.call(term: @line.text, result: result)
128
+ end
129
+
130
+ def result
131
+ @history2search[@last_match_index] if @last_match_index
132
+ end
133
+
134
+ def search_again_backward
135
+ Treefell['shell'].puts "history searching again backward"
136
+ if @last_search_was == :forward
137
+ @last_match_index = @history.length - @last_match_index - 1
138
+ @history2search = @history.reverse
139
+ end
140
+ perform_search(starting_index: @last_match_index, type: :backward)
141
+ end
142
+
143
+ def search_again_forward
144
+ Treefell['shell'].puts "history searching again forward"
145
+ if @last_search_was == :backward
146
+ @last_match_index = @history.length - @last_match_index - 1
147
+ @history2search = @history
148
+ end
149
+ perform_search(starting_index: @last_match_index, type: :forward)
150
+ end
151
+
152
+ def search_with_bytes(bytes)
153
+ part = bytes.map(&:chr).join
154
+ @line.write(part.scan(/[[:print:]]/).join)
155
+ @history2search = @history.reverse
156
+ perform_search(type: :backward)
157
+ end
158
+
159
+ def perform_search(starting_index: -1, type:)
160
+ if @line.text.empty?
161
+ no_match_found
162
+ return
163
+ end
164
+
165
+ # fuzzy search
166
+ characters = @line.text.split('').map { |ch| Regexp.escape(ch) }
167
+ fuzzy_search_regex = /#{characters.join('.*?')}/
168
+
169
+ # non-fuzzy-search
170
+ # fuzzy_search_regex = /#{Regexp.escape(@line.text)}/
171
+
172
+ Treefell['shell'].puts "history search matching on regex=#{fuzzy_search_regex.inspect} starting_index=#{starting_index}"
173
+ @last_search_was = type
174
+
175
+ match = @history2search.detect.with_index do |item, i|
176
+ next if i <= starting_index
177
+
178
+ # Treefell['shell'].puts "history search matching #{(item + @line.text).inspect} =~ #{fuzzy_search_regex}"
179
+ md = (item + @line.text).match(fuzzy_search_regex)
180
+ if md && md.end(0) <= item.length
181
+ # Treefell['shell'].puts "history search match #{item} at #{i}"
182
+ @last_match_index = i
183
+ end
184
+ end
185
+
186
+ if match
187
+ found_match(result: match)
188
+ else
189
+ no_match_found
190
+ end
191
+ end
192
+ end
193
+ end
@@ -89,7 +89,7 @@ class KeyboardMacros < Addon
89
89
  configuration.start.call if configuration.start
90
90
 
91
91
  debug_log "taking over keyboard input processing from editor"
92
- world.editor.keyboard_input_processors.push(self)
92
+ world.editor.push_keyboard_input_processor(self)
93
93
 
94
94
  wait_timeout_in_seconds = 0.1
95
95
  world.editor.input.wait_timeout_in_seconds = wait_timeout_in_seconds
@@ -195,9 +195,9 @@ class KeyboardMacros < Addon
195
195
  definition.configuration.stop.call if definition.configuration.stop
196
196
  end
197
197
  @stack.clear
198
- if world.editor.keyboard_input_processors.last == self
198
+ if world.editor.keyboard_input_processor == self
199
199
  debug_log "giving keyboard input processing control back"
200
- world.editor.keyboard_input_processors.pop
200
+ world.editor.pop_keyboard_input_processor
201
201
 
202
202
  debug_log "restoring default editor input timeout"
203
203
  world.editor.input.restore_default_timeout
@@ -6,12 +6,14 @@ class RightPrompt < Addon
6
6
  def initialize_world(world)
7
7
  @world = world
8
8
 
9
- # @world.subscribe(:refresh_right_prompt) do |event|
10
- # @world.right_prompt_text = Time.now.strftime("%H:%M:%S")
11
- # end
12
- #
13
- # @world.events.recur(
14
- # name: "refresh_right_prompt", source: self, interval_in_ms: 1_000
15
- # )
9
+ @world.subscribe(:refresh_right_prompt) do |event|
10
+ @world.right_prompt_text = Time.now.strftime("%H:%M:%S")
11
+ end
12
+
13
+ @world.events.recur(
14
+ name: "refresh_right_prompt",
15
+ interval_in_ms: 1_000,
16
+ source: self
17
+ )
16
18
  end
17
19
  end
@@ -1,28 +1,29 @@
1
- class PromptUpdates < Addon
2
- attr_reader :world
3
-
4
- def initialize_world(world)
5
- current_branch = determine_branch
6
-
7
- @world = world
8
- @world.events.recur(
9
- name: 'prompt_updates',
10
- source: self,
11
- interval_in_ms: 100
12
- ) do
13
- new_branch = determine_branch
14
- if current_branch != new_branch
15
- current_branch = new_branch
16
- @world.refresh_prompt
17
- end
18
- end
19
1
 
20
- end
21
2
 
22
- private
3
+ class PromptUpdates < Addon
4
+ def initialize_world(world)
5
+ @world = world
6
+
7
+ current_branch = determine_branch
23
8
 
24
- def determine_branch
25
- `git branch 2>/dev/null`.scan(/\*\s*(.*)$/).flatten.first
26
- end
9
+ @world.events.recur(
10
+ name: 'prompt_updates',
11
+ source: self,
12
+ interval_in_ms: 100
13
+ ) do
14
+ new_branch = determine_branch
15
+ if current_branch != new_branch
16
+ current_branch = new_branch
17
+ @world.refresh_prompt
18
+ end
19
+ end
20
+
21
+ end
27
22
 
28
- end
23
+ private
24
+
25
+ def determine_branch
26
+ `git branch 2>/dev/null`.scan(/\*\s*(.*)$/).flatten.first
27
+ end
28
+
29
+ end
data/bin/yap CHANGED
@@ -1,20 +1,35 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- if ENV["YAP_SHELL"].nil?
3
+ if ENV['YAP_SHELL'] != 'active'
4
4
  # Start YAP with a pristine environment
5
5
  env2keep = {
6
- 'PATH' => ENV['PATH'],
6
+ # DISPLAY needs to be inherited in order to launch GUI apps
7
+ 'DISPLAY' => ENV['DISPLAY'],
7
8
  'HOME' => ENV['HOME'],
9
+ 'PATH' => ENV['PATH'],
10
+
11
+ # For Yap's sanity
8
12
  'RUBYOPT' => '-rubygems -EUTF-8',
9
- 'TREEFELL_OUT' => ENV['TREEFELL_OUT'],
13
+ 'YAP_SHELL' => 'active',
14
+
15
+ # Inherit the user's preferred shell
16
+ 'SHELL' => ENV['SHELL'],
17
+
18
+ # Necessary for ssh-agent
19
+ 'SSH_AUTH_SOCK' => ENV['SSH_AUTH_SOCK'],
20
+
21
+ # DEBUG/TREEFELL_OUT are for debuging yap itself
10
22
  'DEBUG' => ENV['DEBUG'],
11
- 'YAP_SHELL' => 'active'
23
+ 'TREEFELL_OUT' => ENV['TREEFELL_OUT']
12
24
  }
25
+
26
+ ENV.clear
13
27
  env_params = env2keep.each_with_object([]) do |(key,value),arr|
14
28
  next if value.nil?
15
29
  arr << %|#{key}="#{value}"|
16
30
  end.join(' ')
17
- cmd = %|env -i #{env_params} #{$0}|
31
+
32
+ cmd = %|env -i #{env_params} #{File.expand_path(__FILE__)}|
18
33
  exec cmd
19
34
  else
20
35
  file = __FILE__
@@ -30,18 +45,10 @@ else
30
45
  $LOAD_PATH.unshift File.dirname(file) + '/../lib'
31
46
 
32
47
  ENV['TERM'] ||= 'linux'
33
-
34
- # Delete all RBENV/RVM environment variables
35
- # Once we're booted, we don't want them being inherited
36
- # by other child processes since those children cannot
37
- # modify Yap's ENV, only their own child env.
38
- ENV.keys.each do |key|
39
- if key =~ /^(rbenv_|rvm_)/i
40
- ENV.delete(key)
41
- end
42
- end
48
+ ENV['YAP_SHELL'] = 'active'
43
49
 
44
50
  require "term/ansicolor"
51
+ require "tins"
45
52
  require "byebug"
46
53
  require "pry"
47
54
  require "yap"
@@ -1,4 +1,50 @@
1
1
  namespace :addons do
2
+ task :new do
3
+ require 'highline'
4
+ require 'term/ansicolor'
5
+ require 'pathname'
6
+
7
+ extend Term::ANSIColor
8
+
9
+ yap_path = Pathname.new(File.dirname(__FILE__)).join('../..')
10
+ yap_lib_path = yap_path.join('lib')
11
+ yap_addons_path = yap_path.join('addons')
12
+
13
+ $LOAD_PATH.unshift yap_lib_path
14
+ require 'yap'
15
+
16
+ cli = HighLine.new
17
+ answer = cli.ask("Name for the addon? ")
18
+
19
+ addon_name = answer.downcase.gsub(/\W+/, '_')
20
+ addon_class_name = addon_name.split('_').map(&:capitalize).join
21
+ addon_path = yap_addons_path.join(addon_name)
22
+
23
+ loop do
24
+ answer = cli.ask("Create #{addon_class_name} addon in #{addon_path}? [Yn] ")
25
+ break if answer =~ /y/i
26
+ exit 1 if answer =~ /n/i
27
+ end
28
+ puts "Generating #{addon_class_name}"
29
+ puts
30
+
31
+ print " Creating #{addon_path} "
32
+ FileUtils.mkdir_p addon_path
33
+ puts green('done')
34
+
35
+ addon_file = addon_path.join("#{addon_name}.rb")
36
+ print " Creating #{addon_file} "
37
+ File.write addon_file, <<-FILE.gsub(/^\s*\|/, '')
38
+ |class #{addon_class_name} < Addon
39
+ | def initialize_world(world)
40
+ | # initialization code here
41
+ | end
42
+ |end
43
+ FILE
44
+ puts green('done')
45
+ puts
46
+ end
47
+
2
48
  namespace :update do
3
49
  desc "Update the gemspec based on add-on specific dependnecies"
4
50
  task :gemspec do
@@ -172,6 +172,7 @@ module Yap::Shell
172
172
  }
173
173
 
174
174
  if node.params.any?
175
+ Treefell['shell'].puts "block node params: #{node.params.inspect}"
175
176
  values.each_slice(node.params.length).each do |_slice|
176
177
  with_env do
177
178
  Hash[ node.params.zip(_slice) ].each_pair do |k,v|
@@ -44,6 +44,16 @@ module Yap::Shell::Execution
44
44
  begin
45
45
  before = ENV.to_h.dup
46
46
  ENV.replace(@world.env)
47
+ Treefell['shell'].puts <<-MSG.gsub(/^\s*\|/, '')
48
+ |forked child process
49
+ | pid=#{Process.pid} #{command.to_executable_str}
50
+ | stdin=#{stdin.inspect}
51
+ | stdout=#{stdout.inspect}
52
+ | stderr=#{stderr.inspect}
53
+ | $stdin=#{$stdin.inspect}
54
+ | $stdout=#{$stdout.inspect}
55
+ | $stderr=#{$stderr.inspect}
56
+ MSG
47
57
  Kernel.exec command.to_executable_str
48
58
  ensure
49
59
  ENV.replace(before)
@@ -6,7 +6,7 @@ module Yap::Shell::Execution
6
6
  possible_parameters = {
7
7
  command: command.str,
8
8
  args: command.args,
9
- stdin: @stdin,
9
+ stdin: (@stdin != $stdin ? @stdin : StringIO.new),
10
10
  stdout: @stdout,
11
11
  stderr: @stderr,
12
12
  world: @world,
@@ -19,10 +19,12 @@ module Yap::Shell::Execution
19
19
  h
20
20
  end
21
21
 
22
- Treefell['shell'].puts "shell command executing with params: #{params.inspect}"
23
- command_result = func.call(**params)
22
+ Treefell['shell'].puts "shell command executing with params: #{params.inspect} $stdout=#{$stdout.inspect} $stderr=#{$stderr.inspect}"
23
+ func.call(**params)
24
+
24
25
  @stdout.close if @stdout != $stdout && !@stdout.closed?
25
26
  @stderr.close if @stderr != $stderr && !@stderr.closed?
27
+ @stdin.close if @stdin != $stdin && !@stdin.closed?
26
28
  end
27
29
  end
28
30
  end
@@ -30,7 +30,6 @@ module Yap::Shell
30
30
  line = line_read << "\n"
31
31
  begin
32
32
  @blk.call(line)
33
- @world.editor.redraw_prompt
34
33
  rescue Yap::Shell::Parser::Lexer::NonterminatedString,
35
34
  Yap::Shell::Parser::Lexer::LineContinuationFound => ex
36
35
  Treefell['shell'].puts "rescued #{ex}, asking user for more input"
@@ -1,5 +1,5 @@
1
1
  module Yap
2
2
  module Shell
3
- VERSION = "0.4.11"
3
+ VERSION = "0.5.1"
4
4
  end
5
5
  end
@@ -98,12 +98,12 @@ module Yap
98
98
  attr_reader :file
99
99
 
100
100
  def initialize(file)
101
- @file = file
101
+ @file = File.expand_path(file)
102
102
  end
103
103
 
104
104
  def initialize_world(world)
105
105
  Treefell['shell'].puts "initializing rcfile: #{file}"
106
- world.instance_eval File.read(@file)
106
+ world.instance_eval File.read(@file), @file
107
107
  end
108
108
  end
109
109
 
data/lib/yap/world.rb CHANGED
@@ -129,7 +129,17 @@ module Yap
129
129
  evaluation.evaluate(statement) do |command, stdin, stdout, stderr, wait|
130
130
  context.clear_commands
131
131
  context.add_command_to_run command, stdin:stdin, stdout:stdout, stderr:stderr, wait:wait
132
- @last_result = context.execute(world:self)
132
+ @last_result = context.execute(world:self) || 0
133
+ if @last_result.is_a?(Integer)
134
+ Yap::Shell::Execution::Result.new(
135
+ status_code: @last_result,
136
+ directory: Dir.pwd,
137
+ n: 1,
138
+ of: 1
139
+ )
140
+ else
141
+ @last_result
142
+ end
133
143
  end
134
144
  end
135
145
 
@@ -224,6 +234,9 @@ module Yap
224
234
  dom.prompt_box = @prompt_box
225
235
  dom.input_box = @input_box
226
236
  dom.content_box = @content_box
237
+ @prompt_box.name = "prompt-box"
238
+ @input_box.name = "input-box"
239
+ @content_box.name = "content-box"
227
240
  end
228
241
  end
229
242
  end
data/rcfiles/yaprc CHANGED
@@ -155,6 +155,10 @@ world.editor.bind(:alt_down_arrow) do
155
155
  keyboard_macros.cycle(:recent_git_branches).previous
156
156
  end
157
157
 
158
+ world.editor.bind(:ctrl_r) do
159
+ world.addons[:history_search].prompt_user_to_search
160
+ end
161
+
158
162
  # Or, you can set the trigger key for a particular set of macros
159
163
  # by specifying it when you call .configure(...).
160
164
  world.addons[:keyboard_macros].configure(trigger_key: ?\C-g) do |macro|
data/yap-shell.gemspec CHANGED
@@ -65,11 +65,11 @@ Gem::Specification.new do |spec|
65
65
  spec.require_paths = ["lib"]
66
66
 
67
67
  spec.add_dependency "pry-byebug", "~> 3.3.0"
68
- spec.add_dependency "yap-shell-parser", "~> 0.6.1"
68
+ spec.add_dependency "yap-shell-parser", "~> 0.6.2"
69
69
  spec.add_dependency "term-ansicolor", "~> 1.3"
70
70
  spec.add_dependency "ruby-termios", "~> 0.9.6"
71
71
  spec.add_dependency "ruby-terminfo", "~> 0.1.1"
72
- spec.add_dependency "yap-rawline", "~> 0.3.5"
72
+ spec.add_dependency "yap-rawline", "~> 0.4.0"
73
73
  spec.add_dependency "treefell", "~> 0.2.3"
74
74
 
75
75
  spec.add_development_dependency "bundler", "~> 1.6"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yap-shell
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.11
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Dennis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-18 00:00:00.000000000 Z
11
+ date: 2016-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry-byebug
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.6.1
33
+ version: 0.6.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.6.1
40
+ version: 0.6.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: term-ansicolor
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.3.5
89
+ version: 0.4.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.3.5
96
+ version: 0.4.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: treefell
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -169,6 +169,7 @@ files:
169
169
  - WISHLIST.md
170
170
  - addons/history/README.md
171
171
  - addons/history/history.rb
172
+ - addons/history_search/history_search.rb
172
173
  - addons/keyboard_macros/keyboard_macros.rb
173
174
  - addons/keyboard_macros/lib/keyboard_macros/cycle.rb
174
175
  - addons/prompt/Gemfile