aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--Cargo.toml4
-rw-r--r--rust-toolchain.toml2
-rw-r--r--src/app.rs58
-rw-r--r--src/input.rs2
-rw-r--r--src/main.rs1
-rw-r--r--src/ui.rs124
7 files changed, 168 insertions, 27 deletions
diff --git a/.gitignore b/.gitignore
index 1de0ed8..15e547a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,7 @@ Cargo.lock
# CLion
.idea
+
+# Visual Studio Code
+.vscode
+
diff --git a/Cargo.toml b/Cargo.toml
index a6e119b..b52a89c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
[package]
name = "sydney"
-version = "0.1.7"
+version = "0.1.8"
authors = ["Fuwn <[email protected]>"]
edition = "2021"
description = "Vim-like, Command-line Gemini Client"
@@ -19,7 +19,7 @@ codegen-units = 1
opt-level = 3
[dependencies]
-germ = { version = "0.3.3", default-features = false, features = ["request", "ast"] } # Gemini
+germ = { version = "0.3.7", default-features = false, features = ["request", "ast"] } # Gemini
url = "2.2.2" # URL
tui = "0.18.0" # Terminal User Interface
crossterm = "0.24.0" # Cross-platform Terminal
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 60883f4..3aa68ad 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,2 +1,2 @@
[toolchain]
-channel = "1.59.0"
+channel = "nightly-2022-07-23"
diff --git a/src/app.rs b/src/app.rs
index 6e3b7fd..6094f9a 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -18,13 +18,13 @@
use std::time::{Duration, Instant};
use crossterm::event;
-use germ::request::Status;
+use germ::{ast::Node, request::Status};
use url::Url;
use crate::{input::Mode as InputMode, stateful_list::StatefulList};
pub struct App {
- pub items: StatefulList<(Vec<String>, Option<String>)>,
+ pub items: StatefulList<(Vec<Node>, Option<String>, bool)>,
pub input: String,
pub input_mode: InputMode,
pub command_stroke_history: Vec<event::KeyCode>,
@@ -72,7 +72,7 @@ impl App {
pub fn make_request(&mut self) {
self.items = StatefulList::with_items({
- let mut items = vec![];
+ let mut items: Vec<(Vec<Node>, Option<String>, bool)> = vec![];
match germ::request::request(&self.url) {
Ok(mut response) => {
@@ -111,30 +111,50 @@ impl App {
items = self.items.items.clone();
}
- items.push((vec![response.meta().to_string()], None));
- items.push((vec!["".to_string()], None));
+ // items.push((
+ // vec![Node::Text(response.meta().to_string())],
+ // None,
+ // false,
+ // ));
+ // items.push((vec![Node::Text("".to_string())], None, false));
+
+ let mut pre = false;
if let Some(content) = response.content().clone() {
- for line in content.lines().clone() {
+ let real_lines = content.lines();
+
+ for line in real_lines {
let line = line.replace('\t', " ");
- let mut parts = line.split_whitespace();
- let lines = if line.is_empty() {
- vec![line.to_string()]
+ let pre_like = if line.starts_with("```") {
+ pre = !pre;
+
+ true
} else {
- line
- .as_bytes()
- .chunks(self.wrap_at as usize)
- .map(|buf| {
- #[allow(unsafe_code)]
- unsafe { std::str::from_utf8_unchecked(buf) }.to_string()
- })
- .collect::<Vec<_>>()
+ false
};
+ let ast = germ::ast::Ast::from_string(&line);
+ let ast_node = ast.inner().first().map_or_else(
+ || {
+ if pre_like || pre {
+ if line == "```" {
+ Node::Text("sydney_abc_123".to_string())
+ } else {
+ Node::Text(line.get(3..).unwrap_or("").to_string())
+ }
+ } else {
+ Node::Whitespace
+ }
+ },
+ Clone::clone,
+ );
+
+ let mut parts = line.split_whitespace();
+
if let (Some("=>"), Some(to)) = (parts.next(), parts.next()) {
- items.push((lines, Some(to.to_string())));
+ items.push((vec![ast_node], Some(to.to_string()), false));
} else {
- items.push((lines, None));
+ items.push((vec![ast_node], None, pre));
}
}
} else if response.status() != &Status::Input
diff --git a/src/input.rs b/src/input.rs
index 3a44018..1fac12a 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -20,7 +20,7 @@ use url::Url;
use crate::command::Command;
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
pub enum Mode {
Normal,
Editing,
diff --git a/src/main.rs b/src/main.rs
index ab628f8..060ca08 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,6 +26,7 @@
clippy::nursery,
clippy::pedantic
)]
+#![feature(iter_advance_by)]
#![recursion_limit = "128"]
mod app;
diff --git a/src/ui.rs b/src/ui.rs
index 188d311..8e6ff6c 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -15,13 +15,16 @@
// Copyright (C) 2022-2022 Fuwn <[email protected]>
// SPDX-License-Identifier: GPL-3.0-only
+use germ::ast::Node;
use tui::{
layout::{Constraint, Direction, Layout, Rect},
- style::{Color, Style},
+ style::{Color, Modifier, Style},
+ text::{Span, Spans},
widgets,
widgets::{ListItem, Paragraph},
};
+#[allow(clippy::too_many_lines)]
pub fn ui<B: tui::backend::Backend>(
f: &mut tui::Frame<'_, B>,
app: &mut crate::App,
@@ -42,11 +45,119 @@ pub fn ui<B: tui::backend::Backend>(
.items
.items
.iter()
- .map(|(text_lines, _link)| {
+ .map(|(text_lines, _link, pre)| {
let mut spans = vec![];
for line in text_lines {
- spans.push(tui::text::Spans::from(line.as_str()));
+ let mut line = line.clone();
+
+ if *pre {
+ if let Node::Text(text) = line {
+ line = Node::PreformattedText {
+ alt_text: None,
+ text: text.to_string(),
+ }
+ }
+ }
+
+ match line {
+ germ::ast::Node::Text(text) =>
+ if text != "sydney_abc_123" {
+ spans.push(tui::text::Spans::from(format!(" {}", text)));
+ },
+ germ::ast::Node::Blockquote(text) => {
+ spans.push(Spans::from(vec![
+ Span::styled(" > ", Style::default().fg(Color::LightBlue)),
+ Span::styled(
+ text,
+ Style::default().add_modifier(Modifier::ITALIC),
+ ),
+ ]));
+ }
+ germ::ast::Node::Link {
+ to,
+ text,
+ } => {
+ let mut span_list =
+ vec![Span::styled(" => ", Style::default().fg(Color::LightBlue))];
+
+ span_list.push(Span::styled(
+ text.unwrap_or_else(|| to.clone()),
+ Style::default().add_modifier(Modifier::UNDERLINED),
+ ));
+ span_list.push(Span::from(" "));
+ span_list
+ .push(Span::styled(to, Style::default().fg(Color::LightBlue)));
+
+ spans.push(Spans::from(span_list));
+ }
+ germ::ast::Node::Heading {
+ text,
+ level,
+ } => {
+ spans.push(Spans::from(vec![
+ Span::styled(
+ match level {
+ 1 => " # ",
+ 2 => " ## ",
+ 3 => "### ",
+ _ => unreachable!(),
+ },
+ Style::default().fg(Color::LightBlue),
+ ),
+ Span::styled(text, {
+ let mut style = Style::default().add_modifier(Modifier::BOLD);
+
+ match level {
+ 1 => {
+ style = style.add_modifier(Modifier::UNDERLINED);
+ }
+ 3 => {
+ style = style.add_modifier(Modifier::ITALIC);
+ }
+ _ => {}
+ }
+
+ style
+ }),
+ ]));
+ }
+ germ::ast::Node::List(list_items) => {
+ let mut span_list = vec![];
+
+ for list_item in list_items {
+ span_list.push(Span::styled(
+ " * ",
+ Style::default().fg(Color::LightBlue),
+ ));
+ span_list.push(Span::from(format!("{}\n", list_item)));
+ }
+
+ spans.push(Spans::from(span_list));
+ }
+ germ::ast::Node::PreformattedText {
+ text,
+ alt_text,
+ } => {
+ let mut span_list = vec![];
+
+ span_list.push(Span::styled(
+ "``` ",
+ Style::default().fg(Color::LightBlue),
+ ));
+ span_list
+ .push(Span::from(alt_text.unwrap_or_else(|| "".to_string())));
+
+ if text != "sydney_abc_123" {
+ span_list.push(Span::from(text));
+ }
+
+ spans.push(Spans::from(span_list));
+ }
+ germ::ast::Node::Whitespace => {
+ spans.push(Spans::from("".to_string()));
+ }
+ };
}
ListItem::new(spans)
@@ -54,7 +165,12 @@ pub fn ui<B: tui::backend::Backend>(
.collect();
let items = widgets::List::new(items)
- .highlight_style(Style::default().bg(Color::White).fg(Color::Black))
+ .highlight_style(
+ Style::default()
+ .bg(Color::White)
+ .fg(Color::Black)
+ .remove_modifier(Modifier::BOLD),
+ )
.style(Style::default().bg(Color::Black).fg(Color::White));
f.render_stateful_widget(items, chunks[0], &mut app.items.state);