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

Do plugins the same way as GHC #1

Closed
mgsloan opened this issue Oct 22, 2015 · 16 comments
Closed

Do plugins the same way as GHC #1

mgsloan opened this issue Oct 22, 2015 · 16 comments
Milestone

Comments

@mgsloan
Copy link
Collaborator

mgsloan commented Oct 22, 2015

I'm thinking that a good way to implement plugins is by emulating ghc's plugin system, perhaps even calling functions from it. Based on a quick look at the DynamicLoading module, it seems like it'd be a good approach to just copy+modify the loadPlugin function.

It makes sense to have something similar to the Plugin datatype, and have a field per "callback". Perhaps this is getting into details too early, but maybe these callbacks should be wrapped in Maybes, like the aptly named Hooks datatype. It's informative to know which things a particular plugin hooks into.

@mgsloan mgsloan changed the title Plugin layer Do plugins the same way as GHC Oct 22, 2015
@alanz
Copy link
Collaborator

alanz commented Oct 22, 2015

I think the main thing would be to define what plugin hooks exist, and how separate plugins interact with each other.

Another mental model would be closer to a container with shared services for accessing the GHC session and loaded code, as well as access to the iDE

@gracjan
Copy link
Contributor

gracjan commented Oct 22, 2015

As an alternative approach we can consider XMonad as a different architecture.

@alanz
Copy link
Collaborator

alanz commented Oct 22, 2015

I think XMonad (and yi) use https://hackage.haskell.org/package/dyre

@mgsloan
Copy link
Collaborator Author

mgsloan commented Oct 23, 2015

Looks like dyre is inspired by XMonad, but XMonad does not use it. Expressing your configuration as a Haskell file can indeed be powerful, but is it really what we want here? I imagine that having more knobs than just "Use these plugins" could easily lead to compatibility issues. For example, it would be unfortunate to need to change your configuration in order to support a particular editor.

@gracjan
Copy link
Contributor

gracjan commented Oct 23, 2015

I see project automatic upgrades as one of possible applications, for example GHC 7.8.4 to GHC 7.10.2 or Parsec2 to Parsec3. This application possibly requires rather complicated config to handle all the configuration edge cases.

@alanz
Copy link
Collaborator

alanz commented Oct 23, 2015

Personally I think dynamic reconfiguration is unnecessary.

Many (some) editors require a restart to update packages, e.g. spacemacs.
So long as it is a smooth process this should not be a burden.

Also, since haskell-ide will probably run as a daemon, changing config and
restarting should be straightforward.

Having a simple config format that is more in line with industry standards
would make more sense for this

On Fri, Oct 23, 2015 at 7:56 AM, Gracjan Polak notifications@github.com
wrote:

I see project automatic upgrades as one of possible applications, for
example GHC 7.8.4 to GHC 7.10.2 or Parsec2 to Parsec3. This application
possibly requires rather complicated config to handle all the configuration
edge cases.


Reply to this email directly or view it on GitHub
#1 (comment).

@mgsloan
Copy link
Collaborator Author

mgsloan commented Oct 24, 2015

I've taken a swing at the basics of plugins. Check it out on this branch: https://github.com/haskell/haskell-ide/tree/cli-and-plugins

Here's how to use it:

stack build
stack exec -- haskell-ide --plugin Haskell.Ide.ExamplePlugin start app/Main.hs

This tells it to load up an example plugin which just consists of a putStrLn. The "app/Main.hs" is passed as a target, which gets used to intiialize a ghc-mod session, but .

Here's the expected output:

Initializing plugins
Hello from example plugin!
Done initializing plugins

It turned out to be pretty straightforward to do this plugins stuff. However, I'm a bit concerned that it's a brittle way to do things. You need to compile the plugin against the exact same haskell-ide library that the binary is built against. I think this is likely why things like "hs-plugins" never really caught on.

As @gracjan, maybe it makes sense to take the XMonad approach, and have the user compile their own haskell-ide by having a small haskell file which imports the tools they want, and compiles them all together. Here are some positive benefits:

  • Starts up faster than linking at runtime.
  • The error messages will be far better with this approach.
  • Probably less error prone.
  • Less overall complexity.

Downsides:

  • Can't add a tool to an already running interpreter (this would be tricky with plugins, anyway)
  • More user steps to setup (but probably less frustration). In order to reduce setup for the typical case, there can be a package offering a typical setup.
  • Might cause tools to offer customization / configuration at this level. I'd rather avoid the circumstance where editors demand a particular configuration that might not work for some other editor.

