ADR: Segment Sorting in the Editor

Status

Proposed (Date: 2026-07-23)

Context

Feature request #1094 asks for a way to sort the segments displayed in the editor, for example alphabetically by source text, so that translators can group similar segments and translate them in one pass.

Historically the editor displays segments strictly in their natural project order (the order in which the file filters produced them from the source files). There was no extension point for reordering the display.

Implementing sorting on top of an existing editor extension point was considered and rejected. In particular, IEditorFilter is a hook for batch processing of the segments, not a display-order mechanism: attaching ordering to it would have forced every existing and future implementation to also deal with ordering, and plugins and scripts could not have reordered the editor without replacing an active IEditorFilter. Which segments the editor displays and in which order it displays them are orthogonal concerns, so ordering gets its own dedicated hook and the two mechanisms stay independent of each other.

In addition, parts of the entry navigation assumed that displayed segments appear in ascending entry-number order (positional lookups), an assumption that any custom order breaks.

Decision

Sorting is provided through a dedicated, minimal core hook, with the sorter model and its UI kept outside the core.

1. The IEditorSorter interface

org.omegat.gui.editor.IEditorSorter decides in which order the editor displays the segments of the currently displayed file, without any influence on which segments are displayed. It exposes a single method:

  • getComparator() returns a Comparator<SegmentBuilder> used to order the displayed list of segments. Implementations must define a stable, total order and should fall back to the natural project order (by entry number) for otherwise-equal segments, so that the result is fully deterministic.

The comparator is applied in EditorController.loadDocument() to the segments being displayed. When no sorter is set, the loading code path is unchanged and the document order is identical to previous releases.

2. API on IEditor

IEditor gains setSort, getSort and removeSort. ConsoleBindings implements the new methods, so scripts running in console mode keep working. Plugins and scripts can therefore reorder the editor display without touching any other editor mechanism.

3. Scope: per-file ordering

The editor loads one source file at a time, so the comparator only reorders the segments within the currently displayed file. It does not establish a project-wide order across files; navigation still moves from file to file in natural project order.

4. Navigation by entry number

Entry navigation locates entries by their exact entry number instead of assuming positional (ascending) order, so activation, history and neighbour navigation keep working under any custom order.

5. Sorter model and UI outside the core hook

The core only knows the IEditorSorter hook. The concrete sorter model and its UI are delivered separately:

  • The sort bar UI and the multi-key sorter model (org.omegat.gui.editor.sort: SortBar, SortKey, MultiKeySorter, TextKeyComparator, NumericValueComparator, CachingCollatorComparator).

  • The collapsible bar component (CollapsibleBar) that hosts the sort bar without taking up editor space when unused.

  • Numeric ordering of textual numbers builds on the numeral parsing foundation (NumeralValueParser).

Consequences

  • With no sorter set, the editor behaves exactly as before; the default code path is unaffected.

  • Sorting is independent of the editor’s other extension points; in particular it neither uses nor restricts the IEditorFilter batch-processing API, and both can be active at the same time.

  • Plugins and scripts get a supported way to reorder the editor display.

  • Entry navigation is robust under any permutation of the displayed segments.

  • Ordering is limited to the currently displayed file; a project-wide order across files is out of scope for this design.

  • The core commitment is a single small interface; sorting criteria and UI can evolve (or be replaced by plugins) without further core changes.

References