yap-shell 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/.ruby-version +1 -1
- data/.travis.yml +11 -0
- data/Gemfile.travis +8 -0
- data/README.md +9 -11
- data/addons/history/history.rb +1 -0
- data/addons/history_search/history_search.rb +21 -17
- data/bin/yap +47 -55
- data/bin/yap-dev +0 -1
- data/lib/yap/configuration.rb +25 -0
- data/lib/yap/shell/builtins/alias.rb +16 -0
- data/lib/yap/shell/commands.rb +15 -3
- data/lib/yap/shell/evaluation/shell_expansions.rb +10 -10
- data/lib/yap/shell/evaluation.rb +29 -4
- data/lib/yap/shell/execution/context.rb +3 -2
- data/lib/yap/shell/execution/file_system_command_execution.rb +9 -17
- data/lib/yap/shell/repl.rb +2 -5
- data/lib/yap/shell/version.rb +1 -1
- data/lib/yap/shell.rb +8 -2
- data/lib/yap/world.rb +23 -18
- data/lib/yap.rb +52 -7
- data/spec/features/aliases_spec.rb +78 -0
- data/spec/features/environment_variables_spec.rb +69 -0
- data/spec/features/filesystem_commands_spec.rb +61 -0
- data/spec/features/first_time_spec.rb +45 -0
- data/spec/features/grouping_spec.rb +81 -0
- data/spec/features/line_editing_spec.rb +166 -0
- data/spec/features/range_spec.rb +35 -0
- data/spec/features/redirection_spec.rb +225 -0
- data/spec/features/repetition_spec.rb +118 -0
- data/spec/features/shell_expansions_spec.rb +127 -0
- data/spec/spec_helper.rb +162 -0
- data/spec/support/matchers/have_not_printed.rb +30 -0
- data/spec/support/matchers/have_printed.rb +30 -0
- data/spec/support/very_soon.rb +9 -0
- data/spec/support/yap_spec_dsl.rb +240 -0
- data/yap-shell.gemspec +4 -2
- metadata +69 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7186e70881e605ba5563cd30e9674030c55f4332
|
4
|
+
data.tar.gz: abbfa86bde0fabf472adca6a87843588e8760671
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4498e667793d6009c6a988fd85b3977b7a01d79dee15565e71b9c6b10cc86a844263f9215205bf382e9ad152fde34589890d022a7bdb92d536204e3595df967f
|
7
|
+
data.tar.gz: fb6bff600285457f6aeea74c1fb5bf8d843dbba8b4a3b17c791b69ebd5dd93a5c1e2e0f7b7a660ed64afe468e49a3e2a73801a643d17fa811bfa6055ced9710f
|
data/.rspec
ADDED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.3.1
|
data/.travis.yml
ADDED
data/Gemfile.travis
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
gem 'treefell', git: 'https://github.com/zdennis/treefell.git'
|
6
|
+
gem 'yap-shell-parser', git: 'https://github.com/zdennis/yap-shell-parser.git'
|
7
|
+
gem 'terminal-layout', git: 'https://github.com/zdennis/terminal-layout.git'
|
8
|
+
gem 'yap-rawline', git: 'https://github.com/zdennis/rawline.git'
|
data/README.md
CHANGED
@@ -1,24 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
TODO: Write a gem description
|
1
|
+
[![Build Status](https://travis-ci.org/zdennis/yap-shell.svg?branch=master)](https://travis-ci.org/zdennis/yap-shell)
|
4
2
|
|
5
|
-
|
3
|
+
# Yap
|
6
4
|
|
7
|
-
|
5
|
+
Yap is a modern, developer shell. Inspired by shells like bash and zsh it's a modern implementation keeping the good parts and leaving out the rest.
|
8
6
|
|
9
|
-
|
7
|
+
See the slide deck that [introduces Yap](http://slides.com/zdennis/yaptastic-1#/)
|
10
8
|
|
11
|
-
|
9
|
+
## Installation
|
12
10
|
|
13
|
-
|
11
|
+
This should not go in your Gemfile, you should install from the command line:
|
14
12
|
|
15
|
-
|
13
|
+
> gem install yap-shell
|
16
14
|
|
17
|
-
|
15
|
+
Then follow the on-screen installation instructions.
|
18
16
|
|
19
17
|
## Usage
|
20
18
|
|
21
|
-
|
19
|
+
See the Yap [shell reference](https://github.com/zdennis/yap-shell/wiki/ShellReference)
|
22
20
|
|
23
21
|
## Contributing
|
24
22
|
|
data/addons/history/history.rb
CHANGED
@@ -80,22 +80,7 @@ class HistorySearch < Addon
|
|
80
80
|
if bytes.any?
|
81
81
|
Treefell['shell'].puts "history search found bytes: #{bytes.inspect}"
|
82
82
|
|
83
|
-
|
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
|
83
|
+
search_bytes = process_bytes(bytes)
|
99
84
|
|
100
85
|
if search_bytes.any?
|
101
86
|
Treefell['shell'].puts "history searching with bytes=#{bytes.inspect}"
|
@@ -106,12 +91,31 @@ class HistorySearch < Addon
|
|
106
91
|
|
107
92
|
private
|
108
93
|
|
94
|
+
# given [1,2,3] first try [1,2,3]. If no key binding
|
95
|
+
# matches, then try [1,2]. If no keybinding matches try [1].
|
96
|
+
# Execution should flow in left to right, positional order.
|
97
|
+
# This returns an array of left over bytes in the order they
|
98
|
+
# appeared that did not match any keybinding
|
99
|
+
def process_bytes bytes, leftover=[]
|
100
|
+
if bytes.empty?
|
101
|
+
leftover
|
102
|
+
elsif @keys[bytes]
|
103
|
+
@keys[bytes].call
|
104
|
+
leftover
|
105
|
+
else
|
106
|
+
process_bytes(
|
107
|
+
bytes[0..-2],
|
108
|
+
[bytes[-1]].concat(leftover)
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
109
113
|
def accept
|
110
114
|
@done_proc.call(execute: false, result: result)
|
111
115
|
end
|
112
116
|
|
113
117
|
def cancel
|
114
|
-
@done_proc.call(execute: false, result:
|
118
|
+
@done_proc.call(execute: false, result: nil)
|
115
119
|
end
|
116
120
|
|
117
121
|
def execute
|
data/bin/yap
CHANGED
@@ -1,58 +1,50 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
else
|
35
|
-
file = __FILE__
|
36
|
-
if File.symlink?(file)
|
37
|
-
file = File.readlink(file)
|
38
|
-
end
|
39
|
-
|
40
|
-
trap "SIGTSTP", "IGNORE"
|
41
|
-
trap "SIGINT", "IGNORE"
|
42
|
-
trap "SIGTTIN", "IGNORE"
|
43
|
-
trap "SIGTTOU", "IGNORE"
|
44
|
-
|
45
|
-
$LOAD_PATH.unshift File.dirname(file) + '/../lib'
|
46
|
-
|
47
|
-
ENV['TERM'] ||= 'linux'
|
48
|
-
ENV['YAP_SHELL'] = 'active'
|
49
|
-
|
50
|
-
require "term/ansicolor"
|
51
|
-
require "tins"
|
52
|
-
require "byebug"
|
53
|
-
require "pry"
|
54
|
-
require "yap"
|
55
|
-
|
56
|
-
STDOUT.sync = true
|
57
|
-
Yap.run_shell
|
3
|
+
# Start YAP with a pristine environment
|
4
|
+
env2keep = {
|
5
|
+
# DISPLAY needs to be inherited in order to launch GUI apps
|
6
|
+
'DISPLAY' => ENV['DISPLAY'],
|
7
|
+
'HOME' => ENV['HOME'],
|
8
|
+
'PATH' => ENV['PATH'],
|
9
|
+
|
10
|
+
# For Yap's sanity
|
11
|
+
'RUBYOPT' => '-rubygems -EUTF-8',
|
12
|
+
|
13
|
+
# Inherit the user's preferred shell
|
14
|
+
'SHELL' => ENV['SHELL'],
|
15
|
+
|
16
|
+
# Necessary for ssh-agent
|
17
|
+
'SSH_AUTH_SOCK' => ENV['SSH_AUTH_SOCK'],
|
18
|
+
|
19
|
+
# DEBUG/TREEFELL_OUT are for debuging yap itself
|
20
|
+
'DEBUG' => ENV['DEBUG'],
|
21
|
+
'TREEFELL_OUT' => ENV['TREEFELL_OUT']
|
22
|
+
}
|
23
|
+
|
24
|
+
ENV.clear
|
25
|
+
env_params = env2keep.each_with_object([]) do |(key,value),arr|
|
26
|
+
# next if value.nil?
|
27
|
+
arr << %|#{key}="#{value}"|
|
28
|
+
ENV[key] = value
|
29
|
+
end.join(' ')
|
30
|
+
|
31
|
+
file = __FILE__
|
32
|
+
if File.symlink?(file)
|
33
|
+
file = File.readlink(file)
|
58
34
|
end
|
35
|
+
|
36
|
+
trap "SIGTSTP", "IGNORE"
|
37
|
+
trap "SIGINT", "IGNORE"
|
38
|
+
trap "SIGTTIN", "IGNORE"
|
39
|
+
trap "SIGTTOU", "IGNORE"
|
40
|
+
|
41
|
+
$LOAD_PATH.unshift File.dirname(file) + '/../lib'
|
42
|
+
|
43
|
+
ENV['TERM'] ||= 'linux'
|
44
|
+
|
45
|
+
require "yap"
|
46
|
+
|
47
|
+
STDOUT.sync = true
|
48
|
+
STDERR.sync = true
|
49
|
+
|
50
|
+
Yap.run_shell(ARGV)
|
data/bin/yap-dev
CHANGED
data/lib/yap/configuration.rb
CHANGED
@@ -11,6 +11,31 @@ module Yap
|
|
11
11
|
attr_accessor :addon_paths
|
12
12
|
attr_accessor :rcfiles
|
13
13
|
|
14
|
+
def self.option(name, type=nil, default: nil)
|
15
|
+
reader_method = name.to_s
|
16
|
+
define_method(reader_method) do
|
17
|
+
return default unless instance_variable_defined?("@#{name}")
|
18
|
+
value = instance_variable_get("@#{name}")
|
19
|
+
return !!value if type == :boolean
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
writer_method = "#{reader_method}="
|
24
|
+
define_method(writer_method) do |value|
|
25
|
+
instance_variable_set("@#{name}", value)
|
26
|
+
end
|
27
|
+
|
28
|
+
if type == :boolean
|
29
|
+
query_method = "#{reader_method}?"
|
30
|
+
alias_method query_method, reader_method
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
option :skip_first_time, :boolean, default: false
|
35
|
+
option :use_addons, :boolean, default: true
|
36
|
+
option :use_history, :boolean, default: true
|
37
|
+
option :use_rcfiles, :boolean, default: true
|
38
|
+
|
14
39
|
def initialize
|
15
40
|
@addon_paths = [
|
16
41
|
"#{File.dirname(__FILE__)}/../../addons",
|
@@ -4,6 +4,8 @@ module Yap::Shell
|
|
4
4
|
require 'yap/shell/aliases'
|
5
5
|
|
6
6
|
module Builtins
|
7
|
+
Color = ::Term::ANSIColor
|
8
|
+
|
7
9
|
builtin :alias do |args:, stdout:, **kwargs|
|
8
10
|
output = []
|
9
11
|
if args.empty?
|
@@ -18,9 +20,23 @@ module Yap::Shell
|
|
18
20
|
else
|
19
21
|
name_eq_value = args.map(&:shellsplit).join(' ')
|
20
22
|
name, command = name_eq_value.scan(/^(.*?)\s*=\s*(.*)$/).flatten
|
23
|
+
output << "Setting alias #{name} #{Color.green('done')}"
|
21
24
|
Yap::Shell::Aliases.instance.set_alias name, command
|
22
25
|
end
|
23
26
|
stdout.puts output.join("\n")
|
24
27
|
end
|
28
|
+
|
29
|
+
builtin :unalias do |args:, stdout:, **kwargs|
|
30
|
+
output = []
|
31
|
+
if args.empty?
|
32
|
+
output << "Usage: unalias <aliasname>"
|
33
|
+
else
|
34
|
+
args.each do |alias_name|
|
35
|
+
Yap::Shell::Aliases.instance.unset_alias alias_name
|
36
|
+
output << "Removing alias #{alias_name} #{Color.green('done')}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
stdout.puts output.join("\n")
|
40
|
+
end
|
25
41
|
end
|
26
42
|
end
|
data/lib/yap/shell/commands.rb
CHANGED
@@ -5,7 +5,6 @@ module Yap::Shell
|
|
5
5
|
require 'yap/shell/execution/result'
|
6
6
|
|
7
7
|
class CommandError < StandardError ; end
|
8
|
-
class CommandUnknownError < CommandError ; end
|
9
8
|
|
10
9
|
class CommandFactory
|
11
10
|
def self.build_command_for(world:, command:, args:, heredoc:, internally_evaluate:, line:)
|
@@ -14,9 +13,9 @@ module Yap::Shell
|
|
14
13
|
case command
|
15
14
|
when ShellCommand then ShellCommand.new(world:world, str:command, args:args, heredoc:heredoc, line:line)
|
16
15
|
when BuiltinCommand then BuiltinCommand.new(world:world, str:command, args:args, heredoc:heredoc)
|
17
|
-
when FileSystemCommand
|
16
|
+
when FileSystemCommand then FileSystemCommand.new(world:world, str:command, args:args, heredoc:heredoc)
|
18
17
|
else
|
19
|
-
|
18
|
+
UnknownCommand.new(world:world, str:command, args:args, heredoc:heredoc)
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -75,6 +74,19 @@ module Yap::Shell
|
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
77
|
+
class UnknownCommand < Command
|
78
|
+
EXIT_CODE = 127
|
79
|
+
|
80
|
+
def execute(stdin:, stdout:, stderr:)
|
81
|
+
stderr.puts "yap: command not found: #{str}"
|
82
|
+
EXIT_CODE
|
83
|
+
end
|
84
|
+
|
85
|
+
def type
|
86
|
+
:BuiltinCommand
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
78
90
|
class FileSystemCommand < Command
|
79
91
|
def self.world
|
80
92
|
::Yap::World.instance
|
@@ -39,7 +39,8 @@ module Yap::Shell
|
|
39
39
|
private
|
40
40
|
|
41
41
|
def env_expand(str)
|
42
|
-
|
42
|
+
# match "$a", "$a $b", "$a$b", "$cat$dog $foo"
|
43
|
+
str.gsub(/\$([^\$\s]+)/) do |match,*args|
|
43
44
|
var_name = match[1..-1]
|
44
45
|
if var_name == '?'
|
45
46
|
(world.last_result ? world.last_result.status_code.to_s : '0').tap do |expanded|
|
@@ -60,17 +61,16 @@ module Yap::Shell
|
|
60
61
|
if content
|
61
62
|
expansions = content.split(",", -1)
|
62
63
|
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
return expanded
|
64
|
+
# Break compatibility with Bash/Zsh. They do not expand words
|
65
|
+
# when there is only one word supplied (e.g. "a_{word}"), but this
|
66
|
+
# is counter-intuitive to me. It should behave the same regardless
|
67
|
+
# of the number of words provided to expand.
|
68
|
+
expanded = expansions.map { |expansion| str.sub(/\{([^\}]+)\}/, expansion) }.tap do |expanded|
|
69
|
+
Treefell['shell'].puts "shell-expansions expanding words in #{str} to #{expanded}"
|
71
70
|
end
|
71
|
+
else
|
72
|
+
[str]
|
72
73
|
end
|
73
|
-
[str]
|
74
74
|
end
|
75
75
|
|
76
76
|
def process_expansions(expansions, escape_directory_expansions: true)
|
data/lib/yap/shell/evaluation.rb
CHANGED
@@ -158,7 +158,7 @@ module Yap::Shell
|
|
158
158
|
values = []
|
159
159
|
if node.head
|
160
160
|
node.head.accept(self)
|
161
|
-
values = stdin.read.split(/\
|
161
|
+
values = stdin.read.split(/\n|\0/)
|
162
162
|
else
|
163
163
|
# assume range for now
|
164
164
|
values = @current_range_values
|
@@ -327,10 +327,13 @@ module Yap::Shell
|
|
327
327
|
def process_ArgumentNode(node)
|
328
328
|
if node.single_quoted?
|
329
329
|
debug_visit(node, 'single quoted argument, performing no expansion')
|
330
|
-
["
|
330
|
+
["#{node.lvalue}"]
|
331
331
|
elsif node.double_quoted?
|
332
332
|
debug_visit(node, 'double quoted argument, performing variable expansion')
|
333
333
|
[variable_expand(node.lvalue)]
|
334
|
+
elsif node.escaped?
|
335
|
+
debug_visit(node, 'escaped argument, skipping variable expansion')
|
336
|
+
[node.lvalue]
|
334
337
|
else
|
335
338
|
debug_visit(node, 'unquoted argument, performing shell expansion')
|
336
339
|
shell_expand(node.lvalue, escape_directory_expansions: false)
|
@@ -388,16 +391,38 @@ module Yap::Shell
|
|
388
391
|
case redirect.kind
|
389
392
|
when "<"
|
390
393
|
stdin = redirect.target
|
394
|
+
stdin = File.open(stdin, "rb") if stdin.is_a?(String)
|
391
395
|
when ">", "1>"
|
392
396
|
stdout = redirect.target
|
397
|
+
stdout = File.open(stdout, "wb") if stdout.is_a?(String)
|
393
398
|
when "1>&2"
|
394
|
-
|
399
|
+
stdout = redirect.target
|
400
|
+
stdout = File.open(stdout, "wb") if stdout.is_a?(String)
|
401
|
+
stderr = stdout
|
395
402
|
when "2>"
|
396
403
|
stderr = redirect.target
|
404
|
+
stderr = File.open(stderr, "wb") if stderr.is_a?(String)
|
397
405
|
when "2>&1"
|
398
|
-
|
406
|
+
stderr = redirect.target
|
407
|
+
stderr = File.open(stderr, "wb") if stderr.is_a?(String)
|
408
|
+
stdout = stderr
|
409
|
+
when "1>>", ">>"
|
410
|
+
stdout = redirect.target
|
411
|
+
stdout = File.open(stdout, "ab") if stdout.is_a?(String)
|
412
|
+
when "2>>"
|
413
|
+
stderr = redirect.target
|
414
|
+
stderr = File.open(stderr, "ab") if stderr.is_a?(String)
|
415
|
+
when "&>"
|
416
|
+
stdout = redirect.target
|
417
|
+
stdout = File.open(stdout, "wb") if stdout.is_a?(String)
|
418
|
+
stderr = stdout
|
419
|
+
when "&>>"
|
420
|
+
stdout = redirect.target
|
421
|
+
stdout = File.open(stdout, "ab") if stdout.is_a?(String)
|
422
|
+
stderr = stdout
|
399
423
|
end
|
400
424
|
end
|
425
|
+
|
401
426
|
[stdin, stdout, stderr]
|
402
427
|
end
|
403
428
|
|
@@ -59,7 +59,8 @@ module Yap::Shell::Execution
|
|
59
59
|
world: world
|
60
60
|
)
|
61
61
|
|
62
|
-
@saved_tty_attrs = Termios.tcgetattr(STDIN)
|
62
|
+
@saved_tty_attrs = Termios.tcgetattr(STDIN) if STDIN.isatty
|
63
|
+
|
63
64
|
Treefell['shell'].puts "firing :before_execute for #{command}"
|
64
65
|
self.class.fire :before_execute, world, command: command
|
65
66
|
|
@@ -90,7 +91,7 @@ module Yap::Shell::Execution
|
|
90
91
|
self.class.fire :after_execute, world, command: command, result: result
|
91
92
|
|
92
93
|
results << process_execution_result(execution_context:execution_context, result:result)
|
93
|
-
Termios.tcsetattr(STDIN, Termios::TCSANOW, @saved_tty_attrs)
|
94
|
+
Termios.tcsetattr(STDIN, Termios::TCSANOW, @saved_tty_attrs) if STDIN.isatty
|
94
95
|
end
|
95
96
|
end
|
96
97
|
|
@@ -27,16 +27,6 @@ module Yap::Shell::Execution
|
|
27
27
|
# Set the process group of the forked to child to that of the
|
28
28
|
Process.setpgrp
|
29
29
|
|
30
|
-
# Start a new process group as the session leader. Now we are
|
31
|
-
# responsible for sending signals that would have otherwise
|
32
|
-
# been propagated to the process, e.g. SIGINT, SIGSTOP, SIGCONT, etc.
|
33
|
-
stdin = File.open(stdin, "rb") if stdin.is_a?(String)
|
34
|
-
stdout = File.open(stdout, "wb") if stdout.is_a?(String)
|
35
|
-
stderr = File.open(stderr, "wb") if stderr.is_a?(String)
|
36
|
-
|
37
|
-
stdout = stderr if stdout == :stderr
|
38
|
-
stderr = stdout if stderr == :stdout
|
39
|
-
|
40
30
|
$stdin.reopen stdin
|
41
31
|
$stdout.reopen stdout
|
42
32
|
$stderr.reopen stderr
|
@@ -72,7 +62,7 @@ module Yap::Shell::Execution
|
|
72
62
|
end
|
73
63
|
|
74
64
|
# Set terminal's process group to that of the child process
|
75
|
-
Termios.tcsetpgrp STDIN, pid
|
65
|
+
Termios.tcsetpgrp STDIN, pid if STDIN.isatty
|
76
66
|
pid, status = Process.wait2(pid, Process::WUNTRACED) if wait
|
77
67
|
|
78
68
|
# If we're not printing to the terminal then close in/out/err. This
|
@@ -92,12 +82,14 @@ module Yap::Shell::Execution
|
|
92
82
|
# if the pid that just stopped was the process group owner then
|
93
83
|
# give it back to the us so we can become the foreground process
|
94
84
|
# in the terminal
|
95
|
-
if
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
85
|
+
if STDIN.isatty
|
86
|
+
if pid == Termios.tcgetpgrp(STDIN)
|
87
|
+
Treefell['shell'].puts <<-DEBUG.gsub(/^\s*\|/, '')
|
88
|
+
|restoring process group for STDIN to yap process with pid=#{Process.pid}
|
89
|
+
DEBUG
|
90
|
+
Process.setpgid Process.pid, Process.pid
|
91
|
+
Termios.tcsetpgrp STDIN, Process.pid
|
92
|
+
end
|
101
93
|
end
|
102
94
|
|
103
95
|
# if the reason we stopped is from being suspended
|
data/lib/yap/shell/repl.rb
CHANGED
@@ -38,14 +38,9 @@ module Yap::Shell
|
|
38
38
|
line << more_input
|
39
39
|
retry
|
40
40
|
end
|
41
|
-
rescue ::Yap::Shell::CommandUnknownError => ex
|
42
|
-
Treefell['shell'].puts "rescued #{ex}, telling user"
|
43
|
-
puts " CommandError: #{ex.message}"
|
44
41
|
rescue ::Yap::Shell::Parser::ParseError => ex
|
45
42
|
Treefell['shell'].puts "rescued #{ex}, telling user"
|
46
43
|
puts " Parse error: #{ex.message}"
|
47
|
-
ensure
|
48
|
-
@world.editor.reset_line
|
49
44
|
end
|
50
45
|
|
51
46
|
ensure_process_group_controls_the_tty
|
@@ -209,6 +204,8 @@ module Yap::Shell
|
|
209
204
|
# if we haven't been made the process group controlling the TTY that we
|
210
205
|
# become so. This method intentionally blocks.
|
211
206
|
def ensure_process_group_controls_the_tty
|
207
|
+
return unless STDIN.isatty
|
208
|
+
|
212
209
|
tty_pgrp = Termios.tcgetpgrp(STDIN)
|
213
210
|
while ![Process.pid, Process.getpgrp].include?(tty_pgrp)
|
214
211
|
Termios.tcsetpgrp(STDIN, Process.pid)
|
data/lib/yap/shell/version.rb
CHANGED
data/lib/yap/shell.rb
CHANGED
@@ -11,7 +11,6 @@ module Yap
|
|
11
11
|
|
12
12
|
autoload :CommandFactory, "yap/shell/commands"
|
13
13
|
autoload :CommandError, "yap/shell/commands"
|
14
|
-
autoload :CommandUnknownError, "yap/shell/commands"
|
15
14
|
autoload :BuiltinCommand, "yap/shell/commands"
|
16
15
|
autoload :FileSystemCommand, "yap/shell/commands"
|
17
16
|
autoload :RubyCommand, "yap/shell/commands"
|
@@ -102,7 +101,14 @@ module Yap
|
|
102
101
|
@world.editor.puts "^C"
|
103
102
|
retry
|
104
103
|
rescue Exception => ex
|
105
|
-
|
104
|
+
if !ex.is_a?(SystemExit)
|
105
|
+
if $stdout.isatty
|
106
|
+
binding.pry
|
107
|
+
else
|
108
|
+
$stdout.puts ex.message
|
109
|
+
raise ex
|
110
|
+
end
|
111
|
+
end
|
106
112
|
end
|
107
113
|
end
|
108
114
|
end
|
data/lib/yap/world.rb
CHANGED
@@ -33,24 +33,28 @@ module Yap
|
|
33
33
|
|
34
34
|
# ensure yap directory exists
|
35
35
|
if !File.exists?(configuration.yap_path)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
36
|
+
if configuration.skip_first_time?
|
37
|
+
# skipping first time
|
38
|
+
else
|
39
|
+
puts
|
40
|
+
puts yellow("Yap directory not found: #{configuration.yap_path}")
|
41
|
+
puts
|
42
|
+
puts "Initializing yap for the first time:"
|
43
|
+
puts
|
44
|
+
|
45
|
+
print " Creating #{configuration.yap_path} "
|
46
|
+
FileUtils.mkdir_p configuration.yap_path
|
47
|
+
puts green("done")
|
48
|
+
|
49
|
+
print " Creating default #{configuration.preferred_yaprc_path} "
|
50
|
+
FileUtils.cp configuration.yaprc_template_path, configuration.yap_path
|
51
|
+
puts green("done")
|
52
|
+
puts
|
53
|
+
puts "To tweak yap take a look at #{configuration.preferred_yaprc_path}."
|
54
|
+
puts
|
55
|
+
puts "Reloading shell"
|
56
|
+
reload!
|
57
|
+
end
|
54
58
|
end
|
55
59
|
|
56
60
|
@editor = RawLine::Editor.create(dom: dom)
|
@@ -147,6 +151,7 @@ module Yap
|
|
147
151
|
end
|
148
152
|
|
149
153
|
def foreground?
|
154
|
+
return unless STDIN.isatty
|
150
155
|
Process.getpgrp == Termios.tcgetpgrp($stdout)
|
151
156
|
end
|
152
157
|
|