Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

DLTK IDE Guide:Step 1 Skeleton

Overview

Each Eclipse based application consists of a set of plug-ins. DLTK based Python IDE is not an exception, so the first implementation effort is the plug-in creation procedure. The best practice is to divide a core functionality and a user interface stuff into separate plug-ins but in this tutorial all classes will be combined in one plug-in just for simplicity. All UI functionality will be placed in .ui. packages.

Requirements

  • Eclipse 3.5, 3.6, 3.7
  • Latest DLTK 3.0
  • Plugins code from cvs

Plug-in project creation

Create a plug-in using well-known Eclipse Project Wizard: *New->Plug-in Project*. The name of the new plug-in is org.eclipse.dltk.examples.python:

Dltk 003 new project.png

Plug-in project configuration

First of all add DLTK dependencies to the project. Select MANIFEST.MF file from the project and open it with *Plug-in manifest editor*. Then add dependencies on the following plug-ins:

  • org.eclipse.dltk.core
  • org.eclipse.dltk.ui
  • org.eclipse.core.resource
  • org.eclipse.ui.editors
  • org.eclipse.ui.ide

Dltk 006 config project.png

Creating IDE based stuff

Project nature

The project nature is contributed using org.eclipse.core.resource.natures extension point. Nature identifier is a project name concatenated with the nature name: org.eclipse.dltk.examples.python.nature:

<extension id="nature" point="org.eclipse.core.resources.natures">
      <runtime>
         <run class="org.eclipse.dltk.examples.internal.python.core.ExamplePythonNature"/>
      </runtime>
   </extension>

ExamplePythonNature is a class that extends ScriptNature class. SriptNature has a stuff for the nature management and sets up the incremental builder for the project.

ExamplePythonNature.java

package org.eclipse.dltk.examples.python;
 
import org.eclipse.dltk.core.ScriptNature;
 
public class ExamplePythonNature extends ScriptNature {
	public static final String PYTHON_NATURE = PythonCorePlugin.PLUGIN_ID
			+ ".nature";
}

Content type for Python files

Content types allow Eclipse to identify that the exact file has a specific content, e.g. python code. The identification can be done by checking a file extension or a file content. Python file extension is *.py and specified in file-extensions attribute. Content describer is used to analyze the file content (mostly for files without an extension). For example, it's possible to check that the first file line is a "#\!/usr/bin/python".

<extension point="org.eclipse.core.runtime.contentTypes">
      <content-type
            base-type="org.eclipse.core.runtime.text"
            describer="org.eclipse.dltk.examples.internal.python.core.ExamplePythonContentDescriber"
            file-extensions="py"
            id="org.eclipse.dltk.examples.python.content-type"
            name="Example Python content type"
            priority="high">
      </content-type>
   </extension>

ExamplePythonContentDescriber.java

public class ExamplePythonContentDescriber extends ScriptContentDescriber {
	public ExamplePythonContentDescriber() {
	}
 
	protected static Pattern[] header_patterns = {
	    Pattern.compile("^#!.*python.*", Pattern.MULTILINE)
        }; 
 
	protected Pattern[] getHeaderPatterns() {
		return header_patterns;
	}
}

Eclipse has a powerful file associations based on contributed content types. These associations can be easily configured from preferences: *General->Content Types*. New file extensions can be added for already defined content types: Dltk 009 content types.png

DLTK Language Toolkit

Language Toolkit class is the core part of DLTK based script IDE. It's the entry point for access all language specific features. Language Toolkit is added to DLTK using org.eclipse.dltk.language extension point. For python language toolkit we use the created nature identifier and a class which implements IDLTKLanguageToolkit interface:

<extension point="org.eclipse.dltk.core.language">
      <language
            class="org.eclipse.dltk.examples.internal.python.core.ExamplePythonLanguageToolkit"
            nature="org.eclipse.dltk.examples.python.nature"
            priority="0">
      </language>
   </extension>

AbstractLanguageToolkit class is a good base which implements IDLTKLanguageToolkit with additional useful methods:

ExamplePythonLanguageToolkit.java

public class ExamplePythonLanguageToolkit extends AbstractLanguageToolkit {
	private static ExamplePythonLanguageToolkit toolkit;
 
	public static IDLTKLanguageToolkit getDefault() {
		if (toolkit == null) {
			toolkit = new ExamplePythonLanguageToolkit();
		}
		return toolkit;
	}
 
	public String getLanguageName() {
		return "Python";
	}
 
	public String getNatureId() {
		return ExamplePythonNature.PYTHON_NATURE;
	}
 
	public String getLanguageContentType() {
		return "org.eclipse.dltk.examples.python.content-type";
	}
}

DLTK UI-Language Toolkit

Most of UI language-specific things are provided by UI-language toolkit:

  • Label providers
  • Editor partitioning information
  • Source viewer configuration
  • Default editor information
  • Default preference page information

UI-Language toolkit is contributed using org.eclipse.dltk.ui.language extension point:

<extension point="org.eclipse.dltk.ui.language">
      <language
            class="org.eclipse.dltk.examples.internal.python.ui.ExamplePythonUILanguageToolkit"
            nature="org.eclipse.dltk.examples.python.nature"
            priority="0">
      </language>
   </extension>

AbstractDLTKUILanguageToolkit is the default implementation of IDLTKUILanguageToolkit interface and it plays the same role a AbstractDLTKLanguageToolkit for IDLTKLanguageToolkit.

ExamplePythonUILanguageToolkit.java

public class ExamplePythonUILanguageToolkit extends AbstractDLTKUILanguageToolkit {
	public IPreferenceStore getPreferenceStore() {
		return PythonCorePlugin.getDefault().getPreferenceStore();
	}
 
	public IDLTKLanguageToolkit getCoreToolkit() {
		return ExamplePythonLanguageToolkit.getDefault();
	}
}

Structure parser (simple implementation)

DLTK builds the following structure for each project and source module:

Project
 ├─── Project Fragment
 │     ├─── Script Folder
 │     │     ├─── Source Module
 │     │     │      ├─── Field
 │     │     │      ├─── Method
 │     │     │      ├─── Class
 │     │     │      │     ├─── Field
 │     │     │      │     ├─── Method
 │     │     │      │     ├─── Class
...   ...   ...    ...   ...   ...
 │     │     │      │     │

For Projects, Project Fragments and Script Folders the model is built automatically. Source element parsers are used to create a model of Source Module (with Fields, Methods and Classes).

Create a simple source element parser to demonstrate the power of DLTK. This parser will "convert" raw python script files to the set of Java objects (Classes, Fields, Methods) representing a model of code. Then this model will be used for different purposes, e.g. for Python syntax checking, for visual representation (Outline View, Script Explorer) etc.

Part of plugin.xml.

<extension
         point="org.eclipse.dltk.core.sourceElementParsers">
      <parser
            class="org.eclipse.dltk.examples.internal.python.core.parser.ExamplePythonSourceElementParser"
            nature="org.eclipse.dltk.examples.python.nature"
            priority="0">
      </parser>
   </extension>

ExamplePythonSourceElementParser.java

public class ExamplePythonSourceElementParser extends AbstractSourceElementParser {
	public void parseSourceModule(IModuleSource module) {
		ISourceElementRequestor requestor = getRequestor();
 
		requestor.enterModule();
		TypeInfo info = new TypeInfo();
		info.name = "Example type";
		requestor.enterType(info);
		requestor.exitType(0);
		requestor.exitModule(0);
	}
}

Described source element parser creates the same code model for all python files without paying attention to their content. The model is very simple: one source module with one type definition.

Project wizard

It's necessary to create a Python project wizard to test python language implementation. To create a project wizard it's required to contribute to the org.eclipse.ui.newWizard extension point:

<extension point="org.eclipse.ui.newWizards">
      <wizard
            category="org.eclipse.dltk.examples.python.category"
            class="org.eclipse.dltk.ui.wizards.GenericDLTKProjectWizard:org.eclipse.dltk.examples.python.nature"
            icon="icons/etool16/newprj_wiz.gif"
            id="org.eclipse.dltk.examples.python.wizard1"
            name="Example Python ProjectWizard"
            project="true">
      </wizard>
      <category
            id="org.eclipse.dltk.examples.python.category"
            name="DLTK Examples">
      </category>
   </extension>

This extension point uses GenericDLTKPRojectWizard class with the python nature identifier as a parameter.

First Python project

Python project wizard has been already added. Now it can be used for the first python Project creation:

File:Dltk 013 new example python project.png Dltk 013 new example python project first page.png

New python files can be added to the recently created project using a NewFile dialog. Script Explorer will display the project structure and the model of python code. Each file in Script Explorer can be expanded to see the code model:

Dltk 014 script explorer pc.png => Dltk 014 script explorer files.png

Python interpreter

To execute python files the IDE should have knowledge about python interpreters. DLTK has a support of generic interpreter management that can be extended in a flexible way by the IDE. Support of interpreter also gives an access to all its builtin libraries.

It's required to add the following plug-ins to the dependency list in the plug-in manifest:

  • org.eclipse.dltk.launching
  • org.eclipse.dltk.debug
  • org.eclipse.dltk.debug.ui
  • org.eclipse.debug.core
  • org.eclipse.debug.ui.

Each script language need to contribute at least one *Interpreter Install Type*. It's possible to create several interpreter install types for different python interpreters: common python, cpython and jython. There can be several installations or *Install Locations* of the same interpreter install type. For example it's possible to have python 2.4 and python 2.5 installed on the same machine.

<extension point="org.eclipse.dltk.launching.interpreterInstallTypes">
      <interpreterInstallType
            class="org.eclipse.dltk.examples.internal.python.interpreter.ExamplePythonInstallType"
            id="org.eclipse.dltk.internal.debug.ui.launcher.ExamplePythonInstallType">
      </interpreterInstallType>
   </extension>

ExamplePythonInstallType.java

public class ExamplePythonInstallType extends AbstractInterpreterInstallType {
	private static final String[] INTERPRETER_NAMES = { "python", "pythonw" };
 
	public String getNatureId() {
		return ExamplePythonNature.PYTHON_NATURE;
	}
 
	public String getName() {
		return "Example Python";
	}
 
	protected String getPluginId() {
		return PythonCorePlugin.PLUGIN_ID;
	}
 
	protected String[] getPossibleInterpreterNames() {
		return INTERPRETER_NAMES;
	}
 
	protected IInterpreterInstall doCreateInterpreterInstall(String id) {
		return new ExamplePythonInstall(this, id);
	}
 
	protected IPath createPathFile(IDeployment deployment) throws IOException {
		Bundle bundle = PythonCorePlugin.getDefault().getBundle();
		return deployment.add(bundle, "scripts/path.py");
	}
 
	protected ILog getLog() {
		return PythonCorePlugin.getDefault().getLog();
	}
}

AbstractInterpreterInstallType class is a base for custom interpreter install type. This class contains the interpreter management logic and gives an easy access to the interpreter library locations. Each interpreter install has a set of configured library location paths. Interpreter install type uses a native python script to obtain the list of libraries: path.py

import sys
print(" ".join( sys.path ))

This script returns a set of library paths separated by a space.

ExamplePythonInstallType class provides the possible interpreter names: python, pythonw. ExamplePythonInstall.java

public class ExamplePythonInstall extends AbstractInterpreterInstall {
	public ExamplePythonInstall(IInterpreterInstallType type, String id) {
		super(type, id);
	}
 
	public String getNatureId() {
		return ExamplePythonNature.PYTHON_NATURE;
	}
}

The interpreter preference page support can be added using the org.eclipse.ui.preferencePages extension point:

<extension
         point="org.eclipse.ui.preferencePages">
      <page class="org.eclipse.dltk.examples.internal.python.interpreter.ui.ExamplePythonInterpreterPreferencePage"
            id="org.eclipse.dltk.python.examples.preferences.interpreters"
            name="Example Python Interpreters"/>
   </extension>

The following set of classes is used for the preference dialog support. All DLTK preferences are based on configuration blocks (like JDT).


ExamplePythonInterpreterPreferencePage.java

public class ExamplePythonInterpreterPreferencePage extends
		ScriptInterpreterPreferencePage {
	public static final String PAGE_ID = "org.eclipse.dltk.python.examples.preferences.interpreters";
 
	public InterpretersBlock createInterpretersBlock() {
		return new ExamplePythonInterpretersBlock();
	}
}

The configuration block for the interpreter:

ExamplePythonInterpretersBlock.java

public class ExamplePythonInterpretersBlock extends InterpretersBlock {
	protected AddScriptInterpreterDialog createInterpreterDialog(
			IInterpreterInstall standin) {
		ExampleAddPythonInterpreterDialog dialog = new ExampleAddPythonInterpreterDialog(
				this, getShell(), ScriptRuntime
						.getInterpreterInstallTypes(getCurrentNature()),
				standin);
		return dialog;
	}
 
	protected String getCurrentNature() {
		return ExamplePythonNature.PYTHON_NATURE;
	}
}

ExampleAddPythonInterpreterDialog.java

public class ExampleAddPythonInterpreterDialog extends AddScriptInterpreterDialog {
	public ExampleAddPythonInterpreterDialog(IAddInterpreterDialogRequestor requestor,
             Shell shell, IInterpreterInstallType[] interpreterInstallTypes, IInterpreterInstall editedInterpreter) {
		super(requestor, shell, interpreterInstallTypes, editedInterpreter);
	}
 
	protected AbstractInterpreterLibraryBlock createLibraryBlock(AddScriptInterpreterDialog dialog) {
		return new ExamplePythonInterpreterLibraryBlock(dialog);
	}
}

ExamplePythonInterpreterLibraryBlock.java

public class ExamplePythonInterpreterLibraryBlock extends AbstractInterpreterLibraryBlock {
      public ExamplePythonInterpreterLibraryBlock(AddScriptInterpreterDialog d) {
             super(d);
      }
 
      protected IBaseLabelProvider getLabelProvider() {
 		return new LibraryLabelProvider();
      }
}

All tedious stuff was implemented and now the interpreter can be seen in action:

Dltk 015 interpreter config 0.png

The "Search" button makes all magic for interpreter searching. All folders from the system PATH variable are scanned (with the deep of two). Interpreter can be added manually by clicking on "Add" button.

Dltk 015 interpreter config 1.png

The selected interpreter is visible from Script Explorer as shown below: Dltk 015 interpreter config 2.png

Getting the code

The tutorial source code is available from Eclipse Git:

Back to the top