forked from haskell/haskell-language-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExample.hs
234 lines (205 loc) · 8.32 KB
/
Example.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
module Ide.Plugin.Example
(
descriptor
) where
import Control.DeepSeq ( NFData )
import Control.Monad.Trans.Maybe
import Data.Aeson
import Data.Binary
import Data.Functor
import qualified Data.HashMap.Strict as Map
import qualified Data.HashSet as HashSet
import Data.Hashable
import qualified Data.Text as T
import Data.Typeable
import Development.IDE.Core.OfInterest
import Development.IDE.Core.RuleTypes
import Development.IDE.Core.Rules
import Development.IDE.Core.Service
import Development.IDE.Core.Shake
import Development.IDE.Types.Diagnostics as D
import Development.IDE.Types.Location
import Development.IDE.Types.Logger
import Development.Shake hiding ( Diagnostic )
import GHC.Generics
import Ide.Plugin
import Ide.Types
import Language.Haskell.LSP.Types
import Text.Regex.TDFA.Text()
-- ---------------------------------------------------------------------
descriptor :: PluginId -> PluginDescriptor
descriptor plId = (defaultPluginDescriptor plId)
{ pluginRules = exampleRules
, pluginCommands = [PluginCommand "codelens.todo" "example adding" addTodoCmd]
, pluginCodeActionProvider = Just codeAction
, pluginCodeLensProvider = Just codeLens
, pluginHoverProvider = Just hover
, pluginSymbolsProvider = Just symbols
, pluginCompletionProvider = Just completion
}
-- ---------------------------------------------------------------------
hover :: IdeState -> TextDocumentPositionParams -> IO (Either ResponseError (Maybe Hover))
hover = request "Hover" blah (Right Nothing) foundHover
blah :: NormalizedFilePath -> Position -> Action (Maybe (Maybe Range, [T.Text]))
blah _ (Position line col)
= return $ Just (Just (Range (Position line col) (Position (line+1) 0)), ["example hover 1\n"])
-- ---------------------------------------------------------------------
-- Generating Diagnostics via rules
-- ---------------------------------------------------------------------
data Example = Example
deriving (Eq, Show, Typeable, Generic)
instance Hashable Example
instance NFData Example
instance Binary Example
type instance RuleResult Example = ()
exampleRules :: Rules ()
exampleRules = do
define $ \Example file -> do
_pm <- getParsedModule file
let diag = mkDiag file "example" DsError (Range (Position 0 0) (Position 1 0)) "example diagnostic, hello world"
return ([diag], Just ())
action $ do
files <- getFilesOfInterest
void $ uses Example $ HashSet.toList files
mkDiag :: NormalizedFilePath
-> DiagnosticSource
-> DiagnosticSeverity
-> Range
-> T.Text
-> FileDiagnostic
mkDiag file diagSource sev loc msg = (file, D.ShowDiag,)
Diagnostic
{ _range = loc
, _severity = Just sev
, _source = Just diagSource
, _message = msg
, _code = Nothing
, _tags = Nothing
, _relatedInformation = Nothing
}
-- ---------------------------------------------------------------------
-- code actions
-- ---------------------------------------------------------------------
-- | Generate code actions.
codeAction :: CodeActionProvider
codeAction _lf _state _pid (TextDocumentIdentifier uri) _range CodeActionContext{_diagnostics=List _xs} = do
let
title = "Add TODO Item 1"
tedit = [TextEdit (Range (Position 2 0) (Position 2 0))
"-- TODO1 added by Example Plugin directly\n"]
edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing
pure $ Right $ List
[ CACodeAction $ CodeAction title (Just CodeActionQuickFix) (Just $ List []) (Just edit) Nothing ]
-- ---------------------------------------------------------------------
codeLens :: CodeLensProvider
codeLens _lf ideState plId CodeLensParams{_textDocument=TextDocumentIdentifier uri} = do
logInfo (ideLogger ideState) "Example.codeLens entered (ideLogger)" -- AZ
case uriToFilePath' uri of
Just (toNormalizedFilePath -> filePath) -> do
_ <- runIdeAction "Example.codeLens" ideState $ runMaybeT $ useE TypeCheck filePath
_diag <- getDiagnostics ideState
_hDiag <- getHiddenDiagnostics ideState
let
title = "Add TODO Item via Code Lens"
-- tedit = [TextEdit (Range (Position 3 0) (Position 3 0))
-- "-- TODO added by Example Plugin via code lens action\n"]
-- edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing
range = Range (Position 3 0) (Position 4 0)
let cmdParams = AddTodoParams uri "do abc"
cmd <- mkLspCommand plId "codelens.todo" title (Just [(toJSON cmdParams)])
pure $ Right $ List [ CodeLens range (Just cmd) Nothing ]
Nothing -> pure $ Right $ List []
-- ---------------------------------------------------------------------
-- | Parameters for the addTodo PluginCommand.
data AddTodoParams = AddTodoParams
{ file :: Uri -- ^ Uri of the file to add the pragma to
, todoText :: T.Text
}
deriving (Show, Eq, Generic, ToJSON, FromJSON)
addTodoCmd :: CommandFunction AddTodoParams
addTodoCmd _lf _ide (AddTodoParams uri todoText) = do
let
pos = Position 3 0
textEdits = List
[TextEdit (Range pos pos)
("-- TODO:" <> todoText <> "\n")
]
res = WorkspaceEdit
(Just $ Map.singleton uri textEdits)
Nothing
return (Right Null, Just (WorkspaceApplyEdit, ApplyWorkspaceEditParams res))
-- ---------------------------------------------------------------------
foundHover :: (Maybe Range, [T.Text]) -> Either ResponseError (Maybe Hover)
foundHover (mbRange, contents) =
Right $ Just $ Hover (HoverContents $ MarkupContent MkMarkdown
$ T.intercalate sectionSeparator contents) mbRange
-- | Respond to and log a hover or go-to-definition request
request
:: T.Text
-> (NormalizedFilePath -> Position -> Action (Maybe a))
-> Either ResponseError b
-> (a -> Either ResponseError b)
-> IdeState
-> TextDocumentPositionParams
-> IO (Either ResponseError b)
request label getResults notFound found ide (TextDocumentPositionParams (TextDocumentIdentifier uri) pos _) = do
mbResult <- case uriToFilePath' uri of
Just path -> logAndRunRequest label getResults ide pos path
Nothing -> pure Nothing
pure $ maybe notFound found mbResult
logAndRunRequest :: T.Text -> (NormalizedFilePath -> Position -> Action b)
-> IdeState -> Position -> String -> IO b
logAndRunRequest label getResults ide pos path = do
let filePath = toNormalizedFilePath path
logInfo (ideLogger ide) $
label <> " request at position " <> T.pack (showPosition pos) <>
" in file: " <> T.pack path
runAction "Example" ide $ getResults filePath pos
-- ---------------------------------------------------------------------
symbols :: SymbolsProvider
symbols _lf _ide (DocumentSymbolParams _doc _mt)
= pure $ Right [r]
where
r = DocumentSymbol name detail kind deprecation range selR chList
name = "Example_symbol_name"
detail = Nothing
kind = SkVariable
deprecation = Nothing
range = Range (Position 2 0) (Position 2 5)
selR = range
chList = Nothing
-- ---------------------------------------------------------------------
completion :: CompletionProvider
completion _lf _ide (CompletionParams _doc _pos _mctxt _mt)
= pure $ Right $ Completions $ List [r]
where
r = CompletionItem label kind tags detail documentation deprecated preselect
sortText filterText insertText insertTextFormat
textEdit additionalTextEdits commitCharacters
command xd
label = "Example completion"
kind = Nothing
tags = List []
detail = Nothing
documentation = Nothing
deprecated = Nothing
preselect = Nothing
sortText = Nothing
filterText = Nothing
insertText = Nothing
insertTextFormat = Nothing
textEdit = Nothing
additionalTextEdits = Nothing
commitCharacters = Nothing
command = Nothing
xd = Nothing
-- ---------------------------------------------------------------------