From 94b54c1ceec4dab37021589c642f39854f7226cc Mon Sep 17 00:00:00 2001 From: Mykyta Holubakha Date: Wed, 16 Aug 2017 09:48:38 +0300 Subject: Generalized iquery (Prompt class) separated prompt with editable values and simple picker moved bugz backend to EditSelectPrompt --- pomu/source/bugz.py | 4 +- pomu/util/iquery.py | 153 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 107 insertions(+), 50 deletions(-) diff --git a/pomu/source/bugz.py b/pomu/source/bugz.py index 34d98df..bf528b4 100644 --- a/pomu/source/bugz.py +++ b/pomu/source/bugz.py @@ -8,7 +8,7 @@ from urllib.parse import urlparse from pomu.package import Package from pomu.source import dispatcher -from pomu.util.iquery import Prompt +from pomu.util.iquery import EditSelectPrompt from pomu.util.misc import extract_urls from pomu.util.query import query from pomu.util.result import Result @@ -64,7 +64,7 @@ class BugzillaSource(): items = [(x['file_name'], x['data'].data.decode('utf-8')) for x in attachments] + comment_links if not items: return Result.Err() - p = Prompt(items) + p = EditSelectPrompt(items) files = p.run() if not files: return Result.Err() diff --git a/pomu/util/iquery.py b/pomu/util/iquery.py index 70007f8..eaea254 100644 --- a/pomu/util/iquery.py +++ b/pomu/util/iquery.py @@ -14,30 +14,22 @@ class Position: def clamp(x, m, M): return max(m, min(x, M)) -def render_entry(entry, width, active=False): - # (name, contents, state, value) - char = '*' if entry[2] else ' ' - w = 3 + fmtstr(entry[0]).width + 2 - if entry[3]: - text = fmtstr(entry[3]) - val = entry[3][:width - w - 2] + '..' if text.width < width - w else entry[3] +def render_entry(name, state, value, width, active=False): + char = '*' if state else ' ' + w = 3 + fmtstr(name).width + 2 + if value: + text = fmtstr(value) + val = value[:width - w - 2] + '..' if text.width < width - w else value else: val = '' return fmtstr( '[' + (invert(char) if active else char) + '] ' + - entry[0] + ' ' + val) - -def process_entry(entry): - if isinstance(entry, str): - return (entry[0], None, False, None) - return (entry[0], entry[1], False, entry[0] if entry[0].endswith('.ebuild') else 'files/{}'.format(entry[0])) + name + ' ' + val) class Prompt: def __init__(self, entries): - self.entries = [process_entry(x) for x in entries] + self.entries = [self.process_entry(x) for x in entries] self.idx = 0 - self.text = '' - self.list = True self.cursor_pos = Position() def run(self): @@ -54,23 +46,58 @@ class Prompt: if self.process_event(event) == -1: break self.render() - return [(x[0], x[1], x[3]) for x in self.entries if x[2]] + return self.results() def clamp(self, x): return clamp(x, 0, len(self.entries)) + def results(self): + raise NotImplementedError() + def preview(self): - entry = self.entries[self.idx] - if entry[0] is not None: - pager(entry[1]) + pass + + def extract_ncv(self, entry): + raise NotImplementedError() + + def toggle(self): + raise NotImplementedError() + + def process_entry(x, entry): + raise NotImplementedError() + + def process_event(self, event): + if event == '': + self.idx = self.clamp(self.idx - 1) + elif event == '': + self.idx = self.clamp(self.idx + 1) + elif event == '': + self.toggle() + elif event in {'p', 'P'}: + self.preview() + elif event in {'', ''}: + return -1 else: - gr = grab(entry) - if not gr: - del self.entries[self.idx] - self.idx = self.clamp(self.idx - 1) - pager('Error: could not fetch '.format(entry)) - self.entries[self.idx:self.idx+1] = [process_entry((x[0], x[1].encode('utf-8'))) for x in gr] - pager(self.entries[self.idx][1]) + return False + return True + + def render(self): + output = fsarray( + [render_entry(*self.extract_ncv(), self.window.width, i == self.idx) for i, x in enumerate(self.entries)] + + [' [ ' + + ('OK' if self.idx < len(self.entries) else invert('OK')) + + ' ] '], width=self.window.width) + self.window.render_to_terminal(output) + +class PickerPrompt(Prompt): + def process_entry(self, entry): + return (entry[0], False, entry[1]) + + def extract_ncv(self, entry): + return entry + + def results(self): + return [x[0] for x in self.entries if x[1]] def toggle(self): if self.idx == len(self.entries): @@ -78,23 +105,40 @@ class Prompt: e = self.entries[self.idx] self.entries[self.idx] = (e[0], e[1], not e[2], e[3]) + +class EditSelectPrompt(Prompt): + def __init__(self): + super.init() + self.text = '' + self.list = True + + def render(self): + if self.list: + super.render() + else: + self.cursor_pos.row = 1 + cur = self.entries[self.idx] + output = fsarray(['Please provide value for {}'.format(cur[0]), cur[3]], width=self.window.width) + self.window.render_to_terminal(output, (self.cursor_pos.row, self.cursor_pos.column)) + + def results(self): + return [(x[0], x[1], x[3]) for x in self.entries if x[2]] + def process_event(self, event): if self.list: - if event == '': - self.idx = self.clamp(self.idx - 1) - elif event == '': - self.idx = self.clamp(self.idx + 1) - elif event == '': - self.toggle() - elif event in {'p', 'P'}: - self.preview() - elif event in {'', ''}: + res = super.process_event(event) + if res == -1: return -1 + elif res: + return True elif event in {'e', '', ''}: self.list = False if self.idx == len(self.entries): return -1 self.cursor_pos.column = fmtstr(self.entries[self.idx][3]).width + else: + return False + return True else: if event in {'', ''}: self.list = True @@ -116,20 +160,33 @@ class Prompt: self.list = True elif isinstance(event, str) and not event.startswith('<'): self.add_char(event) + else: + return False + return True - def render(self): - if self.list: - output = fsarray( - [render_entry(x, self.window.width, i == self.idx) for i, x in enumerate(self.entries)] + - [' [ ' + - ('OK' if self.idx < len(self.entries) else invert('OK')) + - ' ] '], width=self.window.width) - self.window.render_to_terminal(output) + def process_entry(self, entry): + if isinstance(entry, str): + return (entry[0], None, False, None) + return (entry[0], entry[1], False, entry[0] if entry[0].endswith('.ebuild') else 'files/{}'.format(entry[0])) + + def preview(self): + entry = self.entries[self.idx] + if entry[0] is not None: + pager(entry[1]) + else: + gr = grab(entry) + if not gr: + del self.entries[self.idx] + self.idx = self.clamp(self.idx - 1) + pager('Error: could not fetch '.format(entry)) + self.entries[self.idx:self.idx+1] = [self.process_entry((x[0], x[1].encode('utf-8'))) for x in gr] + pager(self.entries[self.idx][1]) + + def toggle(self): + if self.idx == len(self.entries): return - self.cursor_pos.row = 1 - cur = self.entries[self.idx] - output = fsarray(['Please provide value for {}'.format(cur[0]), cur[3]], width=self.window.width) - self.window.render_to_terminal(output, (self.cursor_pos.row, self.cursor_pos.column)) + e = self.entries[self.idx] + self.entries[self.idx] = (e[0], e[1], not e[2], e[3]) def add_char(self, char): e = self.entries[self.idx] -- cgit v1.2.3-65-gdbad