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

Feat: Folding Ranges #3058

Merged
merged 34 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
098882d
save some progress: add basic starter code for folding ranges
sloorush Jul 23, 2022
2e44b7a
save some progress: add function to traverse through coderange and fo…
sloorush Aug 6, 2022
fec1824
save some progress: add parsing of folding ranges
sloorush Aug 9, 2022
f9ffcc1
fix: maybe issue with foldingRanges
sloorush Aug 9, 2022
1d28a2c
add: generate folding ranges from coderange
sloorush Aug 9, 2022
60b2136
add: plugin request method instance for folding ranges
sloorush Aug 9, 2022
02a1e9d
ref: alter function and var names
sloorush Aug 9, 2022
a032c78
post review: cleanup crk to frk & fix typo
sloorush Aug 10, 2022
892a129
fix: find folding ranges function
sloorush Aug 12, 2022
e6a2b5c
format: run formatter and add comments
sloorush Aug 12, 2022
e21f5cb
fix: return all response results of folding range request
sloorush Aug 12, 2022
799db9b
Revert "format: run formatter and add comments"
sloorush Aug 13, 2022
5d0d159
add: removed comments after revert
sloorush Aug 13, 2022
332e953
fix: formatting
sloorush Aug 16, 2022
c4f386d
docs: add folding range to features section and cabal file
sloorush Aug 16, 2022
8eb7a30
refactor: use destructuring for createFoldingRange function and use c…
sloorush Aug 16, 2022
60e3fb2
test: add basic unit test for findFoldingRanges function
sloorush Sep 7, 2022
e3f0007
test: add tests for children and code kind
sloorush Sep 7, 2022
474ffef
test: add more test cases
sloorush Sep 7, 2022
6975302
test: add test for createFoldingRange
sloorush Sep 8, 2022
a430a43
test: add integration test for folding ranges
sloorush Sep 10, 2022
baf419e
fix: duplicate start line foldingranges and remove single line
sloorush Sep 11, 2022
d6a8666
Merge branch 'master' of github.com:sloorush/haskell-language-server …
sloorush Sep 12, 2022
e9dc569
refactor: duplicate folding range functionality
sloorush Sep 12, 2022
c46a7f4
fix: formatting in code range plugin
sloorush Sep 12, 2022
959a53b
added more descriptive comments and encorporate code review suggestions
sloorush Sep 14, 2022
e8ee9f9
revert: automatic formatting for selection range test case file
sloorush Sep 14, 2022
44c5819
fix: ignoring children if root fails to provide folding ranges
sloorush Sep 18, 2022
9181b04
remove: redundant match on crkToFrk
sloorush Sep 19, 2022
86f1068
revert: filtering same line foldings and multiple foldings on the sam…
sloorush Sep 19, 2022
c3f1c4a
Merge branch 'haskell:master' into folding-ranges
sloorush Sep 19, 2022
57cb482
revert: formatting change to selection range test file
sloorush Sep 19, 2022
ccd9fa5
fix: entire file folding because of root node
sloorush Sep 21, 2022
c023548
Merge branch 'master' into folding-ranges
kokobd Sep 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion hls-plugin-api/src/Ide/Plugin/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ data PluginConfig =
, plcCompletionOn :: !Bool
, plcRenameOn :: !Bool
, plcSelectionRangeOn :: !Bool
, plcFoldingRangeOn :: !Bool
, plcConfig :: !A.Object
} deriving (Show,Eq)

Expand All @@ -125,11 +126,12 @@ instance Default PluginConfig where
, plcCompletionOn = True
, plcRenameOn = True
, plcSelectionRangeOn = True
, plcFoldingRangeOn = True
, plcConfig = mempty
}

instance A.ToJSON PluginConfig where
toJSON (PluginConfig g ch ca cl d h s c rn sr cfg) = r
toJSON (PluginConfig g ch ca cl d h s c rn sr fr cfg) = r
where
r = object [ "globalOn" .= g
, "callHierarchyOn" .= ch
Expand All @@ -141,6 +143,7 @@ instance A.ToJSON PluginConfig where
, "completionOn" .= c
, "renameOn" .= rn
, "selectionRangeOn" .= sr
, "foldingRangeOn" .= fr
, "config" .= cfg
]

Expand All @@ -156,6 +159,7 @@ instance A.FromJSON PluginConfig where
<*> o .:? "completionOn" .!= plcCompletionOn def
<*> o .:? "renameOn" .!= plcRenameOn def
<*> o .:? "selectionRangeOn" .!= plcSelectionRangeOn def
<*> o .:? "selectionRangeOn" .!= plcFoldingRangeOn def
sloorush marked this conversation as resolved.
Show resolved Hide resolved
<*> o .:? "config" .!= plcConfig def

-- ---------------------------------------------------------------------
10 changes: 10 additions & 0 deletions hls-plugin-api/src/Ide/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,13 @@ instance PluginMethod Request TextDocumentSelectionRange where
uri = msgParams ^. J.textDocument . J.uri
pid = pluginId pluginDesc

instance PluginMethod Request TextDocumentFoldingRange where
pluginEnabled _ msgParams pluginDesc conf = pluginResponsible uri pluginDesc
&& pluginEnabledConfig plcFoldingRangeOn pid conf
where
uri = msgParams ^. J.textDocument . J.uri
pid = pluginId pluginDesc

instance PluginMethod Request CallHierarchyIncomingCalls where
-- This method has no URI parameter, thus no call to 'pluginResponsible'
pluginEnabled _ _ pluginDesc conf = pluginEnabledConfig plcCallHierarchyOn pid conf
Expand Down Expand Up @@ -470,6 +477,9 @@ instance PluginRequestMethod TextDocumentPrepareCallHierarchy where
instance PluginRequestMethod TextDocumentSelectionRange where
combineResponses _ _ _ _ (x :| _) = x

instance PluginRequestMethod TextDocumentFoldingRange where
combineResponses _ _ _ _ (x :| _) = x
sloorush marked this conversation as resolved.
Show resolved Hide resolved

instance PluginRequestMethod CallHierarchyIncomingCalls where

instance PluginRequestMethod CallHierarchyOutgoingCalls where
Expand Down
70 changes: 64 additions & 6 deletions plugins/hls-code-range-plugin/src/Ide/Plugin/CodeRange.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Maybe (MaybeT (MaybeT),
maybeToExceptT)
import Data.Either.Extra (maybeToEither)
import Data.Maybe (fromMaybe)
import Data.Maybe ( fromMaybe, catMaybes )
import Data.Vector (Vector)
import qualified Data.Vector as V
import Development.IDE (IdeAction,
Expand All @@ -33,7 +33,7 @@ import Development.IDE.Core.PositionMapping (PositionMapping,
import Development.IDE.Types.Logger (Pretty (..))
import Ide.Plugin.CodeRange.Rules (CodeRange (..),
GetCodeRange (..),
codeRangeRule)
codeRangeRule, CodeRangeKind (CodeKindComment, CodeKindImports, CodeKindRegion))
import qualified Ide.Plugin.CodeRange.Rules as Rules (Log)
import Ide.PluginUtils (pluginResponse,
positionInRange)
Expand All @@ -47,18 +47,20 @@ import Language.LSP.Types (List (List),
Position (..),
Range (_start),
ResponseError,
SMethod (STextDocumentSelectionRange),
SMethod (STextDocumentSelectionRange, STextDocumentFoldingRange),
SelectionRange (..),
SelectionRangeParams (..),
FoldingRange (..),
FoldingRangeParams(..),
TextDocumentIdentifier (TextDocumentIdentifier),
Uri)
Uri, FoldingRangeKind (FoldingRangeComment, FoldingRangeImports, FoldingRangeRegion)
)
import Prelude hiding (log, span)

descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState
descriptor recorder plId = (defaultPluginDescriptor plId)
{ pluginHandlers = mkPluginHandler STextDocumentSelectionRange selectionRangeHandler
-- TODO @sloorush add folding range
-- <> mkPluginHandler STextDocumentFoldingRange foldingRangeHandler
<> mkPluginHandler STextDocumentFoldingRange foldingRangeHandler
, pluginRules = codeRangeRule (cmapWithPrio LogRules recorder)
}

