TextoA minimalist writing editor for markdown, inside VSCode. Hidden markdown
syntax, readable typography, no distractions; the texts stay as See Guide for the AuthorThis part assumes nothing: not that you know VSCode, not that you have ever written a configuration file. Follow the steps in order. The extension's own text — Settings UI, command palette, status bar, word
count — follows VSCode's display language: Spanish if VSCode is in Spanish,
English otherwise, with no setting of its own to override that (see
Two conventions used throughout:
1. Install the extensionThis project publishes tagged releases to the VS Code Marketplace and to the
Open VSX Registry (search
To update later, repeat steps 2–4; VSCode replaces the old version. Reload
any window already open — command palette → 2. Open a Chapter in the Writing editorA Chapter is one
The same file, now as prose. Section 3 makes this permanent for a whole folder, so you never have to do either again. If Texto: Writing editor (or Open with Texto) is not in that list, stop here and go back to section 1 — the extension is not installed. The way back — plain markdown, syntax and all — is the same menu's other
entry, Open as markdown. Handy inside a Writing space (section 3),
where One paragraph, one line. Write each paragraph as a single line and let it
wrap on screen — press Already have a Chapter hard-wrapped this way? VSCode's own Join Lines
(Unir líneas, 3. Make a folder a Writing spaceA Writing space is a folder whose
This only affects that folder — Keep this block when adding the settings of section 5 to the same file; the complete example is at the end of that section. 4. The two places a setting can liveEvery option in section 5 is a VSCode setting, and VSCode stores settings in two places — worth understanding, because it decides who the setting applies to:
The second is a plain text file inside your Work's folder — commit it and the configuration travels with the text, on any computer, for anyone. When a setting is in both places, the folder's file wins for its files. That also decides where a change lands: the buttons in section 6 write to
the Work's 5. The settings, one by oneFour in total: Editor theme, Text size, Alignment and Focus mode. Section 6 is the fast way to reach all four without leaving the Chapter; this section is the reference for what each does and how to set it permanently.
5.1. Editor theme (
|
| Value | What you get |
|---|---|
light |
Paper background, dark ink. The default. |
dark |
Dark background, light ink. |
vscode |
The Writing editor follows VSCode's active theme, and changes with it. |
The short way (recommended). No files, just a dropdown:
- Press
Cmd+,/Ctrl+,to open Settings (Configuración). - In the search box at the top, type
texto. - You get a section titled Texto with a dropdown for the theme
setting, described as The Writing editor's own theme. Pick
light,darkorvscode. - Nothing to save. Any open Chapter changes colour immediately.
That dropdown writes to User settings, applying everywhere. To scope it to one Work's folder instead, click the Workspace (Área de trabajo) tab under the search box before choosing the value.
The long way (the file itself). For a folder you're setting up to
commit: open .vscode/settings.json as in section 3, and add the setting
next to what's already there — replacing the file drops the
workbench.editorAssociations block and the Chapter goes back to the code
editor:
{
"workbench.editorAssociations": {
"*.md": "texto.editor"
},
"texto.theme": "dark"
}
The quotes, the colon, the commas between entries and the braces all matter; if you get one wrong VSCode underlines it in red and tells you what it expected.
5.2. Text size (texto.textSize)
The body text's size, in pixels — 14 to 28, 18 by default. Separate from
VSCode's own zoom (Cmd+=/Cmd+-, which resizes the whole window): this
only affects the Writing editor, and the column's measure grows with it, so
characters-per-line stays comfortable at any size.
While writing, from inside the Chapter itself:
| Action | Shortcut |
|---|---|
| Increase | Cmd+= / Ctrl+= |
| Decrease | Cmd+- / Ctrl+- |
| Reset | Cmd+0 / Ctrl+0 |
If your platform's window manager steals Cmd+=/Cmd+- first (it's also
VSCode's own zoom shortcut), use Cmd+Alt+= / Cmd+Alt+- instead — always
active, no configuration needed. Same three actions in the command palette:
Texto: Increase text size, Texto: Decrease text size, Texto: Reset text size.
Permanently, same two ways as the theme — the text size field under
Settings → search texto, or in the JSON file:
{
"texto.textSize": 22
}
5.3. Alignment (texto.alignment)
Left-aligned by default. justified straightens both edges of the column,
like a printed book, with automatic hyphenation so Spanish's longer words
don't open rivers of white space — the two go together, hyphenation isn't
offered on its own.
| Value | What you get |
|---|---|
left |
Left-aligned. The default. |
right |
Right-aligned. |
justified |
Justified, with hyphenation. |
Justified only straightens paragraphs long enough to wrap — the last line stays ragged, as in a printed book. A paragraph broken by hand into several file lines is several paragraphs to the editor, none of them justified; see One paragraph, one line in section 2.
Same two ways as every setting — the alignment dropdown under Settings
→ search texto, or:
{
"texto.alignment": "justified"
}
5.4. Focus mode (texto.focusMode)
Focus mode dims the whole Chapter except the block your cursor is in — paragraph, heading, quote, list item or Scene break. On by default.
Turning it on and off while writing — the way you'll actually use it:
- Press
Cmd+Shift+P/Ctrl+Shift+P. - Type
Texto: Toggle focus mode, pressEnter. Each run flips it.
Worth a keyboard shortcut of its own: Cmd+K then Cmd+S opens Keyboard
Shortcuts (Métodos abreviados de teclado), search Toggle focus mode,
double-click the row and press your keys.
Permanently — same two ways as the theme: the focus mode checkbox
under Settings → search texto, or in the JSON file:
{
"texto.focusMode": false
}
The palette command always writes to User settings, globally: Focus mode is a preference of the Author, not a property of one Chapter.
5.5. The whole file
A complete .vscode/settings.json for a Work, association and all four
settings:
{
"workbench.editorAssociations": {
"*.md": "texto.editor"
},
"texto.theme": "light",
"texto.textSize": 18,
"texto.alignment": "left",
"texto.focusMode": true
}
Commit that file with the text and the Work carries its own configuration. Section 7 extends this same file with the settings that put the rest of VSCode into writing mode.
6. The status bar: word count and the settings toolbar
With a Chapter open, the status bar (the strip along the very bottom) shows
the Chapter's word count. Select text and the selection count joins it —
1204 words (37 selected) — and disappears when you click away. It only
counts prose: a heading's ##, emphasis's *, a Scene break's ---
are not words, so the number matches what Google Docs would show for the
same text.
Right next to it, a row of small buttons — one per setting from section 5,
plus one more. Nothing to open or search: each acts the moment you click it,
showing a $(check) mark, an eye, a book, whichever tells you its current
value at a glance.
| Buttons | What clicking one does |
|---|---|
| Theme Light · Theme Dark · Theme VSCode | Switches the theme (5.1). The active one is marked. |
− · 18px · + |
Text size (5.2): reduce, restore the factory size, increase. |
| Left · Just · Right | Alignment (5.3). The active one is marked. |
| $(eye)/$(eye-closed) Focus mode | Toggles Focus mode (5.4). The icon shows whether it is on. |
| $(book)/$(code) Raw markdown | See below. |
Raw markdown. Shows the Chapter exactly as it is in the file — every #,
*, --- — with Live preview and Focus mode's dimming off, in place, no
tab change. Click again (or run Texto: Raw markdown) to go back; cursor
stays put. Not a setting — nothing is saved, a Chapter always opens
composed. For the raw markdown in a proper code editor instead (to search,
edit as text), use Open as markdown (section 2).
None of this adds anything to the Chapter itself (DEC-002): the writing surface stays exactly as many pixels as the text needs.
7. Turning off VSCode's navigation for a Writing space
The extension can't remove VSCode's own chrome — breadcrumb bar, minimap,
line numbers, vertical ruler — it's VSCode's workbench, configured the
ordinary way. A Writing space carries that configuration in the same
.vscode/settings.json as section 3, so opening the folder puts the whole
window into writing mode:
{
"workbench.editorAssociations": {
"*.md": "texto.editor"
},
"breadcrumbs.enabled": false,
"editor.minimap.enabled": false,
"editor.lineNumbers": "off",
"editor.rulers": [],
"editor.glyphMargin": false,
"texto.theme": "light",
"texto.focusMode": true,
"texto.textSize": 18,
"texto.alignment": "left"
}
A copy of this exact file lives at
examples/espacio-de-escritura/.vscode/settings.json
in this repository — copy the whole .vscode folder into a Work's root
and commit it.
Those five workbench settings (everything except texto.*) are ordinary
VSCode configuration — they work the same with the extension not installed,
which is why there's no button for them in section 6 or a command that
writes this file for you (AD-005): the writing environment is configuration
versioned next to the text, not a feature. They apply to the whole
window, not just Chapters — a package.json or .gitignore in the same
Work shows the same stripped-down chrome. That's the point: the folder
is a writing environment.
8. Upgrading a Writing space built before the English rename
Every texto.* key and value, and the Writing editor's viewType, used to
be Spanish (texto.tema, texto.modoFoco, claro/oscuro,
izquierda/derecha/justificado, texto.editorDeEscritura). The rename
is breaking on purpose, no alias — a Writing space built against the old
names keeps its .vscode/settings.json untouched, silently, until you edit
it by hand. Two symptoms tell you it needs updating:
- A Chapter opens in VSCode's plain markdown editor instead of the Writing
editor.
workbench.editorAssociationsstill points attexto.editorDeEscritura. Fix: replace it withtexto.editor(section 3's snippet). Meanwhile, reach the Writing editor with Open with Texto (section 2). - A Chapter opens in the Writing editor with the factory look, ignoring
the folder's settings. The old keys (
texto.tema,texto.modoFoco,texto.tamanoDeTexto,texto.alineacion) go unrecognised, so it falls back to defaults, quietly. Fix: rename each to its English form (texto.theme,texto.focusMode,texto.textSize,texto.alignment) and its value where it's an enum (claro→light,oscuro→dark,izquierda→left,derecha→right,justificado→justified;vscodeis unchanged). Section 5.5 has the complete file to copy from.
Neither symptom raises an error — the accepted cost of the rename, not a bug to report.
9. If something does not work
Nine times out of ten it's one of the first two:
- Settings greyed out, or
Unknown Configuration Setting. Not installed in this VSCode. Extensions panel → searchTexto→ must be under Installed. Install it (section 1), thenDeveloper: Reload Window. VSCode only honours settings some installed extension declared, and ignores the rest in silence. - The Chapter is a different colour than
texto.themesays. You're looking at VSCode's normal code editor, not the Writing editor. Reopen it with Reopen Editor With… → Texto: Writing editor (section 2), then set up the folder as a Writing space (section 3) so it stays that way. - The
.mdstill opens with symbols showing. The association wasn't picked up: check the file is under the folder VSCode opened, the path is exactly.vscode/settings.json, and the value istexto.editor— if it'stexto.editorDeEscritura, see section 8. - A
texto.*setting stopped the file opening as prose. You replacedsettings.json's contents instead of adding to it, dropping theworkbench.editorAssociationsblock. See 5.5 for the whole file. Texto: Toggle focus modemissing from the palette. Same as the first entry — not installed, or the window predates the install.settings.jsonunderlined in red. A missing or trailing comma; hover the underline for what VSCode expected.- The theme didn't change. Only
light/dark/vscodeare valid; anything else — including the old Spanish values — falls back tolight. Cmd+=/Cmd+-zoom the window instead of resizing the text. Your platform stole the shortcut first. UseCmd+Alt+=/Cmd+Alt+-(always active) or the palette commands.- "Raw markdown" turned off after reopening the Chapter. Intended: it's panel state, not a setting, and a Chapter always opens composed.
- Breadcrumb / minimap / line numbers still there. Either the folder is missing section 7's settings, or the file is outside it — both are workspace-scoped, like the association in section 3.
10. What the Writing editor composes
The Writing editor is for fiction and non-fiction alike (docs/PRODUCT.md,
PD-007). Everything below is markdown syntax, hidden while the cursor is
elsewhere and revealed while it touches the text it marks — the file on disk
always stays exactly what you typed.
Composed:
| Construct | Written as | Reads as |
|---|---|---|
| Heading | ## Title, or Title over ====/---- (setext) |
Sized, weighted title |
| Strong / emphasis | **text** / *text* |
Bold / italic |
| Strikethrough | ~~text~~ |
Struck through |
| Inline code | `code` |
Monospaced, on a discreet ground |
| Escape | \* |
The literal character, backslash hidden |
| Scene break | --- on its own, blank line above |
Centred ⁂ |
| Blockquote | > text |
Indented, with a left rail |
| List (bullet/ordered) | - item / 1. item |
A bullet or number, indented by nesting depth |
| Task / task list | - [ ] item / - [x] item |
A clickable box, empty or ticked |
| Link (inline, reference, autolink, bare URL) | [text](https://github.com/asiermarques/texto/blob/HEAD/url), [text][ref], <url>, a bare https://… |
Underlined text, target hidden (hover or Cmd/Ctrl+click to see/follow it) |
| Image |  |
Its alternative text, marked distinctly from a Link — never the picture itself |
| Code block (fenced or indented) | ```lang…``` or a 4-space indent |
Preformatted, monospaced, never justified |
| Footnote | text[^1] … [^1]: note |
The call as a superscript, the note apart from the prose |
| Reference definition | [ref]: url |
A discreet line, apart from the prose |
Not composed, shown and kept exactly as written:
- Tables. Aligning columns is the one construct that can't be expressed as a decoration over the Author's own characters.
- HTML, inline or block.
- Front matter (a leading
----delimited YAML block). It renders worse now that a bare---composes (see below) —title: …over---reads as a heading. Known, not a bug; there is no supported way to write front matter that looks right in the Writing editor today. - Syntax colouring inside a Code block. One colour, preformatted — this editor quotes code, it doesn't highlight it.
The --- rule. Directly under a line of prose, with no blank line
between them, --- is a setext heading (CommonMark's own reading — the line
above becomes an H2). With a blank line above it, --- is a Scene break.
The same three dashes, two different meanings, decided by nothing more than
whether you pressed Enter twice or once before typing them — every Scene
break already in this project's own history is written the second way, so
nothing here changes on its own.
From the keyboard, once something is selected (or, for the first two, even without a selection):
| Shortcut | Does |
|---|---|
Cmd+B / Ctrl+B |
Wraps/unwraps the selection in ** (strong) |
Cmd+I / Ctrl+I |
Wraps/unwraps the selection in * (emphasis) |
Cmd+K / Ctrl+K |
Wraps the selection as [text](), cursor left on the target |
Cmd+Alt+K / Ctrl+Alt+K |
Same as Cmd+K — use this if your VSCode swallows Cmd+K first as its own shortcut chord (Cmd+K Cmd+S, Cmd+K V, …) |
| Paste a URL over a selection | Turns the selection into a Link with the pasted URL as target; pasting over a selection that already is a Link's text replaces only its target |
Enter inside a list item, a Task or a blockquote |
Continues it — next bullet, next number, an empty (unchecked) Task box, another > — and on an empty item, removes the marker and leaves the block instead |
| Click a Task's box | Toggles [ ] ↔ [x] in the file |
Cmd/Ctrl+click a Link |
Opens its target with VSCode's own link handling — the Writing editor never navigates on its own |
Development
npm install
npm run build # bundles the extension and the webview into dist/
npm run watch # same, in watch mode
npm run typecheck # tsc --noEmit over the whole project
To try it without installing: open this folder and press F5 (Run and
Debug → Run Extension) — a second VSCode window opens with the extension
loaded from source.
Tests
npm run test:unit # vitest — the pure logic in src/domain
npm run test:integration # @vscode/test-electron — a real VSCode, end to end
npm test # both
The first test:integration run downloads a copy of VSCode into
.vscode-test/ (not distributed, only used to run the tests).
TEXTO_TEST_FILTER=<substring> npm run test:integration runs only the
integration files whose name contains <substring> — faster than a full
VSCode boot on every change. Unset, it runs the whole suite, which CI and
any task's closing check always use.
Layout
See Conventions in docs/ARCHITECTURE.md.
License
MIT — see LICENSE.