-
Notifications
You must be signed in to change notification settings - Fork 273
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4674 from unisonweb/cp/lsp-folding
- Loading branch information
Showing
10 changed files
with
218 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
unison-cli/src/Unison/Codebase/Editor/HandleInput/DebugFoldRanges.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
module Unison.Codebase.Editor.HandleInput.DebugFoldRanges (debugFoldRanges) where | ||
|
||
import Control.Lens | ||
import Control.Monad.Reader | ||
import Data.Text qualified as Text | ||
import Language.LSP.Protocol.Lens | ||
import Language.LSP.Protocol.Types qualified as LSP | ||
import Unison.Cli.Monad (Cli) | ||
import Unison.Cli.Monad qualified as Cli | ||
import Unison.Cli.MonadUtils qualified as Cli | ||
import Unison.Codebase.Editor.HandleInput.FormatFile (TextReplacement (..)) | ||
import Unison.Codebase.Editor.HandleInput.FormatFile qualified as FormatFile | ||
import Unison.Codebase.Editor.Output | ||
import Unison.LSP.Conversions qualified as CV | ||
import Unison.LSP.FoldingRange (foldingRangesForFile) | ||
import Unison.Prelude | ||
import Unison.Util.Range qualified as U | ||
|
||
debugFoldRanges :: Cli () | ||
debugFoldRanges = do | ||
Cli.Env {loadSource} <- ask | ||
(filePath, _) <- Cli.expectLatestFile | ||
parsedFile <- Cli.expectLatestParsedFile | ||
let foldingRanges = | ||
foldingRangesForFile parsedFile | ||
& fmap | ||
( \fr -> | ||
LSP.Range | ||
(LSP.Position (fr ^. startLine) (fromMaybe 0 $ fr ^. startCharacter)) | ||
( case (fr ^. endCharacter) of | ||
Just c -> LSP.Position (fr ^. endLine) c | ||
-- If there's no end char specified, go all the way to the beginning of the next line | ||
Nothing -> LSP.Position ((fr ^. endLine) + 1) 0 | ||
) | ||
) | ||
sourceTxt <- | ||
liftIO (loadSource (Text.pack filePath)) >>= \case | ||
Cli.InvalidSourceNameError -> Cli.returnEarly $ InvalidSourceName filePath | ||
Cli.LoadError -> Cli.returnEarly $ SourceLoadFailed filePath | ||
Cli.LoadSuccess contents -> pure contents | ||
Cli.respond $ AnnotatedFoldRanges $ annotateRanges sourceTxt foldingRanges | ||
|
||
-- | Annotate the bounds of a range within text using 《 and 》. | ||
-- | ||
-- Useful for checking that computed ranges make sense against the source text. | ||
-- | ||
-- >>> annotateRanges "one\ntwo\nthree\nfour" [ LSP.Range (LSP.Position 1 0) (LSP.Position 2 3) ] | ||
-- "one\n\12298two\nthr\12299ee\nfour" | ||
annotateRanges :: Text -> [LSP.Range] -> Text | ||
annotateRanges txt ranges = | ||
let replacements = | ||
ranges | ||
& foldMap | ||
( \(LSP.Range start end) -> | ||
let startPos = CV.lspToUPos start | ||
endPos = CV.lspToUPos end | ||
in [ TextReplacement "《" (U.Range startPos startPos), | ||
TextReplacement "》" (U.Range endPos endPos) | ||
] | ||
) | ||
in FormatFile.applyTextReplacements replacements txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,71 @@ | ||
{-# LANGUAGE DataKinds #-} | ||
|
||
module Unison.LSP.FoldingRange where | ||
module Unison.LSP.FoldingRange | ||
( foldingRangeRequest, | ||
foldingRangesForFile, | ||
) | ||
where | ||
|
||
import Control.Lens hiding (List) | ||
import Data.Map qualified as Map | ||
import Data.Text qualified as Text | ||
import Language.LSP.Protocol.Lens hiding (id, to) | ||
import Language.LSP.Protocol.Message qualified as Msg | ||
import Language.LSP.Protocol.Types | ||
import Unison.ABT qualified as ABT | ||
import Unison.DataDeclaration qualified as DD | ||
import Unison.Debug qualified as Debug | ||
import Unison.LSP.Conversions (annToRange) | ||
import Unison.LSP.FileAnalysis (getFileAnalysis) | ||
import Unison.LSP.Types | ||
import Unison.Parser.Ann (Ann) | ||
import Unison.Prelude | ||
import Unison.Symbol (Symbol) | ||
import Unison.UnisonFile (UnisonFile (..)) | ||
import Unison.UnisonFile qualified as UF | ||
import Unison.Var qualified as Var | ||
|
||
foldingRangeRequest :: Msg.TRequestMessage 'Msg.Method_TextDocumentFoldingRange -> (Either Msg.ResponseError (Msg.MessageResult 'Msg.Method_TextDocumentFoldingRange) -> Lsp ()) -> Lsp () | ||
foldingRangeRequest m respond = do | ||
foldRanges <- foldingRangesForFile (m ^. params . textDocument . uri) | ||
Debug.debugM Debug.LSP "Folding Ranges" foldRanges | ||
let fileUri = m ^. params . textDocument . uri | ||
foldRanges <- | ||
fromMaybe [] <$> runMaybeT do | ||
FileAnalysis {parsedFile = mayParsedFile} <- getFileAnalysis fileUri | ||
parsedFile <- hoistMaybe mayParsedFile | ||
pure $ foldingRangesForFile parsedFile | ||
respond . Right . InL $ foldRanges | ||
|
||
-- | Return a folding range for each top-level definition | ||
foldingRangesForFile :: Uri -> Lsp [FoldingRange] | ||
foldingRangesForFile fileUri = | ||
fromMaybe [] | ||
<$> runMaybeT do | ||
FileAnalysis {parsedFile} <- getFileAnalysis fileUri | ||
UnisonFileId {dataDeclarationsId, effectDeclarationsId, terms} <- MaybeT $ pure parsedFile | ||
let dataFolds = dataDeclarationsId ^.. folded . _2 . to dataDeclSpan | ||
let abilityFolds = effectDeclarationsId ^.. folded . _2 . to DD.toDataDecl . to dataDeclSpan | ||
let termFolds = terms ^.. folded . _3 . to ABT.annotation | ||
let folds = dataFolds <> abilityFolds <> termFolds | ||
let ranges = mapMaybe annToRange folds | ||
pure $ | ||
ranges <&> \r -> | ||
FoldingRange | ||
{ _startLine = r ^. start . line, | ||
_startCharacter = Just (r ^. start . character), | ||
_endLine = r ^. end . line, | ||
_endCharacter = Just (r ^. end . character), | ||
_kind = Just FoldingRangeKind_Region, | ||
_collapsedText = Nothing | ||
} | ||
where | ||
dataDeclSpan dd = | ||
-- We don't have a proper Annotation for data decls so we take the span of all the | ||
-- constructors using their monoid instance. | ||
DD.annotation dd <> DD.constructors' dd ^. folded . to (\(a, _v, typ) -> a <> ABT.annotation typ) | ||
foldingRangesForFile :: UF.UnisonFile Symbol Ann -> [FoldingRange] | ||
foldingRangesForFile UnisonFileId {dataDeclarationsId, effectDeclarationsId, terms, watches} = | ||
let dataFolds = | ||
dataDeclarationsId | ||
& Map.toList | ||
& map \(sym, (_typ, decl)) -> (Just sym, DD.annotation decl) | ||
abilityFolds = | ||
effectDeclarationsId | ||
& Map.toList | ||
& map \(sym, (_typ, decl)) -> (Just sym, DD.annotation . DD.toDataDecl $ decl) | ||
termFolds = terms & fmap \(sym, ann, _trm) -> (Just sym, ann) | ||
watchFolds = | ||
watches | ||
& fold | ||
& fmap | ||
( \(_sym, ann, _trm) -> | ||
-- We don't use the symbol here because watch symbols are often auto-generated | ||
-- and ugly. | ||
(Nothing, ann) | ||
) | ||
folds = | ||
dataFolds <> abilityFolds <> termFolds <> watchFolds | ||
ranges = | ||
folds | ||
& mapMaybe \(sym, range) -> | ||
(Text.pack . Var.nameStr <$> sym,) <$> annToRange range | ||
in ranges <&> \(maySym, r) -> | ||
FoldingRange | ||
{ _startLine = r ^. start . line, | ||
_startCharacter = Just (r ^. start . character), | ||
_endLine = r ^. end . line, | ||
_endCharacter = Just (r ^. end . character), | ||
_kind = Just FoldingRangeKind_Region, | ||
_collapsedText = maySym | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
```ucm:hide | ||
.> builtins.mergeio | ||
``` | ||
|
||
```unison:hide | ||
{{ Type doc }} | ||
structural type Optional a = | ||
None | ||
| Some a | ||
{{ | ||
Multi line | ||
Term doc | ||
}} | ||
List.map : | ||
(a -> b) | ||
-> [a] | ||
-> [b] | ||
List.map f = cases | ||
(x +: xs) -> f x +: List.map f xs | ||
[] -> [] | ||
test> z = let | ||
x = "hello" | ||
y = "world" | ||
[Ok (x ++ y)] | ||
``` | ||
|
||
```ucm | ||
.> debug.lsp.fold-ranges | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
```unison | ||
{{ Type doc }} | ||
structural type Optional a = | ||
None | ||
| Some a | ||
{{ | ||
Multi line | ||
Term doc | ||
}} | ||
List.map : | ||
(a -> b) | ||
-> [a] | ||
-> [b] | ||
List.map f = cases | ||
(x +: xs) -> f x +: List.map f xs | ||
[] -> [] | ||
test> z = let | ||
x = "hello" | ||
y = "world" | ||
[Ok (x ++ y)] | ||
``` | ||
|
||
```ucm | ||
.> debug.lsp.fold-ranges | ||
《{{ Type doc }}》 | ||
《structural type Optional a = | ||
None | ||
| Some a》 | ||
《{{ | ||
Multi line | ||
Term doc | ||
}}》 | ||
《List.map : | ||
(a -> b) | ||
-> [a] | ||
-> [b] | ||
List.map f = cases | ||
(x +: xs) -> f x +: List.map f xs | ||
[] -> []》 | ||
《test> z = let | ||
x = "hello" | ||
y = "world" | ||
[Ok (x ++ y)]》 | ||
``` |