Compare commits
No commits in common. "84764644df64aee8d7d107c87b9f89df8bbf8b42" and "62619f29fb2175cb258480c218e42cdf6d3af696" have entirely different histories.
84764644df
...
62619f29fb
45
README.md
45
README.md
|
@ -1,45 +0,0 @@
|
||||||
Bebop
|
|
||||||
=====
|
|
||||||
|
|
||||||
Bebop is a [Gemini][gemini] browser for the terminal, focusing on practicality
|
|
||||||
and speed. It is a personal project to learn how to use ncurses and try new
|
|
||||||
ways to explore the Geminispace. It borrows some ideas from [Amfora][amfora],
|
|
||||||
another great terminal browser, Vim for interactivity and tries to support mouse
|
|
||||||
usage decently.
|
|
||||||
|
|
||||||
[gemini]: https://gemini.circumlunar.space/
|
|
||||||
[amfora]: https://github.com/makeworld-the-better-one/amfora
|
|
||||||
|
|
||||||
If you are interested in Gemini and looking for a client, I recommend trying a
|
|
||||||
graphical one like the excellent [Lagrange][lagrange] or [Kristall][kristall],
|
|
||||||
or Amfora if you're feeling more at home in the terminal. Bebop won't attempt
|
|
||||||
to support every feature other clients might have.
|
|
||||||
|
|
||||||
[lagrange]: https://git.skyjake.fi/skyjake/lagrange
|
|
||||||
[kristall]: https://kristall.random-projects.net/
|
|
||||||
|
|
||||||
It passes the Conman's client test but not Egsam's for now.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Features
|
|
||||||
--------
|
|
||||||
|
|
||||||
### What works
|
|
||||||
|
|
||||||
- Basic browsing: scrolling, follow links, redirections, Web links.
|
|
||||||
|
|
||||||
### What is planned
|
|
||||||
|
|
||||||
- Handle more content types.
|
|
||||||
- Great config options.
|
|
||||||
- Identity management with temporary and managed certificates.
|
|
||||||
- Buffers (or tabs if you prefer).
|
|
||||||
- Home page.
|
|
||||||
- Bookmarks.
|
|
||||||
|
|
||||||
### What is not planned for now
|
|
||||||
|
|
||||||
- 256-colors mode and themes.
|
|
||||||
- Subscriptions. I have no need for them as I prefer to use a browser-agnostic
|
|
||||||
aggregator at the moment.
|
|
|
@ -222,11 +222,7 @@ class Browser:
|
||||||
else:
|
else:
|
||||||
pass # TODO
|
pass # TODO
|
||||||
|
|
||||||
data = req.proceed()
|
response = Response.parse(req.proceed())
|
||||||
if not data:
|
|
||||||
self.set_status_error(f"Server did not respond in time ({url}).")
|
|
||||||
return
|
|
||||||
response = Response.parse(data)
|
|
||||||
if not response:
|
if not response:
|
||||||
self.set_status_error(f"Server response parsing failed ({url}).")
|
self.set_status_error(f"Server response parsing failed ({url}).")
|
||||||
return
|
return
|
||||||
|
|
|
@ -81,7 +81,7 @@ class Request:
|
||||||
self.payload += LINE_TERM
|
self.payload += LINE_TERM
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sock = socket.create_connection((hostname, port), timeout=10)
|
sock = socket.create_connection((hostname, port))
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
self.state = Request.STATE_CONNECTION_FAILED
|
self.state = Request.STATE_CONNECTION_FAILED
|
||||||
self.error = exc.strerror
|
self.error = exc.strerror
|
||||||
|
@ -124,10 +124,7 @@ class Request:
|
||||||
self.ssock.sendall(self.payload)
|
self.ssock.sendall(self.payload)
|
||||||
response = b""
|
response = b""
|
||||||
while True:
|
while True:
|
||||||
try:
|
buf = self.ssock.recv(4096)
|
||||||
buf = self.ssock.recv(4096)
|
|
||||||
except socket.timeout:
|
|
||||||
buf = None
|
|
||||||
if not buf:
|
if not buf:
|
||||||
return response
|
return response
|
||||||
response += buf
|
response += buf
|
||||||
|
@ -175,7 +172,6 @@ class Response:
|
||||||
content: bytes = b""
|
content: bytes = b""
|
||||||
|
|
||||||
HEADER_RE = re.compile(r"(\d{2}) (.*)")
|
HEADER_RE = re.compile(r"(\d{2}) (.*)")
|
||||||
MAX_META_LEN = 1024
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def generic_code(self):
|
def generic_code(self):
|
||||||
|
@ -193,8 +189,6 @@ class Response:
|
||||||
if not match:
|
if not match:
|
||||||
return None
|
return None
|
||||||
code, meta = match.groups()
|
code, meta = match.groups()
|
||||||
if len(meta) > Response.MAX_META_LEN:
|
|
||||||
return None
|
|
||||||
response = Response(StatusCode(int(code)), meta=meta)
|
response = Response(StatusCode(int(code)), meta=meta)
|
||||||
if response.generic_code == StatusCode.SUCCESS:
|
if response.generic_code == StatusCode.SUCCESS:
|
||||||
content_offset = response_header_len + len(LINE_TERM)
|
content_offset = response_header_len + len(LINE_TERM)
|
||||||
|
|
|
@ -215,13 +215,10 @@ def render_lines(metalines, window, max_width):
|
||||||
- max_width: line length limit for the pad.
|
- max_width: line length limit for the pad.
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
The tuple of integers (error, height, width), error being a non-zero value
|
The tuple (height, width) of the resized window.
|
||||||
if an error occured during rendering, and height and width being the new
|
|
||||||
dimensions of the resized window.
|
|
||||||
"""
|
"""
|
||||||
num_lines = len(metalines)
|
num_lines = len(metalines)
|
||||||
new_dimensions = num_lines, max_width
|
window.resize(num_lines, max_width)
|
||||||
window.resize(*new_dimensions)
|
|
||||||
for line_index, metaline in enumerate(metalines):
|
for line_index, metaline in enumerate(metalines):
|
||||||
meta, line = metaline
|
meta, line = metaline
|
||||||
line = line[:max_width - 1]
|
line = line[:max_width - 1]
|
||||||
|
@ -240,10 +237,7 @@ def render_lines(metalines, window, max_width):
|
||||||
attr = curses.color_pair(ColorPair.BLOCKQUOTE) | curses.A_ITALIC
|
attr = curses.color_pair(ColorPair.BLOCKQUOTE) | curses.A_ITALIC
|
||||||
else: # includes LineType.PARAGRAPH
|
else: # includes LineType.PARAGRAPH
|
||||||
attr = curses.color_pair(ColorPair.NORMAL)
|
attr = curses.color_pair(ColorPair.NORMAL)
|
||||||
try:
|
window.addstr(line, attr)
|
||||||
window.addstr(line, attr)
|
|
||||||
except ValueError:
|
|
||||||
return new_dimensions
|
|
||||||
if line_index < num_lines - 1:
|
if line_index < num_lines - 1:
|
||||||
window.addstr("\n")
|
window.addstr("\n")
|
||||||
return new_dimensions
|
return num_lines, max_width
|
||||||
|
|
Reference in a new issue