feat: format cli command, fix format trim

This commit is contained in:
Artemy Egorov 2024-08-11 16:26:34 +03:00
parent 68cd970a1f
commit 6338097658
6 changed files with 114 additions and 60 deletions

View file

@ -40,13 +40,15 @@ This is element
br
# if no tag is specified but a '{- text}' is present, then the 'p' tag is placed
# '\n' is deleted in this format. If a break line is needed in a paragraph, use ' \n'.
# '\n' is replaced with ' ' in this format.
{-
Check Dalet too
This is one paragraph
}
{- This is another paragraph ({- text\}) }
{-
This is another paragraph ({- text\})
}
row "center" [
link "https://github.com/txtdot/txtdot": Homepage

View file

@ -1,8 +1,10 @@
use std::path::PathBuf;
use clap::{Parser, Subcommand};
#[derive(Debug, Parser)]
#[command(name = "cimengine", bin_name = "cimengine")]
#[command(about = "CIMEngine build tools")]
#[command(name = "dalet", bin_name = "dalet")]
#[command(about = "dalet cli")]
pub struct Cli {
#[command(subcommand)]
pub cmd: Commands,
@ -10,4 +12,7 @@ pub struct Cli {
#[derive(Debug, Subcommand)]
#[clap(author, version, about)]
pub enum Commands {}
pub enum Commands {
/// Format file
Format { path: PathBuf },
}

View file

@ -1,6 +1,6 @@
use super::{
lexer::types::{Spanned, Token},
utils::set_indent,
utils::{prepend_indent, set_indent},
};
fn additional_str<'src>(
@ -83,72 +83,72 @@ pub fn format<'src>(spanned_tokens: &Vec<Spanned<Token<'src>>>) -> String {
}
Token::RSquare => {
current_indent -= 1;
format!("{}\n", set_indent("]", current_indent))
format!("{}\n", prepend_indent("]", current_indent))
}
Token::NumberArgument(n) => format!("{n}"),
Token::TextArgument(t) => format!(" \"{t}\""),
Token::TextBody(t) => format!(": {}\n", t.trim()),
Token::TextBody(t) => format!(": {}\n", t),
Token::MLText(t) => format!(
" {{\n{}\n{}\n",
set_indent(t, current_indent + 1),
set_indent("}", current_indent)
prepend_indent("}", current_indent)
),
Token::MLMSText(n, t) => format!(
" {{~{n}\n{}\n{}\n",
set_indent(t, current_indent + 1),
set_indent("}", current_indent)
prepend_indent("}", current_indent)
),
Token::RMLText(t) => format!(" {{#{t}}}\n"),
Token::Comment(c) => format!("{}\n", set_indent(&format!("#{c}"), current_indent)),
Token::Comment(c) => format!("{}\n", prepend_indent(&format!("#{c}"), current_indent)),
Token::TextTag(t) => format!("{}\n", set_indent(t, current_indent)),
Token::TextTag(t) => format!("{}\n", prepend_indent(t, current_indent)),
Token::El => set_indent("el", current_indent),
Token::H => set_indent("h", current_indent),
Token::P => set_indent("p", current_indent),
Token::Br => set_indent("br", current_indent),
Token::Ul => set_indent("ul", current_indent),
Token::Ol => set_indent("ol", current_indent),
Token::Row => set_indent("row", current_indent),
Token::Link => set_indent("link", current_indent),
Token::Navlink => set_indent("navlink", current_indent),
Token::Btn => set_indent("btn", current_indent),
Token::Navbtn => set_indent("navbtn", current_indent),
Token::Img => set_indent("img", current_indent),
Token::Table => set_indent("table", current_indent),
Token::Tcol => set_indent("tcol", current_indent),
Token::Tpcol => set_indent("tpcol", current_indent),
Token::Hr => set_indent("hr", current_indent),
Token::B => set_indent("b", current_indent),
Token::I => set_indent("i", current_indent),
Token::Bq => set_indent("bq", current_indent),
Token::Footlnk => set_indent("footlnk", current_indent),
Token::Footn => set_indent("footn", current_indent),
Token::A => set_indent("a", current_indent),
Token::S => set_indent("s", current_indent),
Token::Sup => set_indent("sup", current_indent),
Token::Sub => set_indent("sub", current_indent),
Token::Disc => set_indent("disc", current_indent),
Token::Block => set_indent("block", current_indent),
Token::Carousel => set_indent("carousel", current_indent),
Token::Code => set_indent("code", current_indent),
Token::Pre => set_indent("pre", current_indent),
Token::Meta => set_indent("meta", current_indent),
Token::El => prepend_indent("el", current_indent),
Token::H => prepend_indent("h", current_indent),
Token::P => prepend_indent("p", current_indent),
Token::Br => prepend_indent("br", current_indent),
Token::Ul => prepend_indent("ul", current_indent),
Token::Ol => prepend_indent("ol", current_indent),
Token::Row => prepend_indent("row", current_indent),
Token::Link => prepend_indent("link", current_indent),
Token::Navlink => prepend_indent("navlink", current_indent),
Token::Btn => prepend_indent("btn", current_indent),
Token::Navbtn => prepend_indent("navbtn", current_indent),
Token::Img => prepend_indent("img", current_indent),
Token::Table => prepend_indent("table", current_indent),
Token::Tcol => prepend_indent("tcol", current_indent),
Token::Tpcol => prepend_indent("tpcol", current_indent),
Token::Hr => prepend_indent("hr", current_indent),
Token::B => prepend_indent("b", current_indent),
Token::I => prepend_indent("i", current_indent),
Token::Bq => prepend_indent("bq", current_indent),
Token::Footlnk => prepend_indent("footlnk", current_indent),
Token::Footn => prepend_indent("footn", current_indent),
Token::A => prepend_indent("a", current_indent),
Token::S => prepend_indent("s", current_indent),
Token::Sup => prepend_indent("sup", current_indent),
Token::Sub => prepend_indent("sub", current_indent),
Token::Disc => prepend_indent("disc", current_indent),
Token::Block => prepend_indent("block", current_indent),
Token::Carousel => prepend_indent("carousel", current_indent),
Token::Code => prepend_indent("code", current_indent),
Token::Pre => prepend_indent("pre", current_indent),
Token::Meta => prepend_indent("meta", current_indent),
Token::ElOpen => {
let s = set_indent("[[", current_indent);
let s = prepend_indent("[[", current_indent);
current_indent += 1;
format!("{s}\n")
}
Token::ElClose => {
current_indent -= 1;
format!("{}\n", set_indent("]]", current_indent))
format!("{}\n", prepend_indent("]]", current_indent))
}
Token::Paragraph(t) => format!(
"{{-\n{}\n{}\n",
set_indent(t, current_indent + 1),
set_indent("}", current_indent)
prepend_indent("}", current_indent)
),
Token::EmptyLine => "\n".to_owned(),

View file

@ -75,7 +75,10 @@ pub fn lexer<'src>(
.ignore_then(just('}'))
.labelled("Multi-line escape sequence");
let text = none_of("\n").repeated().to_slice();
let text = none_of("\n")
.repeated()
.to_slice()
.padded_by(text::inline_whitespace());
let text_body = just(':')
.ignore_then(text)
@ -90,18 +93,17 @@ pub fn lexer<'src>(
let multiline_text_body = none_of("}\\")
.or(escape)
.repeated()
.to_slice()
.labelled("Body of multiline text");
let paragraph = multiline_text_body
.clone()
.to_slice()
.delimited_by(just("{-"), just("}"))
.map(Token::Paragraph)
.labelled("Paragraph syntax");
let mltext = multiline_text_body
.clone()
.to_slice()
.delimited_by(just('{'), just('}'))
.map(Token::MLText)
.labelled("Multiline text");
@ -112,14 +114,13 @@ pub fn lexer<'src>(
.labelled("Minimum spaces number");
mlms_n
.then(multiline_text_body.clone().to_slice())
.then(multiline_text_body.clone())
.then_ignore(just("}"))
.map(|(n, t)| Token::MLMSText(n, t))
.labelled("Multi line text with min spaces")
};
let rmltext = multiline_text_body
.to_slice()
.delimited_by(just("{#"), just('}'))
.map(Token::RMLText)
.labelled("Raw multiline text");

View file

@ -1,5 +1,5 @@
pub fn trim_indent(input: &str) -> String {
let lines: Vec<&str> = input.lines().collect();
let lines: Vec<&str> = trim_unused(input).lines().collect();
// Find the minimum indentation of non-empty lines
let min_indent = lines
@ -21,28 +21,36 @@ pub fn trim_indent(input: &str) -> String {
})
.collect();
trim_newline(&trimmed_lines.join("\n")).to_owned()
trimmed_lines.join("\n")
}
pub fn set_indent(input: &str, indent: usize) -> String {
prepend_indent(&trim_indent(input), &" ".repeat(indent))
prepend_indent(&trim_indent(input), indent)
}
fn trim_newline<'a>(s: &'a str) -> &'a str {
fn trim_unused<'a>(s: &'a str) -> &'a str {
let mut trim_start = 0;
let mut been_newlines = false;
for start_char in s.chars() {
if start_char != '\n' && start_char != '\r' {
if !been_newlines
&& (char::is_whitespace(start_char) && start_char != '\n' && start_char != '\r')
{
trim_start += 1;
continue;
} else if start_char != '\n' && start_char != '\r' {
break;
} else {
been_newlines = true;
trim_start += 1;
}
trim_start += 1;
}
&s[(trim_start)..].trim_end()
}
fn prepend_indent(input: &str, indent: &str) -> String {
pub fn prepend_indent(input: &str, indent: usize) -> String {
let indent = &" ".repeat(indent);
let lines: Vec<String> = input
.lines()
.map(|line| format!("{}{}", indent, line))

View file

@ -1,3 +1,41 @@
mod commands;
fn main() {}
use ariadne::{Color, Label, Report, ReportKind, Source};
use chumsky::Parser;
use clap::Parser as ClapParser;
use commands::{Cli, Commands::*};
use dalet::daleth::{format::format, lexer::lexer};
use std::fs;
fn main() {
let args = Cli::parse();
match args.cmd {
// TODO: add parser check before format
Format { path } => {
let src_file = &path.to_string_lossy().to_string();
let src = fs::read_to_string(src_file).unwrap();
let parsed = lexer().parse(&src);
match parsed.into_result() {
Ok(t) => {
fs::write(path, format(&t)).unwrap();
}
Err(e) => e.into_iter().for_each(|e| {
Report::build(ReportKind::Error, src_file, e.span().start)
.with_code("Compiler")
.with_message(e.to_string().clone())
.with_label(
Label::new((src_file, e.span().into_range()))
.with_message(e.to_string())
.with_color(Color::Red),
)
.finish()
.print((src_file, Source::from(&src)))
.unwrap()
}),
};
}
}
}