Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,23 @@ npm run build
runtime assets. The generated Rust contract bindings are checked in so normal
builds do not require a sibling Echo checkout or generator invocation.

## Files explorer

Ctrl+B opens Files in navigation mode. Click a folder or press Enter to expand
or collapse it inline. Right/l expands a folder or selects its first visible
child; Left/h collapses it or selects its parent. Backspace and Alt+Up move the
explorer root upward. Refresh with r or Ctrl+R reloads the root and collapses
expanded branches.

Click a file to select it and preview its contents in the main viewer. Enter
opens that file for editing. Previews use Graft syntax colors, prefer unsaved
open-buffer text, and remain read-only. Unsupported syntax or a parser failure
leaves a readable plain-text preview.

Press / to filter known visible paths; matching children retain their folder
ancestors, and the matching file stays selected. Esc/Enter exits filter editing
and keeps the query. Closed directories are loaded only when expanded.

## Validate The Workspace

Use the normal local gate:
Expand Down
236 changes: 236 additions & 0 deletions docs/design/0164-explorer-inline-tree-preview-syntax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
---
title: "DX-0164 - Inline explorer tree and preview syntax"
legend: "DX"
lane: "design"
issue: "https://github.com/flyingrobots/jedit/issues/348"
status: "active"
owners: ["@flyingrobots"]
created: "2026-10-15"
updated: "2026-10-15"
---

# DX-0164 - Inline explorer tree and preview syntax

## Linked Issue

https://github.com/flyingrobots/jedit/issues/348

## Decision Summary

The workspace Files explorer expands directories inline on click or Enter,
with indentation and disclosure markers. File click remains selection/preview;
file Enter remains an explicit open. Bounded read-only previews receive Graft
syntax spans without creating a buffer or claiming an Echo head.

## Sponsored Human

A Jim user wants to browse several open folders and read colored source previews
without repeatedly changing the explorer root or opening unwanted buffers.

## Sponsored Agent

An agent needs inspectable expansion state, selected entry identity, bounded
preview text and stale-result rejection to prove input and authority boundaries.

## Hill

Click and Enter reveal/hide folder children in place. Selecting a source file
renders syntax colors in the main preview while buffer authority remains intact.

## Current Truth

