[tor-commits] [nyx/master] Rewrite descriptor dialog's draw() method

atagar at torproject.org atagar at torproject.org
Sat Jun 27 21:20:49 UTC 2015


commit 55166969f6caad16c080f3cbd85d9a372eb0cc90
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Jun 27 12:31:00 2015 -0700

    Rewrite descriptor dialog's draw() method
    
    Not quite done with the dialog, but damn its draw method is now better. :P
---
 nyx/connections/descriptor_popup.py |  194 ++++++++++++-----------------------
 nyx/popups.py                       |   19 ++--
 2 files changed, 73 insertions(+), 140 deletions(-)

diff --git a/nyx/connections/descriptor_popup.py b/nyx/connections/descriptor_popup.py
index 7eeb9df..1d155c3 100644
--- a/nyx/connections/descriptor_popup.py
+++ b/nyx/connections/descriptor_popup.py
@@ -12,14 +12,11 @@ from nyx.util import panel, tor_controller, ui_tools
 
 from stem.util import str_tools
 
-# field keywords used to identify areas for coloring
-
-LINE_NUM_COLOR = 'yellow'
+HEADERS = ['Consensus:', 'Microdescriptor:', 'Server Descriptor:']
 HEADER_COLOR = 'cyan'
-HEADER_PREFIX = ['Consensus:', 'Microdescriptor:', 'Server Descriptor:']
+LINE_NUMBER_COLOR = 'yellow'
 
-SIG_START_KEYS = ['-----BEGIN RSA PUBLIC KEY-----', '-----BEGIN SIGNATURE-----']
-SIG_END_KEYS = ['-----END RSA PUBLIC KEY-----', '-----END SIGNATURE-----']
+BLOCK_START, BLOCK_END = '-----BEGIN ', '-----END '
 
 UNRESOLVED_MSG = 'No consensus data available'
 ERROR_MSG = 'Unable to retrieve data'
@@ -42,11 +39,9 @@ def show_descriptor_popup(conn_panel):
   conn_panel.redraw(True)
 
   control = nyx.controller.get_controller()
-  panel.CURSES_LOCK.acquire()
-  is_done = False
 
-  try:
-    while not is_done:
+  with panel.CURSES_LOCK:
+    while True:
       selection = conn_panel.get_selection()
 
       if not selection:
@@ -55,52 +50,42 @@ def show_descriptor_popup(conn_panel):
       fingerprint = selection.foreign.get_fingerprint()
 
       if fingerprint == 'UNKNOWN':
-        fingerprint = None
-
-      display_text = _display_text(fingerprint)
-      display_color = nyx.connections.conn_entry.CATEGORY_COLOR[selection.get_type()]
-      show_line_numbers = fingerprint is not None
-
-      # determines the maximum popup size the display_text can fill
+        title = 'Consensus Descriptor (%s):' % fingerprint
+        lines = [UNRESOLVED_MSG]
+        show_line_numbers = False
+      else:
+        title = 'Consensus Descriptor:'
+        lines = _display_text(fingerprint)
+        show_line_numbers = True
 
-      popup_height, popup_width = _preferred_size(display_text, conn_panel.max_x, show_line_numbers)
+      color = nyx.connections.conn_entry.CATEGORY_COLOR[selection.get_type()]
+      popup_height, popup_width = _preferred_size(lines, conn_panel.max_x, show_line_numbers)
 
       with nyx.popups.popup_window(popup_height, popup_width) as (popup, _, height):
         if popup:
-          scroll, is_changed = 0, True
-
-          while not is_done:
-            if is_changed:
-              draw(popup, fingerprint, display_text, display_color, scroll, show_line_numbers)
-              is_changed = False
+          scroll = 0
+          _draw(popup, title, lines, color, scroll, show_line_numbers)
 
+          while True:
             key = control.key_input()
 
             if key.is_scroll():
-              # TODO: This is a bit buggy in that scrolling is by display_text
-              # lines rather than the displayed lines, causing issues when
-              # content wraps. The result is that we can't have a scrollbar and
-              # can't scroll to the bottom if there's a multi-line being
-              # displayed. However, trying to correct this introduces a big can
-              # of worms and after hours decided that this isn't worth the
-              # effort...
-
-              new_scroll = ui_tools.get_scroll_position(key, scroll, height - 2, len(display_text))
+              new_scroll = ui_tools.get_scroll_position(key, scroll, height - 2, len(lines))
 
               if scroll != new_scroll:
