From 2b072bcc768331c0e863b15553a99f5926de7355 Mon Sep 17 00:00:00 2001 From: dece Date: Sat, 15 May 2021 19:06:44 +0200 Subject: [PATCH] navigation: abandon assume_absolute URL madness --- bebop/browser/browser.py | 35 +++++++++++++++++++++------------- bebop/browser/gemini.py | 4 ++-- bebop/navigation.py | 28 +++------------------------ bebop/tests/test_navigation.py | 6 ------ 4 files changed, 27 insertions(+), 46 deletions(-) diff --git a/bebop/browser/browser.py b/bebop/browser/browser.py index 696d04e..c5c162f 100644 --- a/bebop/browser/browser.py +++ b/bebop/browser/browser.py @@ -150,7 +150,9 @@ class Browser: ) if start_url: - self.open_url(start_url, assume_absolute=True) + self.open_url(start_url) + else: + self.open_home() while self.running: try: @@ -309,7 +311,7 @@ class Browser: self.running = False return if command in ("o", "open"): - self.open_url(words[1], assume_absolute=True) + self.open_url(words[1]) elif command == "forget-certificate": from bebop.browser.gemini import forget_certificate forget_certificate(self, words[1]) @@ -323,8 +325,8 @@ class Browser: result = result.strip() return result - def open_url(self, url, base_url=None, redirects=0, assume_absolute=False, - history=True, use_cache=False): + def open_url(self, url, base_url=None, redirects=0, history=True, + use_cache=False): """Try to open an URL. This function assumes that the URL can be from an user and thus tries a @@ -338,7 +340,6 @@ class Browser: - url: an URL string, may not be completely compliant. - base_url: an URL string to use as base in case `url` is relative. - redirections: number of redirections we did yet for the same request. - - assume_absolute: assume we intended to use an absolute URL if True. - history: whether the URL should be pushed to history on success. - use_cache: whether we should look for an already cached document. """ @@ -347,10 +348,7 @@ class Browser: return current_scheme = self.current_scheme or "gemini" - if assume_absolute or not self.current_url: - parts = parse_url(url, absolute=True, default_scheme=current_scheme) - else: - parts = parse_url(url, default_scheme=current_scheme) + parts = parse_url(url, default_scheme=current_scheme) # If there is a no netloc part, try to join the URL. if ( @@ -358,10 +356,20 @@ class Browser: and parts["scheme"] == current_scheme and parts["scheme"] not in NO_NETLOC_SCHEMES ): - base_url = base_url or self.current_url + url_is_usable = False + # Join from either a given base URL, e.g. redirections or following + # a relative link. If there is no such reference URL, try to guess + # what the user meant to do. if base_url: parts = parse_url(join_url(base_url, url)) - else: + url_is_usable = True + elif parts["scheme"] and parts["path"]: + guessed_url = parts["scheme"] + "://" + parts["path"] + if self.prompt(f"Did you mean '{guessed_url}'?", "yn") == "y": + parts = parse_url(guessed_url) + url_is_usable = True + # If nothing could be done, just give up. + if not url_is_usable: self.set_status_error(f"Can't open '{url}'.") return @@ -429,7 +437,7 @@ class Browser: if not link_id in links: self.set_status_error(f"Unknown link ID {link_id}.") return - self.open_url(links[link_id]) + self.open_url(links[link_id], base_url=self.current_url) def handle_mouse(self, mouse_id: int, x: int, y: int, z: int, bstate: int): """Handle mouse events. @@ -608,7 +616,8 @@ class Browser: def prompt(self, text, keys): """Display the text and allow it to type one of the given keys.""" - self.set_status(text) + choice = "/".join(keys) + self.set_status(f"{text} [{choice}]") return self.command_line.prompt_key(keys) def open_history(self): diff --git a/bebop/browser/gemini.py b/bebop/browser/gemini.py index 27fed6b..7122198 100644 --- a/bebop/browser/gemini.py +++ b/bebop/browser/gemini.py @@ -330,7 +330,7 @@ def create_identity(browser: Browser, url: str): Returns: The created identity on success (already registered in identities """ - key = browser.prompt("Create client certificate? [y/n]", "yn") + key = browser.prompt("Create client certificate?", "yn") if key != "y": browser.reset_status() return None @@ -357,7 +357,7 @@ def create_identity(browser: Browser, url: str): def forget_certificate(browser: Browser, hostname: str): """Remove the fingerprint associated to this hostname for the cert stash.""" - key = browser.prompt(f"Remove fingerprint for {hostname}? [y/n]", "yn") + key = browser.prompt(f"Remove fingerprint for {hostname}?", "yn") if key != "y": browser.reset_status() return diff --git a/bebop/navigation.py b/bebop/navigation.py index 6428748..dcaa8c3 100644 --- a/bebop/navigation.py +++ b/bebop/navigation.py @@ -31,11 +31,7 @@ class InvalidUrlException(Exception): self.url = url -def parse_url( - url: str, - absolute: bool =False, - default_scheme: Optional[str] =None -) -> Dict[str, Any]: +def parse_url(url: str, default_scheme: Optional[str] =None) -> Dict[str, Any]: """Return URL parts from this URL. Use the RFC regex to get parts from URL. This function can be used on @@ -44,15 +40,8 @@ def parse_url( Arguments: - url: URL to parse. - - absolute: assume the URL is absolute, e.g. in the case we are trying to - parse an URL an user has written, which is most of the time an absolute - URL even if not perfectly so. This only has an effect if, after the - initial parsing, there is no netloc available and if there is no scheme - that is known to not have a netloc (i.e. the dummy "bebop" scheme). - default_scheme: specify the scheme to use if the URL either does not - specify it and we need it (e.g. there is a location), or `absolute` is - true; if absolute is true but `default_scheme` is not specified, a netloc - marker ("//") is prefixed without scheme. + specify it and we need it (e.g. there is a location). Returns: URL parts, as a dictionary with the following keys: "scheme", "netloc", @@ -72,18 +61,7 @@ def parse_url( for k in ("scheme", "netloc", "path", "query", "fragment") } - # Smol hack: if we assume it's an absolute URL and no netloc has been found, - # just prefix default scheme (if any) and "//". - if ( - absolute - and not parts["netloc"] - and parts["scheme"] not in NO_NETLOC_SCHEMES - ): - scheme = parts["scheme"] or default_scheme - prefix = scheme + "://" if scheme else "//" - return parse_url(prefix + url) - - # Another smol hack: if there is no scheme, use `default_scheme` as default. + # Smol hack: if there is no scheme, use `default_scheme` as default. if default_scheme and parts["scheme"] is None: parts["scheme"] = default_scheme diff --git a/bebop/tests/test_navigation.py b/bebop/tests/test_navigation.py index 3965d58..00880de 100644 --- a/bebop/tests/test_navigation.py +++ b/bebop/tests/test_navigation.py @@ -33,12 +33,6 @@ class TestNavigation(unittest.TestCase): self.assertIsNone(res["netloc"]) self.assertEqual(res["path"], "dece.space/parse-me.gmi") - # No scheme nor netloc but we should pretend having an absolute URL. - res = parse_url("dece.space/parse-me.gmi", absolute=True) - self.assertIsNone(res["scheme"]) - self.assertEqual(res["netloc"], "dece.space") - self.assertEqual(res["path"], "/parse-me.gmi") - # HTTPS scheme. res = parse_url("https://dece.space/index.html") self.assertEqual(res["scheme"], "https")