External Edit Protocol

Introduction

The External Edit protocol allows one application to delegate editing, display, or playback of a single data object to another application. The client application starts an external editing session, transfers an initial data object if required, and later requests the edited data back. The editor application opens an appropriate window or playback context for that object, allows the user to work with it, and returns the resulting data through the normal RISC OS data transfer mechanisms.

Overview

The protocol is intended to provide a simple, desktop-oriented alternative to embedding many specialised editors inside larger applications. It applies the same basic idea used by command-line systems, where an application saves data, invokes an external editor, and then reloads the result, but adapts that model to a multitasking desktop environment.

The protocol also exists as a reaction against monolithic applications that contain their own weak built-in editors for specialist data. Instead of forcing every application to carry a private bitmap editor, text editor, sound viewer, or palette chooser, the desktop can share one capable editor for each kind of data and let users choose which editor they prefer.

Using a separate data editor has several practical advantages:

The protocol therefore provides a lightweight form of hotlinking. The data is treated as a single transferable object, handed out to another task for work, and later returned as a single object. It does not try to provide continuous, system-wide live linking, but it does provide a simple and effective base level of inter-application cooperation with far less operating system support and far less implementation complexity.

An external edit session always involves three parties:

The protocol is deliberately built around standard Wimp messages and the existing RAM transfer and file transfer protocols. This keeps client-side support small and allows editors to reuse existing data transfer code.

Typical uses

The original protocol document described a range of uses that motivated the design:

  • A compiler can open a source file in a text editor, position the cursor at the error, and recompile when the user requests return of the edited text.
  • A desktop publisher can hand a DrawFile illustration to a drawing package and later replace the embedded object with the returned result.
  • A DrawFile editor can hand text areas to a text editor and sprites to a paint package.
  • A music or sample editor can display and play individual sample data in a specialist sample editor.
  • An adventure authoring system can use fully-featured external text and graphics editors while keeping only the game-specific location and object editing logic in-house.
  • A hypermedia or browser-style application can ask the desktop to display or play file types that it does not itself understand.
  • A configuration tool can centralise preference editing for multiple applications through a shared editor for the configuration data.
  • Palette or true-colour chooser data can be delegated to a colour editor that returns the chosen values in a form the client can use.

Technical Details

Session model

The client starts a session by broadcasting Message_EditRq. An editor that can handle the requested data type opens a blank editing context and replies with Message_EditAck. The client may then send one or more Message_EditDataSave messages to insert data, may use Message_EditCursor to set or inspect the current cursor or selection, and may use Message_EditReturn to request the edited data back. Either party may terminate the session with Message_EditAbort.

The editor may also initiate return of the data, for example when the user chooses a save action or closes the external edit window. The returned data is sent through Message_EditDataSave followed by the normal Acorn data transfer messages.

Common data items

Data type word

Most protocol messages carry a 32-bit data type word in the form &eeee0ttt. The low 16 bits carry the base RISC OS file type. The high 16 bits carry an extension that refines the meaning of that file type when a plain file type is not precise enough.

An extension of &0000 means that no extra typing information is supplied beyond the base RISC OS file type. Values &0001 to &04FF are reserved for user allocation, although shared protocol use benefits from a single agreed allocation for each specialised data type.

Job handle

The job handle identifies one session throughout its lifetime. It has the form &eeeecccc, where the low 16 bits are chosen by the client and the high 16 bits are chosen by the editor. Both halves must be non-zero. Once established, the handle never changes for that session.

Each side should choose values that are unique across the lifetime of the task, rather than recycling handle values. A practical implementation is to use part of the local 16-bit half as a monotonically increasing session number and part as an array index, then validate the full 32-bit handle before acting on any message for an existing session.

Flag word

The protocol uses a single flag word layout across all messages. Some flags are only meaningful for particular messages; unsupported or irrelevant flags should be ignored.

Bit(s)NameMeaning
0Continue editing For messages that return data, this bit controls whether the session continues after the transfer completes. A set bit means that editing should continue; a clear bit means that the session should end once the data has been returned.
1Selection only In Message_EditReturn, this bit requests that only the current selection be returned. When data is returned, the same bit reports whether the whole object or only the selection is being sent.
2Read-only Requests that the editor treat the data as read-only. Editors that support read-only operation should prevent modification; clients must still be ready to ignore unexpected attempts to return changed data.
3Immediate execution Requests that playable or executable data should start as soon as practical after receipt. If the data type has no playback concept, the editor ignores this flag.
4Adjust selection For Message_EditCursor, adds the supplied selection range to the current selection rather than replacing it.
5-31Reserved, must be zero

Data transfer

The protocol does not define a new payload transfer format. Instead, it uses Message_EditDataSave as the session-scoped equivalent of Message_DataSave, then follows the normal RAM transfer or file transfer conventions already used elsewhere on the desktop.

The client typically sends one initial data transfer immediately after receiving Message_EditAck, but a blank edit window is also valid. Additional transfers from the client are inserted at the current cursor position when that concept exists. Transfers from the editor return the current edited object or selection to the client.

Cursor and selection model

Message_EditCursor positions a cursor, selects a contiguous range of data units, or queries the current values. The smallest meaningful unit depends on the data type. If no specialised unit has been agreed for a type, byte offsets are the default.

The cursor position identifies a data unit counted from the start of the object. Unit 1 is the first item, unit 2 the second, and so on. For text-like data where a caret sits between units, the caret is positioned after the named unit; the special position 0 therefore places the caret before the first unit. For object-based formats such as DrawFile, position 0 should be treated as 1.

The value -1 (&FFFFFFFF) means "leave this position unchanged". The value -2 (&FFFFFFFE) means "end of data". Setting all three new position fields to -1 reads the current positions without moving them.

TypeFile typeData unit
Text&FFFCharacter.
Command&FFECharacter.
TaskObey&FD7Character.
TaskExec&FD6Character.
Obey&FEBCharacter.
Data&FFDByte offset.
BASIC&FFBByte offset in tokenised form, or character offset in text form.
Sprite&FF9Sprite number or index.
Palette&FEDColour index in the standard file format.
DrawFile&AFFDraw object.
ARMovie&AE7Animation frame number.

Returning data

The client can explicitly request return of the edited data by sending Message_EditReturn. The editor can also return the data because of user actions within the editing session.

Common editor-side triggers are:

  • The user chooses a save action or confirms the save-as dialogue, in which case the editor returns the data and then ends the session only if the Continue editing flag is clear.
  • The user drags the save icon to a file destination, in which case the editor writes a copy to disc and continues editing.
  • The user closes the external edit window, in which case the editor should offer the same Save, Discard, and Cancel choices that it would for an ordinary modified document.

Error handling and closure

Missing replies do not always indicate failure. Some protocol steps expect no response, and Message_EditCursor in particular is not a reliable heartbeat for session liveness. A session should only be assumed dead when a definitive failure occurs or when the surrounding data transfer protocols report a real breakdown.

When communication has genuinely failed, or when either task must abandon the session unexpectedly, it should send Message_EditAbort if at all possible and then release all local state for that handle. Clients should treat externally edited data as modified data when deciding whether a document may be closed.

If a document contains data currently being edited externally, closing that document should behave like closing a document with unsaved changes. The user should be able to request a return-and-save operation or discard the external session explicitly.

Multi-file and nested editing

ExtEdit exchanges a single data object. Document formats that consist of multiple files or directories must define their own representation for transporting that object as a single transferable entity. One workable approach is to avoid RAM transfer for such formats and rely on saved files on disc; another is to define a custom single-file transport form.

Editors should treat child external edits as separate sessions rather than automatically pulling those child results back into the parent object when the parent itself is returned. A parent editor may warn that child external edits remain unreturned, but it should not silently update its own return data from those child sessions.

Registered users and future extensions

The original document recorded current and planned users of the protocol to encourage adoption and interoperability. At that time, StrongEd 2 and StrongHlp already supported the protocol, and Zap, ZEdit, and DSEdit II were listed as intending to support it.

The protocol also reserved space for future extension. New flag bits, extended data types, and any extra messages or SWI-based support layered on top of the core protocol should be allocated in a coordinated way so that independent applications do not collide.

Wimp Messages

Message_EditRq&45D80
Request an external editing session
OffsetSizeNameContents
204data_typeData type word for the object to be edited.
244job_handleClient-generated session handle. The top 16 bits must be zero and the low 16 bits must contain a unique non-zero client identifier.
284flagsFlag word. Valid bits are Continue editing, Read-only, and Immediate execution.
3220parent_nameNull-terminated parent document or application name. Editors should include this in the temporary window title when present.
52204leaf_nameSuggested leafname for display in the title bar and as the default save-as name.
Client task
Editors able to handle the requested data type
Message must be broadcast (destination 0)

Message may only be sent normally (reason code 17)

The client broadcasts this message when it wants another task to open an external editing or playback session. Editors that can support the request claim it by opening an appropriate blank context and replying with Message_EditAck.

Read-only editors should only reply when the Read-only flag is set. A client that prefers a full editor should first broadcast with Read-only clear, then retry with Read-only set only if no suitable editor responds.

Message_EditAck&45D81
Acknowledge and claim an external editing session
OffsetSizeNameContents
204data_typeCopied from the request message.
244job_handleThe client half from the request plus the editor's own unique non-zero high 16-bit identifier.
284flagsReturned status flags. The editor reports the actual state it can provide, including whether the session is read-only.
Editor task
The requesting client task
Message must be sent directly to task

Message may only be sent normally (reason code 17)

An editor sends this message only in reply to Message_EditRq after opening a blank editing context for the requested data type.

The returned flags tell the client what kind of session has actually been opened. If the reported state is unacceptable, such as a forced read-only session when editable data was required, the client should inform the user and abort the session.

Message_EditReturn&45D82
Request return of the current external edit data
OffsetSizeNameContents
204data_typeRequested return type. This allows the client to ask for the returned data in a format different from the one originally sent.
244job_handleSession handle.
284flagsValid bits are Continue editing and Selection only.
Client task
The editor task for the session
Message must be sent directly to task

Message may only be sent normally (reason code 17)

The client sends this message when it wants the current edited data back, for example to recompile a source file or update an embedded object in its own document.

If the editor cannot return the data in the requested type, it should ignore the request. The client may then retry with a different type until a suitable compromise is found. This message should not be used for read-only sessions.

Message_EditAbort&45D83
Terminate an external editing session
OffsetSizeNameContents
204reservedReserved, must be zero
244job_handleSession handle to be abandoned.
Client or editor task
The other task participating in the session
Message must be sent directly to task

Message may only be sent normally (reason code 17)

Either party may send this message to terminate the session completely. After receiving it, both parties should discard local state for the handle and ignore all later traffic that refers to that session.

The editor should close its window and stop any playback associated with the session. The sender is responsible for reporting any failure to the user. This message should not be sent before a valid session exists and should not be sent in the middle of a data transfer.

Message_EditDataSave&45D84
Start a data transfer within an external edit session
OffsetSizeNameContents
204job_handleSession handle. This replaces the normal window handle field of Message_DataSave.
244ignored_iconIgnored. Occupies the position of the normal icon handle.
284ignored_xIgnored. Occupies the position of the normal X coordinate.
324ignored_yIgnored. Occupies the position of the normal Y coordinate.
364estimated_sizeEstimated transfer size in bytes.
404file_typeBase RISC OS file type for the transferred object, not the extended data type word.
44212leaf_nameProposed leafname for the transfer, as in Message_DataSave.
Client or editor task
The other task participating in the session
Message must be sent directly to task

Message may only be sent normally (reason code 17)

This message is the ExtEdit equivalent of Message_DataSave. After it is sent, all follow-up messages are the normal Acorn data transfer messages. The sender may use RAM transfer or file transfer exactly as it would for any other desktop data exchange.

The client normally sends this message soon after Message_EditAck to provide the initial object to edit, but it may also send additional transfers later. The editor sends this message when returning data after Message_EditReturn or after user-driven save or close actions.

Message_EditCursor&45D85
Set or query cursor and selection positions
OffsetSizeNameContents
204reservedReserved, must be zero
244job_handleSession handle.
284flagsValid bits are Read-only, Immediate execution, and Adjust selection. The editor returns the new current flag state in the reply.
324new_cursorNew cursor position, or -1 to leave unchanged.
364new_selection_startNew start of selection, or -1 to leave unchanged.
404new_selection_endNew end of selection, or -1 to leave unchanged.
444old_cursorPrevious or current cursor position returned by the editor.
484old_selection_startPrevious or current selection start returned by the editor.
524old_selection_endPrevious or current selection end returned by the editor.
Client task
The editor task for the session
Message must be sent directly to task

Message may only be sent normally (reason code 17)

The client sends this message to position the cursor, select data, toggle read-only or playback state, or inspect the editor's current values. The editor returns the message immediately to confirm the result.

The value -2 means end of data. To select an entire object, set the selection range from 0 to -2. Editors that cannot describe their current cursor or selection as one contiguous range should return -1 in the old-value fields.

System Variables

Alias$@EditType_xxx
Command used to start a suitable external editor for a file type

Clients that receive no suitable reply to Message_EditRq should first retry with less specific data types or with a read-only request if that is acceptable. If no editor is already running, the client may then attempt to start one by executing the most appropriate Alias$@EditType_xxx variable, where xxx is the three-digit hexadecimal base file type.

Editors should normally define these aliases in their boot sequence so that clients can run a suitable editor without hard-wiring any particular application name.

Examples

Boot-time alias definition

An editor for plain text might define both a normal run alias and an ExtEdit alias in its boot file:

Set Alias$@RunType_FFF Run <Obey$Dir>.!Run %%*0
Set Alias$@EditType_FFF Run <Obey$Dir>.!Run

Client fallback behaviour

A robust client follows this general policy:

  1. Broadcast Message_EditRq for the preferred extended data type.
  2. If no editor replies, retry with a less specific type or with a read-only request if displaying the data would still be useful.
  3. If no running editor responds, execute the most appropriate Alias$@EditType_xxx variable and then retry the request.
  4. If every attempt fails, report to the user that no suitable editor is available.