-                scroll, is_changed = new_scroll, True
+                scroll = new_scroll
+                _draw(popup, title, lines, color, scroll, show_line_numbers)
             elif key.is_selection() or key.match('d'):
-              is_done = True  # closes popup
+              return  # closes popup
             elif key.match('left'):
               conn_panel.handle_key(panel.KeyInput(curses.KEY_UP))
               break
             elif key.match('right'):
               conn_panel.handle_key(panel.KeyInput(curses.KEY_DOWN))
               break
-  finally:
-    conn_panel.set_title_visible(True)
-    conn_panel.redraw(True)
-    panel.CURSES_LOCK.release()
+
+  conn_panel.set_title_visible(True)
+  conn_panel.redraw(True)
 
 
 def _display_text(fingerprint):
@@ -112,9 +97,6 @@ def _display_text(fingerprint):
   :returns: **list** with the lines that should be displayed in the dialog
   """
 
-  if not fingerprint:
-    return [UNRESOLVED_MSG]
-
   controller = tor_controller()
   router_status_entry = controller.get_network_status(fingerprint, None)
   microdescriptor = controller.get_microdescriptor(fingerprint, None)
@@ -153,108 +135,60 @@ def _preferred_size(text, max_width, show_line_numbers):
   return (height, width)
 
 
-def draw(popup, fingerprint, display_text, display_color, scroll, show_line_numbers):
-  popup.win.erase()
-  popup.win.box()
-  x_offset = 2
-
-  if fingerprint:
-    title = 'Consensus Descriptor (%s):' % fingerprint
-  else:
-    title = 'Consensus Descriptor:'
-
-  popup.addstr(0, 0, title, curses.A_STANDOUT)
-
-  line_number_width = int(math.log10(len(display_text))) + 1
-  is_encryption_block = False   # flag indicating if we're currently displaying a key
-
-  # checks if first line is in an encryption block
+def _draw(popup, title, lines, entry_color, scroll, show_line_numbers):
+  def draw_msg(popup, min_x, x, y, width, msg, *attr):
+    while msg:
+      draw_msg, msg = str_tools.crop(msg, width - x, None, ending = None, get_remainder = True)
 
-  for i in range(0, scroll):
-    line_text = display_text[i].strip()
+      if not draw_msg:
+        draw_msg, msg = str_tools.crop(msg, width - x), ''  # first word is longer than the line
 
-    if line_text in SIG_START_KEYS:
-      is_encryption_block = True
-    elif line_text in SIG_END_KEYS:
-      is_encryption_block = False
+      x = popup.addstr(y, x, draw_msg, *attr)
 
-  draw_line, page_height = 1, popup.max_y - 2
+      if msg:
+        x, y = min_x, y + 1
 
-  for i in range(scroll, scroll + page_height):
-    line_text = display_text[i].strip()
-    x_offset = 2
+    return x, y
 
-    if show_line_numbers:
-      line_number_label = ('%%%ii' % line_number_width) % (i + 1)
-
-      popup.addstr(draw_line, x_offset, line_number_label, curses.A_BOLD, LINE_NUM_COLOR)
-      x_offset += line_number_width + 1
-
-    # Most consensus and descriptor lines are keyword/value pairs. Both are
-    # shown with the same color, but the keyword is bolded.
-
-    keyword, value = line_text, ''
-    draw_format = display_color
-
-    if line_text.startswith(HEADER_PREFIX[0]) or line_text.startswith(HEADER_PREFIX[1]):
-      keyword, value = line_text, ''
-      draw_format = HEADER_COLOR
-    elif line_text == UNRESOLVED_MSG or line_text == ERROR_MSG:
-      keyword, value = line_text, ''
-    elif line_text in SIG_START_KEYS:
-      keyword, value = line_text, ''
-      is_encryption_block = True
-    elif line_text in SIG_END_KEYS:
-      keyword, value = line_text, ''
-      is_encryption_block = False
-    elif is_encryption_block:
-      keyword, value = '', line_text
-    elif ' ' in line_text:
-      div_index = line_text.find(' ')
-      keyword, value = line_text[:div_index], line_text[div_index:]
-
-    display_queue = [(keyword, (draw_format, curses.A_BOLD)), (value, (draw_format,))]
-    cursor_location = x_offset
-
-    while display_queue:
-      msg, msg_format = display_queue.pop(0)
-
-      if not msg:
-        continue
-
-      max_msg_size = popup.max_x - 1 - cursor_location
-
-      if len(msg) >= max_msg_size:
-        # needs to split up the line
+  popup.win.erase()
 
-        msg, remainder = str_tools.crop(msg, max_msg_size, None, ending = None, get_remainder = True)
+  line_number_width = int(math.log10(len(lines))) + 1
+  in_block = False   # flag indicating if we're currently in crypto content
+  width = popup.max_x - 2  # leave space on the right for the border and an empty line
+  height = popup.max_y - 2  # height of the dialog without the top and bottom border
+  offset = line_number_width + 3 if show_line_numbers else 2
 
-        if x_offset == cursor_location and msg == '':
-          # first word is longer than the line
+  y = 1
 
-          msg = str_tools.crop(remainder, max_msg_size)
+  for i, line in enumerate(lines):
+    keyword, value = line, ''
+    color = entry_color
 
-          if ' ' in remainder:
-            remainder = remainder.split(' ', 1)[1]
-          else:
-            remainder = ''
+    if line in HEADERS:
+      color = HEADER_COLOR
+    elif line.startswith(BLOCK_START):
+      in_block = True
+    elif line.startswith(BLOCK_END):
+      in_block = False
+    elif in_block:
+      keyword, value = '', line
+    elif ' ' in line and line != UNRESOLVED_MSG and line != ERROR_MSG:
+      keyword, value = line.split(' ', 1)
 
-        popup.addstr(draw_line, cursor_location, msg, *msg_format)
-        cursor_location = x_offset
+    if i < scroll:
+      continue
 
-        if remainder:
-          display_queue.insert(0, (remainder.strip(), msg_format))
-          draw_line += 1
-      else:
-        popup.addstr(draw_line, cursor_location, msg, *msg_format)
-        cursor_location += len(msg)
+    if show_line_numbers:
+      popup.addstr(y, 2, str(i + 1).rjust(line_number_width), curses.A_BOLD, LINE_NUMBER_COLOR)
 
-      if draw_line > page_height:
-        break
+    x, y = draw_msg(popup, offset, offset, y, width, keyword, color, curses.A_BOLD)
+    x, y = draw_msg(popup, offset, x + 1, y, width, value, color)
 
-    draw_line += 1
+    y += 1
 
-    if draw_line > page_height:
+    if y > height:
       break
 
+  popup.win.box()
+  popup.addstr(0, 0, title, curses.A_STANDOUT)
   popup.win.refresh()
diff --git a/nyx/popups.py b/nyx/popups.py
index 355d7f1..38eade0 100644
--- a/nyx/popups.py
+++ b/nyx/popups.py
@@ -71,16 +71,15 @@ def input_prompt(msg, initial_value = ''):
     initial_value - initial value of the field
   """
 
-  panel.CURSES_LOCK.acquire()
-  control = nyx.controller.get_controller()
-  msg_panel = control.get_panel('msg')
-  msg_panel.set_message(msg)
-  msg_panel.redraw(True)
-  user_input = msg_panel.getstr(0, len(msg), initial_value)
-  control.set_msg()
-  panel.CURSES_LOCK.release()
-
-  return user_input
+  with panel.CURSES_LOCK:
+    control = nyx.controller.get_controller()
+    msg_panel = control.get_panel('msg')
+    msg_panel.set_message(msg)
+    msg_panel.redraw(True)
+    user_input = msg_panel.getstr(0, len(msg), initial_value)
+    control.set_msg()
+
+    return user_input
 
 
 def show_msg(msg, max_wait = -1, attr = curses.A_STANDOUT):





More information about the tor-commits mailing list