neovim 0.6.2 → 0.9.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/docs.yml +36 -0
  3. data/.github/workflows/linter.yml +32 -0
  4. data/.github/workflows/tests.yml +62 -0
  5. data/.gitignore +5 -1
  6. data/.rubocop.yml +149 -0
  7. data/CHANGELOG.md +56 -0
  8. data/CODE_OF_CONDUCT.md +3 -3
  9. data/Gemfile +0 -11
  10. data/README.md +22 -23
  11. data/Rakefile +47 -15
  12. data/VimFlavor +1 -0
  13. data/exe/neovim-ruby-host +5 -0
  14. data/lib/neovim.rb +15 -6
  15. data/lib/neovim/api.rb +2 -1
  16. data/lib/neovim/buffer.rb +81 -53
  17. data/lib/neovim/client.rb +226 -41
  18. data/lib/neovim/client_info.rb +46 -0
  19. data/lib/neovim/connection.rb +73 -0
  20. data/lib/neovim/event_loop.rb +41 -37
  21. data/lib/neovim/executable.rb +1 -0
  22. data/lib/neovim/host.rb +50 -51
  23. data/lib/neovim/host/cli.rb +41 -0
  24. data/lib/neovim/host/loader.rb +1 -4
  25. data/lib/neovim/line_range.rb +16 -16
  26. data/lib/neovim/logging.rb +18 -18
  27. data/lib/neovim/message.rb +70 -0
  28. data/lib/neovim/plugin.rb +7 -5
  29. data/lib/neovim/plugin/dsl.rb +10 -4
  30. data/lib/neovim/plugin/handler.rb +8 -8
  31. data/lib/neovim/remote_object.rb +8 -5
  32. data/lib/neovim/ruby_provider.rb +52 -26
  33. data/lib/neovim/ruby_provider/buffer_ext.rb +1 -0
  34. data/lib/neovim/ruby_provider/object_ext.rb +5 -0
  35. data/lib/neovim/ruby_provider/vim.rb +19 -6
  36. data/lib/neovim/ruby_provider/window_ext.rb +1 -0
  37. data/lib/neovim/session.rb +45 -50
  38. data/lib/neovim/tabpage.rb +8 -15
  39. data/lib/neovim/version.rb +1 -1
  40. data/lib/neovim/window.rb +39 -36
  41. data/neovim.gemspec +11 -6
  42. data/script/ci/download_nvim.sh +40 -0
  43. data/script/{dump_api → dump_api.rb} +1 -1
  44. data/script/{generate_docs → generate_docs.rb} +6 -7
  45. data/script/{j2mp → j2mp.rb} +0 -0
  46. data/script/{mp2j → mp2j.rb} +0 -0
  47. data/script/run_acceptance.rb +39 -0
  48. data/spec/acceptance/client_info_spec.vim +42 -0
  49. data/spec/acceptance/rplugin_autocmd_spec.vim +20 -10
  50. data/spec/acceptance/rplugin_command_spec.vim +54 -56
  51. data/spec/acceptance/rplugin_function_spec.vim +28 -22
  52. data/spec/acceptance/ruby_spec.vim +52 -53
  53. data/spec/acceptance/rubydo_spec.vim +49 -52
  54. data/spec/acceptance/rubyeval_spec.vim +22 -0
  55. data/spec/acceptance/rubyfile/curbuf_ivar_get.rb +1 -1
  56. data/spec/acceptance/rubyfile/curbuf_ivar_set.rb +1 -1
  57. data/spec/acceptance/rubyfile/define_foo.rb +1 -1
  58. data/spec/acceptance/rubyfile/nested.rb +1 -1
  59. data/spec/acceptance/rubyfile/nested_inner.rb +1 -1
  60. data/spec/acceptance/rubyfile/set_pwd_after.rb +1 -1
  61. data/spec/acceptance/rubyfile/set_pwd_before.rb +1 -1
  62. data/spec/acceptance/rubyfile_spec.vim +60 -66
  63. data/spec/acceptance/runtime/init.vim +5 -4
  64. data/spec/acceptance/runtime/rplugin/ruby/autocmds.rb +7 -3
  65. data/spec/acceptance/runtime/rplugin/ruby/commands.rb +18 -17
  66. data/spec/acceptance/runtime/rplugin/ruby/functions.rb +9 -9
  67. data/spec/helper.rb +38 -9
  68. data/spec/neovim/api_spec.rb +2 -2
  69. data/spec/neovim/buffer_spec.rb +10 -6
  70. data/spec/neovim/client_info_spec.rb +77 -0
  71. data/spec/neovim/client_spec.rb +19 -12
  72. data/spec/neovim/connection_spec.rb +106 -0
  73. data/spec/neovim/current_spec.rb +13 -14
  74. data/spec/neovim/event_loop_spec.rb +48 -46
  75. data/spec/neovim/executable_spec.rb +2 -2
  76. data/spec/neovim/host/cli_spec.rb +94 -0
  77. data/spec/neovim/host/loader_spec.rb +18 -11
  78. data/spec/neovim/host_spec.rb +84 -92
  79. data/spec/neovim/line_range_spec.rb +17 -19
  80. data/spec/neovim/logging_spec.rb +3 -3
  81. data/spec/neovim/message_spec.rb +119 -0
  82. data/spec/neovim/plugin_spec.rb +34 -34
  83. data/spec/neovim/remote_object_spec.rb +1 -2
  84. data/spec/neovim/ruby_provider/buffer_ext_spec.rb +8 -9
  85. data/spec/neovim/ruby_provider/object_ext_spec.rb +10 -0
  86. data/spec/neovim/ruby_provider/vim_spec.rb +5 -5
  87. data/spec/neovim/ruby_provider/window_ext_spec.rb +12 -15
  88. data/spec/neovim/session_spec.rb +20 -47
  89. data/spec/neovim/window_spec.rb +1 -2
  90. data/spec/neovim_spec.rb +28 -51
  91. data/spec/support.rb +27 -1
  92. metadata +83 -48
  93. data/.coveralls.yml +0 -1
  94. data/.gitmodules +0 -3
  95. data/.rspec +0 -1
  96. data/.travis.yml +0 -23
  97. data/appveyor.yml +0 -21
  98. data/bin/neovim-ruby-host +0 -18
  99. data/lib/neovim/event_loop/connection.rb +0 -78
  100. data/lib/neovim/event_loop/message_builder.rb +0 -127
  101. data/lib/neovim/event_loop/serializer.rb +0 -37
  102. data/spec/acceptance/runtime/rplugin.vim +0 -37
  103. data/spec/acceptance/runtime/vader.vim/autoload/vader.vim +0 -348
  104. data/spec/acceptance/runtime/vader.vim/autoload/vader/assert.vim +0 -116
  105. data/spec/acceptance/runtime/vader.vim/autoload/vader/helper.vim +0 -43
  106. data/spec/acceptance/runtime/vader.vim/autoload/vader/parser.vim +0 -179
  107. data/spec/acceptance/runtime/vader.vim/autoload/vader/syntax.vim +0 -73
  108. data/spec/acceptance/runtime/vader.vim/autoload/vader/window.vim +0 -205
  109. data/spec/acceptance/runtime/vader.vim/plugin/vader.vim +0 -37
  110. data/spec/acceptance_spec.rb +0 -82
  111. data/spec/neovim/event_loop/connection_spec.rb +0 -89
  112. data/spec/neovim/event_loop/message_builder_spec.rb +0 -105
  113. data/spec/neovim/event_loop/serializer_spec.rb +0 -63
