diff --git a/BOARD.txt b/BOARD.txt index ee9f168..24b615c 100644 --- a/BOARD.txt +++ b/BOARD.txt @@ -12,6 +12,7 @@ TODO DONE view/edit sources downloads configuration + help page open last download actual TOFU home page diff --git a/README.md b/README.md index 2e3ea75..1610de6 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ Python's standard library. [asn1crypto]: https://github.com/wbond/asn1crypto +### Nice keybinds + +A lot of keybinds are defined. Find them in the help page by pressing `?`. + ### Fun Link navigation is done by entering the link ID with automatic validation: if diff --git a/bebop/browser/browser.py b/bebop/browser/browser.py index 54b9133..5c3a6ab 100644 --- a/bebop/browser/browser.py +++ b/bebop/browser/browser.py @@ -13,6 +13,7 @@ from bebop.bookmarks import ( from bebop.colors import ColorPair, init_colors from bebop.command_line import CommandLine from bebop.external import open_external_program +from bebop.help import HELP_PAGE from bebop.history import History from bebop.links import Links from bebop.mouse import ButtonState @@ -23,7 +24,26 @@ from bebop.page_pad import PagePad class Browser: - """Manage the events, inputs and rendering.""" + """Manage the events, inputs and rendering. + + Attributes: + - config: config dict passed to the browser. + - stash: certificate stash passed to the browser. + - screen: curses stdscr. + - dim: current screen dimensions. + - page_pad: curses pad containing the current page view. + - status_line: curses window used to report current status. + - command_line: a CommandLine object for the user to interact with. + - running: the browser will continue running while this is true. + - status_data: 3-uple of status text, color pair and attributes of the + status line, used to reset status after an error. + - history: an History object. + - cache: a dict containing cached pages + - special_pages: a dict containing page names used with "bebop" scheme; + values are dicts as well: the "open" key maps to a callable to use when + the page is accessed, and the optional "source" key maps to callable + returning the page source path. + """ def __init__(self, config, cert_stash): self.config = config @@ -37,6 +57,7 @@ class Browser: self.status_data = ("", 0, 0) self.history = History() self.cache = {} + self.special_pages = self.setup_special_pages() self._current_url = "" @property @@ -58,6 +79,18 @@ class Browser: self._current_url = url self.set_status(url) + def setup_special_pages(self): + """Return a dict with the special pages functions.""" + return { + "bookmarks": { + "open": self.open_bookmarks, + "source": lambda: str(get_bookmarks_path()) + }, + "help": { + "open": self.open_help, + }, + } + def run(self, *args, **kwargs): """Use curses' wrapper around _run.""" os.environ.setdefault("ESCDELAY", "25") @@ -99,7 +132,9 @@ class Browser: def handle_inputs(self): char = self.screen.getch() - if char == ord(":"): + if char == ord("?"): + self.open_help() + elif char == ord(":"): self.quick_command("") elif char == ord("r"): self.reload_page() @@ -287,8 +322,11 @@ class Browser: from bebop.browser.file import open_file open_file(self, parts.path, history=history) elif parts.scheme == "bebop": - if parts.netloc == "bookmarks": - self.open_bookmarks() + special_page = self.special_pages.get(parts.netloc) + if special_page: + special_page["open"]() + else: + self.set_status_error("Unknown page.") else: self.set_status_error(f"Protocol {parts.scheme} not supported.") @@ -458,11 +496,13 @@ class Browser: directly from their location on disk. """ delete_source_after = False - special_pages = { - "bebop://bookmarks": str(get_bookmarks_path()) - } - if self.current_url in special_pages: - source_filename = special_pages[self.current_url] + if self.current_url.startswith("bebop://"): + page_name = self.current_url[len("bebop://"):] + special_pages_functions = self.special_pages.get(page_name) + if not special_pages_functions: + return + get_source = special_pages_functions.get("source") + source_filename = get_source() if get_source else None else: if not self.page_pad.current_page: return @@ -472,8 +512,16 @@ class Browser: source_filename = source_file.name delete_source_after = True + if not source_filename: + return + command = self.config["source_editor"] + [source_filename] open_external_program(command) if delete_source_after: os.unlink(source_filename) self.refresh_windows() + + def open_help(self): + """Show the help page.""" + self.load_page(Page.from_gemtext(HELP_PAGE, self.config["text_width"])) + self.current_url = "bebop://help" diff --git a/bebop/help.py b/bebop/help.py new file mode 100644 index 0000000..d172e54 --- /dev/null +++ b/bebop/help.py @@ -0,0 +1,38 @@ +"""Help page. Currently only keybinds are shown as help.""" + +HELP_PAGE = """\ +# Bebop keybinds + +Keybinds using the SHIFT key are written uppercase. Keybinds using the ALT (or \ +META) key are written using the "M-" prefix. Symbol keys are written as their \ +name, not the symbol itself. + +``` list of bebop keybinds +- colon: focus the command-line +- r: reload page +- h: scroll left a bit +- j: scroll down a bit +- k: scroll up a bit +- l: scroll right a bit +- H: scroll left a whole page +- J: scroll down a whole page +- K: scroll up a whole page +- L: scroll right a whole page +- M-h: scroll one column left +- M-j: scroll one line down +- M-k: scroll one line up +- M-l: scroll one column right +- circumflex: horizontally scroll back to the first column +- gg: go to the top of the page +- G: go to the bottom of the page +- o: open an URL +- p: go to the previous page +- u: go to the parent page (up a level in URL) +- U: go to the root page (root URL for the current domain) +- b: open bookmarks +- B: add current page to bookmarks +- e: open the current page source in an editor +- digits: go to the corresponding link ID +- escape: reset status line text +``` +"""