Browse Source

ui: new `item_chooser()` function

The MMGen Project 1 week ago
parent
commit
a75518e78f
2 changed files with 23 additions and 20 deletions
  1. 7 19
      mmgen/tw/addresses.py
  2. 16 1
      mmgen/ui.py

+ 7 - 19
mmgen/tw/addresses.py

@@ -12,7 +12,7 @@
 tw.addresses: Tracking wallet listaddresses class for the MMGen suite
 """
 
-from ..util import msg, is_int, die
+from ..util import msg, die
 from ..obj import MMGenListItem, ImmutableAttr, ListItemAttr, TwComment, NonNegativeInt
 from ..addr import CoinAddr, MMGenID, MMGenAddrType
 from ..amt import CoinAmtChk
@@ -403,24 +403,12 @@ class TwAddresses(TwView):
 		"""
 
 		def choose_address(addrs):
-
-			def format_line(n, d):
-				return '{a:3}) {b}{c}'.format(
-					a = n,
-					b = d.twmmid.hl(),
-					c = yellow(' <== has a label!') if d.comment else ''
-				)
-
-			prompt = '\nChoose a {desc}:\n\n{items}\n\nEnter a number> '.format(
-				desc = desc,
-				items = '\n'.join(format_line(n, d) for n, d in enumerate(addrs, 1)))
-
-			from ..ui import line_input
-			while True:
-				res = line_input(self.cfg, prompt)
-				if is_int(res) and 0 < int(res) <= len(addrs):
-					return addrs[int(res)-1]
-				msg(f'{res}: invalid entry')
+			def format_addr(d):
+				return '{a}{b}'.format(
+					a = d.twmmid.hl(),
+					b = yellow(' <== has a label!') if d.comment else '')
+			from ..ui import item_chooser
+			return item_chooser(self.cfg, f'Choose a {desc}', addrs, format_addr).item
 
 		def get_addr(mmtype):
 			return [self.get_change_address(

+ 16 - 1
mmgen/ui.py

@@ -14,7 +14,7 @@ ui: Interactive user interface functions for the MMGen suite
 
 import sys, os
 
-from .util import msg, msg_r, Msg, die
+from .util import msg, msg_r, Msg, die, is_int
 
 def confirm_or_raise(cfg, message, action, *, expect='YES', exit_msg='Exiting at user request'):
 	if message:
@@ -117,6 +117,21 @@ def keypress_confirm(
 			case _:
 				msg_r('\nInvalid reply\n' if verbose else '\r')
 
+def item_chooser(cfg, hdr, items, item_formatter, indent='  '):
+	from collections import namedtuple
+	col1_w = len(str(len(items)))
+	prompt = '{i}{a}:\n{i}{b}\n{i}{c}'.format(
+		a = hdr,
+		b = ('\n' + indent).join(f'  {n:{col1_w}}) {item_formatter(d)}' for n, d in enumerate(items, 1)),
+		c = 'Enter a number> ',
+		i = indent)
+	while True:
+		res = line_input(cfg, prompt)
+		if is_int(res) and 0 < int(res) <= len(items):
+			num = int(res)
+			return namedtuple('user_choice', 'num idx item')(num, num - 1, items[num - 1])
+		msg(f'{indent}{res}: invalid entry\n')
+
 def do_pager(text):
 
 	pagers = ['less', 'more']