[tor-commits] [arm/release] Moving content and backlog tracking to interpretor

atagar at torproject.org atagar at torproject.org
Sun Sep 25 21:38:27 UTC 2011


commit 59b70998b162c461ec03780e9ca4cabdb7411af4
Author: Damian Johnson <atagar at torproject.org>
Date:   Tue Aug 30 09:41:53 2011 -0700

    Moving content and backlog tracking to interpretor
    
    The interpretor class will be tracking state so moving this information to it
    from the panel. This will make a common saving function feasable.
---
 src/cli/interpretorPanel.py |   49 +++++++++++-----------------------
 src/util/torInterpretor.py  |   60 +++++++++++++++++++++++++++++++++++--------
 2 files changed, 65 insertions(+), 44 deletions(-)

diff --git a/src/cli/interpretorPanel.py b/src/cli/interpretorPanel.py
index 02868ce..cc8b496 100644
--- a/src/cli/interpretorPanel.py
+++ b/src/cli/interpretorPanel.py
@@ -10,17 +10,12 @@ from util import panel, textInput, torInterpretor, uiTools
 USAGE_INFO = "to use this panel press enter"
 PROMPT_LINE = [torInterpretor.PROMPT, (USAGE_INFO, torInterpretor.USAGE_FORMAT)]
 
-# limits used for cropping
-BACKLOG_LIMIT = 100
-LINES_LIMIT = 2000
-
-# lazy loaded curses formatting constants
+# lazy loaded mapping of interpretor attributes to curses formatting constants
 FORMATS = {}
 
 def getFormat(formatAttr):
   """
-  Provides the curses drawing attributes for torInterpretor formatting
-  attributes.
+  Provides the curses drawing attributes for torInterpretor formats.
   
   Arguments:
     formatAttr - list of formatting attributes
@@ -45,11 +40,10 @@ def getFormat(formatAttr):
 class InterpretorPanel(panel.Panel):
   def __init__(self, stdscr):
     panel.Panel.__init__(self, stdscr, "interpretor", 0)
+    self.interpretor = torInterpretor.ControlInterpretor()
+    self.inputCompleter = torInterpretor.TorControlCompleter()
     self.isInputMode = False
     self.scroll = 0
-    self.interpretor = torInterpretor.ControlInterpretor()
-    self.previousCommands = []     # user input, newest to oldest
-    self.contents = [PROMPT_LINE]  # (msg, format enum) tuples being displayed (oldest to newest)
   
   def prompt(self):
     """
@@ -64,17 +58,16 @@ class InterpretorPanel(panel.Panel):
       self.redraw(True)
       
       # intercepts input so user can cycle through the history
-      torCommands = torInterpretor.TorControlCompleter()
-      
       validator = textInput.BasicValidator()
-      validator = textInput.HistoryValidator(self.previousCommands, validator)
-      validator = textInput.TabCompleter(torCommands.getMatches, validator)
+      validator = textInput.HistoryValidator(list(reversed(self.interpretor.getBacklog())), validator)
+      validator = textInput.TabCompleter(self.inputCompleter.getMatches, validator)
       
       xOffset = len(torInterpretor.PROMPT[0])
-      if len(self.contents) > self.maxY - 1:
+      displayLength = len(self.interpretor.getDisplayContents(PROMPT_LINE))
+      if displayLength > self.maxY - 1:
         xOffset += 3 # offset for scrollbar
       
-      inputLine = min(self.maxY - 1, len(self.contents))
+      inputLine = min(self.maxY - 1, displayLength)
       inputFormat = getFormat(torInterpretor.INPUT_FORMAT)
       input = self.getstr(inputLine, xOffset, "", inputFormat, validator = validator)
       input, isDone = input.strip(), False
@@ -83,22 +76,10 @@ class InterpretorPanel(panel.Panel):
         # terminate input when we get a blank line
         isDone = True
       else:
-        self.previousCommands.insert(0, input)
-        self.previousCommands = self.previousCommands[:BACKLOG_LIMIT]
-        
         try:
           inputEntry, outputEntry = self.interpretor.handleQuery(input)
         except torInterpretor.InterpretorClosed:
           isDone = True
-        
-        promptEntry = self.contents.pop() # removes old prompt entry
-        self.contents += inputEntry
-        self.contents += outputEntry
-        self.contents.append(promptEntry)
-        
-        # if too long then crop lines
-        cropLines = len(self.contents) - LINES_LIMIT
-        if cropLines > 0: self.contents = self.contents[cropLines:]
       
       if isDone:
         self.isInputMode = False
@@ -112,7 +93,8 @@ class InterpretorPanel(panel.Panel):
       self.prompt()
     elif uiTools.isScrollKey(key) and not self.isInputMode:
       pageHeight = self.getPreferredSize()[0] - 1
-      newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, len(self.contents))
+      displayLength = len(self.interpretor.getDisplayContents(PROMPT_LINE))
+      newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, displayLength)
       
       if self.scroll != newScroll:
         self.scroll = newScroll