@@ -8,9 +8,6 @@ module Neovim
8
8
  @host = host
9
9
  end
10
10
 
11
- # Load the provided Ruby files while temporarily overriding
12
- # +Neovim.plugin+ to expose the remote plugin DSL and register the result
13
- # to the host.
14
11
  def load(paths)
15
12
  paths.each do |path|
16
13
  override_plugin_method(path) do
@@ -27,7 +24,7 @@ module Neovim
27
24
 
28
25
  Neovim.define_singleton_method(:plugin) do |&block|
29
26
  plugin = Plugin.from_config_block(path, &block)
30
- at_host.register(plugin)
27
+ at_host.plugins << plugin
31
28
  end
32
29
 
33
30
  yield
@@ -12,8 +12,8 @@ module Neovim
12
12
  # @yieldparam line [String]
13
13
  def each(&block)
14
14
  (0...@buffer.count).each_slice(5000) do |linenos|
15
- _start, _stop = linenos[0], linenos[-1] + 1
16
- @buffer.get_lines(_start, _stop, true).each(&block)
15
+ start, stop = linenos[0], linenos[-1] + 1
16
+ @buffer.get_lines(start, stop, true).each(&block)
17
17
  end
18
18
  end
19
19
 
@@ -50,15 +50,15 @@ module Neovim
50
50
  # @example Get the first two lines using an index and length
