1
+ {-# LANGUAGE ScopedTypeVariables #-}
1
2
{-# OPTIONS_GHC -fno-warn-partial-type-signatures #-}
2
-
3
- {-# LANGUAGE PartialTypeSignatures #-}
4
3
{-# LANGUAGE DataKinds #-}
5
- {-# LANGUAGE OverloadedStrings #-}
6
4
{-# LANGUAGE GADTs #-}
5
+ {-# LANGUAGE OverloadedStrings #-}
6
+ {-# LANGUAGE PartialTypeSignatures #-}
7
+ {-# LANGUAGE RankNTypes #-}
8
+
7
9
module Haskell.Ide.HaRePlugin where
8
10
9
- import Control.Monad.IO.Class
11
+ import Control.Monad.State
12
+ import Control.Monad.Trans.Control
10
13
import Data.Aeson
14
+ import Data.Monoid
11
15
import qualified Data.Text as T
16
+ import Exception
12
17
import Haskell.Ide.Engine.PluginDescriptor
13
18
import Haskell.Ide.Engine.PluginUtils
14
19
import Haskell.Ide.Engine.SemanticTypes
15
- import Language.Haskell.Refact.HaRe
16
-
17
-
18
- import qualified Exception as G
19
- import qualified Language.Haskell.GhcMod as GM
20
20
import qualified Language.Haskell.GhcMod.Monad as GM
21
- import System.Directory
21
+ import qualified Language.Haskell.GhcMod.Error as GM
22
+ import Language.Haskell.Refact.HaRe
23
+ import Language.Haskell.Refact.Utils.Monad
24
+ import Language.Haskell.Refact.Utils.Types
25
+ import Language.Haskell.Refact.Utils.Utils
22
26
import System.FilePath
23
27
24
28
-- ---------------------------------------------------------------------
@@ -66,11 +70,11 @@ demoteCmd = CmdSync $ \_ctxs req ->
66
70
case getParams (IdFile " file" :& IdPos " start_pos" :& RNil ) req of
67
71
Left err -> return err
68
72
Right (ParamFile fileName :& ParamPos pos :& RNil ) ->
69
- runHareCommand fileName " demote" (\ s o f -> demote s o f pos)
73
+ runHareCommand " demote" (compDemote ( T. unpack fileName) pos)
70
74
Right _ -> return $ IdeResponseError (IdeError InternalError
71
75
" HaRePlugin.demoteCmd: ghc’s exhaustiveness checker is broken" Null )
72
76
73
- -- demote :: RefactSettings -> GM.Options -> FilePath -> SimpPos -> IO [FilePath]
77
+ -- compDemote :: FilePath -> SimpPos -> IO [FilePath]
74
78
75
79
-- ---------------------------------------------------------------------
76
80
@@ -79,11 +83,11 @@ dupdefCmd = CmdSync $ \_ctxs req ->
79
83
case getParams (IdFile " file" :& IdPos " start_pos" :& IdText " name" :& RNil ) req of
80
84
Left err -> return err
81
85
Right (ParamFile fileName :& ParamPos pos :& ParamText name :& RNil ) ->
82
- runHareCommand fileName " duplicateDef " (\ s o f -> duplicateDef s o f (T. unpack name) pos)
86
+ runHareCommand " dupdef " (compDuplicateDef ( T. unpack fileName) (T. unpack name) pos)
83
87
Right _ -> return $ IdeResponseError (IdeError InternalError
84
88
" HaRePlugin.dupdefCmd: ghc’s exhaustiveness checker is broken" Null )
85
89
86
- -- duplicateDef :: RefactSettings -> GM.Options -> FilePath -> String -> SimpPos -> IO [FilePath]
90
+ -- compDuplicateDef :: FilePath -> String -> SimpPos -> IO [FilePath]
87
91
88
92
-- ---------------------------------------------------------------------
89
93
@@ -92,11 +96,11 @@ iftocaseCmd = CmdSync $ \_ctxs req ->
92
96
case getParams (IdFile " file" :& IdPos " start_pos" :& IdPos " end_pos" :& RNil ) req of
93
97
Left err -> return err
94
98
Right (ParamFile fileName :& ParamPos start :& ParamPos end :& RNil ) ->
95
- runHareCommand fileName " ifToCase " (\ s o f -> ifToCase s o f start end)
99
+ runHareCommand " iftocase " (compIfToCase ( T. unpack fileName) start end)
96
100
Right _ -> return $ IdeResponseError (IdeError InternalError
97
101
" HaRePlugin.ifToCaseCmd: ghc’s exhaustiveness checker is broken" Null )
98
102
99
- -- ifToCase :: RefactSettings -> GM.Options -> FilePath -> SimpPos -> SimpPos -> IO [FilePath]
103
+ -- compIfToCase :: FilePath -> SimpPos -> SimpPos -> IO [FilePath]
100
104
101
105
-- ---------------------------------------------------------------------
102
106
@@ -105,11 +109,11 @@ liftonelevelCmd = CmdSync $ \_ctxs req ->
105
109
case getParams (IdFile " file" :& IdPos " start_pos" :& RNil ) req of
106
110
Left err -> return err
107
111
Right (ParamFile fileName :& ParamPos pos :& RNil ) ->
108
- runHareCommand fileName " liftOneLevel " (\ s o f -> liftOneLevel s o f pos)
112
+ runHareCommand " liftonelevel " (compLiftOneLevel ( T. unpack fileName) pos)
109
113
Right _ -> return $ IdeResponseError (IdeError InternalError
110
114
" HaRePlugin.liftOneLevel: ghc’s exhaustiveness checker is broken" Null )
111
115
112
- -- liftOneLevel :: RefactSettings -> GM.Options -> FilePath -> SimpPos -> IO [FilePath]
116
+ -- compLiftOneLevel :: FilePath -> SimpPos -> IO [FilePath]
113
117
114
118
-- ---------------------------------------------------------------------
115
119
@@ -118,11 +122,11 @@ lifttotoplevelCmd = CmdSync $ \_ctxs req ->
118
122
case getParams (IdFile " file" :& IdPos " start_pos" :& RNil ) req of
119
123
Left err -> return err
120
124
Right (ParamFile fileName :& ParamPos pos :& RNil ) ->
121
- runHareCommand fileName " liftToTopLevel " (\ s o f -> liftToTopLevel s o f pos)
125
+ runHareCommand " lifttotoplevel " (compLiftToTopLevel ( T. unpack fileName) pos)
122
126
Right _ -> return $ IdeResponseError (IdeError InternalError
123
127
" HaRePlugin.liftToTopLevel: ghc’s exhaustiveness checker is broken" Null )
124
128
125
- -- liftToTopLevel :: RefactSettings -> GM.Options -> FilePath -> SimpPos -> IO [FilePath]
129
+ -- compLiftToTopLevel :: FilePath -> SimpPos -> IO [FilePath]
126
130
127
131
-- ---------------------------------------------------------------------
128
132
@@ -131,11 +135,11 @@ renameCmd = CmdSync $ \_ctxs req ->
131
135
case getParams (IdFile " file" :& IdPos " start_pos" :& IdText " name" :& RNil ) req of
132
136
Left err -> return err
133
137
Right (ParamFile fileName :& ParamPos pos :& ParamText name :& RNil ) ->
134
- runHareCommand fileName " rename" (\ s o f -> rename s o f (T. unpack name) pos)
138
+ runHareCommand " rename" (compRename ( T. unpack fileName) (T. unpack name) pos)
135
139
Right _ -> return $ IdeResponseError (IdeError InternalError
136
140
" HaRePlugin.renameCmd: ghc’s exhaustiveness checker is broken" Null )
137
141
138
- -- rename :: RefactSettings -> Options -> FilePath -> String -> SimpPos -> IO [FilePath]
142
+ -- compRename :: FilePath -> String -> SimpPos -> IO [FilePath]
139
143
140
144
-- ---------------------------------------------------------------------
141
145
@@ -152,27 +156,51 @@ makeRefactorResult changedFiles = do
152
156
-- ---------------------------------------------------------------------
153
157
154
158
155
- runHareCommand :: T. Text -- ^ The file name we'll operate on
156
- -> String -- ^ command name for log
157
- -> (RefactSettings -> GM. Options -> FilePath -> IO [FilePath ])
159
+ runHareCommand :: String -> RefactGhc [ApplyRefacResult ]
158
160
-> IdeM (IdeResponse RefactorResult )
159
- runHareCommand fp name cmd = do
160
- let (dir,_) = fileInfo fp
161
- let opts = GM. defaultOptions
162
- old <- liftIO getCurrentDirectory
163
- G. gbracket (liftIO $ setCurrentDirectory dir)
164
- (\ _ -> liftIO $ setCurrentDirectory old)
165
- (\ _ -> do
166
- -- we need to get the root of our folder
167
- -- ghc-mod returns a new line at the end...
168
- root <- takeWhile (`notElem` [' \r ' ,' \n ' ]) <$> GM. runGmOutT opts GM. rootInfo
169
- liftIO $ setCurrentDirectory root
170
- res <- liftIO $ catchException $ cmd defaultSettings GM. defaultOptions (T. unpack fp)
171
- liftIO $ setCurrentDirectory old
172
- case res of
173
- Left err -> return $ IdeResponseFail (IdeError PluginError
174
- (T. pack $ name ++ " : " ++ show err) Null )
175
- Right fs -> do
176
- r <- liftIO $ makeRefactorResult fs
177
- return (IdeResponseOk r)
178
- )
161
+ runHareCommand name cmd =
162
+ do let initialState =
163
+ RefSt {rsSettings = defaultSettings
164
+ ,rsUniqState = 1
165
+ ,rsSrcSpanCol = 1
166
+ ,rsFlags = RefFlags False
167
+ ,rsStorage = StorageNone
168
+ ,rsCurrentTarget = Nothing
169
+ ,rsModule = Nothing }
170
+ let cmd' = unRefactGhc cmd
171
+ embeddedCmd =
172
+ GM. unGmlT $
173
+ hoist (liftIO . flip evalStateT initialState)
174
+ (GM. GmlT cmd')
175
+ handlers
176
+ :: Applicative m
177
+ => [GM. GHandler m (Either String a )]
178
+ handlers =
179
+ [GM. GHandler (\ (ErrorCall e) -> pure (Left e))
180
+ ,GM. GHandler (\ (err :: GM. GhcModError ) -> pure (Left (show err)))]
181
+ eitherRes <- fmap Right embeddedCmd `GM.gcatches` handlers
182
+ case eitherRes of
183
+ Left err ->
184
+ pure (IdeResponseFail
185
+ (IdeError PluginError
186
+ (T. pack $ name <> " : \" " <> err <> " \" " )
187
+ Null ))
188
+ Right res ->
189
+ do liftIO $
190
+ writeRefactoredFiles (rsetVerboseLevel defaultSettings)
191
+ res
192
+ let files = modifiedFiles res
193
+ refactRes <- liftIO $ makeRefactorResult files
194
+ pure (IdeResponseOk refactRes)
195
+
196
+ -- | This is like hoist from the mmorph package, but build on
197
+ -- `MonadTransControl` since we don’t have an `MFunctor` instance.
198
+ hoist
199
+ :: (MonadTransControl t ,Monad (t m' ),Applicative m' ,Monad m' ,Monad m )
200
+ => (forall b . m b -> m' b ) -> t m a -> t m' a
201
+ hoist f a =
202
+ liftWith (\ run ->
203
+ let b = run a
204
+ c = f b
205
+ in pure c) >>=
206
+ restoreT
0 commit comments