yap-shell 0.5.2 → 0.6.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +11 -0
  5. data/Gemfile.travis +8 -0
  6. data/README.md +9 -11
  7. data/addons/history/history.rb +1 -0
  8. data/addons/history_search/history_search.rb +21 -17
  9. data/bin/yap +47 -55
  10. data/bin/yap-dev +0 -1
  11. data/lib/yap/configuration.rb +25 -0
  12. data/lib/yap/shell/builtins/alias.rb +16 -0
  13. data/lib/yap/shell/commands.rb +15 -3
  14. data/lib/yap/shell/evaluation/shell_expansions.rb +10 -10
  15. data/lib/yap/shell/evaluation.rb +29 -4
  16. data/lib/yap/shell/execution/context.rb +3 -2
  17. data/lib/yap/shell/execution/file_system_command_execution.rb +9 -17
  18. data/lib/yap/shell/repl.rb +2 -5
  19. data/lib/yap/shell/version.rb +1 -1
  20. data/lib/yap/shell.rb +8 -2
  21. data/lib/yap/world.rb +23 -18
  22. data/lib/yap.rb +52 -7
  23. data/spec/features/aliases_spec.rb +78 -0
  24. data/spec/features/environment_variables_spec.rb +69 -0
  25. data/spec/features/filesystem_commands_spec.rb +61 -0
  26. data/spec/features/first_time_spec.rb +45 -0
  27. data/spec/features/grouping_spec.rb +81 -0
  28. data/spec/features/line_editing_spec.rb +166 -0
  29. data/spec/features/range_spec.rb +35 -0
  30. data/spec/features/redirection_spec.rb +225 -0
  31. data/spec/features/repetition_spec.rb +118 -0
  32. data/spec/features/shell_expansions_spec.rb +127 -0
  33. data/spec/spec_helper.rb +162 -0
  34. data/spec/support/matchers/have_not_printed.rb +30 -0
  35. data/spec/support/matchers/have_printed.rb +30 -0
  36. data/spec/support/very_soon.rb +9 -0
  37. data/spec/support/yap_spec_dsl.rb +240 -0
  38. data/yap-shell.gemspec +4 -2
  39. metadata +69 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87a1ed22865947c8ef75b2a16007dc72270dab7a
4
- data.tar.gz: 38e78b4b608f6ec74c922472d6e965ef0fcccd1e
3
+ metadata.gz: 7186e70881e605ba5563cd30e9674030c55f4332
4
+ data.tar.gz: abbfa86bde0fabf472adca6a87843588e8760671
5
5
  SHA512:
6
- metadata.gz: 66989ed7684b9327859f04c655991b49bbeefeb83706bb14889395e32b75d08ad81a6858d780ac78ad75bb0fc1a35b3b99b8467eac1275d35a51bdca114a65a8
7
- data.tar.gz: ed9d4d26e65195606b817ac1f6c46d7ac490cf147cb6e74471e7ce192f41c7e5082ffba2e58e931b61fa83013dfc5f1bcc14b46c39389d24ef4d93159a2cd645
6
+ metadata.gz: 4498e667793d6009c6a988fd85b3977b7a01d79dee15565e71b9c6b10cc86a844263f9215205bf382e9ad152fde34589890d022a7bdb92d536204e3595df967f
7
+ data.tar.gz: fb6bff600285457f6aeea74c1fb5bf8d843dbba8b4a3b17c791b69ebd5dd93a5c1e2e0f7b7a660ed64afe468e49a3e2a73801a643d17fa811bfa6055ced9710f
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.3
1
+ 2.3.1
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ cache: bundler
5
+ gemfile: Gemfile.travis
6
+ script:
7
+ - bundle exec rspec -fd spec
8
+ notifications:
9
+ on_success: change
10
+ on_failure: always
11
+ on_start: false
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
- # Yap
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
- ## Installation
3
+ # Yap
6
4
 
