Skip to content

Commit 2857eee

Browse files
July541jneira
andauthored
Support call hierarchy on type signature & add plugin to generic config & docs (#2072)
* Document call hierarchy plugin * Fix typo * Supoort call hierarchy on type signatures * Add change log in readme * Add call hierarchy config * Remove unused tests * Add plugin section in main readme * Update plugins/hls-call-hierarchy-plugin/test/Main.hs Co-authored-by: Javier Neira <[email protected]> * Update plugins/hls-call-hierarchy-plugin/README.md Detailed description about config Co-authored-by: Javier Neira <[email protected]> * Revise version Co-authored-by: Javier Neira <[email protected]>
1 parent 463d804 commit 2857eee

File tree

8 files changed

+99
-33
lines changed

8 files changed

+99
-33
lines changed

hls-plugin-api/hls-plugin-api.cabal

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 2.4
22
name: hls-plugin-api
3-
version: 1.2.0.0
3+
version: 1.2.0.1
44
synopsis: Haskell Language Server API for plugin communication
55
description:
66
Please see the README on GitHub at <https://github.com/haskell/haskell-language-server#readme>

hls-plugin-api/src/Ide/Plugin/ConfigUtils.hs

+9-7
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,14 @@ pluginsToDefaultConfig IdePlugins {..} =
8686
-- This function captures ide methods registered by the plugin, and then converts it to kv pairs
8787
handlersToGenericDefaultConfig :: DSum.DSum IdeMethod f -> [A.Pair]
8888
handlersToGenericDefaultConfig (IdeMethod m DSum.:=> _) = case m of
89-
STextDocumentCodeAction -> ["codeActionsOn" A..= True]
90-
STextDocumentCodeLens -> ["codeLensOn" A..= True]
91-
STextDocumentRename -> ["renameOn" A..= True]
92-
STextDocumentHover -> ["hoverOn" A..= True]
93-
STextDocumentDocumentSymbol -> ["symbolsOn" A..= True]
94-
STextDocumentCompletion -> ["completionOn" A..= True]
95-
_ -> []
89+
STextDocumentCodeAction -> ["codeActionsOn" A..= True]
90+
STextDocumentCodeLens -> ["codeLensOn" A..= True]
91+
STextDocumentRename -> ["renameOn" A..= True]
92+
STextDocumentHover -> ["hoverOn" A..= True]
93+
STextDocumentDocumentSymbol -> ["symbolsOn" A..= True]
94+
STextDocumentCompletion -> ["completionOn" A..= True]
95+
STextDocumentPrepareCallHierarchy -> ["callHierarchyOn" A..= True]
96+
_ -> []
9697

9798
-- | Generates json schema used in haskell vscode extension
9899
-- Similar to 'pluginsToDefaultConfig' but simpler, since schema has a flatten structure
@@ -121,6 +122,7 @@ pluginsToVSCodeExtensionSchema IdePlugins {..} = A.object $ mconcat $ singlePlug
121122
STextDocumentHover -> [withIdPrefix "hoverOn" A..= schemaEntry "hover"]
122123
STextDocumentDocumentSymbol -> [withIdPrefix "symbolsOn" A..= schemaEntry "symbols"]
123124
STextDocumentCompletion -> [withIdPrefix "completionOn" A..= schemaEntry "completions"]
125+
STextDocumentPrepareCallHierarchy -> [withIdPrefix "callHierarchyOn" A..= schemaEntry "call hierarchy"]
124126
_ -> []
125127
schemaEntry desc =
126128
A.object
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Call hierarchy plugin for the [Haskell Language Server](https://github.com/haskell/haskell-language-server#readme)
2+
3+
The call hierarchy plugin can review the code to determine where functions are called and how they relate to other functions.
4+
5+
This plugin is useful when debugging and refactoring code because it allows you to see how different parts of the code are related. And it is more conducive for users to quickly understand their macro architecture in the face of strange code.
6+
7+
## Demo
8+
9+
![Call Hierarchy in Emacs](call-hierarchy-in-emacs.gif)
10+
11+
![Call Hierarchy in VSCode](call-hierarchy-in-vscode.gif)
12+
13+
## Prerequisite
14+
None. You can experience the whole feature without any setting.
15+
16+
## Configuration
17+
Enabled by default. You can disable it in your editor settings whenever you like.
18+
19+
```json
20+
{
21+
"haskell.plugin.callHierarchy.globalOn": true
22+
}
23+
24+
## Change log
25+
### 1.0.0.1
26+
- Support call hierarchy on type signatures.
27+
28+
## Acknowledgments
29+
Supported by
30+
31+
* [Google Summer of Code](https://summerofcode.withgoogle.com/)
32+
* Warm and timely help from mentors [@jneira](https://github.com/jneira) and [@pepeiborra](https://github.com/pepeiborra)
Loading
Loading

plugins/hls-call-hierarchy-plugin/hls-call-hierarchy-plugin.cabal

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 2.4
22
name: hls-call-hierarchy-plugin
3-
version: 1.0.0.0
3+
version: 1.0.0.1
44
synopsis: Call hierarchy plugin for Haskell Language Server
55
license: Apache-2.0
66
license-file: LICENSE

plugins/hls-call-hierarchy-plugin/src/Ide/Plugin/CallHierarchy/Internal.hs

+37-19
Original file line numberDiff line numberDiff line change
@@ -62,38 +62,43 @@ constructFromAst nfp pos =
6262
\case
6363
Nothing -> pure Nothing
6464
Just (HAR _ hf _ _ _) -> do
65-
case listToMaybe $ pointCommand hf pos extract of
66-
Just res -> pure $ Just $ mapMaybe (construct nfp) res
67-
Nothing -> pure Nothing
65+
resolveIntoCallHierarchy hf pos nfp
66+
67+
resolveIntoCallHierarchy :: Applicative f => HieASTs a -> Position -> NormalizedFilePath -> f (Maybe [CallHierarchyItem])
68+
resolveIntoCallHierarchy hf pos nfp =
69+
case listToMaybe $ pointCommand hf pos extract of
70+
Just res -> pure $ Just $ mapMaybe (construct nfp hf) res
71+
Nothing -> pure Nothing
6872

6973
extract :: HieAST a -> [(Identifier, S.Set ContextInfo, Span)]
7074
extract ast = let span = nodeSpan ast
7175
infos = M.toList $ M.map identInfo (Compat.getNodeIds ast)
7276
in [ (ident, contexts, span) | (ident, contexts) <- infos ]
7377

7478
recFieldInfo, declInfo, valBindInfo, classTyDeclInfo,
75-
useInfo, patternBindInfo :: S.Set ContextInfo -> Maybe ContextInfo
76-
recFieldInfo ctxs = listToMaybe [ctx | ctx@RecField{} <- S.toList ctxs]
77-
declInfo ctxs = listToMaybe [ctx | ctx@Decl{} <- S.toList ctxs]
78-
valBindInfo ctxs = listToMaybe [ctx | ctx@ValBind{} <- S.toList ctxs]
79-
classTyDeclInfo ctxs = listToMaybe [ctx | ctx@ClassTyDecl{} <- S.toList ctxs]
80-
useInfo ctxs = listToMaybe [Use | Use <- S.toList ctxs]
81-
patternBindInfo ctxs = listToMaybe [ctx | ctx@PatternBind{} <- S.toList ctxs]
82-
83-
construct :: NormalizedFilePath -> (Identifier, S.Set ContextInfo, Span) -> Maybe CallHierarchyItem
84-
construct nfp (ident, contexts, ssp)
79+
useInfo, patternBindInfo, tyDeclInfo :: [ContextInfo] -> Maybe ContextInfo
80+
recFieldInfo ctxs = listToMaybe [ctx | ctx@RecField{} <- ctxs]
81+
declInfo ctxs = listToMaybe [ctx | ctx@Decl{} <- ctxs]
82+
valBindInfo ctxs = listToMaybe [ctx | ctx@ValBind{} <- ctxs]
83+
classTyDeclInfo ctxs = listToMaybe [ctx | ctx@ClassTyDecl{} <- ctxs]
84+
useInfo ctxs = listToMaybe [Use | Use <- ctxs]
85+
patternBindInfo ctxs = listToMaybe [ctx | ctx@PatternBind{} <- ctxs]
86+
tyDeclInfo ctxs = listToMaybe [TyDecl | TyDecl <- ctxs]
87+
88+
construct :: NormalizedFilePath -> HieASTs a -> (Identifier, S.Set ContextInfo, Span) -> Maybe CallHierarchyItem
89+
construct nfp hf (ident, contexts, ssp)
8590
| isInternalIdentifier ident = Nothing
8691

87-
| Just (RecField RecFieldDecl _) <- recFieldInfo contexts
92+
| Just (RecField RecFieldDecl _) <- recFieldInfo ctxList
8893
-- ignored type span
8994
= Just $ mkCallHierarchyItem' ident SkField ssp ssp
9095

91-
| Just ctx <- valBindInfo contexts
96+
| Just ctx <- valBindInfo ctxList
9297
= Just $ case ctx of
9398
ValBind _ _ span -> mkCallHierarchyItem' ident SkFunction (renderSpan span) ssp
9499
_ -> mkCallHierarchyItem' ident skUnknown ssp ssp
95100

96-
| Just ctx <- declInfo contexts
101+
| Just ctx <- declInfo ctxList
97102
= Just $ case ctx of
98103
Decl ClassDec span -> mkCallHierarchyItem' ident SkInterface (renderSpan span) ssp
99104
Decl ConDec span -> mkCallHierarchyItem' ident SkConstructor (renderSpan span) ssp
@@ -103,15 +108,18 @@ construct nfp (ident, contexts, ssp)
103108
Decl SynDec span -> mkCallHierarchyItem' ident SkTypeParameter (renderSpan span) ssp
104109
_ -> mkCallHierarchyItem' ident skUnknown ssp ssp
105110

106-
| Just (ClassTyDecl span) <- classTyDeclInfo contexts
111+
| Just (ClassTyDecl span) <- classTyDeclInfo ctxList
107112
= Just $ mkCallHierarchyItem' ident SkMethod (renderSpan span) ssp
108113

109-
| Just (PatternBind _ _ span) <- patternBindInfo contexts
114+
| Just (PatternBind _ _ span) <- patternBindInfo ctxList
110115
= Just $ mkCallHierarchyItem' ident SkFunction (renderSpan span) ssp
111116

112-
| Just Use <- useInfo contexts
117+
| Just Use <- useInfo ctxList
113118
= Just $ mkCallHierarchyItem' ident SkInterface ssp ssp
114119

120+
| Just _ <- tyDeclInfo ctxList
121+
= renderTyDecl
122+
115123
| otherwise = Nothing
116124
where
117125
renderSpan = \case Just span -> span
@@ -125,6 +133,16 @@ construct nfp (ident, contexts, ssp)
125133
Left _ -> False
126134
Right name -> isInternalName name
127135

136+
ctxList = S.toList contexts
137+
138+
renderTyDecl = case ident of
139+
Left _ -> Nothing
140+
Right name -> case getNameBindingInClass name ssp (getAsts hf) of
141+
Nothing -> Nothing
142+
Just sp -> case resolveIntoCallHierarchy hf (realSrcSpanToRange sp ^. L.start) nfp of
143+
Just (Just items) -> listToMaybe items
144+
_ -> Nothing
145+
128146
mkCallHierarchyItem :: NormalizedFilePath -> Identifier -> SymbolKind -> Span -> Span -> CallHierarchyItem
129147
mkCallHierarchyItem nfp ident kind span selSpan =
130148
CallHierarchyItem

plugins/hls-call-hierarchy-plugin/test/Main.hs

+19-5
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ plugin = descriptor "callHierarchy"
2525

2626
main :: IO ()
2727
main = defaultTestRunner $
28-
testGroup "Call Hierarchy"
29-
[ prepareCallHierarchyTests
30-
, incomingCallsTests
31-
, outgoingCallsTests
32-
]
28+
testGroup "Call Hierarchy"
29+
[ prepareCallHierarchyTests
30+
, incomingCallsTests
31+
, outgoingCallsTests
32+
]
3333

3434
prepareCallHierarchyTests :: TestTree
3535
prepareCallHierarchyTests =
@@ -164,6 +164,20 @@ prepareCallHierarchyTests =
164164
selRange = mkRange 1 13 1 14
165165
expected = mkCallHierarchyItemC "A" SkConstructor range selRange
166166
oneCaseWithCreate contents 1 13 expected
167+
, testGroup "type signature"
168+
[ testCase "next line" $ do
169+
let contents = T.unlines ["a::Int", "a=3"]
170+
range = mkRange 1 0 1 3
171+
selRange = mkRange 1 0 1 1
172+
expected = mkCallHierarchyItemV "a" SkFunction range selRange
173+
oneCaseWithCreate contents 0 0 expected
174+
, testCase "multi functions" $ do
175+
let contents = T.unlines [ "a,b::Int", "a=3", "b=4"]
176+
range = mkRange 2 0 2 3
177+
selRange = mkRange 2 0 2 1
178+
expected = mkCallHierarchyItemV "b" SkFunction range selRange
179+
oneCaseWithCreate contents 0 2 expected
180+
]
167181
]
168182

169183
incomingCallsTests :: TestTree

0 commit comments

Comments
 (0)