1use std::path;
5use texlang::parse::FileLocation;
6use texlang::traits::*;
7use texlang::*;
8
9pub fn get_input<S: TexlangState>() -> command::BuiltIn<S> {
11 command::BuiltIn::new_expansion(input_fn)
12}
13
14fn input_fn<S: TexlangState>(
15 input_token: token::Token,
16 input: &mut vm::ExpansionInput<S>,
17) -> Result<Vec<token::Token>, Box<command::Error>> {
18 let file_location = FileLocation::parse(input)?;
19 let (file_path, source_code) = read_file(input_token, input.vm(), file_location, ".tex")?;
20 input.push_source(input_token, file_path.into(), source_code)?;
21 Ok(Vec::new())
22}
23
24fn read_file<S>(
25 t: token::Token,
26 vm: &vm::VM<S>,
27 file_location: parse::FileLocation,
28 default_extension: &str,
29) -> command::Result<(String, String)> {
30 let raw_file_path = format![
31 "{}{}",
32 &file_location.path,
33 match &file_location.extension {
34 None => default_extension,
35 Some(ext) => ext,
36 }
37 ];
38 let file_path = match path::Path::new(&raw_file_path).is_absolute() {
39 true => path::Path::new(&raw_file_path).to_path_buf(),
40 false => match file_location.area {
41 None => match &vm.working_directory {
42 None => {
43 panic!("TODO: handle this error");
44 }
45 Some(working_directory) => working_directory.join(&raw_file_path),
46 },
47 Some(_area) => {
48 panic!("TODO: handle this error");
49 }
50 },
51 };
52
53 match vm.file_system.read_to_string(&file_path) {
54 Ok(s) => Ok((raw_file_path, s)),
55 Err(_err) => Err(error::SimpleTokenError::new(
56 vm,
57 t,
58 format!("could not read from {:?}", &file_path),
59 )
60 .into()), }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use crate::testing::*;
68 use std::collections::HashMap;
69
70 fn initial_commands() -> HashMap<&'static str, command::BuiltIn<State>> {
71 HashMap::from([("input", get_input())])
72 }
73
74 fn custom_vm_initialization(vm: &mut vm::VM<State>) {
75 let cwd = vm.working_directory.clone().unwrap();
76
77 let mut file_system: InMemoryFileSystem = Default::default();
78
79 let mut path_1 = cwd.to_path_buf();
80 path_1.push("file1.tex");
81 file_system.add_file(path_1, "content1\n");
82
83 let mut path_2 = cwd.to_path_buf();
84 path_2.push("file2.tex");
85 file_system.add_file(path_2, "content2%\n");
86
87 let mut path_3 = cwd.to_path_buf();
88 path_3.push("file3.tex");
89 file_system.add_file(path_3, r"\input nested/file4");
90
91 let mut path_4 = cwd.to_path_buf();
92 path_4.push("nested");
93 path_4.push("file4.tex");
94 file_system.add_file(path_4, "content4");
95
96 vm.file_system = Box::new(file_system);
97 }
98
99 test_suite!(
100 options(
101 TestOption::InitialCommands(initial_commands),
102 TestOption::CustomVMInitialization(custom_vm_initialization),
103 ),
104 expansion_equality_tests(
105 (basic_case, r"\input file1 hello", "content1 hello"),
106 (input_together, r"\input file2 hello", r"content2hello"),
107 (basic_case_with_ext, r"\input file1.tex", r"content1 "),
108 (nested, r"\input file3", r"content4"),
109 ),
110 );
111}