51
51
  # line_range[0, 2] # => ["first", "second"]
52
52
  def [](pos, len=nil)
53
- if Range === pos
53
+ if pos.is_a?(Range)
54
54
  @buffer.get_lines(*range_indices(pos), true)
55
55
  else
56
- _begin, _end = length_indices(pos, len || 1)
57
- lines = @buffer.get_lines(_begin, _end, true)
56
+ start, stop = length_indices(pos, len || 1)
57
+ lines = @buffer.get_lines(start, stop, true)
58
58
  len ? lines : lines.first
59
59
  end
60
60
  end
61
- alias_method :slice, :[]
61
+ alias slice []
62
62
 
63
63
  # Set a line or line range.
64
64
  #
@@ -85,11 +85,11 @@ module Neovim
85
85
  *target, val = args
86
86
  pos, len = target
87
87
 
88
- if Range === pos
88
+ if pos.is_a?(Range)
89
89
  @buffer.set_lines(*range_indices(pos), true, Array(val))
90
90
  else
91
- _begin, _end = length_indices(pos, len || 1)
92
- @buffer.set_lines(_begin, _end, true, Array(val))
91
+ start, stop = length_indices(pos, len || 1)
92
+ @buffer.set_lines(start, stop, true, Array(val))
93
93
  end
94
94
  end
95
95
 
@@ -113,18 +113,18 @@ module Neovim
113
113
  private
114
114
 
115
115
  def range_indices(range)
116
- _begin = adjust_index(range.begin)
117
- _end = adjust_index(range.end)
118
- _end += 1 unless range.exclude_end?
116
+ start = adjust_index(range.begin)
117
+ stop = adjust_index(range.end)
118
+ stop += 1 unless range.exclude_end?
119
119
 
120
- [_begin, _end]
120
+ [start, stop]
121
121
  end
122
122
 
123
123
  def length_indices(index, len)
124
- _begin = adjust_index(index)
125
- _end = _begin < 0 ? [_begin + len, -1].min : _begin + len
124
+ start = adjust_index(index)
125
+ stop = start < 0 ? [start + len, -1].min : start + len
126
126
 
127
- [_begin, _end]
127
+ [start, stop]
128
128
  end
129
129
 
130
130
  def adjust_index(i)
@@ -13,13 +13,12 @@ module Neovim
13
13
  def self.logger(env=ENV)
14
14
  return @logger if instance_variable_defined?(:@logger)
15
15
 
16
- if env_file = env["NVIM_RUBY_LOG_FILE"]
17
- @logger = Logger.new(env_file)
18
- else
19
- @logger = Logger.new(STDERR)
20
- end
16
+ env_file, env_level =
17
+ env.values_at("NVIM_RUBY_LOG_FILE", "NVIM_RUBY_LOG_LEVEL")
18
+
19
+ @logger = Logger.new(env_file || STDERR)
21
20
 
