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.
DLTK IDE Guide:Step 1 Skeleton
Contents
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:
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
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 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
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:
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:
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.
The selected interpreter is visible from Script Explorer as shown below:
Getting the code
The tutorial source code is available from Eclipse Git: