diff --git a/lib/Backend/Commands.hs b/lib/Backend/Commands.hs index 181f4ec3..d7f68969 100644 --- a/lib/Backend/Commands.hs +++ b/lib/Backend/Commands.hs @@ -176,7 +176,7 @@ deleteFieldCmd config (DeleteFieldOptions qPath@(QualifiedPath backendNameMb pat findCmd :: (Members '[BackendEffect, Error CofferError] r) => Config -> FindOptions -> Sem r (Maybe Directory) -findCmd config (FindOptions qPathMb textMb sortMb filters filterFields) = do +findCmd config (FindOptions qPathMb textMb sortMb filters) = do let backendNameMb = qPathMb >>= qpBackendName backend <- getBackend config backendNameMb let @@ -196,9 +196,10 @@ findCmd config (FindOptions qPathMb textMb sortMb filters filterFields) = do applyFilter e = \case FilterByName substr -> substr `T.isInfixOf` (e ^. E.path . to entryPathName) FilterByDate op date -> matchDate op date (e ^. dateModified) + FilterByField name field -> applyFilterField e name field - applyFilterField :: Entry -> (FieldName, FilterField) -> Bool - applyFilterField e (fieldName, filter) = + applyFilterField :: Entry -> FieldName -> FilterField -> Bool + applyFilterField e fieldName filter = case e ^? fields . ix fieldName of Nothing -> False Just field -> @@ -217,7 +218,6 @@ findCmd config (FindOptions qPathMb textMb sortMb filters filterFields) = do & Dir.filterEntries (\e -> (filterByPath e || filterByTag e) && all (applyFilter e) filters - && all (applyFilterField e) filterFields ) & Dir.mapDir (\entries -> case sortMb of diff --git a/lib/CLI/Parser.hs b/lib/CLI/Parser.hs index 80bcddf5..481e307e 100644 --- a/lib/CLI/Parser.hs +++ b/lib/CLI/Parser.hs @@ -35,6 +35,7 @@ import Entry import Fmt (pretty) import Options.Applicative import Options.Applicative.Help.Pretty qualified as Pretty +import Text.Megaparsec (try) import Text.Megaparsec qualified as P import Text.Megaparsec.Char qualified as P import Text.Megaparsec.Char.Lexer qualified as P @@ -233,14 +234,6 @@ findOptions = , expectedFilterFormat ] ]) - <*> many (option readFilterField $ mconcat - [ metavar "FILTERFIELD" - , long "filter-field" - , helpDoc $ Just $ Pretty.vsep - [ "Filter entries based on a field." - , expectedFilterFieldFormat - ] - ]) renameOptions :: Parser RenameOptions renameOptions = @@ -505,29 +498,14 @@ expectedQualifiedPathFormat = Pretty.vsep expectedFilterFormat :: Pretty.Doc expectedFilterFormat = Pretty.vsep - [ "Expected format is: 'name~' or `date`." - , " can be '<=', '>=', '<', '>', or '='." - , " can be 'YYYY', 'YYYY-MM', 'YYYY-MM-DD', or 'YYYY-MM-DD HH:MM:SS'." - , "Examples: 'name~vault', 'date<2020-02'." - ] - -readFilterField :: ReadM (FieldName, FilterField) -readFilterField = do - eitherReader \input -> - P.parse (parseFilterField <* P.eof) "" (T.pack input) & first \err -> unlines - [ "Invalid filter-field format: " <> show input <> "." - , show expectedFilterFieldFormat - , "" - , "Parser error:" - , P.errorBundlePretty err - ] - -expectedFilterFieldFormat :: Pretty.Doc -expectedFilterFieldFormat = Pretty.vsep - [ "Expected format is: ':contents~' or `:date`." + [ "Expected format is:" + , " * to filter by entry name: 'name~'," + , " * to filter by entry's last modified date: 'date'," + , " * to filter by a field's contents: ':contents~'," + , " * to filter by a field's last modified date: ':date'." , " can be '<=', '>=', '<', '>', or '='." , " can be 'YYYY', 'YYYY-MM', 'YYYY-MM-DD', or 'YYYY-MM-DD HH:MM:SS'." - , "Examples: 'url:contents~google.com', 'pw:date<2020-02'." + , "Examples: 'name~vault', 'date<2020-02', 'url:contents~google.com', 'pw:date<2020-02'." ] ---------------------------------------------------------------------------- @@ -588,7 +566,7 @@ parseFilterOp = parseFilter :: MParser Filter parseFilter = - parseFilterByName <|> parseFilterByDate + try parseFilterByName <|> try parseFilterByDate <|> parseFilterByField where parseFilterByName = do void $ P.string "name" >> P.char '~' @@ -601,13 +579,12 @@ parseFilter = localTime <- parseFilterDate pure $ FilterByDate op localTime -parseFilterField :: MParser (FieldName, FilterField) -parseFilterField = do +parseFilterByField :: MParser Filter +parseFilterByField = do fieldName <- parseFieldNameWhile (/= ':') void $ P.char ':' filterField <- parseFilterFieldByContents <|> parseFilterFieldByDate - - pure (fieldName, filterField) + pure $ FilterByField fieldName filterField where parseFilterFieldByContents = do void $ P.string "contents" >> P.char '~' diff --git a/lib/CLI/Types.hs b/lib/CLI/Types.hs index 078d986a..293b8e2d 100644 --- a/lib/CLI/Types.hs +++ b/lib/CLI/Types.hs @@ -126,7 +126,6 @@ data FindOptions = FindOptions , foText :: Maybe Text , foSort :: Maybe (Sort, Direction) , foFilters :: [Filter] - , foFilterFields :: [(FieldName, FilterField)] } deriving stock Show @@ -193,6 +192,7 @@ data FilterDate data Filter = FilterByDate FilterOp FilterDate | FilterByName Text + | FilterByField FieldName FilterField deriving stock Show data FilterField diff --git a/tests/golden/common/common.bats b/tests/golden/common/common.bats index d816e3d4..99c8fb6c 100644 --- a/tests/golden/common/common.bats +++ b/tests/golden/common/common.bats @@ -110,10 +110,10 @@ EOF } @test "bad filter field" { - run coffer find --filter-field "$(echo -e "name:bad\n\n~str")" + run coffer find --filter "$(echo -e "name:bad\n\n~str")" assert_failure assert_output --partial - <1000" --filter name~a + + assert_success + assert_output - <