Skip to content

Commit 892a20f

Browse files
committed
Inline Fuzzy.match to apply [1] and to be case-sensitive on first match
[1] - joom/fuzzy#4
1 parent f131974 commit 892a20f

File tree

2 files changed

+66
-19
lines changed

2 files changed

+66
-19
lines changed

ghcide/src/Text/Fuzzy/Parallel.hs

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ module Text.Fuzzy.Parallel
55
Scored(..),
66
-- reexports
77
Fuzzy,
8-
match
98
) where
109

1110
import Control.Monad.ST (runST)
@@ -16,12 +15,58 @@ import Data.Vector (Vector, (!))
1615
import qualified Data.Vector as V
1716
-- need to use a stable sort
1817
import Data.Bifunctor (second)
19-
import Data.Maybe (fromJust)
18+
import Data.Char (toLower)
19+
import Data.Maybe (fromMaybe)
20+
import qualified Data.Monoid.Textual as T
2021
import Prelude hiding (filter)
21-
import Text.Fuzzy (Fuzzy (..), match)
22+
import Text.Fuzzy (Fuzzy (..))
2223

2324
data Scored a = Scored {score_ :: !Int, original:: !a}
24-
deriving Functor
25+
deriving (Functor,Show)
26+
27+
-- | Returns the rendered output and the
28+
-- matching score for a pattern and a text.
29+
-- Two examples are given below:
30+
--
31+
-- >>> match "fnt" "infinite" "" "" id True
32+
-- Just ("infinite",3)
33+
--
34+
-- >>> match "hsk" ("Haskell",1995) "<" ">" fst False
35+
-- Just ("<h>a<s><k>ell",5)
36+
--
37+
{-# INLINABLE match #-}
38+
39+
match :: (T.TextualMonoid s)
40+
=> s -- ^ Pattern in lowercase except for first character
41+
-> t -- ^ The value containing the text to search in.
42+
-> s -- ^ The text to add before each match.
43+
-> s -- ^ The text to add after each match.
44+
-> (t -> s) -- ^ The function to extract the text from the container.
45+
-> Maybe (Fuzzy t s) -- ^ The original value, rendered string and score.
46+
match pattern t pre post extract =
47+
if null pat then Just (Fuzzy t result totalScore) else Nothing
48+
where
49+
null :: (T.TextualMonoid s) => s -> Bool
50+
null = not . T.any (const True)
51+
52+
s = extract t
53+
(totalScore, _currScore, result, pat, _) =
54+
T.foldl'
55+
undefined
56+
(\(tot, cur, res, pat, isFirst) c ->
57+
case T.splitCharacterPrefix pat of
58+
Nothing -> (tot, 0, res <> T.singleton c, pat, isFirst)
59+
Just (x, xs) ->
60+
-- the case of the first character has to match
61+
-- otherwise use lower case since the pattern is assumed lower
62+
let !c' = if isFirst then c else toLower c in
63+
if x == c' then
64+
let cur' = cur * 2 + 1 in
65+
(tot + cur', cur', res <> pre <> T.singleton c <> post, xs, False)
66+
else (tot, 0, res <> T.singleton c, pat, isFirst)
67+
) ( 0
68+
, 1 -- matching at the start gives a bonus (cur = 1)
69+
, mempty, pattern, True) s
2570

2671
-- | The function to filter a list of values by fuzzy search on the text extracted from them.
2772
filter :: (TextualMonoid s)
@@ -32,15 +77,20 @@ filter :: (TextualMonoid s)
3277
-> s -- ^ The text to add before each match.
3378
-> s -- ^ The text to add after each match.
3479
-> (t -> s) -- ^ The function to extract the text from the container.
35-
-> Bool -- ^ Case sensitivity.
3680
-> [Scored t] -- ^ The list of results, sorted, highest score first.
37-
filter chunkSize maxRes pattern ts pre post extract caseSen = runST $ do
81+
filter chunkSize maxRes pattern ts pre post extract = runST $ do
3882
let v = V.mapMaybe id
39-
(V.map (\t -> match pattern t pre post extract caseSen) (V.fromList ts)
83+
(V.map (\t -> match pattern' t pre post extract) (V.fromList ts)
4084
`using`
4185
parVectorChunk chunkSize (evalTraversable forceScore))
42-
perfectScore = score $ fromJust $ match pattern pattern "" "" id False
86+
perfectScore = score $ fromMaybe (error $ T.toString undefined pattern) $
87+
match pattern' pattern' "" "" id
4388
return $ partialSortByAscScore maxRes perfectScore v
89+
where
90+
-- Preserve case for the first character, make all others lowercase
91+
pattern' = case T.splitCharacterPrefix pattern of
92+
Just (c, rest) -> T.singleton c <> T.map toLower rest
93+
_ -> pattern
4494

4595
-- | Return all elements of the list that have a fuzzy
4696
-- match against the pattern. Runs with default settings where
@@ -56,7 +106,7 @@ simpleFilter :: (TextualMonoid s)
56106
-> [s] -- ^ List of texts to check.
57107
-> [Scored s] -- ^ The ones that match.
58108
simpleFilter chunk maxRes pattern xs =
59-
filter chunk maxRes pattern xs mempty mempty id False
109+
filter chunk maxRes pattern xs mempty mempty id
60110

61111
--------------------------------------------------------------------------------
62112

ghcide/test/exe/Main.hs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4189,15 +4189,13 @@ topLevelCompletionTests = [
41894189
"variable"
41904190
["bar = xx", "-- | haddock", "xxx :: ()", "xxx = ()", "-- | haddock", "data Xxx = XxxCon"]
41914191
(Position 0 8)
4192-
[("xxx", CiFunction, "xxx", True, True, Nothing),
4193-
("XxxCon", CiConstructor, "XxxCon", False, True, Nothing)
4192+
[("xxx", CiFunction, "xxx", True, True, Nothing)
41944193
],
41954194
completionTest
41964195
"constructor"
41974196
["bar = xx", "-- | haddock", "xxx :: ()", "xxx = ()", "-- | haddock", "data Xxx = XxxCon"]
41984197
(Position 0 8)
4199-
[("xxx", CiFunction, "xxx", True, True, Nothing),
4200-
("XxxCon", CiConstructor, "XxxCon", False, True, Nothing)
4198+
[("xxx", CiFunction, "xxx", True, True, Nothing)
42014199
],
42024200
completionTest
42034201
"class method"
@@ -4311,10 +4309,9 @@ nonLocalCompletionTests =
43114309
[("head", CiFunction, "head ${1:([a])}", True, True, Nothing)],
43124310
completionTest
43134311
"constructor"
4314-
["module A where", "f = Tru"]
4315-
(Position 1 7)
4316-
[ ("True", CiConstructor, "True ", True, True, Nothing),
4317-
("truncate", CiFunction, "truncate ${1:a}", True, True, Nothing)
4312+
["{-# OPTIONS_GHC -Wall #-}", "module A where", "f = True"]
4313+
(Position 2 8)
4314+
[ ("True", CiConstructor, "True ", True, True, Nothing)
43184315
],
43194316
completionTest
43204317
"type"
@@ -4331,8 +4328,8 @@ nonLocalCompletionTests =
43314328
],
43324329
completionTest
43334330
"duplicate import"
4334-
["module A where", "import Data.List", "import Data.List", "f = perm"]
4335-
(Position 3 8)
4331+
["module A where", "import Data.List", "import Data.List", "f = permu"]
4332+
(Position 3 9)
43364333
[ ("permutations", CiFunction, "permutations ${1:([a])}", False, False, Nothing)
43374334
],
43384335
completionTest

0 commit comments

Comments
 (0)