Getting started

This page is a gentle introduction to the pyQode framework.

Before reading this, you should have pyqode.core and PySide/PyQt4/PyQt5 installed on your system.

Design and philosophy

In opposition to what other code editor projects might do, pyqode does not aim to support all languages from scratch. Instead it provides a framework that let you build the code editor of your dream for your favorite language. pyqode.core really is a toolbox that you will use to build your own specialised code editor.

A generic code editor exists in pyqode.core but it is highly inefficient and probably not good enough to target your preferred language. It is there to be used as a fallback editor for secondary languages (i.e. languages that are not the main target of your application, for whatever reason).

There are many reasons why you would want to build a specialised editor instead of using pyqode.core.widgets.GenericCodeEdit. We can see the following reasons:

  • implement a native highlighter for maximum flexiblity and better load times (the generic pygments highlighter is usually 2-3 times slower than a native one).
  • implement code folding. Code outline must be detected differently depending on the language. That’s why the generic pygments highlighter does not detect code outline at all.
  • implement a code completion engine. Not every language use the same tools, you will be better served by a specialised completione engine than by trying to use a generic one.

Support for new languages are added by external (namespace) packages. That way, the user can only pick up what he needs, minimizing the list of dependencies. If you are working on Go editor, you would not want to have to download clang, jedi or pyFlakes. The only dependency you will have are the pyqode.core dependencies which boil down to pygments and optionally chardet.

Packages

Here is a brief overview of the content of pyqode.core and how to import it.

pyqode.core is made up of a series of subpackages. Each subpackage defines its own api (classes defined in a module of a subpackage are available at the subpackage level).

Here are the main subpackages:

  • api: contains the bases classes of the API
  • backend: classes for controlling the backend process
  • modes: contains all available modes
  • panels: contains all available panels
  • styles: contains a series of pygments styles specific to pyQode
  • widgets: contains a series of useful widgets.

Note

Not all subpackages are presented here, internal package or very specific one have been left out. You can read more about them in the API reference section.

To use pyQode, simply import one of those packages:

from pyqode.core import api
from pyqode.core import backend
from pyqode.core import modes
from pyqode.core import panels
from pyqode.core import widgets

# then you start using pyqode, e.g:
editor = api.CodeEdit()
editor.modes.append(modes.CodeCompletionMode())
editor.panels.append(panels.LineNumberPanel())

tabWidget = widgets.TabWidget()
tabWidget.add_code_edit(editor)

Selecting a Qt bindings

The first thing to do when using pyQode is to specify the Qt bindings you want to use in your application.

By default, pyQode will try to use PyQt5 and will fallback to PyQt4 or PySide in case of import errors. You can enforce the use of a specific bindings by setting up the QT_API environment variable.

For example, to use PySide:

import os
os.environ['QT_API'] = 'PySide'
from pyqode.qt import QtCore, QtGui, QtWidgets
print('Qt version:%s' % QtCore.__version__)
print(QtCore.QEvent)
print(QtGui.QPainter)
print(QtWidgets.QWidget)

Note

You can also use the qt package of pyqode.core to write a bindings independent application but you have to be aware that pyqode.qt does not wrap the entire Qt API (it only what was required to write pyQode).

The backend

pyQode is a client server API, the GUI side is called the frontend and the background process used to perfom heavyweight computation is called the backend.

When writing a pyQode application, you have to write both the frontend script and the backend script. Fortunately, writing the backend script is an easy task. All you have to do is to configure the server script (sys.path, workers,...) and call pyqode.core.backend.serve_forever()

Here is an example of server script:

from pyqode.core import backend

if __name__ == '__main__':
    backend.CodeCompletionWorker.providers.append(
        backend.DocumentWordsProvider())
    backend.serve_forever()

The frontend

Writing the pyqode frontend is not more complicated than writing the backend.

All you have to do is:

  1. create a pyqode.core.api.CodeEdit
  2. start the backend process
  3. configure CodeEdit
  4. open a file or set some text
  5. run the Qt main loop

Here is a simple example of a frontend script:

import sys
from pyqode.core import api
from pyqode.core import modes
from pyqode.core import panels
from pyqode.qt import QtWidgets


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    # create editor and window
    window = QtWidgets.QMainWindow()
    editor = api.CodeEdit()
    window.setCentralWidget(editor)

    # start the backend as soon as possible
    editor.backend.start('server.py')

    # append some modes and panels
    editor.modes.append(modes.CodeCompletionMode())
    editor.modes.append(modes.PygmentsSyntaxHighlighter(editor.document()))
    editor.modes.append(modes.CaretLineHighlighterMode())
    editor.panels.append(panels.SearchAndReplacePanel(),
                      api.Panel.Position.BOTTOM)

    # open a file
    editor.file.open(__file__)

    # run
    window.show()
    app.exec_()

CodeEdit

The editor widget is a simple extension to QPlainTextEdit.

It adds a few utility signals/methods and introduces the concept of Managers, Modes and Panels.

A mode/panel is an editor extension that, once added to a CodeEdit instance, may modify its behaviour and appearance:

  • Modes are simple objects which connect to the editor signals to append new behaviours (such as automatic indentation, code completion, syntax checking,...)

  • Panels are the combination of a Mode and a QWidget. They are displayed in the QCodeEdit’s content margins.

    When you install a Panel on a CodeEdit, you can choose to install it in one of the four following zones:

    _images/editor_widget.png

A manager is an object that literally manage a specific aspect of pyqode.core.api.CodeEdit. There are managers to manage the list of modes/panels, to open/save file and to control the backend:

Starting from version 2.1, CodeEdit defines the pyqode.core.api.CodeEdit.mimetypes class attribute. property which is a list of supported mimetypes. An empty list means the CodeEdit is generic. Code edit specialised for a specific language should define this attribute!

IDE can use that property and and mimetypes.guess_type() to make file types-editor associations.

Controlling the backend

To use the backend (from the frontend), you need to use pyqode.core.managers.BackendManager.

To start the backend, use pyqode.core.managers.BackendManager.start. You can specify a custom interpreter if needed (useful in python for working with a python2 interpreter or when using a virtual environment):

code_editor.backend.start('path/to/server_script.py',
                          interpreter='/usr/bin/python2.7')

To request some work to be done on the backend, just use pyqode.core.managers.BackendManager.send_request. You can specify a callback to be called when the work has finished (i.e. to retrieve the job results):

code_editor.backend.send_request(my_worker, {'parameters': None,}, my_callback)

To stop the backend, just use pyqode.core.managers.BackendManager.stop:

code_editor.backend.stop()

You should not need to call it manually as the backend is automatically stopped when the editor got deleted by the python interpreter.

Opening and saving files

Opening and saving files is made easy by using the pyqode.core.managers.FileManager.

Opening a file:

code_edit.file.open('/path/to/file.py')

Saving a file:

code_editor.file.save()

Saving a file as:

code_editor.file.save('/path/to/new_file.py')

You can always replace a manager by your own version if you’re not happy with it or if you want to extend it.

Using modes and panels

To use modes and panels, you must use the corresponding managers:

Those managers are available as attributes of CodeEdit:

To install a mode/panel, use the append method:

code_editor.modes.append(MyMode())

To retrieve a mode/panel, use the get method. This method accepts either the mode name or the mode class:

m_name = code_editor.modes.get('MyMode')
m_class = code_editor.modes.get(MyMode)
assert m_name == m_class

Note

The order of installation of modes is important because some modes have interdependances. Also it is worth noting that the order of installation of modes define the order of reaction to a specific events.

Usually, this kind of restriction is documented for a specific modes in its class documentation.

Changing editor style and properties

You can change any property of CodeEdit, or any of its modes, at runtime.

E.g.:

# change color scheme
code_editor.modes.get(PygmentsSyntaxHighlighter).pygments_style = 'monokai'
# change property
code_editor.show_white_spaces = True
# change action shortcut
code_editor.action_duplicate_line.setShortcut('Ctrl+Shift+Down')