Tholp's bespoke website generator

prep

+170 -54
+1
Cargo.toml
··· 4 edition = "2021" 5 6 [dependencies] 7 chrono = "0.4.41" 8 clap = { version = "4.5.40", features = ["derive"] } 9 colored = "3.0.0"
··· 4 edition = "2021" 5 6 [dependencies] 7 + boa_engine = "0.20.0" 8 chrono = "0.4.41" 9 clap = { version = "4.5.40", features = ["derive"] } 10 colored = "3.0.0"
+78
src/closures.rs
···
··· 1 + // Closures are essentally blocked macros that change behavior on symbol instead of name 2 + // Instances of most types of closures can be named as sections ... 3 + // ... to work with !insert() to pick certain parts out of a file 4 + 5 + use boa_engine::Context; 6 + 7 + use crate::{ 8 + project::ProjectContext, 9 + types::{SkidContext, Token}, 10 + }; 11 + 12 + type ClosureFunction = fn(&[Token], &mut ProjectContext, &mut SkidContext) -> Vec<Token>; 13 + 14 + pub struct Closure { 15 + pub opener: &'static str, 16 + pub opener2: &'static str, 17 + pub closer: &'static str, 18 + pub function: ClosureFunction, 19 + } 20 + 21 + // (opener) name (opener2) ... (closer) 22 + 23 + // << js ! .. >> 24 + // <!-- comment --> 25 + // [ name {{ .. }}] 26 + 27 + // <!-- ... --> comment 28 + // ?name<< >> named js 29 + // ?name[[ ]] named section 30 + // ?<< >> js 31 + // ?[[ ]] section 32 + // ?name^[[]] named emphemeral section 33 + // ?name-[[]] named inverted section 34 + 35 + pub static CLOSURE_LIST: &'static [Closure] = &[ 36 + Closure { 37 + opener: "?", 38 + opener2: "<<", 39 + closer: ">>", 40 + function: closure_js, 41 + }, 42 + Closure { 43 + opener: "<!--", 44 + opener2: "", // blank means it doesnt accept a name 45 + closer: "-->", 46 + function: closure_comment, 47 + }, 48 + Closure { 49 + opener: "?", 50 + opener2: "{{", 51 + closer: "}}", 52 + function: closure_section, 53 + }, 54 + ]; 55 + 56 + fn closure_comment( 57 + _tokens: &[Token], 58 + _project_context: &mut ProjectContext, 59 + _skid_context: &mut SkidContext, 60 + ) -> Vec<Token> { 61 + Vec::new() 62 + } 63 + 64 + fn closure_section( 65 + tokens: &[Token], 66 + _project_context: &mut ProjectContext, 67 + _skid_context: &mut SkidContext, 68 + ) -> Vec<Token> { 69 + tokens.to_vec() 70 + } 71 + 72 + fn closure_js( 73 + tokens: &[Token], 74 + project_context: &mut ProjectContext, 75 + skid_context: &mut SkidContext, 76 + ) -> Vec<Token> { 77 + Vec::new() 78 + }
+1 -1
src/console.rs
··· 2 3 use colored::Colorize; 4 5 - use crate::project::{FileIndexing, ProjectContext}; 6 7 pub fn error_generic(msg: &String) { 8 println!("{} {}", "[ERROR]".red(), msg);
··· 2 3 use colored::Colorize; 4 5 + use crate::project::{Indexing, ProjectContext}; 6 7 pub fn error_generic(msg: &String) { 8 println!("{} {}", "[ERROR]".red(), msg);
+3 -3
src/macros/insert.rs
··· 3 use crate::{ 4 console::error_skid, 5 macros::template::SkidTemplate, 6 - project::{FileIndexing, ProjectContext}, 7 stringtools::split_to_tokens, 8 - types::Token, 9 }; 10 11 pub fn macro_insert( 12 origin_index: usize, 13 origin_line: usize, 14 context: &mut ProjectContext, 15 - _templates: &mut Vec<SkidTemplate>, 16 args: &Vec<String>, 17 _scope: &[Token], 18 ) -> Vec<Token> {
··· 3 use crate::{ 4 console::error_skid, 5 macros::template::SkidTemplate, 6 + project::{Indexing, ProjectContext}, 7 stringtools::split_to_tokens, 8 + types::{SkidContext, Token}, 9 }; 10 11 pub fn macro_insert( 12 origin_index: usize, 13 origin_line: usize, 14 context: &mut ProjectContext, 15 + _skid_context: &mut SkidContext, 16 args: &Vec<String>, 17 _scope: &[Token], 18 ) -> Vec<Token> {
+5 -5
src/macros/simple_blocks.rs
··· 5 macros::template::SkidTemplate, 6 project::ProjectContext, 7 stringtools::{find_pattern, split_to_tokens, TokenTools}, 8 - types::Token, 9 }; 10 11 pub fn macro_comment( 12 _origin_index: usize, 13 _origin_line: usize, 14 _context: &mut ProjectContext, 15 - _templates: &mut Vec<SkidTemplate>, 16 _args: &Vec<String>, 17 _scope: &[Token], 18 ) -> Vec<Token> { ··· 23 _origin_index: usize, 24 _origin_line: usize, 25 _context: &mut ProjectContext, 26 - _templates: &mut Vec<SkidTemplate>, 27 _args: &Vec<String>, 28 scope: &[Token], 29 ) -> Vec<Token> { ··· 38 _origin_index: usize, 39 _origin_line: usize, 40 _context: &mut ProjectContext, 41 - _templates: &mut Vec<SkidTemplate>, 42 args: &Vec<String>, 43 scope: &[Token], 44 ) -> Vec<Token> { ··· 60 origin_index: usize, 61 origin_line: usize, 62 context: &mut ProjectContext, 63 - _templates: &mut Vec<SkidTemplate>, 64 args: &Vec<String>, 65 scope: &[Token], 66 ) -> Vec<Token> {
··· 5 macros::template::SkidTemplate, 6 project::ProjectContext, 7 stringtools::{find_pattern, split_to_tokens, TokenTools}, 8 + types::{SkidContext, Token}, 9 }; 10 11 pub fn macro_comment( 12 _origin_index: usize, 13 _origin_line: usize, 14 _context: &mut ProjectContext, 15 + _skid_context: &mut SkidContext, 16 _args: &Vec<String>, 17 _scope: &[Token], 18 ) -> Vec<Token> { ··· 23 _origin_index: usize, 24 _origin_line: usize, 25 _context: &mut ProjectContext, 26 + _skid_context: &mut SkidContext, 27 _args: &Vec<String>, 28 scope: &[Token], 29 ) -> Vec<Token> { ··· 38 _origin_index: usize, 39 _origin_line: usize, 40 _context: &mut ProjectContext, 41 + _skid_context: &mut SkidContext, 42 args: &Vec<String>, 43 scope: &[Token], 44 ) -> Vec<Token> { ··· 60 origin_index: usize, 61 origin_line: usize, 62 context: &mut ProjectContext, 63 + _skid_context: &mut SkidContext, 64 args: &Vec<String>, 65 scope: &[Token], 66 ) -> Vec<Token> {
+6 -6
src/macros/simple_macros.rs
··· 6 use crate::{ 7 console::{error_skid, reminder_skid}, 8 macros::template::SkidTemplate, 9 - project::{FileIndexing, ProjectContext}, 10 stringtools::split_to_tokens, 11 - types::Token, 12 }; 13 14 pub fn macro_time( 15 origin_index: usize, 16 origin_line: usize, 17 context: &mut ProjectContext, 18 - _templates: &mut Vec<SkidTemplate>, 19 args: &Vec<String>, 20 _scope: &[Token], 21 ) -> Vec<Token> { ··· 42 origin_index: usize, 43 origin_line: usize, 44 context: &mut ProjectContext, 45 - _templates: &mut Vec<SkidTemplate>, 46 _args: &Vec<String>, 47 _scope: &[Token], 48 ) -> Vec<Token> { ··· 61 origin_index: usize, 62 _origin_line: usize, 63 context: &mut ProjectContext, 64 - _templates: &mut Vec<SkidTemplate>, 65 _args: &Vec<String>, 66 _scope: &[Token], 67 ) -> Vec<Token> { ··· 80 origin_index: usize, 81 origin_line: usize, 82 context: &mut ProjectContext, 83 - _templates: &mut Vec<SkidTemplate>, 84 args: &Vec<String>, 85 _scope: &[Token], 86 ) -> Vec<Token> {
··· 6 use crate::{ 7 console::{error_skid, reminder_skid}, 8 macros::template::SkidTemplate, 9 + project::{Indexing, ProjectContext}, 10 stringtools::split_to_tokens, 11 + types::{SkidContext, Token}, 12 }; 13 14 pub fn macro_time( 15 origin_index: usize, 16 origin_line: usize, 17 context: &mut ProjectContext, 18 + _skid_context: &mut SkidContext, 19 args: &Vec<String>, 20 _scope: &[Token], 21 ) -> Vec<Token> { ··· 42 origin_index: usize, 43 origin_line: usize, 44 context: &mut ProjectContext, 45 + _skid_context: &mut SkidContext, 46 _args: &Vec<String>, 47 _scope: &[Token], 48 ) -> Vec<Token> { ··· 61 origin_index: usize, 62 _origin_line: usize, 63 context: &mut ProjectContext, 64 + _skid_context: &mut SkidContext, 65 _args: &Vec<String>, 66 _scope: &[Token], 67 ) -> Vec<Token> { ··· 80 origin_index: usize, 81 origin_line: usize, 82 context: &mut ProjectContext, 83 + _skid_context: &mut SkidContext, 84 args: &Vec<String>, 85 _scope: &[Token], 86 ) -> Vec<Token> {
+15 -15
src/macros/template.rs
··· 3 project::ProjectContext, 4 reservednames::{RESERVED_NAMES_HTML, RESERVED_NAMES_MISC}, 5 stringtools::{find_pattern, split_to_tokens, WhitespaceChecks}, 6 - types::Token, 7 }; 8 9 use super::MACRO_LIST; ··· 37 //_file: &mut InputFile, 38 origin_index: usize, 39 origin_line: usize, 40 - context: &mut ProjectContext, 41 args: &Vec<String>, 42 scope: &[Token], 43 ) -> Vec<Token> { ··· 45 46 if !self.allows_trailing_args && args.len() != self.args.len() { 47 error_skid( 48 - context, 49 origin_index, 50 origin_line, 51 &format!( ··· 59 } 60 if self.allows_trailing_args && args.len() < self.args.len() { 61 error_skid( 62 - context, 63 origin_index, 64 origin_line, 65 &format!( ··· 132 pub fn macro_template( 133 origin_index: usize, 134 origin_line: usize, 135 - context: &mut ProjectContext, 136 - templates: &mut Vec<SkidTemplate>, 137 args: &Vec<String>, 138 scope: &[Token], 139 ) -> Vec<Token> { 140 - for t in templates.iter().as_ref() { 141 if t.symbol == args[0] { 142 error_skid( 143 - context, 144 origin_index, 145 origin_line, 146 &format!("Attempted template redefinition of \"{}\"", args[0]), ··· 151 for t in MACRO_LIST { 152 if t.symbol == args[0] { 153 error_skid( 154 - context, 155 origin_index, 156 origin_line, 157 &format!( ··· 165 for r in RESERVED_NAMES_HTML { 166 if **r == args[0] { 167 error_skid( 168 - context, 169 origin_index, 170 origin_line, 171 &format!( ··· 179 for r in RESERVED_NAMES_MISC { 180 if **r == args[0] { 181 error_skid( 182 - context, 183 origin_index, 184 origin_line, 185 &format!( ··· 193 for arg in args { 194 if arg == ".." || arg == "\"..\"" { 195 error_skid( 196 - context, 197 origin_index, 198 origin_line, 199 &format!( ··· 211 } 212 if param.contains_whitespace() { 213 error_skid( 214 - context, 215 origin_index, 216 origin_line, 217 &format!( ··· 224 225 if used_params < args.len() - 1 { 226 error_skid( 227 - context, 228 origin_index, 229 origin_line, 230 &format!( ··· 237 } 238 239 let template = SkidTemplate::new(args[0].clone(), &args[1..], scope); 240 - templates.push(template); 241 242 return Vec::new(); 243 }
··· 3 project::ProjectContext, 4 reservednames::{RESERVED_NAMES_HTML, RESERVED_NAMES_MISC}, 5 stringtools::{find_pattern, split_to_tokens, WhitespaceChecks}, 6 + types::{SkidContext, Token}, 7 }; 8 9 use super::MACRO_LIST; ··· 37 //_file: &mut InputFile, 38 origin_index: usize, 39 origin_line: usize, 40 + project_context: &mut ProjectContext, 41 args: &Vec<String>, 42 scope: &[Token], 43 ) -> Vec<Token> { ··· 45 46 if !self.allows_trailing_args && args.len() != self.args.len() { 47 error_skid( 48 + project_context, 49 origin_index, 50 origin_line, 51 &format!( ··· 59 } 60 if self.allows_trailing_args && args.len() < self.args.len() { 61 error_skid( 62 + project_context, 63 origin_index, 64 origin_line, 65 &format!( ··· 132 pub fn macro_template( 133 origin_index: usize, 134 origin_line: usize, 135 + project_context: &mut ProjectContext, 136 + skid_context: &mut SkidContext, 137 args: &Vec<String>, 138 scope: &[Token], 139 ) -> Vec<Token> { 140 + for t in skid_context.templates.iter().as_ref() { 141 if t.symbol == args[0] { 142 error_skid( 143 + project_context, 144 origin_index, 145 origin_line, 146 &format!("Attempted template redefinition of \"{}\"", args[0]), ··· 151 for t in MACRO_LIST { 152 if t.symbol == args[0] { 153 error_skid( 154 + project_context, 155 origin_index, 156 origin_line, 157 &format!( ··· 165 for r in RESERVED_NAMES_HTML { 166 if **r == args[0] { 167 error_skid( 168 + project_context, 169 origin_index, 170 origin_line, 171 &format!( ··· 179 for r in RESERVED_NAMES_MISC { 180 if **r == args[0] { 181 error_skid( 182 + project_context, 183 origin_index, 184 origin_line, 185 &format!( ··· 193 for arg in args { 194 if arg == ".." || arg == "\"..\"" { 195 error_skid( 196 + project_context, 197 origin_index, 198 origin_line, 199 &format!( ··· 211 } 212 if param.contains_whitespace() { 213 error_skid( 214 + project_context, 215 origin_index, 216 origin_line, 217 &format!( ··· 224 225 if used_params < args.len() - 1 { 226 error_skid( 227 + project_context, 228 origin_index, 229 origin_line, 230 &format!( ··· 237 } 238 239 let template = SkidTemplate::new(args[0].clone(), &args[1..], scope); 240 + skid_context.templates.push(template); 241 242 return Vec::new(); 243 }
+29 -11
src/main.rs
··· 1 mod args; 2 mod console; 3 mod macros; 4 mod project; ··· 7 mod types; 8 9 use crate::{ 10 - args::ProgramArgs, macros::template::SkidTemplate, project::FileGroup, 11 - reservednames::RESERVED_NAMES_MISC, types::Expand, 12 }; 13 use clap::Parser; 14 use console::*; 15 use macros::MACRO_LIST; 16 use markdown::{CompileOptions, Constructs, Options, ParseOptions}; 17 - use project::{parse_project, FileIndexing, ProjectContext}; 18 use reservednames::RESERVED_NAMES_HTML; 19 use std::{ 20 env, ··· 25 use stringtools::{collect_arguments, collect_block, split_to_tokens, trim_whitespace_tokens}; 26 use types::{InputFile, Token}; 27 28 static DELIMITERS: &'static [char] = &[ 29 - ' ', '\n', '\t', '(', ')', '{', '}', '[', ']', '<', '>', '\\', '\'', '\"', ';', 30 ]; 31 32 fn main() { ··· 72 infile.tokens = 73 split_to_tokens(contents, project.context.index_of_file(&infile.file_input)); 74 75 process_skid( 76 &mut infile.tokens, 77 project.context.index_of_file(&infile.file_input), 78 &mut project.context, 79 - Vec::new(), 80 ); 81 } 82 } ··· 86 tokens_in: &mut [Token], 87 file_index: usize, 88 context: &mut ProjectContext, 89 - templates_base: Vec<SkidTemplate>, 90 ) -> Vec<Token> { 91 //}, context: &mut ProjectContext) { 92 //println!("{}\n {}", f.filename_out, contents); ··· 95 96 //let mut escaped = false; 97 let mut tokens = tokens_in.to_vec(); 98 - let mut templates = templates_base; 99 100 let mut working_index = 0; 101 ··· 167 tokens[working_index].origin_file, 168 tokens[working_index].line_number, 169 context, 170 - &mut templates, 171 &args, 172 &block, 173 ); ··· 182 tokens[working_index].origin_file, 183 tokens[working_index].line_number, 184 context, 185 - &mut templates, 186 &args, 187 &Vec::new()[..], 188 ); ··· 204 205 // check for templates 206 // todo maybe deduplicate this 207 - for t in &templates { 208 if &symbol[prefix_len..] == t.symbol { 209 matched_macro = true; 210 //println!("Found a macro ({})", m.symbol); ··· 306 } 307 } 308 } 309 if !matched_macro { 310 working_index += 1; 311 } 312 } 313 - 314 return tokens; 315 } 316
··· 1 mod args; 2 + mod closures; 3 mod console; 4 mod macros; 5 mod project; ··· 8 mod types; 9 10 use crate::{ 11 + args::ProgramArgs, 12 + closures::CLOSURE_LIST, 13 + macros::template::SkidTemplate, 14 + project::FileGroup, 15 + reservednames::RESERVED_NAMES_MISC, 16 + types::{Expand, SkidContext}, 17 }; 18 use clap::Parser; 19 use console::*; 20 use macros::MACRO_LIST; 21 use markdown::{CompileOptions, Constructs, Options, ParseOptions}; 22 + use project::{parse_project, Indexing, ProjectContext}; 23 use reservednames::RESERVED_NAMES_HTML; 24 use std::{ 25 env, ··· 30 use stringtools::{collect_arguments, collect_block, split_to_tokens, trim_whitespace_tokens}; 31 use types::{InputFile, Token}; 32 33 + // really need to change this whole thing to work with characters rather than 34 + // strings split on kind of abitrary chars.. 35 static DELIMITERS: &'static [char] = &[ 36 + ' ', '\n', '\t', '(', ')', '{', '}', '[', ']', '<', '>', '\\', '\'', '\"', ';', '?', '^', '-', 37 ]; 38 39 fn main() { ··· 79 infile.tokens = 80 split_to_tokens(contents, project.context.index_of_file(&infile.file_input)); 81 82 + let mut skid_context = SkidContext::new(); 83 process_skid( 84 &mut infile.tokens, 85 project.context.index_of_file(&infile.file_input), 86 &mut project.context, 87 + &mut skid_context, 88 ); 89 } 90 } ··· 94 tokens_in: &mut [Token], 95 file_index: usize, 96 context: &mut ProjectContext, 97 + skid_context: &mut SkidContext, 98 ) -> Vec<Token> { 99 //}, context: &mut ProjectContext) { 100 //println!("{}\n {}", f.filename_out, contents); ··· 103 104 //let mut escaped = false; 105 let mut tokens = tokens_in.to_vec(); 106 + let mut starting_template_count = skid_context.templates.len(); 107 108 let mut working_index = 0; 109 ··· 175 tokens[working_index].origin_file, 176 tokens[working_index].line_number, 177 context, 178 + skid_context, 179 &args, 180 &block, 181 ); ··· 190 tokens[working_index].origin_file, 191 tokens[working_index].line_number, 192 context, 193 + skid_context, 194 &args, 195 &Vec::new()[..], 196 ); ··· 212 213 // check for templates 214 // todo maybe deduplicate this 215 + for t in &skid_context.templates { 216 if &symbol[prefix_len..] == t.symbol { 217 matched_macro = true; 218 //println!("Found a macro ({})", m.symbol); ··· 314 } 315 } 316 } 317 + 318 + // Not a macro or template, look through our closures 319 + // for c in CLOSURE_LIST 320 + // { 321 + // if tokens[working_index].contents.starts_with(c.opener) 322 + // { 323 + 324 + // } 325 + // } 326 + 327 if !matched_macro { 328 working_index += 1; 329 } 330 } 331 + skid_context.templates.truncate(starting_template_count); 332 return tokens; 333 } 334
+5 -2
src/project.rs
··· 164 return project; 165 } 166 167 - pub trait FileIndexing { 168 fn index_of_file(&mut self, f: &PathBuf) -> usize; 169 fn file_for_index(&self, i: usize) -> Option<PathBuf>; 170 fn file_for_index_canonical(&self, i: usize) -> Option<&PathBuf>; 171 } 172 173 - impl FileIndexing for ProjectContext { 174 fn index_of_file(&mut self, f: &PathBuf) -> usize { 175 let cannonical = f.canonicalize().unwrap(); 176 let mut index = 0;
··· 164 return project; 165 } 166 167 + pub trait Indexing { 168 fn index_of_file(&mut self, f: &PathBuf) -> usize; 169 fn file_for_index(&self, i: usize) -> Option<PathBuf>; 170 fn file_for_index_canonical(&self, i: usize) -> Option<&PathBuf>; 171 + 172 + // fn index_of_section_name(&mut self, name: String) -> usize; 173 + // fn section_name_for_index(&self, index: usize) -> String; 174 } 175 176 + impl Indexing for ProjectContext { 177 fn index_of_file(&mut self, f: &PathBuf) -> usize { 178 let cannonical = f.canonicalize().unwrap(); 179 let mut index = 0;
+27 -11
src/types.rs
··· 1 use std::path::PathBuf; 2 3 use crate::{ ··· 11 pub origin_file: usize, 12 pub template_origin: usize, 13 pub line_number: usize, 14 } 15 16 pub struct InputFile { ··· 20 pub tokens: Vec<Token>, 21 } 22 23 - type MacroExpansion = fn( 24 - usize, 25 - usize, 26 - &mut ProjectContext, 27 - &mut Vec<SkidTemplate>, 28 - &Vec<String>, 29 - &[Token], 30 - ) -> Vec<Token>; 31 // ( 32 // origin_index: usize, 33 // origin_line: usize, ··· 51 origin_index: usize, 52 origin_line: usize, 53 context: &mut ProjectContext, 54 - templates: &mut Vec<SkidTemplate>, 55 args: &Vec<String>, 56 scope: &[Token], 57 ) -> Vec<Token>; ··· 65 origin_index: usize, 66 origin_line: usize, 67 context: &mut ProjectContext, 68 - templates: &mut Vec<SkidTemplate>, 69 args: &Vec<String>, 70 scope: &[Token], 71 ) -> Vec<Token> { ··· 74 self.symbol, args.len(), self.min_args, if self.max_args == usize::max_value() {"No Limit".to_string()} else {format!("{}", self.max_args)})); 75 Vec::new() 76 } else { 77 - (self.expansion)(origin_index, origin_line, context, templates, args, scope) 78 } 79 } 80 ··· 107 origin_file: origin_file, 108 template_origin: origin_file, 109 line_number: line_number, 110 } 111 } 112 }
··· 1 + use boa_engine::Context; 2 use std::path::PathBuf; 3 4 use crate::{ ··· 12 pub origin_file: usize, 13 pub template_origin: usize, 14 pub line_number: usize, 15 + pub section_name_index: usize, 16 } 17 18 pub struct InputFile { ··· 22 pub tokens: Vec<Token>, 23 } 24 25 + pub struct SkidContext { 26 + pub templates: Vec<SkidTemplate>, 27 + } 28 + 29 + impl SkidContext { 30 + pub fn new() -> SkidContext { 31 + SkidContext { 32 + templates: Vec::new(), 33 + } 34 + } 35 + } 36 + 37 + type MacroExpansion = 38 + fn(usize, usize, &mut ProjectContext, &mut SkidContext, &Vec<String>, &[Token]) -> Vec<Token>; 39 // ( 40 // origin_index: usize, 41 // origin_line: usize, ··· 59 origin_index: usize, 60 origin_line: usize, 61 context: &mut ProjectContext, 62 + skid_context: &mut SkidContext, 63 args: &Vec<String>, 64 scope: &[Token], 65 ) -> Vec<Token>; ··· 73 origin_index: usize, 74 origin_line: usize, 75 context: &mut ProjectContext, 76 + skid_context: &mut SkidContext, 77 args: &Vec<String>, 78 scope: &[Token], 79 ) -> Vec<Token> { ··· 82 self.symbol, args.len(), self.min_args, if self.max_args == usize::max_value() {"No Limit".to_string()} else {format!("{}", self.max_args)})); 83 Vec::new() 84 } else { 85 + (self.expansion)( 86 + origin_index, 87 + origin_line, 88 + context, 89 + skid_context, 90 + args, 91 + scope, 92 + ) 93 } 94 } 95 ··· 122 origin_file: origin_file, 123 template_origin: origin_file, 124 line_number: line_number, 125 + section_name_index: 0, 126 } 127 } 128 }