module XMonad.Prompt.FuzzyMatch (
fuzzyMatch
, fuzzySort
) where
import XMonad.Prelude
import qualified Data.List.NonEmpty as NE
fuzzyMatch :: String -> String -> Bool
fuzzyMatch :: String -> String -> Bool
fuzzyMatch String
a String
b = forall a. Eq a => [a] -> [a] -> Bool
isSubsequenceOf (forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
a) (forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
b)
fuzzySort :: String -> [String] -> [String]
fuzzySort :: String -> [String] -> [String]
fuzzySort String
q = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Ord a => [a] -> [a]
sort forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> ((Int, Int), String)
rankMatch String
q)
rankMatch :: String -> String -> ((Int, Int), String)
rankMatch :: String -> String -> ((Int, Int), String)
rankMatch String
q String
s = (if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Int, Int)]
matches then (forall a. Bounded a => a
maxBound, forall a. Bounded a => a
maxBound) else forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [(Int, Int)]
matches, String
s)
where matches :: [(Int, Int)]
matches = String -> String -> [(Int, Int)]
rankMatches String
q String
s
rankMatches :: String -> String -> [(Int, Int)]
rankMatches :: String -> String -> [(Int, Int)]
rankMatches [] String
_ = [(Int
0, Int
0)]
rankMatches (Char
q:String
qs) String
s = forall a b. (a -> b) -> [a] -> [b]
map (\(Int
l, Int
r) -> (Int
r forall a. Num a => a -> a -> a
- Int
l, Int
l)) forall a b. (a -> b) -> a -> b
$ NonEmpty Char -> String -> [(Int, Int)]
findShortestMatches (Char
q forall a. a -> [a] -> NonEmpty a
:| String
qs) String
s
findShortestMatches :: NonEmpty Char -> String -> [(Int, Int)]
findShortestMatches :: NonEmpty Char -> String -> [(Int, Int)]
findShortestMatches NonEmpty Char
q String
s = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' [(Int, Int)] -> [Int] -> [(Int, Int)]
extendMatches [(Int, Int)]
spans [[Int]]
oss
where ([Int]
os :| [[Int]]
oss) = forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
NE.map (String -> Char -> [Int]
findOccurrences String
s) NonEmpty Char
q
spans :: [(Int, Int)]
spans = [(Int
o, Int
o) | Int
o <- [Int]
os]
findOccurrences :: String -> Char -> [Int]
findOccurrences :: String -> Char -> [Int]
findOccurrences String
s Char
c = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
filter ((Char -> Char
toLower Char
c forall a. Eq a => a -> a -> Bool
==) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Char
toLower forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) forall a b. (a -> b) -> a -> b
$ forall a b. [a] -> [b] -> [(a, b)]
zip String
s [Int
0..]
extendMatches :: [(Int, Int)] -> [Int] -> [(Int, Int)]
extendMatches :: [(Int, Int)] -> [Int] -> [(Int, Int)]
extendMatches [(Int, Int)]
spans = forall a b. (a -> b) -> [a] -> [b]
map forall a. [a] -> a
last forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall a b. (a, b) -> b
snd) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Int, Int)] -> [Int] -> [(Int, Int)]
extendMatches' [(Int, Int)]
spans
extendMatches' :: [(Int, Int)] -> [Int] -> [(Int, Int)]
extendMatches' :: [(Int, Int)] -> [Int] -> [(Int, Int)]
extendMatches' [] [Int]
_ = []
extendMatches' [(Int, Int)]
_ [] = []
extendMatches' spans :: [(Int, Int)]
spans@((Int
l, Int
r):[(Int, Int)]
spans') xs :: [Int]
xs@(Int
x:[Int]
xs') | Int
r forall a. Ord a => a -> a -> Bool
< Int
x = (Int
l, Int
x) forall a. a -> [a] -> [a]
: [(Int, Int)] -> [Int] -> [(Int, Int)]
extendMatches' [(Int, Int)]
spans' [Int]
xs
| Bool
otherwise = [(Int, Int)] -> [Int] -> [(Int, Int)]
extendMatches' [(Int, Int)]
spans [Int]
xs'