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 br
# if no tag is specified but a '{- text}' is present, then the 'p' tag is placed # 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 Check Dalet too
This is one paragraph This is one paragraph
} }
{- This is another paragraph ({- text\}) } {-
This is another paragraph ({- text\})
}
row "center" [ row "center" [
link "https://github.com/txtdot/txtdot": Homepage link "https://github.com/txtdot/txtdot": Homepage

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,41 @@
mod commands; 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()
}),
};
}
}
}