So, we can start using this runtime plugins stuff if people want to, but I think it makes more sense to:

  • Go with the "custom Ide.hs" approach for now
  • Still have a Plugin datatype. I'm imagining that the user will call a function like haskellIde :: [Plugin] -> IO ().

@alanz
Copy link
Collaborator

alanz commented Oct 24, 2015

By "custom Ide.hs" approach do you mean the XMonad one suggested by @gracjan?

Just for completeness, the plugin model could end up being defined as a set of internal service APIs and haskell-ide then has a section that offers integration for all the plugins as part of the project.

Pros

  • simplicity

Cons

  • forces everyone to have to install all the plugins
  • makes it hard to bring in new/experimental plugins

This might be good to take as a very early approach to clarify what interfaces are needed, and then to break it out to the plugin architecture.

There is also the middle ground of using the XMonad approach, but then generating the config haskell file from a setup config that is deliberately simple, perhaps just a list of plugins to include, similar to stack.yaml

As a tool writer it is appealing to be able to provide the haskell-ide integration as one of the artefacts of the project, so it would offer access to the tool either as an exe, as a library, or as a plugin. I imagine this would be done by defining a function something like

getPluginInfo :: PluginInfo

Here the PluginInfo structure would provide a description of the facilities offered and or required.

@alanz
Copy link
Collaborator

alanz commented Oct 24, 2015

It just struck me that Android has a very mature ecosystem for allowing individual apps (== plugins) to coexist and make use of shared infrastructure, including defining new shared infrastructure to be used by other applications.

See http://developer.android.com/guide/components/fundamentals.html#ActivatingComponents

It may be possible to reuse some of these concepts

@mgsloan
Copy link
Collaborator Author

mgsloan commented Oct 26, 2015

This might be good to take as a very early approach to clarify what interfaces are needed, and then to break it out to the plugin architecture.

Agreed! I'm thinking this approach might be the main way to do it for quite a while. I should probably explain why the current plugins approach is error-prone:

The issue is that you'll need to build your haskell-ide plugins with the haskell-ide package version which corresponds to your installed executable. For example, if you've built a locally modified version, this means you need to know to do one of the following:

  • Add the plugin to the haskell-ide stack.yaml. Alternatively, have a stack.yaml in a directory above, which includes haskell-ide - even then it seems iffy whether the results will match up).
  • Either reuse the cabal sandbox or use add-source (I think, not too experienced with that side of cabal sandboxes).

Also, when haskell-ide is executed, it will need to know the package-dbs to use to find the installed plugins. These might be different than the package-dbs involved in building the user's code.

Building the tools statically into haskell-ide, via the "XMonad.hs" approach, means that there's no potential for version mismatch, and you don't need to know anything about the package DBs used for building the tooling.

@alanz
Copy link
Collaborator

alanz commented Oct 26, 2015

I think that initially we should try to get a handle on how plugins fit together into haskell-ide, and how they share comms to the external IDE, and how those comms are wrapped.

This can be explored without going for a complex plugin architecture initially.

In fact, the less onerous the better, so we can easily test options for the comms

In other words, initial plugins are shims that expose the working part of the thing being plugged in, e.g. HaRe.

@mgsloan
Copy link
Collaborator Author

mgsloan commented Oct 26, 2015

Yup, I'm just saying even in the long run it is likely good to avoid any sort of plugin architecture. It seems quite hard to make it work well for users.

@alanz
Copy link
Collaborator

alanz commented Oct 26, 2015

Ok, I think we are in agreement then.

I interpret a plugin as something that complies with a set of internal interfaces and can be easily inserted by someone who does not otherwise know much about haskell-ide

@DanielG
Copy link
Collaborator

DanielG commented Oct 26, 2015

The issue is that you'll need to build your haskell-ide plugins with the haskell-ide package version which corresponds to your installed executable.

@mgsloan can you explain a bit more why you think this is the case?

@mgsloan
Copy link
Collaborator Author

mgsloan commented Oct 26, 2015

Presumably your plugin will call into haskell-ide functions, which means your ABI needs to match up

@alanz
Copy link
Collaborator

alanz commented Nov 4, 2015

Closing this as we have a way of doing it in master now, which is simply adding a library and configuring it in. Nothing dynamic

@alanz alanz closed this as completed Nov 4, 2015
alanz pushed a commit that referenced this issue Mar 3, 2018
Fix issue with caching module
@alanz alanz added this to the prehistory milestone Feb 2, 2019
expipiplus1 pushed a commit to expipiplus1/haskell-ide-engine that referenced this issue Apr 22, 2019
alanz pushed a commit that referenced this issue Jan 19, 2020
Get rid of allow-newer in stack files
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants