debugger-xml 0.0.4 → 0.1.0

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