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

Plugin startup / private data #83

Closed
alanz opened this issue Nov 18, 2015 · 4 comments
Closed

Plugin startup / private data #83

alanz opened this issue Nov 18, 2015 · 4 comments

Comments

@alanz
Copy link
Collaborator

alanz commented Nov 18, 2015

Some plugins need to do some initial startup, and then store some state.

We need to come up with a way to do this.

This will probably include some kind of life-cycle methods exposed as part of the plugin, together with a way to store the state.

It may be simplest to define the state as being of type Data.Dynamic, as each plugin will know how to convert it for its own internal use.

So we add

startPlugin :: IO Dynamic

and each CommandFunc gets an additional Dynamic parameter passed in.

@alanz
Copy link
Collaborator Author

alanz commented Nov 18, 2015

Hmm. How do we update the private state? The sync version is easy

type SyncCommandFunc resp = forall m. (MonadIO m,GHC.GhcMonad m,HasIdeState m)
           => Dynamic -> [AcceptedContext] -> IdeRequest -> m (IdeResponse resp,Dynamic)

What about the async?

type AsyncCommandFunc resp = forall m. (MonadIO m,GHC.GhcMonad m,HasIdeState m)
                => (IdeResponse resp -> IO ()) -> [AcceptedContext] -> IdeRequest -> m ()

At the moment the (IdeResponse resp -> IO ()) function routes the reply directly to the transport, bypassing the dispatcher.

So there are two different issues

  • Does the response function still bypass the dispatcher, or should it go to the dispatcher always, on another TChan which pulls off the updated state and passes the response on the the transport according to the response Chan it passed in.
  • Should the original call return the updated state, or the async return, or neither, or both.

Potentially

type AsyncCommandFunc resp = forall m. (MonadIO m,GHC.GhcMonad m,HasIdeState m)
                => (IdeResponse resp -> (Maybe Dynamic) -> IO ()) -> [AcceptedContext] -> IdeRequest -> m (Maybe Dynamic)

Another simple but horribly way is to never update the state after initial creation, on the assumption that it creates an IORef which is then passed in to each command func and used to update the actual state, using whatever policy suits the plugin.

@mgsloan
Copy link
Collaborator

mgsloan commented Nov 20, 2015

Another simple but horribly way is to never update the state after initial creation, on the assumption that it creates an IORef which is then passed in to each command func and used to update the actual state, using whatever policy suits the plugin.

I don't find this horrible at all, I quite like this approach because then I can put a variety of different ref types in my state. It handily solves the async conundrum.

How about doing something like XMonad's ExtensibleState? In line with not actually handling mutation, it'd look like:

class PluginState a where
  initializeState :: _ => m a

getPluginState :: forall m a. (HasPluginState m, PluginState a, _) => m a

(where the _ are some more constraints, perhaps MonadIO m?)

So, if there's no value for a in the Map TypeRep a, then the state gets initialized.

I like this XMonad-ey approach because it also allows plugins to share state. If plugin A imports plugin B, then it can use plugin B's exported state types. For example, if there's a plugin that tracks how the renamer is renaming things and storing this away in a map, this map is generally useful to numerous queries which don't necessarily reside in the same plugin. This gets a bit tricky though, because it also means that plugin B also needs to actually be used by HIE.

@alanz
Copy link
Collaborator Author

alanz commented Nov 20, 2015

Good point. We already have a state variable in IdeM, can put either a private accessor for the given plugin or one to access all the state.

The types can by shared anyway, because it is all compiled in, so the dependencies are present.

@gracjan gracjan changed the title plugin startup / private data Plugin startup / private data Nov 29, 2015
@alanz
Copy link
Collaborator Author

alanz commented Dec 15, 2015

The extensible state work is happening here: https://github.com/alanz/haskell-ide-engine/tree/plugin-state

@alanz alanz mentioned this issue Dec 16, 2015
@alanz alanz added this to the prehistory milestone Feb 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants