yap-shell 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
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