debugger-xml 0.0.4 → 0.1.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.
@@ -0,0 +1,7 @@
1
+ ## 0.1.0
2
+ * Added rdebug-vim, used by vim-ruby-debugger. It is designed specifically for that vim plugin.
3
+ It creates new unix socket, and listen connections to it. After receiving commands/events, it
4
+ writes response to a file, and pokes Vim, so it can read it.
5
+
6
+ ## 0.0.4
7
+ * First working version, copies ruby-debug-ide interface
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'rake/testtask'
4
4
  desc "Run tests."
5
5
  task :test do
6
6
  Rake::TestTask.new(:test) do |t|
7
- t.test_files = FileList["test/*_test.rb"]
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
8
  t.verbose = true
9
9
  end
10
10
  end
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
4
+ require 'optparse'
5
+ require 'ostruct'
6
+ require 'debugger'
7
+ require 'debugger/xml'
8
+
9
+ $stdout.sync = true
10
+
11
+ class RdebugVim
12
+
13
+ def initialize
14
+ check_argv!
15
+ Debugger.const_set("RDEBUG_SCRIPT", File.expand_path($0))
16
+ install_interruption_hander
17
+ Debugger.tracing = false
18
+ Debugger.wait_for_start = true
19
+ Debugger.printer = Printers::Xml.new
20
+ Debugger.const_set("PROG_SCRIPT", ARGV.shift)
21
+ end
22
+
23
+ def run
24
+ Debugger.start_for_vim(options)
25
+ bt = Debugger.debug_load(Debugger::PROG_SCRIPT, false, false)
26
+ if bt
27
+ print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n"
28
+ print "Uncaught exception: #{bt}\n"
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def check_argv!
35
+ if ARGV.empty?
36
+ puts opts
37
+ puts
38
+ puts "Must specify a script to run"
39
+ exit(1)
40
+ end
41
+ end
42
+
43
+ def install_interruption_hander
44
+ trap('INT') { Debugger.interrupt_last }
45
+ end
46
+
47
+ def options
48
+ opts
49
+ @options
50
+ end
51
+
52
+ def opts
53
+ @opts ||= begin
54
+ @options = OpenStruct.new
55
+ opts = OptionParser.new do |opts|
56
+ opts.banner = %{
57
+ Using rdebug-vim
58
+ Usage: rdebug-vim is supposed to be called from vim-ruby-debugger.
59
+ The command line interface to 'debugger' is rdebug.
60
+ }.gsub(/^\s*/, '')
61
+ opts.separator ""
62
+ opts.separator "Options:"
63
+ opts.on("-f", "--file FILE", String, "File for communication with Vim") { |file| @options.file = file }
64
+ opts.on("-o", "--output FILE", String, "File where standard/error output is sent to") do |file|
65
+ @options.output_file = file
66
+ end
67
+ opts.on("-s", "--socket FILE", String, "Socket file to communicate with debugger") do |file|
68
+ @options.socket = file
69
+ end
70
+ opts.on("-lf", "--logger_file FILE", String, "File for logging") { |file| @options.logger_file = file }
71
+ opts.on("-dm", "--debug_mode MODE", Integer, "Debug mode") { |mode| @options.debug_mode = mode == 1 }
72
+ opts.on("-ve", "--vim_executable FILE", String, "Vim executable file (e.g., 'mvim')") do |file|
73
+ @options.vim_executable = file
74
+ end
75
+ opts.on("-vs", "--vim_servername NAME", String, "Vim servername (e.g., 'VIM')") do |name|
76
+ @options.vim_servername = name
77
+ end
78
+ opts.on("-spr", "--separator NAME", String, "Output results separator") do |name|
79
+ @options.separator = name
80
+ end
81
+ opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") { |path| $LOAD_PATH.unshift(path) }
82
+ end
83
+ opts.parse!
84
+ opts
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ RdebugVim.new.run
@@ -0,0 +1,47 @@
1
+ require_relative 'ide_server'
2
+
3
+ module Debugger
4
+ class << self
5
+
6
+ def start_for_vim(options)
7
+ return if @control_thread
8
+ daemonize!
9
+ $stdout.reopen(options.output_file, 'w')
10
+ $stderr.reopen(options.output_file, 'w')
11
+ @mutex = Mutex.new
12
+ @proceed = ConditionVariable.new
13
+ start
14
+ File.unlink(options.socket) if File.exist?(options.socket)
15
+ server = UNIXServer.new(options.socket)
16
+ Xml::Vim::Notification.new("establish_connection", options).send
17
+ @control_thread = DebugThread.new do
18
+ begin
19
+ while (session = server.accept)
20
+ interface = Xml::Vim::Interface.new(session, options)
21
+ processor = Xml::Vim::ControlCommandProcessor.new(interface)
22
+ self.handler = Xml::Vim::Processor.new(interface)
23
+ processor.process_commands
24
+ end
25
+ rescue Exception => e
26
+ puts "INTERNAL ERROR!!! #{$!}" rescue nil
27
+ puts $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
28
+ raise e
29
+ ensure
30
+ server.close
31
+ end
32
+ end
33
+ @mutex.synchronize { @proceed.wait(@mutex) } if wait_for_start
34
+ end
35
+
36
+ private
37
+
38
+ def daemonize!
39
+ pid = Process.fork
40
+ if pid
41
+ print pid
42
+ exit
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,81 @@
1
+ module Debugger
2
+ module Xml
3
+ module Ide
4
+
5
+ class ControlCommandProcessor < Debugger::Processor
6
+
7
+ def initialize(interface)
8
+ @interface = interface
9
+ end
10
+
11
+ def process_commands
12
+ while input = @interface.read_command
13
+ process_input(input)
14
+ end
15
+ rescue IOError, Errno::EPIPE
16
+ rescue Exception
17
+ print "INTERNAL ERROR!!! #{$!}\n" rescue nil
18
+ print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
19
+ ensure
20
+ @interface.close
21
+ end
22
+
23
+ def process_command(cmd)
24
+ catch(:debug_error) do
25
+ if matched_cmd = control_commands.find { |c| c.match(cmd) }
26
+ matched_cmd.execute
27
+ else
28
+ process_context_commands(cmd)
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def control_commands
36
+ @control_commands = begin
37
+ control_command_classes = Command.commands.select(&:allow_in_control)
38
+ state = Debugger::ControlCommandProcessor::State.new(@interface, control_command_classes)
39
+ control_command_classes.map { |cmd| cmd.new(state) }
40
+ end
41
+ end
42
+
43
+ def process_input(input)
44
+ split_commands(input).each do |cmd|
45
+ process_command(cmd)
46
+ end
47
+ end
48
+
49
+ def process_context_commands(input)
50
+ unless Debugger.handler.at_line?
51
+ errmsg pr("base.errors.no_suspended_thread", input: input)
52
+ return
53
+ end
54
+ event_command_classes = Command.commands.select(&:event)
55
+ state = Debugger::CommandProcessor::State.new do |s|
56
+ s.context = Debugger.handler.context
57
+ s.file = Debugger.handler.file
58
+ s.line = Debugger.handler.line
59
+ s.binding = Debugger.handler.context.frame_binding(0)
60
+ s.interface = @interface
61
+ s.commands = event_command_classes
62
+ end
63
+ event_commands = event_command_classes.map { |cls| cls.new(state) }
64
+ catch(:debug_error) do
65
+ if cmd = event_commands.find { |c| c.match(input) }
66
+ if state.context.dead? && cmd.class.need_context
67
+ print pr("base.errors.command_unavailable")
68
+ else
69
+ cmd.execute
70
+ end
71
+ else
72
+ print pr("base.errors.unknown_command", input: input)
73
+ end
74
+ end
75
+ state.context.thread.run if state.proceed?
76
+ end
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,67 @@
1
+ module Debugger
2
+ module Xml
3
+ module Ide
4
+ class Interface < Debugger::Interface # :nodoc:
5
+ attr_accessor :command_queue
6
+ attr_accessor :histfile
7
+ attr_accessor :history_save
8
+ attr_accessor :history_length
9
+ attr_accessor :restart_file
10
+
11
+ def initialize(socket)
12
+ @command_queue = []
13
+ @socket = socket
14
+ @history_save = false
15
+ @history_length = 256
16
+ @histfile = ''
17
+ @restart_file = nil
18
+ end
19
+
20
+ def close
21
+ @socket.close
22
+ rescue Exception
23
+ end
24
+
25
+ def print_debug(msg)
26
+ STDOUT.puts(msg)
27
+ end
28
+
29
+ def errmsg(*args)
30
+ print(*args)
31
+ end
32
+
33
+ def confirm(prompt)
34
+ true
35
+ end
36
+
37
+ def finalize
38
+ close
39
+ end
40
+
41
+ # Workaround for JRuby issue http://jira.codehaus.org/browse/JRUBY-2063
42
+ def non_blocking_gets
43
+ loop do
44
+ result, _, _ = IO.select([@socket], nil, nil, 0.2)
45
+ next unless result
46
+ return result[0].gets
47
+ end
48
+ end
49
+
50
+ def read_command(*args)
51
+ result = non_blocking_gets
52
+ raise IOError unless result
53
+ result.chomp
54
+ end
55
+
56
+ def readline_support?
57
+ false
58
+ end
59
+
60
+ def print(*args)
61
+ @socket.printf(*escape_input(args))
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,93 @@
1
+ require 'ruby-debug/processor'
2
+
3
+ module Debugger
4
+ module Xml
5
+ module Ide
6
+
7
+ class Processor < Debugger::Processor
8
+ attr_reader :context, :file, :line, :display
9
+ def initialize(interface)
10
+ @mutex = Mutex.new
11
+ @interface = interface
12
+ @display = []
13
+ end
14
+
15
+ def at_breakpoint(context, breakpoint)
16
+ raise "@last_breakpoint supposed to be nil. is #{@last_breakpoint}" if @last_breakpoint
17
+ # at_breakpoint is immediately followed by #at_line event. So postpone breakpoint printing until #at_line.
18
+ @last_breakpoint = breakpoint
19
+ end
20
+ protect :at_breakpoint
21
+
22
+ # TODO: Catching exceptions doesn't work so far, need to fix
23
+ def at_catchpoint(context, excpt)
24
+ end
25
+
26
+ # We don't have tracing for IDE
27
+ def at_tracing(*args)
28
+ end
29
+
30
+ def at_line(context, file, line)
31
+ if context.nil? || context.stop_reason == :step
32
+ print_file_line(context, file, line)
33
+ end
34
+ line_event(context, file, line)
35
+ end
36
+ protect :at_line
37
+
38
+ def at_return(context, file, line)
39
+ print_file_line(context, file, line)
40
+ context.stop_frame = -1
41
+ line_event(context, file, line)
42
+ end
43
+
44
+ def at_line?
45
+ !!@line
46
+ end
47
+
48
+ private
49
+
50
+ def print_file_line(context, file, line)
51
+ print(
52
+ Debugger.printer.print(
53
+ "stop.suspend",
54
+ file: CommandProcessor.canonic_file(file), line_number: line, line: Debugger.line_at(file, line),
55
+ thnum: context && context.thnum, frames: context && context.stack_size
56
+ )
57
+ )
58
+ end
59
+
60
+ def line_event(context, file, line)
61
+ @line = line
62
+ @file = file
63
+ @context = context
64
+ if @last_breakpoint
65
+ # followed after #at_breakpoint in the same thread. Print breakpoint
66
+ # now when @line, @file and @context are correctly set to prevent race
67
+ # condition with `control thread'.
68
+ n = Debugger.breakpoints.index(@last_breakpoint) + 1
69
+ print pr("breakpoints.stop_at_breakpoint",
70
+ id: n, file: @file, line: @line, thread_id: Debugger.current_context.thnum
71
+ )
72
+ end
73
+ if @context && @context.thread.is_a?(Debugger::DebugThread)
74
+ raise pr("thread.errors.debug_trace", thread: @context.thread)
75
+ end
76
+ # will be resumed by commands like `step', `next', `continue', `finish'
77
+ # from `control thread'
78
+ stop_thread
79
+ ensure
80
+ @line = nil
81
+ @file = nil
82
+ @context = nil
83
+ @last_breakpoint = nil
84
+ end
85
+
86
+ def stop_thread
87
+ Thread.stop
88
+ end
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -1,5 +1,5 @@
1
1
  module Debugger
