Skip to content

Commit

Permalink
Merge branch 'main' into language-selection
Browse files Browse the repository at this point in the history
  • Loading branch information
Builditluc authored Aug 5, 2023
2 parents a7f8350 + 317843b commit 41effae
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 41 deletions.
139 changes: 120 additions & 19 deletions src/ui/article/lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ use std::collections::HashMap;
use std::mem;
use std::rc::Rc;

const DISAMBIGUATION_PADDING: u8 = 1;
const DISAMBIGUATION_PREFIX: char = '|';

const LIST_ITEM_PADDING: u8 = 2;

const DESCRIPTION_LIST_TERM_PADDING: u8 = 2;
const DESCRIPTION_LIST_DESCRIPTION_PADDING: u8 = 4;

/// An element only containing the neccessary information for rendering (and an id so that it can
/// be referenced to an article element
#[derive(Debug)]
Expand Down Expand Up @@ -62,6 +70,12 @@ pub struct LinesWrapper {

/// The ids and positions of the links
pub links: Vec<(usize, Vec2)>,

/// The leading padding for elements in new lines
left_padding: u8,

/// The prefix that is displayed at the start of every line (after the padding)
line_prefix: Option<char>,
}

impl LinesWrapper {
Expand All @@ -81,6 +95,10 @@ impl LinesWrapper {

links: Vec::new(),
anchors: HashMap::new(),

left_padding: 0,

line_prefix: None,
}
}

