yap-shell 0.7.1 → 0.7.2

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -24
  3. data/Gemfile +1 -5
  4. data/LICENSE.txt +17 -18
  5. data/README.md +28 -14
  6. data/Rakefile +4 -1
  7. data/bin/yap +1 -3
  8. data/lib/.gitkeep +0 -0
  9. data/yap-shell.gemspec +12 -11
  10. metadata +19 -184
  11. data/.rspec +0 -2
  12. data/.travis.yml +0 -11
  13. data/DESIGN.md +0 -87
  14. data/Gemfile.travis +0 -8
  15. data/Gemfile.travis.lock +0 -104
  16. data/WISHLIST.md +0 -54
  17. data/bin/yap-dev +0 -45
  18. data/lib/tasks/gem.rake +0 -62
  19. data/lib/yap.rb +0 -52
  20. data/lib/yap/addon.rb +0 -24
  21. data/lib/yap/addon/base.rb +0 -52
  22. data/lib/yap/addon/export_as.rb +0 -12
  23. data/lib/yap/addon/loader.rb +0 -84
  24. data/lib/yap/addon/path.rb +0 -56
  25. data/lib/yap/addon/rc_file.rb +0 -21
  26. data/lib/yap/addon/reference.rb +0 -22
  27. data/lib/yap/cli.rb +0 -4
  28. data/lib/yap/cli/commands.rb +0 -6
  29. data/lib/yap/cli/commands/addon.rb +0 -14
  30. data/lib/yap/cli/commands/addon/disable.rb +0 -35
  31. data/lib/yap/cli/commands/addon/enable.rb +0 -35
  32. data/lib/yap/cli/commands/addon/list.rb +0 -37
  33. data/lib/yap/cli/commands/addon/search.rb +0 -99
  34. data/lib/yap/cli/commands/generate.rb +0 -13
  35. data/lib/yap/cli/commands/generate/addon.rb +0 -258
  36. data/lib/yap/cli/commands/generate/addonrb.template +0 -22
  37. data/lib/yap/cli/commands/generate/gemspec.template +0 -25
  38. data/lib/yap/cli/commands/generate/license.template +0 -21
  39. data/lib/yap/cli/commands/generate/rakefile.template +0 -6
  40. data/lib/yap/cli/commands/generate/readme.template +0 -40
  41. data/lib/yap/cli/options.rb +0 -162
  42. data/lib/yap/cli/options/addon.rb +0 -64
  43. data/lib/yap/cli/options/addon/disable.rb +0 -62
  44. data/lib/yap/cli/options/addon/enable.rb +0 -63
  45. data/lib/yap/cli/options/addon/list.rb +0 -65
  46. data/lib/yap/cli/options/addon/search.rb +0 -76
  47. data/lib/yap/cli/options/generate.rb +0 -59
  48. data/lib/yap/cli/options/generate/addon.rb +0 -63
  49. data/lib/yap/configuration.rb +0 -74
  50. data/lib/yap/gem_helper.rb +0 -195
  51. data/lib/yap/gem_tasks.rb +0 -6
  52. data/lib/yap/shell.rb +0 -116
  53. data/lib/yap/shell/aliases.rb +0 -58
  54. data/lib/yap/shell/builtins.rb +0 -18
  55. data/lib/yap/shell/builtins/alias.rb +0 -42
  56. data/lib/yap/shell/builtins/cd.rb +0 -57
  57. data/lib/yap/shell/builtins/env.rb +0 -11
  58. data/lib/yap/shell/commands.rb +0 -163
  59. data/lib/yap/shell/evaluation.rb +0 -439
  60. data/lib/yap/shell/evaluation/shell_expansions.rb +0 -99
  61. data/lib/yap/shell/event_emitter.rb +0 -18
  62. data/lib/yap/shell/execution.rb +0 -16
  63. data/lib/yap/shell/execution/builtin_command_execution.rb +0 -20
  64. data/lib/yap/shell/execution/command_execution.rb +0 -30
  65. data/lib/yap/shell/execution/context.rb +0 -128
  66. data/lib/yap/shell/execution/file_system_command_execution.rb +0 -137
  67. data/lib/yap/shell/execution/result.rb +0 -18
  68. data/lib/yap/shell/execution/ruby_command_execution.rb +0 -80
  69. data/lib/yap/shell/execution/shell_command_execution.rb +0 -30
  70. data/lib/yap/shell/prompt.rb +0 -21
  71. data/lib/yap/shell/repl.rb +0 -237
  72. data/lib/yap/shell/version.rb +0 -5
  73. data/lib/yap/world.rb +0 -286
  74. data/rcfiles/yaprc +0 -390
  75. data/scripts/4 +0 -8
  76. data/scripts/bg-vim +0 -4
  77. data/scripts/fail +0 -3
  78. data/scripts/letters +0 -8
  79. data/scripts/lots-of-output +0 -6
  80. data/scripts/pass +0 -3
  81. data/scripts/simulate-long-running +0 -4
  82. data/scripts/write-to-stderr.rb +0 -3
  83. data/scripts/write-to-stdout.rb +0 -3
  84. data/spec/features/addons/generating_an_addon_spec.rb +0 -55
  85. data/spec/features/addons/using_an_addon_spec.rb +0 -182
  86. data/spec/features/aliases_spec.rb +0 -78
  87. data/spec/features/environment_variables_spec.rb +0 -69
  88. data/spec/features/filesystem_commands_spec.rb +0 -61
  89. data/spec/features/first_time_spec.rb +0 -45
  90. data/spec/features/grouping_spec.rb +0 -81
  91. data/spec/features/line_editing_spec.rb +0 -174
  92. data/spec/features/range_spec.rb +0 -35
  93. data/spec/features/redirection_spec.rb +0 -234
  94. data/spec/features/repetition_spec.rb +0 -118
  95. data/spec/features/shell_expansions_spec.rb +0 -127
  96. data/spec/spec_helper.rb +0 -172
  97. data/spec/support/matchers/have_not_printed.rb +0 -30
  98. data/spec/support/matchers/have_printed.rb +0 -68
  99. data/spec/support/very_soon.rb +0 -9
  100. data/spec/support/yap_spec_dsl.rb +0 -258
  101. data/test.rb +0 -206
  102. data/update-rawline.sh +0 -6
