Add your own programming language to SharpDevelop Part 1: Make your templates available

While documenting myself for developping a new language I looked at how to add support for a programming language to the free available SharpDvelop IDE. Allthough there is some information available in the forums at their site, most of it is scattered. So, I decided to start from scratch with a pure SharpDevelop addin in build up until I had a language supported by the SharpDevelop IDE.

In this first part we will start with the fun part: adding your project type to the IDE

What we need

This article is about the SharpDevelop 2.0 IDE. In order to be able to debug our addin and see how SharpDevelop implements certain features we will also get the SharpDevelop sourcecode and compile a debug version of it.

This is where you can get all the goodies:

  • The sample project used in this article can be downloaded from here
  • The IDE itself, to be able to develop our addin, you can get from here.
  • How to get the sourcecode is explained here.

The documentation for obtaining the sourcecode leads you to the Subversion trunk svn://sharpdevelop.net/sharpdevelop/branches/2.0/SharpDevelop, but if you go one folder back up, just at svn://sharpdevelop.net/sharpdevelop/branches/2.0 and download from there, you will also download some batch files which allow you to compile the whole project.

Now, let’s get going…

Creating the addin

Start by creating a SharpDevelop addin using the appropriate template in SharpDevelop. I used the C# language.

sharpdevelopaddin.gif

If you look at the sample code provided with this article, you will see that the project structure is probably not what you are used to. For a detailed justification, just take a look at my series of articles about building a development environment.

After you created this project you will see that it created some files automatically. For this part we will only need the file with extension “addin” and the AssemblyInfo.cs file. So we delete the other files.

Also, in the downloaded sourcetree of SharpDevelop, look for the AddIn subfolder and in this folder create a subfolder with the name “SharpDevelopLanguagBinding”. On my PC this became:

folderstructure.gif

In the projectsettings of the SharpDevelop projects just created, select the Compiling tab and select the just created subfolder as an outputfolder for your project. So you het something like the following:

outputfolder.gif

Customizing the addin

First, where going to add some entries to the addin definition file. That is the file with extension “addin”

In the addin file we specify the following:

The root tag is the AddIn node which has some attributes specifying the name of the addin and some information on who authered it, etc…

Next is the Manifest node. The Manifest node specifies an identity for your addin, such that other addins can refernce it. It will be clear that this identity has to be unique in your installation of SharpDevelop. That is why I use the inverted URL style, that is “be.HungryForKnowledge.SharpDevelopLanguagBinding”. It is also possible to specify dependencies in the Manifest node, if your addin needs specific other addins. We do not make use of this at this time.

The we have the Runtime node. This node specifies the dll that is your addin. You simply specify the name of the dll as the value of an assembly attribute.

So, we get the following:

<AddIn name = SharpDevelopLanguagBinding

       author = Serge Desmedt

       url = https://sdesmedt.wordpress.com/

       description = Sample Language Binding for the SharpDevelop IDE>

    <Manifest>

        <Identity name = HungryForKnowledge.SharpDevelopLanguagBinding/>

    </Manifest>

 

    <Runtime>

        <Import assembly = SharpDevelopLanguagBinding.dll/>

    </Runtime>

 

</AddIn>

Now, we will specify the resources used by our addin.
We have two types of resources:

  • Bitmap resources: these can be used to specify the bitmap to be used for our project type in the “New Project” dialog box.
  • String resources: these ra e used to specify for example a description for out project templates in the “New Project” dialog box.

To add bitmap resources, do the following (allthough the documentation states not to do it this way, but I was far to impatient to go the long way):

  1. Add a folder “Resources” to your project (This is optional, but avoids cluttering the root folder)
  2. Add a resource file to this folder and name it “BitmapResources.resource”
  3. Set the properties of this file to “Copy to output directory = Always” in the IDE.

To add string resources, do the following (allthough the documentation states not to do it this way, but I was far to impatient to go the long way):

  1. Add a folder “Resources” to your project, allthough you probably already did this while adding bitmap resources.
  2. Add a resource file to this folder and name it “StringResources.resource”
  3. Set the properties of this file to “Copy to output directory = Always” in the IDE.
  4. To add foreign language string resources, add a resource file to this folder and name it “StringResources.[culture].resource” in which you replace “[culture]” with the abbreviation of the language. For example, dutch string resources get a name “StringResources.nl.resource”
  5. Set the properties of this file to “Copy to output directory = Always” in the IDE.

If you followed above instructions, your project should look something like this:

resources.gif

Finally, we have to associate our resources with our Addin and make them known to SharpDevelop. For this, we add following lines to our addin file:

<AddIn name = SharpDevelopLanguagBinding

       author = Serge Desmedt

       url = https://sdesmedt.wordpress.com/

       description = Sample Language Binding for the SharpDevelop IDE>

 

  <!– Previous lines where here –>

 

  <BitmapResources file=Resources\BitmapResources.resources />

  <StringResources file=Resources\StringResources.resources />

 

</AddIn>

As you can see, you do not have to add anything for your foreign language. By taking the culture specific file naming into account, SharpDevelop is able to load the correct resource file.

Everything is in place now to start using these resources and make our language known to SharpDevelop.

Adding the file types for our language and language project

There are basically two types of files that are associated with a language. Firstly, there are of course the source files with your code, but you also have the project files associated with the project type for your language.

In the SharpDevelop IDE you can open these type of files by following the menu structure File > Open > File …, or for the latter by following File > Open > Project/Solution …

The association is done in the addin file by using the <path> tag. The value of the “name” attribute distinguishes what kind of association you are making. Inside the Path tag you specify a FileFilter tag with the information for your filetype.

So, you get this:

<AddIn name = SharpDevelopLanguagBinding

       author = Serge Desmedt

       url = https://sdesmedt.wordpress.com/

       description = Sample Language Binding for the SharpDevelop IDE>

 

    <!– previous tags here–>

 

    <!– Makes the type of project available for selection when

        selecting File – Open – Project/Solution… –>

    <Path name = /SharpDevelop/Workbench/Combine/FileFilter>

        <FileFilter id        = SharpDevelopLanguageBindingProject

                    insertbefore=AllFiles

                    name       = ${res:SharpDevelopLanguageBinding.MyLanguagePrjFiles}

                    class      = ICSharpCode.SharpDevelop.Project.LoadProject

                    extensions = *.mylbproj/>

    </Path>

 

    <!– Makes the type of sourcefile available for selection when

        selecting File – Open – Project/Solution… –>

    <Path name = /SharpDevelop/Workbench/FileFilter>

        <FileFilter id = SharpDevelopLanguageBinding

                    insertbefore=AllFiles

                    name = ${res:SharpDevelopLanguageBinding.MyLanguageFiles} (*.mylb)

                    extensions = *.mylb/>

    </Path>

 

</AddIn>

The attributes of the <FileFilter> tag are self-explanatory, except maybe for the strange ${res:[SomeTextString]} values. They are simple references to strings in the string resource we setup previously. In the above example we must have two strings in our resource, one with Id “SharpDevelopLanguageBinding.MyLanguagePrjFiles” and the other with Id “SharpDevelopLanguageBinding.MyLanguageFiles”. The Id “ICSharpCode.FiletypeRegisterer.Project” is of SharpDevelop itself and is automatically available.

The “InsertBefore” and “InsertAfter” attributes give you the opportunity to set an order to the entries that will be made available in the dialogboxes. The values of these attributes are simply the value of id attributes from other <FileFilter> tags in other addin files. If you go to the AddIns folder in the SharpDevelop sourcetree you will see a file named “ICSharpCode.SharpDevelop.addin” in which you can find the “AllFiles” FileFilter.

OK, compile and run the project. This is what you get:
For opening projects:

projectassociation.gif

For opening files:

fileassociation.gif

There is also the possibillity to add your filetypes to the Filetype Registerer addin. Fot this, you add following lines to your addin file:

    <!– OPTIONAL: Makes the file extension available for association with SharpDevelop

        when selecting Tools – Options… – General – File Format Associations –>

    <Path name = /AddIns/FileTypeRegisterer/FileTypes>

        <FiletypeAssociation

            id = sdlbindproj

            insertafter = sln

            insertbefore = sdaddin

            autoRegister = True

            icon = ${AddInPath:ICSharpCode.FiletypeRegisterer}/filetypes/prjx.ico

            text = MyLanguage ${res:ICSharpCode.FiletypeRegisterer.Project}/>

    </Path>

This will give you the following in the user interface of SharpDevelop:

fileregisterer.gif

Adding a languagebinding for our language

Adding templates for your projecttype and language involves a little more then just adding your template description files in the right folder. You also need to add two classes to your addin:

  • A class for your projecttype, derived from MSBuildProject: MyProject.
  • A class for your language, implementing the ILanguageBinding interface: MyLanguageBinding.

For the moment, we will keep these very basic:

The class MyProject has two constructors:

  • a constructor which receives an object of type ProjectCreationInformation which has the basic properties of the project to create, and our MyProject constructor simply calls the Create method of the MSBuildProject base class which then creates the properties for the project.
  • a constructor which takes a filename and a projectname and these are respective the name of the projectfile (in our case the file with extension “mylbproj”) and the name of the project which is the string entered in the create project dialog box.

The class MyLanguageBinding implements the interface ILanguageBinding. It has a readonly property which returns the name of the language, “MyLanguage” in our case, and two methods which enable construction of a project, and opening of a project. They are respectively named “LoadProject” and “CreateProject”. The method “CreateProject” is used to create a new project, and the method “LoadProject” is used to open a created project.

If you would like to know the exact functioning of these classes, put a breakpoint on the property and the two methods of the class MyLanguageBinding and start SharpDevelop in debug mode. You can now investiate the callstack and get a feel of what is going on.

We now have to make our language binding known to SharpDevelop itself. This means telling SharpDvelop what it is through the addin file. For this we add the following to the addin file:

    <Path name = /SharpDevelop/Workbench/LanguageBindings>

        <LanguageBinding id = MyLanguage

                        guid = {028A5042-B5AB-47BD-9ED8-97B066293609}

                        supportedextensions = .mylb

                        projectfileextension = .mylbproj

                        class = HFK.SharpDevelopLanguagBinding.MyLanguageBinding />

    </Path>

The above is just an “xml-ification” of the class LanguageBindingDescriptor which you can find in the namespace ICSharpCode.Core of the project ICSharpCode.SharpDevelop. Most of the attributes are self-explanatory and the class attributes references of course the full name of your ILanguageBinding implementing class.

Adding a template for our language

Finally we can add the templates for our language.

First, we must tell SharpDevelop where it can find the temlplates for our language. As usual, this is done in the addin file by adding a <path> tag:

    <Path name = /SharpDevelop/BackendBindings/Templates>

        <Directory id = MyLanguage path = ./Templates />

    </Path>

And next we define a template:

Create a folder “Templates” in the add-in project. The name of this folder has to be the same name you have used in your addin file. In this folder you create a file with extension “xpt”, in which you put following xml:

<?xml version=1.0?>

<Template originator = Serge Desmedt>

    <TemplateConfiguration>

        <Name>MyLanguage Console Project</Name>

        <Category>MyLanguage Binding</Category>

        <Icon>SharpDevLanguageBindingProject</Icon>

        <LanguageName>MyLanguage</LanguageName>

        <Description>Console Project for the MyLanguage binding</Description>

    </TemplateConfiguration>

 

    <!– Actions –>

    <Actions>

        <Open filename = Program.mylb/>

    </Actions>

 

    <!– Template Content –>

    <Combine name = ${ProjectName} directory = .>

        <Options/>

 

        <Project name = ${ProjectName} directory = .>

            <Options/>

 

            <ProjectItems>

                <Reference Include=System.Data />

                <Reference Include=System.Xml />

            </ProjectItems>

 

            <Files>

                <File name=Program.mylb><![CDATA[

namespace ${StandardNamespace}

 

import System

import System.Collections

 

// Add the code for your language here…

]]></File>

            </Files>

        </Project>

    </Combine>

</Template>

The basic structure of this file is the following:

<?xml version=1.0?>

<Template originator = Serge Desmedt>

  <!– Defines the basic properties of the template –>

  <TemplateConfiguration>

  </TemplateConfiguration>

 

  <!– Actions to be performed when the

       template is expanded–>

  <Actions>

  </Actions>

 

  <!– Template Content –>

  <Combine name = ${ProjectName} directory = .>

  </Combine>

</Template>

Inside the <TemplateConfiguration> tags you definethe visual properties of your template as it will be made available in the “New Project” dialog. With the above childnodes we get following dialog:

openprojectdialog.gif

The <Actions> tag gives you the opportunity to specify some actions SharpDevelop has to perform once the template got expanded. In the version of SharpDevelop I analysed for this article, only one action is supported: opening files. You add an inner node which has an attribute with key “filename” and value the name of the file to open. The fle must of course have been created by your template (see further).

