browser: add text search
This commit is contained in:
parent
7cb6d03668
commit
bd8d4bbfb1
|
@ -1,6 +1,5 @@
|
||||||
TODO
|
TODO
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
search in page (ugh)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +28,7 @@ remember scroll pos in history
|
||||||
identity management
|
identity management
|
||||||
"previous/next" pages
|
"previous/next" pages
|
||||||
configurable keybinds
|
configurable keybinds
|
||||||
|
handle big files (e.g. gemini://tilde.team/~tomasino/irc/log.txt)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,3 +58,4 @@ different rendering mode
|
||||||
preferences per site
|
preferences per site
|
||||||
basic mouse support
|
basic mouse support
|
||||||
basic local browsing
|
basic local browsing
|
||||||
|
search in page
|
||||||
|
|
|
@ -64,8 +64,12 @@ class Browser:
|
||||||
returning the page source path.
|
returning the page source path.
|
||||||
- last_download: tuple of MimeType and path, or None.
|
- last_download: tuple of MimeType and path, or None.
|
||||||
- identities: identities map.
|
- identities: identities map.
|
||||||
|
- search_res_lines: list of lines containing results of the last search.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
SEARCH_NEXT = 0
|
||||||
|
SEARCH_PREVIOUS = 1
|
||||||
|
|
||||||
def __init__(self, config, cert_stash):
|
def __init__(self, config, cert_stash):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.stash = cert_stash
|
self.stash = cert_stash
|
||||||
|
@ -81,6 +85,7 @@ class Browser:
|
||||||
self.special_pages = self.setup_special_pages()
|
self.special_pages = self.setup_special_pages()
|
||||||
self.last_download: Optional[Tuple[MimeType, Path]] = None
|
self.last_download: Optional[Tuple[MimeType, Path]] = None
|
||||||
self.identities = {}
|
self.identities = {}
|
||||||
|
self.search_res_lines = []
|
||||||
self._current_url = ""
|
self._current_url = ""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -244,6 +249,12 @@ class Browser:
|
||||||
self.open_history()
|
self.open_history()
|
||||||
elif char == ord("§"):
|
elif char == ord("§"):
|
||||||
self.toggle_render_mode()
|
self.toggle_render_mode()
|
||||||
|
elif char == ord("/"):
|
||||||
|
self.search_in_page()
|
||||||
|
elif char == ord("n"):
|
||||||
|
self.move_to_search_result(Browser.SEARCH_NEXT)
|
||||||
|
elif char == ord("N"):
|
||||||
|
self.move_to_search_result(Browser.SEARCH_PREVIOUS)
|
||||||
elif curses.ascii.isdigit(char):
|
elif curses.ascii.isdigit(char):
|
||||||
self.handle_digit_input(char)
|
self.handle_digit_input(char)
|
||||||
elif char == curses.KEY_MOUSE:
|
elif char == curses.KEY_MOUSE:
|
||||||
|
@ -494,9 +505,9 @@ class Browser:
|
||||||
|
|
||||||
If the click is on a link (appropriate line and columns), open it.
|
If the click is on a link (appropriate line and columns), open it.
|
||||||
"""
|
"""
|
||||||
if not self.page_pad or not self.page_pad.current_page:
|
|
||||||
return
|
|
||||||
page = self.page_pad.current_page
|
page = self.page_pad.current_page
|
||||||
|
if not page:
|
||||||
|
return
|
||||||
px, py = self.page_pad.current_column, self.page_pad.current_line
|
px, py = self.page_pad.current_column, self.page_pad.current_line
|
||||||
line_pos = y + py
|
line_pos = y + py
|
||||||
if line_pos >= len(page.metalines):
|
if line_pos >= len(page.metalines):
|
||||||
|
@ -727,13 +738,14 @@ class Browser:
|
||||||
|
|
||||||
def show_page_info(self):
|
def show_page_info(self):
|
||||||
"""Show some page informations in the status bar."""
|
"""Show some page informations in the status bar."""
|
||||||
if not self.page_pad or not self.page_pad.current_page:
|
|
||||||
return
|
|
||||||
page = self.page_pad.current_page
|
page = self.page_pad.current_page
|
||||||
|
if not page:
|
||||||
|
return
|
||||||
mime = page.mime.short if page.mime else "(unknown MIME type)"
|
mime = page.mime.short if page.mime else "(unknown MIME type)"
|
||||||
encoding = page.encoding or "(unknown encoding)"
|
encoding = page.encoding or "(unknown encoding)"
|
||||||
size = f"{len(page.source)} chars"
|
size = f"{len(page.source)} chars"
|
||||||
info = f"{mime} {encoding} {size}"
|
lines = f"{len(page.metalines)} lines"
|
||||||
|
info = f"{mime} {encoding} {size} {lines}"
|
||||||
self.set_status(info)
|
self.set_status(info)
|
||||||
|
|
||||||
def set_render_mode(self, mode):
|
def set_render_mode(self, mode):
|
||||||
|
@ -758,9 +770,9 @@ class Browser:
|
||||||
|
|
||||||
def toggle_render_mode(self):
|
def toggle_render_mode(self):
|
||||||
"""Switch to the next render mode for the current page."""
|
"""Switch to the next render mode for the current page."""
|
||||||
if not self.page_pad or not self.page_pad.current_page:
|
|
||||||
return
|
|
||||||
page = self.page_pad.current_page
|
page = self.page_pad.current_page
|
||||||
|
if not page:
|
||||||
|
return
|
||||||
if page.render is None or page.render not in RENDER_MODES:
|
if page.render is None or page.render not in RENDER_MODES:
|
||||||
next_mode = RENDER_MODES[0]
|
next_mode = RENDER_MODES[0]
|
||||||
else:
|
else:
|
||||||
|
@ -773,3 +785,46 @@ class Browser:
|
||||||
)
|
)
|
||||||
self.load_page(new_page)
|
self.load_page(new_page)
|
||||||
self.set_status(f"Using render mode '{next_mode}'.")
|
self.set_status(f"Using render mode '{next_mode}'.")
|
||||||
|
|
||||||
|
def search_in_page(self):
|
||||||
|
"""Search for words in the page."""
|
||||||
|
page = self.page_pad.current_page
|
||||||
|
if not page:
|
||||||
|
return
|
||||||
|
search = self.get_user_text_input("Search", CommandLine.CHAR_TEXT)
|
||||||
|
if not search:
|
||||||
|
return
|
||||||
|
self.search_res_lines = []
|
||||||
|
for index, (_, line) in enumerate(page.metalines):
|
||||||
|
if search in line:
|
||||||
|
self.search_res_lines.append(index)
|
||||||
|
if self.search_res_lines:
|
||||||
|
self.move_to_search_result(Browser.SEARCH_NEXT)
|
||||||
|
else:
|
||||||
|
self.set_status(f"'{search}' not found.")
|
||||||
|
|
||||||
|
def move_to_search_result(self, prev_or_next: int):
|
||||||
|
"""Move to the next or previous search result."""
|
||||||
|
current_line = self.page_pad.current_line
|
||||||
|
next_line = None
|
||||||
|
index = 1
|
||||||
|
max_index = len(self.search_res_lines)
|
||||||
|
if prev_or_next == Browser.SEARCH_NEXT:
|
||||||
|
for line in self.search_res_lines:
|
||||||
|
if line > current_line:
|
||||||
|
next_line = line
|
||||||
|
break
|
||||||
|
index += 1
|
||||||
|
elif prev_or_next == Browser.SEARCH_PREVIOUS:
|
||||||
|
index = max_index
|
||||||
|
for line in reversed(self.search_res_lines):
|
||||||
|
if line < current_line:
|
||||||
|
next_line = line
|
||||||
|
break
|
||||||
|
index -= 1
|
||||||
|
if next_line is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.set_status(f"Result {index}/{max_index}")
|
||||||
|
self.page_pad.current_line = next_line
|
||||||
|
self.refresh_windows()
|
||||||
|
|
|
@ -38,6 +38,9 @@ Keybinds using the SHIFT key are written uppercase. Keybinds using the ALT (or M
|
||||||
* digits: go to the corresponding link ID
|
* digits: go to the corresponding link ID
|
||||||
* escape: reset status line text
|
* escape: reset status line text
|
||||||
* section sign (§): toggle between render modes for the current page
|
* section sign (§): toggle between render modes for the current page
|
||||||
|
* slash (/): search for some text
|
||||||
|
* n: go to next search result
|
||||||
|
* N: go to previous search result
|
||||||
* C-c: cancel current operation
|
* C-c: cancel current operation
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
|
@ -19,9 +19,8 @@ def render_lines(metalines, window, max_width):
|
||||||
- max_width: line length limit for the pad.
|
- max_width: line length limit for the pad.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The tuple of integers (error, height, width), error being a non-zero value
|
The tuple of integers (height, width), the new dimensions of the resized
|
||||||
if an error occured during rendering, and height and width being the new
|
window.
|
||||||
dimensions of the resized window.
|
|
||||||
"""
|
"""
|
||||||
num_lines = len(metalines)
|
num_lines = len(metalines)
|
||||||
new_dimensions = max(num_lines, 1), max_width
|
new_dimensions = max(num_lines, 1), max_width
|
||||||
|
|
Reference in a new issue