@@ -1,99 +0,0 @@
1
- module Yap::Shell
2
- class Evaluation
3
- class ShellExpansions
4
- attr_reader :aliases, :world
5
-
6
- def initialize(world:, aliases: Aliases.instance)
7
- @world = world
8
- @aliases = aliases
9
- end
10
-
11
- def expand_aliases_in(input)
12
- Treefell['shell'].puts "shell-expansions expand aliases in: #{input.inspect}"
13
- head, *tail = input.split(/\s/, 2).first
14
- expanded = if aliases.has_key?(head)
15
- new_head=aliases.fetch_alias(head)
16
- [new_head].concat(tail).join(" ")
17
- else
18
- input
19
- end
20
- expanded
21
- end
22
-
23
- def expand_words_in(input, escape_directory_expansions: true)
24
- Treefell['shell'].puts "shell-expansions expand words in: #{input.inspect}"
25
- expanded = [input].flatten.inject([]) do |results,str|
26
- results << process_expansions(
27
- word_expand(str),
28
- escape_directory_expansions: escape_directory_expansions
29
- )
30
- end.flatten
31
- expanded
32
- end
33
-
34
- def expand_variables_in(input)
35
- Treefell['shell'].puts "shell-expansions expand variables in: #{input.inspect}"
36
- env_expand(input)
37
- end
38
-
39
- private
40
-
41
- def env_expand(str)
42
- # match "$a", "$a $b", "$a$b", "$cat$dog $foo"
43
- str.gsub(/\$([^\$\s]+)/) do |match,*args|
44
- var_name = match[1..-1]
45
- if var_name == '?'
46
- (world.last_result ? world.last_result.status_code.to_s : '0').tap do |expanded|
47
- Treefell['shell'].puts "shell-expansions expanding env var #{match} to #{expanded}"
48
- end
49
- elsif world.env.has_key?(var_name)
50
- world.env.fetch(var_name).tap do |expanded|
51
- Treefell['shell'].puts "shell-expansions expanding env var #{match} to #{expanded}"
52
- end
53
- else
54
- match
55
- end
56
- end
57
- end
58
-
59
- def word_expand(str)
60
- content = str.scan(/\{([^\}]+)\}/).flatten.first
61
- if content
62
- expansions = content.split(",", -1)
63
-
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}"
70
- end
71
- else
72
- [str]
73
- end
74
- end
75
-
76
- def process_expansions(expansions, escape_directory_expansions: true)
77
- expansions.map do |s|
78
- # Basic bash-style tilde expansion
79
- s.gsub!(/\A~(.*)/, world.env["HOME"] + '\1')
80
-
81
- # Basic bash-style variable expansion
82
- s = env_expand(s)
83
-
84
- # Basic bash-style path-name expansion
85
- expansions = Dir[s]
86
- if expansions.any?
87
- if escape_directory_expansions
88
- expansions.map(&:shellescape)
89
- else
90
- expansions
91
- end
92
- else
93
- s
94
- end
95
- end.flatten
96
- end
97
- end
98
- end
99
- end
@@ -1,18 +0,0 @@
1
- module Yap::Shell
2
- module EventEmitter
3
- def _callbacks
4
- @_callbacks ||= Hash.new { |h, k| h[k] = [] }
5
- end
6
-
7
- def on(type, *args, &blk)
8
- _callbacks[type] << blk
9
- self
10
- end
11
-
12
- def emit(type, *args)
13
- _callbacks[type].each do |blk|
14
- blk.call(*args)
15
- end
16
- end
17
- end
18
- end
@@ -1,16 +0,0 @@
1
- module Yap::Shell
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
- Context.register BuiltinCommandExecution, command_type: :BuiltinCommand
12
- Context.register FileSystemCommandExecution, command_type: :FileSystemCommand
13
- Context.register ShellCommandExecution, command_type: :ShellCommand
14
- Context.register RubyCommandExecution, command_type: :RubyCommand
15
- end
16
- end
@@ -1,20 +0,0 @@
1
- module Yap::Shell::Execution
2
- require 'yap/shell/execution/result'
3
-
4
- class BuiltinCommandExecution < CommandExecution
5
- on_execute do |command:, n:, of:, wait:|
6
- Treefell['shell'].puts "builtin command executing: #{command}"
7
- status_code = command.execute(stdin:@stdin, stdout:@stdout, stderr:@stderr)
8
- if status_code == :resume
9
- Treefell['shell'].puts "builtin command execution resumed: #{command}"
10
- ResumeExecution.new(status_code:0, directory:Dir.pwd, n:n, of:of)
11
- else
12
- @stdout.close if @stdout != $stdout && !@stdout.closed?
13
- @stderr.close if @stderr != $stderr && !@stderr.closed?
14
- Result.new(status_code:status_code, directory:Dir.pwd, n:n, of:of).tap do |result|
15
- Treefell['shell'].puts "builtin command execution done with result=#{result.inspect}"
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,30 +0,0 @@
1
- module Yap::Shell::Execution
2
- class CommandExecution
3
- attr_reader :stdin, :stdout, :stderr, :world
4
-
5
- def self.on_execute(&blk)
6
- if block_given?
7
- @on_execute_blk = blk
8
- else
9
- @on_execute_blk
10
- end
11
- end
12
-
13
- def initialize(stdin:, stdout:, stderr:, world:)
14
- @stdin, @stdout, @stderr = stdin, stdout, stderr
15
- @world = world
16
- end
17
-
18
- def execute(command:, n:, of:, wait:true)
19
- if self.class.on_execute
20
- self.instance_exec(command:command, n:n, of:of, wait:wait, &self.class.on_execute)
21
- else
22
- raise NotImplementedError, "on_execute block hasn't been implemented!"
23
- end
24
- end
25
-
26
- def suspended?
27
- @suspended
28
- end
29
- end
30
- end
@@ -1,128 +0,0 @@
1
- require 'uri'
2
-
3
- module Yap::Shell::Execution
4
- class Context
5
- def self.on(event=nil, &blk)
6
- @on_callbacks ||= Hash.new{ |h,k| h[k] = [] }
7
- if event
8
- @on_callbacks[event.to_sym].push blk
9
- end
10
- @on_callbacks
11
- end
12
-
13
- def self.fire(event, context, *args)
14
- on[event.to_sym].each do |block|
15
- block.call(context, *args)
16
- end
17
- end
18
-
19
- def self.register(context, command_type:)
20
- raise "context cannot be nil" if context.nil?
21
- @registrations ||= {}
22
- @registrations[command_type] = context
23
- true
24
- end
25
-
26
- def self.execution_context_for(command)
27
- @registrations[command.type] || raise("No execution context found for given #{command.type} command: #{command.inspect}")
28
- end
29
-
30
- def initialize(stdin:, stdout:, stderr:)
31
- @stdin, @stdout, @stderr = stdin, stdout, stderr
32
- @command_queue = []
33
- @suspended_execution_contexts = []
34
- end
35
-
36
- def add_command_to_run(command, stdin:, stdout:, stderr:, wait:)
37
- @command_queue << [command, stdin, stdout, stderr, wait]
38
- end
39
-
40
- def clear_commands
41
- @command_queue.clear
42
- end
43
-
44
- def execute(world:)
45
- results = []
46
- @command_queue.each_with_index do |(command, stdin, stdout, stderr, wait), reversed_i|
47
- of = @command_queue.length
48
- i = reversed_i + 1
49
- stdin = @stdin if stdin == :stdin
50
- stdout = @stdout if stdout == :stdout
51
- stderr = @stderr if stderr == :stderr
52
-
53
- execution_context_factory = self.class.execution_context_for(command)
54
- if execution_context_factory
55
- execution_context = execution_context_factory.new(
56
- stdin: stdin,
57
- stdout: stdout,
58
- stderr: stderr,
59
- world: world
60
- )
61
-
62
- @saved_tty_attrs = Termios.tcgetattr(STDIN) if STDIN.isatty
63
-
64
- Treefell['shell'].puts "firing :before_execute for #{command}"
65
- self.class.fire :before_execute, world, command: command
66
-
67
- begin
68
- result = execution_context.execute(command:command, n:i, of:of, wait:wait)
69
- rescue Exception => ex
70
- raise(ex) if ex.is_a?(SystemExit)
71
-
72
- Treefell['shell'].puts "rescued unexpected error=#{ex} with message=#{ex.message.inspect}"
73
- puts <<-ERROR.gsub(/^\s*\|/, '')
74
- |******************************
75
- |\e[31mWhoops! An unexpected error has occurred\e[0m
76
- |******************************
77
- |
78
- |The error was:
79
- | #{ex.message}
80
- |
81
- |Backtrace:
82
- |#{ex.backtrace.join("\n")}
83
- |
84
- |Report this to yap-shell on github:
85
- | https://github.com/zdennis/yap-shell/issues/new?title=#{URI.escape(ex.message)}
86
- |
87
- ERROR
88
- end
89
-
90
- Treefell['shell'].puts "firing :after_execute for #{command}"
91
- self.class.fire :after_execute, world, command: command, result: result
92
-
93
- results << process_execution_result(execution_context:execution_context, result:result)
94
- Termios.tcsetattr(STDIN, Termios::TCSANOW, @saved_tty_attrs) if STDIN.isatty
95
- end
96
- end
97
-
98
- clear_commands
99
-
100
- results.last
101
- end
102
-
103
- private
104
-
105
- def process_execution_result(execution_context:, result:)
106
- case result
107
- when SuspendExecution
108
- Treefell['shell'].puts "suspending execution context"
109
- @suspended_execution_contexts.push execution_context
110
- return result
111
-
112
- when ResumeExecution
113
- Treefell['shell'].puts "resuming suspended execution context"
114
- execution_context = @suspended_execution_contexts.pop
115
- if execution_context
116
- nresult = execution_context.resume
117
- Treefell['shell'].puts "resuming suspended execution context success"
118
- return process_execution_result execution_context: execution_context, result: nresult
119
- else
120
- Treefell['shell'].puts "error: cannot resume execution when there is nothing suspended"
121
- @stderr.puts "fg: No such job"
122
- end
123
- else
124
- return result
125
- end
126
- end
127
- end
128
- end
@@ -1,137 +0,0 @@
1
- require 'termios'
2
-
3
- module Yap::Shell::Execution
4
- require 'yap/shell/execution/result'
5
-
6
- class FileSystemCommandExecution < CommandExecution
7
- on_execute do |command:, n:, of:, wait:, resume_blk:nil|
8
- stdin, stdout, stderr, world = @stdin, @stdout, @stderr, @world
9
- result = nil
10
- if resume_blk
11
- pid = resume_blk.call
12
- else
13
- r,w = nil, nil
14
- if command.heredoc
15
- r,w = IO.pipe
16
- stdin = r
17
- end
18
-
19
- pid = fork do
20
- # reset signals in case any were ignored
21
- Signal.trap("SIGINT", "DEFAULT")
22
- Signal.trap("SIGQUIT", "DEFAULT")
23
- Signal.trap("SIGTSTP", "DEFAULT")
24
- Signal.trap("SIGTTIN", "DEFAULT")
25
- Signal.trap("SIGTTOU", "DEFAULT")
26
-
27
- # Set the process group of the forked to child to that of the
28
- Process.setpgrp
29
-
30
- $stdin.reopen stdin
31
- $stdout.reopen stdout
32
- $stderr.reopen stderr
33
-
34
- begin
35
- before = ENV.to_h.dup
36
- ENV.replace(@world.env)
37
- Treefell['shell'].puts <<-MSG.gsub(/^\s*\|/, '')
38
- |forked child process
39
- | pid=#{Process.pid} #{command.to_executable_str}
40
- | stdin=#{stdin.inspect}
41
- | stdout=#{stdout.inspect}
42
- | stderr=#{stderr.inspect}
43
- | $stdin=#{$stdin.inspect}
44
- | $stdout=#{$stdout.inspect}
45
- | $stderr=#{$stderr.inspect}
46
- MSG
47
- Kernel.exec command.to_executable_str
48
- ensure
49
- ENV.replace(before)
50
- end
51
- end
52
- Treefell['shell'].puts "forked child process pid=#{pid} to execute #{command}"
53
-
54
- # Put the child process into a process group of its own
55
- Process.setpgid pid, pid
56
-
57
- if command.heredoc
58
- Treefell['shell'].puts "command has heredoc, wriing to stdin"
59
- w.write command.heredoc
60
- w.close
61
- end
62
- end
63
-
64
- # Set terminal's process group to that of the child process
65
- Termios.tcsetpgrp STDIN, pid if STDIN.isatty
66
- pid, status = Process.wait2(pid, Process::WUNTRACED) if wait
67
-
68
- # If we're not printing to the terminal then close in/out/err. This
69
- # is so the next command in the pipeline can complete and don't hang waiting for
70
- # stdin after the command that's writing to its stdin has completed.
71
- if stdout != $stdout && stdout.is_a?(IO) && !stdout.closed? then
72
- Treefell['shell'].puts "closing stdout for child process with pid=#{pid}"
73
- stdout.close
74
- end
75
- if stderr != $stderr && stderr.is_a?(IO) && !stderr.closed? then
76
- Treefell['shell'].puts "closing stderr for child process with pid=#{pid}"
77
- stderr.close
78
- end
79
- # if stdin != $stdin && !stdin.closed? then stdin.close end
80
-
81
-
82
- # if the pid that just stopped was the process group owner then
83
- # give it back to the us so we can become the foreground process
84
- # in the terminal
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
93
- end
94
-
95
- # if the reason we stopped is from being suspended
96
- sigtstp = Signal.list["TSTP"]
97
- if status && status.stopsig == sigtstp
98
- Treefell['shell'].puts "process pid=#{pid} suspended by signal=#{status.stopsig.inspect}"
99
- Treefell['shell'].puts "$?: #{$?.inspect}"
100
- suspended(command:command, n:n, of:of, pid: pid)
101
- result = Yap::Shell::Execution::SuspendExecution.new(status_code:nil, directory:Dir.pwd, n:n, of:of)
102
- else
103
- caused_by_signal = status ? (status.termsig || status.stopsig) : nil
104
- Treefell['shell'].puts "process pid=#{pid} stopped by signal=#{caused_by_signal.inspect}"
105
- Treefell['shell'].puts "$?: #{$?.inspect}"
106
- # if a signal killed or stopped the process (such as SIGINT or SIGTSTP) $? is nil.
107
- exitstatus = $? ? $?.exitstatus : nil
108
- result = Yap::Shell::Execution::Result.new(status_code:exitstatus, directory:Dir.pwd, n:n, of:of)
109
- end
110
- end
111
-
112
- def resume
113
- args = @suspended
114
- @suspended = nil
115
- pid = args[:pid]
116
- sigcont = Signal.list["CONT"]
117
-
118
- Treefell['shell'].puts "resuming suspended process pid=#{pid} by sending it signal=#{sigcont}"
119
- resume_blk = lambda do
120
- Process.kill sigcont, pid
121
- pid
122
- end
123
-
124
- self.instance_exec command:args[:command], n:args[:n], of:args[:of], resume_blk:resume_blk, wait:true, &self.class.on_execute
125
- end
126
-
127
- def suspended(command:, n:, of:, pid:)
128
- Treefell['shell'].puts "process pid=#{pid} suspended"
129
- @suspended = {
130
- command: command,
131
- n: n,
132
- of: of,
133
- pid: pid
134
- }
135
- end
136
- end
137
- end