screen: handle input request (code 10)
This commit is contained in:
parent
5ef9a0430a
commit
b23e4a8d6a
|
@ -1,7 +1,7 @@
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
|
|
||||||
def parse_url(url, absolute=False):
|
def parse_url(url: str, absolute: bool =False):
|
||||||
"""Return URL parts from this URL.
|
"""Return URL parts from this URL.
|
||||||
|
|
||||||
This uses urllib.parse.urlparse to not reinvent the wheel, with a few
|
This uses urllib.parse.urlparse to not reinvent the wheel, with a few
|
||||||
|
@ -25,14 +25,22 @@ def parse_url(url, absolute=False):
|
||||||
return parts
|
return parts
|
||||||
|
|
||||||
|
|
||||||
def sanitize_url(url):
|
def sanitize_url(url: str):
|
||||||
"""Parse and unparse an URL to ensure it has been properly formatted."""
|
"""Parse and unparse an URL to ensure it has been properly formatted."""
|
||||||
return urllib.parse.urlunparse(parse_url(url))
|
return urllib.parse.urlunparse(parse_url(url))
|
||||||
|
|
||||||
|
|
||||||
def join_url(base_url, url):
|
def join_url(base_url: str, url: str):
|
||||||
"""Join a base URL with a relative url."""
|
"""Join a base URL with a relative url."""
|
||||||
if base_url.startswith("gemini://"):
|
if base_url.startswith("gemini://"):
|
||||||
base_url = base_url[7:]
|
base_url = base_url[7:]
|
||||||
parts = parse_url(urllib.parse.urljoin(base_url, url))
|
parts = parse_url(urllib.parse.urljoin(base_url, url))
|
||||||
return urllib.parse.urlunparse(parts)
|
return urllib.parse.urlunparse(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def set_parameter(url: str, user_input: str):
|
||||||
|
"""Return a new URL with the user input escaped (RFC 3986) appended."""
|
||||||
|
quoted_input = urllib.parse.quote(user_input)
|
||||||
|
if "?" in url:
|
||||||
|
url = url.rsplit("?", maxsplit=1)[0]
|
||||||
|
return url + "?" + quoted_input
|
||||||
|
|
|
@ -7,7 +7,7 @@ from bebop.colors import ColorPair, init_colors
|
||||||
from bebop.command_line import (CommandLine, EscapeCommandInterrupt,
|
from bebop.command_line import (CommandLine, EscapeCommandInterrupt,
|
||||||
TerminateCommandInterrupt)
|
TerminateCommandInterrupt)
|
||||||
from bebop.mouse import ButtonState
|
from bebop.mouse import ButtonState
|
||||||
from bebop.navigation import join_url, parse_url, sanitize_url
|
from bebop.navigation import join_url, parse_url, sanitize_url, set_parameter
|
||||||
from bebop.page import Page
|
from bebop.page import Page
|
||||||
from bebop.protocol import Request, Response
|
from bebop.protocol import Request, Response
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ class Screen:
|
||||||
if char == ord("q"):
|
if char == ord("q"):
|
||||||
running = False
|
running = False
|
||||||
elif char == ord(":"):
|
elif char == ord(":"):
|
||||||
command = self.input_common_command()
|
command = self.take_user_input()
|
||||||
self.set_status(f"Command: {command}")
|
self.set_status(f"Command: {command}")
|
||||||
elif char == ord("s"):
|
elif char == ord("s"):
|
||||||
self.set_status(f"h {self.h} w {self.w}")
|
self.set_status(f"h {self.h} w {self.w}")
|
||||||
|
@ -203,6 +203,8 @@ class Screen:
|
||||||
elif response.generic_code in (40, 50):
|
elif response.generic_code in (40, 50):
|
||||||
error = f"Server error: {response.meta or Response.code.name}."
|
error = f"Server error: {response.meta or Response.code.name}."
|
||||||
self.set_status_error(error)
|
self.set_status_error(error)
|
||||||
|
elif response.generic_code == 10:
|
||||||
|
self.handle_input_request(url, response)
|
||||||
|
|
||||||
def load_page(self, gemtext: bytes):
|
def load_page(self, gemtext: bytes):
|
||||||
"""Load Gemtext data as the current page."""
|
"""Load Gemtext data as the current page."""
|
||||||
|
@ -215,9 +217,9 @@ class Screen:
|
||||||
else:
|
else:
|
||||||
self.refresh_page()
|
self.refresh_page()
|
||||||
|
|
||||||
def input_common_command(self):
|
def take_user_input(self, type_char: str =":"):
|
||||||
"""Focus command line to type a regular command. Currently useless."""
|
"""Focus command line to let the user type something"""
|
||||||
return self.command_line.focus(":", self.validate_common_char)
|
return self.command_line.focus(type_char, self.validate_common_char)
|
||||||
|
|
||||||
def validate_common_char(self, ch: int):
|
def validate_common_char(self, ch: int):
|
||||||
"""Generic input validator, handles a few more cases than default.
|
"""Generic input validator, handles a few more cases than default.
|
||||||
|
@ -321,6 +323,16 @@ class Screen:
|
||||||
return
|
return
|
||||||
self.open_url(links[link_id])
|
self.open_url(links[link_id])
|
||||||
|
|
||||||
|
def handle_input_request(self, from_url: str, response: Response):
|
||||||
|
if response.meta:
|
||||||
|
self.set_status(f"Input needed: {response.meta}")
|
||||||
|
else:
|
||||||
|
self.set_status("Input needed:")
|
||||||
|
user_input = self.take_user_input("?")
|
||||||
|
if user_input:
|
||||||
|
url = set_parameter(from_url, user_input)
|
||||||
|
self.open_gemini_url(url)
|
||||||
|
|
||||||
def handle_mouse(self, mouse_id: int, x: int, y: int, z: int, bstate: int):
|
def handle_mouse(self, mouse_id: int, x: int, y: int, z: int, bstate: int):
|
||||||
"""Handle mouse events.
|
"""Handle mouse events.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from ..navigation import join_url, parse_url
|
from ..navigation import join_url, parse_url, set_parameter
|
||||||
|
|
||||||
|
|
||||||
class TestNavigation(unittest.TestCase):
|
class TestNavigation(unittest.TestCase):
|
||||||
|
@ -28,3 +28,9 @@ class TestNavigation(unittest.TestCase):
|
||||||
self.assertEqual(url, "gemini://dece.space/dir1/other-file.gmi")
|
self.assertEqual(url, "gemini://dece.space/dir1/other-file.gmi")
|
||||||
url = join_url("gemini://dece.space/dir1/file.gmi", "../top-level.gmi")
|
url = join_url("gemini://dece.space/dir1/file.gmi", "../top-level.gmi")
|
||||||
self.assertEqual(url, "gemini://dece.space/top-level.gmi")
|
self.assertEqual(url, "gemini://dece.space/top-level.gmi")
|
||||||
|
|
||||||
|
def test_set_parameter(self):
|
||||||
|
url = set_parameter("gemini://gus.guru/search", "my search")
|
||||||
|
self.assertEqual(url, "gemini://gus.guru/search?my%20search")
|
||||||
|
url = set_parameter("gemini://gus.guru/search?old%20search", "new")
|
||||||
|
self.assertEqual(url, "gemini://gus.guru/search?new")
|
||||||
|
|
Reference in a new issue