yap-shell 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/addons/history/README.md +16 -0
- data/addons/history/history.rb +31 -77
- data/addons/keyboard_macros/keyboard_macros.rb +115 -43
- data/addons/keyboard_macros/lib/keyboard_macros/cycle.rb +38 -0
- data/addons/prompt_updates/prompt_updates.rb +1 -1
- data/addons/tab_completion/lib/tab_completion/basic_completion.rb +151 -0
- data/addons/tab_completion/tab_completion.rb +11 -7
- data/bin/yap +1 -12
- data/bin/yap-dev +12 -0
- data/lib/yap/configuration.rb +33 -0
- data/lib/yap/shell/aliases.rb +5 -1
- data/lib/yap/shell/builtins/alias.rb +2 -1
- data/lib/yap/shell/builtins.rb +2 -2
- data/lib/yap/shell/commands.rb +4 -4
- data/lib/yap/shell/evaluation.rb +22 -11
- data/lib/yap/shell/execution/builtin_command_execution.rb +2 -2
- data/lib/yap/shell/execution/file_system_command_execution.rb +2 -1
- data/lib/yap/shell/execution.rb +8 -8
- data/lib/yap/shell/repl.rb +13 -2
- data/lib/yap/shell/version.rb +1 -1
- data/lib/yap/shell.rb +3 -2
- data/lib/yap/world.rb +30 -5
- data/lib/yap.rb +9 -7
- data/rcfiles/.yaprc +42 -10
- data/yap-shell.gemspec +44 -4
- metadata +27 -51
- data/addons/history/Gemfile +0 -2
- data/addons/history/lib/history/buffer.rb +0 -204
- data/addons/history/lib/history/events.rb +0 -13
- data/addons/tab_completion/lib/tab_completion/file_completion.rb +0 -75
@@ -4,7 +4,7 @@ class TabCompletion < Addon
|
|
4
4
|
require 'tab_completion/completer'
|
5
5
|
require 'tab_completion/dsl_methods'
|
6
6
|
require 'tab_completion/custom_completion'
|
7
|
-
require 'tab_completion/
|
7
|
+
require 'tab_completion/basic_completion'
|
8
8
|
|
9
9
|
class CompletionResult
|
10
10
|
attr_accessor :text, :type, :descriptive_text
|
@@ -28,7 +28,7 @@ class TabCompletion < Addon
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
COMPLETIONS = [
|
31
|
+
COMPLETIONS = [ BasicCompletion ]
|
32
32
|
|
33
33
|
Color = Term::ANSIColor
|
34
34
|
|
@@ -37,15 +37,19 @@ class TabCompletion < Addon
|
|
37
37
|
)
|
38
38
|
|
39
39
|
STYLE_PROCS = Hash.new{ |h,k| h[k] = ->(text){ text } }.merge(
|
40
|
+
alias: -> (text){ Color.bold(Color.color("#ff00d7"){ text } ) },
|
41
|
+
builtin: -> (text){ Color.bold(Color.color("#d7af00"){ text } ) },
|
40
42
|
directory: -> (text){ Color.bold(Color.red(text)) },
|
41
43
|
command: -> (text){ Color.bold(Color.green(text)) },
|
44
|
+
shell_command: -> (text){ Color.bold(Color.color("#ffafff"){ text } ) },
|
42
45
|
symlink: -> (text){ Color.bold(Color.cyan(text)) },
|
43
46
|
selected: -> (text){ Color.negative(text) }
|
44
47
|
)
|
45
48
|
|
46
49
|
DECORATION_PROCS = Hash.new{ |h,k| h[k] = ->(text){ text } }.merge(
|
47
50
|
directory: -> (text){ text + "/" },
|
48
|
-
command: -> (text){ text + "@" }
|
51
|
+
command: -> (text){ text + "@" },
|
52
|
+
shell_command: -> (text) { text + "🐚" }
|
49
53
|
)
|
50
54
|
|
51
55
|
attr_reader :editor, :world
|
@@ -54,8 +58,8 @@ class TabCompletion < Addon
|
|
54
58
|
@world = world
|
55
59
|
@world.extend TabCompletion::DslMethods
|
56
60
|
@editor = @world.editor
|
57
|
-
@editor.completion_proc = -> (word, line){
|
58
|
-
complete(word, line)
|
61
|
+
@editor.completion_proc = -> (word, line, word_index){
|
62
|
+
complete(word, line, word_index)
|
59
63
|
}
|
60
64
|
@editor.bind(:tab){ @editor.complete }
|
61
65
|
@completions = COMPLETIONS.dup
|
@@ -116,7 +120,7 @@ class TabCompletion < Addon
|
|
116
120
|
@style_procs[type] = blk
|
117
121
|
end
|
118
122
|
|
119
|
-
def complete(word,
|
123
|
+
def complete(word, words, word_index)
|
120
124
|
matches = @completions.sort_by(&:priority).reverse.map do |completion|
|
121
125
|
if completion.respond_to?(:call)
|
122
126
|
completion.call
|
@@ -124,7 +128,7 @@ class TabCompletion < Addon
|
|
124
128
|
completions = completion.new(
|
125
129
|
world: @world,
|
126
130
|
word_break_characters: editor.word_break_characters
|
127
|
-
).completions_for(word,
|
131
|
+
).completions_for(word, words, word_index)
|
128
132
|
completions.each do |completion|
|
129
133
|
completion.text = display_text_for_match(completion)
|
130
134
|
end
|
data/bin/yap
CHANGED
@@ -1,29 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'bundler'
|
4
|
-
Bundler.setup
|
5
|
-
require 'pry'
|
6
|
-
|
7
3
|
file = __FILE__
|
8
4
|
if File.symlink?(file)
|
9
5
|
file = File.readlink(file)
|
10
6
|
end
|
11
7
|
|
12
|
-
$z = File.open("/tmp/z.log", "w+")
|
13
|
-
$z.sync = true
|
14
|
-
|
15
8
|
trap "SIGTSTP", "IGNORE"
|
16
9
|
trap "SIGINT", "IGNORE"
|
17
10
|
trap "SIGTTIN", "IGNORE"
|
18
11
|
trap "SIGTTOU", "IGNORE"
|
19
12
|
|
20
|
-
#ENV["PATH"] = "/Applications/Postgres.app/Contents/MacOS/bin:/usr/local/share/npm/bin/:/usr/local/heroku/bin:/Users/zdennis/.bin:/Users/zdennis/.rvm/gems/ruby-2.1.5/bin:/Users/zdennis/.rvm/gems/ruby-2.1.5@global/bin:/Users/zdennis/.rvm/rubies/ruby-2.1.5/bin:/usr/local/bin:/usr/local/sbin:/Users/zdennis/bin:/bin:/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/CrossPack-AVR/bin:/private/tmp/.tidbits/bin:/Users/zdennis/source/playground/AdobeAir/AdobeAIRSDK/bin:/Users/zdennis/.rvm/bin:/Users/zdennis/Downloads/adt-bundle-mac-x86_64-20130219/sdk/tools/:/Users/zdennis/.rvm/bin"
|
21
|
-
|
22
13
|
$LOAD_PATH.unshift File.dirname(file) + '/../lib'
|
23
|
-
# $LOAD_PATH.unshift File.dirname(file) + '/../../yap-shell-parser/lib'
|
24
14
|
|
25
15
|
require "yap"
|
26
16
|
|
27
|
-
|
28
|
-
|
17
|
+
STDOUT.sync = true
|
29
18
|
Yap.run_shell
|
data/bin/yap-dev
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Yap
|
4
|
+
require 'yap/world'
|
5
|
+
|
6
|
+
def self.configuration
|
7
|
+
@configuration ||= Configuration.new
|
8
|
+
end
|
9
|
+
|
10
|
+
class Configuration
|
11
|
+
attr_accessor :addon_paths
|
12
|
+
attr_accessor :rcfiles
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@addon_paths = [
|
16
|
+
Dir["#{File.dirname(__FILE__)}/../../addons/*"],
|
17
|
+
Dir["#{ENV['HOME']}/.yap/addons/*"]
|
18
|
+
].flatten
|
19
|
+
|
20
|
+
@rcfiles = [
|
21
|
+
Dir["#{ENV['HOME']}/.yaprc"]
|
22
|
+
].flatten
|
23
|
+
end
|
24
|
+
|
25
|
+
def path_for(part)
|
26
|
+
yap_path.join(part)
|
27
|
+
end
|
28
|
+
|
29
|
+
def yap_path
|
30
|
+
Pathname.new "#{ENV['HOME']}/.yap"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/yap/shell/aliases.rb
CHANGED
@@ -13,6 +13,10 @@ module Yap::Shell
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
def names
|
17
|
+
@aliases.keys
|
18
|
+
end
|
19
|
+
|
16
20
|
def fetch_alias(name)
|
17
21
|
@aliases[name]
|
18
22
|
end
|
@@ -31,7 +35,7 @@ module Yap::Shell
|
|
31
35
|
end
|
32
36
|
|
33
37
|
def to_h
|
34
|
-
@aliases.keys.sort.inject(Hash.new) do |h,k|
|
38
|
+
@aliases.keys.compact.sort.inject(Hash.new) do |h,k|
|
35
39
|
h[k] = @aliases[k]
|
36
40
|
h
|
37
41
|
end
|
data/lib/yap/shell/builtins.rb
CHANGED
data/lib/yap/shell/commands.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'shellwords'
|
2
|
-
require 'yap/shell/aliases'
|
3
|
-
require 'yap/shell/execution/result'
|
4
2
|
|
5
3
|
module Yap::Shell
|
4
|
+
require 'yap/shell/aliases'
|
5
|
+
require 'yap/shell/execution/result'
|
6
|
+
|
6
7
|
class CommandError < StandardError ; end
|
7
8
|
class CommandUnknownError < CommandError ; end
|
8
9
|
|
@@ -102,10 +103,9 @@ module Yap::Shell
|
|
102
103
|
(@registered_functions ||= {}).freeze
|
103
104
|
end
|
104
105
|
|
105
|
-
def self.define_shell_function(name_or_pattern, &blk)
|
106
|
+
def self.define_shell_function(name_or_pattern, name: nil, &blk)
|
106
107
|
raise ArgumentError, "Must provide block when defining a shell function" unless blk
|
107
108
|
name_or_pattern = name_or_pattern.to_s if name_or_pattern.is_a?(Symbol)
|
108
|
-
name_or_pattern = /^#{Regexp.escape(name_or_pattern)}$/ if name_or_pattern.is_a?(String)
|
109
109
|
(@registered_functions ||= {})[name_or_pattern] = blk
|
110
110
|
end
|
111
111
|
|
data/lib/yap/shell/evaluation.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'yap/shell/parser'
|
2
|
-
require 'yap/shell/commands'
|
3
|
-
require 'yap/shell/aliases'
|
4
|
-
require 'yap/shell/evaluation/shell_expansions'
|
5
|
-
|
6
1
|
module Yap::Shell
|
2
|
+
require 'yap/shell/parser'
|
3
|
+
require 'yap/shell/commands'
|
4
|
+
require 'yap/shell/aliases'
|
5
|
+
require 'yap/shell/evaluation/shell_expansions'
|
6
|
+
|
7
7
|
class Evaluation
|
8
8
|
attr_reader :world
|
9
9
|
|
@@ -54,9 +54,7 @@ module Yap::Shell
|
|
54
54
|
@aliases_expanded ||= []
|
55
55
|
@command_node_args_stack ||= []
|
56
56
|
with_standard_streams do |stdin, stdout, stderr|
|
57
|
-
args = node.args
|
58
|
-
shell_expand(arg, escape_directory_expansions: false)
|
59
|
-
end
|
57
|
+
args = process_ArgumentNodes(node.args)
|
60
58
|
if !node.literal? && !@aliases_expanded.include?(node.command) && _alias=Aliases.instance.fetch_alias(node.command)
|
61
59
|
@suppress_events = true
|
62
60
|
@command_node_args_stack << args
|
@@ -197,7 +195,9 @@ module Yap::Shell
|
|
197
195
|
#
|
198
196
|
def visit_EnvWrapperNode(node)
|
199
197
|
with_env do
|
200
|
-
node.env.each_pair
|
198
|
+
node.env.each_pair do |env_var_name, arg_node|
|
199
|
+
world.env[env_var_name] = process_ArgumentNode(arg_node)
|
200
|
+
end
|
201
201
|
node.node.accept(self)
|
202
202
|
end
|
203
203
|
end
|
@@ -213,8 +213,8 @@ module Yap::Shell
|
|
213
213
|
# they cleared or overridden.
|
214
214
|
#
|
215
215
|
def visit_EnvNode(node)
|
216
|
-
node.env.each_pair do |key,
|
217
|
-
world.env[key] =
|
216
|
+
node.env.each_pair do |key, arg_node|
|
217
|
+
world.env[key] = process_ArgumentNode(arg_node)
|
218
218
|
end
|
219
219
|
Yap::Shell::Execution::Result.new(status_code:0, directory:Dir.pwd, n:1, of:1)
|
220
220
|
end
|
@@ -276,6 +276,17 @@ module Yap::Shell
|
|
276
276
|
# #
|
277
277
|
######################################################################
|
278
278
|
|
279
|
+
def process_ArgumentNodes(nodes)
|
280
|
+
nodes.map { |arg_node| process_ArgumentNode(arg_node) }
|
281
|
+
end
|
282
|
+
|
283
|
+
def process_ArgumentNode(node)
|
284
|
+
if node.quoted?
|
285
|
+
variable_expand(node.lvalue)
|
286
|
+
else
|
287
|
+
shell_expand(node.lvalue, escape_directory_expansions: false).first
|
288
|
+
end
|
289
|
+
end
|
279
290
|
|
280
291
|
# +pipeline_stack+ is used to determine if we are about go inside of a
|
281
292
|
# pipeline. It will be empty when we are coming out of a pipeline node.
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require 'yap/shell/execution/result'
|
2
|
-
|
3
1
|
module Yap::Shell::Execution
|
2
|
+
require 'yap/shell/execution/result'
|
3
|
+
|
4
4
|
class BuiltinCommandExecution < CommandExecution
|
5
5
|
on_execute do |command:, n:, of:, wait:|
|
6
6
|
status_code = command.execute(stdin:@stdin, stdout:@stdout, stderr:@stderr)
|
@@ -1,7 +1,8 @@
|
|
1
|
-
require 'yap/shell/execution/result'
|
2
1
|
require 'termios'
|
3
2
|
|
4
3
|
module Yap::Shell::Execution
|
4
|
+
require 'yap/shell/execution/result'
|
5
|
+
|
5
6
|
class FileSystemCommandExecution < CommandExecution
|
6
7
|
on_execute do |command:, n:, of:, wait:, resume_blk:nil|
|
7
8
|
stdin, stdout, stderr, world = @stdin, @stdout, @stderr, @world
|
data/lib/yap/shell/execution.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
require "yap/shell/execution/context"
|
2
|
-
require "yap/shell/execution/command_execution"
|
3
|
-
require "yap/shell/execution/builtin_command_execution"
|
4
|
-
require "yap/shell/execution/file_system_command_execution"
|
5
|
-
require "yap/shell/execution/ruby_command_execution"
|
6
|
-
require "yap/shell/execution/shell_command_execution"
|
7
|
-
require "yap/shell/execution/result"
|
8
|
-
|
9
1
|
module Yap::Shell
|
10
2
|
module Execution
|
3
|
+
require "yap/shell/execution/context"
|
4
|
+
require "yap/shell/execution/command_execution"
|
5
|
+
require "yap/shell/execution/builtin_command_execution"
|
6
|
+
require "yap/shell/execution/file_system_command_execution"
|
7
|
+
require "yap/shell/execution/ruby_command_execution"
|
8
|
+
require "yap/shell/execution/shell_command_execution"
|
9
|
+
require "yap/shell/execution/result"
|
10
|
+
|
11
11
|
Context.register BuiltinCommandExecution, command_type: :BuiltinCommand
|
12
12
|
Context.register FileSystemCommandExecution, command_type: :FileSystemCommand
|
13
13
|
Context.register ShellCommandExecution, command_type: :ShellCommand
|
data/lib/yap/shell/repl.rb
CHANGED
@@ -21,12 +21,17 @@ module Yap::Shell
|
|
21
21
|
|
22
22
|
@world.editor.on_read_line do |event|
|
23
23
|
# editor.history = true?
|
24
|
-
line = event[:payload][:line]
|
24
|
+
line = event[:payload][:line] << "\n"
|
25
25
|
begin
|
26
26
|
@blk.call(line)
|
27
27
|
@world.editor.redraw_prompt
|
28
|
+
rescue Yap::Shell::Parser::Lexer::NonterminatedString, Yap::Shell::Parser::Lexer::LineContinuationFound
|
29
|
+
line << read_another_line_of_input
|
30
|
+
retry
|
28
31
|
rescue ::Yap::Shell::CommandUnknownError => ex
|
29
32
|
puts " CommandError: #{ex.message}"
|
33
|
+
rescue ::Yap::Shell::Parser::ParseError => ex
|
34
|
+
puts " Parse error: #{ex.message}"
|
30
35
|
ensure
|
31
36
|
@world.editor.reset_line
|
32
37
|
end
|
@@ -38,6 +43,11 @@ module Yap::Shell
|
|
38
43
|
|
39
44
|
private
|
40
45
|
|
46
|
+
def read_another_line_of_input
|
47
|
+
print @world.secondary_prompt.update.text
|
48
|
+
gets
|
49
|
+
end
|
50
|
+
|
41
51
|
def kill_ring
|
42
52
|
@kill_ring ||= []
|
43
53
|
end
|
@@ -187,7 +197,8 @@ module Yap::Shell
|
|
187
197
|
# if we haven't been made the process group controlling the TTY that we
|
188
198
|
# become so. This method intentionally blocks.
|
189
199
|
def ensure_process_group_controls_the_tty
|
190
|
-
|
200
|
+
tty_pgrp = Termios.tcgetpgrp(STDIN)
|
201
|
+
while ![Process.pid, Process.getpgrp].include?(tty_pgrp)
|
191
202
|
Termios.tcsetpgrp(STDIN, Process.pid)
|
192
203
|
sleep 0.1
|
193
204
|
end
|
data/lib/yap/shell/version.rb
CHANGED
data/lib/yap/shell.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'readline'
|
2
2
|
require 'yaml'
|
3
|
-
require 'yap/shell/version'
|
4
|
-
require 'yap/shell/builtins'
|
5
3
|
require 'fcntl'
|
6
4
|
|
7
5
|
module Yap
|
8
6
|
module Shell
|
7
|
+
require 'yap/shell/version'
|
8
|
+
require 'yap/shell/builtins'
|
9
|
+
|
9
10
|
autoload :Aliases, "yap/shell/aliases"
|
10
11
|
|
11
12
|
autoload :CommandFactory, "yap/shell/commands"
|
data/lib/yap/world.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'term/ansicolor'
|
2
2
|
require 'forwardable'
|
3
|
-
|
4
3
|
require 'rawline'
|
5
|
-
require 'yap/shell/execution'
|
6
|
-
require 'yap/shell/prompt'
|
7
|
-
require 'yap/world/addons'
|
8
4
|
require 'termios'
|
9
5
|
|
10
6
|
module Yap
|
7
|
+
require 'yap/shell/execution'
|
8
|
+
require 'yap/shell/prompt'
|
9
|
+
require 'yap/world/addons'
|
10
|
+
|
11
11
|
class World
|
12
12
|
include Term::ANSIColor
|
13
13
|
extend Forwardable
|
@@ -46,10 +46,26 @@ module Yap
|
|
46
46
|
addons.each { |addon| addon.initialize_world(self) }
|
47
47
|
end
|
48
48
|
|
49
|
+
def configuration
|
50
|
+
::Yap.configuration
|
51
|
+
end
|
52
|
+
|
49
53
|
def [](addon_name)
|
50
54
|
@addons.fetch(addon_name){ raise(ArgumentError, "No addon loaded registered as #{addon_name}") }
|
51
55
|
end
|
52
56
|
|
57
|
+
def aliases
|
58
|
+
Yap::Shell::Aliases.instance
|
59
|
+
end
|
60
|
+
|
61
|
+
def builtins
|
62
|
+
Yap::Shell::BuiltinCommand.builtins.keys.map(&:to_s)
|
63
|
+
end
|
64
|
+
|
65
|
+
def shell_commands
|
66
|
+
Yap::Shell::ShellCommand.registered_functions.keys.map(&:to_s)
|
67
|
+
end
|
68
|
+
|
53
69
|
def events
|
54
70
|
@editor.events
|
55
71
|
end
|
@@ -111,7 +127,6 @@ module Yap
|
|
111
127
|
end
|
112
128
|
|
113
129
|
def prompt=(prompt=nil, &blk)
|
114
|
-
# TODO if prompt_controller then undefine, cancel events, etc
|
115
130
|
if prompt.is_a?(Yap::Shell::Prompt)
|
116
131
|
@prompt = prompt
|
117
132
|
elsif prompt.respond_to?(:call) # proc
|
@@ -121,6 +136,16 @@ module Yap
|
|
121
136
|
end
|
122
137
|
end
|
123
138
|
|
139
|
+
def secondary_prompt=(prompt=nil, &blk)
|
140
|
+
if prompt.is_a?(Yap::Shell::Prompt)
|
141
|
+
@secondary_prompt = prompt
|
142
|
+
elsif prompt.respond_to?(:call) # proc
|
143
|
+
@secondary_prompt = Yap::Shell::Prompt.new(text:prompt.call, &prompt)
|
144
|
+
else # text
|
145
|
+
@secondary_prompt = Yap::Shell::Prompt.new(text:prompt, &blk)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
124
149
|
def refresh_prompt
|
125
150
|
@editor.prompt = @prompt.update.text
|
126
151
|
end
|
data/lib/yap.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
require 'yap/shell'
|
2
|
-
require 'yap/world'
|
3
|
-
|
4
1
|
module Yap
|
2
|
+
require 'yap/configuration'
|
3
|
+
require 'yap/shell'
|
4
|
+
require 'yap/world'
|
5
|
+
|
5
6
|
def self.run_shell
|
6
|
-
addons = [
|
7
|
-
|
8
|
-
|
7
|
+
addons = [
|
8
|
+
World::Addons.load_directories(configuration.addon_paths),
|
9
|
+
World::Addons.load_rcfiles(configuration.rcfiles)
|
10
|
+
].flatten
|
9
11
|
|
10
|
-
Shell::Impl.new(addons: addons
|
12
|
+
Shell::Impl.new(addons: addons).repl
|
11
13
|
end
|
12
14
|
end
|
data/rcfiles/.yaprc
CHANGED
@@ -29,7 +29,11 @@ require 'term/ansicolor'
|
|
29
29
|
require 'terminfo'
|
30
30
|
|
31
31
|
env.delete("BUNDLE_GEMFILE")
|
32
|
-
|
32
|
+
env.delete("BUNDLE_BIN_PATH")
|
33
|
+
|
34
|
+
# Resize history to be infinite
|
35
|
+
infinity = 1 / 0.0
|
36
|
+
world.history.resize(infinity)
|
33
37
|
|
34
38
|
func :reload! do |args:, stdin:, stdout:, stderr:|
|
35
39
|
stdout.puts "Reloading shell:"
|
@@ -39,6 +43,7 @@ func :reload! do |args:, stdin:, stdout:, stderr:|
|
|
39
43
|
exec File.expand_path($0)
|
40
44
|
end
|
41
45
|
|
46
|
+
|
42
47
|
completion_cache = {}
|
43
48
|
|
44
49
|
# tab_completion_display do |matches|
|
@@ -91,6 +96,14 @@ self.prompt = -> do
|
|
91
96
|
last_prompt = "#{dark(green('£'))} #{yellow(pwd)} #{git_branch}#{red(arrow)} "
|
92
97
|
end
|
93
98
|
|
99
|
+
#
|
100
|
+
# The secondary_prompt is equivalent to the PS2 prompt in bash. It is what
|
101
|
+
# is displayed when entering a multiline command. It can be set to a string
|
102
|
+
# or a proc. It defaults to '> '
|
103
|
+
#
|
104
|
+
# To see it in action, type "echo 'foo" with no completing single quote and
|
105
|
+
# hit enter.
|
106
|
+
self.secondary_prompt = '> '
|
94
107
|
|
95
108
|
###############################################################################
|
96
109
|
# KEYBOARD MACROS
|
@@ -139,6 +152,15 @@ world.addons[:keyboard_macros].timeout_in_ms = nil
|
|
139
152
|
# set to false you can keep attempting to type in your macro.
|
140
153
|
world.addons[:keyboard_macros].cancel_on_unknown_sequences = true
|
141
154
|
|
155
|
+
keyboard_macros = world.addons[:keyboard_macros]
|
156
|
+
keyboard_macros.cycle(:recent_git_branches) { `git recent`.lines.map(&:chomp) }
|
157
|
+
world.editor.bind(:alt_up_arrow) do
|
158
|
+
keyboard_macros.cycle(:recent_git_branches).next
|
159
|
+
end
|
160
|
+
world.editor.bind(:alt_down_arrow) do
|
161
|
+
keyboard_macros.cycle(:recent_git_branches).previous
|
162
|
+
end
|
163
|
+
|
142
164
|
# Or, you can set the trigger key for a particular set of macros
|
143
165
|
# by specifying it when you call .configure(...).
|
144
166
|
world.addons[:keyboard_macros].configure(trigger_key: ?\C-g) do |macro|
|
@@ -155,22 +177,30 @@ world.addons[:keyboard_macros].configure(trigger_key: ?\C-g) do |macro|
|
|
155
177
|
world.editor.content_box.children = []
|
156
178
|
end
|
157
179
|
|
158
|
-
macro.define 'z',
|
159
|
-
|
160
|
-
|
161
|
-
|
180
|
+
macro.define 'z', "git open-pull\n"
|
181
|
+
macro.define 'abc', 'echo abc'
|
182
|
+
macro.define 'u', -> { world.editor.undo }
|
183
|
+
|
184
|
+
macro.define 'b' do |macro|
|
185
|
+
macro.start { macro.cycle(:recent_git_branches).reset }
|
186
|
+
|
187
|
+
macro.cycle(:recent_git_branches) { `git recent`.lines.map(&:chomp) }
|
188
|
+
macro.fragment :up_arrow, -> { macro.cycle(:recent_git_branches).next }
|
189
|
+
macro.fragment :down_arrow, -> { macro.cycle(:recent_git_branches).previous }
|
190
|
+
end
|
162
191
|
|
163
192
|
macro.define 'l', 'git log ' do |macro|
|
164
193
|
macro.fragment 'n', '--name-status '
|
194
|
+
macro.fragment 'm', 'master..HEAD '
|
165
195
|
macro.fragment 'o', '--oneline '
|
166
196
|
macro.fragment /\d/, -> (a) { "-n#{a} " }
|
167
197
|
end
|
168
198
|
|
169
199
|
macro.define 'd', 'git diff ' do |macro|
|
170
|
-
macro.
|
171
|
-
|
172
|
-
|
173
|
-
macro.
|
200
|
+
macro.fragment 'n', '--name-status '
|
201
|
+
macro.fragment 'm', 'master..HEAD '
|
202
|
+
macro.fragment 'o', '--oneline '
|
203
|
+
macro.fragment /\d/, -> (a) { "-n#{a} " }
|
174
204
|
end
|
175
205
|
end
|
176
206
|
|
@@ -267,7 +297,9 @@ end
|
|
267
297
|
func history_matcher do |world:, args:, stdout:|
|
268
298
|
num_commands = args.first.to_i
|
269
299
|
num_commands = world.history.length - 1 if num_commands == 0
|
300
|
+
history_size = world.history.length
|
270
301
|
world.history[-(num_commands + 1)...-1].each_with_index do |command, i|
|
271
|
-
|
302
|
+
position = history_size - num_commands + i
|
303
|
+
stdout.puts " #{position} #{command}"
|
272
304
|
end
|
273
305
|
end
|
data/yap-shell.gemspec
CHANGED
@@ -13,21 +13,61 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = "https://github.com/zdennis/yap-shell"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
|
+
spec.post_install_message = <<-POST_INSTALL_MESSAGE.gsub(/^\s*\|/, '')
|
17
|
+
|
|
18
|
+
|Greetings forward-thinking traveler!
|
19
|
+
|
|
20
|
+
|Let's waste no time and get right to it.
|
21
|
+
|
|
22
|
+
|\e[033mFirstly\e[0m, thank you for installing the yap shell!
|
23
|
+
|
|
24
|
+
|\e[033mSecondly\e[0m, this is my beta's beta. Yap has many cool ideas. I dare
|
25
|
+
|say some of those made it into this very release.
|
26
|
+
|
|
27
|
+
|\e[033mLastly\e[0m, create an alias to the yap executable using the ruby version
|
28
|
+
|you just installed it for. For example, with rbenv I use the below
|
29
|
+
|alias in my ~/.profile file:
|
30
|
+
|
|
31
|
+
| alias yap='~/.rbenv/versions/2.2.3/bin/ruby ~/.rbenv/shims/yap'
|
32
|
+
|
|
33
|
+
|Then, `source ~/.profile` or reload your shell. Now you can finally run:
|
34
|
+
|
|
35
|
+
| yap
|
36
|
+
|
|
37
|
+
|You know your tooling better than me. If you need things to go a little
|
38
|
+
|differently than above you go right ahead. If any questions arise don't
|
39
|
+
|hesitate to holler over at Github. I may not always be home, but there will
|
40
|
+
|always be a cozy textarea with dozens of emoji friends waiting to hear your
|
41
|
+
|thoughts. All day. All night.
|
42
|
+
|
|
43
|
+
|Until the next update: Happy coding!
|
44
|
+
|
|
45
|
+
|Sincerely,
|
46
|
+
|
|
47
|
+
| \e[51mThe Lagniappe (Yap) Shell\e[0m
|
48
|
+
|
|
49
|
+
|\e[033mP.S.\e[0m If you have ideas for loading other than the hard-coded
|
50
|
+
|alias, do tell, right over here:
|
51
|
+
|
|
52
|
+
| \e[1mhttp://github.com/zdennis/yap-shell/issues\e[0m
|
53
|
+
|
|
54
|
+
|\e[033mP.P.S.\e[0m OSX support? YES! Linux? I assume YES! Windows? Um...
|
55
|
+
|
|
56
|
+
POST_INSTALL_MESSAGE
|
57
|
+
|
16
58
|
spec.files = `git ls-files -z`.split("\x0")
|
17
59
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
60
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
61
|
spec.require_paths = ["lib"]
|
20
62
|
|
21
|
-
spec.add_dependency "yap-shell-parser", "~> 0.
|
63
|
+
spec.add_dependency "yap-shell-parser", "~> 0.5.0"
|
22
64
|
spec.add_dependency "term-ansicolor", "~> 1.3"
|
23
65
|
spec.add_dependency "ruby-termios", "~> 0.9.6"
|
24
66
|
spec.add_dependency "ruby-terminfo", "~> 0.1.1"
|
25
|
-
spec.
|
26
|
-
spec.add_dependency "yap-rawline", "~> 0.2.0"
|
67
|
+
spec.add_dependency "yap-rawline", "~> 0.3.1"
|
27
68
|
|
28
69
|
spec.add_development_dependency "bundler", "~> 1.6"
|
29
70
|
spec.add_development_dependency "rake", "~> 10"
|
30
|
-
spec.add_development_dependency 'pry-byebug', '~> 3.3', '>= 3.3.0'
|
31
71
|
|
32
72
|
#--BEGIN_ADDON_GEM_DEPENDENCIES--#
|
33
73
|
spec.add_dependency "chronic", "~> 0.10.2"
|