The fetched base is
[af1fad8ab3356fa6d96548c8793aa6f2afea8c6b](https://github.com/flyingrobots/jedit/commit/af1fad8ab3356fa6d96548c8793aa6f2afea8c6b),
footer PR #344. `file-tree.ts` changes cwd for a directory. `mouse.ts` only selects
rows. `file-explorer-preview-view.ts` builds an uncolored text Surface.
`file-explorer-preview.ts` already bounds reads and rejects stale results.
The Graft adapter currently accepts an editor-head basis; Graft itself allows
basis-free projections for disposable content.

## Problem

Entering a directory loses sibling context, clicking cannot expand it, and source
previews lose the syntax information available in the editor.

## Scope

Lazy inline expansion/collapse, nested indentation, directory pointer/keyboard
actions, filtered ancestry, refresh behavior, and read-only preview syntax.

## Non-Goals

Recursive filesystem indexing, watchers, persisted expansion, symbol search,
preview editing, new Echo buffer authorities, or changes to the startup picker.

## User Experience / Product Shape

Folders show ▸ when closed and ▾ when open; each child is indented two cells.
Clicking any part of a folder row selects and toggles it. Enter toggles it too.
Right/l expands a closed folder or enters its first child; Left/h collapses an
open folder or selects its parent. Backspace and Alt+Up retain root-parent
navigation. Refresh reloads the current root and collapses expanded branches.
An empty folder still shows its open disclosure. An unreadable folder shows the
existing directory error toast and keeps the current tree intact.

The filter searches the currently known visible rows. Matching children retain
their directory ancestors. Filtering never recursively loads closed directories.
Hover remains distinct from selection; a file click only previews, while Enter
opens it. Folder actions do not modify cwd, editor text or Echo authority.

Source previews load/highlight asynchronously. Parser errors or unsupported
languages retain readable text. The existing loading/binary/unavailable/truncated
labels remain. Header and truncation notice receive no source syntax colors.

### User Journey

Open Files with Ctrl+B, expand src and a nested folder, select a file to inspect
its highlighted preview, then Enter to open it or collapse the folder to keep
browsing. Closing Files reveals the existing editor unchanged.

### Wide UI Mockup

100x32, current theme. [Native capture](0164-explorer-witness/nested-syntax-dark-100x32.png):

```text
Files / filter Preview · main.ts
▾ src/
▸ components/ export const answer = 42;
› main.ts ^ keyword ^ number
▸ tests/
README.md
```

### Narrow UI Mockup

60x12, [native capture](0164-explorer-witness/nested-syntax-dark-60x12.png): the same pinned header and indented rows use the existing list viewport.
The selected row remains visible through collapse/expand and scrolling. The
preview occupies the existing main viewer, with clipped lines and syntax tokens.

### Accessibility Considerations

Disclosure characters communicate state without color; selection keeps the
existing filled token and hover keeps its separate token. Keyboard-only and
pointer flows share the same visible row projection and directory operation.

## Runtime / API Contract

Files entries remain the visible ordered list; optional tree metadata records
per-path depth, parent and expanded state. Loading is lazy through FileSystemPort.
The startup picker and command-path directory opens retain their existing API.

A basis-free PreviewHighlighter port accepts only preview path/text and bounded
line coordinates. The Graft adapter shares syntax-span conversion with editor
highlighting but omits the editor-head basis for previews. Preview text is
sanitized once before both parsing and rendering. The existing preview request
identity gates the combined text/syntax result. Open-buffer text remains preferred.

## Lower Modes

Unsupported syntax and parser failures produce plain text; no new required
service. Unicode, tabs and stripped controls must keep text/color alignment.
Existing minimum terminal dimensions and no-color text state remain valid.

## Data / State Model

UI-only tree metadata and preview spans are ephemeral. Collapse drops the
visible descendants and their expansion metadata. Refresh/root changes clear
metadata. Expansion loads immediate children only and excludes parent rows.
No filesystem content cache, serialization, buffer import or Echo Tick is added.

## Accessibility Posture

Folder disclosure, nesting and error state are visible without accent colors.
Active input ownership stays with Files. The main document remains a preview
until an explicit file open; hover performs no filesystem read.

## Localization / Directionality Posture

Reuse localized preview and directory-error copy. Keep literal path order in
RTL locales and reuse the existing Files indentation convention. Update the
existing Enter hint to communicate toggle/open in all 20 authored locales.

## Agent Inspectability / Explainability Posture

Tests can inspect tree metadata, selected indexes, preview result/spans and
rendered token colors. Native witnesses must show nested expansion and a colored
preview rather than infer either feature from source strings.

## Linked Invariants

Hover is not selection. Selection is not open. A preview is disposable and
read-only. Filesystem/Graft work belongs behind ports. Echo owns buffer authority.

## Design Alternatives Considered

Recursively walking the repository would delay the requested interaction and
increase read scope. Replacing cwd preserves the current defect. Lazy visible
rows with small per-path metadata fit existing selection/filter geometry.
Reusing a made-up editor head for preview syntax would misrepresent provenance;
a basis-free Graft projection is the appropriate read-only boundary.

## Decision

Implement the lazy tree and basis-free syntax projection. Preserve the existing
startup-picker and explicit file-opening behaviors.

## Implementation Slices

- [x] Slice 1: Inline directory state, rendering, keyboard and pointer behavior.
- [x] Slice 2: Basis-free Graft preview highlighting and stale/failure protection.
- [x] Slice 3: Native witnesses, full checks and review handoff.

## Tests To Write First

- [x] Enter/click expand and collapse nested directories without changing root.
- [x] Sibling branches, selection, indentation and filter ancestors stay coherent.
- [x] Empty/unreadable directories and root refresh preserve safe navigation.
- [x] Real Graft syntax colors reach the preview, including unsaved buffer text.
- [x] Stale results, parser failure, tabs, Unicode and truncation remain safe.

## Acceptance Criteria

Both actions work through the real runtime; selected previews display theme
syntax tokens. Focus/filter and explicit-open behavior remain intact. Native
terminal witnesses and focused/full checks pass. No new buffer authority exists.

## Validation Plan

TypeScript compile, focused explorer/preview/Graft tests, quality, full npm run
check, shard coverage, native wide/narrow dark/light/RTL witnesses and hosted CI.

## Playback / Witness

Ctrl+B; click or Enter on a folder; expand another level; select a TypeScript
file; verify keyword/number colors; collapse/reopen; explicitly open a file.

## Risks

A flat visible list must keep stable entry identity while indexes shift. Metadata
and rendering share one projection; mouse uses the renderer's exact rows. Syntax
must parse the same sanitized text it paints, without coloring the notice row.

## Follow-On Debt

None introduced by this scope. Global recursive search remains outside this cycle.

## Retrospective

Inline expansion, collapse, filtered ancestry and read-only syntax are implemented.
File clicks remain previews; Enter remains an explicit open for files. Directory
clicks and Enter share one lazy filesystem operation. The preview port omits an
editor-head basis, and parser failures preserve readable text.

Tests exposed one interaction refinement: filter ancestry must not steal the
initial selection from the actual match. A later full check found that row
identity needed to remain index-based rather than path-based. Both have focused
regressions, and the corrected full check passed 907 tests: 895 passed, 12 existing
skips, zero failures. Quality has no new debt; all 140 specs are assigned.

[Native evidence](0164-explorer-witness/README.md) covers mouse and Enter toggles,
root preservation, nested/filtered rows, dark 100x32 and minimum 60x12, and Arabic
light 60x16. Graft produced 13 syntax spans while preview authority remained none
and textRequestId remained 0. Only explicit file Enter opened a buffer.
Arabic rasterization proves alignment, not terminal-specific shaping.

PR: https://github.com/flyingrobots/jedit/pull/349. The change is stacked on footer
PR #344; the separate Dojo Feed branch is not part of this change.
46 changes: 46 additions & 0 deletions docs/design/0164-explorer-witness/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Inline explorer and preview syntax witnesses

These captures render Surface cells from the native Bijou terminal loop with
production Echo and the installed Graft parser. The fixture is synthetic local
TypeScript source. The committed helper reproduces the flow.

| Capture | Behavior |
| --- | --- |
| [Nested folders and colored source, 100x32](nested-syntax-dark-100x32.png) | Click expanded src/components; clicking panel.ts previewed 13 syntax spans. |
| [Filtered hierarchy, 100x32](filtered-nested-dark-100x32.png) | /panel retained src and components, selected panel.ts, and kept its colored preview. |
| [Collapsed folder, 100x32](collapsed-nested-dark-100x32.png) | Enter removed components' children and kept sibling main.ts visible. |
| [Minimum-size dark, 60x12](nested-syntax-dark-60x12.png) | Enter expanded both levels; selection/indentation and keyword/string/number colors fit. |
| [Arabic/light, 60x16](nested-syntax-light-rtl-60x16.png) | Localized preview label and footer, literal paths/source, themed syntax colors. |

Recorded native observations:

- The explorer cwd stayed identical across all wide-run operations.
- The selected preview contained 13 Graft syntax spans; textRequestId stayed 0
and authority stayed none during folder operations and preview selection.
- Enter on the selected file then produced textRequestId 1, editor focus and
opened authority through the production Echo path.
- Mouse expanded directories; keyboard Enter collapsed and reopened them.

The cell images use Menlo with Apple Symbols/Geeza Pro fallback fonts.
Arabic glyph shaping is terminal-dependent; this rasterization verifies cell
alignment and literal code/path order, not full Arabic shaping.
`receipt.json` records dimensions and captured-cell digests.

Reproduce after `npm run build`:

```sh
node scripts/explorer-inline-witness.mjs
JIM_EXPLORER_WITNESS_LOCALE=ar JIM_EXPLORER_WITNESS_LIGHT=1 node scripts/explorer-inline-witness.mjs
```

The helper writes synthetic files, isolated preferences and Echo WAL to a fresh
temporary directory. Its path is in `/tmp/jim-inline-tree-witness-directory.txt`.
Use Ctrl+B, then j Enter j Enter j to expand both levels and select panel.ts.
Clicking the same directory rows exercises pointer toggling. Type /panel to
filter; Esc exits filtering. Enter on the file opens it. Ctrl+C exits.

Validation: 47 focused explorer/Graft tests passed; the selection-index
correction then passed 24 focused navigation/tree/syntax tests. The final full
local check passed 907 tests: 895 passed, 12 existing skips, zero failures, and
no quality regressions. All 140 specs belong to CI shards. Hosted exact-head
checks are recorded in PR #349.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions docs/design/0164-explorer-witness/receipt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"method": "Native Echo/Bijou PTY cells rendered with Menlo, Apple Symbols and Geeza Pro. Glyph shaping depends on the terminal.",
"captures": [
{
"image": "collapsed-nested-dark-100x32.png",
"columns": 100,
"rows": 32,
"cellsSha256": "05243d7105c217e0d0f6d1c24eedda85881dda2eb7527015e7bdc6446aa05606"
},
{
"image": "filtered-nested-dark-100x32.png",
"columns": 100,
"rows": 32,
"cellsSha256": "c752224892407378f0be614a1cc79d6541f030b2f50f72f209a85f5796a818d6"
},
{
"image": "nested-syntax-dark-100x32.png",
"columns": 100,
"rows": 32,
"cellsSha256": "79b8061e1e9ad6bbb95cdd2e80b0b21c46e00c763a280f0facf3a79824e8b359"
},
{
"image": "nested-syntax-dark-60x12.png",
"columns": 60,
"rows": 12,
"cellsSha256": "6f0a04658851d160d4ec32ad264e5b9123564e9d887d6bf8cb2b725dc5ff1f71"
},
{
"image": "nested-syntax-light-rtl-60x16.png",
"columns": 60,
"rows": 16,
"cellsSha256": "e0ddd64ee03dec8deca3c987f0e6ea5e4c16872700093e39e811e31282bef156"
}
]
}
17 changes: 17 additions & 0 deletions docs/jim-component-ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,23 @@ continues through the native Echo text-import path.
a future workspace or symbol index must remain a rebuildable projection and
declare its observation basis and staleness policy.

The Files explorer owns ephemeral inline-tree metadata alongside its visible
entry list. Directory click/Enter toggle immediate children in place through the
filesystem port, preserving cwd and other branches. Disclosure, indentation,
selection and hover derive from the same rows used by pointer hit testing.
Filtering retains ancestors of matching known rows without recursively reading
closed directories; it selects the first actual match. Collapse drops descendant
metadata, and refresh/root changes reset expansion. The startup picker retains
its existing directory-changing behavior.

Preview syntax is a disposable Graft projection through a basis-free preview
highlighting port, separate from editor-head highlighting. Both parse and render
use the same sanitized bounded text. Open-buffer text remains preferred, and
request/entry identity rejects stale text and spans together. Parser failure
retains plain text. Preview colors do not introduce a buffer, head, Tick or save
authority. [DX-0164](design/0164-explorer-inline-tree-preview-syntax.md) refines
[DX-0161](design/0161-file-explorer-search.md) and owns this cycle's evidence.

The footer layout is a Jedit presentation preference, remembered across launches
through an injected preferences port and the `~/.jimrc` JSON adapter. The
`filepathStyle` preference shares that adapter and chooses paths relative to
Expand Down
Loading
Loading