forked from haskell/haskell-language-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cabal plugin outline view (haskell#4323)
* working test message cabal file * trivial outline with rule invocation * outline with field lines * complete outline prototype * small improvements * remove fieldLines, one line Section display * stylish haskell * tests * imports changes * outline tests changes * duplicate defDocumentSymbol * cabal outline test imports change * schema 96 94 update * schema 94 update * 94 schema update * 94 schema update * + cabal-add * Revert "+ cabal-add" This reverts commit f77dea5. * + docs, refactoring * Update plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completion/CabalFields.hs * formatting * newline --------- Co-authored-by: fendor <fendor@users.noreply.github.com>
- Loading branch information
Showing
17 changed files
with
282 additions
and
4 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
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
119 changes: 119 additions & 0 deletions
119
plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Outline.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,119 @@ | ||
{-# LANGUAGE CPP #-} | ||
{-# LANGUAGE DataKinds #-} | ||
{-# LANGUAGE DuplicateRecordFields #-} | ||
{-# LANGUAGE GADTs #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE ViewPatterns #-} | ||
|
||
module Ide.Plugin.Cabal.Outline where | ||
|
||
import Control.Monad.IO.Class | ||
import Data.Maybe | ||
import qualified Data.Text as T | ||
import Data.Text.Encoding (decodeUtf8) | ||
import Development.IDE.Core.Rules | ||
import Development.IDE.Core.Shake (IdeState (shakeExtras), | ||
runIdeAction, | ||
useWithStaleFast) | ||
import Development.IDE.Types.Location (toNormalizedFilePath') | ||
import Distribution.Fields.Field (Field (Field, Section), | ||
Name (Name)) | ||
import Distribution.Parsec.Position (Position) | ||
import Ide.Plugin.Cabal.Completion.CabalFields (onelineSectionArgs) | ||
import Ide.Plugin.Cabal.Completion.Types (ParseCabalFields (..), | ||
cabalPositionToLSPPosition) | ||
import Ide.Plugin.Cabal.Orphans () | ||
import Ide.Types (PluginMethodHandler) | ||
import Language.LSP.Protocol.Message (Method (..)) | ||
import Language.LSP.Protocol.Types (DocumentSymbol (..)) | ||
import qualified Language.LSP.Protocol.Types as LSP | ||
|
||
|
||
moduleOutline :: PluginMethodHandler IdeState Method_TextDocumentDocumentSymbol | ||
moduleOutline ideState _ LSP.DocumentSymbolParams {_textDocument = LSP.TextDocumentIdentifier uri} = | ||
case LSP.uriToFilePath uri of | ||
Just (toNormalizedFilePath' -> fp) -> do | ||
mFields <- liftIO $ runIdeAction "cabal-plugin.fields" (shakeExtras ideState) (useWithStaleFast ParseCabalFields fp) | ||
case fmap fst mFields of | ||
Just fieldPositions -> pure $ LSP.InR (LSP.InL allSymbols) | ||
where | ||
allSymbols = mapMaybe documentSymbolForField fieldPositions | ||
Nothing -> pure $ LSP.InL [] | ||
Nothing -> pure $ LSP.InL [] | ||
|
||
-- | Creates a @DocumentSymbol@ object for the | ||
-- cabal AST, without displaying @fieldLines@ and | ||
-- displaying @Section Name@ and @SectionArgs@ in one line. | ||
-- | ||
-- @fieldLines@ are leaves of a cabal AST, so they are omitted | ||
-- in the outline. Sections have to be displayed in one line, because | ||
-- the AST representation looks unnatural. See examples: | ||
-- | ||
-- * part of a cabal file: | ||
-- | ||
-- > if impl(ghc >= 9.8) | ||
-- > ghc-options: -Wall | ||
-- | ||
-- * AST representation: | ||
-- | ||
-- > if | ||
-- > impl | ||
-- > ( | ||
-- > ghc >= 9.8 | ||
-- > ) | ||
-- > | ||
-- > ghc-options: | ||
-- > -Wall | ||
-- | ||
-- * resulting @DocumentSymbol@: | ||
-- | ||
-- > if impl(ghc >= 9.8) | ||
-- > ghc-options: | ||
-- > | ||
documentSymbolForField :: Field Position -> Maybe DocumentSymbol | ||
documentSymbolForField (Field (Name pos fieldName) _) = | ||
Just | ||
(defDocumentSymbol range) | ||
{ _name = decodeUtf8 fieldName, | ||
_kind = LSP.SymbolKind_Field, | ||
_children = Nothing | ||
} | ||
where | ||
range = cabalPositionToLSPRange pos `addNameLengthToLSPRange` decodeUtf8 fieldName | ||
documentSymbolForField (Section (Name pos fieldName) sectionArgs fields) = | ||
Just | ||
(defDocumentSymbol range) | ||
{ _name = joinedName, | ||
_kind = LSP.SymbolKind_Object, | ||
_children = | ||
Just | ||
(mapMaybe documentSymbolForField fields) | ||
} | ||
where | ||
joinedName = decodeUtf8 fieldName <> " " <> onelineSectionArgs sectionArgs | ||
range = cabalPositionToLSPRange pos `addNameLengthToLSPRange` joinedName | ||
|
||
-- | Creates a single point LSP range | ||
-- using cabal position | ||
cabalPositionToLSPRange :: Position -> LSP.Range | ||
cabalPositionToLSPRange pos = LSP.Range lspPos lspPos | ||
where | ||
lspPos = cabalPositionToLSPPosition pos | ||
|
||
addNameLengthToLSPRange :: LSP.Range -> T.Text -> LSP.Range | ||
addNameLengthToLSPRange (LSP.Range pos1 (LSP.Position line char)) name = | ||
LSP.Range | ||
pos1 | ||
(LSP.Position line (char + fromIntegral (T.length name))) | ||
|
||
defDocumentSymbol :: LSP.Range -> DocumentSymbol | ||
defDocumentSymbol range = DocumentSymbol | ||
{ _detail = Nothing | ||
, _deprecated = Nothing | ||
, _name = "" | ||
, _kind = LSP.SymbolKind_File | ||
, _range = range | ||
, _selectionRange = range | ||
, _children = Nothing | ||
, _tags = Nothing | ||
} |
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,103 @@ | ||
{-# LANGUAGE OverloadedStrings #-} | ||
|
||
module Outline ( | ||
outlineTests, | ||
) where | ||
|
||
import Language.LSP.Protocol.Types (DocumentSymbol (..), | ||
Position (..), Range (..)) | ||
import qualified Test.Hls as T | ||
import Utils | ||
|
||
testSymbols :: (T.HasCallStack) => T.TestName -> FilePath -> [DocumentSymbol] -> T.TestTree | ||
testSymbols testName path expectedSymbols = | ||
runCabalTestCaseSession testName "outline-cabal" $ do | ||
docId <- T.openDoc path "cabal" | ||
symbols <- T.getDocumentSymbols docId | ||
T.liftIO $ symbols T.@?= Right expectedSymbols | ||
|
||
outlineTests :: T.TestTree | ||
outlineTests = | ||
T.testGroup | ||
"Cabal Outline Tests" | ||
[ testSymbols | ||
"cabal Field outline test" | ||
"field.cabal" | ||
[fieldDocumentSymbol] | ||
, testSymbols | ||
"cabal FieldLine outline test" | ||
"fieldline.cabal" | ||
[fieldLineDocumentSymbol] | ||
, testSymbols | ||
"cabal Section outline test" | ||
"section.cabal" | ||
[sectionDocumentSymbol] | ||
, testSymbols | ||
"cabal SectionArg outline test" | ||
"sectionarg.cabal" | ||
[sectionArgDocumentSymbol] | ||
] | ||
where | ||
fieldDocumentSymbol :: DocumentSymbol | ||
fieldDocumentSymbol = | ||
( defDocumentSymbol | ||
( Range { _start = Position{_line = 0, _character = 0} | ||
, _end = Position{_line = 0, _character = 8} }) | ||
) | ||
{ _name = "homepage" | ||
, _kind = T.SymbolKind_Field | ||
, _children = Nothing | ||
} | ||
fieldLineDocumentSymbol :: DocumentSymbol | ||
fieldLineDocumentSymbol = | ||
( defDocumentSymbol | ||
( Range { _start = Position{_line = 0, _character = 0} | ||
, _end = Position{_line = 0, _character = 13} }) | ||
) | ||
{ _name = "cabal-version" | ||
, _kind = T.SymbolKind_Field | ||
, _children = Nothing -- the values of fieldLine are removed from the outline | ||
} | ||
sectionDocumentSymbol :: DocumentSymbol | ||
sectionDocumentSymbol = | ||
( defDocumentSymbol | ||
( Range { _start = Position{_line = 0, _character = 2} | ||
, _end = Position{_line = 0, _character = 15} }) | ||
) | ||
{ _name = "build-depends" | ||
, _kind = T.SymbolKind_Field | ||
, _children = Nothing -- the values of fieldLine are removed from the outline | ||
} | ||
sectionArgDocumentSymbol :: DocumentSymbol | ||
sectionArgDocumentSymbol = | ||
( defDocumentSymbol | ||
( Range { _start = Position{_line = 0, _character = 2} | ||
, _end = Position{_line = 0, _character = 19} }) | ||
) | ||
{ _name = "if os ( windows )" | ||
, _kind = T.SymbolKind_Object | ||
, _children = Just $ [sectionArgChildrenDocumentSymbol] | ||
} | ||
sectionArgChildrenDocumentSymbol :: DocumentSymbol | ||
sectionArgChildrenDocumentSymbol = | ||
( defDocumentSymbol | ||
( Range { _start = Position{_line = 1, _character = 4} | ||
, _end = Position{_line = 1, _character = 17} }) | ||
) | ||
{ _name = "build-depends" | ||
, _kind = T.SymbolKind_Field | ||
, _children = Nothing | ||
} | ||
|
||
defDocumentSymbol :: Range -> DocumentSymbol | ||
defDocumentSymbol range = | ||
DocumentSymbol | ||
{ _detail = Nothing | ||
, _deprecated = Nothing | ||
, _name = "" | ||
, _kind = T.SymbolKind_File | ||
, _range = range | ||
, _selectionRange = range | ||
, _children = Nothing | ||
, _tags = Nothing | ||
} |
1 change: 1 addition & 0 deletions
1
plugins/hls-cabal-plugin/test/testdata/outline-cabal/field.cabal
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 @@ | ||
homepage: |
1 change: 1 addition & 0 deletions
1
plugins/hls-cabal-plugin/test/testdata/outline-cabal/fieldline.cabal
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 @@ | ||
cabal-version: 3.0 |
2 changes: 2 additions & 0 deletions
2
plugins/hls-cabal-plugin/test/testdata/outline-cabal/section.cabal
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,2 @@ | ||
build-depends: | ||
base >=4.16 && <5 |
2 changes: 2 additions & 0 deletions
2
plugins/hls-cabal-plugin/test/testdata/outline-cabal/sectionarg.cabal
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,2 @@ | ||
if os(windows) | ||
build-depends: Win32 |
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
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