Skip to content

Commit

Permalink
re #189 Update script runner so debug breakpoints move intelligently …
Browse files Browse the repository at this point in the history
…when code is inserted/deleted in front of the breakpoint
  • Loading branch information
Donald Hall committed May 4, 2017
1 parent f470e85 commit f841765
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 25 deletions.
58 changes: 52 additions & 6 deletions lib/cosmos/gui/text/ruby_editor.rb
Expand Up @@ -17,7 +17,7 @@ module Cosmos

class RubyEditor < CompletionTextEdit
# private slot used to connect to the blockCountChanged signal
slots 'line_count_changed()'
slots 'line_count_changed(int)'
# private slot used to connect to the updateRequest signal
slots 'update_line_number_area(const QRect &, int)'

Expand All @@ -26,6 +26,7 @@ class RubyEditor < CompletionTextEdit
signals 'breakpoints_cleared()'

attr_accessor :enable_breakpoints
attr_accessor :filename

# This works but slows down the GUI significantly when
# pasting a large (10k line) block of code into the editor
Expand Down Expand Up @@ -153,6 +154,8 @@ def paintEvent(event)
end

CHAR_57 = Qt::Char.new(57)
BREAKPOINT_SET = 1
BREAKPOINT_CLEAR = -1

def initialize(parent)
super(parent)
Expand All @@ -171,10 +174,10 @@ def initialize(parent)
@syntax = RubySyntax.new(document())
@lineNumberArea = LineNumberArea.new(self)

connect(self, SIGNAL('blockCountChanged(int)'), self, SLOT('line_count_changed()'))
connect(self, SIGNAL('blockCountChanged(int)'), self, SLOT('line_count_changed(int)'))
connect(self, SIGNAL('updateRequest(const QRect &, int)'), self, SLOT('update_line_number_area(const QRect &, int)'))

line_count_changed()
line_count_changed(-1)
end

def dispose
Expand All @@ -196,19 +199,59 @@ def context_menu(point)

def add_breakpoint(line)
@breakpoints << line
block = document.findBlockByNumber(line-1)
block.setUserState(BREAKPOINT_SET)
block.dispose
block = nil
@lineNumberArea.repaint
end

def clear_breakpoint(line)
@breakpoints.delete(line)
block = document.findBlockByNumber(line-1)
block.setUserState(BREAKPOINT_CLEAR)
block.dispose
block = nil
@lineNumberArea.repaint
end

def clear_breakpoints
@breakpoints = []
block = document.firstBlock()
while (block.isValid())
block.setUserState(BREAKPOINT_CLEAR)
next_block = block.next()
block.dispose
block = next_block
end
block.dispose
block = nil
@lineNumberArea.repaint
end

def update_breakpoints
breakpoints = []
block = document.firstBlock()
while (block.isValid())
if block.userState() == BREAKPOINT_SET
line = block.firstLineNumber() + 1
breakpoints << line
end
next_block = block.next()
block.dispose
block = next_block
end
block.dispose
block = nil

# Only emit signals if the breakpoints have changed.
if @breakpoints.sort != breakpoints.sort
emit breakpoints_cleared
breakpoints.each {|line| emit breakpoint_set(line)}
@breakpoints = breakpoints
end
end

def comment_or_uncomment_lines
cursor = textCursor
no_selection = cursor.hasSelection ? false : true
Expand Down Expand Up @@ -281,7 +324,7 @@ def line_number_area_paint_event(event)
Qt::AlignRight, # flags
number.to_s) # text