@@ -127,17 +109,18 @@ class InterpretorPanel(panel.Panel):
     self.addstr(0, 0, "Control Interpretor%s:" % usageMsg, curses.A_STANDOUT)
     
     xOffset = 0
-    if len(self.contents) > height - 1:
+    displayContents = self.interpretor.getDisplayContents(PROMPT_LINE)
+    if len(displayContents) > height - 1:
       # if we're in input mode then make sure the last line is visible
       if self.isInputMode:
-        self.scroll = len(self.contents) - height + 1
+        self.scroll = len(displayContents) - height + 1
       
       xOffset = 3
-      self.addScrollBar(self.scroll, self.scroll + height - 1, len(self.contents), 1)
+      self.addScrollBar(self.scroll, self.scroll + height - 1, len(displayContents), 1)
     
     # draws prior commands and output
     drawLine = 1
-    for entry in self.contents[self.scroll:]:
+    for entry in displayContents[self.scroll:]:
       cursor = xOffset
       
       for msg, formatEntry in entry:
diff --git a/src/util/torInterpretor.py b/src/util/torInterpretor.py
index c7bcebb..e062532 100644
--- a/src/util/torInterpretor.py
+++ b/src/util/torInterpretor.py
@@ -31,6 +31,10 @@ ERROR_FORMAT = (Attr.BOLD, Color.RED)
 CSI = "\x1B[%sm"
 RESET = CSI % "0"
 
+# limits used for cropping
+BACKLOG_LIMIT = 100
+CONTENT_LIMIT = 2000
+
 class InterpretorClosed(Exception):
   """
   Exception raised when the interpretor should be shut down.
@@ -92,11 +96,10 @@ class TorControlCompleter:
           if line.startswith("config/*") or line.startswith("dir-usage"):
             continue
           
-          # strips off the ending asterisk if it accepts a value
           infoOpt = line.split(" ", 1)[0]
           
-          if infoOpt.endswith("*"):
-            infoOpt = infoOpt[:-1]
+          # strips off the ending asterisk if it accepts a value
+          if infoOpt.endswith("*"): infoOpt = infoOpt[:-1]
           
           self.commands.append("GETINFO %s" % infoOpt)
     else: self.commands.append("GETINFO ")
@@ -157,7 +160,7 @@ class TorControlCompleter:
   
   def getMatches(self, text):
     """
-    Provides all options that match the given input.
+    Provides all options that match the given input. This is case insensetive.
     
     Arguments:
       text - user input text to be matched against
@@ -171,10 +174,9 @@ class TorControlCompleter:
     the readlines set_completer function.
     """
     
-    for cmd in self.commands:
-      if cmd.lower().startswith(text.lower()):
-        if not state: return cmd
-        else: state -= 1
+    for cmd in self.getMatches(text):
+      if not state: return cmd
+      else: state -= 1
 
 class ControlInterpretor:
   """
@@ -183,8 +185,29 @@ class ControlInterpretor:
   """
   
   def __init__(self):
-    self.queries = []   # requests made, newest to oldest
-    self.contents = []  # (msg, format list) tuples of both input and output (oldest to newest)
+    self.backlog = []   # prior requests the user has made
+    self.contents = []  # (msg, format list) tuples for what's been displayed
+  
+  def getBacklog(self):
+    """
+    Provides the backlog of prior user input.
+    """
+    
+    return self.backlog
+  
+  def getDisplayContents(self, appendPrompt = None):
+    """
+    Provides a list of lines to be displayed, each being a list of (msg,
+    format) tuples for the content to be displayed. This is ordered as the
+    oldest to newest.
+    
+    Arguments:
+      appendPrompt - adds the given line to the end
+    """
+    
+    if appendPrompt:
+      return self.contents + [appendPrompt]
+    else: return self.contents
   
   def handleQuery(self, input):
     """
@@ -199,6 +222,12 @@ class ControlInterpretor:
     """
     
     input = input.strip()
+    
+    # appends new input, cropping if too long
+    self.backlog.append(input)
+    backlogCrop = len(self.backlog) - BACKLOG_LIMIT
+    if backlogCrop > 0: self.backlog = self.backlog[backlogCrop:]
+    
     inputEntry, outputEntry = [PROMPT], []
     conn = torTools.getConn()
     
@@ -258,7 +287,16 @@ class ControlInterpretor:
         except Exception, exc:
           outputEntry.append((str(exc), ERROR_FORMAT))
     
-    return (_splitOnNewlines(inputEntry), _splitOnNewlines(outputEntry))
+    # converts to lists split on newlines
+    inputLines = _splitOnNewlines(inputEntry)
+    outputLines = _splitOnNewlines(outputEntry)
+    
+    # appends new contents, cropping if too long
+    self.contents += inputLines + outputLines
+    cropLines = len(self.contents) - CONTENT_LIMIT
+    if cropLines > 0: self.contents = self.contents[cropLines:]
+    
+    return (inputLines, outputLines)
 
 def prompt():
   prompt = format(">>> ", Color.GREEN, Attr.BOLD)





More information about the tor-commits mailing list