-
-
Notifications
You must be signed in to change notification settings - Fork 406
Cabal plugin outline view #4323
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
Changes from 4 commits
d49a000
632f5a0
3574165
965d61b
fd0b2ea
a5e7e53
d616c54
a953ecb
d201493
f4d57a5
526fac3
9860ea3
a79be35
a0642ef
c867a29
aeca984
ae772a2
f77dea5
6f9fbcd
4735e7d
000dcbe
851daef
cb2fbf7
050af38
af4d8c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,131 @@ | ||||||
{-# LANGUAGE CPP #-} | ||||||
{-# LANGUAGE DataKinds #-} | ||||||
{-# LANGUAGE DuplicateRecordFields #-} | ||||||
{-# LANGUAGE GADTs #-} | ||||||
{-# LANGUAGE OverloadedStrings #-} | ||||||
{-# LANGUAGE RecordWildCards #-} | ||||||
{-# LANGUAGE ViewPatterns #-} | ||||||
|
||||||
module Ide.Plugin.Cabal.Outline | ||||||
( moduleOutline, | ||||||
) | ||||||
where | ||||||
|
||||||
import Control.Monad.IO.Class | ||||||
import Data.Maybe | ||||||
import Data.Text qualified as T | ||||||
import Data.Text.Encoding (decodeASCII, decodeLatin1) | ||||||
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), | ||||||
FieldLine (FieldLine), | ||||||
Name (Name), | ||||||
SectionArg (SecArgName, SecArgOther, SecArgStr), | ||||||
) | ||||||
import Distribution.Parsec.Position (Position) | ||||||
import Ide.Plugin.Cabal.Completion.Types (ParseCabalFields (..), cabalPositionToLSPPosition) | ||||||
import Ide.Plugin.Cabal.Orphans () | ||||||
import Ide.Types | ||||||
import Language.LSP.Protocol.Message qualified as LSP | ||||||
import Language.LSP.Protocol.Types qualified as LSP | ||||||
|
||||||
moduleOutline :: PluginMethodHandler IdeState LSP.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 [] | ||||||
|
||||||
documentSymbolForField :: Field Position -> Maybe LSP.DocumentSymbol | ||||||
documentSymbolForField (Field (Name pos fieldName) fieldLines) = | ||||||
Just | ||||||
(defDocumentSymbol range) | ||||||
{ LSP._name = decodeASCII fieldName, | ||||||
fendor marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
LSP._kind = LSP.SymbolKind_Object, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
LSP._children = Just $ mapMaybe documentSymbolForFieldLine fieldLines | ||||||
} | ||||||
where | ||||||
range = cabalPositionToLSPRange pos `addNameLengthToLSPRange` decodeASCII fieldName | ||||||
documentSymbolForField (Section (Name pos fieldName) sectionArgs fields) = | ||||||
Just | ||||||
(defDocumentSymbol range) | ||||||
{ LSP._name = decodeASCII fieldName, | ||||||
LSP._kind = LSP.SymbolKind_Object, | ||||||
LSP._children = | ||||||
Just | ||||||
( mapMaybe documentSymbolForField fields | ||||||
++ mapMaybe documentSymbolForSectionArgs sectionArgs | ||||||
) | ||||||
} | ||||||
where | ||||||
range = cabalPositionToLSPRange pos `addNameLengthToLSPRange` decodeASCII fieldName | ||||||
|
||||||
documentSymbolForSectionArgs :: SectionArg Position -> Maybe LSP.DocumentSymbol | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm unsure we want to include these either, what do they correspond to? It looks like this is responsible for e.g. the weirdness with conditionals. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think they can also include the names of stanzas so we definitely want to process them somehow but probably not into their own DocumentSymbol element |
||||||
documentSymbolForSectionArgs (SecArgName pos identifier) = | ||||||
Just | ||||||
(defDocumentSymbol range) | ||||||
{ LSP._name = decodeLatin1 identifier, | ||||||
fendor marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
LSP._kind = LSP.SymbolKind_Variable, | ||||||
LSP._children = Nothing | ||||||
} | ||||||
where | ||||||
range = cabalPositionToLSPRange pos `addNameLengthToLSPRange` decodeASCII identifier | ||||||
documentSymbolForSectionArgs (SecArgStr pos quotedString) = | ||||||
Just | ||||||
(defDocumentSymbol range) | ||||||
{ LSP._name = decodeLatin1 quotedString, | ||||||
LSP._kind = LSP.SymbolKind_Constant, | ||||||
LSP._children = Nothing | ||||||
} | ||||||
where | ||||||
range = cabalPositionToLSPRange pos `addNameLengthToLSPRange` decodeASCII quotedString | ||||||
documentSymbolForSectionArgs (SecArgOther pos string) = | ||||||
Just | ||||||
(defDocumentSymbol range) | ||||||
{ LSP._name = decodeLatin1 string, | ||||||
LSP._kind = LSP.SymbolKind_String, | ||||||
LSP._children = Nothing | ||||||
} | ||||||
where | ||||||
range = cabalPositionToLSPRange pos `addNameLengthToLSPRange` decodeASCII string | ||||||
|
||||||
documentSymbolForFieldLine :: FieldLine Position -> Maybe LSP.DocumentSymbol | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think what I'm suggesting is that we get rid of this. |
||||||
documentSymbolForFieldLine (FieldLine pos line) = | ||||||
Just | ||||||
(defDocumentSymbol range) | ||||||
{ LSP._name = decodeLatin1 line, -- since there is no ascii invariant (?) | ||||||
LSP._kind = LSP.SymbolKind_Field, | ||||||
LSP._children = Nothing -- can't delete even though the base case covers this (?) | ||||||
} | ||||||
where | ||||||
range = cabalPositionToLSPRange pos `addNameLengthToLSPRange` decodeASCII line | ||||||
|
||||||
cabalPositionToLSPRange :: Position -> LSP.Range | ||||||
fendor marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
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 -> LSP.DocumentSymbol | ||||||
defDocumentSymbol range = LSP.DocumentSymbol {..} | ||||||
where | ||||||
_detail = Nothing | ||||||
_deprecated = Nothing | ||||||
_name = "" | ||||||
_kind = LSP.SymbolKind_File | ||||||
_range = range | ||||||
_selectionRange = range | ||||||
_children = Nothing | ||||||
_tags = Nothing |
Uh oh!
There was an error while loading. Please reload this page.