Skip to content

Commit

Permalink
Filepath completion now no longer considers './' when matching
Browse files Browse the repository at this point in the history
Some refactoring
  • Loading branch information
VeryMilkyJoe committed Jun 16, 2023
1 parent d4cdec4 commit 7a6d82b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 24 deletions.
2 changes: 1 addition & 1 deletion plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -292,4 +292,4 @@ completion _ide _ complParams = do
where
(Position linePos charPos) = VFS.cursorPos prefix
context = getContext (Position linePos charPos) (Rope.lines $ cnts ^. VFS.file_text)
completionContext = getFilePathCompletionContext fp prefix
completionContext = getCabalCompletionContext fp prefix
43 changes: 31 additions & 12 deletions plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import System.Directory (doesDirectoryExist,
import qualified System.FilePath as FP
import qualified System.FilePath.Posix as Posix
import qualified Text.Fuzzy.Parallel as Fuzzy
import Debug.Trace (traceShowM, traceShowId)

{- | Takes information needed to build possible completion items
and returns the list of possible completion items
Expand Down Expand Up @@ -77,7 +76,17 @@ data KeyWordContext
type KeyWordName = T.Text
type StanzaName = T.Text

-- Information about the current completion status
{- | Information about the current completion status
Example: @"dir1/fi@ having been written to the file
would correspond to:
@
completionPrefix = "dir1/fi"
completionSuffix = Just "\\""
...
@
-}
data CabalCompletionContext = CabalCompletionContext
{ completionPrefix :: T.Text
-- ^ text prefix to complete
Expand Down Expand Up @@ -166,7 +175,7 @@ getContext pos ls =
-}
getKeyWordContext :: Position -> [T.Text] -> Map KeyWordName a -> Maybe KeyWordContext
getKeyWordContext pos ls keywords = do
case traceShowId $ lastNonEmptyLineM of
case lastNonEmptyLineM of
Nothing -> Just None
Just lastLine' -> do
let (whiteSpaces, lastLine) = T.span (== ' ') lastLine'
Expand All @@ -181,14 +190,13 @@ getKeyWordContext pos ls keywords = do
Just kw -> Just $ KeyWord kw
else Just None
where
currentLineM = ls Extra.!? (fromIntegral $ pos ^. JL.line)
lastNonEmptyLineM :: Maybe T.Text
lastNonEmptyLineM = do
cur' <- currentLineM
traceShowM ("cur line", cur')
let cur = stripPartiallyWritten $ T.take (fromIntegral $ pos ^. JL.character) cur'
traceShowM ("cur line before pref", cur)
List.find (not . T.null . T.stripEnd)
$ cur : previousLines pos ls
currentLineM = ls Extra.!? (fromIntegral $ pos ^. JL.line)

{- | Parse the given set of lines (starting before current cursor position
up to the start of the file) to find the nearest stanza declaration,
Expand Down Expand Up @@ -237,8 +245,8 @@ stripPartiallyWritten = T.dropWhileEnd (\y -> (y /= ' ') && (y /= ':'))
checks whether a suffix needs to be completed,
and calculates the range in the document in which to complete
-}
getFilePathCompletionContext :: FilePath -> VFS.PosPrefixInfo -> CabalCompletionContext
getFilePathCompletionContext dir prefixInfo =
getCabalCompletionContext :: FilePath -> VFS.PosPrefixInfo -> CabalCompletionContext
getCabalCompletionContext dir prefixInfo =
CabalCompletionContext
{ completionPrefix = filepathPrefix
, completionSuffix = Just suffix
Expand All @@ -264,7 +272,7 @@ getFilePathCompletionContext dir prefixInfo =
cursorColumn = fromIntegral $ VFS.cursorPos prefixInfo ^. JL.character
-- if the filepath is inside apostrophes, we parse until the apostrophe,
-- otherwise we parse until a space occurs
stopConditionChars = apostropheOrSpaceSeparator : [',']
stopConditionChars = apostropheOrSpaceSeparator : [',', ':']

buildCompletion :: CabalCompletionItem -> J.CompletionItem
buildCompletion completionItem =
Expand Down Expand Up @@ -317,8 +325,9 @@ filePathCompleter :: Completer
filePathCompleter ctx = do
let suffix = fromMaybe "" $ completionSuffix ctx
complInfo = pathCompletionInfoFromCompletionContext ctx
toMatch = fromMaybe "" $ T.stripPrefix "./" $ partialFileName complInfo
filePathCompletions <- listFileCompletions complInfo
let scored = Fuzzy.simpleFilter 1000 10 (partialFileName complInfo) (map T.pack filePathCompletions)
let scored = Fuzzy.simpleFilter 1000 10 toMatch (map T.pack filePathCompletions)
forM
scored
( \compl' -> do
Expand All @@ -327,7 +336,7 @@ filePathCompleter ctx = do
pure $ makeCabalCompletionItem (completionRange ctx) fullFilePath fullFilePath
)
where
-- \| Takes a suffix, a completed path and a pathCompletionInfo and
-- Takes a suffix, a completed path and a pathCompletionInfo and
-- generates the whole filepath including the already written prefix
-- and the suffix in case the completed path is a filepath
makeFullFilePath :: T.Text -> T.Text -> PathCompletionInfo -> IO T.Text
Expand All @@ -354,7 +363,7 @@ directoryCompleter ctx = do
pure $ makeCabalCompletionItem (completionRange ctx) fullDirPath fullDirPath
)
where
-- \| Takes a directory and PathCompletionInfo and
-- Takes a directory and PathCompletionInfo and
-- returns the whole path including the prefix that was already written
makeFullDirPath :: T.Text -> PathCompletionInfo -> IO T.Text
makeFullDirPath completion' complInfo = do
Expand Down Expand Up @@ -420,6 +429,16 @@ mkDirFromCWD complInfo fp = Posix.addTrailingPathSeparator $ mkCompletionDirecto
Note that partialFileName combined with partialFileDir results in
the original prefix.
Example:
On the written filepath: @dir1/fi@ the
resulting PathCompletionInfo would be:
@
partialFileName = "fi"
partialFileDir = "dir1/dir2/fi"
...
@
-}
data PathCompletionInfo = PathCompletionInfo
{ partialFileName :: T.Text
Expand Down
22 changes: 11 additions & 11 deletions plugins/hls-cabal-plugin/test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ completionHelperTests =
where
getFilePathCursorPrefix :: T.Text -> UInt -> UInt -> T.Text
getFilePathCursorPrefix lineString linePos charPos =
completionPrefix . getFilePathCompletionContext "" $
completionPrefix . getCabalCompletionContext "" $
VFS.PosPrefixInfo
{ VFS.fullLine = lineString
, VFS.prefixModule = ""
Expand All @@ -128,35 +128,35 @@ filePathCompletionContextTests =
testGroup
"File Path Completion Context Tests"
[ testCase "empty line" $ do
let complContext = getFilePathCompletionContext "" (simplePosPrefixInfo " " 0 3)
let complContext = getCabalCompletionContext "" (simplePosPrefixInfo " " 0 3)
completionSuffix complContext @?= Just ""
completionPrefix complContext @?= ""
, testCase "simple filepath" $ do
let complContext = getFilePathCompletionContext "" (simplePosPrefixInfo " src/" 0 7)
let complContext = getCabalCompletionContext "" (simplePosPrefixInfo " src/" 0 7)
completionSuffix complContext @?= Just ""
completionPrefix complContext @?= "src/"
, testCase "simple filepath - starting apostrophe" $ do
let complContext = getFilePathCompletionContext "" (simplePosPrefixInfo " \"src/" 0 8)
let complContext = getCabalCompletionContext "" (simplePosPrefixInfo " \"src/" 0 8)
completionSuffix complContext @?= Just "\""
completionPrefix complContext @?= "src/"
, testCase "simple filepath - starting apostrophe, already closed" $ do
let complContext = getFilePathCompletionContext "" (simplePosPrefixInfo " \"src/\"" 0 8)
let complContext = getCabalCompletionContext "" (simplePosPrefixInfo " \"src/\"" 0 8)
completionSuffix complContext @?= Just ""
completionPrefix complContext @?= "src/"
, testCase "second filepath - starting apostrophe" $ do
let complContext = getFilePathCompletionContext "" (simplePosPrefixInfo "fp.txt \"src/" 0 12)
let complContext = getCabalCompletionContext "" (simplePosPrefixInfo "fp.txt \"src/" 0 12)
completionSuffix complContext @?= Just "\""
completionPrefix complContext @?= "src/"
, testCase "middle filepath - starting apostrophe" $ do
let complContext = getFilePathCompletionContext "" (simplePosPrefixInfo "fp.txt \"src/ fp2.txt" 0 12)
let complContext = getCabalCompletionContext "" (simplePosPrefixInfo "fp.txt \"src/ fp2.txt" 0 12)
completionSuffix complContext @?= Just "\""
completionPrefix complContext @?= "src/"
, testCase "middle filepath - starting apostrophe, already closed" $ do
let complContext = getFilePathCompletionContext "" (simplePosPrefixInfo "fp.t xt \"src\" fp2.txt" 0 12)
let complContext = getCabalCompletionContext "" (simplePosPrefixInfo "fp.t xt \"src\" fp2.txt" 0 12)
completionSuffix complContext @?= Just ""
completionPrefix complContext @?= "src"
, testCase "middle filepath - starting apostrophe, already closed" $ do
let complContext = getFilePathCompletionContext "" (simplePosPrefixInfo "\"fp.txt\" \"src fp2.txt" 0 13)
let complContext = getCabalCompletionContext "" (simplePosPrefixInfo "\"fp.txt\" \"src fp2.txt" 0 13)
completionSuffix complContext @?= Just "\""
completionPrefix complContext @?= "src"
]
Expand Down Expand Up @@ -341,10 +341,10 @@ contextTests =
-- for a completely empty file, the context needs to
-- be top level without a specified keyword
getContext (Position 0 0) [""] @?= Just (TopLevel, None)
, testCase "Cabal version keyword - no value" $ do
, testCase "Cabal version keyword - no value, no space after :" $ do
-- on a file, where the keyword is already written
-- the context should still be toplevel but the keyword should be recognized
getContext (Position 0 15) ["cabal-version:"] @?= Just (TopLevel, KeyWord "cabal-version:")
getContext (Position 0 14) ["cabal-version:"] @?= Just (TopLevel, KeyWord "cabal-version:")
, testCase "Cabal version keyword - cursor in keyword" $ do
-- on a file, where the keyword is already written
-- but the cursor is in the middle of the keyword,
Expand Down

0 comments on commit 7a6d82b

Please sign in to comment.