Tholp's bespoke website generator

Better errors and warns

Tholp1 478cd07f 4f40cfb3

+1
Cargo.toml
···
[dependencies]
chrono = "0.4.41"
glob = "0.3.2"
markdown = "1.0.0"
# markdown = {path = "/home/tholp/Desktop/Code/libs/markdown-rs"}
···
[dependencies]
chrono = "0.4.41"
+
colored = "3.0.0"
glob = "0.3.2"
markdown = "1.0.0"
# markdown = {path = "/home/tholp/Desktop/Code/libs/markdown-rs"}
+43
src/console.rs
···
···
+
use std::process::exit;
+
+
use colored::Colorize;
+
+
use crate::projectparse::{FileIndexing, ProjectContext};
+
+
pub fn error_generic(msg: String) {
+
println!("{} {}", "[ERROR]".red(), msg);
+
exit(1);
+
}
+
+
pub fn error_skid(context: &ProjectContext, origin_index: usize, origin_line: usize, msg: String) {
+
println!(
+
"{} {:?}:{}; {}",
+
"[ERROR]".red(),
+
context
+
.file_for_index(origin_index)
+
.expect("Panic in the error func.... (file_for_index() was None!)"),
+
origin_line,
+
msg
+
);
+
exit(1);
+
}
+
+
pub fn warn_generic(msg: String) {
+
println!("{} {}", "[WARN]".yellow(), msg);
+
}
+
+
pub fn warn_skid(context: &ProjectContext, origin_index: usize, origin_line: usize, msg: String) {
+
println!(
+
"{} {:?}:{}; {}",
+
"[WARN]".yellow(),
+
context
+
.file_for_index(origin_index)
+
.expect("Panic in the warn func.... (file_for_index() was None!)"),
+
origin_line,
+
msg
+
);
+
}
+
+
pub fn ok_generic(msg: String) {
+
println!("{} {}", "[OK]".green(), msg);
+
}
-10
src/error.rs
···
-
pub fn exit_error(msg : String)
-
{
-
println!("[Error]" + msg);
-
exit(1);
-
}
-
-
pub fn warn(msg: String)
-
{
-
-
}
···
+10 -8
src/macros/insert.rs
···
};
use crate::{
projectparse::{FileIndexing, ProjectContext},
stringtools::{split_keep_delimiters, split_to_tokens, strings_to_tokens},
types::{InputFile, Token},
···
.expect("Macro 'Insert' was given a bad origin index")
.clone();
if args.len() != 1 {
-
println!(
-
"[ERROR] {:?}:{} ;Insert only accepts 1 argument, got given {} ({:?})",
-
origin_file.to_str(),
origin_line,
-
args.len(),
-
args
);
-
exit(1);
}
let mut arg = args[0].clone();
···
}
if !ok {
-
println!("[ERROR] {:?}: Insert was unable to find the file \"{}\" relative to its origin or in project root.", origin_file.to_str().unwrap(), arg);
-
exit(1);
}
let mut output = fs::read_to_string(&include_file).expect("File unreadable or missing");
···
};
use crate::{
+
console::error_skid,
projectparse::{FileIndexing, ProjectContext},
stringtools::{split_keep_delimiters, split_to_tokens, strings_to_tokens},
types::{InputFile, Token},
···
.expect("Macro 'Insert' was given a bad origin index")
.clone();
if args.len() != 1 {
+
error_skid(
+
context,
+
origin_index,
origin_line,
+
format!(
+
"Insert only accepts 1 argument, got given {} ({:?})",
+
args.len(),
+
args
+
),
);
}
let mut arg = args[0].clone();
···
}
if !ok {
+
error_skid(context, origin_index, origin_line, format!("Insert was unable to find the file \"{}\" relative to its origin or in project root.", arg));
}
let mut output = fs::read_to_string(&include_file).expect("File unreadable or missing");
+3 -3
src/macros/mod.rs
···
use super::types::Macro;
use insert::macro_insert;
-
use simple_blocks::{macro_comment, macro_repeat, macro_section, macro_skip};
use simple_macros::{macro_clear, macro_filename, macro_filename_canonical, macro_time};
use template::macro_template;
···
has_scope: true,
},
Macro {
-
symbol: "skip",
-
expand: macro_skip,
has_scope: true,
},
];
···
use super::types::Macro;
use insert::macro_insert;
+
use simple_blocks::{macro_comment, macro_for_each_arg, macro_repeat, macro_section};
use simple_macros::{macro_clear, macro_filename, macro_filename_canonical, macro_time};
use template::macro_template;
···
has_scope: true,
},
Macro {
+
symbol: "for_each_arg",
+
expand: macro_for_each_arg,
has_scope: true,
},
];
+68 -12
src/macros/simple_blocks.rs
···
// This file for implementations of short blocks, im qualifying that as less than 30ish lines
use crate::{
-
projectparse::ProjectContext,
types::{InputFile, Token},
};
···
return tokens;
}
-
pub fn macro_skip(
-
_file: &mut InputFile,
-
_origin_index: usize,
-
_origin_line: usize,
-
_context: &mut ProjectContext,
-
_args: &Vec<String>,
-
scope: &[Token],
-
) -> Vec<Token> {
-
Vec::new()
-
}
-
pub fn macro_repeat(
_file: &mut InputFile,
_origin_index: usize,
···
}
return tokens;
}
···
// This file for implementations of short blocks, im qualifying that as less than 30ish lines
+
use std::{env::args, fmt::format, process::exit};
+
use crate::{
+
console::error_skid,
+
projectparse::{FileIndexing, ProjectContext},
+
stringtools::{find_pattern, split_to_tokens},
types::{InputFile, Token},
};
···
return tokens;
}
pub fn macro_repeat(
_file: &mut InputFile,
_origin_index: usize,
···
}
return tokens;
}
+
+
pub fn macro_for_each_arg(
+
_file: &mut InputFile,
+
origin_index: usize,
+
origin_line: usize,
+
context: &mut ProjectContext,
+
args: &Vec<String>,
+
scope: &[Token],
+
) -> Vec<Token> {
+
let mut output = Vec::new();
+
let block: Vec<Token> = scope.into();
+
+
let mut replacement_count: usize = 0;
+
+
let mut replacement_pattern = find_pattern(scope, "[[..1]]".into());
+
while replacement_pattern.is_some() {
+
replacement_count += 1;
+
replacement_pattern =
+
find_pattern(scope, format!("[[..{}]]", replacement_count + 1).into());
+
}
+
+
if replacement_count == 0 {
+
for _i in 0..args.iter().count() {
+
output.append(&mut block.clone());
+
}
+
return output;
+
}
+
+
if args.len() % replacement_count != 0 {
+
error_skid(context, origin_index, origin_line,
+
format!("`for_each_var` was not given a number of arguments({}) that was a multiple of its replacement posistions({}) (got {:?})",
+
args.len(),
+
replacement_count,
+
args));
+
}
+
+
let mut replacement_index: usize = 0;
+
let mut arg_output: Vec<Token> = block.clone();
+
for arg in args {
+
let mut found_pattern =
+
find_pattern(&arg_output, format!("[[..{}]]", replacement_index + 1));
+
+
while found_pattern.is_some() {
+
let (start, len) = found_pattern.unwrap();
+
let replacement = split_to_tokens(arg.clone(), origin_index);
+
arg_output.splice(start..start + len, replacement);
+
found_pattern = find_pattern(&output, format!("[[..{}]]", replacement_index + 1));
+
println!("{}", replacement_index + 1);
+
}
+
+
println!("{} {}", replacement_index, replacement_count);
+
replacement_index += 1;
+
if replacement_index == replacement_count {
+
replacement_index = 0;
+
output.append(&mut arg_output);
+
arg_output = block.clone();
+
println!("push");
+
}
+
println!("test");
+
}
+
+
return output;
+
}
+75 -24
src/macros/template.rs
···
-
use std::{process::exit, thread::scope};
use crate::{
projectparse::{FileIndexing, ProjectContext},
stringtools::{find_pattern, split_to_tokens, strings_to_tokens, WhitespaceChecks},
types::{InputFile, Token},
···
pub tokens: Vec<Token>,
pub has_scope: bool,
}
impl SkidTemplate {
pub fn new(name: String, args: &[String], tokens: &[Token]) -> SkidTemplate {
let scoped: bool = find_pattern(&tokens, "[[{}]]".into()).is_some();
SkidTemplate {
symbol: name,
args: args.to_vec(),
tokens: tokens.to_vec(),
has_scope: scoped,
}
}
···
&self,
//_file: &mut InputFile,
origin_index: usize,
-
_context: &mut ProjectContext,
args: &Vec<String>,
scope: &[Token],
) -> Vec<Token> {
//println!("{:?}", args);
let mut output = self.tokens.clone();
···
) -> Vec<Token> {
for t in &file.templates {
if t.symbol == args[0] {
-
println!(
-
"[ERROR] {:?}:{} ; Attempted template redefinition of \"{}\"",
-
context.file_for_index(origin_index).unwrap(),
origin_line,
-
args[0]
);
-
exit(1);
}
}
for t in MACRO_LIST {
if t.symbol == args[0] {
-
println!(
-
"[ERROR] {:?}:{} ; Attempted to make a template using a reserved name \"{}\"",
-
context.file_for_index(origin_index).unwrap(),
origin_line,
-
args[0]
);
-
exit(1);
}
}
···
used_params += 1;
}
if param.contains_whitespace() {
-
println!(
-
"[ERROR] {:?}:{} ; Attempted to make a template with a parameter that contains whitespace \"{}\"",
-
context.file_for_index(origin_index).unwrap(),
origin_line,
-
param
);
-
exit(1);
}
}
if used_params < args.len() - 1 {
-
println!(
-
"[ERROR] {:?}:{} ; Template definition of \"{}\" has {} paramters but only uses {}",
-
context.file_for_index(origin_index).unwrap(),
origin_line,
-
args[0],
-
args.len() - 1,
-
used_params
);
-
exit(1);
}
let template = SkidTemplate::new(args[0].clone(), &args[1..], scope);
···
+
use std::{fmt::format, process::exit, thread::scope};
use crate::{
+
console::error_skid,
projectparse::{FileIndexing, ProjectContext},
stringtools::{find_pattern, split_to_tokens, strings_to_tokens, WhitespaceChecks},
types::{InputFile, Token},
···
pub tokens: Vec<Token>,
pub has_scope: bool,
+
pub allows_trailing_args: bool,
}
impl SkidTemplate {
pub fn new(name: String, args: &[String], tokens: &[Token]) -> SkidTemplate {
let scoped: bool = find_pattern(&tokens, "[[{}]]".into()).is_some();
+
let trailing: bool = find_pattern(&tokens, "[[..]]".into()).is_some()
+
|| find_pattern(&tokens, "[[\"..\"]]".into()).is_some();
SkidTemplate {
symbol: name,
args: args.to_vec(),
tokens: tokens.to_vec(),
has_scope: scoped,
+
allows_trailing_args: trailing,
}
}
···
&self,
//_file: &mut InputFile,
origin_index: usize,
+
origin_line: usize,
+
context: &mut ProjectContext,
args: &Vec<String>,
scope: &[Token],
) -> Vec<Token> {
//println!("{:?}", args);
+
+
if !self.allows_trailing_args && args.len() != self.args.len() {
+
// println!(
+
// "[ERROR] {:?}:{}; Template \"{}\" requires exactly {} arguments, got given {} ({:?})",
+
// context.file_for_index(origin_index).unwrap(),
+
// origin_line,
+
// self.symbol,
+
// self.args.len(),
+
// args.len(),
+
// args
+
// );
+
// exit(1);
+
+
error_skid(
+
context,
+
origin_index,
+
origin_line,
+
format!(
+
"Template \"{}\" requires exactly {} arguments, got given {} ({:?})",
+
self.symbol,
+
self.args.len(),
+
args.len(),
+
args
+
),
+
);
+
}
+
if self.allows_trailing_args && args.len() < self.args.len() {
+
error_skid(
+
context,
+
origin_index,
+
origin_line,
+
format!(
+
"Template \"{}\" requires at least {} arguments, got given {} ({:?})",
+
self.symbol,
+
self.args.len(),
+
args.len(),
+
args
+
),
+
);
+
}
let mut output = self.tokens.clone();
···
) -> Vec<Token> {
for t in &file.templates {
if t.symbol == args[0] {
+
error_skid(
+
context,
+
origin_index,
origin_line,
+
format!("Attempted template redefinition of \"{}\"", args[0]),
);
}
}
for t in MACRO_LIST {
if t.symbol == args[0] {
+
error_skid(
+
context,
+
origin_index,
origin_line,
+
format!(
+
"Attempted to make a template using a reserved name \"{}\"",
+
args[0]
+
),
);
}
}
···
used_params += 1;
}
if param.contains_whitespace() {
+
error_skid(
+
context,
+
origin_index,
origin_line,
+
format!(
+
"Attempted to make a template with a parameter that contains whitespace \"{}\"",
+
param
+
),
);
}
}
if used_params < args.len() - 1 {
+
error_skid(
+
context,
+
origin_index,
origin_line,
+
format!(
+
"Template definition of \"{}\" has {} paramters but only uses {}",
+
args[0],
+
args.len() - 1,
+
used_params
+
),
);
}
let template = SkidTemplate::new(args[0].clone(), &args[1..], scope);
+27 -21
src/main.rs
···
mod macros;
mod projectparse;
mod stringtools;
mod types;
use macros::MACRO_LIST;
use markdown::{to_html_with_options, CompileOptions, Constructs, Options, ParseOptions};
use projectparse::{parse_project, FileIndexing, ProjectContext};
···
while !project_path.exists() || project_path.is_dir() {
let ok = project_folder.pop();
if !ok {
-
println!("[ERROR] No skidmark.toml project file found in this folder or ancestors.");
-
exit(1);
}
project_path = project_folder.clone();
project_path.push("skidmark.toml");
···
let block_opt =
collect_block(&file.tokens[(file.working_index + args_tokcount)..]);
if block_opt.is_none() {
-
println!(
-
"[ERROR] {:?}:{} ;Malformed block",
-
file.tokens[file.working_index].origin_file,
-
file.tokens[file.working_index].line_number
);
-
exit(1);
}
let block: Vec<Token>;
(block, block_tokcount) = block_opt.unwrap();
···
let block_opt =
collect_block(&file.tokens[(file.working_index + args_tokcount)..]);
if block_opt.is_none() {
-
println!(
-
"[ERROR] {:?}:{} ;Malformed block",
-
file.tokens[file.working_index].origin_file,
-
file.tokens[file.working_index].line_number
);
-
exit(1);
}
(block, block_tokcount) = block_opt.unwrap();
···
expansion = m.expand(
//file,
file.tokens[file.working_index].origin_file,
-
//file.tokens[file.working_index].line_number,
context,
&args,
&block,
···
expansion = m.expand(
//file,
file.tokens[file.working_index].origin_file,
-
//file.tokens[file.working_index].line_number,
context,
&args,
&Vec::new()[..],
···
}
}
if !matched_macro {
-
println!(
-
"[WARN] {:?}:{}; Token written as a function but no such function exists \"{}\"",
-
context.file_for_index(file.tokens[file.working_index].origin_file).unwrap(),
file.tokens[file.working_index].line_number,
-
file.tokens[file.working_index].contents.trim()
);
}
}
···
)
.unwrap();
fs::write(&file.file_htmlout, &html_output).expect("Couldn't write html to file");
-
print!(
-
"[OK] {} written.\n\n",
file.file_htmlout
.to_str()
.unwrap_or("Couldnt Unwrap htmlout name")
-
);
}
···
+
mod console;
mod macros;
mod projectparse;
mod stringtools;
mod types;
+
use console::*;
use macros::MACRO_LIST;
use markdown::{to_html_with_options, CompileOptions, Constructs, Options, ParseOptions};
use projectparse::{parse_project, FileIndexing, ProjectContext};
···
while !project_path.exists() || project_path.is_dir() {
let ok = project_folder.pop();
if !ok {
+
error_generic(
+
"No skidmark.toml project file found in this folder or ancestors.".into(),
+
);
}
project_path = project_folder.clone();
project_path.push("skidmark.toml");
···
let block_opt =
collect_block(&file.tokens[(file.working_index + args_tokcount)..]);
if block_opt.is_none() {
+
error_skid(
+
context,
+
file.tokens[file.working_index].template_origin,
+
file.tokens[file.working_index].line_number,
+
"Malformed Block".into(),
);
}
let block: Vec<Token>;
(block, block_tokcount) = block_opt.unwrap();
···
let block_opt =
collect_block(&file.tokens[(file.working_index + args_tokcount)..]);
if block_opt.is_none() {
+
error_skid(
+
context,
+
file.tokens[file.working_index].template_origin,
+
file.tokens[file.working_index].line_number,
+
"Malformed Block".into(),
);
}
(block, block_tokcount) = block_opt.unwrap();
···
expansion = m.expand(
//file,
file.tokens[file.working_index].origin_file,
+
file.tokens[file.working_index].line_number,
context,
&args,
&block,
···
expansion = m.expand(
//file,
file.tokens[file.working_index].origin_file,
+
file.tokens[file.working_index].line_number,
context,
&args,
&Vec::new()[..],
···
}
}
if !matched_macro {
+
warn_skid(
+
context,
+
file.tokens[file.working_index].origin_file,
file.tokens[file.working_index].line_number,
+
format!(
+
"Token written as a function but no such function exists \"{}\"",
+
file.tokens[file.working_index].contents.trim()
+
),
);
}
}
···
)
.unwrap();
fs::write(&file.file_htmlout, &html_output).expect("Couldn't write html to file");
+
ok_generic(format!(
+
"{} written \n\n",
file.file_htmlout
.to_str()
.unwrap_or("Couldnt Unwrap htmlout name")
+
));
}
+5 -1
src/types.rs
···
pub struct Token {
pub contents: String,
pub origin_file: usize,
pub line_number: usize,
}
···
Token {
contents: contents,
origin_file: origin_file,
line_number: line_number,
}
}
···
impl Clone for Token {
fn clone(&self) -> Self {
-
return Token::new(
self.contents.clone(),
self.origin_file.clone(),
self.line_number,
);
}
}
···
pub struct Token {
pub contents: String,
pub origin_file: usize,
+
pub template_origin: usize,
pub line_number: usize,
}
···
Token {
contents: contents,
origin_file: origin_file,
+
template_origin: origin_file,
line_number: line_number,
}
}
···
impl Clone for Token {
fn clone(&self) -> Self {
+
let mut t = Token::new(
self.contents.clone(),
self.origin_file.clone(),
self.line_number,
);
+
t.template_origin = self.template_origin;
+
return t;
}
}