diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 | 
| commit | 14f1b3e8826ce43b978db93a62d1166055db5394 (patch) | |
| tree | 0a00ad8d3498783fe0193f3b656bca17c4c8697d /utils/vim-lldb/python-vim-lldb/vim_panes.py | |
| parent | 4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff) | |
Notes
Diffstat (limited to 'utils/vim-lldb/python-vim-lldb/vim_panes.py')
| -rw-r--r-- | utils/vim-lldb/python-vim-lldb/vim_panes.py | 987 | 
1 files changed, 519 insertions, 468 deletions
| diff --git a/utils/vim-lldb/python-vim-lldb/vim_panes.py b/utils/vim-lldb/python-vim-lldb/vim_panes.py index ec537199922c..b0c804d19628 100644 --- a/utils/vim-lldb/python-vim-lldb/vim_panes.py +++ b/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") | 