22
- if env_level = env["NVIM_RUBY_LOG_LEVEL"]
21
+ if /\S+/.match?(env_level)
23
22
  begin
24
23
  @logger.level = Integer(env_level)
25
24
  rescue ArgumentError
@@ -43,29 +42,30 @@ module Neovim
43
42
  end
44
43
 
45
44
  def self.json_formatter
46
- Proc.new do |level, time, _, fields|
45
+ lambda do |level, time, _, fields|
47
46
  require "multi_json"
48
47
 
49
48
  MultiJson.encode(
50
49
  {
51
- :_level => level,
52
- :_time => time.strftime(TIMESTAMP_FORMAT)
50
+ _level: level,
51
+ _time: time.strftime(TIMESTAMP_FORMAT)
53
52
  }.merge!(fields)
54
53
  ) << "\n"
55
54
  end
56
55
  end
57
56
  private_class_method :json_formatter
58
57
 
58
+ # @api private
59
59
  module Helpers
60
60
  private
61
61
 
62
- def log(level, _method=nil, &block)
62
+ def log(level, method=nil, &block)
63
63
  begin
64
64
  Logging.logger.public_send(level) do
65
65
  {
66
- :_class => self.class,
67
- :_method => _method || block.binding.eval("__method__"),
68
- }.merge!(block.call)
66
+ _class: self.class,
67
+ _method: method || block.binding.eval("__method__")
68
+ }.merge!(yield)
69
69
  end
70
70
  rescue => ex
71
71
  Logging.logger.error("failed to log: #{ex.inspect}")
@@ -74,13 +74,13 @@ module Neovim
74
74
  # Inability to log shouldn't abort process
75
75
  end
76
76
 
77
- def log_exception(level, ex, _method)
78
- log(level, _method) do
79
- {:exception => ex.class, :message => ex.message}
77
+ def log_exception(level, ex, method)
78
+ log(level, method) do
79
+ {exception: ex.class, message: ex.message}
80
80
  end
81
81
 
82
- log(:debug, _method) do
83
- {:exception => ex.class, :message => ex.message, :backtrace => ex.backtrace}
82
+ log(:debug, method) do
83
+ {exception: ex.class, message: ex.message, backtrace: ex.backtrace}
84
84
  end
85
85
  end
86
86
  end
@@ -0,0 +1,70 @@
1
+ require "neovim/logging"
2
+
3
+ module Neovim
4
+ # @api private
5
+ class Message
6
+ def self.from_array((kind, *payload))
7
+ case kind
8
+ when 0
9
+ request(*payload)
10
+ when 1
11
+ reqid, (_, error), value = payload
12
+ response(reqid, error, value)
13
+ when 2
14
+ notification(*payload)
15
+ else
16
+ raise "Unknown message type #{kind.inspect}"
17
+ end
18
+ end
19
+
20
+ def self.request(id, method, args)
21
+ Request.new(id, method, args)
22
+ end
23
+
24
+ def self.response(request_id, error, value)
25
+ Response.new(request_id, error, value)
26
+ end
27
+
28
+ def self.notification(method, args)
29
+ Notification.new(method, args)
30
+ end
31
+
32
+ Request = Struct.new(:id, :method_name, :arguments) do
33
+ def to_a
34
+ [0, id, method_name, arguments]
35
+ end
36
+
37
+ def received(_)
38
+ yield self
39
+ end
40
+
41
+ def sync?
42
+ true
43
+ end
44
+ end
45
+
46
+ Response = Struct.new(:request_id, :error, :value) do
47
+ def to_a
48
+ [1, request_id, error, value]
49
+ end
50
+
51
+ def received(handlers)
52
+ handlers.delete(request_id).call(self)
53
+ end
54
+ end
55
+
56
+ Notification = Struct.new(:method_name, :arguments) do
57
+ def to_a
58
+ [2, method_name, arguments]
59
+ end
60
+
61
+ def received(_)
62
+ yield self
63
+ end
64
+
65
+ def sync?
66
+ false
67
+ end
68
+ end
69
+ end
70
+ end
@@ -3,10 +3,9 @@ require "neovim/plugin/dsl"
3
3
  module Neovim
