Como Crear Plugins Para NINJA-IDE
NINJA-IDE puede ser fácilmente extendido mediante la incorporación de Plugins, los cuales pueden ser desarrollados teniendo en cuenta 3 elementos:
- El descriptor del Plugin para que NINJA-IDE pueda integrarlo correctamente con la aplicación.
- El código del Plugin.
- El Objecto PluginAccess que se le entrega al Plugin para que pueda interactuar con el IDE.
Para la creación de Plugins se puede utilizar el Plugin: "PluginProject", el cual nos brinda un Wizard que nos pregunta que tipo de plugin queremos crear y al finalizar el proceso nos arma la estructura del proyecto con la respectiva Clase Plugin necesaria y los métodos a implementar. También nos permite empaquetar automáticamente el Plugin en un .zip al finalizar para poder distribuirlo.
Escribiendo el Descriptor:
El "descriptor" es simplemente un archivo .JSON el cual almacena la siguiente información:
{
"module": "name",
"lang": "py",
"menu-project": true,
"menu-editor": true,
"menu-app": true,
"project-type": "project-type-name",
"display": "path-to-image",
"properties": {
"name": "properties-name",
"icon": "path-to-image"
},
"toolbar": {
"name": "toolbar-name",
"icon": "path-to-image"
},
"connect": [
"returnKeyEvent",
"anyKeyEvent",
"run-code",
"run-program"
]
}- module : Indica el nombre del modulo donde se encontrara la clase Plugin que NINJA-IDE se encargara de instanciar.
- lang : Establece para que lenguaje se esta desarrollando el Plugin. Es de utilidad para Plugins que completen información en la Clase, que agreguen funciones de ejecución en el árbol del Proyecto, etc.
- connect : almacena un array indicando a cuales eventos el Plugin estaría enganchado. Los posibles eventos son:
- returnKeyEvent : Es ejecutado cuando se presiona "enter/return" en el editor.
- anyKeyEvent : Es ejecutado cuando se presiona cualquier tecla en el editor.
- run-code : Es ejecutado cuando se selecciona la opción de ejecutar el archivo abierto en el editor.
- run-program : Es ejecutado cuando se selecciona la opción de ejecutar el proyecto.
- Ejemplo ClassCompleterPlugin
- menu-app : Especifica si el Plugin deberá ser añadido al Menu de la Aplicación.
- menu-editor : Especifica si el Plugin deberá ser añadido al menu contextual del Editor.
- menu-project : Especifica si el Plugin deberá ser añadido al menu contextual del Explorador de Proyectos. (Ejemplo: PluginProject)
- project-type : Especifica que el Plugin permite la creación de Proyectos. Y también agrega al IDE un nuevo Tipo de Proyecto para las Preferencias de un Proyecto, para que al seleccionar el Tipo agregado las funciones de este Plugin se habiliten para ese Proyecto. Permite dirigir las funcionalidades de un Plugin a Proyectos específicos, al igual que lo hace la propiedad "lang" en algunos casos. (Ejemplo: PluginProject)
- display : Se establece el path de la imagen que se mostrara en el combo situado en la Toolbar del IDE utilizado para seleccionar cual es el display visible. (Ejemplo: PastebinPlugin)
- properties : Almacena un diccionario el cual establece el nombre con el que figurara este Plugin en la interfaz del IDE y la imagen que se mostrara junto al nombre.
- toolbar : Almacena un diccionario el cual establece el nombre con el que figurara este Plugin en la interfaz del IDE y la imagen que se mostrara junto al nombre.
El descriptor de un Plugin puede presentar cualquier combinación de las propiedades mencionadas arriba, ninguna es excluyente de la otra, pero si es necesario que siempre se especifique el nombre del modulo y el lenguaje.
Escribiendo el Plugin:
Primero que nada, la Clase Plugin (la cual debe llevar ese nombre) que creemos debe heredar de la Clase PluginBase la cual se encuentra dentro del modulo "plugins" de NINJA-IDE, e implementar el constructor de la Clase de la siguiente forma:
from plugins import PluginBase
class MyPlugin(PluginBase):
def __init__(self, access):
PluginBase.__init__(self, access)
...En cuanto a los Widgets gráficos, por el momento solo esta soportado incorporar Widgets hechos con PyQt.
Dependiendo de cuales sean las interacciones entre el Plugin y el IDE especificadas en el descriptor, va a ser necesario implementar algunos métodos:
- Para menu-app es necesario implementar: def addMenuApp(self):. Metodo el cual sera llamado para obtener el Menu que se desea cargar en la Aplicación (debe retornar un objeto QMenu)
- Para menu-project es necesario implementar: def menuProject(self):. Metodo el cual sera llamado para obtener el Menu que se desea cargar en el Explorador de Proyecto (debe retornar un objeto QMenu). Hay que tener en cuenta que en este caso, el menu solo se cargara para proyectos que sean del tipo de lenguaje colocado en el descriptor.
- Para menu-editor es necesario implementar: def menuEditor(self):. Metodo el cual sera llamado para obtener el Menu que se desea cargar en el Editor (debe retornar un objeto QMenu). Hay que tener en cuenta que en este caso, el menu solo se cargara para archivos que sean del tipo de lenguaje colocado en el descriptor.
- Para project-type es necesario implementar: def getPages(self):, el cual devuelve una lista de objectos QWizardPage para colocar en el Wizard cuando se seleccione este tipo de Proyecto. A su vez, también es necesario implementar: def onWizardFinish(self, wizard):, el cual es llamado al apretar el boton finalizar del Wizard si se selecciono el tipo de proyecto indicado por este Plugin y recibe un objeto QWizard que contiene como primer página la de selección de Proyectos y como última página la de configuración de ubicación del Proyecto. Para ver como trabajar con estas páginas se puede consultar el código del plugin PluginProject. También es posible implementar el método def projectFiles(self):, el cual devuelve una lista de Strings con la extensiones propias de un tipo de proyecto para que sean agregadas en el Menu "File->Open Project Type" (de la forma: ".py", ".html", etc).
- Para display es necesario implementar: def stackWidget(self):, el cual devolverá un objeto de tipo QWidget que se asociara al icono identificador del Plugin situado en el ComboBox de la toolbar.
- Para toolbar es necesario implementar: def toolbarAction(self):, el cual será llamado cada vez que se presione el boton (con el icono especificado en el descriptor) de la ToolBar que corresponde a este plugin.
- Para properties es necesario implementar: def propertiesWidget(self):, debe devolver un objeto de tipo QWidget, el cual sera instalado en el Panel de Propiedades (donde se encuentra contenido también el Explorador de Proyectos).
- Para las acciones de "connect":
- En el caso de returnKeyEvent es necesario implementar def eventKeyReturn(self):, el cual será llamado cada vez que se presione la tecla enter/return en el editor.
- En el caso de anyKeyEvent es necesario implementar def eventKeyAny(self):, el cual será llamado cada vez que se presione una tecla en el editor.
- En el caso de run-code es necesario implementar def executeFile(self):, el cual será llamado cuando se de la orden de ejecutar el archivo abierto en el editor.
- En el caso de run-program es necesario implementar def executeProgram(self):, el cual será llamado cuando se de la orden de ejecutar el proyecto activo.
Accediendo al IDE:
Como se puede ver en la sección anterior, el Constructor de la Clase Plugin recibe un objeto PluginAccess, el cual provee los siguientes objetos:
- Editor (PluginAccess.editor) con los siguientes métodos:
- get_text() : Obtiene el texto del Editor que se este mostrando.
- editor_path() : Obtiene el path del archivo cargando en el Editor que posee el foco.
- add_new_editor(lang='py') : Abre un nuevo Editor sin contenido. Se le puede indicar como parámetro (opcional) el tipo de lenguaje que contendrá el editor mediante un String con la extensión del lenguaje.
- Tabs (PluginAccess.tabs) con los siguientes métodos:
- add_tab(QWidget, 'title') : Agrega el Widget pasado como parámetro en un nuevo Tab con el titulo indicado.
- save_file() : Ejecuta la opción de grabado para el elemento activo en el TabWidget del IDE.
- open_document(fileName) : Abre el contenido del archivo pasado por parámetro dentro de un Editor nuevo.
- open_image(path-image) : Muestra la imágen pasada por parámetro en el TabWidget.
- Projects (PluginAccess.projects) con los siguientes métodos:
- project_path() : Devuelve el path del proyecto activo.
Otras Consideraciones:
- Si utilizamos el Creador de Plugins para crear un proyecto plugin, al momento de elegir una imágen para el Display, Toolbar, etc. El creador de proyectos plugin se encargara de copiar esa imágen en la carpeta del proyecto automáticamente para que quede debidamente referenciada.
- Todo Widget que deba ser incorporado como un Tab en el IDE debe heredar de la Clase BaseCentralWidget, la cual se encuentra dentro del módulo "gui.generic".
- Para que NINJA-IDE pueda reconocer el proyecto el siguiente debe ser colocado dentro de la carpeta plugins de la siguiente manera:
Esta estructura también es válida para empaquetar el plugin y que pueda ser correctamente instalado y desinstalado por el IDE de forma automática al proveer la URL.