Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add rendering for textbox and hyperlink #119

Merged
merged 4 commits into from
Nov 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions commons/src/lexer/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ impl AddAssign<Option<SpanLen>> for Position {
}
}

impl AddAssign<usize> for Position {
fn add_assign(&mut self, rhs: usize) {
self.col_utf8 += rhs;
self.col_utf16 += rhs;
self.col_grapheme += rhs;
}
}

impl<T> Add<T> for Position
where
Position: AddAssign<T>,
Expand Down Expand Up @@ -122,13 +130,21 @@ impl SubAssign<SpanLen> for Position {
impl SubAssign<Option<SpanLen>> for Position {
fn sub_assign(&mut self, rhs: Option<SpanLen>) {
if let Some(rhs) = rhs {
self.col_utf8 += rhs.len_utf8;
self.col_utf16 += rhs.len_utf16;
self.col_grapheme += rhs.len_grapheme;
self.col_utf8 -= rhs.len_utf8;
self.col_utf16 -= rhs.len_utf16;
self.col_grapheme -= rhs.len_grapheme;
}
}
}

impl SubAssign<usize> for Position {
fn sub_assign(&mut self, rhs: usize) {
self.col_utf8 -= rhs;
self.col_utf16 -= rhs;
self.col_grapheme -= rhs;
}
}

impl<T> Sub<T> for Position
where
Position: SubAssign<T>,
Expand Down
1 change: 1 addition & 0 deletions inline/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ unimarkup-commons = { path = "../commons/", version = "0" }

[dev-dependencies]
unimarkup-commons = { path ="../commons/", version = "0", features = ["test_runner"] }
unimarkup-core = { path = "../core/", version = "0" }
serde.workspace = true
serde_yaml.workspace = true
libtest-mimic = "0.6.1"
10 changes: 5 additions & 5 deletions inline/src/element/formatting/ambiguous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ fn resolve_closing<'slice, 'input>(
close_token.kind,
inner,
None, // check for optional attributes here
open_token.start,
open_token.start + counterpart(close_token.kind).len(), // Because inner token gets closed
close_token.end,
false,
));
Expand Down Expand Up @@ -271,12 +271,12 @@ fn to_inline<'input>(
inner,
None,
inner_token.start,
inner_token.end,
end - outer_token.kind.len(), // Because the outer token is at "end"
implicit_end,
)],
attributes,
outer_token.start,
outer_token.end,
end,
implicit_end,
)
} else {
Expand Down Expand Up @@ -320,7 +320,7 @@ fn main_part(kind: InlineTokenKind) -> InlineTokenKind {
InlineTokenKind::Italic | InlineTokenKind::BoldItalic => InlineTokenKind::Bold,
InlineTokenKind::Underline => kind,
InlineTokenKind::Subscript | InlineTokenKind::UnderlineSubscript => {
InlineTokenKind::Underline
InlineTokenKind::Subscript
}
_ => kind,
}
Expand All @@ -334,7 +334,7 @@ fn sub_part(kind: InlineTokenKind) -> InlineTokenKind {
InlineTokenKind::Bold | InlineTokenKind::BoldItalic => InlineTokenKind::Italic,
InlineTokenKind::Subscript => kind,
InlineTokenKind::Underline | InlineTokenKind::UnderlineSubscript => {
InlineTokenKind::Subscript
InlineTokenKind::Underline
}
_ => kind,
}
Expand Down
19 changes: 17 additions & 2 deletions inline/src/element/formatting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,25 @@ const STRIKETHROUGH_INDEX: usize = 5;
const HIGHLIGHT_INDEX: usize = 6;
const OVERLINE_INDEX: usize = 7;
const QUOTE_INDEX: usize = 8;
pub(crate) const NR_OF_UNSCOPED_FORMATS: usize = 9;
const NR_OF_UNSCOPED_FORMATS: usize = 9;

/// Type used to keep track of open formats that do not open their own scope.
pub(crate) type OpenFormatMap = [bool; NR_OF_UNSCOPED_FORMATS];
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub(crate) struct OpenFormatMap([bool; NR_OF_UNSCOPED_FORMATS]);

impl OpenFormatMap {
pub(crate) fn is_open(&self, index: usize) -> bool {
self.0[index]
}

pub(crate) fn open(&mut self, index: usize) {
self.0[index] = true;
}

pub(crate) fn close(&mut self, index: usize) {
self.0[index] = false;
}
}

/// Returns the index in the open format map for the given unscoped format.
pub(crate) fn map_index(kind: &InlineTokenKind) -> usize {
Expand Down
4 changes: 2 additions & 2 deletions inline/src/element/formatting/scoped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ macro_rules! scoped_parser {
// ignore implicits, because only escapes and logic elements are allowed in following inline verbatim
let prev_context_flags = parser.context.flags;

let mut scoped_parser =
let (mut scoped_parser, outer_open_formats) =
parser.nest_scoped(Some(Rc::new(|matcher: &mut dyn EndMatcher| {
!matcher.prev_is_space()
&& matcher.consumed_matches(&[InlineTokenKind::$kind.into()])
Expand All @@ -41,7 +41,7 @@ macro_rules! scoped_parser {
scoped_parser = updated_parser;

let end_reached = scoped_parser.iter.end_reached();
parser = scoped_parser.unfold();
parser = scoped_parser.unfold(outer_open_formats);
parser.context.flags = prev_context_flags;

let prev_token = parser.iter.prev_token().expect(
Expand Down
21 changes: 12 additions & 9 deletions inline/src/element/textbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,22 @@ pub(crate) fn parse<'slice, 'input>(
open_token.kind
);

let mut scoped_parser = parser.nest_scoped(Some(Rc::new(|matcher: &mut dyn EndMatcher| {
matcher.consumed_matches(&[TokenKind::CloseBracket])
})));
let (mut scoped_parser, outer_open_formats) =
parser.nest_scoped(Some(Rc::new(|matcher: &mut dyn EndMatcher| {
matcher.consumed_matches(&[TokenKind::CloseBracket])
})));

let checkpoint = scoped_parser.iter.checkpoint();
let (updated_parser, box_variant_opt) = parse_box_variant(scoped_parser);
scoped_parser = updated_parser;

match box_variant_opt {
Some(box_variant) => {
return (scoped_parser.unfold(), Some(box_variant));
return (scoped_parser.unfold(outer_open_formats), Some(box_variant));
}
None => {
scoped_parser.iter.rollback(checkpoint);
scoped_parser.iter.next(); // Consume open bracket
}
}

Expand All @@ -104,17 +106,18 @@ pub(crate) fn parse<'slice, 'input>(
.expect("Inlines in textbox => previous token must exist.")
};
let end_reached = scoped_parser.iter.end_reached();
parser = scoped_parser.unfold();
parser = scoped_parser.unfold(outer_open_formats);

// check for `()`
if end_reached && parser.iter.peek_kind() == Some(InlineTokenKind::OpenParenthesis) {
parser
.iter
.next()
.expect("Peeked before, so `next` must return Some."); // Consume open parenthesis
let mut link_parser = parser.nest_scoped(Some(Rc::new(|matcher: &mut dyn EndMatcher| {
matcher.consumed_matches(&[TokenKind::CloseParenthesis])
})));
let (mut link_parser, outer_open_formats) =
parser.nest_scoped(Some(Rc::new(|matcher: &mut dyn EndMatcher| {
matcher.consumed_matches(&[TokenKind::CloseParenthesis])
})));

let link = link_parser
.iter
Expand Down Expand Up @@ -142,7 +145,7 @@ pub(crate) fn parse<'slice, 'input>(
)
};

parser = link_parser.unfold();
parser = link_parser.unfold(outer_open_formats);

return (
parser,
Expand Down
4 changes: 3 additions & 1 deletion inline/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Crate for parsing Unimarkup inline elements.

pub mod element;
pub mod parser;

mod tokenize;

pub mod parser;
pub use tokenize::kind::InlineTokenKind;
38 changes: 15 additions & 23 deletions inline/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use unimarkup_commons::lexer::token::iterator::{IteratorEndFn, IteratorPrefixFn, TokenIterator};

use crate::{
element::Inline,
element::{formatting::OpenFormatMap, Inline},
tokenize::{iterator::InlineTokenIterator, kind::InlineTokenKind},
};

Expand Down Expand Up @@ -32,7 +32,7 @@ pub fn parse_inlines<'slice, 'input>(
end_reached: updated_parser.iter.end_reached(),
prefix_mismatch: updated_parser.iter.prefix_mismatch(),
};
inline_parser = updated_parser.unfold();
inline_parser = updated_parser.unfold(OpenFormatMap::default());

(
inline_parser.iter.into(),
Expand Down Expand Up @@ -99,9 +99,6 @@ impl<'slice, 'input> InlineParser<'slice, 'input> {
let mut inlines = Vec::default();
let mut format_closes = false;

#[cfg(debug_assertions)]
let mut curr_len = parser.iter.max_len();

parser.iter.reset_peek();

'outer: while let Some(kind) = parser.iter.peek_kind() {
Expand Down Expand Up @@ -142,8 +139,8 @@ impl<'slice, 'input> InlineParser<'slice, 'input> {
let success = parser.iter.rollback(checkpoint);
debug_assert!(
success,
"Rollback was not successful for checkpoint '{:?}'",
checkpoint
"Inline rollback was not successful at '{:?}'",
parser.iter.peek()
)
}
}
Expand All @@ -154,15 +151,6 @@ impl<'slice, 'input> InlineParser<'slice, 'input> {

parser = updated_parser;
inlines = updated_inlines;

#[cfg(debug_assertions)]
{
assert!(
parser.iter.max_len() < curr_len,
"Parser consumed no token in iteration."
);
curr_len = parser.iter.max_len();
}
}

if !format_closes {
Expand All @@ -174,15 +162,19 @@ impl<'slice, 'input> InlineParser<'slice, 'input> {
}

/// Create an inline parser that has this parser as parent.
pub fn nest_scoped(mut self, end_match: Option<IteratorEndFn>) -> Self {
self.iter = self.iter.nest_scoped(end_match);
self
/// Returns the nested parser, and the [`OpenFormatMap`] of the outer scope.
/// This [`OpenFormatMap`] must be used when calling `unfold()` to get correct inline formatting.
pub fn nest_scoped(mut self, end_match: Option<IteratorEndFn>) -> (Self, OpenFormatMap) {
let (scoped_iter, outer_open_formats) = self.iter.nest_scoped(end_match);
self.iter = scoped_iter;

(self, outer_open_formats)
}

/// Returns the parent parser if this parser is nested.
/// Otherwise, self is returned unchanged.
pub fn unfold(mut self) -> Self {
self.iter = self.iter.unfold();
/// Overrides the internal [`OpenFormatMap`] with the given one.
pub fn unfold(mut self, outer_open_formats: OpenFormatMap) -> Self {
self.iter = self.iter.unfold(outer_open_formats);
self
}
}
Expand Down Expand Up @@ -230,7 +222,7 @@ mod test {

#[test]
fn dummy_for_debugging() {
let tokens = unimarkup_commons::lexer::token::lex_str("`a`");
let tokens = unimarkup_commons::lexer::token::lex_str("[Simple textbox]");
let mut inline_parser = InlineParser {
iter: InlineTokenIterator::from(TokenIterator::from(&*tokens)),
context: InlineContext::default(),
Expand Down
Loading
Loading