4
4
  # @api private
5
5
  class Plugin
6
- attr_accessor :handlers, :setup_blocks
6
+ attr_accessor :handlers, :setup_blocks, :script_host
7
7
  attr_reader :source
8
8
 
9
- # Entrypoint to the +Neovim.plugin+ DSL.
10
9
  def self.from_config_block(source)
11
10
  new(source).tap do |instance|
12
11
  yield DSL.new(instance) if block_given?
@@ -14,21 +13,24 @@ module Neovim
14
13
  end
15
14
 
16
15
  def initialize(source)
17
- @handlers = []
18
16
  @source = source
17
+ @handlers = []
19
18
  @setup_blocks = []
19
+ @script_host = false
20
20
  end
21
21
 
22
- # Return specs used by +nvim+ to register plugins.
23
22
  def specs
24
23
  @handlers.inject([]) do |acc, handler|
25
24
  handler.qualified? ? acc + [handler.to_spec] : acc
26
25
  end
27
26
  end
28
27
 
29
- # Run all registered setup blocks.
30
28
  def setup(client)
31
29
  @setup_blocks.each { |bl| bl.call(client) }
32
30
  end
31
+
32
+ def script_host?
33
+ !!@script_host
34
+ end
33
35
  end
34
36
  end
@@ -68,6 +68,12 @@ module Neovim
68
68
 
69
69
  private
70
70
 
71
+ # Mark this plugin as the Ruby script host started by nvim. Should only
72
+ # be used in +Neovim::RubyProvider+.
73
+ def script_host!
74
+ @plugin.script_host = true
75
+ end
76
+
71
77
  # Register a setup block to run once before the host starts. The block
72
78
  # should expect to receive a single argument, a +Neovim::Client+.
73
79
  #
@@ -85,14 +91,14 @@ module Neovim
85
91
  @plugin.handlers.push(Handler.unqualified(name, block))
86
92
  end
87
93
 
88
- def register_handler(type, name, _options, block)
94
+ def register_handler(type, name, options, block)
89
95
  if type == :autocmd
90
- options = _options.dup
96
+ options = options.dup
91
97
  else
92
- options = standardize(_options.dup)
98
+ options = standardize(options.dup)
93
99
  end
94
100
 
95
- sync = options.delete(:sync)
101
+ sync = !!options.delete(:sync)
96
102
 
