aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordesvox <ofunknowndescent@gmail.com>2018-07-27 17:28:34 -0500
committerdesvox <ofunknowndescent@gmail.com>2018-07-27 17:28:34 -0500
commit22b4a5d5a51a511d885625d9ab09fe199f2f9946 (patch)
tree1ef4570ae2144087e7627f4d21d0add17edfb120
parent4177c6080c3d7c88af7466f8caef1b211267af2e (diff)
downloadbbj-22b4a5d5a51a511d885625d9ab09fe199f2f9946.tar.gz
Add basic search support (needs a little work, btw HI MODS)
-rw-r--r--clients/urwid/main.py132
-rw-r--r--todo.org1
2 files changed, 104 insertions, 29 deletions
diff --git a/clients/urwid/main.py b/clients/urwid/main.py
index fad9b9a..e1e7b96 100644
--- a/clients/urwid/main.py
+++ b/clients/urwid/main.py
@@ -268,6 +268,12 @@ class App(object):
self.usermap = {}
self.window_split = False
self.last_pos = None
+ self.last_alarm = None
+ self.match_data = {
+ "query": "",
+ "matches": [],
+ "position": 0,
+ }
# these can be changed and manipulated by other methods
self.walker = urwid.SimpleFocusListWalker([])
@@ -732,16 +738,91 @@ class App(object):
pass
+ def search_index_callback(self, query):
+ simple_query = query.lower().strip()
+ threads, usermap = network.thread_index()
+ self.usermap.update(usermap)
+ results = [
+ thread for thread in threads
+ if simple_query in thread["title"].lower().strip()
+ ]
+ if results:
+ self.index(threads=results)
+ if query:
+ self.set_header("Searching for '{}'", query)
+ else:
+ self.temp_footer_message("No results for '{}'".format(query))
+
+
+ def search_thread_callback(self, query):
+ # TODO: Not that!!
+ # fetch the thread again because we need all the messages without formatting
+ thread, _ = network.thread_load(self.thread["thread_id"])
+ query = query.lower().strip()
+ self.match_data["matches"] = [
+ message for message in thread["messages"]
+ if query in message["body"].lower().strip()
+ ]
+ if self.match_data["matches"]:
+ self.match_data["query"] = query
+ self.match_data["position"] = -1
+ # self.highlight_query()
+ self.do_search_result()
+ else:
+ self.temp_footer_message("No results for '{}'".format(query))
+
+
+ def do_search_result(self, forward=True):
+ self.match_data["position"] += 1 if forward else -1
+ length = len(self.match_data["matches"])
+ if forward:
+ if self.match_data["position"] == length:
+ self.match_data["position"] = 0
+ else:
+ if self.match_data["position"] == -1:
+ self.match_data["position"] = length - 1
+ self.goto_post(self.match_data["matches"][self.match_data["position"]]["post_id"])
+ self.temp_footer_message(
+ "({}/{}) Searching for {} [#]Next [@]Previous".format(
+ self.match_data["position"] + 1, length, self.match_data["query"]
+ ), 5)
+
+
+ # XXX: Try to find a way to overlay properties onto an existing widget instead of this trainwreck.
+ # def highlight_query(self):
+ # # pass
+ # query = self.match_data["query"]
+ # for match in self.match_data["matches"]:
+ # widget = self.walker[match["post_id"] * 5 + 2].base_widget
+ # # (">>OP\n\nThat's a nice initiative x)", [('50', 4), (None, 2), ('default', 27)])
+ # text, attrs = widget.get_text()
+ # spans = [m.span() for m in re.finditer(query, text)]
+ # start, end = spans.pop(0)
+ # new_attrs = []
+ # index = 0
+ # for prop, length in attrs:
+ # if index and index > start:
+ # index = end
+ # new_attrs.append(("20", end - start))
+ # start, end = spans.pop(0)
+ # else:
+ # index += length
+ # new_attrs.append((prop, length))
+
+
def search_prompt(self):
- # XXX: remove if when thread search is supported
- if self.mode != "index":
+ if self.mode == "index":
+ callback = self.search_index_callback
+ elif self.mode == "thread":
+ callback = self.search_thread_callback
+ else:
return
popup = OptionsMenu(
urwid.ListBox(
urwid.SimpleFocusListWalker([
urwid.Text(("button", "Enter a query:")),
- urwid.AttrMap(StringPrompt(self.search_callback), "opt_prompt"),
+ urwid.AttrMap(StringPrompt(callback), "opt_prompt"),
urwid.Text("Use a blank query to reset the {}.".format(self.mode))
])),
**frame_theme())
@@ -753,24 +834,6 @@ class App(object):
width=("relative", 40), height=6)
- def search_callback(self, query):
- threads, usermap = network.thread_index()
- self.usermap.update(usermap)
- if self.mode == "index":
- results = [
- thread for thread in threads
- if query in thread["title"].lower().strip().replace(" ", "")
- ]
- if results:
- self.index(threads=results)
- if query:
- self.set_header("Searching for '{}'", query)
- else:
- self.temp_footer_message("No results for '{}'".format(query))
- elif self.mode == "thread":
- pass
-
-
def thread_load(self, button, thread_id):
"""
Open a thread.
@@ -786,6 +849,7 @@ class App(object):
thread, usermap = network.thread_load(thread_id, format="sequential")
self.usermap.update(usermap)
self.thread = thread
+ self.match_data["matches"].clear()
self.walker.clear()
for message in thread["messages"]:
self.walker += self.make_message_body(message)
@@ -1347,19 +1411,20 @@ class App(object):
self.loop.widget.focus_position = "footer"
- def reset_footer(self, _, from_temp):
- if from_temp and self.window_split:
+ def reset_footer(self, *_):
+ if self.window_split:
return
- try:
- self.set_default_footer(True)
- self.loop.widget.focus_position = "body"
- except:
+ self.set_default_footer()
+ # try:
+ # self.loop.widget.focus_position = "body"
+ # except:
# just keep trying until the focus widget can handle it
- self.loop.set_alarm_in(0.5, self.reset_footer)
+ # return self.loop.set_alarm_in(0.25, self.reset_footer)
def temp_footer_message(self, string, duration=3):
- self.loop.set_alarm_in(duration, self.reset_footer, True)
+ self.loop.remove_alarm(self.last_alarm)
+ self.last_alarm = self.loop.set_alarm_in(duration, self.reset_footer)
self.set_footer(string)
@@ -1939,6 +2004,12 @@ class ActionBox(urwid.ListBox):
elif keyl in ("r", "f5") and not overlay:
app.refresh()
+ elif key == "#":
+ app.do_search_result(True)
+
+ elif key == "@":
+ app.do_search_result(False)
+
elif key == "~":
# sssssshhhhhhhh
app.loop.stop()
@@ -1946,6 +2017,9 @@ class ActionBox(urwid.ListBox):
except: pass
app.loop.start()
+ elif keyl == "f12":
+ app.loop.stop()
+
elif app.mode == "thread" and not app.window_split and not overlay:
message = app.thread["messages"][app.get_focus_post()]
diff --git a/todo.org b/todo.org
index edd4231..98790d2 100644
--- a/todo.org
+++ b/todo.org
@@ -5,3 +5,4 @@ when given a certain time (kind of like `message_feed`)
* TODO Author-only "announcement" threads
* TODO HTML output from the formatter
* TODO integrate thread pins to urwid client
+* TODO add search highlights to in-thread searching
Un proyecto texto-plano.xyz