if @enable_breakpoints and @breakpoints.include?(number)
if @enable_breakpoints and block.userState() == BREAKPOINT_SET
painter.setBrush(Cosmos::RED)
painter.drawEllipse(2,
top+2,
Expand Down Expand Up @@ -312,7 +355,10 @@ def line_number_area_paint_event(event)

private

def line_count_changed
def line_count_changed(new_block_count)
if new_block_count >= 0
update_breakpoints()
end
setViewportMargins(line_number_area_width(), 0, 0, 0)
update
end
Expand All @@ -325,7 +371,7 @@ def update_line_number_area(rect, dy)
end
my_viewport = viewport()
viewport_rect = my_viewport.rect()
line_count_changed() if (rect.contains(viewport_rect))
line_count_changed(-1) if (rect.contains(viewport_rect))
viewport_rect.dispose
end

Expand Down
2 changes: 2 additions & 0 deletions lib/cosmos/tools/script_runner/script_runner.rb
Expand Up @@ -465,6 +465,7 @@ def file_close
close_active_tab()
else
active_script_runner_frame().stop_message_log
active_script_runner_frame().clear_breakpoints
@tab_book.setTabText(0, ' Untitled ')
@tab_book.currentTab.clear
end
Expand Down Expand Up @@ -849,6 +850,7 @@ def create_tab(filename = '')
def close_active_tab
if @tab_book.count > 1
active_script_runner_frame().stop_message_log
active_script_runner_frame().clear_breakpoints
tab_index = @tab_book.currentIndex
@tab_book.removeTab(tab_index)
if tab_index >= 1
Expand Down
64 changes: 45 additions & 19 deletions lib/cosmos/tools/script_runner/script_runner_frame.rb
Expand Up @@ -120,6 +120,7 @@ class ScriptRunnerFrame < Qt::Widget
@@limits_sleeper = Sleeper.new
@@cancel_output = false
@@cancel_limits = false
@@file_number = 1

def initialize(parent, default_tab_text = 'Untitled')
super(parent)
Expand All @@ -128,6 +129,11 @@ def initialize(parent, default_tab_text = 'Untitled')
@initialized = false
@debug_frame = nil

# Keep track of a unique file number so we can differentiate untitled tabs
@file_number = @@file_number
@@file_number +=1
@filename = ''

@layout = Qt::VBoxLayout.new
@layout.setContentsMargins(0,0,0,0)

Expand All @@ -149,6 +155,7 @@ def initialize(parent, default_tab_text = 'Untitled')

# Add Initial Text Window
@script = create_ruby_editor()
@script.filename = unique_filename()
@script.connect(SIGNAL('modificationChanged(bool)')) do |changed|
emit modificationChanged(changed)
end
Expand Down Expand Up @@ -182,7 +189,6 @@ def initialize(parent, default_tab_text = 'Untitled')

# Configure Variables
@line_offset = 0
@filename = ''
@output_io = StringIO.new('', 'r+')
@output_io_mutex = Mutex.new
@change_callback = nil
Expand Down Expand Up @@ -210,19 +216,22 @@ def initialize(parent, default_tab_text = 'Untitled')
@find_dialog = nil
@replace_dialog = nil

mark_breakpoints('')
mark_breakpoints(@script.filename)
end

def unique_filename
if @filename and !@filename.empty?
return @filename
else
return @default_tab_text.strip + @file_number.to_s
end
end

def current_tab_filename
if @tab_book_shown
filename = @tab_book.tabText(@tab_book.currentIndex)
if filename == @default_tab_text
return ''
else
return filename.strip
end
return @tab_book.widget(@tab_book.currentIndex).filename
else
return @filename
return @script.filename
end
end

Expand Down Expand Up @@ -262,7 +271,17 @@ def filename=(filename)
# Stop the message log so a new one will be created with the new filename
stop_message_log()
@filename = filename
mark_breakpoints(filename)

# Deal with breakpoints created under the previous filename.
bkpt_filename = unique_filename()
if @@breakpoints[bkpt_filename].nil?
@@breakpoints[bkpt_filename] = @@breakpoints[@script.filename]
end
if bkpt_filename != @script.filename
@@breakpoints.delete(@script.filename)
@script.filename = bkpt_filename
end
mark_breakpoints(@script.filename)
end

def modified
Expand Down Expand Up @@ -298,6 +317,7 @@ def allow_start=(value)
def clear
self.set_text('')
self.filename = ''
@script.filename = unique_filename()
self.modified = false
end

Expand Down Expand Up @@ -384,13 +404,15 @@ def set_text(text, filename = '')
@script.setPlainText(text)
@script.stop_highlight
@filename = filename
mark_breakpoints(filename)
@script.filename = unique_filename()
mark_breakpoints(@script.filename)
end
end

def set_text_from_file(filename)
unless running?()
@@file_cache[filename] = nil
@@breakpoints[filename] = nil
load_file_into_script(filename)
@filename = filename
end
Expand Down Expand Up @@ -960,26 +982,27 @@ def hide_debug
end

def self.set_breakpoint(filename, line_number)
filename = File.basename(filename)
@@breakpoints[filename] ||= {}
@@breakpoints[filename][line_number] = true
end

def self.clear_breakpoint(filename, line_number)
filename = File.basename(filename)
@@breakpoints[filename] ||= {}
@@breakpoints[filename].delete(line_number) if @@breakpoints[filename][line_number]
end

def self.clear_breakpoints(filename = nil)
filename = File.basename(filename) unless filename.nil?
if filename == nil or filename.empty?
@@breakpoints = {}
else
@@breakpoints[filename] = {}
@@breakpoints.delete(filename)
end
end

def clear_breakpoints
ScriptRunnerFrame.clear_breakpoints(unique_filename())
end

def select_tab_and_destroy_tabs_after_index(index)
Qt.execute_in_main_thread(true) do
if @tab_book_shown
Expand Down Expand Up @@ -1352,6 +1375,7 @@ def handle_potential_tab_change(filename)
else # new file
# Create new tab
new_script = create_ruby_editor()
new_script.filename = filename
@tab_book.addTab(new_script, ' ' + File.basename(filename) + ' ')

@call_stack.push(filename.dup)
Expand All @@ -1373,9 +1397,12 @@ def show_active_tab
end

def handle_pause(filename, line_number)
filename = File.basename(filename)
bkpt_filename = ''
Qt.execute_in_main_thread(true) {bkpt_filename = @active_script.filename}
breakpoint = false
breakpoint = true if @@breakpoints[filename] and @@breakpoints[filename][line_number]
breakpoint = true if @@breakpoints[bkpt_filename] and @@breakpoints[bkpt_filename][line_number]

filename = File.basename(filename)
if @pause
@pause = false unless @@step_mode
if breakpoint
Expand Down Expand Up @@ -1544,8 +1571,7 @@ def load_file_into_script(filename)
end

def mark_breakpoints(filename)
@active_script.clear_breakpoints
breakpoints = @@breakpoints[File.basename(filename)]
breakpoints = @@breakpoints[filename]
if breakpoints
breakpoints.each do |line_number, present|
@active_script.add_breakpoint(line_number) if present
Expand Down

0 comments on commit f841765

Please sign in to comment.