@@ -73,6 +73,7 @@ enum Op {
7373 Compose ( Vec < Filter > ) ,
7474 Chain ( Filter , Filter ) ,
7575 Subtract ( Filter , Filter ) ,
76+ Exclude ( Filter ) ,
7677}
7778
7879/// Pretty print the filter on multiple lines with initial indentation level.
@@ -113,10 +114,10 @@ fn pretty2(op: &Op, indent: usize, compose: bool) -> String {
113114 } ;
114115 match op {
115116 Op :: Compose ( filters) => ff ( filters, "" , indent) ,
116- Op :: Subtract ( af, bf) => match ( to_op ( * af) , to_op ( * bf) ) {
117- ( Op :: Nop , Op :: Compose ( filters ) ) => ff ( & filters , "exclude" , indent ) ,
118- ( Op :: Nop , b ) => format ! ( ": exclude[{}] ", pretty2 ( & b , indent, false ) ) ,
119- _ => ff ( & vec ! [ * af , * bf ] , "subtract" , indent + 4 ) ,
117+ Op :: Subtract ( af, bf) => ff ( & vec ! [ * af, * bf] , "subtract" , indent + 4 ) ,
118+ Op :: Exclude ( bf ) => match to_op ( * bf ) {
119+ Op :: Compose ( filters ) => ff ( & filters , " exclude", indent) ,
120+ b => format ! ( ":exclude[{}]" , pretty2 ( & b , indent, false ) ) ,
120121 } ,
121122 Op :: Chain ( a, b) => match ( to_op ( * a) , to_op ( * b) ) {
122123 ( Op :: Subdir ( p1) , Op :: Prefix ( p2) ) if p1 == p2 => {
@@ -157,6 +158,9 @@ fn spec2(op: &Op) -> String {
157158 Op :: Subtract ( a, b) => {
158159 format ! ( ":subtract[{},{}]" , spec( * a) , spec( * b) )
159160 }
161+ Op :: Exclude ( b) => {
162+ format ! ( ":exclude[{}]" , spec( * b) )
163+ }
160164 Op :: Workspace ( path) => {
161165 format ! ( ":workspace={}" , path. to_string_lossy( ) )
162166 }
@@ -389,9 +393,21 @@ fn apply_to_commit2(
389393 } ;
390394 let bf = repo. find_tree ( bf) ?;
391395 let bu = unapply ( transaction, * b, bf, tree:: empty ( repo) ) ?;
392- let ba = apply ( transaction, * a, bu) ?;
393-
394- repo. find_tree ( tree:: subtract ( repo, af, ba. id ( ) ) ?) ?
396+ let ba = apply ( transaction, * a, bu) ?. id ( ) ;
397+ repo. find_tree ( tree:: subtract ( repo, af, ba) ?) ?
398+ }
399+ Op :: Exclude ( b) => {
400+ let bf = {
401+ transaction
402+ . repo ( )
403+ . find_commit ( some_or ! (
404+ apply_to_commit2( & to_op( * b) , commit, transaction) ?,
405+ { return Ok ( None ) }
406+ ) )
407+ . map ( |x| x. tree_id ( ) )
408+ . unwrap_or ( tree:: empty_id ( ) )
409+ } ;
410+ repo. find_tree ( tree:: subtract ( repo, commit. tree_id ( ) , bf) ?) ?
395411 }
396412 _ => apply ( transaction, filter, commit. tree ( ) ?) ?,
397413 } ;
@@ -476,8 +492,12 @@ fn apply2<'a>(
476492 let af = apply ( transaction, * a, tree. clone ( ) ) ?;
477493 let bf = apply ( transaction, * b, tree. clone ( ) ) ?;
478494 let bu = unapply ( transaction, * b, bf, tree:: empty ( repo) ) ?;
479- let ba = apply ( transaction, * a, bu) ?;
480- Ok ( repo. find_tree ( tree:: subtract ( repo, af. id ( ) , ba. id ( ) ) ?) ?)
495+ let ba = apply ( transaction, * a, bu) ?. id ( ) ;
496+ Ok ( repo. find_tree ( tree:: subtract ( repo, af. id ( ) , ba) ?) ?)
497+ }
498+ Op :: Exclude ( b) => {
499+ let bf = apply ( transaction, * b, tree. clone ( ) ) ?. id ( ) ;
500+ Ok ( repo. find_tree ( tree:: subtract ( repo, tree. id ( ) , bf) ?) ?)
481501 }
482502
483503 Op :: Paths => tree:: pathstree ( "" , tree. id ( ) , transaction) ,
@@ -640,21 +660,19 @@ fn unapply2<'a>(
640660 }
641661 }
642662
643- Op :: Subtract ( a, b) => match ( to_op ( * a) , to_op ( * b) ) {
644- ( Op :: Nop , b) => {
645- let subtracted = tree:: subtract (
646- transaction. repo ( ) ,
647- tree. id ( ) ,
648- unapply2 ( transaction, & b, tree, tree:: empty ( transaction. repo ( ) ) ) ?. id ( ) ,
649- ) ?;
650- Ok ( transaction. repo ( ) . find_tree ( tree:: overlay (
651- transaction. repo ( ) ,
652- parent_tree. id ( ) ,
653- subtracted,
654- ) ?) ?)
655- }
656- _ => return Err ( josh_error ( "filter not reversible" ) ) ,
657- } ,
663+ Op :: Subtract ( _, _) => return Err ( josh_error ( "filter not reversible" ) ) ,
664+ Op :: Exclude ( b) => {
665+ let subtracted = tree:: subtract (
666+ transaction. repo ( ) ,
667+ tree. id ( ) ,
668+ unapply ( transaction, * b, tree, tree:: empty ( transaction. repo ( ) ) ) ?. id ( ) ,
669+ ) ?;
670+ Ok ( transaction. repo ( ) . find_tree ( tree:: overlay (
671+ transaction. repo ( ) ,
672+ parent_tree. id ( ) ,
673+ subtracted,
674+ ) ?) ?)
675+ }
658676 Op :: Glob ( pattern) => {
659677 let pattern = glob:: Pattern :: new ( pattern) ?;
660678 let options = glob:: MatchOptions {
0 commit comments