aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMykyta Holubakha <hilobakho@gmail.com>2017-08-16 09:48:38 +0300
committerMykyta Holubakha <hilobakho@gmail.com>2017-08-16 09:48:38 +0300
commit94b54c1ceec4dab37021589c642f39854f7226cc (patch)
treec3183642b415a075984a327224263c31c63213e0
parentRemote fetching (diff)
downloadpomu-94b54c1ceec4dab37021589c642f39854f7226cc.tar.gz
pomu-94b54c1ceec4dab37021589c642f39854f7226cc.tar.bz2
pomu-94b54c1ceec4dab37021589c642f39854f7226cc.zip
Generalized iquery (Prompt class)
separated prompt with editable values and simple picker moved bugz backend to EditSelectPrompt
-rw-r--r--pomu/source/bugz.py4
-rw-r--r--pomu/util/iquery.py153
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 == '<UP>':
+ self.idx = self.clamp(self.idx - 1)
+ elif event == '<DOWN>':
+ self.idx = self.clamp(self.idx + 1)
+ elif event == '<SPACE>':
+ self.toggle()
+ elif event in {'p', 'P'}:
+ self.preview()
+ elif event in {'<ESC>', '<Ctrl-g>'}:
+ 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 == '<UP>':
- self.idx = self.clamp(self.idx - 1)
- elif event == '<DOWN>':
- self.idx = self.clamp(self.idx + 1)
- elif event == '<SPACE>':
- self.toggle()
- elif event in {'p', 'P'}:
- self.preview()
- elif event in {'<ESC>', '<Ctrl-g>'}:
+ res = super.process_event(event)
+ if res == -1:
return -1
+ elif res:
+ return True
elif event in {'e', '<Ctrl-j>', '<Ctrl-m>'}:
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 {'<ESC>', '<Ctrl-g>'}:
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]