Tholp's bespoke website generator

more filegroup options, basic universal macro arg count error checking

Tholp1 141d8a02 29599d68

+163 -69
+31 -11
src/macros/mod.rs
··· 9 9 use simple_macros::{macro_clear, macro_filename, macro_filename_canonical, macro_time}; 10 10 use template::macro_template; 11 11 12 - pub static MACRO_LIST: &'static [Macro<'_>] = &[ 12 + pub static MACRO_LIST: &'static [Macro] = &[ 13 13 // Unscoped 14 14 Macro { 15 15 symbol: "insert", // Inserts another file 16 - expand: macro_insert, 16 + expansion: macro_insert, 17 17 has_scope: false, 18 + min_args: 1, 19 + max_args: 1, 18 20 }, 19 21 Macro { 20 22 symbol: "clear", // Clears text buffer 21 - expand: macro_clear, 23 + expansion: macro_clear, 22 24 has_scope: false, 25 + min_args: 0, 26 + max_args: 0, 23 27 }, 24 28 Macro { 25 29 symbol: "time", 26 - expand: macro_time, 30 + expansion: macro_time, 27 31 has_scope: false, 32 + min_args: 1, 33 + max_args: 1, 28 34 }, 29 35 Macro { 30 36 symbol: "filename", 31 - expand: macro_filename, 37 + expansion: macro_filename, 32 38 has_scope: false, 39 + min_args: 0, 40 + max_args: 0, 33 41 }, 34 42 Macro { 35 43 symbol: "filename_canonical", 36 - expand: macro_filename_canonical, 44 + expansion: macro_filename_canonical, 37 45 has_scope: false, 46 + min_args: 0, 47 + max_args: 0, 38 48 }, 39 49 // Scoped 40 50 Macro { 41 51 symbol: "comment", // Nothing 42 - expand: macro_comment, 52 + expansion: macro_comment, 43 53 has_scope: true, 54 + min_args: 0, 55 + max_args: 0, 44 56 }, 45 57 Macro { 46 58 symbol: "repeat", // Outputs what its give x number of times 47 - expand: macro_repeat, 59 + expansion: macro_repeat, 48 60 has_scope: true, 61 + min_args: 1, 62 + max_args: 1, 49 63 }, 50 64 Macro { 51 65 symbol: "section", 52 - expand: macro_section, 66 + expansion: macro_section, 53 67 has_scope: true, 68 + min_args: 0, 69 + max_args: 1, 54 70 }, 55 71 Macro { 56 72 symbol: "template", 57 - expand: macro_template, 73 + expansion: macro_template, 58 74 has_scope: true, 75 + min_args: 1, 76 + max_args: usize::max_value(), 59 77 }, 60 78 Macro { 61 79 symbol: "for_each_arg", 62 - expand: macro_for_each_arg, 80 + expansion: macro_for_each_arg, 63 81 has_scope: true, 82 + min_args: 1, 83 + max_args: usize::max_value(), 64 84 }, 65 85 ];
+4 -4
src/macros/simple_blocks.rs
··· 103 103 let replacement = split_to_tokens(arg.clone(), origin_index); 104 104 arg_output.splice(start..start + len, replacement); 105 105 found_pattern = find_pattern(&arg_output, format!("[[..{}]]", replacement_index + 1)); 106 - println!("{}", replacement_index + 1); 106 + //println!("{}", replacement_index + 1); 107 107 } 108 108 109 - println!("{} {}", replacement_index, replacement_count); 109 + //println!("{} {}", replacement_index, replacement_count); 110 110 replacement_index += 1; 111 111 if replacement_index == replacement_count { 112 112 replacement_index = 0; 113 113 output.append(&mut arg_output.trim_whitespace().into()); 114 114 arg_output = block.clone(); 115 - println!("push"); 115 + //println!("push"); 116 116 } 117 - println!("test"); 117 + //println!("test"); 118 118 } 119 119 120 120 return output;
+8 -8
src/macros/template.rs
··· 102 102 args_index += 1; 103 103 } 104 104 105 - let mut found_block_pattern = find_pattern(&output, "[[{}]]".into()); 106 - while found_block_pattern.is_some() { 107 - let (start, len) = found_block_pattern.unwrap(); 108 - let replacement = scope.to_vec(); 109 - output.splice(start..start + len, replacement); 110 - found_block_pattern = find_pattern(&output, "[[{}]]".into()); 111 - } 112 - 113 105 //replace [[..]] with space seperated remaining args 114 106 let mut found_trailing_pattern = find_pattern(&output, "[[..]]".into()); 115 107 while found_trailing_pattern.is_some() { ··· 135 127 } 136 128 output.splice(start..start + len, replacement); 137 129 found_trailing_pattern = find_pattern(&output, "[[\"..\"]]".into()); 130 + } 131 + 132 + let mut found_block_pattern = find_pattern(&output, "[[{}]]".into()); 133 + while found_block_pattern.is_some() { 134 + let (start, len) = found_block_pattern.unwrap(); 135 + let replacement = scope.to_vec(); 136 + output.splice(start..start + len, replacement); 137 + found_block_pattern = find_pattern(&output, "[[{}]]".into()); 138 138 } 139 139 140 140 output
+49 -35
src/main.rs
··· 7 7 use console::*; 8 8 use macros::MACRO_LIST; 9 9 use markdown::{to_html_with_options, CompileOptions, Constructs, Options, ParseOptions}; 10 - use projectparse::{parse_project, FileIndexing, ProjectContext}; 10 + use projectparse::{parse_project, FileGroup, FileIndexing, ProjectContext}; 11 11 use std::{ 12 - env, 12 + convert, env, 13 13 fs::{self, File}, 14 14 io::Write, 15 15 path::PathBuf, ··· 20 20 trim_whitespace_tokens, 21 21 }; 22 22 use types::{InputFile, Macro, Token}; 23 + 24 + use crate::types::Expand; 23 25 24 26 static DELIMITERS: &'static [char] = &[ 25 27 ' ', '\n', '\t', '(', ')', '{', '}', '[', ']', '<', '>', '\\', '\'', '\"', ';', ··· 55 57 println!("Proccesing {} files.", num); 56 58 for group in &mut project.filegroups { 57 59 for infile in &mut group.files { 58 - process_file(infile, &mut project.context); 60 + process_file(infile, group.convert_html, &mut project.context); 59 61 } 60 62 } 61 63 } 62 64 63 - fn process_file(file: &mut InputFile, context: &mut ProjectContext) { 65 + fn process_file(file: &mut InputFile, convert_html: bool, context: &mut ProjectContext) { 64 66 //}, context: &mut ProjectContext) { 65 67 let contents = fs::read_to_string(&file.file_input).expect("File unreadable or missing"); 66 68 //println!("{}\n {}", f.filename_out, contents); ··· 138 140 if ephemeral { 139 141 expansion = Vec::new(); 140 142 } else { 141 - expansion = (m.expand)( 143 + expansion = m.expand( 142 144 file, 143 145 file.tokens[file.working_index].origin_file, 144 146 file.tokens[file.working_index].line_number, ··· 153 155 if ephemeral { 154 156 expansion = Vec::new(); 155 157 } else { 156 - expansion = (m.expand)( 158 + expansion = m.expand( 157 159 file, 158 160 file.tokens[file.working_index].origin_file, 159 161 file.tokens[file.working_index].line_number, ··· 270 272 for t in &file.tokens { 271 273 skid_output += &t.contents; 272 274 } 273 - fs::write(&file.file_skidout, &skid_output).expect("Couldn't write skid to file"); 274 275 275 - //let html_output = markdown::to_html(&skid_output); 276 - let html_output = markdown::to_html_with_options( 277 - &skid_output, 278 - &Options { 279 - compile: CompileOptions { 280 - allow_dangerous_html: true, 281 - allow_dangerous_protocol: true, 282 - gfm_tagfilter: false, 283 - // gfm_footnote_clobber_prefix: 284 - gfm_task_list_item_checkable: true, 285 - allow_any_img_src: true, 286 - ..CompileOptions::gfm() 287 - }, 288 - parse: ParseOptions { 289 - constructs: Constructs { 290 - code_indented: false, 291 - ..Constructs::gfm() 276 + if convert_html { 277 + fs::write(&file.file_skidout, &skid_output).expect("Couldn't write skid to file"); 278 + 279 + //let html_output = markdown::to_html(&skid_output); 280 + let html_output = markdown::to_html_with_options( 281 + &skid_output, 282 + &Options { 283 + compile: CompileOptions { 284 + allow_dangerous_html: true, 285 + allow_dangerous_protocol: true, 286 + gfm_tagfilter: false, 287 + // gfm_footnote_clobber_prefix: 288 + gfm_task_list_item_checkable: true, 289 + allow_any_img_src: true, 290 + ..CompileOptions::gfm() 292 291 }, 293 - ..ParseOptions::default() 292 + parse: ParseOptions { 293 + constructs: Constructs { 294 + code_indented: false, 295 + //html_flow: false, 296 + ..Constructs::gfm() 297 + }, 298 + ..ParseOptions::default() 299 + }, 294 300 }, 295 - }, 296 - ) 297 - .unwrap(); 298 - fs::write(&file.file_htmlout, &html_output).expect("Couldn't write html to file"); 299 - ok_generic(format!( 300 - "\"{}\" written \n\n", 301 - file.file_htmlout 302 - .to_str() 303 - .unwrap_or("Couldnt Unwrap htmlout name") 304 - )); 301 + ) 302 + .unwrap(); 303 + fs::write(&file.file_out, &html_output).expect("Couldn't write output to file"); 304 + ok_generic(format!( 305 + "\"{}\" written \n\n", 306 + file.file_out 307 + .to_str() 308 + .unwrap_or("Couldnt Unwrap file_out name") 309 + )); 310 + } else { 311 + fs::write(&file.file_out, &skid_output).expect("Couldn't write output to file"); 312 + ok_generic(format!( 313 + "\"{}\" written \n\n", 314 + file.file_out 315 + .to_str() 316 + .unwrap_or("Couldnt Unwrap file_out name") 317 + )); 318 + } 305 319 }
+12 -5
src/projectparse.rs
··· 21 21 pub pre_insert: PathBuf, 22 22 pub post_insert: PathBuf, 23 23 pub process: bool, 24 + pub convert_html: bool, 25 + pub output_extention: String, 24 26 } 25 27 26 28 // pub struct ProjectSettings { ··· 118 120 continue; 119 121 } 120 122 let filegroup_def: &toml::map::Map<String, toml::Value> = v.as_table().unwrap(); 121 - let name = k.clone(); 123 + 122 124 let pre_insert = get_table_string_or_default!(filegroup_def, "preInsert", ""); 123 125 let post_insert = get_table_string_or_default!(filegroup_def, "postInsert", ""); 124 126 let process = get_table_bool_or_default!(filegroup_def, "process", false); 127 + let convert_html = get_table_bool_or_default!(filegroup_def, "convertHTML", true); 128 + let extention = get_table_string_or_default!(filegroup_def, "outputExtention", "html"); 125 129 126 130 let recurse_find = get_table_bool_or_default!(filegroup_def, "recursiveFind", false); 127 131 ··· 133 137 pre_insert: pre_insert.into(), 134 138 post_insert: post_insert.into(), 135 139 process, 140 + convert_html, 141 + output_extention: extention.into(), 136 142 }; 137 143 138 144 if filegroup_def.contains_key("files") { ··· 146 152 k 147 153 ) 148 154 }); 155 + 149 156 let mut new_file = crate::types::InputFile::new(); 150 157 new_file.file_input = project.context.input_folder.clone(); 151 158 new_file.file_input.push(filename); 152 159 153 - new_file.file_htmlout = project.context.output_folder.clone(); 154 - new_file.file_htmlout.push(filename); 155 - new_file.file_htmlout.set_extension("html"); 160 + new_file.file_out = project.context.output_folder.clone(); 161 + new_file.file_out.push(filename); 162 + new_file.file_out.set_extension(extention); 156 163 157 - new_file.file_skidout = new_file.file_htmlout.clone(); 164 + new_file.file_skidout = new_file.file_out.clone(); 158 165 new_file.file_skidout.set_extension("sko"); 159 166 160 167 group.files.push(new_file);
+3
src/stringtools.rs
··· 262 262 263 263 pub fn find_pattern(tokens: &[Token], pat: String) -> Option<(usize, usize)> { 264 264 // (startpoint, length) 265 + // FIXME: this fucks up when the begining of a pattern is repeated 266 + // ex. searching for "[[hello]]" in "[[[[hello]]" yeilds None 267 + // ALSO, this is a coarse search, operating on tokens only, not the characters within 265 268 let split_pattern = split_to_tokens(pat, 0); 266 269 let mut pattern_index: usize = 0; 267 270 let mut token_index: usize = 0;
+56 -6
src/types.rs
··· 1 1 use std::path::PathBuf; 2 2 3 - use crate::{macros::template::SkidTemplate, projectparse::ProjectContext}; 3 + use crate::{ 4 + console::error_skid, 5 + macros::{simple_blocks::macro_comment, template::SkidTemplate}, 6 + projectparse::ProjectContext, 7 + }; 4 8 5 9 pub struct Token { 6 10 pub contents: String, ··· 12 16 pub struct InputFile { 13 17 pub file_input: PathBuf, 14 18 pub file_skidout: PathBuf, 15 - pub file_htmlout: PathBuf, 19 + pub file_out: PathBuf, 16 20 pub tokens: Vec<Token>, 17 21 pub working_index: usize, 18 22 pub templates: Vec<SkidTemplate>, ··· 29 33 // _scope: &[Token], 30 34 // ) -> Vec<Token> 31 35 32 - pub struct Macro<'a> { 33 - pub symbol: &'a str, 34 - pub expand: MacroExpansion, 36 + pub struct Macro { 37 + pub symbol: &'static str, 38 + pub expansion: MacroExpansion, 35 39 pub has_scope: bool, //takes blocks of text input as well as parameters using {{...}} 40 + pub min_args: usize, 41 + pub max_args: usize, 42 + } 43 + 44 + pub trait Expand { 45 + fn expand( 46 + &self, 47 + input_file: &mut InputFile, 48 + origin_index: usize, 49 + origin_line: usize, 50 + context: &mut ProjectContext, 51 + args: &Vec<String>, 52 + scope: &[Token], 53 + ) -> Vec<Token>; 54 + 55 + fn default() -> Macro; 56 + } 57 + 58 + impl Expand for Macro { 59 + fn expand( 60 + &self, 61 + input_file: &mut InputFile, 62 + origin_index: usize, 63 + origin_line: usize, 64 + context: &mut ProjectContext, 65 + args: &Vec<String>, 66 + scope: &[Token], 67 + ) -> Vec<Token> { 68 + if (args.len() > self.max_args) || (args.len() < self.min_args) { 69 + error_skid(context, origin_index, origin_line, format!("Macro \'{}\' was given a number of arguments ({}) not in its acceptable range ({}-{})", 70 + self.symbol, args.len(), self.min_args, if self.max_args == usize::max_value() {"No Limit".to_string()} else {format!("{}", self.max_args)})); 71 + Vec::new() 72 + } else { 73 + (self.expansion)(input_file, origin_index, origin_line, context, args, scope) 74 + } 75 + } 76 + 77 + fn default() -> Macro { 78 + Macro { 79 + symbol: "default_symbol", 80 + expansion: macro_comment, 81 + has_scope: true, 82 + min_args: 0, 83 + max_args: usize::max_value(), 84 + } 85 + } 36 86 } 37 87 38 88 impl InputFile { ··· 40 90 InputFile { 41 91 file_input: "".into(), 42 92 file_skidout: "".into(), 43 - file_htmlout: "".into(), 93 + file_out: "".into(), 44 94 tokens: Vec::new(), 45 95 working_index: 0, 46 96 templates: Vec::new(),