Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 222600f

Browse files
committed
Refactor ExtensibleState
This removes the persistence since we don’t need it. Also it replaces the existential by Dynamic from Data.Dynamic. In addition to that it replaces some undefined hacks using ScopedTypeVariables.
1 parent 3e09229 commit 222600f

File tree

2 files changed

+26
-68
lines changed

2 files changed

+26
-68
lines changed
Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE PatternGuards #-}
1+
{-# LANGUAGE ScopedTypeVariables #-}
22
-- Based on the one in xmonad-contrib, original header below
33
-----------------------------------------------------------------------------
44
-- |
@@ -24,24 +24,21 @@ module Haskell.Ide.Engine.ExtensibleState (
2424
, gets
2525
) where
2626

27-
import Control.Applicative
28-
import Data.Typeable (typeOf,Typeable,cast)
29-
import qualified Data.Map as M
30-
import Haskell.Ide.Engine.PluginDescriptor
3127
import qualified Control.Monad.State.Strict as State
32-
import Data.Maybe (fromMaybe)
33-
import Control.Monad
34-
import Control.Monad.Trans.Class
28+
import Control.Monad.Trans.Class
29+
import Data.Dynamic
30+
import qualified Data.Map as M
31+
import Haskell.Ide.Engine.PluginDescriptor
3532

3633
-- ---------------------------------------------------------------------
3734
-- $usage
3835
--
39-
-- To utilize this feature in a contrib module, create a data type
36+
-- To utilize this feature in a plugin, create a data type
4037
-- and make it an instance of ExtensionClass. You can then use
4138
-- the functions from this module for storing and retrieving your data:
4239
--
4340
-- > {-# LANGUAGE DeriveDataTypeable #-}
44-
-- > import qualified XMonad.Util.ExtensibleState as XS
41+
-- > import qualified Haskell.Ide.Engine.ExtensibleState as XS
4542
-- >
4643
-- > data ListStorage = ListStorage [Integer] deriving Typeable
4744
-- > instance ExtensionClass ListStorage where
@@ -58,28 +55,19 @@ import Control.Monad.Trans.Class
5855
--
5956
-- > .. XS.get :: X ListStorage
6057
--
61-
-- To make your data persistent between restarts, the data type needs to be
62-
-- an instance of Read and Show and the instance declaration has to be changed:
63-
--
6458
-- > data ListStorage = ListStorage [Integer] deriving (Typeable,Read,Show)
6559
-- >
6660
-- > instance ExtensionClass ListStorage where
6761
-- > initialValue = ListStorage []
68-
-- > extensionType = PersistentExtension
6962
--
70-
-- One should take care that the string representation of the chosen type
71-
-- is unique among the stored values, otherwise it will be overwritten.
72-
-- Normally these string representations contain fully qualified module names
73-
-- when automatically deriving Typeable, so
74-
-- name collisions should not be a problem in most cases.
7563
-- A module should not try to store common datatypes(e.g. a list of Integers)
7664
-- without a custom data type as a wrapper to avoid collisions with other modules
7765
-- trying to store the same data type without a wrapper.
7866
--
7967

8068
-- | Modify the map of state extensions by applying the given function.
81-
modifyStateExts :: (M.Map String (Either String StateExtension)
82-
-> M.Map String (Either String StateExtension))
69+
modifyStateExts :: (M.Map TypeRep Dynamic
70+
-> M.Map TypeRep Dynamic)
8371
-> IdeM ()
8472
modifyStateExts f = lift $ lift $ State.modify $ \st -> st { extensibleState = f (extensibleState st) }
8573

@@ -92,30 +80,22 @@ modify f = put . f =<< get
9280
-- type will be overwritten. (More precisely: A value whose string representation of its type
9381
-- is equal to the new one's)
9482
put :: ExtensionClass a => a -> IdeM ()
95-
put v = modifyStateExts . M.insert (show . typeOf $ v) . Right . extensionType $ v
83+
put v = modifyStateExts . M.insert (typeOf $ v) . toDyn $ v
9684

9785
-- | Try to retrieve a value of the requested type, return an initial value if there is no such value.
98-
get :: ExtensionClass a => IdeM a
99-
get = getState' undefined -- `trick' to avoid needing -XScopedTypeVariables
100-
where toValue val = maybe initialValue id $ cast val
101-
getState' :: ExtensionClass a => a -> IdeM a
102-
getState' k = do
103-
v <- lift $ lift $ State.gets $ M.lookup (show . typeOf $ k) . extensibleState
104-
case v of
105-
Just (Right (StateExtension val)) -> return $ toValue val
106-
Just (Right (PersistentExtension val)) -> return $ toValue val
107-
Just (Left str) | PersistentExtension x <- extensionType k -> do
108-
let val = fromMaybe initialValue $ cast =<< safeRead str `asTypeOf` Just x
109-
put (val `asTypeOf` k)
110-
return val
111-
_ -> return $ initialValue
112-
safeRead str = case reads str of
113-
[(x,"")] -> Just x
114-
_ -> Nothing
86+
get :: forall a. ExtensionClass a => IdeM a
87+
get =
88+
do v <-
89+
lift $
90+
lift $
91+
State.gets $ M.lookup (typeRep $ (Proxy :: Proxy a)) . extensibleState
92+
case v of
93+
Just dyn -> return $ fromDyn dyn initialValue
94+
_ -> return initialValue
11595

11696
gets :: ExtensionClass a => (a -> b) -> IdeM b
11797
gets = flip fmap get
11898

11999
-- | Remove the value from the extensible state field that has the same type as the supplied argument
120-
remove :: ExtensionClass a => a -> IdeM ()
121-
remove wit = modifyStateExts $ M.delete (show . typeOf $ wit)
100+
remove :: ExtensionClass a => proxy a -> IdeM ()
101+
remove wit = modifyStateExts $ M.delete (typeRep $ wit)

hie-plugin-api/Haskell/Ide/Engine/PluginDescriptor.hs

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ module Haskell.Ide.Engine.PluginDescriptor
4444
-- * The IDE monad
4545
, IdeM
4646
, IdeState(..)
47-
, StateExtension(..)
4847
, ExtensionClass(..)
4948
, getPlugins
5049
, untagPluginDescriptor
@@ -59,19 +58,18 @@ module Haskell.Ide.Engine.PluginDescriptor
5958
, module Haskell.Ide.Engine.PluginTypes
6059
) where
6160

62-
import GHC.TypeLits
63-
import Haskell.Ide.Engine.PluginTypes
64-
65-
import Data.Singletons
6661
import Control.Applicative
6762
import Control.Monad.State.Strict
6863
import Data.Aeson
64+
import Data.Dynamic
6965
import qualified Data.Map as Map
66+
import Data.Singletons
7067
import qualified Data.Text as T
71-
import Data.Typeable
7268
import Data.Vinyl
7369
import qualified Data.Vinyl.Functor as Vinyl
7470
import GHC.Generics
71+
import GHC.TypeLits
72+
import Haskell.Ide.Engine.PluginTypes
7573
import qualified Language.Haskell.GhcMod.Monad as GM
7674

7775
-- ---------------------------------------------------------------------
@@ -211,7 +209,7 @@ type IdeT m = GM.GhcModT (StateT IdeState m)
211209
data IdeState = IdeState
212210
{
213211
idePlugins :: Plugins
214-
, extensibleState :: !(Map.Map String (Either String StateExtension))
212+
, extensibleState :: !(Map.Map TypeRep Dynamic)
215213
-- ^ stores custom state information.
216214
} deriving (Show)
217215

@@ -230,23 +228,3 @@ getPlugins = lift $ lift $ idePlugins <$> get
230228
class Typeable a => ExtensionClass a where
231229
-- | Defines an initial value for the state extension
232230
initialValue :: a
233-
-- | Specifies whether the state extension should be
234-
-- persistent. Setting this method to 'PersistentExtension'
235-
-- will make the stored data survive restarts, but
236-
-- requires a to be an instance of Read and Show.
237-
--
238-
-- It defaults to 'StateExtension', i.e. no persistence.
239-
extensionType :: a -> StateExtension
240-
extensionType = StateExtension
241-
242-
-- | Existential type to store a state extension.
243-
data StateExtension =
244-
forall a. ExtensionClass a => StateExtension a
245-
-- ^ Non-persistent state extension
246-
| forall a. (Read a, Show a, ExtensionClass a) => PersistentExtension a
247-
-- ^ Persistent extension
248-
249-
instance Show StateExtension where
250-
show _ = "StateExtension"
251-
252-
-- EOF

0 commit comments

Comments
 (0)