If you look in the templates for other languagebindings, you will see actions defines like this:

    <Actions>

        <Open filename = somefilename.ext/>

    </Actions>

If you look in the sourcecode of SharpDevelop however, at least the version I checked, you will see that it simply iterates over all the childnodes of the <Actions> node and looks for an attribute with key “filename” and creates a command to open this file. It does not check for the name of this childnode! So you could add a childnode with name <Close> and the “filename” attribute, and the file would still get opened…

Finally, the <combine> tag describes the solution that will be created. SharpDevelop also supports using the <Solution> tag instead.

The exact supported tags and properties can be found in the file “ProjectTemplate.cs” in the folder “SharpDevelop\src\Main\Base\Project\Src\Internal\Templates\Project\” or by navigating through the soltution: Main/ICSharpCode.SharpDevelop/Src/Internal/Templates/Project

Inside the <combine> tag you find the definition of the SharpDevelop solution that will be created for you. It has following structure:

    <!– Template Content –>

    <Combine name = ${ProjectName} directory = .>

        <Options/>

 

        <Project name = ${ProjectName} directory = .>

        </Project>

    </Combine>

It defines a name and folder for your solution, the solution options and the projects it will contain. The currently supported options are <StartupProject> which gives the name of the startup project in the solution you created with this template.

The exact supported tags and properties can be found in the file “CombineDescriptor.cs” in the folder “SharpDevelop\src\Main\Base\Project\Src\Internal\Templates\Project\” or by navigating through the soltution: Main/ICSharpCode.SharpDevelop/Src/Internal/Templates/Project

Then each project has a structure like following:

        <Project name = ${ProjectName} directory = .>

            <Options/>

 

            <ProjectItems>

                <Reference Include=System.Data />

                <Reference Include=System.Xml />

            </ProjectItems>

 

            <Files>

                <File name=Program.mylb><![CDATA[

namespace ${StandardNamespace}

 

import System

import System.Collections

 

// Add the code for your language here…

]]></File>

            </Files>

        </Project>

Again, the <Project> tag gives the name and folder of the project. The childnodes provide <Options>, <ProjectItems> and <Files> for your project.

What is supported in the <Options> tag is dependent on your language. If you look at the ILanguageBinding interface we implemented above, you will see that the CreateProject method has a parameter projectOptions of type XmlElement: yes, that is this <Options> node which gets passed into it. So it’s up to you to parse it.

The <ProjectItems> tag allows you to support the creation of for example references. The other supported items can be founs in the method CreateProjectItem of the class ICSharpCode.SharpDevelop.Project.ProjectItemFactory, which can be found in the file ProjectItemFactory.cs in the folder “SharpDevelop\src\Main\Base\Project\Src\Project\Items”

And finally the <Files> tag allows for the creation of files. For each file to create, you provide a <File> node. The allowed attributes for this node can be found in the file “FileDescriptionTemplate.cs” in the folder “SharpDevelop\src\Main\Base\Project\Src\Internal\Templates\File\” or by navigating through the solution: Main/ICSharpCode.SharpDevelop/Src/Internal/Templates/File

The template file gets expanded using the StringParser singleton. You can see this happen in the CreateProject method of the ProjectDescriptor class. Just put a break on the foreach loop that iterates over the FileDescriptionTemplate collection.
Once inside the loop your project gets adapted to include the file to be created and then, inside a try-catch block, a StreamWriter is created and the content of your template gets written to it, after being processed by the StringParser singleton. You can look inside the GetValue method of the StringParser class to have an idea of available keywords which can be replaced.

Conclusion

You should now be able to include a languagebinding for your own language into SharpDevelop. Of course, the above is only the tip of the iceberg. But now that you have included your own templates for your language, lets try to inlude the compiler for our language.

This will hower be for a follow-up article…

Resources

[1] Sharpdevelop Add In Writing Tutorials.
[2] Binding for IronPython.
[3] does sharpdevelop can develop a addin to support other language(like php, c language)?
[4] In the source tree of SharpDevelop, there is a folder “doc/technotes” with some files explaining the use of addin’s.

Updates

16 Februari 2007: original version
01 March 2007: added sourcecode for sample language binding.

Advertisements

One thought on “Add your own programming language to SharpDevelop Part 1: Make your templates available

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s