diff options
Diffstat (limited to 'lldb/utils/vim-lldb/python-vim-lldb/vim_panes.py')
-rw-r--r-- | lldb/utils/vim-lldb/python-vim-lldb/vim_panes.py | 987 |
1 files changed, 519 insertions, 468 deletions
diff --git a/lldb/utils/vim-lldb/python-vim-lldb/vim_panes.py b/lldb/utils/vim-lldb/python-vim-lldb/vim_panes.py index ec537199922..b0c804d1962 100644 --- a/lldb/utils/vim-lldb/python-vim-lldb/vim_panes.py +++ b/lldb/utils/vim-lldb/python-vim-lldb/vim_panes.py @@ -6,8 +6,8 @@ # - get_content() - returns a string with the pane contents # # Optionally, to highlight text, implement: -# - get_highlights() - returns a map -# +# - get_highlights() - returns a map +# # And call: # - define_highlight(unique_name, colour) # at some point in the constructor. @@ -16,7 +16,7 @@ # If the pane shows some key-value data that is in the context of a # single frame, inherit from FrameKeyValuePane and implement: # - get_frame_content(self, SBFrame frame) -# +# # # If the pane presents some information that can be retrieved with # a simple LLDB command while the subprocess is stopped, inherit @@ -27,12 +27,12 @@ # Optionally, you can implement: # - get_selected_line() # to highlight a selected line and place the cursor there. -# +# # # FIXME: implement WatchlistPane to displayed watched expressions -# FIXME: define interface for interactive panes, like catching enter +# FIXME: define interface for interactive panes, like catching enter # presses to change selected frame/thread... -# +# import lldb import vim @@ -44,6 +44,8 @@ import sys # ============================================================== # Shamelessly copy/pasted from lldbutil.py in the test suite + + def get_description(obj, option=None): """Calls lldb_obj.GetDescription() and returns a string, or None. @@ -70,512 +72,552 @@ def get_description(obj, option=None): if not success: return None return stream.GetData() - + + def get_selected_thread(target): - """ Returns a tuple with (thread, error) where thread == None if error occurs """ - process = target.GetProcess() - if process is None or not process.IsValid(): - return (None, VimPane.MSG_NO_PROCESS) + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") - thread = process.GetSelectedThread() - if thread is None or not thread.IsValid(): - return (None, VimPane.MSG_NO_THREADS) - return (thread, "") def get_selected_frame(target): - """ Returns a tuple with (frame, error) where frame == None if error occurs """ - (thread, error) = get_selected_thread(target) - if thread is None: - return (None, error) + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") - frame = thread.GetSelectedFrame() - if frame is None or not frame.IsValid(): - return (None, VimPane.MSG_NO_FRAME) - return (frame, "") def _cmd(cmd): - vim.command("call confirm('%s')" % cmd) - vim.command(cmd) + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + def move_cursor(line, col=0): - """ moves cursor to specified line and col """ - cw = vim.current.window - if cw.cursor[0] != line: - vim.command("execute \"normal %dgg\"" % line) + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + def winnr(): - """ Returns currently selected window number """ - return int(vim.eval("winnr()")) + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + def bufwinnr(name): - """ Returns window number corresponding with buffer name """ - return int(vim.eval("bufwinnr('%s')" % name)) + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + def goto_window(nr): - """ go to window number nr""" - if nr != winnr(): - vim.command(str(nr) + ' wincmd w') + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + def goto_next_window(): - """ go to next window. """ - vim.command('wincmd w') - return (winnr(), vim.current.buffer.name) + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + def goto_previous_window(): - """ go to previously selected window """ - vim.command("execute \"normal \\<c-w>p\"") + """ go to previously selected window """ + vim.command("execute \"normal \\<c-w>p\"") + def have_gui(): - """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ - return int(vim.eval("has('gui_running')")) == 1 + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + class PaneLayout(object): - """ A container for a (vertical) group layout of VimPanes """ + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes=[]): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a + # first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and + # closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName=None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained=True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or + # reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains( + curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes=[]): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) - def __init__(self): - self.panes = {} - def havePane(self, name): - """ Returns true if name is a registered pane, False otherwise """ - return name in self.panes +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer is None or len( + dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True - def prepare(self, panes = []): - """ Draw panes on screen. If empty list is provided, show all. """ + def prepare(self, method='new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer is None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("set nonumber") # Don't display line numbers + # vim.command("set nowrap") # Don't wrap text + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int(vim.eval("winwidth(0)")) + self.height = int(vim.eval("winheight(0)")) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min( + original_cursor[1], len( + self.buffer[ + cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane + # implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None - # If we can't select a window contained in the layout, we are doing a first draw - first_draw = not self.selectWindow(True) - did_first_draw = False + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command( + "highlight %s ctermbg=%s guibg=%s" % + (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True - # Prepare each registered pane - for name in self.panes: - if name in panes or len(panes) == 0: - if first_draw: - # First window in layout will be created with :vsp, and closed later - vim.command(":vsp") - first_draw = False - did_first_draw = True - self.panes[name].prepare() + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None - if did_first_draw: - # Close the split window - vim.command(":q") + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass - self.selectWindow(False) + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} - def contains(self, bufferName = None): - """ Returns True if window with name bufferName is contained in the layout, False otherwise. - If bufferName is None, the currently selected window is checked. - """ - if not bufferName: - bufferName = vim.current.buffer.name - for p in self.panes: - if bufferName is not None and bufferName.endswith(p): - return True - return False +class FrameKeyValuePane(VimPane): - def selectWindow(self, select_contained = True): - """ Selects a window contained in the layout (if select_contained = True) and returns True. - If select_contained = False, a window that is not contained is selected. Returns False - if no group windows can be selected. - """ - if select_contained == self.contains(): - # Simple case: we are already selected - return True + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, + # variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed=False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or ( + key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret - # Otherwise, switch to next window until we find a contained window, or reach the first window again. - first = winnr() - (curnum, curname) = goto_next_window() - while not select_contained == self.contains(curname) and curnum != first: - (curnum, curname) = goto_next_window() +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ - return self.contains(curname) == select_contained + def __init__(self, owner, name='locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) - def hide(self, panes = []): - """ Hide panes specified. If empty list provided, hide all. """ - for name in self.panes: - if name in panes or len(panes) == 0: - self.panes[name].destroy() + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = True + self.show_in_scope_only = True - def registerForUpdates(self, p): - self.panes[p.name] = p + def format_variable(self, var): + """ Returns a Tuple of strings "(Type) Name", "Value" for SBValue var """ + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace + # with ... + val = "..." - def update(self, target, controller): - for name in self.panes: - self.panes[name].update(target, controller) + return ("(%s) %s" % (var.GetTypeName(), var.GetName()), "%s" % val) + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + return [self.format_variable(x) for x in vals] -class VimPane(object): - """ A generic base class for a pane that displays stuff """ - CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' - CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' - CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' - - SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' - SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' - SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' - - MSG_NO_TARGET = "Target does not exist." - MSG_NO_PROCESS = "Process does not exist." - MSG_NO_THREADS = "No valid threads." - MSG_NO_FRAME = "No valid frame." - - # list of defined highlights, so we avoid re-defining them - highlightTypes = [] - - def __init__(self, owner, name, open_below=False, height=3): - self.owner = owner - self.name = name - self.buffer = None - self.maxHeight = 20 - self.openBelow = open_below - self.height = height - self.owner.registerForUpdates(self) - - def isPrepared(self): - """ check window is OK """ - if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: - return False - return True - - def prepare(self, method = 'new'): - """ check window is OK, if not then create """ - if not self.isPrepared(): - self.create(method) - - def on_create(self): - pass - - def destroy(self): - """ destroy window """ - if self.buffer == None or len(dir(self.buffer)) == 0: - return - vim.command('bdelete ' + self.name) - - def create(self, method): - """ create window """ - - if method != 'edit': - belowcmd = "below" if self.openBelow else "" - vim.command('silent %s %s %s' % (belowcmd, method, self.name)) - else: - vim.command('silent %s %s' % (method, self.name)) - - self.window = vim.current.window - - # Set LLDB pane options - vim.command("setlocal buftype=nofile") # Don't try to open a file - vim.command("setlocal noswapfile") # Don't use a swap file - vim.command("set nonumber") # Don't display line numbers - #vim.command("set nowrap") # Don't wrap text - - # Save some parameters and reference to buffer - self.buffer = vim.current.buffer - self.width = int( vim.eval("winwidth(0)") ) - self.height = int( vim.eval("winheight(0)") ) - - self.on_create() - goto_previous_window() - - def update(self, target, controller): - """ updates buffer contents """ - self.target = target - if not self.isPrepared(): - # Window is hidden, or otherwise not ready for an update - return - - original_cursor = self.window.cursor - - # Select pane - goto_window(bufwinnr(self.name)) - - # Clean and update content, and apply any highlights. - self.clean() - - if self.write(self.get_content(target, controller)): - self.apply_highlights() - - cursor = self.get_selected_line() - if cursor is None: - # Place the cursor at its original position in the window - cursor_line = min(original_cursor[0], len(self.buffer)) - cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) - else: - # Place the cursor at the location requested by a VimPane implementation - cursor_line = min(cursor, len(self.buffer)) - cursor_col = self.window.cursor[1] - - self.window.cursor = (cursor_line, cursor_col) - - goto_previous_window() - - def get_selected_line(self): - """ Returns the line number to move the cursor to, or None to leave - it where the user last left it. - Subclasses implement this to define custom behaviour. - """ - return None - - def apply_highlights(self): - """ Highlights each set of lines in each highlight group """ - highlights = self.get_highlights() - for highlightType in highlights: - lines = highlights[highlightType] - if len(lines) == 0: - continue - - cmd = 'match %s /' % highlightType - lines = ['\%' + '%d' % line + 'l' for line in lines] - cmd += '\\|'.join(lines) - cmd += '/' - vim.command(cmd) - - def define_highlight(self, name, colour): - """ Defines highlihght """ - if name in VimPane.highlightTypes: - # highlight already defined - return - - vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) - VimPane.highlightTypes.append(name) - - def write(self, msg): - """ replace buffer with msg""" - self.prepare() - - msg = str(msg.encode("utf-8", "replace")).split('\n') - try: - self.buffer.append(msg) - vim.command("execute \"normal ggdd\"") - except vim.error: - # cannot update window; happens when vim is exiting. - return False - - move_cursor(1, 0) - return True - - def clean(self): - """ clean all datas in buffer """ - self.prepare() - vim.command(':%d') - #self.buffer[:] = None - - def get_content(self, target, controller): - """ subclasses implement this to provide pane content """ - assert(0 and "pane subclass must implement this") - pass - - def get_highlights(self): - """ Subclasses implement this to provide pane highlights. - This function is expected to return a map of: - { highlight_name ==> [line_number, ...], ... } - """ - return {} +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ -class FrameKeyValuePane(VimPane): - def __init__(self, owner, name, open_below): - """ Initialize parent, define member variables, choose which highlight - to use based on whether or not we have a gui (MacVim/Gvim). - """ + def __init__(self, owner, name='registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) - VimPane.__init__(self, owner, name, open_below) + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) - # Map-of-maps key/value history { frame --> { variable_name, variable_value } } - self.frameValues = {} + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ - if have_gui(): - self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI - else: - self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM - self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, - VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) - - def format_pair(self, key, value, changed = False): - """ Formats a key/value pair. Appends a '*' if changed == True """ - marker = '*' if changed else ' ' - return "%s %s = %s\n" % (marker, key, value) - - def get_content(self, target, controller): - """ Get content for a frame-aware pane. Also builds the list of lines that - need highlighting (i.e. changed values.) - """ - if target is None or not target.IsValid(): - return VimPane.MSG_NO_TARGET + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) - self.changedLines = [] + for reg in register_sets: + result.append(self.format_register(reg)) + return result - (frame, err) = get_selected_frame(target) - if frame is None: - return err - output = get_description(frame) - lineNum = 1 +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ - # Retrieve the last values displayed for this frame - frameId = get_description(frame.GetBlock()) - if frameId in self.frameValues: - frameOldValues = self.frameValues[frameId] - else: - frameOldValues = {} - - # Read the frame variables - vals = self.get_frame_content(frame) - for (key, value) in vals: - lineNum += 1 - if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): - output += self.format_pair(key, value) - else: - output += self.format_pair(key, value, True) - self.changedLines.append(lineNum) - - # Save values as oldValues - newValues = {} - for (key, value) in vals: - newValues[key] = value - self.frameValues[frameId] = newValues - - return output - - def get_highlights(self): - ret = {} - ret[self.changedHighlight] = self.changedLines - return ret + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required -class LocalsPane(FrameKeyValuePane): - """ Pane that displays local variables """ - def __init__(self, owner, name = 'locals'): - FrameKeyValuePane.__init__(self, owner, name, open_below=True) - - # FIXME: allow users to customize display of args/locals/statics/scope - self.arguments = True - self.show_locals = True - self.show_statics = True - self.show_in_scope_only = True - - def format_variable(self, var): - """ Returns a Tuple of strings "(Type) Name", "Value" for SBValue var """ - val = var.GetValue() - if val is None: - # If the value is too big, SBValue.GetValue() returns None; replace with ... - val = "..." - - return ("(%s) %s" % (var.GetTypeName(), var.GetName()), "%s" % val) - - def get_frame_content(self, frame): - """ Returns list of key-value pairs of local variables in frame """ - vals = frame.GetVariables(self.arguments, - self.show_locals, - self.show_statics, - self.show_in_scope_only) - return [self.format_variable(x) for x in vals] + def setCommand(self, command, args=""): + self.command = command + self.args = args -class RegistersPane(FrameKeyValuePane): - """ Pane that displays the contents of registers """ - def __init__(self, owner, name = 'registers'): - FrameKeyValuePane.__init__(self, owner, name, open_below=True) - - def format_register(self, reg): - """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ - name = reg.GetName() - val = reg.GetValue() - if val is None: - val = "..." - return (name, val.strip()) - - def get_frame_content(self, frame): - """ Returns a list of key-value pairs ("name", "value") of registers in frame """ - - result = [] - for register_sets in frame.GetRegisters(): - # hack the register group name into the list of registers... - result.append((" = = %s =" % register_sets.GetName(), "")) - - for reg in register_sets: - result.append(self.format_register(reg)) - return result + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput( + self.command, self.args) + return output -class CommandPane(VimPane): - """ Pane that displays the output of an LLDB command """ - def __init__(self, owner, name, open_below, process_required=True): - VimPane.__init__(self, owner, name, open_below) - self.process_required = process_required - - def setCommand(self, command, args = ""): - self.command = command - self.args = args - - def get_content(self, target, controller): - output = "" - if not target: - output = VimPane.MSG_NO_TARGET - elif self.process_required and not target.GetProcess(): - output = VimPane.MSG_NO_PROCESS - else: - (success, output) = controller.getCommandOutput(self.command, self.args) - return output class StoppedCommandPane(CommandPane): - """ Pane that displays the output of an LLDB command when the process is - stopped; otherwise displays process status. This class also implements - highlighting for a single line (to show a single-line selected entity.) - """ - def __init__(self, owner, name, open_below): - """ Initialize parent and define highlight to use for selected line. """ - CommandPane.__init__(self, owner, name, open_below) - if have_gui(): - self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI - else: - self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM - self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, - VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) - - def get_content(self, target, controller): - """ Returns the output of a command that relies on the process being stopped. - If the process is not in 'stopped' state, the process status is returned. + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) """ - output = "" - if not target or not target.IsValid(): - output = VimPane.MSG_NO_TARGET - elif not target.GetProcess() or not target.GetProcess().IsValid(): - output = VimPane.MSG_NO_PROCESS - elif target.GetProcess().GetState() == lldb.eStateStopped: - (success, output) = controller.getCommandOutput(self.command, self.args) - else: - (success, output) = controller.getCommandOutput("process", "status") - return output - def get_highlights(self): - """ Highlight the line under the cursor. Users moving the cursor has - no effect on the selected line. - """ - ret = {} - line = self.get_selected_line() - if line is not None: - ret[self.selectedHighlight] = [line] - return ret - return ret - - def get_selected_line(self): - """ Subclasses implement this to control where the cursor (and selected highlight) - is placed. - """ - return None + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput( + self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + class DisassemblyPane(CommandPane): - """ Pane that displays disassembly around PC """ - def __init__(self, owner, name = 'disassembly'): - CommandPane.__init__(self, owner, name, open_below=True) + """ Pane that displays disassembly around PC """ + + def __init__(self, owner, name='disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) - # FIXME: let users customize the number of instructions to disassemble - self.setCommand("disassemble", "-c %d -p" % self.maxHeight) class ThreadPane(StoppedCommandPane): - """ Pane that displays threads list """ - def __init__(self, owner, name = 'threads'): - StoppedCommandPane.__init__(self, owner, name, open_below=False) - self.setCommand("thread", "list") + """ Pane that displays threads list """ + + def __init__(self, owner, name='threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") # FIXME: the function below assumes threads are listed in sequential order, # which turns out to not be the case. Highlighting of selected thread @@ -592,27 +634,36 @@ class ThreadPane(StoppedCommandPane): # else: # return thread.GetIndexID() + 1 + class BacktracePane(StoppedCommandPane): - """ Pane that displays backtrace """ - def __init__(self, owner, name = 'backtrace'): - StoppedCommandPane.__init__(self, owner, name, open_below=False) - self.setCommand("bt", "") + """ Pane that displays backtrace """ + def __init__(self, owner, name='backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") - def get_selected_line(self): - """ Returns the line number in the buffer with the selected frame. - Formula: selected_line = selected_frame_id + 2 - FIXME: the above formula hack does not work when the function return - value is printed in the bt window; the wrong line is highlighted. - """ + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 - (frame, err) = get_selected_frame(self.target) - if frame is None: - return None - else: - return frame.GetFrameID() + 2 class BreakpointsPane(CommandPane): - def __init__(self, owner, name = 'breakpoints'): - super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) - self.setCommand("breakpoint", "list") + + def __init__(self, owner, name='breakpoints'): + super( + BreakpointsPane, + self).__init__( + owner, + name, + open_below=False, + process_required=False) + self.setCommand("breakpoint", "list") |