Expand All @@ -68,6 +70,26 @@ instance Pretty Log where
pretty log = case log of
LogRules codeRangeLog -> pretty codeRangeLog

foldingRangeHandler :: IdeState -> PluginId -> FoldingRangeParams -> LspM c (Either ResponseError (List FoldingRange))
foldingRangeHandler ide _ FoldingRangeParams{..} = do
pluginResponse $ do
filePath <- ExceptT . pure . maybeToEither "fail to convert uri to file path" $
toNormalizedFilePath' <$> uriToFilePath' uri
foldingRanges <- ExceptT . liftIO . runIdeAction "FoldingRange" (shakeExtras ide) . runExceptT $
getFoldingRanges filePath
pure . List $ foldingRanges
where
uri :: Uri
TextDocumentIdentifier uri = _textDocument

getFoldingRanges :: NormalizedFilePath -> ExceptT String IdeAction [FoldingRange]
getFoldingRanges file = do
(codeRange, _) <- maybeToExceptT "fail to get code range" $ useE GetCodeRange file

let foldingRanges = catMaybes $ findFoldingRanges codeRange

maybeToExceptT "Fail to generate folding range" (MaybeT . pure $ Just foldingRanges)

selectionRangeHandler :: IdeState -> PluginId -> SelectionRangeParams -> LspM c (Either ResponseError (List SelectionRange))
selectionRangeHandler ide _ SelectionRangeParams{..} = do
pluginResponse $ do
Expand Down Expand Up @@ -126,6 +148,42 @@ findPosition pos root = go Nothing root
startOfRight <- _start . _codeRange_range <$> V.headM right
if pos < startOfRight then binarySearchPos left else binarySearchPos right

findFoldingRanges :: CodeRange -> [Maybe FoldingRange]
sloorush marked this conversation as resolved.
Show resolved Hide resolved
findFoldingRanges root = do
let acc = []
let node = _codeRange_children root
binarySearchFoldingRange node acc

binarySearchFoldingRange :: Vector CodeRange -> [Maybe FoldingRange] -> [Maybe FoldingRange]
sloorush marked this conversation as resolved.
Show resolved Hide resolved
binarySearchFoldingRange v acc
| V.null v = []
| V.length v == 1 = do
headOfCodeRange <- V.headM v
let foldingRangesOfRange = createFoldingRange headOfCodeRange
let acc' = acc ++ [foldingRangesOfRange]
acc'
| otherwise = do
let (left, right) = V.splitAt (V.length v `div` 2) v
_ <- binarySearchFoldingRange left acc
binarySearchFoldingRange right acc

createFoldingRange :: CodeRange -> Maybe FoldingRange
createFoldingRange node1 = do
let range = _codeRange_range node1
-- let children = _codeRange_children node1
let Range startPos endPos = range
let Position lineStart _= startPos
let Position lineEnd _ = endPos
let codeRangeKind = _codeRange_kind node1

if codeRangeKind == CodeKindComment
sloorush marked this conversation as resolved.
Show resolved Hide resolved
then Just (FoldingRange lineStart Nothing lineEnd Nothing (Just FoldingRangeComment))
sloorush marked this conversation as resolved.
Show resolved Hide resolved
else if codeRangeKind== CodeKindImports
then Just (FoldingRange lineStart Nothing lineEnd Nothing ( Just FoldingRangeImports))
else if codeRangeKind==CodeKindRegion
then Just (FoldingRange lineStart Nothing lineEnd Nothing (Just FoldingRangeRegion))
else Nothing

-- | Likes 'toCurrentPosition', but works on 'SelectionRange'
toCurrentSelectionRange :: PositionMapping -> SelectionRange -> Maybe SelectionRange
toCurrentSelectionRange positionMapping SelectionRange{..} = do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ data CodeRangeKind =
| CodeKindImports
-- | a comment
| CodeKindComment
deriving (Show, Generic, NFData)
deriving (Show, Eq, Generic, NFData)

Lens.makeLenses ''CodeRange

Expand Down