2
2
  module Xml
3
- VERSION = "0.0.4"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1,17 @@
1
+ module Debugger
2
+ module Xml
3
+ module Vim
4
+
5
+ class ControlCommandProcessor < Ide::ControlCommandProcessor
6
+ private
7
+
8
+ def process_input(input)
9
+ super(input)
10
+ @interface.send_response
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,39 @@
1
+ require 'debugger/xml/ide/interface'
2
+
3
+ module Debugger
4
+ module Xml
5
+ module Vim
6
+ class Interface < Ide::Interface
7
+ def initialize(socket, options)
8
+ super(socket)
9
+ @options = options
10
+ @output = []
11
+ end
12
+
13
+ def print(*args)
14
+ @output << sprintf(*escape_input(args))
15
+ end
16
+
17
+ def send_response
18
+ create_directory(@options.file)
19
+ message = @output.join(@options.separator)
20
+ @output.clear
21
+ unless message.empty?
22
+ File.open(@options.file, 'w') do |f|
23
+ f.puts(message)
24
+ end
25
+ Notification.new("receive_command", @options).send
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def create_directory(file)
32
+ dir = File.dirname(file)
33
+ Dir.mkdir(dir) unless File.exist?(dir) && File.directory?(dir)
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,37 @@
1
+ module Debugger
2
+ module Xml
3
+ module Vim
4
+ class Notification
5
+
6
+ def initialize(command, options)
7
+ @command = command
8
+ @executable = options.vim_executable
9
+ @servername = options.vim_servername
10
+ @debug_mode = options.debug_mode
11
+ @logger_file = options.logger_file
12
+ end
13
+
14
+ def send
15
+ command = ":call RubyDebugger.#{@command}()"
16
+ starter = "<C-\\\\>"
17
+ sys_cmd = "#{@executable} --servername #{@servername} -u NONE -U NONE " +
18
+ "--remote-send \"#{starter}<C-N>#{command}<CR>\""
19
+ log("Executing command: #{sys_cmd}")
20
+ system(sys_cmd);
21
+ end
22
+
23
+ private
24
+
25
+ def log(string)
26
+ if @debug_mode
27
+ File.open(@logger_file, 'a') do |f|
28
+ # match vim redir style new lines, rather than trailing
29
+ f << "\ndebugger-xml, #{Time.now.strftime("%H:%M:%S")} : #{string.chomp}"
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ require 'ruby-debug/processor'
2
+
3
+ module Debugger
4
+ module Xml
5
+ module Vim
6
+
7
+ class Processor < Ide::Processor
8
+ private
9
+ def stop_thread
10
+ processor = Vim::ControlCommandProcessor.new(@interface)
11
+ processor.process_command("where")
12
+ processor.process_command("var local")
13
+ @interface.send_response
14
+ super
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+
@@ -1,15 +1,15 @@
1
- require_relative 'test_helper'
2
- require 'debugger/xml/ide_processor'
1
+ require_relative '../test_helper'
2
+ require 'debugger/xml/ide/control_command_processor'
3
3
 
