Developing Plugins

QuickSharp plugins are .NET library assemblies which contain a class implementing the IQuickSharpPlugin interface. Plugins can be developed using any .NET language and can easily be developed in QuickSharp itself. This guide presents a tutorial approach to plugin development and presents a simple plugin example to help you get started.

Plugin example

Download this sample plugin and unzip the C# source file 'Minimal Plugin.cs' into a QuickSharp workspace. Start QuickSharp and open the file; it should compile without error into a '.dll' plugin file. Shutdown QuickSharp, copy the plugin to the QuickSharp installation directory and restart. The plugin adds a short cut key to the Set Read Only option on the Edit/Advanced menu. You should now see Ctrl+R appearing next to the menu text and the plugin details should appear in the QuickSharp About box.

Here is the source of the plugin:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using QuickSharp.Core;
using QuickSharp.Editor;

//$/r:"C:\Program Files\QuickSharp\QuickSharp.Core.dll"
//$/r:"C:\Program Files\QuickSharp\QuickSharp.Editor.dll"

namespace QuickSharp
{
    public class Module : IQuickSharpPlugin
    {
        public string GetID()
        {
            return "41E1A549-2B56-492c-9438-30B1CE7CD8C0";
        }

        public string GetName()
        {
            return "QuickSharp Minimal Plugin Sample";
        }

        public int GetVersion()
        {
            return 1;
        }

        public string GetDescription()
        {
            return "A simple demonstration plugin for QuickSharp.";
        }

        public List<Plugin> GetDependencies()
        {
            List<Plugin> deps = new List<Plugin>();

            deps.Add(new Plugin(
                QuickSharpPlugins.Editor, "QuickSharp.Editor", 1));

            return deps;
        }

        public void Activate(MainForm mainForm)
        {
            ToolStripMenuItem item =
                mainForm.GetMenuItemByName(
                    QuickSharp.Editor.
                        Constants.UI_EDIT_MENU_SET_READ_ONLY);

            item.ShortcutKeys = Keys.Control | Keys.R;
        }
    }
}

The plugin requires access to types in the QuickSharp.Core and QuickSharp.Editor namespaces so we add these on lines 5 & 6 and add references to the corresponding assemblies on lines 8 & 9.

IQuickSharpPlugin

The next thing to notice is that the plugin class implements the IQuickSharpPlugin interface. This enables QuickSharp to detect that this assembly is actually a plugin and provides the entry point and metadata access methods QuickSharp needs to load, register and activate it. Here's the interface definition from the QuickSharp source:

namespace QuickSharp.Core
{
    public interface IQuickSharpPlugin
    {
        string GetID();
        string GetName();
        int GetVersion();
        string GetDescription();
        List<Plugin> GetDependencies();
        void Activate(MainForm mainForm);
    }
}

GetID(), GetName() and GetDescription() provide metadata describing the plugin. Every plugin must have a unique identifier so we provide a GUID as in line 17 of the plugin source. The name and description are mainly for display purposes and appear in the application about box.

GetVersion() and GetDependencies() are used to manage the loading of dependent plugins and Activate() allows the plugin to add its functionality to the application.

Plugin dependencies

Once a plugin has been activated by QuickSharp its functionality becomes available to any other plugin that requires it. In this way plugins can extend other plugins. For this to happen it is necessary for the base plugin to be loaded before any plugin that depends on it. A plugin uses the GetDependencies() method to provide a list of all the plugins it requires. QuickSharp uses this to load all the plugins it has found in the correct order to satisfy these dependencies.

In our plugin sample we require the QuickSharp.Editor plugin to be loaded first so we can modify one of its menu options. To do this we add it to the dependency list using its ID to communicate the dependency to QuickSharp, and a short name to make the dependency intelligible to humans. The GetDependencies() method should return a list of all required plugins; to find the ID of a plugin use the list in the QuickSharp About box. (For QuickSharp IDE plugins you can also use the QuickSharpPlugins helper class.)

In addition to providing the ID of a required plugin, the required version should also be specified. The plugin's GetVersion() method returns its version and before a dependent plugin can be loaded it must find not only the plugin but an acceptable version of the plugin. If a dependency specifies version 2 of a particular plugin but QuickSharp finds only version 1, the dependency will not be satisfied and the load will fail. If on the other hand the plugin requires version 1 but finds 2 the dependency will be satisfied. In other words the version dependency specifies that a plugin requires a minimum version number in the dependency to be satisfied.

Plugin activation

Once a plugin has been loaded, it must be able to add its functionality to QuickSharp. This is achieved by the Activate() method which is called by QuickSharp once all of the available plugins have been loaded and the dependency order determined. Through Activate() a plugin is granted access to all of QuickSharp's internals and in this way it can extend any of the user interface elements such as the menu and toolbar.

To see what can be done in the Activate() method see the QuickSharp source code; all the standard QuickSharp plugins use this method to extend the core application.

Additional samples

A VB.NET version of the plugin example.

An example of how to add language support to QuickSharp, in this case a Python interpreter.