aboutsummaryrefslogtreecommitdiff
path: root/pomu
diff options
context:
space:
mode:
Diffstat (limited to 'pomu')
-rw-r--r--pomu/cli.py9
-rw-r--r--pomu/data/zugaina.py11
-rw-r--r--pomu/search.py130
-rw-r--r--pomu/util/iquery.py14
4 files changed, 153 insertions, 11 deletions
diff --git a/pomu/cli.py b/pomu/cli.py
index 13a9738..8de900f 100644
--- a/pomu/cli.py
+++ b/pomu/cli.py
@@ -146,6 +146,15 @@ def show(package):
print('Backend:', pkg.backend.__name__)
print('Backend detailes:', pkg.backend)
+@main.command()
+@click.argument('query', required=True)
+@click.option('--fetch-only', default=False, is_flag=True)
+def search(query):
+ """Search gpo.zugaina.org"""
+ ds = ZugainaDataSource(query)
+ p = PSPrompt(ds)
+ packages = p.run()
+
def main_():
try:
main.main(standalone_mode=False)
diff --git a/pomu/data/zugaina.py b/pomu/data/zugaina.py
index 25437fc..6f67444 100644
--- a/pomu/data/zugaina.py
+++ b/pomu/data/zugaina.py
@@ -23,13 +23,13 @@ class ZugainaDataSource(DataSource):
text = self.fetch_page(1)
doc = lxml.html.document_fromstring(text)
field = doc.xpath('//div[@class="pager"]/span')[0].text
- self.pagecount = (field.split(' ')[-1] + 49) // 50
+ self.pagecount = (int(field.split(' ')[-1]) + 49) // 50
return self.pagecount
def get_page(self, page):
text = self.fetch_page(page)
doc = lxml.html.document_fromstring(text)
- return [(strip(x.text), x.getchildren()[0].text)
+ return [(x.text.strip(), x.getchildren()[0].text)
for x in doc.xpath('//div[@id="search_results"]/a/div')]
def list_items(self, ident):
@@ -38,12 +38,13 @@ class ZugainaDataSource(DataSource):
res = []
for div in doc.xpath('//div[@id="ebuild_list"]/ul/div'):
id_ = div.xpath('li/a')[0].get('href').split('/')[3]
- pv = div.xpath('li/div/b').text
+ pv = div.xpath('li/div/b')[0].text
overlay = div.xpath('@id')
- res.append(id_, pv, overlay)
+ res.append((id_, pv, overlay))
+ return res
def get_item(self, ident):
- return results.get(BASE_URL + 'AJAX/Ebuild/' + ident).text
+ return requests.get(BASE_URL + 'AJAX/Ebuild/' + str(ident)).text
def fetch_item(self, ident):
if ident in self.itemcache:
diff --git a/pomu/search.py b/pomu/search.py
new file mode 100644
index 0000000..6f0a2b0
--- /dev/null
+++ b/pomu/search.py
@@ -0,0 +1,130 @@
+from enum import Enum
+from pydoc import pager
+
+from curtsies import FullscreenWindow, width, invert, fmtstr
+
+from pomu.util.iquery import Prompt, clamp
+
+class Entry:
+ def __init__(self, item, source, children=None):
+ self.expanded = False
+ self._source = source
+ self.item = item
+ self.children = children
+
+ def toggle(self, idx):
+ if idx == 0:
+ self.expanded = not self.expanded
+ else:
+ child = self.children[idx - 1]
+ self.children[idx - 1] = (not child[0], child[1])
+ if self.expanded and not self.children:
+ self.children = [(False, x) for x in self._source.list_items(self.item[0])]
+
+ def get_idx(self, idx):
+ return ((self, None if idx == 0 or not self.children else self.children[idx-1]))
+
+ def __len__(self):
+ return len(self.children) + 1 if self.expanded else 1
+
+ def selected(self):
+ return [child for child in self.children if child[0]]
+
+class PromptState(Enum):
+ TOP_PREV=0
+ TOP_OK=1
+ LIST=2
+
+class PSPrompt(Prompt):
+ def __init__(self, source):
+ super().__init__([])
+ self.data = source
+ self.page_count = self.data.page_count()
+ self.pages = {}
+ self.state = PromptState.LIST
+ self.set_page(1)
+
+ def set_page(self, page):
+ self.idx = 0
+ self.page = page
+ if page in self.pages:
+ self.entries = self.pages[page]
+ else:
+ self.entries = [self.process_entry(x) for x in self.data.get_page(page)]
+ self.pages[page] = self.entries
+
+ def render(self):
+ title = str(self.page)
+ if self.page > 1:
+ title = ('[ ' +
+ (invert('Prev') if self.state == 0 else ('Prev')) +
+ ' ] ' + title)
+ if self.page < self.page_count:
+ title = (title + ' [ ' +
+ (invert('Next') if self.state == 1 else ('Next')) +
+ ' ]')
+ title = center(title)
+ bottom = ('[ ' + invert('OK') if self.idx == len(self) else 'OK' + ' ]')
+ bottom = center(bottom)
+ items = [render_entry(e, idx) for idx, e in enumerate(self.lens())]
+ output = fsarray([title] + items + [bottom])
+ self.window.render_to_terminal(output)
+
+ def render_entry(self, entry, idx):
+ winw = self.window.width
+ if entry[1]:
+ hld, data = *entry[1]
+ stt = '*' if hld else ' '
+ text = ' [' + invert(stt) if idx == 0 else stt + '] '
+ text += '{}::{}'.format(data[1], data[2])
+ else if entry[0]:
+ data = entry[0]
+ exp = 'v' if entry.expanded else '>'
+ text = '[' + invert(exp) if idx == 0 else exp + '] '
+ text += data[0] + ' '
+ strw = fmtstr(text).width
+ insw = fmtstr(data[1]).width
+ text += data[1][:winw - strw - 2] + '..' if insw + strw > winw else data[1]
+ else:
+ text = ''
+ return text
+
+
+ def __len__(self):
+ return sum(lun(y) for y in self.entries)
+
+ def center(self, stri):
+ tw = fmtstr(stri).width
+ pw = (self.window.width - tw) // 2
+ return ' ' * pw + stri + ' ' * pw
+
+ def clamp(self, x):
+ return clamp(x, 0, len(self))
+
+ def preview(self):
+ target = self.get_target()
+ if target[1]:
+ data = self.data.get_item(target[1][0])
+ pager(data)
+
+ def lens(self):
+ h = self.window.height - 2
+ lst = [self.get_idx(i) for i in range(self.idx, self.clamp(self.idx + h))]
+ lst += [(None, None)] * clamp(h - len(lst), 0, h)
+ return lst
+
+ def get_target(self):
+ return get_idx(self.idx)
+
+ def get_idx(self, idx):
+ for entry in self.entries():
+ if len(entry) > idx:
+ break
+ idx -= len(entry)
+ return entry.get_idx(idx)
+
+ def process_entry(self, entry):
+ return Entry(item, self.data)
+
+ def run(self):
+ return super().run(FullscreenWindow, hide_cursor=True)
diff --git a/pomu/util/iquery.py b/pomu/util/iquery.py
index f5ca50c..606d79d 100644
--- a/pomu/util/iquery.py
+++ b/pomu/util/iquery.py
@@ -32,14 +32,15 @@ class Prompt:
self.idx = 0
self.cursor_pos = Position()
- def run(self):
+ def run(self, window_type=CursorAwareWindow, **args):
with open('/dev/tty', 'r') as tty_in, \
open('/dev/tty', 'w') as tty_out, \
Input(in_stream=tty_in) as input_, \
- CursorAwareWindow(in_stream=tty_in,
- out_stream=tty_out,
- hide_cursor=False,
- extra_bytes_callback=input_.unget_bytes) as window:
+ window_type(in_stream=tty_in,
+ out_stream=tty_out,
+ hide_cursor=False,
+ extra_bytes_callback=input_.unget_bytes,
+ **args) as window:
self.window = window
self.render()
for event in input_:
@@ -163,7 +164,8 @@ class EditSelectPrompt(Prompt):
self.list = True
elif isinstance(event, str) and not event.startswith('<'):
self.add_char(event)
- else:
+ else,
+ **args:
return False
return True