From BlenderWiki

Jump to: navigation, search

Improving Python Editing In Blender

This project enables users to develop Python scripts with greater ease by including a number of new features to the text editor and improving upon the existing functionality.

For information on the changes made to Blender and the way it fits in with current development see the Integration Document

Or for information on using the new system, see the User Manual

Current Status

The key aspect of this project has been the text plug-in system. This system allows Python scripts to be created that interact directly with the user, and the text on which the user is working. For information on how to write a text plug-in, see the section on Writing a Text Plug-in below.

These videos demonstrate the features introduced by this project. For a more complete list see below.


Features Completed

The following list outlines the features brought to Blender by this project:

  • Code/member suggestion and completion [done]
  • Scrollable documentation access panel [done]
  • Whole word operations [done]
  • Insert/overwrite support [done]
  • Header lists active file (or "Internal") and modified status (*) [done]
  • External modifications are checked for and reported with options [done]
  • Word wrap

It will also fix the following issues:

  • Library linked Text can be edited [fixed]
  • Backspace at top of file inserted blank line on undo [fixed]

Additional

Additional features that are being considered or would be good extensions to the project:

  • Better search: all text search, find and replace [done]
  • Interaction between Blender clipboard and text clipboard [done]
  • Additional line and positional markers, which would then allow... [done]
  • Code templates and snippets1 [done]
  • Mindrones' Wishlist2
  • Better support for other languages
  • Script output redirect

Other issues found:

  • Redo fails when re-deleting backward-selected text [fixed]
  • Pressing up at the top or down at the bottom breaks undo [fixed]

Feature Descriptions

Code Completion

When editing Python scripts it is often desirable to have a list of functions and variables defined in the current script. It is also useful to have the ability to list the various functions and fields of a given object.

The code completion section of this project brings both of these to the user and provides a platform for further completion methods (such as snippets or tags) to be implemented.

The actual completion comes from the ability to type only a few (if any) of the characters of the method or field before invoking the suggestions list. For template-like completion the system makes it very easy to add. A script can be written with the shortcut ⇆ Tab that strips out at the word preceding the cursor, looks it up in some template dict and insert()s the template into the code positioning the cursor in the right place with setCursorPos(). If time allows I will produce such a script and a tutorial on its creation at the end of the project.

To invoke completion simply enable syntax highlighting and press CtrlSpace. This will list all modules, functions and variables available or defined in the script. Additional scripts work to complete import statements:

import |

...and member fields:

import Blender
Blender.|

Where | marks the cursor position. The last period or space typed will invoke these context sensitive scripts. CtrlSpace may also be used here.

Documentation Listings

On similar lines to code completion a quick view of the documentation for an object is displayable. This aims to reduce the need for using external documentation by bringing it into the interface.

Currently, whilst inside a function:

print somefunc(somevar, | )

Pressing CtrlI will list the somefunc function's documentation text. If the cursor is not inside a function's parentheses it will attempt to display the documentation string for the name preceding it:

import Blender|

will display the text "The main Blender module"

Editing Methods

Editors typically have a set of operations that users have come to expect yet Blender lacked a number of these.

Text overwrite support. Before this project you could only insert text and the Ins key had little use. Now the Ins toggles insert/overwrite modes and changes the cursor to reflect this.

Whole word operations (implemented in some editors as Ctrl, CtrlDel, Ctrl← Backspace, etc.) have been added. Unfortunately, CtrlLeft/right are reserved for screen switching so Alt equivalents have been substituted where appropriate:

AltLeft/right Moves the cursor left/right by one word or group of symbols.
CtrlBackspace/del
AltBackspace/del
Deletes the word to the left/right of the cursor.

Word wrap is another missing feature and is very useful for writing text that is not part of a script. Word wrap will have a toggle button associated with it but is not yet implemented.

Writing a Text Plug-in

To write your own text plug-in take a look at the template under File → Script Templates → Text Plugin. The BPy module, together with the new Text object functions allow a variety of useful tools to be created.

The BPyTextPlugin Module

The central component of many text plug-ins is the python module BPyTextPlugin. This module provides tools for parsing and obtaining useful information about a given Text object. Here is a short description of how it works and the interface for using it in your own scripts.

The method of most use is get_cached_descriptor(txtobj) which returns an instance of ScriptDesc when passed a Blender Text object. If the text has not been previously parsed or for whatever reason, it is decided to reparse the text, parse_text(txtobj) is called. This method can also be used to force a re-parse.

import BPyTextPlugin, bpy

txt  = bpy.data.texts.active
desc = BPyTextPlugin.get_cached_descriptor(txt)

BPyTextPlugin.print_cache_for(txt)

The best way to understand the ScriptDesc instance is to look at the BPyTextPlugin module itself. Its vars and defs fields provide lists of VarDesc and FuncDesc instances which further describe the text. The classes field provides access to classes with their own vars and defs lists.

Each descriptor has a lineno field for accessing the number of the line on which it is first defined, and a name field for obtaining the symbol name.

Changes To The Text Object

Once a script has obtained the information it requires it can feed this information to the user by two new methods:

txt.showDoc(doc) Displays word-wrapped documentation in an easily dismissable panel
txt.suggest(list, prefix) Displays suggestions list limited to show items with the specified prefix.

It may also create markers (see below) by calling

txt.markSelection(group, (r,g,b), flags) Marks the current selection with the specified group, colour and behaviour flags. Use Text.TMARK_EDITALL to indicate that all markers of the same group should be edited together*

* Markers with this flag must be of the same length and mark equal text

Example using the suggestion and documentation tools:

import bpy
from BPyTextPlugin import suggest_cmp

txt = bpy.data.texts.active
sugs = [('suggest_me', 'v'),  # v for variable
        ('suggest_this', 'f') # f for function
       ]
sugs.sort(cmp=suggest_cmp)

txt.showDocs('Some kind of documentation string, automatically word-wrapped')
txt.suggest(sugs, 'suggest_')

Note: It is no longer necessary to sort the suggestions list but it is still recommended. Use sort(cmp=BPyTextPlugin.suggest_cmp) for sorting.

Other additions to the Blender Text object (txt):

row, col = txt.getCursorPos() Returns the cursor position (row, col). Note that line numbers are usually 1-based in python, whereas row is 0-based here.
txt.setCursorPos(row, col) Sets the position of the cursor in the Text object (or as close as possible). Selections are cleared.
row, col = txt.getSelectPos() Returns the selection cursor position (row, col). Note that line numbers are usually 1-based in python, whereas row is 0-based here.
txt.setSelectPos(row, col) Sets the position of the selection cursor in the Text object (or as close as possible). Selections are extended to this point, use setCursorPos first to base the selection.
txt.insert(string) Inserts string at the current cursor position.
txt.readline() Reads a line from the Text object in accordance with other readline methods.
txt.reset() Resets the IO pointer to the beginning (for reading).

With these tools, many plug-ins can be produced, from class browsers to template completion scripts.

Markers

Markers provide a neat way to jump around text and edit repeated portions in one go. They allow templates to be constructed where certain bits must be filled in and expand on the find and replace options.

To see markers in action see the video above or take a look at my template script:

https://svn.blender.org/svnroot/bf-blender/branches/soc-2008-quorn/release/scripts/textplugin_templates.py

The template syntax used in this script is based on GEdit's snippets1

Project Schedule

During the first week, I shall learn as much as possible about the current implementation and outline the possibilities. Some of the simpler features and fixes may be carried out here. The remainder of the time will be split as follows:

Stage 1: Implement the back end functions for code completion, documentation and other features. Output is generally directed at the console at this stage.

Stage 2: Create UI elements for displaying the requested information. Output is fed to these on request.

Stage 3: Implement advanced UI features and interaction (scrollable documentation panel, member selection). Also allow the user to enable/disable these features, possibly adding options to User Preferences although this should be limited.

Stage 4: Seemless integration: enabling context sensitive pop-up without specific user request (eg. when the user types a . after a valid variable or pressing tab for snippet completion).

Stage 5: Final testing, debugging and tidy-up. Optimizing the code for best possible performance.


On completion of the project, changes merged with the trunk will be documented for the general public. The wiki page at Manual/Python_Scripting#The_Text_Editor will be updated.

About Me

I am a 21 year old Mathematics student who has just finished his final year. I am about to embark on a Masters degree in Computer Animation. I have been developing software since an early age and have experience in many languages including Pascal, Java, C, C++ and Python. I have worked on the development of an open source renderfarm for Blender3 and make use of many open source tools in my daily life.

I love the idea of making something useful for all and hope that this project will do just that.

References

  1. GEdit Snippets
  2. Mindrones' Wishlist
  3. Distriblend