Class: Yap::Shell::Impl

Inherits:
Object
  • Object
show all
Defined in:
lib/yap/shell.rb

Instance Method Summary collapse

Constructor Details

#initialize(addons:) ⇒ Impl

Returns a new instance of Impl.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/yap/shell.rb', line 25

def initialize(addons:)
  @original_file_descriptor_flags = {
    stdin: $stdin.fcntl(Fcntl::F_GETFL, 0),
    stdout: $stdout.fcntl(Fcntl::F_GETFL, 0),
    stderr: $stderr.fcntl(Fcntl::F_GETFL, 0)
  }

  @stdin = $stdin
  @stdout = $stdout
  @stderr = $stderr

  @stdout.sync = true
  @stderr.sync = true

  addons_str = "\n  - " + addons.map(&:class).map(&:name).join("\n  - ")
  Treefell['shell'].puts "Constructing world instance with addons: #{addons_str}"
  @world = Yap::World.instance(addons:addons)
end

Instance Method Details

#replObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/yap/shell.rb', line 65

def repl
  context = Yap::Shell::Execution::Context.new(
    stdin:  @stdin,
    stdout: @stdout,
    stderr: @stderr
  )

  @world.repl.on_input do |input|
    Treefell['shell'].puts "repl received input: #{input.inspect}"
    evaluation = Yap::Shell::Evaluation.new(stdin:@stdin, stdout:@stdout, stderr:@stderr, world:@world)
    evaluation.evaluate(input) do |command, stdin, stdout, stderr, wait|
      Treefell['shell'].puts <<-DEBUG.gsub(/^\s*\|/, '')
        |adding #{command} to run in context of:
        |  stdin: #{stdin.inspect}
        |  stdout: #{stdout.inspect}
        |  stderr: #{stderr.inspect}
        |  wait for child process to complete? #{wait.inspect}
      DEBUG
      context.clear_commands
      context.add_command_to_run command, stdin:stdin, stdout:stdout, stderr:stderr, wait:wait

      with_original_file_descriptor_flags do
        context.execute(world:@world)
      end
    end
  end

  begin
    Treefell['shell'].puts "enter interactive mode"
    @world.interactive!
  # rescue Errno::EIO => ex
  #   # This happens when yap is no longer the foreground process
  #   # but it tries to receive input/output from the tty. I believe it
  #   # is a race condition when launching a child process.
  rescue Interrupt
    Treefell['shell'].puts "^C"
    @world.editor.puts "^C"
    retry
  rescue Exception => ex
    if !ex.is_a?(SystemExit)
      if $stdout.isatty
        binding.pry
      else
        $stdout.puts ex.class.name
        raise ex
      end
    end
  end
end

#with_original_file_descriptor_flags(&block) ⇒ Object

Yields to the passed in block after restoring the file descriptor flags that Yap started in. This ensures that any changes Yap has made to run the shell don’t interfere with child processes.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/yap/shell.rb', line 47

def with_original_file_descriptor_flags(&block)
  current_file_descriptor_flags = {
    stdin: $stdin.fcntl(Fcntl::F_GETFL, 0),
    stdout: $stdout.fcntl(Fcntl::F_GETFL, 0),
    stderr: $stderr.fcntl(Fcntl::F_GETFL, 0)
  }

  $stdin.fcntl(Fcntl::F_SETFL, @original_file_descriptor_flags[:stdin])
  $stdout.fcntl(Fcntl::F_SETFL, @original_file_descriptor_flags[:stdout])
  $stderr.fcntl(Fcntl::F_SETFL, @original_file_descriptor_flags[:stderr])

  yield
ensure
  $stdin.fcntl(Fcntl::F_SETFL, current_file_descriptor_flags[:stdin])
  $stdout.fcntl(Fcntl::F_SETFL, current_file_descriptor_flags[:stdout])
  $stderr.fcntl(Fcntl::F_SETFL, current_file_descriptor_flags[:stderr])
end