@@ -86,15 +86,25 @@ flexRate pattern c@(Completion (_,ident,_)) = do
8686-- the matchas a (start, length) tuple if there's a match.
8787-- If match fails then it would be (-1,0)
8888flexScore :: Text -> DeclIdent -> Maybe Double
89−flexScore "" _ = Nothing
9089flexScore pat str =
91− case TE.encodeUtf8 str =~ TE.encodeUtf8 pat' :: (Int, Int) of
92− (-1,0) -> Nothing
93− (start,len) -> Just $ calcScore start (start + len)
94− where
95− Just (first,pattern) = T.uncons pat
96− -- This just interleaves the search string with .*
97− -- abcd -> a.*b.*c.*d
98− pat' = first `T.cons` T.concatMap (T.snoc ".*") pattern
99− calcScore start end =
100− 100.0 / fromIntegral ((1 + start) * (end - start + 1))
90+ case T.uncons pat of
91+ Nothing -> Nothing
92+ Just (first, pattern) ->
93+ case TE.encodeUtf8 str =~ TE.encodeUtf8 pat' :: (Int, Int) of
94+ (-1,0) -> Nothing
95+ (start,len) -> Just $ calcScore start (start + len)
96+ where
97+ escapedPattern :: [Text]
98+ escapedPattern = map escape (T.unpack pattern)
99+
100+ -- escape prepends a backslash to "regexy" characters to prevent the
101+ -- matcher from crashing when trying to build the regex
102+ escape :: Char -> Text
103+ escape c = if c `elem` ("[\\^$.|?*+(){}" :: String)
104+ then T.pack ['\\', c]
105+ else T.singleton c
106+ -- This just interleaves the search pattern with .*
107+ -- abcd[*] -> a.*b.*c.*d.*[*]
108+ pat' = escape first <> foldMap (<> ".*") escapedPattern
109+ calcScore start end =
110+ 100.0 / fromIntegral ((1 + start) * (end - start + 1))