From 16a27dba874699d521681c860fddc440865f6bf8 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 25 May 2024 18:10:06 -0700 Subject: [PATCH] List unsorted imported recipes by import depth and offset (#2092) --- src/compiler.rs | 4 +- src/justfile.rs | 11 +--- src/parser.rs | 6 ++ src/recipe.rs | 2 + src/source.rs | 11 +++- src/testing.rs | 1 + src/unresolved_recipe.rs | 1 + tests/list.rs | 123 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 147 insertions(+), 12 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 066c135b..9eaf985b 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -23,6 +23,7 @@ impl Compiler { let mut ast = Parser::parse( current.file_depth, ¤t.path, + ¤t.import_offsets, ¤t.namepath, current.submodule_depth, &tokens, @@ -94,7 +95,7 @@ impl Compiler { }); } *absolute = Some(import.clone()); - stack.push(current.import(import)); + stack.push(current.import(import, path.offset)); } else if !*optional { return Err(Error::MissingImportFile { path: *path }); } @@ -172,6 +173,7 @@ impl Compiler { let ast = Parser::parse( 0, &PathBuf::new(), + &[], &Namepath::default(), 0, &tokens, diff --git a/src/justfile.rs b/src/justfile.rs index 57fdb54e..a74a94c1 100644 --- a/src/justfile.rs +++ b/src/justfile.rs @@ -495,16 +495,7 @@ impl<'src> Justfile<'src> { .collect::>>(); if config.unsorted { - recipes.sort_by_key(|recipe| { - ( - self - .loaded - .iter() - .position(|path| path == recipe.name.path) - .unwrap(), - recipe.name.offset, - ) - }); + recipes.sort_by_key(|recipe| (&recipe.import_offsets, recipe.name.offset)); } recipes diff --git a/src/parser.rs b/src/parser.rs index 9b907d34..3a05fea5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -27,6 +27,7 @@ pub(crate) struct Parser<'run, 'src> { expected_tokens: BTreeSet, file_depth: u32, file_path: &'run Path, + import_offsets: Vec, module_namepath: &'run Namepath<'src>, next_token: usize, recursion_depth: usize, @@ -40,6 +41,7 @@ impl<'run, 'src> Parser<'run, 'src> { pub(crate) fn parse( file_depth: u32, file_path: &'run Path, + import_offsets: &[usize], module_namepath: &'run Namepath<'src>, submodule_depth: u32, tokens: &'run [Token<'src>], @@ -49,6 +51,7 @@ impl<'run, 'src> Parser<'run, 'src> { expected_tokens: BTreeSet::new(), file_depth, file_path, + import_offsets: import_offsets.to_vec(), module_namepath, next_token: 0, recursion_depth: 0, @@ -801,6 +804,7 @@ impl<'run, 'src> Parser<'run, 'src> { doc, file_depth: self.file_depth, file_path: self.file_path.into(), + import_offsets: self.import_offsets.clone(), name, namepath: self.module_namepath.join(name), parameters: positional.into_iter().chain(variadic).collect(), @@ -1040,6 +1044,7 @@ mod tests { let justfile = Parser::parse( 0, &PathBuf::new(), + &[], &Namepath::default(), 0, &tokens, @@ -1086,6 +1091,7 @@ mod tests { match Parser::parse( 0, &PathBuf::new(), + &[], &Namepath::default(), 0, &tokens, diff --git a/src/recipe.rs b/src/recipe.rs index f974e394..62c6d279 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -27,6 +27,8 @@ pub(crate) struct Recipe<'src, D = Dependency<'src>> { pub(crate) file_depth: u32, #[serde(skip)] pub(crate) file_path: PathBuf, + #[serde(skip)] + pub(crate) import_offsets: Vec, pub(crate) name: Name<'src>, pub(crate) namepath: Namepath<'src>, pub(crate) parameters: Vec>, diff --git a/src/source.rs b/src/source.rs index 00754215..f81ae0ba 100644 --- a/src/source.rs +++ b/src/source.rs @@ -4,6 +4,7 @@ use super::*; pub(crate) struct Source<'src> { pub(crate) file_depth: u32, pub(crate) file_path: Vec, + pub(crate) import_offsets: Vec, pub(crate) namepath: Namepath<'src>, pub(crate) path: PathBuf, pub(crate) submodule_depth: u32, @@ -15,6 +16,7 @@ impl<'src> Source<'src> { Self { file_depth: 0, file_path: vec![path.into()], + import_offsets: Vec::new(), namepath: Namepath::default(), path: path.into(), submodule_depth: 0, @@ -22,7 +24,7 @@ impl<'src> Source<'src> { } } - pub(crate) fn import(&self, path: PathBuf) -> Self { + pub(crate) fn import(&self, path: PathBuf, import_offset: usize) -> Self { Self { file_depth: self.file_depth + 1, file_path: self @@ -31,6 +33,12 @@ impl<'src> Source<'src> { .into_iter() .chain(iter::once(path.clone())) .collect(), + import_offsets: self + .import_offsets + .iter() + .copied() + .chain(iter::once(import_offset)) + .collect(), namepath: self.namepath.clone(), path, submodule_depth: self.submodule_depth, @@ -47,6 +55,7 @@ impl<'src> Source<'src> { .into_iter() .chain(iter::once(path.clone())) .collect(), + import_offsets: Vec::new(), namepath: self.namepath.join(name), path: path.clone(), submodule_depth: self.submodule_depth + 1, diff --git a/src/testing.rs b/src/testing.rs index 9a60ecd8..a5977692 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -62,6 +62,7 @@ pub(crate) fn analysis_error( let ast = Parser::parse( 0, &PathBuf::new(), + &[], &Namepath::default(), 0, &tokens, diff --git a/src/unresolved_recipe.rs b/src/unresolved_recipe.rs index 80d49045..af076f20 100644 --- a/src/unresolved_recipe.rs +++ b/src/unresolved_recipe.rs @@ -51,6 +51,7 @@ impl<'src> UnresolvedRecipe<'src> { doc: self.doc, file_depth: self.file_depth, file_path: self.file_path, + import_offsets: self.import_offsets, name: self.name, namepath: self.namepath, parameters: self.parameters, diff --git a/tests/list.rs b/tests/list.rs index 2b40ca47..9d073608 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -131,3 +131,126 @@ fn nested_modules_are_properly_indented() { ) .run(); } + +#[test] +fn unsorted_list_order() { + Test::new() + .write("a.just", "a:") + .write("b.just", "b:") + .write("c.just", "c:") + .write("d.just", "d:") + .justfile( + " + import 'a.just' + import 'b.just' + import 'c.just' + import 'd.just' + x: + y: + z: + ", + ) + .args(["--list", "--unsorted"]) + .stdout( + " + Available recipes: + x + y + z + a + b + c + d + ", + ) + .run(); + + Test::new() + .write("a.just", "a:") + .write("b.just", "b:") + .write("c.just", "c:") + .write("d.just", "d:") + .justfile( + " + x: + y: + z: + import 'd.just' + import 'c.just' + import 'b.just' + import 'a.just' + ", + ) + .args(["--list", "--unsorted"]) + .stdout( + " + Available recipes: + x + y + z + d + c + b + a + ", + ) + .run(); + + Test::new() + .write("a.just", "a:\nimport 'e.just'") + .write("b.just", "b:\nimport 'f.just'") + .write("c.just", "c:\nimport 'g.just'") + .write("d.just", "d:\nimport 'h.just'") + .write("e.just", "e:") + .write("f.just", "f:") + .write("g.just", "g:") + .write("h.just", "h:") + .justfile( + " + x: + y: + z: + import 'd.just' + import 'c.just' + import 'b.just' + import 'a.just' + ", + ) + .args(["--list", "--unsorted"]) + .stdout( + " + Available recipes: + x + y + z + d + h + c + g + b + f + a + e + ", + ) + .run(); + + Test::new() + .write("task1.just", "task1:") + .write("task2.just", "task2:") + .justfile( + " + import 'task1.just' + import 'task2.just' + ", + ) + .args(["--list", "--unsorted"]) + .stdout( + " + Available recipes: + task1 + task2 + ", + ) + .run(); +}