7
- Add this line to your application's Gemfile:
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
- gem 'yap-shell'
7
+ See the slide deck that [introduces Yap](http://slides.com/zdennis/yaptastic-1#/)
10
8
 
11
- And then execute:
9
+ ## Installation
12
10
 
13
- $ bundle
11
+ This should not go in your Gemfile, you should install from the command line:
14
12
 
15
- Or install it yourself as:
13
+ > gem install yap-shell
16
14
 
17
- $ gem install yap-shell
15
+ Then follow the on-screen installation instructions.
18
16
 
19
17
  ## Usage
20
18
 
21
- TODO: Write usage instructions here
19
+ See the Yap [shell reference](https://github.com/zdennis/yap-shell/wiki/ShellReference)
22
20
 
23
21
  ## Contributing
24
22
 
@@ -3,6 +3,7 @@ class History < Addon
3
3
  attr_reader :position
4
4
 
5
5
  def initialize_world(world)
6
+ return unless world.configuration.use_history?
6
7
  @world = world
7
8
 
8
9
  @file = world.configuration.path_for('history')
@@ -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
- # [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
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: 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
- if ENV['YAP_SHELL'] != 'active'
4
- # Start YAP with a pristine environment
5
- env2keep = {
6
- # DISPLAY needs to be inherited in order to launch GUI apps
7
- 'DISPLAY' => ENV['DISPLAY'],
8
- 'HOME' => ENV['HOME'],
9
- 'PATH' => ENV['PATH'],
10
-
11
- # For Yap's sanity
12
- 'RUBYOPT' => '-rubygems -EUTF-8',
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
22
- 'DEBUG' => ENV['DEBUG'],
23
- 'TREEFELL_OUT' => ENV['TREEFELL_OUT']
24
- }
25
-
26
- ENV.clear
27
- env_params = env2keep.each_with_object([]) do |(key,value),arr|
28
- next if value.nil?
29
- arr << %|#{key}="#{value}"|
30
- end.join(' ')
31
-
32
- cmd = %|env -i #{env_params} #{File.expand_path(__FILE__)}|
33
- exec cmd
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
@@ -4,6 +4,5 @@ require 'bundler'
4
4
  Bundler.setup
5
5
  require 'pry'
6
6
 
7
- ENV['YAP_SHELL'] = 'active'
8
7
  $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
9
8
  load File.dirname(__FILE__) + '/yap'
@@ -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
@@ -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 then FileSystemCommand.new(world:world, str:command, args:args, heredoc:heredoc)
16
+ when FileSystemCommand then FileSystemCommand.new(world:world, str:command, args:args, heredoc:heredoc)
18
17
  else
19
- raise CommandUnknownError, "Don't know how to execute command: #{command}"
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
- str.gsub(/\$(\S+)/) do |match,*args|
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
- # Be compatible with Bash/Zsh which only do word-expansion if there
64
- # at least one comma listed. E.g. "a_{1,2}" => "a_1 a_2" whereas
65
- # "a_{1}" => "a_{1}"
66
- if expansions.length > 1
67
- expanded = expansions.map { |expansion| str.sub(/\{([^\}]+)\}/, expansion) }.tap do |expanded|
68
- Treefell['shell'].puts "shell-expansions expanding words in #{str} to #{expanded}"
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)
@@ -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(/\s+/)
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
- ["'#{node.lvalue}'"]
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
- stderr = :stdout
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
- stdout = :stderr
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 pid == Termios.tcgetpgrp(STDIN)
96
- Treefell['shell'].puts <<-DEBUG.gsub(/^\s*\|/, '')
97
- |restoring process group for STDIN to yap process with pid=#{Process.pid}
98
- DEBUG
99
- Process.setpgid Process.pid, Process.pid
100
- Termios.tcsetpgrp STDIN, Process.pid
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
@@ -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)
@@ -1,5 +1,5 @@
1
1
  module Yap
2
2
  module Shell
3
- VERSION = "0.5.2"
3
+ VERSION = "0.6.0"
4
4
  end
5
5
  end
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
- binding.pry unless ex.is_a?(SystemExit)
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
- puts
37
- puts yellow("Yap directory not found: #{configuration.yap_path}")
38
- puts
39
- puts "Initializing yap for the first time:"
40
- puts
41
-
42
- print " Creating #{configuration.yap_path} "
43
- FileUtils.mkdir_p configuration.yap_path
44
- puts green("done")
45
-
46
- print " Creating default #{configuration.preferred_yaprc_path} "
47
- FileUtils.cp configuration.yaprc_template_path, configuration.yap_path
48
- puts green("done")
49
- puts
50
- puts "To tweak yap take a look at #{configuration.preferred_yaprc_path}."
51
- puts
52
- puts "Reloading shell"
53
- reload!
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