tag icon indicating copy to clipboard operation
tag copied to clipboard

Add invert-find operation mode

Open dstadulis opened this issue 1 year ago • 1 comments

These changes introduce a new feature to the tag command-line tool: the ability to find files that do not contain any of the specified tags. This is achieved through the addition of two new operation modes:

  1. OperationModeInvertFind: This mode is triggered by the -F or --invert-find option, and it causes the tool to search for files that do not contain any of the specified tags.
  2. A new method called doInvertFind is added to the Tag class to handle this operation mode. This method calls another new method called findFilesWithoutTagWithUsage:NO, which performs the actual file search.

The changes also modify the existing help text and man page to document the new feature.

Here's a summary of the key changes:

  • Added two new operation modes: OperationModeInvertFind and a new method doInvertFind to handle it.
  • Modified the existing help text and man page to document the new feature.
  • Introduced a new method called findFilesWithoutTagWithUsage:NO, which performs the actual file search for files that do not contain any of the specified tags.

Demonstrating these changes enable users to find files that do not contain specific tags:

$ ./tag(invert_find) bin/tag -F red .
./tag/LICENSE
./tag/Makefile
./tag/README.md
./tag/Tag
./tag/Tag/Tag.h
./tag/Tag/Tag.m
./tag/Tag.xcodeproj
./tag/Tag/TagName.h
./tag/Tag/TagName.m
./tag/bin
./tag/Tag/main.m
./tag/bin/tag
./tag/Tag/tag.1

$ # Set red to ./tag/bin/tag and confirm file no longer is returned from -F search
$ ./tag(invert_find) bin/tag -s red bin/tag
$ ./tag(invert_find) bin/tag --invert-find red .
./tag/LICENSE
./tag/Makefile
./tag/README.md
./tag/Tag
./tag/Tag/Tag.h
./tag/Tag/Tag.m
./tag/Tag.xcodeproj
./tag/Tag/TagName.h
./tag/Tag/TagName.m
./tag/bin
./tag/Tag/main.m
./tag/Tag/tag.1

$ # Success! ./tag/bin/tag no longer is returned from -F search (above)
$ ./tag(invert_find) bin/tag -f red .
./tag/bin/tag

dstadulis avatar Jul 29 '24 05:07 dstadulis

Instead of searching for files and then post-qualifying them to those that don't contain the tags, is is possible to make this work by forming the metadata query to search for those without tags in the first place?

Currently the code does this:

    else // if tagSet count > 0
    {
        NSMutableArray* subpredicates = [NSMutableArray new];
        for (TagName* tag in tagSet)
            [subpredicates addObject:[NSPredicate predicateWithFormat:@"%K ==[c] %@", kMDItemUserTags, tag.visibleName]];
        result = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
    }

Is it possible to make something like this work?

    else // if tagSet count > 0
    {
        NSMutableArray* subpredicates = [NSMutableArray new];
        for (TagName* tag in tagSet)
            if negativeTagSearch {
                [subpredicates addObject:[NSPredicate predicateWithFormat:@"%K !=[c] %@", kMDItemUserTags, tag.visibleName]];
            } else {
                [subpredicates addObject:[NSPredicate predicateWithFormat:@"%K ==[c] %@", kMDItemUserTags, tag.visibleName]];
            }
        result = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
    }

jdberry avatar Jul 29 '24 13:07 jdberry