Skip to content

Instantly share code, notes, and snippets.

@bombless
Created March 29, 2023 10:05
Show Gist options
  • Save bombless/3780e177acd24504d75ba78fff3e89ee to your computer and use it in GitHub Desktop.
Save bombless/3780e177acd24504d75ba78fff3e89ee to your computer and use it in GitHub Desktop.
Compile moderncv to typst
#[derive(Debug)]
enum Value {
Plain(String),
Section(String),
CvEntry(Vec<String>),
CvItem(Vec<String>),
}
fn parse(input: &str) {
use std::mem::replace;
let mut quoting_buffer = String::new();
let mut quoting_depth = 0;
let mut stream = Vec::new();
let mut context = String::new();
let mut blocks = Vec::new();
let mut commenting = false;
let mut in_bracket = false;
for c in input.chars() {
if c == '%' {
commenting = true;
}
else if commenting && c != '\n' {
continue;
}
else if c == ']' {
in_bracket = false;
}
else if c == '[' {
in_bracket = true;
}
else if in_bracket {
continue;
}
else if c == '}' {
quoting_depth -= 1;
if quoting_depth == 0 {
blocks.push(replace(&mut quoting_buffer, String::new()));
}
}
else if c == '\n' {
commenting = false;
if context.len() == 0 { continue }
match replace(&mut context, String::new()).as_str() {
"\\section" => {
if blocks.len() < 1 { continue }
stream.push(Value::Section(replace(&mut blocks, Vec::new()).pop().unwrap()));
}
"\\cventry" => {
if blocks.len() < 6 { continue }
stream.push(Value::CvEntry(replace(&mut blocks, Vec::new())));
}
"\\cvitem" => {
if blocks.len() < 2 { continue }
stream.push(Value::CvItem(replace(&mut blocks, Vec::new())));
},
"\\firstname" => (),
"\\familyname" => (),
"\\title" => (),
"\\mobile" => (),
"\\email" => (),
"\\address" => (),
"\\photo" => (),
"\\makecvtitle" => (),
"\\begin" => (),
"\\end" => (),
"\\documentclass" => (),
"\\moderncvstyle" => (),
"\\moderncvcolor" => (),
"\\usepackage" => (),
"\\setlength" => (),
x => {
if x.starts_with("\\") {
println!(":{}", x);
unreachable!()
}
stream.push(Value::Plain(x.to_string()));
}
}
}
else if c == '{' {
if quoting_depth > 0 {
quoting_buffer.clear();
}
quoting_depth += 1;
}
else if quoting_depth > 0 {
quoting_buffer.push(c);
}
else if !c.is_whitespace() {
context.push(c)
}
}
for item in stream {
match item {
Value::Plain(val) => {
println!("{}", val);
},
Value::Section(val) => {
println!("\n= {}\n#line(length: 100%)", val);
},
Value::CvEntry(parts) => {
println!("#v(.2em)");
if parts[2].len() > 0 {
println!("== {}", parts[2]);
}
println!("*{}* #h(1fr) {}#v(.1em)\n{}", parts[1], parts[0], parts[5]);
},
Value::CvItem(parts) => {
println!("/ {}:`{}`", parts[0], parts[1]);
},
}
}
}
fn main() {
parse(r"
\firstname{Jane}
\familyname{Doe}
\title{Curriculum Vitae}
\address{Street}{City}{}
\mobile{Number}
\email{email}
\begin{document}
\makecvtitle
\section{Education}
\cventry
{2020--2025}
{Degree}
{University}
{Location}
{\textit{Grade}}% Missing this
{Some info including a link in my real document. The automatic linebreak works here, but not below}
\setlength{\hintscolumnwidth}{4cm}
\setlength{\maincolumnwidth}{\dimexpr\linewidth-\hintscolumnwidth-\separatorcolumnwidth}
\cvitem{Item 1}{This is the description of item 1 and it is very long so I need an automatic linebreak here so the text doesn't go beyond the linewidth.}
\cvitem{Item 2}{This is the description of item 2 and it is very long so I need an automatic linebreak here which I don't know how to create.}
\cvitem{Item 3}{This is the description of item 3 and it is even longer and spans across multiple lines so I need an automatic linebreak so the text doesn't go beyond the linewidth, but I don't know how to create this.}
\end{document}
")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment