{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}

{-|

/libnotmuch/ search expressions.  See also @notmuch-search-terms(7)@.

-}
module Notmuch.Search where

import Data.Semigroup ((<>))
import GHC.Generics (Generic)

import Control.DeepSeq (NFData)
import qualified Data.ByteString.Char8 as C

import Notmuch.Tag (Tag, getTag)
import Notmuch.Binding (MessageId, ThreadId)

-- | Search expression.  Use 'Bare' if you want to use a query
-- string /as-is/ (see also @notmuch-search-terms(7)@).
--
-- Use 'show' to stringify a @SearchTerm@.
--
data SearchTerm
  = FreeForm String
  | From String
  | To String
  | Subject String
  | Attachment String -- <word>
  | Tag Tag
  | Id MessageId
  | Thread ThreadId
  | Folder String -- <maildir-folder>
  | Path String -- <directory-path>  ...  FilePath?
  | Date String String -- <since>..<until>
  | Asterisk
  | And SearchTerm SearchTerm
  | Or SearchTerm SearchTerm
  | Xor SearchTerm SearchTerm
  | Not SearchTerm
  | Bare String
  deriving ((forall x. SearchTerm -> Rep SearchTerm x)
-> (forall x. Rep SearchTerm x -> SearchTerm) -> Generic SearchTerm
forall x. Rep SearchTerm x -> SearchTerm
forall x. SearchTerm -> Rep SearchTerm x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. SearchTerm -> Rep SearchTerm x
from :: forall x. SearchTerm -> Rep SearchTerm x
$cto :: forall x. Rep SearchTerm x -> SearchTerm
to :: forall x. Rep SearchTerm x -> SearchTerm
Generic, SearchTerm -> ()
(SearchTerm -> ()) -> NFData SearchTerm
forall a. (a -> ()) -> NFData a
$crnf :: SearchTerm -> ()
rnf :: SearchTerm -> ()
NFData)

-- | Stringify a query expression.
instance Show SearchTerm where
  show :: SearchTerm -> String
show (FreeForm String
s) = String
s -- TODO quote
  show (From String
s) = String
"from:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
s
  show (To String
s) = String
"to:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
s
  show (Subject String
s) = String
"subject:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
s
  show (Attachment String
s) = String
"attachment:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
s
  show (Tag Tag
t) = String
"tag:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> MessageId -> String
C.unpack (Tag -> MessageId
getTag Tag
t)
  show (Id MessageId
s) = String
"id:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> MessageId -> String
C.unpack MessageId
s
  show (Thread MessageId
s) = String
"thread:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> MessageId -> String
C.unpack MessageId
s
  show (Folder String
s) = String
"folder:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
s
  show (Path String
s) = String
"path:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
s
  show (Date String
t String
u) = String
"date:" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
t String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
".." String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
u
  show SearchTerm
Asterisk = String
"*"
  show (And SearchTerm
a SearchTerm
b)  = String
"( " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SearchTerm -> String
forall a. Show a => a -> String
show SearchTerm
a String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" and " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SearchTerm -> String
forall a. Show a => a -> String
show SearchTerm
b String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" )"
  show (Or SearchTerm
a SearchTerm
b)   = String
"( " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SearchTerm -> String
forall a. Show a => a -> String
show SearchTerm
a String -> ShowS
forall a. Semigroup a => a -> a -> a
<>  String
" or " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SearchTerm -> String
forall a. Show a => a -> String
show SearchTerm
b String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" )"
  show (Xor SearchTerm
a SearchTerm
b)  = String
"( " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SearchTerm -> String
forall a. Show a => a -> String
show SearchTerm
a String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" xor " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SearchTerm -> String
forall a. Show a => a -> String
show SearchTerm
b String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" )"
  show (Not SearchTerm
a)    = String
"( not " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SearchTerm -> String
forall a. Show a => a -> String
show SearchTerm
a String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" )"
  show (Bare String
s)   = String
s