Main > Computers > Applications
Usage, macros, developer documentation
Last changed: April 2 2006
Warning: Information contained on this page comes mostly from my experience and studies of jEdit source code and thus it can be sometimes inaccurate.
See jEdit Source Code Intro at jEdit wiki.
From jEdit wiki:
Each window in jEdit is an instance of the View class. Each text area you see in a View is an instance of JEditTextArea, each of which is contained in its own EditPane. Files are represented by the Buffer class.
![]() |
| NOTES: Only methods important from the point of view of mutual
relations are shown. In words: Every view has 1 jEditTextArea and many EditPanes, each with 1 buffer. Warning: this diagram is my understanding of jEdit's structure and may be inaccurate. |
KeyEvents in jEdit are processed by View.processEvent and are treated differently with respect to the source (text area or another part of the view?) and w.r.t. the type of the event (key pressed/typed/released). The method uses View.inputHandler and its handleKey to handle key bindings - to recognize them, invoke the appropriate action and to discard the input (consuming the event(s)) so that it's not processed further. If an event is consumed KeyEventListeners will never by notified of it (note: KEY_RELEASED events are nearly not filtered at all so even if key pressed/typed event has been discarded you can receive key released). Below I give an approximate diagram of how KEY_PRESSED events originated from a text area are treated.
|
| LEGEND: evt = the KeyEvent object |
An Action object executes its code when it is invoked. It has assigned a name, which is a String such as "next-page" or "backspace" by which it can be reffered to to invoke it. A user invokes the action via its name and jEdit looks up the Action object and executes it. The action name can be associated to a particular key stroke or menu item and when the user types the key stroke or clicks the menu the action is looked up and performed.
| keyStroke/keyBinding | -> | action name | -> | Action.actionPerformed |
|---|---|---|---|---|
| input
map |
action
map |
|||
| Ex: Ctrl-n | "new-file" | jEdit.newFile(view); |
TASK: Perform an action when a word has been typed in a given buffer.
Task analysis:
Printable characters can be observed by a KeyListener. We can only add it to a jEditTextArea or a View who have inherited the method addKeyListener from java.awt.Component. But since we're interested in a file == in a buffer this is not a good way.
Buffer is not a graphical (AWT) class but it offers the method addBufferChangeListener. The following methods of BufferListener would interest us: contentInserted, contentRemoved, transactionComplete (undo/redo/compound edit). Note: According to the doc you shouldn't implement it but rather subclass BufferChangeAdapter.
To detect an event that discards the word being recorded we may listen to caret changes via a CaretListener (jEditTextArea.addCaretListener) and check whether its movement corresponds to the character entered/deleted by backspace or not (=> home, page up etc.). I believe that the parameter offset of contentInserted/Removed should be the same as offset of the caret in the active view. Note: the listener's caretUpdate is called even when the caret hasn't changed (such as pressing End already at the end of a line or clicking to the caret position).
A hypothesis: The buffer may be displayed in edit panes having a different caret & caret position in each => check the pair edit pane + buffer. } => We have to decide whether to observer only one buffer + edit pane or whether we observe all edit panes of the given buffer and discard the recorded word if the user starts editing it in another edit pane.
jEditTextArea.getCaretPosition()
So far I've created the plugin TextAutocomplete and contributed to LaTeX Tools.
Let's see how the SourceForge's user malyvelky creates the plugin named TextAutocomplete
bash$ cvs -z3 -d :ext:malyvelky@cvs.sourceforge.net:/cvsroot/jedit co -l plugins bash$ cd plugins/ bash$ mkdir TextAutocomplete bash$ cvs add TextAutocomplete
Now you leave the plugins/ directory and somewhere else execute:
bash$ cvs -z3 -d :ext:malyvelky@cvs.sourceforge.net:/cvsroot/jedit co plugins/TextAutocomplete malyvelky@cvs.sourceforge.net's password: cvs checkout: Updating plugins/TextAutocompleted
This will create the nearly empty directory plugins/TextAutocomplete/ that will contain the directory CVS/ and that shall become the root directory of your plugin.
The following methods are interesting:
generateCache that opens the plugin's jar
archive and looks there for various files including actions.xml
and *Plugin.java.loadCache(cache) if the cache (the file
<Settings directory>/jars-cache/<Plugin
name>.jar.summary - on Linux Settings directory =
$HOME/.jedit) existsorg.gjt.sp.jedit.BeanShell and its methods
cacheBlock and runCachedBlock. See
BeanShellAction for an example.If you want to add completion (e.g. command completion) to buffers handeled by your plugin, you need to several thing. I will demonstrate that using the SideKickParser uk.co.antroy.latextools.parsers.LaTeXParser with the latex_parser and label LaTeX - thanks to Anthony Roy who wrote it.
First you should read the jEdit Help for SideKick.
Create and setup a SideKick parser
plugin.<your plugin name>.depend.0=plugin sidekick.SideKickPlugin <version> mode.<a mode name>.sidekick.parser=latex_parser # For example: mode.tex.sidekick.parser=latex_parser sidekick.parser.latex_parser.label=LaTeX
parse.<?xml version="1.0"?>
<!DOCTYPE SERVICES SYSTEM "services.dtd">
<SERVICES>
<SERVICE CLASS="sidekick.SideKickParser" NAME="latex_parser">
new uk.co.antroy.latextools.parsers.LaTeXParser("latex_parser");
</SERVICE>
</SERVICES>
Create the support for completion
SideKickCompletion and add the possible
completions of the text typed so far (the parameter 'text') to the list
in its constructor (items.add("completion1")). You may but
don't need to override any method. SideKickParser subclass override the method
supportsCompletion to return true and implement the method
complete(EditPane editPane, int caret) - if the word typed
so far (the 'text' passed to the constructor of the SideKickCompletion)
is important to you, you need to get it - for example as follows: Buffer buffer = editPane.getBuffer();
JEditTextArea textArea = editPane.getTextArea();
int caretLine = textArea.getCaretLine();
int caretInLine = caret - buffer.getLineStartOffset(caretLine);
if (caretInLine == 0) return null;
String line = buffer.getLineText(caretLine);
int wordStart = TextUtilities.findWordStart(line, caretInLine - 1, "");
String currentWord = line.substring(wordStart, caretInLine);
The completion is triggered (and the completions are offered) either manually, after a certain delay (if canCompleteAnywhere is true) or immediately when particular character has been typed - see the SideKickParser's methods