4
- describe Debugger::Xml::IdeControlCommandProcessor do
4
+ describe Debugger::Xml::Ide::ControlCommandProcessor do
5
5
  include TestDsl
6
6
 
7
- let(:klass) { Debugger::Xml::IdeControlCommandProcessor }
7
+ let(:klass) { Debugger::Xml::Ide::ControlCommandProcessor }
8
8
  let(:interface) { Debugger.handler.interface }
9
9
  let(:file) { fullpath('jump') }
10
10
  let(:context) { stub(frame_binding: stub, stop_reason: nil, thread: stub, thnum: 1, stack_size: 2, dead?: false) }
11
11
  subject { klass.new(interface) }
12
- temporary_change_method_value(Debugger, :handler, Debugger::Xml::IdeProcessor.new(TestInterface.new))
12
+ temporary_change_method_value(Debugger, :handler, Debugger::Xml::Ide::Processor.new(TestInterface.new))
13
13
 
14
14
  before do
15
15
  Thread.stubs(:stop)
@@ -1,12 +1,12 @@
1
- require_relative 'test_helper'
2
- require 'debugger/xml/ide_processor'
1
+ require_relative '../test_helper'
2
+ require 'debugger/xml/ide/processor'
3
3
 
4
- describe Debugger::Xml::IdeProcessor do
4
+ describe Debugger::Xml::Ide::Processor do
5
5
  include TestDsl
6
6
 
7
7
  before { Thread.stubs(:stop) }
8
8
 
9
- let(:klass) { Debugger::Xml::IdeProcessor }
9
+ let(:klass) { Debugger::Xml::Ide::Processor }
10
10
  let(:interface) { TestInterface.new }
11
11
  let(:breakpoint) { stub }
12
12
  let(:context) { stub(thread: nil, stop_reason: nil, thnum: 1, stack_size: 2) }
@@ -41,9 +41,16 @@ describe "Printers::Xml" do
41
41
  }
42
42
  end
43
43
 
44
+ def yaml_file_path(filename)
45
+ File.expand_path(
46
+ File.join("..", "..", "..", "lib", "debugger", "printers", "texts", "#{filename}.yml"),
47
+ __FILE__
48
+ )
49
+ end
50
+
44
51
  before do
45
52
  YAML.stubs(:load_file).with(yaml_file_path('xml')).returns(yaml_xml)
46
- YAML.stubs(:load_file).with(yaml_file_path('base')).returns({})
53
+ YAML.stubs(:load_file).with(regexp_matches(/base/)).returns({})
47
54
  end
48
55
 
49
56
  describe "#print" do
@@ -0,0 +1,28 @@
1
+ require_relative '../test_helper'
2
+ require 'debugger/xml/vim/control_command_processor'
3
+
4
+ describe Debugger::Xml::Vim::ControlCommandProcessor do
5
+ include TestDsl
6
+
7
+ let(:klass) { Debugger::Xml::Vim::ControlCommandProcessor }
8
+ let(:interface) { Debugger.handler.interface }
9
+ let(:file) { fullpath('jump') }
10
+ let(:context) { stub(frame_binding: stub, stop_reason: nil, thread: stub, thnum: 1, stack_size: 2, dead?: false) }
11
+ subject { klass.new(interface) }
12
+ temporary_change_method_value(Debugger, :handler, Debugger::Xml::Ide::Processor.new(TestInterface.new))
13
+
14
+ before do
15
+ Thread.stubs(:stop)
16
+ Debugger.handler.instance_variable_set("@context", context)
17
+ Debugger.handler.instance_variable_set("@file", file)
18
+ Debugger.handler.instance_variable_set("@line", 30)
19
+ end
20
+
21
+ it "must send response after executing commands" do
22
+ Debugger::AddBreakpoint.any_instance.stubs(:execute).with()
23
+ Debugger::DeleteBreakpointCommand.any_instance.stubs(:execute).with()
24
+ interface.expects(:send_response)
25
+ enter 'break 5; delete 1'
26
+ subject.process_commands
27
+ end
28
+ end
@@ -0,0 +1,47 @@
1
+ require_relative '../test_helper'
2
+ require 'debugger/xml/vim/interface'
3
+
4
+ describe Debugger::Xml::Vim::Interface do
5
+ include TestDsl
6
+
7
+ let(:klass) { Debugger::Xml::Vim::Interface }
8
+ let(:options) do
9
+ stub(debug_mode: false, file: filename, separator: "--sep--")
10
+ end
11
+ let(:socket) { stub }
12
+ let(:subject) { klass.new(socket, options) }
13
+ let(:filename) { File.expand_path("../tmp", __FILE__) }
14
+ let(:notification) { stub(send: nil) }
15
+
16
+ before do
17
+ File.open(filename, 'w') { |f| }
18
+ end
19
+
20
+ after do
21
+ File.unlink(filename)
22
+ end
23
+
24
+ it "must send command to Vim" do
25
+ Debugger::Xml::Vim::Notification.expects(:new).with("receive_command", options).returns(notification)
26
+ subject.print("foo")
27
+ subject.print("bar")
28
+ subject.send_response
29
+ File.read(filename).strip.must_equal "foo--sep--bar"
30
+ end
31
+
32
+ it "must clear the queue after sending response" do
33
+ Debugger::Xml::Vim::Notification.stubs(:new).with("receive_command", options).returns(notification)
34
+ subject.print("foo")
35
+ subject.print("bar")
36
+ subject.send_response
37
+ subject.print("bla")
38
+ subject.send_response
39
+ File.read(filename).strip.must_equal "bla"
40
+ end
41
+
42
+ it "must not send any command if there is nothing to send" do
43
+ Debugger::Xml::Vim::Notification.expects(:new).never
44
+ subject.send_response
45
+ File.read(filename).strip.must_equal ""
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../test_helper'
2
+ require 'debugger/xml/vim/notification'
3
+
4
+ describe Debugger::Xml::Vim::Notification do
5
+ include TestDsl
6
+
7
+ let(:klass) { Debugger::Xml::Vim::Notification }
8
+ let(:options) do
9
+ stub(vim_executable: "vim", vim_servername: "VIM", debug_mode: true, logger_file: filename)
10
+ end
11
+ let(:subject) { klass.new("foo", options) }
12
+ let(:filename) { File.expand_path("../tmp", __FILE__) }
13
+ let(:command) { %{vim --servername VIM -u NONE -U NONE --remote-send \"<C-\\\\><C-N>:call RubyDebugger.foo()<CR>\"} }
14
+
15
+ before do
16
+ File.open(filename, 'w') { |f| }
17
+ end
18
+
19
+ after do
20
+ File.unlink(filename)
21
+ end
22
+
23
+ it "must send command to Vim" do
24
+ subject.stubs(:log)
25
+ subject.expects(:system).with(command)
26
+ subject.send
27
+ end
28
+
29
+ it "must log to file" do
30
+ subject.stubs(:system).with(command)
31
+ subject.send
32
+ File.read(filename).must_match /Executing command: vim --servername/
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ require_relative '../test_helper'
2
+ require 'debugger/xml/vim/processor'
3
+
4
+ describe Debugger::Xml::Vim::Processor do
5
+ include TestDsl
6
+
7
+ before { Thread.stubs(:stop) }
8
+
9
+ let(:klass) { Debugger::Xml::Vim::Processor }
10
+ let(:interface) { TestInterface.new }
11
+ let(:breakpoint) { stub }
12
+ let(:context) { stub(thread: nil, stop_reason: nil, thnum: 1, stack_size: 2) }
13
+ let(:file) { fullpath('jump') }
14
+ subject { klass.new(interface) }
15
+
16
+ describe "#at_line" do
17
+ it "must send response" do
18
+ processor = stub
19
+ processor.stubs(:process_command).with("where")
20
+ processor.stubs(:process_command).with("var local")
21
+ Debugger::Xml::Vim::ControlCommandProcessor.stubs(:new).with(interface).returns(processor)
22
+ interface.expects(:send_response)
23
+ subject.at_line(context, file, 30)
24
+ end
25
+
26
+ it "must process additional commands" do
27
+ processor = stub
28
+ processor.expects(:process_command).with("where")
29
+ processor.expects(:process_command).with("var local")
30
+ Debugger::Xml::Vim::ControlCommandProcessor.expects(:new).with(interface).returns(processor)
31
+ interface.stubs(:send_response)
32
+ subject.at_line(context, file, 30)
33
+ end
34
+ end
35
+ end
36
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: debugger-xml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-14 00:00:00.000000000 Z
12
+ date: 2013-03-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debugger
@@ -96,15 +96,18 @@ email:
96
96
  - anton.astashov@gmail.com
97
97
  executables:
98
98
  - rdebug-ide
99
+ - rdebug-vim
99
100
  extensions: []
100
101
  extra_rdoc_files: []
101
102
  files:
102
103
  - .gitignore
104
+ - CHANGELOG.md
103
105
  - Gemfile
104
106
  - LICENSE.txt
105
107
  - README.md
106
108
  - Rakefile
107
109
  - bin/rdebug-ide
110
+ - bin/rdebug-vim
108
111
  - debugger-xml.gemspec
109
112
  - lib/debugger/printers/texts/xml.yml
110
113
  - lib/debugger/printers/xml.rb
@@ -118,11 +121,17 @@ files:
118
121
  - lib/debugger/xml/extensions/commands/tmate.rb
119
122
  - lib/debugger/xml/extensions/commands/trace.rb
120
123
  - lib/debugger/xml/extensions/commands/variables.rb
121
- - lib/debugger/xml/extensions/debugger.rb
124
+ - lib/debugger/xml/extensions/ide_server.rb
122
125
  - lib/debugger/xml/extensions/processor.rb
123
- - lib/debugger/xml/ide_processor.rb
124
- - lib/debugger/xml/interface.rb
126
+ - lib/debugger/xml/extensions/vim_server.rb
127
+ - lib/debugger/xml/ide/control_command_processor.rb
128
+ - lib/debugger/xml/ide/interface.rb
129
+ - lib/debugger/xml/ide/processor.rb
125
130
  - lib/debugger/xml/version.rb
131
+ - lib/debugger/xml/vim/control_command_processor.rb
132
+ - lib/debugger/xml/vim/interface.rb
133
+ - lib/debugger/xml/vim/notification.rb
134
+ - lib/debugger/xml/vim/processor.rb
126
135
  - test/breakpoints_test.rb
127
136
  - test/conditions_test.rb
128
137
  - test/continue_test.rb
@@ -154,8 +163,8 @@ files:
154
163
  - test/examples/variables_xml.rb
155
164
  - test/frame_test.rb
156
165
  - test/help_test.rb
157
- - test/ide_control_command_processor_test.rb
158
- - test/ide_processor_test.rb
166
+ - test/ide/control_command_processor_test.rb
167
+ - test/ide/processor_test.rb
159
168
  - test/info_test.rb
160
169
  - test/irb_test.rb
161
170
  - test/jump_test.rb
@@ -171,6 +180,10 @@ files:
171
180
  - test/tmate_test.rb
172
181
  - test/trace_test.rb
173
182
  - test/variables_test.rb
183
+ - test/vim/control_command_processor_test.rb
184
+ - test/vim/interface_test.rb
185
+ - test/vim/notification_test.rb
186
+ - test/vim/processor_test.rb
174
187
  homepage: ''
175
188
  licenses: []
176
189
  post_install_message:
@@ -228,8 +241,8 @@ test_files:
228
241
  - test/examples/variables_xml.rb
229
242
  - test/frame_test.rb
230
243
  - test/help_test.rb
231
- - test/ide_control_command_processor_test.rb
232
- - test/ide_processor_test.rb
244
+ - test/ide/control_command_processor_test.rb
245
+ - test/ide/processor_test.rb
233
246
  - test/info_test.rb
234
247
  - test/irb_test.rb
235
248
  - test/jump_test.rb
@@ -245,3 +258,7 @@ test_files:
245
258
  - test/tmate_test.rb
246
259
  - test/trace_test.rb
247
260
  - test/variables_test.rb
261
+ - test/vim/control_command_processor_test.rb
262
+ - test/vim/interface_test.rb
263
+ - test/vim/notification_test.rb
264
+ - test/vim/processor_test.rb
@@ -1,149 +0,0 @@
1
- require 'ruby-debug/processor'
2
-
3
- module Debugger
4
- module Xml
5
-
6
- class IdeProcessor < Processor
7
- attr_reader :context, :file, :line, :display
8
- def initialize(interface)
9
- @mutex = Mutex.new
10
- @interface = interface
11
- @display = []
12
- end
13
-
14
- def at_breakpoint(context, breakpoint)
15
- raise "@last_breakpoint supposed to be nil. is #{@last_breakpoint}" if @last_breakpoint
16
- # at_breakpoint is immediately followed by #at_line event. So postpone breakpoint printing until #at_line.
17
- @last_breakpoint = breakpoint
18
- end
19
- protect :at_breakpoint
20
-
21
- # TODO: Catching exceptions doesn't work so far, need to fix
22
- def at_catchpoint(context, excpt)
23
- end
24
-
25
- # We don't have tracing for IDE
26
- def at_tracing(*args)
27
- end
28
-
29
- def at_line(context, file, line)
30
- if context.nil? || context.stop_reason == :step
31
- print_file_line(context, file, line)
32
- end
33
- line_event(context, file, line)
34
- end
35
- protect :at_line
36
-
37
- def at_return(context, file, line)
38
- print_file_line(context, file, line)
39
- context.stop_frame = -1
40
- line_event(context, file, line)
41
- end
42
-
43
- def at_line?
44
- !!@line
45
- end
46
-
47
- private
48
-
49
- def print_file_line(context, file, line)
50
- print(
51
- Debugger.printer.print(
52
- "stop.suspend",
53
- file: CommandProcessor.canonic_file(file), line_number: line, line: Debugger.line_at(file, line),
54
- thnum: context && context.thnum, frames: context && context.stack_size
55
- )
56
- )
57
- end
58
-
59
- def line_event(context, file, line)
60
- @line = line
61
- @file = file
62
- @context = context
63
- if @last_breakpoint
64
- # followed after #at_breakpoint in the same thread. Print breakpoint
65
- # now when @line, @file and @context are correctly set to prevent race
66
- # condition with `control thread'.
67
- n = Debugger.breakpoints.index(@last_breakpoint) + 1
68
- print pr("breakpoints.stop_at_breakpoint",
69
- id: n, file: @file, line: @line, thread_id: Debugger.current_context.thnum
70
- )
71
- end
72
- if @context && @context.thread.is_a?(Debugger::DebugThread)
73
- raise pr("thread.errors.debug_trace", thread: @context.thread)
74
- end
75
- # will be resumed by commands like `step', `next', `continue', `finish'
76
- # from `control thread'
77
- Thread.stop
78
- ensure
79
- @line = nil
80
- @file = nil
81
- @context = nil
82
- @last_breakpoint = nil
83
- end
84
- end
85
-
86
- class IdeControlCommandProcessor < Processor
87
-
88
- def initialize(interface)
89
- @interface = interface
90
- end
91
-
92
- def process_commands
93
- control_command_classes = Command.commands.select(&:allow_in_control)
94
- state = ControlCommandProcessor::State.new(@interface, control_command_classes)
95
- control_commands = control_command_classes.map { |cmd| cmd.new(state) }
96
-
97
- while input = @interface.read_command
98
- split_commands(input).each do |cmd|
99
- catch(:debug_error) do
100
- if matched_cmd = control_commands.find { |c| c.match(cmd) }
101
- matched_cmd.execute
102
- else
103
- process_context_commands(cmd)
104
- end
105
- end
106
- end
107
- end
108
- rescue IOError, Errno::EPIPE
109
- rescue Exception
110
- print "INTERNAL ERROR!!! #{$!}\n" rescue nil
111
- print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
112
- ensure
113
- @interface.close
114
- end
115
-
116
- private
117
-
118
- def process_context_commands(input)
119
- unless Debugger.handler.at_line?
120
- errmsg pr("base.errors.no_suspended_thread", input: input)
121
- return
122
- end
123
- event_command_classes = Command.commands.select(&:event)
124
- state = CommandProcessor::State.new do |s|
125
- s.context = Debugger.handler.context
126
- s.file = Debugger.handler.file
127
- s.line = Debugger.handler.line
128
- s.binding = Debugger.handler.context.frame_binding(0)
129
- s.interface = @interface
130
- s.commands = event_command_classes
131
- end
132
- event_commands = event_command_classes.map { |cls| cls.new(state) }
133
- catch(:debug_error) do
134
- if cmd = event_commands.find { |c| c.match(input) }
135
- if state.context.dead? && cmd.class.need_context
136
- print pr("base.errors.command_unavailable")
137
- else
138
- cmd.execute
139
- end
140
- else
141
- print pr("base.errors.unknown_command", input: input)
142
- end
143
- end
144
- state.context.thread.run if state.proceed?
145
- end
146
- end
147
-
148
- end
149
- end
@@ -1,65 +0,0 @@
1
- module Debugger
2
- module Xml
3
- class IdeInterface < Interface # :nodoc:
4
- attr_accessor :command_queue
5
- attr_accessor :histfile
6
- attr_accessor :history_save
7
- attr_accessor :history_length
8
- attr_accessor :restart_file
9
-
10
- def initialize(socket)
11
- @command_queue = []
12
- @socket = socket
13
- @history_save = false
14
- @history_length = 256
15
- @histfile = ''
16
- @restart_file = nil
17
- end
18
-
19
- def close
20
- @socket.close
21
- rescue Exception
22
- end
23
-
24
- def print_debug(msg)
25
- STDOUT.puts(msg)
26
- end
27
-
28
- def errmsg(*args)
29
- print(*args)
30
- end
31
-
32
- def confirm(prompt)
33
- true
34
- end
35
-
36
- def finalize
37
- close
38
- end
39
-
40
- # Workaround for JRuby issue http://jira.codehaus.org/browse/JRUBY-2063
41
- def non_blocking_gets
42
- loop do
43
- result, _, _ = IO.select([@socket], nil, nil, 0.2)
44
- next unless result
45
- return result[0].gets
46
- end
47
- end
48
-
49
- def read_command(*args)
50
- result = non_blocking_gets
51
- raise IOError unless result
52
- result.chomp
53
- end
54
-
55
- def readline_support?
56
- false
57
- end
58
-
59
- def print(*args)
60
- @socket.printf(*escape_input(args))
61
- end
62
-
63
- end
64
- end
65
- end