97
103
  @plugin.handlers.push(
98
104
  Handler.new(@plugin.source, type, name, sync, options, block)
@@ -5,22 +5,22 @@ module Neovim
5
5
  attr_reader :block
6
6
 
7
7
  def self.unqualified(name, block)
8
- new(nil, nil, name, true, {:qualified => false}, block)
8
+ new(nil, nil, name, true, {qualified: false}, block)
9
9
  end
10
10
 
11
11
  def initialize(source, type, name, sync, options, block)
12
12
  @source = source
13
13
  @type = type.to_sym if type.respond_to?(:to_sym)
14
14
  @name = name.to_s
15
- @sync = !!sync
15
+ @sync = sync
16
16
  @options = options
17
- @block = block || Proc.new {}
17
+ @block = block || -> {}
18
18
  @qualified =
19
19
  options.key?(:qualified) ? options.delete(:qualified) : true
20
20
  end
21
21
 
22
22
  def sync?
23
- @sync
23
+ !!@sync
24
24
  end
25
25
 
26
26
  def qualified?
@@ -40,10 +40,10 @@ module Neovim
40
40
 
41
41
  def to_spec
42
42
  {
43
- :type => @type,
44
- :name => @name,
45
- :sync => @sync,
46
- :opts => @options,
43
+ type: @type,
44
+ name: @name,
45
+ sync: @sync,
46
+ opts: @options
47
47
  }
48
48
  end
49
49
 
@@ -1,3 +1,5 @@
1
+ require "set"
2
+
1
3
  module Neovim
2
4
  # @abstract Superclass for all +nvim+ remote objects.
3
5
  #
@@ -23,21 +25,21 @@ module Neovim
23
25
 
24
26
  # Intercept method calls and delegate to appropriate RPC methods.
25
27
  def method_missing(method_name, *args)
26
- if func = @api.function_for_object_method(self, method_name)
28
+ if (func = @api.function_for_object_method(self, method_name))
27
29
  func.call(@session, @index, *args)
28
30
  else
29
31
  super
30
32
  end
31
33
  end
32
34
 
33
- # Extend +respond_to?+ to support RPC methods.
34
- def respond_to?(method_name)
35
+ # Extend +respond_to_missing?+ to support RPC methods.
36
+ def respond_to_missing?(method_name, *)
35
37
  super || rpc_methods.include?(method_name.to_sym)
36
38
  end
37
39
 
38
40
  # Extend +methods+ to include RPC methods
39
41
  def methods(*args)
40
- super | rpc_methods
42
+ super | rpc_methods.to_a
41
43
  end
42
44
 
43
45
  # Extend +==+ to only look at class and index.
@@ -48,7 +50,8 @@ module Neovim
48
50
  private
49
51
 
50
52
  def rpc_methods
51
- @api.functions_for_object(self).map(&:method_name)
53
+ @rpc_methods ||=
54
+ @api.functions_for_object(self).map(&:method_name).to_set
52
55
  end
53
56
  end
54
57
  end
@@ -1,6 +1,8 @@
1
1
  require "neovim/ruby_provider/vim"
2
+ require "neovim/ruby_provider/object_ext"
2
3
  require "neovim/ruby_provider/buffer_ext"
3
4
  require "neovim/ruby_provider/window_ext"
5
+ require "stringio"
4
6
 
5
7
  module Neovim
6
8
  # This class is used to define a +Neovim::Plugin+ to act as a backend for the
@@ -13,28 +15,20 @@ module Neovim
13
15
  Thread.abort_on_exception = true
14
16
 
15
17
  Neovim.plugin do |plug|
18
+ plug.__send__(:script_host!)
19
+
16
20
  __define_setup(plug)
17
21
  __define_ruby_execute(plug)
22
+ __define_ruby_eval(plug)
18
23
  __define_ruby_execute_file(plug)
19
24
  __define_ruby_do_range(plug)
20
25
  __define_ruby_chdir(plug)
21
26
  end
22
27
  end
23
28
 
24
- # Bootstrap the provider client:
25
- #
26
- # 1. Monkeypatch +$stdout+ and +$stderr+ to write to +nvim+.
27
- # 2. Define the +DirChanged+ event to update the provider's pwd.
29
+ # Define the +DirChanged+ event to update the provider's pwd.
28
30
  def self.__define_setup(plug)
29
31
  plug.__send__(:setup) do |client|
30
- $stdout.define_singleton_method(:write) do |string|
31
- client.out_write(string + "\n")
32
- end
33
-
34
- $stderr.define_singleton_method(:write) do |string|
35
- client.err_writeln(string)
36
- end
37
-
38
32
  begin
39
33
  cid = client.api.channel_id
40
34
  client.command("au DirChanged * call rpcrequest(#{cid}, 'ruby_chdir', v:event)")
@@ -52,12 +46,26 @@ module Neovim
52
46
  def self.__define_ruby_execute(plug)
53
47
  plug.__send__(:rpc, :ruby_execute) do |nvim, ruby|
54
48
  __wrap_client(nvim) do
55
- eval(ruby, TOPLEVEL_BINDING, "eval")
49
+ eval(ruby, TOPLEVEL_BINDING, "ruby_execute")
56
50
  end
51
+ nil
57
52
  end
58
53
  end
59
54
  private_class_method :__define_ruby_execute
60
55
 
56
+ # Evaluate the provided Ruby code, exposing the +Vim+ constant for
57
+ # interactions with the editor and returning the value.
58
+ #
59
+ # This is used by the +:rubyeval+ command.
60
+ def self.__define_ruby_eval(plug)
61
+ plug.__send__(:rpc, :ruby_eval) do |nvim, ruby|
62
+ __wrap_client(nvim) do
63
+ eval(ruby, TOPLEVEL_BINDING, "ruby_eval")
64
+ end
65
+ end
66
+ end
67
+ private_class_method :__define_ruby_eval
68
+
61
69
  # Evaluate the provided Ruby file, exposing the +Vim+ constant for
62
70
  # interactions with the editor.
63
71
  #
@@ -65,6 +73,7 @@ module Neovim
65
73
  def self.__define_ruby_execute_file(plug)
66
74
  plug.__send__(:rpc, :ruby_execute_file) do |nvim, path|
67
75
  __wrap_client(nvim) { load(path) }
76
+ nil
68
77
  end
69
78
  end
70
79
  private_class_method :__define_ruby_execute_file
@@ -83,14 +92,15 @@ module Neovim
83
92
  __start, __stop, __ruby = __args
84
93
  __buffer = __nvim.get_current_buf
85
94
 
86
- __update_lines_in_chunks(__buffer, __start, __stop, 5000) do |__lines|
95
+ __update_lines_in_chunks(__buffer, __start, __stop, 1_000) do |__lines|
87
96
  __lines.map do |__line|
88
97
  $_ = __line
89
- eval(__ruby, binding, "eval")
98
+ eval(__ruby, binding, "ruby_do_range")
90
99
  $_
91
100
  end
92
101
  end
93
102
  end
103
+ nil
94
104
  end
95
105
  end
96
106
  private_class_method :__define_ruby_do_range
@@ -107,29 +117,45 @@ module Neovim
107
117
  Vim.__refresh_globals(client)
108
118
 
109
119
  __with_exception_handling(client) do
110
- yield
120
+ __with_std_streams(client) do
121
+ yield
122
+ end
111
123
  end
112
- nil
113
124
  end
114
125
  private_class_method :__wrap_client
115
126
 
116
127
  def self.__with_exception_handling(client)
128
+ yield
129
+ rescue ScriptError, StandardError => e
130
+ msg = [e.class, e.message].join(": ")
131
+ client.err_writeln(msg)
132
+ end
133
+ private_class_method :__with_exception_handling
134
+
135
+ def self.__with_std_streams(client)
136
+ old_stdout = $stdout.dup
137
+ old_stderr = $stderr.dup
138
+
139
+ $stdout, $stderr = StringIO.new, StringIO.new
140
+
117
141
  begin
118
- yield
119
- rescue SignalException => sig
120
- raise sig
121
- rescue Exception => e
122
- msg = [e.class, e.message.gsub("\n", " ")].join(": ")
123
- client.err_writeln(msg.lines.first.strip)
142
+ yield.tap do
143
+ client.out_write($stdout.string + $/) if $stdout.size > 0
144
+ client.err_writeln($stderr.string) if $stderr.size > 0
145
+ end
146
+ ensure
147
+ $stdout = old_stdout
148
+ $stderr = old_stderr
124
149
  end
125
150
  end
151
+ private_class_method :__with_std_streams
126
152
 
127
153
  def self.__update_lines_in_chunks(buffer, start, stop, size)
128
154
  (start..stop).each_slice(size) do |linenos|
129
- _start, _stop = linenos[0]-1, linenos[-1]
130
- lines = buffer.get_lines(_start, _stop, true)
155
+ start, stop = linenos[0] - 1, linenos[-1]
156
+ lines = buffer.get_lines(start, stop, false)
131
157
 
132
- buffer.set_lines(_start, _stop, true, yield(lines))
158
+ buffer.set_lines(start, stop, false, yield(lines))
133
159
  end
134
160
  end
135
161
  private_class_method :__update_lines_in_chunks