Expand Down Expand Up @@ -137,14 +155,66 @@ impl LinesWrapper {
// is this a link?
let is_link = matches!(element.kind, ElementType::Link(..));

// does this element go onto a new line?
if element.kind == ElementType::Newline {
// fill the current line and make the next one blank
self.fill_line();
self.newline();
match element.kind {
ElementType::Newline => {
// fill the current line and make the next one blank
self.fill_line();
self.newline();

last_type = &element.kind;
continue;
}

ElementType::DisambiguationStart => {
self.left_padding = self.left_padding.saturating_add(DISAMBIGUATION_PADDING);
self.line_prefix = Some(DISAMBIGUATION_PREFIX);
continue;
}

ElementType::DisambiguationEnd => {
self.left_padding = self.left_padding.saturating_sub(DISAMBIGUATION_PADDING);
self.line_prefix = None;
continue;
}

ElementType::ListItemStart => {
self.left_padding = self.left_padding.saturating_add(LIST_ITEM_PADDING);
continue;
}

ElementType::ListItemEnd => {
self.left_padding = self.left_padding.saturating_sub(LIST_ITEM_PADDING);
continue;
}

ElementType::DescriptionListTermStart => {
self.left_padding = self
.left_padding
.saturating_add(DESCRIPTION_LIST_TERM_PADDING);
continue;
}

ElementType::DescriptionListTermEnd => {
self.left_padding = self
.left_padding
.saturating_sub(DESCRIPTION_LIST_TERM_PADDING);
continue;
}

last_type = &element.kind;
continue;
ElementType::DescriptionListDescriptionStart => {
self.left_padding = self
.left_padding
.saturating_add(DESCRIPTION_LIST_DESCRIPTION_PADDING);
continue;
}

ElementType::DescriptionListDescriptionEnd => {
self.left_padding = self
.left_padding
.saturating_sub(DESCRIPTION_LIST_DESCRIPTION_PADDING);
continue;
}
_ => (),
}

// what we do here is fairly simple:
Expand Down Expand Up @@ -173,7 +243,7 @@ impl LinesWrapper {

for span in element.content().split_whitespace() {
// does the span fit onto the current line?
if span.chars().count() + merged_element.width + self.current_width < self.width {
if self.is_space_valid(span.chars().count() + merged_element.width) {
// only add a leading whitespace if the merged element is not empty
if !merged_element.content.is_empty() {
merged_element.push(' ');
Expand All @@ -188,8 +258,7 @@ impl LinesWrapper {
// - add the merged element to the current line
// - fill the current line and replace it with a new one
// - add the span to a new merged element
self.current_width += merged_element.width;
self.current_line.push(merged_element);
self.push_element(merged_element);

// if its a link, add it
if is_link {
Expand All @@ -212,7 +281,7 @@ impl LinesWrapper {
};

// does the span fit onto the current line?
if span.chars().count() + merged_element.width + self.current_width < self.width {
if self.is_space_valid(span.chars().count() + merged_element.width) {
// only add a leading whitespace if the merged element is not empty
if !merged_element.content.is_empty() {
merged_element.push(' ');
Expand All @@ -227,8 +296,7 @@ impl LinesWrapper {
// if there are still some spans in the merged_element, add it to the current line and
// register a link if it is one
if !merged_element.content.is_empty() {
self.current_width += merged_element.width;
self.current_line.push(merged_element);
self.push_element(merged_element);

if is_link {
self.register_link(element.id());
Expand All @@ -252,25 +320,56 @@ impl LinesWrapper {
self.links
.push((id, Vec2::new(self.current_width, self.rendered_lines.len())))
}

fn is_space_valid(&self, width: usize) -> bool {
let prefix_len: usize = self.line_prefix.map(|_| 1).unwrap_or_default();

width + self.current_width + self.left_padding as usize + prefix_len <= self.width
}

/// Adds an element to the current line and if needed, registers a link to it
fn push_element(&mut self, element: RenderedElement) {
if self.current_width == 0 {
// if this is a new line and we have some padding, apply it
if self.left_padding != 0 {
self.push_n_whitespace(self.left_padding as usize);
}

// if this is a new line and we have a prefix, add it
if let Some(prefix) = self.line_prefix {
assert!(self.current_width + 2 <= self.width);
self.current_line.push(RenderedElement {
id: usize::MAX,
content: format!("{} ", prefix),
style: Style::none(),
width: 2,
})
}
}

self.current_width += element.width;
self.current_line.push(element);
}

/// Adds a whitespacde to the current line
/// Adds a whitespace to the current line
fn push_whitespace(&mut self) {
self.push_n_whitespace(1)
}

/// Adds n amount of whitespace to the current line
fn push_n_whitespace(&mut self, n: usize) {
// check if we can add a whitespace
if self.current_width == self.width {
if self.current_width + n > self.width {
return;
}

// create a rendered element with the id -1 and push it to the current line
self.push_element(RenderedElement {
self.current_width += n;
self.current_line.push(RenderedElement {
id: usize::MAX,
content: " ".to_string(),
content: " ".repeat(n),
style: Style::from(CONFIG.theme.text),
width: 1,
width: n,
});
}

Expand All @@ -286,7 +385,9 @@ impl LinesWrapper {
/// Fills the remaining space of the line with spaces
fn fill_line(&mut self) {
// if our current line is wider than allowed, we really messed up
assert!(self.current_width <= self.width);
if self.current_width > self.width {
return;
}

// change the max width, if neccessary
if self.current_width > self.max_width {
Expand Down
4 changes: 2 additions & 2 deletions src/ui/article/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ fn open_internal_link(siv: &mut Cursive, data: InternalData) {
siv,
"Information",
&format!(
"The link leads to an article in the '{}' namespace which is supported",
"The link leads to an article in the '{}' namespace which is not supported",
data.namespace
),
);
Expand Down Expand Up @@ -125,7 +125,7 @@ fn open_internal_link(siv: &mut Cursive, data: InternalData) {

if let Some(anchor_data) = data.anchor {
display_message(
siv,
siv,
"Information",
&format!("The link has an anchorpoint to '{}'. \nUnfortunately, anchorpoints are not supported yet, meaning the article will open at the top", anchor_data.title)
);
Expand Down
2 changes: 1 addition & 1 deletion src/ui/article/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
use cursive::{
event::{Callback, Event, EventResult, Key, MouseButton, MouseEvent},
view::CannotFocus,
Rect, Vec2, View,
Vec2, View,
};

/// A view displaying an article
Expand Down
11 changes: 11 additions & 0 deletions src/wiki/article.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,18 @@ pub enum ElementType {
Link(Link),
Header,
Unsupported,

ListMarker,
ListItemStart,
ListItemEnd,

DescriptionListTermStart,
DescriptionListTermEnd,
DescriptionListDescriptionStart,
DescriptionListDescriptionEnd,

DisambiguationStart,
DisambiguationEnd,
}

#[derive(Debug, Clone)]
Expand Down
63 changes: 53 additions & 10 deletions src/wiki/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use super::{

const SHOW_UNSUPPORTED: bool = false;
const LIST_MARKER: char = '-';
const DISAMBIGUATION_MARKER: char = '|';

pub struct Parser<'a> {
endpoint: Url,
Expand Down Expand Up @@ -82,6 +81,10 @@ impl<'a> Parser<'a> {
"a" => self.parse_link(node),
"b" => self.parse_effect(node, Effect::Bold),
"i" => self.parse_effect(node, Effect::Italic),
"ul" if node
.attr("class")
.map(|x| x.contains("portalbox"))
.unwrap_or(false) => {}
"ul" => self.parse_list(node),
"div"
if node
Expand All @@ -99,7 +102,16 @@ impl<'a> Parser<'a> {
{
self.parse_redirect_msg(node)
}
"div"
if node
.attr("class")
.map(|x| x.contains("toc") | x.contains("quotebox"))
.unwrap_or(false) => {}
"" => (),
"dl" => self.parse_description_list(node),
"div" => {
node.children().map(|node| self.parse_node(node)).count();
}
_ if SHOW_UNSUPPORTED => {
self.elements.push(Element::new(
self.next_id(),
Expand Down Expand Up @@ -134,6 +146,16 @@ impl<'a> Parser<'a> {
));
}

fn push_kind(&mut self, kind: ElementType) {
self.elements.push(Element::new(
self.next_id(),
kind,
"",
Style::none(),
HashMap::new(),
))
}

fn is_last_newline(&self) -> bool {
self.elements
.last()
Expand Down Expand Up @@ -246,6 +268,29 @@ impl<'a> Parser<'a> {
self.current_effects.pop();
}

fn parse_description_list(&mut self, node: Node) {
for child in node.children() {
if !self.is_last_newline() {
self.push_newline();
}
match child.name().unwrap_or_default() {
"dt" => {
self.push_kind(ElementType::DescriptionListTermStart);
self.parse_text(child);
self.push_kind(ElementType::DescriptionListTermEnd);
}
"dd" => {
self.push_kind(ElementType::DescriptionListDescriptionStart);
self.parse_text(child);
self.push_kind(ElementType::DescriptionListDescriptionEnd);
}
_ => continue,
}
}
self.push_newline();
self.push_newline();
}

fn parse_list(&mut self, node: Node) {
for child in node
.children()
Expand All @@ -264,10 +309,12 @@ impl<'a> Parser<'a> {
self.combine_effects(Style::from(config::CONFIG.theme.text)),
HashMap::new(),
));
self.parse_text(child)

self.push_kind(ElementType::ListItemStart);
self.parse_text(child);
self.push_kind(ElementType::ListItemEnd);
}
self.push_newline();
self.push_newline();
}

fn parse_redirect_msg(&mut self, node: Node) {
Expand All @@ -277,14 +324,10 @@ impl<'a> Parser<'a> {
}

fn parse_disambiguation(&mut self, node: Node) {
self.elements.push(Element::new(
self.next_id(),
ElementType::Text,
DISAMBIGUATION_MARKER.to_string(),
self.combine_effects(Style::from(config::CONFIG.theme.text)),
HashMap::new(),
));
self.push_kind(ElementType::DisambiguationStart);
self.parse_effect(node, Effect::Italic);
self.push_kind(ElementType::DisambiguationEnd);

self.push_newline();
self.push_newline();
}
Expand Down
Loading

0 comments on commit 41effae

Please sign in to comment.