Editora 0.14.0 docs. You are reading an archived version, kept so links from that release keep working. Read the 0.15.0 docs →

Code navigation

Moving around code is two questions. Reach: can the thing be found at all? Flow: can you jump without losing your place? This page covers both — the server-free symbol index that answers the first, and the peek, preview and related-file moves that answer the second.

For pickers, find, and project-wide search, see Navigation & search.

Go to Symbol in Project

Go to Symbol in Project (index.gotoSymbol) finds a class, method or function anywhere in the project with no language server installed. Editora carries its own declaration scanner, so the question works on a first run and in every language that ships a grammar but has no server.

Sixteen language ids are covered: Java, Kotlin, C#, Python, JavaScript, JSX, TypeScript, TSX, Go, Rust, C, C++, Ruby, PHP, shell and Lua. The symbols it records are the kinds a pattern can identify honestly — type, interface, enum, method, function, field, variable, module — rather than LSP’s twenty-six, most of which need real type resolution to tell apart.

The same index backs the file and symbol halves of Search Everywhere and Go to Related File.

It is built lazily

The index is not built when a project opens. Walking every file the moment you open a folder spends real work on behalf of someone who may never ask it anything; asking for a symbol is the justification. So the first query pays for the walk — under a second on a 650-file project, announced in the status bar so it doesn’t look like a hang — and after that it is incremental: saving a file rescans exactly that file, from the text already in memory.

There is no second filesystem watcher; the project tree already runs one. For files changed outside the editor, Rebuild Symbol Index (index.rebuild) scans the project again from scratch.

It honours your .gitignore the same way Find in Files and the project tree do, skips files over 2 MB, and is bounded (20,000 files, 400,000 symbols) — an index that can grow without limit in the background is a memory leak with a feature attached.

It under-reports on purpose

A missing declaration costs you one fallback to search; an invented one sends you somewhere that doesn’t exist and teaches you not to trust the feature. When the scanner isn’t sure, it says nothing.

The index is a floor, not a competitor. Where a language server is running it is better at this in every respect, and LSP: Go to Symbol in Workspace (lsp.gotoSymbol) remains the better answer there.

Turn it off in Settings → Editor → Display (“Project symbol index”), or with view.toggleSymbolIndex. Disabling it releases the project’s symbols.

Sticky scroll

Sticky scroll pins the enclosing scope headers above the viewport, so deep in a long method you can still see what it belongs to — the class, the method, the block. Clicking a pinned row jumps to it, which is the other half of the feature: the header tells you where you are, and it is also the way back.

Two rules make it stay out of the way:

  • A header already on screen is not pinned. Pinning it would cover the real line with a copy of itself.
  • When the chain is deeper than the cap (5 rows), the outermost entries are kept. The innermost scope is the one you can infer from the code in front of you; the file-level type has been off screen longest.

Rows are rebuilt from the highlighting the editor has already applied, so they match what’s on screen and cost no extra tokenizing. It’s on by default — Settings → Editor → Display, or view.toggleStickyScroll — and off in large-file mode along with the other per-viewport work.

Peek Definition

LSP: Peek Definition (lsp.peekDefinition) shows a definition over the editor and leaves your place, scroll position and tab count exactly where they were.

Go-to-definition answers “what is this” by moving you, and most of the time the question is only a signature and a few lines of body — an answer that doesn’t justify the move. The peek shows a couple of lines of context and a dozen of the definition, syntax-highlighted. Enter commits to the real jump, so nothing is taken away; Esc dismisses it.

A library target with no file to read degrades to the full go-to-definition rather than reporting a failure.

Needs a language server for the file.

Go to Definition in a Split

LSP: Go to Definition in Split (lsp.gotoDefinitionInSplit) puts the definition in a new editor group and leaves the origin where it was — the pair you usually want on screen together is the call and the thing called.

A definition in the same file jumps without splitting: there’s only one tab, so the split would move it and leave the group it came from empty.

Preview tabs

Browsing costs one tab, not one per glance. Arrowing through a picker, or following a definition to see what something is, reuses a single slot whose title is italic — the same “not durable yet” convention the unsaved marker uses.

It becomes a permanent tab when you commit to it:

  • editing the file promotes it, and
  • opening it explicitly (from the file finder, the project tree, anywhere that isn’t a glance) promotes it.

An already-open file is never demoted into the slot. It earned its place by an earlier deliberate open, and quietly making it disposable would lose it on the next glance at something else. A file with unsaved changes is never reused either.

Go: Related File (nav.relatedFile) pairs a file with its counterpart — a test and the class it tests, a header and its implementation, a component and its stylesheet. It works in both directions, and coming from a test the subject leads.

FromOffers
Foo.javaFooTest.java, FooTests.java, FooSpec.java, FooIT.java
FooTest.javaFoo.java
test_foo.pyfoo.py
foo.cfoo.h
foo.cppfoo.hpp, foo.hxx, foo.h
Button.tsxButton.css, Button.scss
app.jsapp.css, app.scss, app.html
x_test.go, x.test.ts, x.spec.tsx.go, x.ts

These are conventions rather than facts, so Editora proposes candidate names in preference order and offers only the ones that exist — a convention being wrong therefore costs nothing, which is what lets the list be generous. A counterpart rarely sits beside its partner (a test lives under src/test, a header under include), so the sibling directory is only the first place looked; the symbol index knows every file in the project and finds the rest.

One match opens. Several offer a picker, since Foo.css and Foo.scss can both exist and only you know which was meant.

Keeping your place

Three things work together here, and each is documented where it lives:

  • Back and forward steps through the jump list.
  • Recent Locations lists the session’s trail with the line you were on, and previews as you arrow through it.
  • Bookmarks mark places you want to return to deliberately, and a mnemonic turns one into a single chord.

None of these commands has a default chord — bind the ones you use from Settings → Keymap.