Preface

The programming interface of Lispworks Editor is not as easily accessible as Emacs, mostly because its exported symbols are too trivial, most of useful functions and facilities are internal and haven't well-documented. In another side, it's source codes are solely in Lisp and have plenty of comments, so playing with it is not much difficult. I will write down some experience here that seems haven't documented well, as a patch for my broken draining memory. Maybe many mistakes, Welcome to correct~

Topics

Multi-thread problem

Every capi:editor instance shares a single standalone editor thread, so calling editor and sharing data/status between editor and interface event loop can be difficult. Here are some points:

  • On the CAPI side, The before-change-callback and after-change-callback are executed in the Editor Thread, so functions like editor:current-point will work, but modifying the interface should use capi:apply-in-pane-process or something else.
  • Also, capi:process-charater etc. have no return value, so we have to decide whether putting the main logic into the CAPI callbacks or the Editor Mode and Commands. Classical difficulty of multiprocessing.
  • Editor-> interface: (editor:window-text-pane (editor:current-window)), Interface -> Editor: (editor:process-character #'(lambda ()) (capi:editor-window <instance>))

Modifying input

  • capi:call-editor capi:call-editor can not only receive string, as the manual said, but can also accept gesture-spec produced by the input-model of capi:output-pane. This behavior have been noticed in the capi manual implicitly.

Text properties, the Way of Controlling Typography

Text property is one of the basic part of editor that being shadowed by LW... Most of Emacs functions have a synonym one in LW editor, can straightly being used.

  • editor::merge-face-property for adding face to exist one;
  • (editor:put-text-property-no-edit <start> <end> 'face <val>) to set a new one, like in Emacs;
  • Can use editor::font-lock-apply-highlight when extending font-lock-mode, will reduce unnecessary changes and improve performance.

Use capi:make-face with name nil to get a temporary face.

Font Lock Mode

Two main part of LW editor's font-lock-mode are fontify-syntactically-region and fontify-keyword-region, excute in order. One is for block-appearances like string, comment, decoration, compiler-macro and so on; and another is for putting different style to function-names, variable-names, class-names, keywords, etc. Buffer-specified fontify functions can be set using two buffer-local Editor-variables starting with font-lock.

There seems no better coding entrance to change editor's default face/font in a buffer-local scale, I've chosen to do it within font-lock function temporarily...

Hooks

LW Editor's Hook system is quite primitive compared to Emacs, some hooks have even no exact functionality :(...

Make it look like...

Obviously, input-hook and make-buffer-hook cannot work, make it quite hard to catch input inside Editor thread, and have to subclass editor instead of just defining modes when acquiring complex functionality. Hopefully there's still a higher layer over the Editor itself... sometimes not too bad compared to Emacs.

Other documented hooks just works well.

I haven't tried to advice editor:self-insert-command, but I think it's not a good way...

Buffer Flags

Flags are omitted from Editor Manual. It's used to distinguish the type of buffers.

  • Buffers with :main-buffer or nil are "selectable", only those buffers can be switched to with editor command. Force edit them may cause severe error.
  • Buffer with :collector binds to a stream - LW can use Editor buffer to store stream content. Background Output is one of them, which is the redirection of *standard-output* and *query-io*. Switch to it to view the standard output.
  • Buffer with :echo is a echo-area buffer, can be a spam when lots of editor-pane created, and that's why it's important to hide them.
  • A listener pane will create a buffer tagged with :listener. Obviously, try to do insertion outside it's listener pane will directly send me to deep-level debugger :(
  • And so on...

Use (editor::selectable-buffers) to get all of selectable buffers, instead of using editor:*buffer-list*. Idk why it's internal...

Add our own buffer flag to editor::*selectable-buffer-flags to make them selectable.

Some Tricks to deal with Unreasonable Issues

(On Windows platform)

  • When the editor pane cannot hold meta key well and always switch focus to it's non-existed menu bar, even after defining capi:interface-key-style method for it's top-level interface, adding lw-tools:lispworks-interface as a superclass of the interface may work.
  • Override Hi-DPI scaling setting of the LW main excutable can cause various effects and makes Hi-DPI applicable:
    • Application: Hi-DPI simple-pane and output-pane, just drawing my own suit of 32x icons can make perfect. Editor and other capi:output-pane subclasses will be more smooth but greatly laggy than before, may because performance issue. Problem becomes obvious when scrolling. how to even only make the pane vertical sync?
    • System: blurred 4-in-1 pixel on my 4k screen, any pane. This is the default visual for me.
    • System (Enhanced): Hi-DPI simple-pane with enlarged 16x icons, great for UI, but Editor and other capi:output-pane subclasses becomes both blurred and laggy... Very dramatic x_x... Capability Settings

Wish you're having a wonderful day, eating your favourite dishes, pooping smoothly, and sleeping until naturally wake up ^_^~