Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cabal file completions #3268

Merged
merged 2 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ghcide/src/Development/IDE/Plugin/Completions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import qualified Language.LSP.Protocol.Lens as L
import Language.LSP.Protocol.Message
import Language.LSP.Protocol.Types
import qualified Language.LSP.Server as LSP
import qualified Language.LSP.VFS as VFS
import Numeric.Natural
import Text.Fuzzy.Parallel (Scored (..))

Expand Down
76 changes: 56 additions & 20 deletions ghcide/src/Text/Fuzzy/Parallel.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
-- | Parallel versions of 'filter' and 'simpleFilter'

module Text.Fuzzy.Parallel
( filter,
simpleFilter,
match,
( filter, filter',
simpleFilter, simpleFilter',
match, defChunkSize, defMaxResults,
Scored(..)
) where

Expand All @@ -29,7 +29,6 @@ data Scored a = Scored {score :: !Int, original:: !a}
-- Just 5
--
{-# INLINABLE match #-}

match :: T.Text -- ^ Pattern in lowercase except for first character
-> T.Text -- ^ The text to search in.
-> Maybe Int -- ^ The score
Expand Down Expand Up @@ -70,22 +69,13 @@ match (T.Text pArr pOff pLen) (T.Text sArr sOff sLen) = go 0 1 pOff sOff

toLowerAscii w = if (w - 65) < 26 then w .|. 0x20 else w

-- | The function to filter a list of values by fuzzy search on the text extracted from them.
filter :: Int -- ^ Chunk size. 1000 works well.
-> Int -- ^ Max. number of results wanted
-> T.Text -- ^ Pattern.
-> [t] -- ^ The list of values containing the text to search in.
-> (t -> T.Text) -- ^ The function to extract the text from the container.
-> [Scored t] -- ^ The list of results, sorted, highest score first.
filter chunkSize maxRes pattern ts extract = partialSortByAscScore maxRes perfectScore (concat vss)
where
-- Preserve case for the first character, make all others lowercase
pattern' = case T.uncons pattern of
Just (c, rest) -> T.cons c (T.toLower rest)
_ -> pattern
vss = map (mapMaybe (\t -> flip Scored t <$> match pattern' (extract t))) (chunkList chunkSize ts)
`using` parList (evalList rseq)
perfectScore = fromMaybe (error $ T.unpack pattern) $ match pattern' pattern'
-- | Sensible default value for chunk size to use when calling simple filter.
defChunkSize :: Int
defChunkSize = 1000

-- | Sensible default value for the number of max results to use when calling simple filter.
defMaxResults :: Int
defMaxResults = 10

-- | Return all elements of the list that have a fuzzy
-- match against the pattern. Runs with default settings where
Expand All @@ -102,6 +92,52 @@ simpleFilter :: Int -- ^ Chunk size. 1000 works well.
simpleFilter chunk maxRes pattern xs =
filter chunk maxRes pattern xs id


-- | The function to filter a list of values by fuzzy search on the text extracted from them,
-- using a custom matching function which determines how close words are.
filter' :: Int -- ^ Chunk size. 1000 works well.
-> Int -- ^ Max. number of results wanted
-> T.Text -- ^ Pattern.
-> [t] -- ^ The list of values containing the text to search in.
-> (t -> T.Text) -- ^ The function to extract the text from the container.
-> (T.Text -> T.Text -> Maybe Int)
-- ^ Custom scoring function to use for calculating how close words are
-- When the function returns Nothing, this means the values are incomparable.
-> [Scored t] -- ^ The list of results, sorted, highest score first.
filter' chunkSize maxRes pattern ts extract match' = partialSortByAscScore maxRes perfectScore (concat vss)
where
-- Preserve case for the first character, make all others lowercase
pattern' = case T.uncons pattern of
Just (c, rest) -> T.cons c (T.toLower rest)
_ -> pattern
vss = map (mapMaybe (\t -> flip Scored t <$> match' pattern' (extract t))) (chunkList chunkSize ts)
`using` parList (evalList rseq)
perfectScore = fromMaybe (error $ T.unpack pattern) $ match' pattern' pattern'

-- | The function to filter a list of values by fuzzy search on the text extracted from them,
-- using a custom matching function which determines how close words are.
filter :: Int -- ^ Chunk size. 1000 works well.
-> Int -- ^ Max. number of results wanted
-> T.Text -- ^ Pattern.
-> [t] -- ^ The list of values containing the text to search in.
-> (t -> T.Text) -- ^ The function to extract the text from the container.
-> [Scored t] -- ^ The list of results, sorted, highest score first.
filter chunkSize maxRes pattern ts extract =
filter' chunkSize maxRes pattern ts extract match

-- | Return all elements of the list that have a fuzzy match against the pattern,
-- the closeness of the match is determined using the custom scoring match function that is passed.
-- Runs with default settings where nothing is added around the matches, as case insensitive.
{-# INLINABLE simpleFilter' #-}
simpleFilter' :: Int -- ^ Chunk size. 1000 works well.
-> Int -- ^ Max. number of results wanted
-> T.Text -- ^ Pattern to look for.
-> [T.Text] -- ^ List of texts to check.
-> (T.Text -> T.Text -> Maybe Int)
-- ^ Custom scoring function to use for calculating how close words are
-> [Scored T.Text] -- ^ The ones that match.
simpleFilter' chunk maxRes pattern xs match' =
filter' chunk maxRes pattern xs id match'
--------------------------------------------------------------------------------

chunkList :: Int -> [a] -> [[a]]
Expand Down
36 changes: 24 additions & 12 deletions plugins/hls-cabal-plugin/hls-cabal-plugin.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,39 @@ library
exposed-modules:
Ide.Plugin.Cabal
Ide.Plugin.Cabal.Diagnostics
Ide.Plugin.Cabal.Completion.Completer.FilePath
Ide.Plugin.Cabal.Completion.Completer.Module
Ide.Plugin.Cabal.Completion.Completer.Simple
Ide.Plugin.Cabal.Completion.Completer.Snippet
Ide.Plugin.Cabal.Completion.Completer.Types
Ide.Plugin.Cabal.Completion.Completions
Ide.Plugin.Cabal.Completion.Data
Ide.Plugin.Cabal.Completion.Types
Ide.Plugin.Cabal.LicenseSuggest
Ide.Plugin.Cabal.Parse


build-depends:
, base >=4.12 && <5
, bytestring
-- Ideally, we only want to support a single Cabal version, supporting
-- older versions is completely pointless since Cabal is backwards compatible,
-- the latest Cabal version can parse all versions of the Cabal file format.
--
-- However, stack is making this difficult, if we change the version of Cabal,
-- we essentially need to make sure all other packages in the snapshot have their
-- Cabal dependency version relaxed.
-- Most packages have a Hackage revision, but stack won't pick these up (for sensible reasons)
-- automatically, forcing us to manually update the packages revision id.
-- This is a lot of work for almost zero benefit, so we just allow more versions here
-- and we eventually completely drop support for building HLS with stack.
, Cabal ^>=3.2 || ^>=3.4 || ^>=3.6 || ^>= 3.8 || ^>= 3.10
, Cabal-syntax >= 3.7
, containers
, deepseq
, directory
, filepath
, extra >=1.7.4
, ghcide == 2.1.0.0
, hashable
, hls-plugin-api == 2.1.0.0
, hls-graph == 2.1.0.0
, lens
, lsp ^>=2.0.0.0
, lsp-types ^>=2.0.0.1
, regex-tdfa ^>=1.3.1
, stm
, text
, text-rope
, transformers
, unordered-containers >=0.2.10.0
, containers
hs-source-dirs: src
Expand All @@ -68,15 +71,24 @@ test-suite tests
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Main.hs
other-modules:
Completer
Context
Utils
build-depends:
, base
, bytestring
, Cabal-syntax >= 3.7
, directory
, filepath
, ghcide
, hls-cabal-plugin
, hls-test-utils == 2.1.0.0
, lens
, lsp
, lsp-types
, tasty-hunit
, text
, text-rope
, transformers
, row-types
Loading
Loading