Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Welcome to Ettin Edit

Edda and Ottar, the two-headed Ettin Edit mascot

Ettin Edit is a fast, friendly text editor for Linux and Windows. It is inspired by Notepad++, shares none of its code, and builds in the tools people usually add to Notepad++ with plugins: JSON and XML tools, a compare view, SQL over CSV files, and more.

This manual explains how to use every part of the editor and how to make it your own. You can read it in two places:

Both show the same text, written for the version of Ettin Edit you have.

Meet the heads

In Norse myth an ettin is a giant, and the famous ones had more than one head. Ours has two. Edda keeps your tabs in order and has never once lost an unsaved file. Ottar compares everything with everything else and keeps asking for one more plugin. You'll see their opinions in the odd tip box.

Where to start

If you want to…Read
Install it, or get the newest versionInstalling and updating
Know what everything on screen isA tour of the window
Open, save and juggle filesFiles and tabs
Edit faster: multiple carets, line tools, completionEditing text
Find and replace, in one file or a whole folderFinding and replacing
Format JSON, check XML, decode Base64Tools
Compare two filesCompare
Query a CSV file with SQLCsvQuery
Change fonts, shortcuts and coloursMaking it yours
Add or write pluginsUsing plugins

Finding your way around this manual

  • The contents are on the left. In the app, the box at the top searches every page; on the web, press S or click the magnifying glass.
  • Menu commands are written like File > Open…: open the File menu, then choose Open….
  • Keyboard shortcuts look like Ctrl+Shift+F. These are the defaults; if you change them in the Shortcut Mapper, the menus show your own.
  • Every command is also in the command palette: press F1 and type a few letters of its name.

Edda says: you don't have to read this front to back. Skim the tour, then come back when you wonder whether Ettin Edit can do something. It probably can.

Installing and updating

Ettin Edit runs on 64-bit Windows and 64-bit Linux (X11 or Wayland). Every release is on the releases page.

Windows

Download one of these:

  • ettin-edit-<version>-setup.exe, the installer. Run it and pick:

    • Install for me only, which needs no administrator rights, or Install for all users.
    • A desktop shortcut (optional).
    • Edit with Ettin Edit in the right-click menu of every file in Explorer.
    • Open with entries for 33 common text and code file types.
    • Adding Ettin Edit to the PATH, so ettin-edit file.txt works in a terminal (optional).

    Ettin Edit then appears in the Start menu. Remove it from Settings > Apps like any other program.

  • The .zip, if you'd rather not install anything. Extract it anywhere and run ettin-edit.exe. Your settings still go to %APPDATA%\EttinEdit (see Files, folders and the command line).

Linux

Your systemDownloadInstall with
Arch, CachyOS, Manjaro, EndeavourOS.pkg.tar.zstsudo pacman -U ./ettin-edit-*.pkg.tar.zst
Debian, Ubuntu, Mint, Pop!_OS.debsudo apt install ./ettin-edit_*_amd64.deb
Anything else.tar.gzExtract it and run ./ettin-edit

The packages add Ettin Edit to your application menu with its icon, and offer it in Open With for text files. Software centres such as GNOME Software, KDE Discover and Ubuntu's App Center show its licence (MIT), website, release notes and age rating.

Getting updates on Debian and Ubuntu

From 1.4.0 the .deb also adds the Ettin Edit package repository, which lives next to this manual on GitHub Pages. After that, your software updater (or sudo apt update && sudo apt upgrade) installs new versions like any other app, and the software centre no longer says "No software repository included". Install the 1.4.0 .deb by hand once if you have an older one.

The repository's settings are in /etc/apt/sources.list.d/ettin-edit.sources. Delete that file to stop getting updates this way.

To add the repository without downloading the .deb first:

sudo curl -fsSLo /usr/share/keyrings/ettin-edit-archive-keyring.gpg \
  https://tharkis.github.io/Ettin-Edit/apt/ettin-edit-archive-keyring.gpg
sudo curl -fsSLo /etc/apt/sources.list.d/ettin-edit.sources \
  https://tharkis.github.io/Ettin-Edit/apt/ettin-edit.sources
sudo apt update && sudo apt install ettin-edit

The .tar.gz needs the usual desktop libraries, which almost every desktop already has: OpenGL and, on X11, libxkbcommon-x11. On Debian or Ubuntu: sudo apt install libxkbcommon-x11-0 libgl1.

Building the Arch package yourself

From a copy of the source code:

cd packaging/arch
makepkg -si

Building from source

Install Rust from https://rustup.rs, then in the source folder:

cargo build --release      # the program is target/release/ettin-edit
cargo run --release -- notes.txt

Updating

On Debian and Ubuntu, the .deb's package repository brings updates through your software updater (see above). Everywhere else, and on Debian and Ubuntu too if you like, Ettin Edit updates itself:

Help > Check for Updates… (also on the toolbar's Home tab) asks GitHub whether there's a newer release. If there is, it shows what changed and an Update Now button. Ettin Edit downloads the file that matches how you installed it, checks it against the SHA-256 checksum GitHub lists for it, and installs it:

Installed withWhat Update Now does
Arch / CachyOS packageInstalls the new .pkg.tar.zst with pacman -U. Your desktop asks for your password first.
Debian / Ubuntu packageInstalls the new .deb with apt-get install. Your desktop asks for your password first.
.tar.gz or Windows .zipReplaces the ettin-edit program in the folder you unpacked it to.
Windows installerDownloads the new setup.exe. Install and Restart closes Ettin Edit, installs the update without any questions and starts Ettin Edit again. Installed for everyone, Windows asks for permission first.

When it's done, Restart Now closes Ettin Edit and starts the new version. It closes the way File > Exit does, so you're asked about unsaved changes (or they're kept, if Preferences remembers them), and your open files come back. Later keeps working with the old version until you next start Ettin Edit (with the Windows installer, it installs the update when you close Ettin Edit). Your settings, themes and plugins are kept.

The password prompt comes from pkexec. Without it, Ettin Edit shows the command to run in a terminal instead, with a Copy button. A copy built from source, or one in a folder you can't write to, can't update itself; the dialog says so and offers the download page. If the download doesn't match its checksum it isn't installed.

Downloads wait in ~/.cache/ettin-edit/updates on Linux (%LOCALAPPDATA%\ettin-edit\updates on Windows) and are removed by the next update.

Ettin Edit also checks by itself once a week and only speaks up when there's something new. Turn that off with Help > Check for Updates Automatically, or in Preferences under Files and Startup. The check sends nothing about you or your files; it only reads the public list of releases.

Coming from NixPad

Ettin Edit used to be called NixPad. The first time Ettin Edit starts, it copies your NixPad settings, session, backups, themes and plugins to its own folder, and plugins written for NixPad keep working. The old folder is left alone, so you can delete it when you're happy.

A tour of the window

Ettin Edit draws its whole window itself, so it looks the same on Linux and Windows and follows the colours of the theme you pick.

Ettin Edit with a JSON file open and the JSON tree panel beside it

From top to bottom:

The menu bar

You can hide the menu bar to give the window a cleaner look: choose View > Menu Bar or press Ctrl+M. While it's hidden, tap Alt on its own to show it for a moment; it goes away again when you run a command, press Escape or Alt, or click elsewhere. Press Ctrl+M (or use View > Menu Bar from the shown menu, or right-click the toolbar) to keep it showing again. The toolbar can be hidden too, and Ettin Edit remembers both choices.

MenuWhat's in it
FileNew, open, save, recent files, print, rename, workspace folders, close
EditUndo, clipboard, line operations, case, comments, multi-select, completion, column editor, read-only
SearchFind, replace, Find in Files, marks, Go to Line, bookmarks
ViewWord wrap, symbols, panels, split view, folding, zoom, distraction-free mode, the menu bar and toolbar
EncodingThe encoding the file is saved in, or read it again in another one
ThemePick a theme, edit its colours, open the themes folder
LanguagePick the highlighting language, add your own languages
SettingsPreferences, the Shortcut Mapper, Customise Toolbar and quick on/off switches
ToolsCompare, CsvQuery, MIME Tools, JSON and JavaScript, XML Tools
PluginsYour plugins' commands, and managing plugins
MacroRecord, play back and save macros
HelpThis manual, update checks and About

Under the menu bar is the toolbar: tabs of buttons for the commands you use most. Right-click it to customise it, or press Ctrl+F1 to collapse it to its tab names.

Help > About Ettin Edit shows the version you have.

Right-clicking the text gives you the whole Edit menu, the Tools menu and your plugins' commands, so you rarely need to go up to the menu bar.

Tabs

Each open file has a tab. A dot on a tab means it has unsaved changes, and a pin means it's pinned. At the end of the tab bar:

  • + opens a new, empty tab (Ctrl+N).
  • ⏷ opens the tab list, handy when there are more tabs than fit.

Right-click a tab for close, pin, split-view and file commands. Hover over it to see the file's full path.

When the window is split in two, each half has its own tab bar.

The find bar

Ctrl+F or Ctrl+H opens the find bar above the text. See Finding and replacing.

The editor

The text itself, with the gutter on its left:

  • line numbers,
  • bookmarks (click the gutter next to a line, or press Ctrl+F2),
  • fold markers: − folds a block away and + shows it again.

The editor highlights the current line, the bracket matching the one at the caret, and other places where the selected word appears. Everything it shows can be turned on and off in the View menu.

Panels

Panels open beside the text and stay until you close them:

PanelWhereOpens with
Folder as WorkspaceleftFile > Open Folder as Workspace…
Function ListrightView > Function List
Document MaprightView > Document Map
JSON treerightCtrl+Alt+J
Search resultsbottomFind All or Find in Files
XPathbottomCtrl+Alt+Shift+E
CsvQuerybottomCtrl+Alt+Q
Plugin panelsright or bottomthe plugin's own command

Drag the edge of a panel to resize it.

The status bar

On the left:

  • The language, such as Rust or Plain Text. Click it to choose another.
  • length (characters) and lines in the document.
  • In XML files, the XPath of the element at the caret. Click it to copy it.
  • ● Recording macro while a macro is being recorded.
  • Read-only when the tab is read-only. Click it to allow editing again.

On the right:

  • Ln and Col, the caret's line and column, followed by Sel (how many characters are selected) and how many carets there are, when that applies. Click it to go to a line.
  • The line ending: Windows (CR LF), Unix (LF) or Macintosh (CR). Click it to change the document's line endings.
  • The encoding, such as UTF-8. Click it for the Encoding menu.
  • The zoom level.

The command palette

Press F1 anywhere. Type a few letters of any command, for example dup for Edit › Line Operations › Duplicate, then press Enter. Words can be in any order and needn't be complete, and each command shows its shortcut, so the palette is also a good way to learn them.

Files and tabs

Opening files

  • File > Open… (Ctrl+O) opens one or more files; select several in the dialog to open them all.
  • File > Open Recent lists the last 12 files you had open. Clear Recent Files at the bottom empties the list.
  • Drag files from your file manager onto the window.
  • Pass them on the command line: ettin-edit notes.txt todo.md (see the command line).
  • On Windows, right-click a file and choose Edit with Ettin Edit, if you turned that on when installing.
  • In the folder workspace, click a file.

A file opened while the only tab is an untouched new one replaces that tab, so you don't collect empty tabs.

Ettin Edit works out each file's encoding and line endings and its language as it opens it, and keeps them when you save. Very large files are fine: a 50 MB log opens in about a second, and word wrap keeps up when you resize the window.

One window or several

By default there is one Ettin Edit window. Opening a file from your file manager or a terminal while Ettin Edit is running sends it to the open window instead of starting a second copy. To get separate windows, turn off Settings > Single Window, or start Ettin Edit with --multi-instance.

New files

File > New (Ctrl+N) or the + at the end of the tabs opens an empty tab named new 1, new 2 and so on. Its line ending, encoding and language come from Preferences > New Documents.

Saving

CommandShortcutWhat it does
File > SaveCtrl+SSaves the current tab. A new tab asks for a name.
File > Save As…Ctrl+Alt+SSaves under a new name; the tab then shows that file.
File > Save AllCtrl+Shift+SSaves every tab with changes.

The file keeps its encoding, line endings and byte-order mark. If the text holds a character the file's encoding can't store, Ettin Edit refuses to save and tells you which character it is, rather than quietly losing it. Pick another encoding from the Encoding menu and save again.

XML files can be checked for mistakes every time they're saved; see XML Tools.

Tabs

  • Click a tab to switch to it, or use Ctrl+Tab / Ctrl+Shift+Tab (also Ctrl+PageDown / Ctrl+PageUp) for the next and previous tab.
  • Drag a tab to move it along the tab bar.
  • Close a tab with its ×, a middle-click, or Ctrl+W. File > Close All (Ctrl+Shift+W) and File > Close Others close the rest.
  • Pin Tab (right-click a tab) keeps a tab at the front with a pin on it. Close All and Close Others leave pinned tabs open, and the × on a pinned tab unpins it instead of closing it.
  • Closing a tab with unsaved changes asks whether to save them.

The tab's right-click menu

CommandWhat it does
Close, Close OthersClose this tab, or every other one
Pin Tab / Unpin TabSee above
Move to Other View, Clone to Other ViewSee split view
Reload from DiskRead the file again, replacing what's in the tab (Undo brings your version back)
Rename…Rename the file on disk; the tab follows it
Move to Trash…Move the file to the Recycle Bin or trash and close the tab
Open Containing FolderShow the file in your file manager, selected where possible
Open Terminal HereOpen a terminal in the file's folder
Copy Full Path, Copy File NameCopy them to the clipboard

The file commands are also in the File menu, for the current tab. Open Terminal Here uses Windows Terminal or cmd on Windows; on Linux it tries $TERMINAL, then common terminals such as Konsole and GNOME Terminal.

You won't lose your work

Ettin Edit backs up unsaved changes every few seconds, including tabs that were never saved. If Ettin Edit, your computer or the power goes away, your tabs and their changes are back next time you start it.

When you quit, Ettin Edit remembers the open tabs, unsaved changes included, without asking, and reopens everything next time: each tab's caret, encoding, line ending, language, pin, read-only state and the split view. If you'd rather be asked to save each file when quitting, turn off Settings > Remember Unsaved Changes on Exit. To start with no tabs from last time, turn off Reopen the files that were open last time in Preferences.

When another program changes the file

If a file you have open is changed by another program, a bar appears above the text:

  • Reload reads the new version. If you had unsaved changes, Undo brings them back.
  • Keep My Version leaves your text alone; saving will overwrite the other program's changes.

If the file is deleted or moved, the bar offers Keep Open, which keeps the text in the tab so you can save it again, or Close.

To reload changed files without being asked, turn on Settings > Reload Files Changed on Disk Automatically. It only reloads files that have no unsaved changes in Ettin Edit.

Read-only tabs

Edit > Read-Only stops a tab from being changed by accident. The status bar shows Read-only; click it, or choose the command again, to allow editing.

Summary

View > Summary… shows the file's full path, when it was created and changed, its encoding, and how many characters, words and lines it has, plus its size on disk and the same counts for the selection.

Editing text

The basics

Ettin Edit edits text the way you'd expect, plus a few extras:

KeysWhat they do
Ctrl+Z / Ctrl+YUndo and redo. Typing is undone a burst at a time, and the tab knows when you're back at the saved version.
Ctrl+X / Ctrl+C / Ctrl+VCut, copy and paste
Ctrl+ASelect everything
HomeGo to the first non-blank character of the line; press again for the very start
Ctrl+Left / Ctrl+RightMove a word at a time
Ctrl+Backspace / Ctrl+DeleteDelete a word at a time
Tab / Shift+Tab on selected linesIndent or outdent them
Double-click / triple-clickSelect a word / a line. Keep the button down and drag to select by words or lines.

Enter keeps the current line's indentation. Whether Tab inserts a tab or spaces, and how wide a tab is, are set in Preferences or Settings > Indent With Spaces.

Multiple carets

Several carets let you make the same change in several places at once. Everything you type, delete or paste happens at each of them.

ToDo this
Add a caretCtrl+click or Alt+click
Add a selectionCtrl+drag
Add a caret on the line above or belowCtrl+Alt+Up / Ctrl+Alt+Down
Select the next place the selected text appearsCtrl+Shift+D (Edit > Multi-Select > Select Next Occurrence)
Select every place it appearsAlt+F3 (Select All Occurrences)
Put a caret on every search matchSearch > Select All Matches
Go back to one caretEsc

Pasting several lines onto the same number of carets puts one line at each caret, which is handy for filling in a column.

The status bar shows how many carets there are.

Column (box) selection

Hold Alt and drag, or use Alt+Shift with the arrow keys, to select a rectangle. Typing then replaces or inserts on every row, and Backspace and Delete work on every row too.

Column Mode

Edit > Column Mode (Alt+Shift+C) saves holding Alt: while it's on, a plain drag and Shift with the arrow keys select a rectangle, and the status bar says Column mode. A plain click still puts one caret where you click, and Shift+click still extends a normal selection. Click Column mode in the status bar, or use the command again, to turn it off. It's off each time Ettin Edit starts.

Column Editor

Edit > Column Editor… (Alt+C) inserts the same thing at every caret, or at the caret's column on each line below it:

  • Text to insert: the same text on every line.
  • Numbers to insert: a sequence, with an Initial number, how much to Increase by, how many times to Repeat each number, Leading zeros, and Dec, Hex, Oct or Bin.

For example, start 1, increase by 1, on ten lines gives 1 to 10; with leading zeros it gives 01 to 10.

Line operations

Edit > Line Operations. The commands in this table work on the lines the selection touches, or on the caret's line:

CommandShortcut
DuplicateCtrl+D
Delete LinesCtrl+Shift+L
Move Up / Move DownCtrl+Shift+Up / Ctrl+Shift+Down
Join LinesCtrl+J
Split Lines at Long-Line ColumnCtrl+I
Insert Blank Line Above / BelowCtrl+Alt+Enter / Ctrl+Alt+Shift+Enter

Sorting, reversing and removing lines work on the selected lines, or on the whole document when nothing is selected. Everything is one undo step.

Sorting, ascending or descending:

  • Lexicographically: in character order, so B comes before a.
  • Ignoring Case: a and A together.
  • As Integers and As Decimals: by the number at the start of each line, so 9 comes before 10. Lines without a number go first.
  • By Length: shortest first.
  • Reverse Line Order flips the lines without sorting.

Removing lines:

  • Remove Duplicate Lines keeps the first copy of each line.
  • Remove Consecutive Duplicate Lines only removes repeats that follow each other, like the Unix uniq.
  • Remove Empty Lines removes lines with nothing on them; Including Blank Ones also removes lines that only hold spaces or tabs.

Spaces and tabs

Edit > Blank Operations work on the selected lines, or the whole document:

  • Trim Trailing Space, Trim Leading Space, or both.
  • EOL to Space joins the lines with a space between them.
  • Tabs to Spaces, Leading Spaces to Tabs and All Spaces to Tabs, using the tab width from Preferences.

Case

Edit > Convert Case To:

CommandShortcutExample
UPPERCASECtrl+Shift+UHELLO WORLD
lowercaseCtrl+Uhello world
Title CaseAlt+UHello World
Sentence caseCtrl+Alt+UHello world
iNVERT cASECtrl+Alt+Shift+UhELLO wORLD

Comments

Edit > Comment > Toggle Line Comment (Ctrl+Q) comments out the selected lines, or uncomments them if they're all comments. Toggle Block Comment (Ctrl+Shift+Q) wraps the selection in a block comment. Ettin Edit uses the right markers for the tab's language: // and /* */ in Rust, # in Python, <!-- --> in HTML, and so on.

Date and time

Edit > Insert > Date and Time puts the current date and time at the caret, short (F5) or long (Shift+F5).

Typing helpers

Each of these can be turned off in the Settings menu or in Preferences.

  • Auto-Close Brackets and Quotes: typing (, [, {, " or ' adds the closing one. Typing the closer steps over it, Backspace removes an empty pair, and typing an opener with text selected wraps the selection.
  • Close Tags Automatically (XML and HTML, in Tools > XML Tools): typing > after <p adds </p>. Empty HTML elements such as <br> are left alone.
  • Smart Indentation: Enter after {, ( or [ (and after : in Python and YAML) indents the new line, and between {} it puts the closing bracket on a line of its own. Typing a closing bracket outdents.
  • Word Completion: as you type, a list offers words already in the document. Ctrl+Space opens it at any time.
  • Keyword and Function Completion: the list also offers the language's keywords and functions, each with its signature.
  • Parameter Hints: typing ( after a function's name shows its parameters above the caret, with the one you're on in bold. It follows you from argument to argument; Esc hides it and Ctrl+Shift+Space brings it back.

In the completion list, use the arrow keys and Enter or Tab to pick a word, or Esc to close it.

Completion knows Python, JavaScript and TypeScript, Rust, C, C++, C#, Java, Go, PHP, Lua, Ruby, Kotlin, Swift, SQL, PowerShell, CSS, HTML and shell scripts, plus the functions your document defines. You can add your own lists; see Languages.

Matching brackets and tags

Putting the caret next to a bracket highlights its partner; an unmatched bracket turns red. In HTML and XML the matching opening or closing tag is highlighted too. Other places where the selected word appears are lightly highlighted, which makes typos easy to spot.

Finding and replacing

The find bar

Search > Find… (Ctrl+F) opens the find bar above the text. If you had text selected, it's already filled in. Ettin Edit searches as you type, highlights every match, and shows 3 of 17 so you know where you are.

In the find barWhat it does
Enter / Shift+EnterNext / previous match
↓ / ↑Next / previous match (also F3 / Shift+F3 from anywhere)
AaMatch case
WWhole words only
\nExtended: \n, \t, \xNN and the like mean those characters
.*Regular expression
…More: Wrap around, Find All, Select All Matches, Mark All
Esc or ×Close the find bar

With Wrap around on (the default), searching past the last match starts again at the top.

Find Selected Next (Ctrl+F3) and Find Selected Previous (Ctrl+Shift+F3) search for the selected text, or the word at the caret, without opening the find bar.

Replacing

Search > Replace… (Ctrl+H), or the ⏵ arrow at the left of the find bar, adds a second row:

  • Replace replaces the current match and moves to the next. Pressing Enter in the replace box does the same.
  • Replace All replaces every match as one undo step. It stays fast on big files: 282,000 replacements in a 50 MB file take about a second.
  • In selection limits Replace All to the selected text. It's turned on for you when you open the bar with several lines selected.

Leave the replace box empty to delete what you searched for: Replace All with an empty box removes every match. This works in all three modes, so Extended \r\n or the regular expression \r\n with an empty replacement joins every line into one.

Line breaks

Ettin Edit keeps every line break as one character while you edit, and writes the tab's own line ending (shown in the status bar) when it saves. So in Extended mode and in regular expressions, \r\n, \r and \n all find a line break, whether the file uses Windows (CR LF), Unix (LF) or old Mac (CR) line endings. A match on a line break is highlighted just past the end of its line.

In a regular expression, an optional \r (as in \r?\n) finds nothing on its own, so \r?\n still finds exactly one line break. To change the line endings a file is saved with, click the line ending in the status bar (see Line endings).

Extended mode (\n, \t, \xNN)

Turn on \n to search for characters you can't type in the find box, without writing a regular expression. Everything else in the box is plain text, so . and * still mean themselves. Extended mode and regular expressions are two ways of reading the box, so turning one on turns the other off. The same escapes work in the replacement.

WriteTo mean
\nA line break
\rA line break too: Ettin Edit keeps every line break as one character and writes the tab's own line ending when it saves, so \r\n, \r and \n all mean a line break
\tA tab
\0The NUL character
\\A backslash
\xNNThe character with hex code NN, such as \x41 for A
\uNNNN or \u{N…}Any Unicode character, such as \u00E9 for é or \u{1F600} for 😀
\dNNNThe character with decimal code NNN (up to 255), such as \d065
\oNNNThe character with octal code NNN (up to 377), such as \o101
\bNNNNNNNNThe character with binary code NNNNNNNN, such as \b01000001

A backslash followed by anything else is searched for as it is.

For example, find ,\t and replace with ;\n to turn every comma followed by a tab into a semicolon and a new line. Find in Files has an Extended box that works the same way.

Regular expressions

Turn on .* to search with a regular expression. Ettin Edit uses the syntax of the Rust regex library, which is close to Perl's and Python's, except that look-around ((?=…), (?<=…)) and back-references inside the pattern aren't supported.

PatternMatches
\d+One or more digits
^\s+$A line holding only spaces or tabs (^ and $ are line starts and ends)
colou?rcolor or colour
(\w+)@(\w+)\.comAn address such as ann@example.com, with two groups
(?<year>\d{4})-(?<month>\d\d)A date, with named groups
(?s)begin.*?endbegin to the nearest end, across lines

In the replacement:

WriteTo insert
$1 or \1The first group ($2, \2 and so on for the others)
${name}A named group
$0The whole match
\n, \tA line break, a tab (\r and \r\n are a line break too)
$$A dollar sign
\\A backslash

For example, find (\w+), (\w+) and replace with $2 $1 to turn Lovelace, Ada into Ada Lovelace.

Finding everything at once

These are in the Search menu and the find bar's … menu:

  • Find All in Current Document lists every matching line in the results panel at the bottom.
  • Find All in Open Tabs does the same for every tab.
  • Select All Matches puts a caret on every match, so you can edit them all at once (see multiple carets).
  • Mark All highlights every match in a different colour that stays after you close the find bar. Mark All and Bookmark Lines also bookmarks each line with a match. Clear All Marks removes the highlights.

Find in Files

Search > Find in Files… (Ctrl+Shift+F) searches every file in a folder:

  • Find what: the text or regular expression, with the same Match case, Whole word and Regular expression options as the find bar.
  • Folder: where to look. Browse… picks one.
  • Files: which files, as patterns separated by spaces or semicolons, such as *.rs *.toml. Start a pattern with ! to leave those files out, for example *.js !*.min.js. Leave it empty for every file.
  • Include subfolders and Include hidden files and folders.

The search runs in the background, so you can keep working; Stop ends it early. Binary files are skipped.

You can also start Find in Files from the folder workspace: right-click a folder and choose Find in Files Here….

The results panel

Find All and Find in Files show their results in a panel below the text, grouped by file, with the matching words highlighted.

  • Click a line to jump to it; the file opens if it isn't open yet.
  • Click a file's heading to fold its results away; Collapse All and Expand All do every file.
  • × closes the panel.

Go to Line

Search > Go to Line… (Ctrl+G), or a click on Ln, Col in the status bar, asks for a line number. Type 120 to go to line 120, or 120:15 for line 120, column 15.

Bookmarks

Bookmarks mark lines you want to come back to. A bookmarked line shows a marker in the gutter.

Command (Search > Bookmark)Shortcut
Toggle Bookmark (or click the gutter)Ctrl+F2
Next BookmarkF2
Previous BookmarkShift+F2
Clear All Bookmarks

The same submenu works on the bookmarked lines as a group: Cut, Copy or Remove Bookmarked Lines, Remove Unbookmarked Lines (keep only the bookmarked ones), and Inverse Bookmarks.

Together with Mark All and Bookmark Lines, that gives a quick way to pull out every line that matches something: mark them, then Copy Bookmarked Lines and paste them into a new tab.

Views, panels and navigation

Everything in this chapter is in the View menu unless it says otherwise.

What the editor shows

CommandShortcutWhat it does
Word WrapAlt+ZWrap long lines at the window's edge instead of scrolling sideways. Line numbers stay with their lines, and the top line stays in place when you resize the window, even in very large files.
Line NumbersThe numbers in the gutter
Highlight Current LineA band behind the caret's line
Show Symbol > Show WhitespaceA dot for each space and an arrow across each tab
Show Symbol > Show End of LineLF, CRLF or CR at each line end
Show Symbol > Show Invisible CharactersA small label for each character you otherwise couldn't see (see below)
Show Symbol > Show All CharactersWhitespace, line ends and invisible characters together; choose it again to hide them all
Show Symbol > Indent GuidesFaint lines at each indentation level
Long-Line MarkerA vertical line at a column, 80 unless you change it

Show Invisible Characters labels characters that look like nothing, or like an ordinary space, so they can't hide in your text:

LabelCharacter
NUL, SOH … US, DEL, C1Control characters, such as ESC (character 27)
NBSP, NNBSPNo-break space and narrow no-break space
SP, MMSP, IDSPOther spaces (en, em, thin, hair and so on, medium mathematical, ideographic)
ZWSP, ZWNJ, ZWJ, WJZero-width space, non-joiner, joiner and word joiner
SHYSoft hyphen
LRM, RLM, ALM, LRE, RLE, PDF, LRO, RLO, LRI, RLI, FSI, PDIText direction marks and controls
BOMA byte-order mark (zero-width no-break space) inside the text
LS, PSUnicode line and paragraph separators
VS, CGJ, TAG, INV, HF, MVS, IAC, DEPRVariation selectors and other invisible formatting characters

Without it, control characters still show as small symbols, but the other characters in the table look like a space or like nothing at all.

Change the long-line column at the bottom of the Settings menu or in Preferences. Edit > Line Operations > Split Lines at Long-Line Column (Ctrl+I) rewraps text to that width.

Zoom

Zoom In (Ctrl+= or Ctrl++), Zoom Out (Ctrl+-) and Reset Zoom (Ctrl+0) change the size of the text. The status bar shows the zoom level. To change the size Reset Zoom returns to, set the font size in Preferences.

Code folding

Folding hides a block of code, such as a function or an if, behind its first line. Blocks follow the language's grammar: brackets, HTML and XML tags, keyword blocks such as if … end, Markdown headings, comment blocks and #region markers. Python, YAML and plain text fold by indentation. The full list is in Languages.

  • Click − in the gutter to fold a block and + to unfold it. A line in the gutter shows where each block starts and ends.
  • The block's closing line stays visible, so } else { folds each half.
Command (View > Folding)Shortcut
Fold AllAlt+0
Unfold AllAlt+Shift+0
Fold Current Level (the block the caret is in)Ctrl+Alt+F
Unfold Current LevelCtrl+Alt+Shift+F
Fold Level 1 to 5 (every block at that depth)Alt+1 … Alt+5

Split view

Split view shows two tabs side by side, or one tab twice.

  • Move to Other View moves the current tab to the other side, splitting the window if it isn't split yet.
  • Clone to Other View shows the same document on both sides. Each side has its own caret and scroll position, and an edit on one side appears on the other at once. Closing one copy leaves the other open.
  • Each side has its own tab bar and current tab. Click a side, or press F8 (Focus Other View), to work in it.
  • Drag the divider to change the sizes.
  • When one side has no tabs left, the split ends.

Both commands are also on the tab's right-click menu. The split is saved with the session. Compare uses the two views too: with the window split, Ctrl+Alt+D compares the two tabs you see.

Function List

View > Function List opens a panel on the right listing the functions, classes, methods and other parts of the document, nested the way they are in the code. It understands about 40 languages, including Markdown headings, INI sections and the keys of JSON and YAML files.

  • Click an entry to jump to it.
  • Type in Filter to find one by name.
  • Show where the caret is keeps the entry you're in selected as you move around.

Character Panel

View > Character Panel opens a table of characters on the right, with each one's decimal and hex code, HTML entity and Unicode name, like Notepad++'s ASCII Codes Insertion Panel.

  • Pick a block in the list: ASCII, Latin-1 Supplement, Greek and Coptic, Arrows, Box Drawing, Currency Symbols and others.
  • Or search: type a character (é), a code (U+00E9, 0xE9, 233, &eacute;) or words of its name (e acute, rightwards arrow, smiling face). The search covers every character up to the emoji.
  • Double-click a row to insert the character at the caret, or at every caret. The second list chooses what is inserted: the character, the HTML entity (&eacute;), the code (U+00E9) or the decimal code (233).
  • Right-click a row to copy the character, its HTML entity or its code.

Hex View

View > Hex View (Ctrl+Alt+Shift+H) shows the current tab as the bytes it's saved as, in its encoding and with its line endings: the offset of each row on the left, sixteen bytes in hex in the middle, and the same bytes as text on the right, where anything that isn't a printable ASCII character is a dot. Choose it again to go back to the text. Each tab remembers whether it's in hex until you close it.

The bar at the bottom shows the offset of the byte at the cursor (in hex and decimal), its value in hex, decimal and binary, how many bytes are selected, and the size of the file.

KeysWhat they do
Arrows, PageUp, PageDownMove the cursor; with Shift, select bytes
Home / EndStart or end of the row; with Ctrl, of the file
0–9, A–FType a byte in hex: the first digit waits for the second, then the byte under the cursor is replaced
TabSwitch between the hex and text columns. In the text column, typing a character replaces the bytes under the cursor with that character's bytes
Delete / BackspaceRemove the selected bytes, or the byte at or before the cursor
InsertInsert a 00 byte at the cursor, to type over
Ctrl+CCopy the selected bytes as hex, such as 48 65 6C
Ctrl+VPaste hex digits over the bytes at the cursor (or over the selection)
Ctrl+Z / Ctrl+YUndo and redo, shared with the text

Every change goes into the tab's text, so Undo works across both views and Save writes the bytes you see.

Changing any byte

You can type any byte anywhere, even one that leaves the text invalid in the tab's encoding. For example, in a UTF-8 file, typing over the first byte of é (C3 A9) leaves half a character, and a lone 0D in a file whose line endings are CR LF would be saved differently. When that happens, the tab is edited as bytes: the bar says so, and Save writes exactly the bytes shown. Undo the change, or finish it (type the second byte of a new character, say), and the tab goes back to being text as soon as its bytes are valid again.

While a tab is edited as bytes it stays in Hex View. Choosing View > Hex View again shows it as text if its bytes read as text in its encoding (or in one Ettin Edit can work out from them); otherwise the bar says why it stays. Encoding > Reopen With reads the file as text in the encoding you pick, whatever its bytes (see Encodings).

Binary and very large files

Files that look like binary data rather than text (images, programs, archives: anything with a 00 byte near the start that isn't UTF-16) open straight into Hex View, edited as bytes, without being read as text first. Files up to 64 MB are read into memory; bigger ones are read from disk as you scroll, so even a file of several gigabytes opens at once and changing a byte in it is instant.

Saving writes to a new file next to the old one and then puts it in place, so the file is never half written. For files over 64 MB, Undo starts again after saving. Unsaved changes to files up to 64 MB come back next time like any other tab's; for bigger files, Ettin Edit asks whether to save them when you quit. Copy copies at most 16 MB.

Document Map

View > Document Map shows the whole document in miniature on the right, with the part on screen marked. Click or drag in it to scroll. It's a quick way to find your place in a long file.

Folder as Workspace

File > Open Folder as Workspace… opens a folder as a tree on the left, for working on a project. View > Folder as Workspace shows or hides the panel, and File > Close Workspace closes the folder.

  • Click a file to open it. The tree follows the current tab, and notices files being added or removed by itself.
  • The panel's buttons collapse every folder, read the folder again, and Show hidden files.
  • Right-click an entry for Open, Copy Path, Find in Files Here… and Open Terminal Here.

The workspace is remembered next time you start Ettin Edit.

Distraction-free mode

View > Distraction-Free Mode (F11) goes full screen and hides the menus, tabs, panels and status bar, leaving the text in a centred column. Press F11 again to come back. Shortcuts and the command palette (F1) still work.

Tab list

View > Tab List…, or the ⏷ button at the end of the tab bar, lists every open tab. Type part of a file or folder name to narrow the list, then press Enter or click a tab to switch to it.

Command palette

View > Command Palette… (F1) lists every command in every menu, your saved macros and your plugins' commands, each with its shortcut. Type a few letters of any words in its name, in any order, then press Enter.

Encodings and line endings

A text file is just bytes; its encoding says which bytes mean which characters. Today almost everything is UTF-8, but older files, and files from some Windows programs, use other encodings. Ettin Edit reads and writes all the common ones.

How Ettin Edit picks an encoding

When a file opens, Ettin Edit looks for, in order:

  1. a byte-order mark (BOM) at the start, which names UTF-8 or UTF-16 for certain;
  2. text that is valid UTF-8;
  3. UTF-16 without a BOM;
  4. failing those, the most likely legacy encoding, such as Windows-1252, Windows-1251 or Shift_JIS.

The encoding is shown on the status bar, and the file is saved in the same one, with or without a BOM just as it was. If some bytes don't make sense in the encoding it chose, Ettin Edit says so and shows them as �. Saving would replace them with �, so if the text looks wrong, use Reopen With (below) first.

Binary files (with a 00 byte near the start that isn't UTF-16) aren't read as text at all: they open in Hex View.

The Encoding menu

Open it from the menu bar or by clicking the encoding on the status bar.

Save as (the top of the menu) changes the encoding the tab will be saved in. The text you see doesn't change; the next save writes it in the new encoding. The choices are:

  • UTF-8, UTF-8 with BOM, UTF-16 LE and UTF-16 BE;
  • about 35 older encodings, grouped by region: Western European (Windows-1252, ISO-8859-1, ISO-8859-15, Mac Roman…), Central European, Cyrillic (including KOI8-R and KOI8-U), Greek, Turkish, Baltic, Nordic, Hebrew, Arabic, Vietnamese, Thai, Romanian, Chinese (GBK, GB18030, Big5), Japanese (Shift_JIS, EUC-JP, ISO-2022-JP) and Korean (EUC-KR).

If the text contains a character the new encoding can't hold, such as € in ISO-8859-1, saving stops and tells you which character and where. Nothing is lost.

Reopen With reads the file from disk again in the encoding you pick. Use it when Ettin Edit guessed wrong and the text looks garbled, for example é where there should be é. It's only available for saved files, and you can undo it.

New tabs use the encoding set in Preferences > New Documents, UTF-8 unless you change it.

Line endings

Lines end with LF on Linux and macOS, and CR LF on Windows; very old Mac files use CR. Ettin Edit detects the ending a file uses and keeps it when saving, so editing a Windows file on Linux doesn't change every line.

Click the line ending on the status bar, Unix (LF), Windows (CR LF) or Macintosh (CR), to convert the whole document to another. View > Show Symbol > Show End of Line shows each line's ending.

New tabs use the line ending set in Preferences > New Documents: your system's usual one unless you change it.

Chinese, Japanese and Korean text

Ettin Edit's own fonts don't include Chinese, Japanese or Korean characters, so it uses a CJK font installed on your system for them, such as Noto Sans CJK on Linux or Microsoft YaHei on Windows. If those characters show as boxes, install a CJK font.

Macros

A macro records what you do in the editor and plays it back, so a repetitive edit only has to be done once.

Recording and playing back

  1. Put the caret where the first edit starts.
  2. Choose Macro > Start Recording (Ctrl+Shift+R). The status bar shows ● Recording macro.
  3. Make the edit: type, move with the keyboard, use the clipboard, and use commands such as Find Next, line operations or case conversion.
  4. Choose Macro > Stop Recording (Ctrl+Shift+R again).
  5. Choose Macro > Playback (Ctrl+Shift+P) to do it all again from wherever the caret is.

The trick is to finish the recording where the next run should start, for example at the beginning of the next line. Use keys rather than the mouse while recording; mouse clicks aren't recorded.

Example: to wrap every line of a list in quotes and add a comma, put the caret at the start of the first line and start recording. Type ", press End, type ",, then press Down and Home. Stop recording. Now each playback does the next line, and Run a Macro Multiple Times does the rest.

Running a macro many times

Macro > Run a Macro Multiple Times… plays the current macro a number of times you choose, or with Run until the end of the file until the caret reaches the last line.

Saving macros

The current macro is forgotten when you record a new one or quit. To keep it, choose Macro > Save Current Macro… and give it a name. Saved macros:

  • appear at the bottom of the Macro menu, ready to play,
  • are in the command palette,
  • can have a keyboard shortcut of their own: find the macro in the Shortcut Mapper and click Set…,
  • are kept between sessions.

Macro > Delete Saved Macro removes one.

Printing and exporting

Printing

File > Print… (Ctrl+P) opens the document in your web browser's print preview, where you choose the printer, page size, margins and which pages to print. Using the browser means printing works the same on every system and you get a proper preview.

The printout keeps the syntax colours, darkened so they read well on white paper. If you use a dark theme, the colours of Ettin Light are used instead, so you don't print a page of black ink. Line numbers are printed in the margin.

Both can be turned off in Preferences, under Files and Startup > Printing: Print line numbers and Print syntax colours.

To save a PDF, choose Save as PDF (or Microsoft Print to PDF) as the printer in the browser's print dialog.

Export as HTML

File > Export as HTML… saves the document as a web page with the current theme's colours and font, ready to put on a website or attach to an email. Line numbers are included when they're turned on in the View menu.

JSON and JavaScript

Tools > JSON and JavaScript covers what the JSTool plugin does for Notepad++, built in.

Like every text tool, these work on the selection, or on each selection when there are several, or on the whole document when nothing is selected. Each use is one undo step. When a tool finds a mistake, a notice at the bottom of the window gives the line and column, the caret moves there, and Go to takes you back to it later.

Format and minify

CommandShortcutWhat it does
FormatCtrl+Alt+MIndents JSON or JavaScript neatly, one item per line
MinifyCtrl+Alt+NRemoves all the spaces and line breaks that aren't needed

Formatting indents with a tab or with spaces, as set for the editor in Preferences.

Both commands try strict JSON first. If the text isn't JSON (it has comments, single quotes, trailing commas or code), they treat it as JavaScript and say so in the notice. The JavaScript formatter understands modern syntax: template strings, regular expression literals, arrow functions, classes, switch and case, and comments, which it keeps.

Checking and sorting

  • Validate JSON checks that the text is valid JSON and points at the first mistake if it isn't.
  • Sort JSON Keys puts the keys of every object in alphabetical order, all the way down, and formats the result.

The JSON tree

JSON Tree (Ctrl+Alt+J) opens a panel on the right showing the current document as a tree of objects, arrays and values.

  • The tree updates as you type and opens at the caret's position.
  • Click a node to jump to it in the text.
  • Type in Filter keys and values to show only the nodes whose key or value contains some text, with their parents.
  • The ⊞ and ⊟ buttons at the top expand and collapse everything; right-click a node for Expand All Inside.
  • Right-click a node to Copy Path (a path such as $.items[2].name), Copy Key or Copy Value.

If the document isn't valid JSON, the panel says where the problem is, with a Go to Error button. Very large documents are too big to show as a tree; the panel says so rather than freezing.

XML Tools

Tools > XML Tools covers what the XML Tools plugin does for Notepad++, built in. Like the other text tools, the formatting commands work on the selection or on the whole document, as one undo step.

Formatting

CommandShortcutWhat it does
Pretty PrintCtrl+Alt+Shift+BIndents the XML, one element per line
Pretty Print, Attributes on New LinesThe same, with each attribute on a line of its own
LinearizeCtrl+Alt+Shift+LRemoves the indentation and line breaks between elements

Text inside elements, comments, CDATA sections and processing instructions is kept as it is.

Checking XML

  • Check Syntax (Ctrl+Alt+Shift+M) checks that the document is well-formed: every tag closed, attributes quoted, one root element. A mistake is shown with its line and column, and the caret moves there.
  • Check Syntax When Saving runs that check each time you save an XML file, and warns you (the file is still saved). Also in Preferences under Files and Startup.

Validating against a schema

Validate checks the document against an XSD schema or a DTD:

  • the XSD named in the root element's xsi:schemaLocation or xsi:noNamespaceSchemaLocation, or
  • the DTD in the document's <!DOCTYPE>, or
  • the schema you last used for that file.

If there isn't one, or to use another, choose Validate Against… and pick the .xsd or .dtd file. Ettin Edit remembers your choice for that file.

Problems are listed in the results panel; click one to jump to its line. A valid document gets a short notice saying so.

Not supported: xs:key, xs:keyref and xs:unique, xs:redefine, and schemas that have to be downloaded from the internet (keep a copy next to your file instead).

XSL Transform

XSL Transform… asks for an XSLT 1.0 stylesheet and runs it over the document. The output opens in a new tab, coloured as HTML or XML when that's what it is. Messages from xsl:message are shown in a notice.

Not supported: xsl:import, xsl:include and the document() function.

XPath

XPath Panel (Ctrl+Alt+Shift+E) opens a panel below the text. Type an XPath 1.0 expression and press Enter or Evaluate:

  • If the result is a set of nodes, each is listed; click one to jump to it in the text. Copy Results copies them all.
  • Otherwise the panel shows the value, such as a number from count(//item) or the text from string(//title).
  • Recent brings back earlier expressions.

Every XPath 1.0 function is available, plus ends-with(), lower-case() and upper-case() from XPath 2.0. Namespace prefixes declared in the document work in expressions, and a name without a prefix also matches elements in the default namespace, so //book finds <book> even in an XHTML or Atom file.

The current XPath

In an XML file the status bar shows where the caret is, such as /catalog/book[3]/title. Click it, or use Copy Current XPath (Ctrl+Alt+Shift+P), to copy it.

Escaping

  • Escape Special Characters turns <, >, &, " and ' into &lt;, &gt;, &amp;, &quot; and &apos;.
  • Unescape Special Characters turns them back.

Closing tags

Close Tags Automatically adds the closing tag as you type an opening one in XML and HTML. Empty HTML elements such as <br> and <img> don't get one.

MIME Tools

Tools > MIME Tools encodes and decodes text the way the MIME Tools plugin does for Notepad++. Each command works on the selection (each selection, if there are several) or on the whole document, and is one undo step. Select just the part you need, such as one value in a JSON file, so the rest is left alone.

Base64

CommandWhat it does
Base64 EncodeEncodes the text (as UTF-8) on one line
Base64 Encode with Line BreaksThe same, with a line break every 76 characters, as in email
Base64 Encode, URL-SafeUses - and _ instead of + and /, without = padding, for URLs and file names
Base64 DecodeDecodes either kind, with or without padding and line breaks

Decoding stops with a message if the result isn't text, for example if the Base64 holds an image.

URLs

CommandWhat it doesa b/c?d=é becomes
URL Encode (Part of a URL)Encodes everything except letters, digits and -_.~, for one value in a query string or patha%20b%2Fc%3Fd%3D%C3%A9
URL Encode (Whole URL)Keeps /, ?, =, &, : and the other characters that give a URL its structurea%20b/c?d=%C3%A9
URL DecodeTurns %XX back into characters

Quoted-printable

Quoted-Printable Encode and Decode handle the encoding used in email bodies, where =C3=A9 stands for é and a line ending in = continues on the next.

HTML

  • HTML Encode turns &, <, >, " and ' into entities.
  • HTML Encode, Including Accents and Symbols also encodes every non-ASCII character, by name where it has one (&eacute;, &euro;) and by number otherwise.
  • HTML Decode turns named and numbered entities back into characters.

SAML

SAML Decode turns a SAML request or response back into readable XML. Select the Base64 text of a POST, the value of a SAMLRequest or SAMLResponse parameter, or a whole redirect URL that contains one. Ettin Edit URL-decodes it if needed, decodes the Base64, inflates it if it was compressed, and pretty prints the XML.

Compare

Tools > Compare shows the differences between two versions of a text, side by side. It's Ettin Edit's take on the ComparePlus plugin.

Starting a comparison

Command (Tools > Compare)Compares the current tab with…
Compare with Previous Tab (Ctrl+Alt+D)the tab you were in before it. When the window is split, this is Compare the Two Views and compares the two tabs you can see.
Compare Withany other open tab you pick
Compare to Last Savethe file as it is on disk, showing your unsaved changes
Compare to Clipboardthe text on the clipboard
Compare to Last Commit (Git)the file as it was in the last Git commit. Needs git installed and the file in a Git repository.
Compare Selectionstwo pieces of text: select one, then Ctrl+drag to select the other, or select one in each view

The same commands are on the editor's right-click menu under Tools > Compare.

The Compare tab

The comparison opens in a tab of its own, with the two texts side by side and their lines lined up:

  • Added lines, removed lines and changed lines each have their own colour, and the words that changed inside a changed line are highlighted.
  • Moved blocks, lines that were cut from one place and pasted in another, are coloured apart from additions and removals.
  • Blank filler rows keep the two sides level, and both sides scroll together.
  • The bar at the right edge shows where all the differences are in the file; click or drag in it to go there.

The Compare tab is read-only, but it follows the tabs being compared: edit one of them and the comparison updates. Double-click a line to jump to it in its own tab and edit it there.

The toolbar

  • First, ↑, ↓ and Last move between differences; F7 and Shift+F7 do the same from anywhere.
  • Difference 3 of 12 and a count of changed, added and removed lines, or Identical when there's nothing to show.
  • Swap Sides puts the left text on the right.
  • Export Patch opens the differences as a unified diff (the format git diff and patch use) in a new tab.
  • Options:
    • Ignore Spaces and Tabs: differences in spacing don't count.
    • Ignore Case: Hello and hello are the same.
    • Ignore Empty Lines: added or removed blank lines don't count.
    • Detect Moved Lines: on by default.
  • × closes the comparison (also Tools > Compare > Close Comparison).

Tools > Compare > Show Comparison brings the Compare tab back to the front.

Very large or very different files stay responsive: the comparison has a time limit and only draws the rows on screen.

CsvQuery

CsvQuery runs SQL queries on the CSV file you have open, like the CsvQuery plugin for Notepad++. Open a .csv, .tsv or other delimited file and choose Tools > CsvQuery > CsvQuery Panel (Ctrl+Alt+Q). A panel opens below the text, and runs SELECT * FROM this straight away.

Ottar says: your spreadsheet would like a word. It can wait.

Tables

  • The current tab is always the table this.
  • Every other open tab is a table named after its file, with anything that isn't a letter or digit turned into _: orders 2024.csv is orders_2024. A tab is only read when a query names it.
  • The Tables menu in the panel inserts a table's name into the query.

So you can join files:

SELECT c.name, SUM(o.total) AS spent
FROM this AS o
JOIN customers AS c ON c.id = o.customer_id
GROUP BY c.name
ORDER BY spent DESC

Writing and running queries

Type SQL in the box at the top of the panel and press Ctrl+Enter, click Run, or use Tools > CsvQuery > Run Query. Queries use SQLite's SQL, so WHERE, GROUP BY, ORDER BY, LIMIT, joins, sub-queries, window functions and SQLite's functions all work.

Queries run in the background, so a big file never freezes the editor. The query runs again by itself when you edit the tab or switch to another one. Recent brings back earlier queries.

UPDATE, DELETE, INSERT and CREATE TABLE work too, on a copy of the data held for the query; the file itself never changes. To keep the result, put it in a new tab (below).

How the file is read

Ettin Edit works out how the file is laid out, and the bar above the query box lets you correct it:

  • Delimiter: comma, semicolon, tab, pipe or space.
  • Quote character: ", ' or none.
  • Header row: whether the first row names the columns. Without one, the columns are called col1, col2 and so on.
  • Reset goes back to what was detected.

Each column is stored as integers, decimals or text, whichever is the narrowest that fits every value. Values with leading zeros, such as zip codes or ids like 007, stay text so the zeros aren't lost. Empty fields are NULL. In semicolon-separated files, decimal commas such as 3,50 count as numbers.

Results

The Results view shows the first 100,000 rows, with how long the query took.

  • Click a column heading to sort by it; click again to reverse.
  • Right-click a cell to Copy Value or Copy Row.
  • Copy (or Tools > CsvQuery > Copy Results) copies every row as tab-separated text, which pastes cleanly into a spreadsheet.
  • Open in New Tab (Results to New Tab) writes all the result rows to a new tab as CSV.

Columns

The Columns view describes each column of this: its type, how many values are filled, empty and distinct, and the minimum, maximum and average. Change a column's Type there if Ettin Edit picked the wrong one, for example to sort a column of numbers stored as text.

Preferences and settings

Settings > Preferences… (Ctrl+,) holds every setting in one window. Changes take effect as you make them; there's no OK button to press. The sections are on the left, with buttons for the Shortcut Mapper, Theme Colours and Customise Toolbar below them.

The most-used switches are also in the Settings menu, so you can flip them without opening Preferences.

Editing

Indentation

  • Tab width: how many columns a tab takes up, and how many spaces an indent is when indenting with spaces.
  • Indent with tabs or Indent with spaces: what Tab and automatic indentation insert. Also Settings > Indent With Spaces.
  • Smart indentation: keep the indent on Enter, and indent after an opening bracket. Also Settings > Smart Indentation.

Typing

  • Close brackets and quotes automatically (Settings > Auto-Close Brackets and Quotes)
  • Close HTML and XML tags automatically (Tools > XML Tools > Close Tags Automatically)
  • Suggest words from the document while typing (Settings > Word Completion)
  • Suggest the language's keywords and functions (Settings > Keyword and Function Completion)
  • Show a function's parameters while typing a call (Settings > Parameter Hints)

See Typing helpers for what each one does.

Display

Font

  • Editor font: the font for the text. The list shows the fonts installed on your computer, monospaced ones first; tick Show proportional fonts to see the rest, and type in Find to look for one. Use Built-in goes back to Hack, the font Ettin Edit comes with.
  • Size: the text size. Ctrl+0 returns to this size after zooming.

Whatever font you choose, Chinese, Japanese and Korean characters are drawn with a CJK font from your system when one is installed.

Show: word wrap, line numbers, the current line highlight, whitespace, end-of-line symbols and invisible characters, indent guides, and the Long-line marker at column, with its column. These are the same switches as in the View menu.

New Documents

What a new tab (Ctrl+N) starts with:

  • Line ending: your system's usual one (LF on Linux, CR LF on Windows), or one you choose.
  • Encoding: UTF-8 unless you choose another.
  • Language: Plain Text, or the language you write most, so new tabs are coloured and complete as that language straight away.

Opened files always keep their own line ending and encoding.

Files and Startup

Interface language

  • The language of menus, dialogs and messages: the same as your system's, or one you choose. Open Translations Folder and Reload are for adding your own translations. See Translations.

Startup and exit

  • Reopen the files that were open last time: start where you left off.
  • Quit without asking about unsaved changes, and bring them back next time: see You won't lose your work. Also Settings > Remember Unsaved Changes on Exit.
  • Open files in the running Ettin Edit window: one window for everything. Also Settings > Single Window.

Files

  • Reload files changed on disk automatically when they have no unsaved changes. Also Settings > Reload Files Changed on Disk Automatically.
  • Check that XML is well-formed each time it's saved. Also Tools > XML Tools > Check Syntax When Saving.

Printing

  • Print line numbers
  • Print syntax colours (darkened to read well on paper)

Updates

  • Check for a new version of Ettin Edit once a week. Also Help > Check for Updates Automatically.

Plugins

Programs that run plugins: the Python 3 and Node.js programs to run plugins with. Leave them empty and Ettin Edit finds them on the PATH; fill them in if you want a particular Python (a virtual environment, say) or a Node.js that isn't on the PATH. Changes apply when plugins are reloaded (Plugins > Reload Plugins).

Where settings are kept

Settings are saved in settings.json in the settings folder. You can copy that file to another computer to take your settings with you. Edit it by hand only while Ettin Edit is closed, because Ettin Edit writes it when settings change.

The toolbar

Under the menu bar is a tabbed toolbar, like the ribbon in Microsoft Office. Each tab holds groups of buttons for commands you use often. You can put any menu command on it, plugin commands and saved macros too, and arrange the tabs, groups and buttons however you like.

The toolbar's Home tab above a document

Using it

  • Click a tab name (Home, Edit, View, Tools) to show its buttons.
  • Hover over a button to see where its command is in the menus and its shortcut.
  • Buttons for commands that turn something on or off, such as Word Wrap, are outlined while it's on. Buttons for commands that can't run right now, such as Undo with nothing to undo, are greyed out.
  • When the window is too narrow for a tab, scroll its buttons sideways with Shift and the mouse wheel.

The default tabs

TabGroups
HomeFile, Clipboard, Undo, Find, Tabs, Help
EditLines, Sort, Case, Comment, Blanks, Selection
ViewShow, Zoom, Folding, Panels, Window, Customise
ToolsCompare, JSON, XML, Data (CsvQuery and MIME Tools), Macros

Collapsing and hiding

To give the text more room, collapse the toolbar so only its tab names show:

  • click ⌃ at the right end of the tab names, or
  • double-click a tab name, or
  • press Ctrl+F1, or
  • choose View > Collapse Toolbar.

While it's collapsed, clicking a tab name opens its buttons over the text; they close again when you click a button or anywhere else. Expand it the same ways (⌄ at the right end).

View > Toolbar hides the toolbar completely and shows it again; so does Hide the toolbar in its right-click menu.

You can hide the classic menu bar as well, with View > Menu Bar, Ctrl+M or Hide the menu bar in the toolbar's right-click menu. While it's hidden, tap Alt to show it for a moment, and press Ctrl+M to bring it back for good. The Help menu's commands (the user manual, Check for Updates and About) are on the toolbar's Home tab too. With both hidden, only the tabs, the text and the status bar are left. Both choices are kept in settings.json.

Customising

Open Settings > Customise Toolbar…, or right-click the toolbar and choose Customise Toolbar… (it's also in View and in Preferences).

The Customise Toolbar dialog: commands on the left, the toolbar's tabs, groups and buttons on the right

On the left is every command you can add: everything in the menus (themes, languages and encodings included), the commands of plugins that are running, and your saved macros. Type in the filter box to narrow the list; it matches every word you type, anywhere in the command's menu path.

On the right is the toolbar: tabs, the groups in each tab, and the buttons in each group.

Adding a button

  • Drag a command from the left onto the right. Dropped on a button, it goes in front of that button; dropped on a group or a tab, it goes at the end of it.
  • Or pick a command on the left, select where it should go on the right, and click Add › (or double-click the command). It goes after the selected button, or at the end of the selected group.

Arranging

  • Drag tabs, groups and buttons to move them. A button can move to another group or tab, and a group to another tab.
  • ▲ and ▼ move the selected item one place. A button at the end of its group moves into the next group.
  • ‹ Remove takes the selected button, group or tab off the toolbar. You can also right-click a button on the toolbar and choose Remove from Toolbar.
  • New Tab and New Group add an empty one after the selection.
  • Untick the box in front of a tab to hide it without losing its buttons.

Changing a button, group or tab

Select it on the right and change it at the bottom of the dialog:

SelectedWhat you can change
A tab or groupIts name. The built-in names follow the interface language until you rename them.
A buttonLabel (leave it empty for the command's own name), Size and Icon

Large buttons have the icon above the label. Small buttons have the icon beside the label, and three of them stack in a column.

Change… opens the icon picker. It has the 1,500 icons of the Phosphor set (MIT licence); type part of a name, like star or arrow, to find one. Use the command's icon goes back to the default.

Click OK or Apply to use your changes, or Cancel to forget them. Reset to Defaults puts back the toolbar Ettin Edit came with (press OK afterwards to keep it).

Plugin commands

Plugin commands appear under Plugins › plugin name in the command list once the plugin is running. A plugin can give its commands an icon; the others get a puzzle piece. While a plugin isn't running (turned off, or still starting), its buttons are left off the toolbar, and they come back when it runs again. In the Customise dialog they show greyed out.

To give your own plugin's commands an icon, see Writing plugins.

Where the layout is kept

Your toolbar is saved in toolbar.json in the settings folder (~/.config/EttinEdit on Linux, %APPDATA%\EttinEdit on Windows). Copy that file to use the same toolbar on another computer. While you haven't changed anything, there's no file and you get the default toolbar, including any new buttons later versions add. A toolbar you have customised keeps your changes; Ettin Edit 1.7 adds only the new Help group to the end of its Home tab (unless you renamed or removed that tab), so the Help commands can be reached while the menu bar is hidden. Delete the group if you don't want it. Whether the toolbar is shown or collapsed is kept in settings.json.

Keyboard shortcuts

Every command in Ettin Edit can have a keyboard shortcut, and you can change any of them. This page lists the defaults; the menus and the command palette always show the ones in use.

Changing shortcuts

Settings > Shortcut Mapper… lists every command, every saved macro and every plugin command, with their shortcuts.

  1. Type in Find to narrow the list, by the command's name or by a shortcut such as ctrl+d. Tick Only commands with a shortcut to hide the rest.
  2. Select a command.
  3. Click Set… (or Change…), then press the new keys. Esc cancels.
  4. If another command already uses those keys, Ettin Edit tells you which one. Move It Here takes the shortcut from the other command; Cancel leaves things as they were.

A command can have more than one shortcut: Add Another… adds one, Remove removes the selected one, and Reset to Default puts the command's original shortcut back. Reset All Shortcuts resets every command.

Rules for shortcuts:

  • They need Ctrl or Alt, unless they use a function key (F1 to F12), so plain typing is never taken over.
  • Ctrl+C, Ctrl+X and Ctrl+V are kept for copy, cut and paste.
  • Undo, redo, cut, copy, paste, select all and completion are handled by the editor itself and can't be changed.

Your shortcuts are saved in settings.json in the settings folder, so they move with your settings.

Default shortcuts

On macOS-style keyboards, Ctrl is still Ctrl; Ettin Edit runs on Linux and Windows only.

File

CommandShortcut
NewCtrl+N
Open…Ctrl+O
SaveCtrl+S
Save As…Ctrl+Alt+S
Save AllCtrl+Shift+S
Print…Ctrl+P
CloseCtrl+W
Close AllCtrl+Shift+W

Edit

CommandShortcut
UndoCtrl+Z
RedoCtrl+Y
CutCtrl+X
CopyCtrl+C
PasteCtrl+V
Select AllCtrl+A
Line Operations > DuplicateCtrl+D
Line Operations > Delete LinesCtrl+Shift+L
Line Operations > Move UpCtrl+Shift+Up
Line Operations > Move DownCtrl+Shift+Down
Line Operations > Join LinesCtrl+J
Line Operations > Split Lines at Long-Line ColumnCtrl+I
Line Operations > Insert Blank Line AboveCtrl+Alt+Enter
Line Operations > Insert Blank Line BelowCtrl+Alt+Shift+Enter
Convert Case To > UPPERCASECtrl+Shift+U
Convert Case To > lowercaseCtrl+U
Convert Case To > Title CaseAlt+U
Convert Case To > Sentence caseCtrl+Alt+U
Convert Case To > iNVERT cASECtrl+Alt+Shift+U
Comment > Toggle Line CommentCtrl+Q
Comment > Toggle Block CommentCtrl+Shift+Q
Insert > Date and Time (Short)F5
Insert > Date and Time (Long)Shift+F5
Multi-Select > Select Next OccurrenceCtrl+Shift+D
Multi-Select > Select All OccurrencesAlt+F3
Auto-Completion > Complete WordCtrl+Space
Auto-Completion > Show Parameter HintCtrl+Shift+Space
Column Editor…Alt+C
Column ModeAlt+Shift+C
CommandShortcut
Find…Ctrl+F
Replace…Ctrl+H
Find NextF3
Find PreviousShift+F3
Find Selected NextCtrl+F3
Find Selected PreviousCtrl+Shift+F3
Find in Files…Ctrl+Shift+F
Go to Line…Ctrl+G
Bookmark > Toggle BookmarkCtrl+F2
Bookmark > Next BookmarkF2
Bookmark > Previous BookmarkShift+F2

View

CommandShortcut
Word WrapAlt+Z
Distraction-Free ModeF11
Command Palette…F1
Collapse ToolbarCtrl+F1
Menu Bar (show or hide)Ctrl+M
Next TabCtrl+Tab or Ctrl+PageDown
Previous TabCtrl+Shift+Tab or Ctrl+PageUp
Focus Other ViewF8
Hex ViewCtrl+Alt+Shift+H
Folding > Fold AllAlt+0
Folding > Unfold AllAlt+Shift+0
Folding > Fold Current LevelCtrl+Alt+F
Folding > Unfold Current LevelCtrl+Alt+Shift+F
Folding > Fold Level 1 … 5Alt+1, Alt+2, Alt+3, Alt+4, Alt+5
Zoom InCtrl++ or Ctrl+=
Zoom OutCtrl+-
Reset ZoomCtrl+0

Settings

CommandShortcut
Preferences…Ctrl+,

Tools

CommandShortcut
Compare > Compare with Previous Tab / the Two ViewsCtrl+Alt+D
Compare > Next DifferenceF7
Compare > Previous DifferenceShift+F7
CsvQuery > CsvQuery PanelCtrl+Alt+Q
CsvQuery > Run Query (in the panel)Ctrl+Enter
JSON and JavaScript > FormatCtrl+Alt+M
JSON and JavaScript > MinifyCtrl+Alt+N
JSON and JavaScript > JSON TreeCtrl+Alt+J
XML Tools > Pretty PrintCtrl+Alt+Shift+B
XML Tools > LinearizeCtrl+Alt+Shift+L
XML Tools > Check SyntaxCtrl+Alt+Shift+M
XML Tools > XPath PanelCtrl+Alt+Shift+E
XML Tools > Copy Current XPathCtrl+Alt+Shift+P

Macro

CommandShortcut
Start or Stop RecordingCtrl+Shift+R
PlaybackCtrl+Shift+P

Help

CommandShortcut
User ManualShift+F1

In the editor

These aren't commands, so they're not in the Shortcut Mapper:

KeysWhat they do
Ctrl+click, Alt+clickAdd a caret
Ctrl+dragAdd a selection
Alt+drag, Alt+Shift+arrowsColumn selection (a plain drag and Shift+arrows in Column Mode)
Ctrl+Alt+Up, Ctrl+Alt+DownAdd a caret above or below
EscBack to one caret; close the completion list, a parameter hint or the find bar
HomeFirst non-blank character, then the start of the line
Ctrl+Left, Ctrl+RightMove by words
Ctrl+Backspace, Ctrl+DeleteDelete by words
Tab, Shift+TabIndent or outdent the selected lines
Middle-click on a tabClose it

Themes and colours

A theme colours both the text and the whole window: menus, tabs, panels and the status bar. Ettin Edit comes with nine:

DarkLight
Ettin Dark (the default, based on Base16 Eighties)Ettin Light
Ettin NightOcean Light
Ocean DarkSolarized Light
MochaGitHub Light
Solarized Dark

Pick one from the Theme menu, where they're listed under Dark and Light. The change is immediate and remembered.

Themes are files

Every theme, built-in ones included, is a TextMate .tmTheme file in the themes folder:

  • Linux: ~/.config/EttinEdit/themes/
  • Windows: %APPDATA%\EttinEdit\themes\

Theme > Open Themes Folder opens it. This means you can:

  • Change a built-in theme by editing its file, then choosing Theme > Reload Themes.
  • Add a theme by dropping any .tmTheme file into the folder and reloading. Themes you add appear under Custom in the Theme menu. Thousands of .tmTheme files exist for TextMate, Sublime Text and other editors.
  • Share a theme by sending someone the file.

When Ettin Edit is updated, built-in themes you haven't edited are updated with it; ones you have edited are left alone. Theme > Restore Built-in Themes puts the original built-in themes back and keeps each edited copy as <name>.tmTheme.bak, so nothing is lost.

Edit Theme Colours

Theme > Edit Theme Colours… changes a theme without touching its file by hand. Every change shows in the editor at once, so you can see what you're doing.

  • Theme at the top picks the theme to edit (and switches to it).
  • Editor colours: the Background, Text, Caret, Selection, Current line, Line numbers, Indent guides, Whitespace symbols, Search matches, and the Accent used for the current tab, buttons and fold markers. Click a colour to change it, or Don't set this colour to fall back to the default.
  • Syntax colours are a list of rules. Each rule has a name, a Scope that says which text it colours, a colour, and B, I and U for bold, italic and underline. Type in Find to look for a rule, such as string or comment. Add Rule adds one, and the button at the end of a rule deletes it.
  • Save writes the changes to the theme's file. Save As New Theme… saves them as a new theme with a name you choose, leaving the original alone. Discard Changes goes back to the theme as it was saved, and closing the window without saving does the same.

Scopes

Languages label each piece of text with a scope, such as comment.line.double-slash.rust or string.quoted.double.json. A rule's scope colours every piece of text whose scope starts with it, so string colours every kind of string in every language, and string.quoted.double.json only colours double-quoted strings in JSON. The most specific rule wins. Separate several scopes with commas.

The scopes most themes set are comment, string, constant.numeric, constant.language, keyword, storage, entity.name.function, entity.name.type, variable, support.function and invalid. See Languages for the scopes your own languages use.

Fonts

The editor's font and size are in Preferences, not in the theme, so they stay the same whichever theme you pick.

Languages in Ettin Edit

Ettin Edit colours code with Sublime Text–style grammars. It ships with the usual set (C, C++, C#, Java, Python, Rust, Go, JavaScript, HTML, CSS, SQL, Markdown, JSON, YAML, XML, shell scripts and more), plus its own grammars for:

  • TOML
  • INI and other key/value files: .ini, .cfg, .conf, .properties, .desktop, .reg, .inf, .editorconfig, .gitconfig and systemd units (.service, .socket, .timer and the rest)
  • TypeScript (.ts, .mts, .cts) and TSX
  • PowerShell
  • Dockerfile (also Containerfile and Dockerfile.*)
  • HL7 v2 messages (the separators are read from each MSH segment)
  • Kotlin, Swift, Dart, Zig
  • CMake, Nginx, .env files
  • Protocol Buffers, GraphQL, Terraform / HCL

Pick a language for the current file from the Language menu. Ettin Edit chooses one when a file opens, by its name, its extension and finally its first line (a shebang such as #!/usr/bin/env python3).

You can add your own languages, or replace a built-in one, in two ways:

  • write a short .lang.json file (no regular expressions needed), or
  • drop in a .sublime-syntax grammar.

The languages folder

Put language files in the languages folder inside the Ettin Edit settings folder:

  • Linux: ~/.config/EttinEdit/languages
  • Windows: %APPDATA%\EttinEdit\languages

Language > Open Languages Folder opens it (and creates it the first time). Language > New Language… puts a commented template there and opens it. Ettin Edit reads the folder when it starts; after adding or changing a file, choose Language > Reload Languages to use it straight away.

  • A file that cannot be loaded is skipped. Ettin Edit tells you which file it was and why; the other files still load.
  • A language with the same name as a built-in one replaces it. For example, a file with "name": "Python" takes over .py files.
  • If two of your files use the same name, the one that comes later in alphabetical order wins.

User-defined languages (.lang.json)

A .lang.json file describes a language by its comments, strings and keywords. Ettin Edit turns it into a grammar when it loads it. Save the file as <anything>.lang.json, for example mylang.lang.json.

Here is a complete example. Keys that start with _ are notes and are ignored, so you can keep them as comments:

{
  "_about": "An Ettin Edit user-defined language. Keep it in the languages folder as <something>.lang.json, then choose Language > Reload Languages. Keys that start with _ are notes and are ignored.",

  "name": "My Language",
  "extensions": ["mylang"],

  "_first_line": "Optional regular expression tried on the first line of files whose extension is unknown, for example a shebang.",
  "first_line": "^#!.*\\bmylang\\b",

  "_case_sensitive": "false makes keywords match in any case (IF, If, if).",
  "case_sensitive": true,

  "line_comment": ["//", "#"],
  "block_comment": [["/*", "*/"]],

  "_strings": "Each entry is [open, close] or [open, close, escape]. Strings end at the end of the line unless multiline_strings is true.",
  "strings": [["\"", "\"", "\\"], ["'", "'", "\\"]],
  "multiline_strings": false,

  "_keywords": "Groups: keyword, type, constant, builtin, modifier, operator, variable, or a scope name such as support.class.",
  "keywords": {
    "keyword": ["if", "then", "else", "elif", "end", "while", "for", "in", "return", "break"],
    "type": ["int", "float", "string", "bool"],
    "constant": ["true", "false", "nil"],
    "builtin": ["print", "len", "open"]
  },

  "operators": ["+", "-", "*", "/", "%", "=", "==", "!=", "<", "<=", ">", ">=", "&&", "||", "!"],
  "numbers": true,

  "_folding": "Pairs that open and close a block, for code folding: brackets such as { } or words such as if … end.",
  "folding": [["{", "}"], ["if", "end"]]
}

Only name is required. Everything else is optional.

KeyMeaningDefault
nameThe name shown in the Language menu.(required)
extensionsFile extensions without the dot, such as ["mylang", "ml2"]. A single string also works.none
first_lineA regular expression tried on the first line of a file whose extension is not known, such as a shebang.none
case_sensitivefalse makes keywords match in any case (IF, If, if).true
line_commentMarkers that start a comment running to the end of the line. A single string also works.none
block_comment[open, close] pairs, such as [["/*", "*/"]].none
strings[open, close] or [open, close, escape] entries. When the escape is the same as the close (["'", "'", "'"]), a doubled quote stays inside the string, as in SQL.none
multiline_stringstrue lets strings run over several lines. Otherwise a string ends at the end of its line, so a missing quote only spoils one line.false
keywordsGroups of words, coloured by group (see below). Words match whole words only.none
operatorsSymbols to colour as operators, such as "+" or "==".none
numbersColour numbers (42, 3.14, 1e-9, 0xFF).true
foldingPairs that open and close a block, such as [["{", "}"], ["begin", "end"]]. Code folding follows them; word pairs are coloured as keywords. Without pairs, ( ), [ ] and { } fold, or failing that, indentation.none

A key Ettin Edit does not recognise is reported as an error, so a typo such as "line_coment" does not go unnoticed.

Keyword groups

The group name decides the colour, using the same scopes as the built-in grammars, so every theme already knows how to colour them:

GroupUsed forScope
keywordcontrol words: if, while, returnkeyword.control
typetype names: int, stringstorage.type
constanttrue, false, nullconstant.language
builtin (or function)built-in functionssupport.function
modifierpublic, static, conststorage.modifier
operatorword operators: and, or, notkeyword.operator.word
variableself, thisvariable.language

Plural names (keywords, types and so on) work too. For anything else, use a scope name with a dot, such as "support.class" or "entity.name.tag".

Sublime Text grammars (.sublime-syntax)

For full control, write a grammar in the sublime-syntax format and save it in the languages folder with the .sublime-syntax extension. Ettin Edit loads it as it is.

  • The grammar's name is what the Language menu shows. Without one, the file name is used.
  • file_extensions and first_line_match decide which files it opens.
  • The grammar needs a main context, and every context it refers to must exist. A grammar that fails these checks is skipped with a message, rather than leaving files uncoloured.
  • Ettin Edit uses the syntect engine, which supports nearly all of the format. Grammars that need the newest Sublime Text features (such as extends or branch_point) may not load.

Only use grammars whose licence lets you use them.

Colours

Grammars only label the text (a keyword, a string, a comment). The theme decides the colours, so a new language follows whichever theme you pick from the Theme menu.

Code folding

Folding follows each language's grammar, so a block ends where its closing bracket, tag or keyword is, wherever the indentation says it does. What folds:

  • brackets: { }, [ ] and ( ) spread over several lines; brackets inside strings and comments don't count
  • tags in HTML, XML, SVG and JSX (<br> and other empty HTML elements, and <tag/>, don't open a block), and the code inside <script> and <style>
  • keyword blocks: Ruby and Lua (def/function/if/do … end), shell scripts (if … fi, case … esac, do … done), Pascal (begin … end), CMake (if() … endif() and the rest), and folding pairs in .lang.json languages
  • LaTeX \begin{…} … \end{…}
  • [sections] in INI and TOML files, and Markdown headings (down to the next heading of the same or a higher level) and fenced code blocks
  • comment blocks: a multi-line comment, or two or more lines of line comments
  • #region … #endregion markers, in a comment (// #region Name, <!-- #region -->) or as C#'s and C++'s #region / #pragma region

The line with the closing bracket stays visible, so } else { keeps working. Python, YAML, Haskell, Makefiles, plain text and files without any blocks fold by indentation, as do files over 300,000 lines.

Completion and parameter hints

As you type, the completion list offers words from the document, the language's keywords, and the functions it knows about. A function shows its signature next to its name. Ctrl+Space opens the list early.

Typing ( after a function's name shows its parameters above the caret, with the one you're typing in bold. It follows the caret from argument to argument and closes when you leave the call or press Esc. Ctrl+Shift+Space shows it again. The signatures come from:

  • the functions the document itself defines (Rust, C, C#, Java, Kotlin, Go, JavaScript, TypeScript, PHP, Python, Ruby, Lua and the other languages the function list understands), and
  • lists of common built-in and library functions for Python, JavaScript and TypeScript, Rust, C, C++, C#, Java, Go, PHP, Lua, Ruby, Kotlin, Swift, SQL, PowerShell and CSS. HTML, CSS, SQL and shell scripts have keyword lists.

Languages without a list (including your own .lang.json ones) still complete the keywords their grammar colours.

Each of these can be turned off in the Settings menu or in Preferences: Word Completion, Keyword and Function Completion, and Parameter Hints.

Your own lists

Put .json files in the api folder next to the languages folder (Language > Open Completion Lists Folder creates it with an example), then choose Language > Reload Languages. A list adds to the built-in one for the same language:

{
  "languages": ["Python"],
  "ignore_case": false,
  "keywords": ["my_keyword"],
  "functions": [
    "my_function(first, second=2) -> int",
    {"signature": "mymodule.helper(path, *, verbose=False)", "doc": "Shown under the signature."}
  ]
}
KeyWhat it is
languagesThe languages the list is for, named as in the Language menu.
ignore_casetrue when IF and if are the same word (SQL, PowerShell).
keywordsWords to offer in the completion list.
functionsSignatures, name(parameters) with anything after the ), such as a return type. A qualified name (os.path.join, std::mem::swap, Math.max) matches calls written either way, join( or os.path.join(. Write {"signature": …, "doc": …} to add a description.

Translations

Ettin Edit's menus, dialogs and messages can be shown in another language. It comes with English, German (Deutsch), French (Français) and Spanish (Español), and you can add more languages or change any translation with a text file.

The German, French and Spanish translations are machine-made starting points. They haven't been checked by native speakers yet, so some wording will be clumsy or wrong. Corrections are very welcome: see Improving a translation.

Choosing the language

Open Settings > Preferences… (Ctrl+,). Interface language is at the top of Files and Startup.

  • Same as the system (the default) follows your system's language. On Linux that's the LANGUAGE, LC_ALL, LC_MESSAGES or LANG setting; on Windows it's the language in your region settings. A regional language uses its base language when there's no translation for the region, so de_AT gets German. A language with no translation gets English.
  • Or pick a language from the list.

The window changes language at once; there's nothing to restart.

What stays in English

  • The user manual, including the in-app copy.
  • Names of programming languages and themes, and Plain Text.
  • Messages from the text tools' parsers, such as a JSON or XML syntax error and its line number, and messages from XPath, XSD, XSLT and SQL.
  • Messages from plugins, unless the plugin translates them itself (see Writing plugins).
  • Templates Ettin Edit writes for you, such as a new language file.

Right-to-left languages such as Arabic and Hebrew can't be shown correctly yet, because the toolkit Ettin Edit is drawn with doesn't lay out right-to-left text.

The translations folder

Open Translations Folder, next to the language list in Preferences, opens the translations folder in your settings folder, creating it if needed. It also puts english-source.ftl.txt there: every message in English, with notes, kept up to date by Ettin Edit. Copy from it; don't edit it, because it is replaced each time.

Each file in the folder is named after its language code, such as pt.ftl for Portuguese, pt-BR.ftl for Brazilian Portuguese, or de.ftl for German. After adding or changing a file, press Reload next to the language list.

Adding a language

  1. Copy english-source.ftl.txt to a new file named after the language, such as it.ftl.
  2. Change language-name = English to the language's own name, such as language-name = Italiano. That's the name shown in the list.
  3. Translate the text after each =. Leave the ids before the =, and anything in { $braces }, as they are.
  4. Press Reload in Preferences and pick the language.

You don't have to translate everything at once. Any message the file doesn't have is shown in English.

Improving a translation

A file for a language Ettin Edit already has is used on top of the built-in translation, message by message. So to fix a few German messages, make a de.ftl that holds only those messages:

save-as = Speichern als …
find-hint = Suchen

To share your fixes with everyone, send them to the project on GitHub. The built-in files are in assets/i18n in the source.

The file format

The files use Fluent, a format made for translating software. Most lines are just id = text. A few things to know:

  • Text in { $braces } is filled in by Ettin Edit, such as a file name or a count. You can move it within the sentence, but keep its name.

  • A long message can continue on the next lines, indented by spaces.

  • Lines starting with # are notes and are ignored.

  • Messages that depend on a number choose between forms:

    differences-count = { $count ->
        [one] { $count } difference
       *[other] { $count } differences
    }
    

    The names in brackets are the language's plural forms (zero, one, two, few, many and other), and the one marked * is used when no other fits. Use the forms your language needs; Polish, for example, uses one, few, many and other.

If a file has a mistake, Ettin Edit shows a message naming the file and the problem when it loads it, and still uses the rest of the file.

Using plugins

Plugins add commands, shortcuts and panels to Ettin Edit. They're written in Python or JavaScript, so anyone who knows either can make one; see Writing plugins.

Many things that need a plugin in other editors are built into Ettin Edit already: the JSON, XML and MIME tools, Compare and CsvQuery.

What you need

  • Python plugins need Python 3 installed. Most Linux systems have it; on Windows, install it from python.org or the Microsoft Store.
  • JavaScript plugins need Node.js 18 or newer.

Ettin Edit finds them on the PATH. If it can't, or you want a different one, set the program in Plugins > Manage Plugins or Preferences > Plugins.

Trying the samples

Plugins > Install Sample Plugins installs and starts four plugins:

PluginLanguageWhat it does
Text StatisticsPythonLive counts for the current tab in a side panel (Ctrl+Alt+T), word frequencies as CSV in a new tab, and a word count of the selection
Markdown OutlineJavaScriptA clickable outline of a Markdown file's headings, Insert UUID, and Wrap Lines… to a width you choose
Markdown PreviewPythonA live preview of the Markdown tab you're editing (see below)
HL7 ViewerPythonBrowse and edit HL7 v2 messages (see below)

Their commands appear in the Plugins menu, under each plugin's name, and in the editor's right-click menu.

Markdown Preview

Open a Markdown file and choose Plugins > Markdown Preview > Show or Hide Markdown Preview (Ctrl+Shift+M). A panel on the right shows the file rendered: headings, lists, tables, quotes, code blocks, links, bold, italic and strikethrough. It updates a moment after you stop typing, keeps its place as you edit, and follows you when you switch tabs.

  • Click a web link to open it in your browser, a link to a heading (#install) to scroll there, or a link to another file (notes.md) to open it in a tab.
  • Images show: PNG, JPEG, GIF, BMP, WebP and SVG, from files next to the Markdown file (![Logo](img/logo.png)) or from the web. An image that can't be found or read shows its description instead. Images in an unsaved tab only load from the web, as there's no folder to look in yet.
  • The preview scrolls along with the text: scroll the editor and the preview shows the same place. Untick Scroll with the text at the top of the preview to scroll it on its own.
  • YAML front matter (the --- block some sites put at the top) isn't shown.
  • Raw HTML is left out.
  • Tabs that aren't Markdown (by language, or a .md / .markdown name) show a note instead.

HL7 Viewer

HL7 v2 is the message format hospitals use to pass patient, order and result data between systems. Open a message (or choose Plugins > HL7 Viewer > Open Sample HL7 Message), then Show or Hide HL7 Viewer (Ctrl+Alt+H):

  • A tree on the right shows the message's segments, fields, repetitions, components and subcomponents. It follows the caret, and clicking a node selects that part of the text.
  • An inspector shows the selected piece's designation (such as PID-5.1), its name, data type, whether it's required or repeatable, its length and its table, from the HL7 v2.5.1 definitions. Change the value there to edit the message.
  • Copy HL7 Field Designation copies the designation of the piece at the caret.

The separators are read from each MSH segment, so messages with unusual delimiters work too. HL7 files are coloured by the built-in HL7 language.

Installing plugins

Plugins > Manage Plugins… has two tabs:

  • Available lists the plugins in the Ettin Edit plugin index. Type in the filter box to search by name, author or description, and click Install.
  • Installed lists your plugins, and offers Update to x.y when the index has a newer version.

You can also install a plugin someone sent you: Install from File… takes a .zip, and Install from Folder… copies a folder that has a plugin.json in it. Or copy the folder into the plugins folder yourself (Plugins > Open Plugins Folder) and choose Plugins > Reload Plugins.

Permission to run

A plugin is a program that runs with your user account: it can read and change your documents and files and use the network, like any program you install. So the first time Ettin Edit finds a plugin, and again whenever its files change, it asks whether to let it run. Choose Allow only for plugins you trust. Don't Allow turns the plugin off; you can turn it on later in Manage Plugins.

The samples you install from the Plugins menu don't ask.

Managing plugins

In the Installed tab of Plugins > Manage Plugins…, each plugin shows whether it's running, stopped or waiting for permission, and has:

  • a switch to turn it on or off,
  • Start, Stop and Restart,
  • Open Folder, to see or edit its files,
  • Remove…, which moves its folder to the trash (so you can get it back),
  • Don't ask when it changes, for a plugin you're writing yourself.

If a plugin fails to start, the reason is shown under its name. Plugins > Reload Plugins stops every plugin, looks for plugins again, and starts them.

The plugin log

Plugins > Plugin Log shows what plugins print, their errors, and anything Ettin Edit refused, such as a shortcut that clashes with one that's already taken. Look here first when a plugin doesn't behave. Copy All copies the log, for a bug report.

A plugin that crashes shows a notice and stops; it can't take Ettin Edit or your documents down with it. Edits a plugin makes are undone in one step, like any other edit.

Plugin shortcuts

Plugins can give their commands shortcuts. A shortcut that's already used by Ettin Edit or another plugin is refused, with a line in the log. You can change or add plugin shortcuts in the Shortcut Mapper, like any other command's.

Writing Ettin Edit plugins

A plugin adds commands, shortcuts and panels to Ettin Edit. You write it in Python or JavaScript, whichever you prefer.

Quick start

  1. Choose Plugins > Install Sample Plugins. Ettin Edit copies four working plugins into your plugins folder and starts them:
    • Text Statistics (Python)
    • Markdown Outline (JavaScript)
    • Markdown Preview (Python): a small example of a markdown panel that updates as you type
    • HL7 Viewer (Python): a bigger example, with a tree panel, an inspector panel and its own unit tests
  2. Try them from the Plugins menu.
  3. Choose Plugins > Open Plugins Folder, copy one of the sample folders, rename it and edit it.
  4. Choose Plugins > Reload Plugins to run your changes.

The plugins folder is ~/.config/EttinEdit/plugins on Linux and %APPDATA%\EttinEdit\plugins on Windows.

Ettin Edit used to be called NixPad. Plugins written for it that import nixpad or require('nixpad') keep working; new plugins use ettin.

What you need

  • Python plugins run with the Python 3 installed on your computer (python3, or python / py on Windows).
  • JavaScript plugins run with Node.js 18 or newer (node).

If Ettin Edit can't find one of them, set its path in Plugins > Manage Plugins. Plugins can use any package you install for that Python or Node, such as one from pip or npm.

A plugin's folder

Each plugin is a folder in the plugins folder. The folder name is the plugin's id.

plugins/
  shout/
    plugin.json
    main.py

plugin.json describes the plugin:

{
  "name": "Shout",
  "version": "1.0.0",
  "description": "Makes the selection upper case.",
  "author": "You",
  "main": "main.py"
}
FieldMeaning
nameShown in menus. Defaults to the folder name.
mainThe script to run, inside the folder. Defaults to main.py or main.js.
runtime"python" or "node". Only needed when main doesn't end in .py or .js.
version, description, authorShown in Manage Plugins.

Folders whose names start with . or _ are skipped. Rename a folder to _shout to hide a plugin without deleting it.

Permission to run

A plugin is a program that runs with your user account. It can read and change your open documents and any of your files, and it can use the network. Only run plugins you trust.

The first time Ettin Edit finds a plugin, it asks whether to let it run. It asks again whenever any file in the plugin's folder changes. If you choose Don't Allow, the plugin is turned off. You can turn it back on in Plugins > Manage Plugins.

Ettin Edit doesn't ask about the sample plugins you install from the Plugins menu. While you write a plugin of your own, tick Don't ask when it changes for it in Manage Plugins, so reloading it doesn't ask each time.

Sharing plugins

Plugins > Manage Plugins has two tabs. Installed lists your plugins, with Remove… (the folder moves to the trash) and Update to x.y when the plugin index has a newer version. Available lists the plugins in the index, with a filter box and an Install button. Install from File… installs a .zip, and Install from Folder… copies a folder that has a plugin.json. A plugin you install or update always asks for permission before it runs, even if you ticked Don't ask when it changes.

To share a plugin, zip it. plugin.json can be at the top of the zip or inside one folder:

shout.zip                 shout.zip
  plugin.json               shout/
  main.py                     plugin.json
                              main.py

The plugin's id (its folder name) comes from the index, otherwise from the folder in the zip, otherwise from the zip's file name. Zips with absolute paths or .. in them are refused.

The index is a JSON file; Ettin Edit reads https://raw.githubusercontent.com/Tharkis/Ettin-Edit/main/plugins/index.json unless you change the address at the bottom of the Available tab. To list a plugin there, add an entry to plugins/index.json in the Ettin Edit repository and open a pull request:

{
  "plugins": [
    {
      "id": "shout",
      "name": "Shout",
      "version": "1.0.0",
      "description": "Makes the selection upper case.",
      "author": "You",
      "homepage": "https://example.com/shout",
      "download": "https://example.com/shout-1.0.0.zip",
      "sha256": "optional: the zip's SHA-256, checked before installing",
      "min_app_version": "optional: the oldest Ettin Edit it works with"
    }
  ]
}

Versions are compared number by number, so 1.10 is newer than 1.9. A download address without https:// is relative to the index itself, so you can host your own index next to your zips. Each Ettin Edit release attaches <id>.zip for the sample plugins.

A Python plugin

import ettin

@ettin.command("Shout", shortcut="Ctrl+Alt+H")
def shout():
    doc = ettin.active()
    doc.replace_selections(doc.selected_text().upper())

@ettin.on("saved")
def saved(doc):
    ettin.log("Saved", doc.path)

ettin.run()

The script must end with ettin.run(). Calls are ordinary function calls that return when Ettin Edit has answered.

A JavaScript plugin

const ettin = require('ettin');

ettin.command('Shout', async () => {
  const doc = await ettin.activeDocument();
  await doc.replaceSelections((await doc.getSelectedText()).toUpperCase());
}, { shortcut: 'Ctrl+Alt+H' });

ettin.on('saved', (doc) => ettin.log('Saved', doc.path));

Every call returns a Promise, so use await. Use require, not import: Ettin Edit makes the ettin module available through NODE_PATH, and ES modules don't read that.

Printing and errors

Ettin Edit and the plugin talk over the plugin's standard input and output. print() in Python and console.log() in JavaScript are sent to the plugin log instead (Plugins > Plugin Log), so use them freely while debugging.

If a command or event handler throws an error, Ettin Edit shows a short message and writes the full traceback to the log. The plugin keeps running.

If the plugin itself stops, Manage Plugins shows why. Fix it, then click Start or choose Reload Plugins.

Text positions

Positions count characters (Unicode code points) from the start of the document, beginning at 0. Lines end with \n whatever the file uses on disk. Line and column numbers begin at 1.

In Python, string indexes already count code points, so positions match text[start:end]. JavaScript strings count UTF-16 units, which differ only for characters outside the Basic Multilingual Plane, such as emoji. Use Array.from(text) to index by code point when that matters.

API reference

Python names are shown first, JavaScript names second.

Commands and events

PythonJavaScriptWhat it does
@command(title, shortcut=None, id=None, icon=None)command(title, fn, {shortcut, id, icon})Adds a command to the Plugins menu, with an optional shortcut and toolbar icon.
@on(event)on(event, fn)Calls the handler with a Document when the event happens.
run()(not needed)Handles commands and events until Ettin Edit stops the plugin.

Shortcuts are written like Ctrl+Alt+U, Ctrl+Shift+F9 or F6. They need Ctrl or Alt unless they use a function key. A shortcut Ettin Edit or another plugin already uses isn't added; the log says why.

Users can put any plugin command on the toolbar. The icon is what its button shows there: a Phosphor icon name such as "star" or "chart-bar", or a .png file inside your plugin's folder, given relative to it ("icons/run.png"; 32×32 pixels looks sharp). An icon that isn't a known name or points outside the folder is left out and the log says why; the button then shows a puzzle piece.

@ettin.command("Count Words", shortcut="Ctrl+Alt+W", icon="hash")
def count_words():
    ...
ettin.command('Count Words', countWords, { shortcut: 'Ctrl+Alt+W', icon: 'hash' });

Events:

EventWhen
openedA tab opened.
savedA document was saved.
closedA tab closed. The document can no longer be used.
activatedAnother tab got focus.
changedThe text was edited. Sent after a short pause in typing.
caretThe caret or selection moved in the active tab. Sent after a short pause.
shutdownEttin Edit is closing or stopping the plugin. No argument.

Documents

PythonJavaScriptWhat it does
active()activeDocument()The document in the tab that has focus.
documents()documents()Every open document, in tab order.
open_file(path)openFile(path)Opens a file, or shows it if it's already open.
new_document(text="", language=None)newDocument(text, language)Opens a new tab. language is a name from the Language menu, such as "JSON".

A Document has these properties, read when you got it (refresh() updates them): id, title, path (None/null for a new tab), language, modified, read_only/readOnly, length, line_count/lineCount, encoding, line_ending/lineEnding and caret (line and column of the main caret) and caret_offset / caret.offset (its text position).

PythonJavaScriptWhat it does
get_text(start=None, end=None), textgetText(start, end)The whole text, or part of it.
set_text(text), text = ...setText(text)Replaces the whole text.
replace(start, end, text)replace(start, end, text)Replaces part of the text.
insert(text)insert(text)Types text at every caret, replacing what is selected.
selections()getSelections()Each selection: start, end, anchor, head and text. The main one is first.
selected_text()getSelectedText()All selected text, joined with new lines.
replace_selections(text_or_list)replaceSelections(textOrArray)Replaces each selection with the same text, or one string per selection.
select(start, end=None)select(start, end)Selects a range, or moves the caret.
select_ranges([(start, end), ...])selectRanges([[start, end], ...])Makes several selections.
goto(line, column=1)goTo(line, column)Moves the caret and scrolls to it.
save()save()Saves. Asks for a name if the tab has none. Returns whether it saved.
activate()activate()Shows the tab.
close()close()Closes the tab. Asks first if there are unsaved changes.

Each edit is one undo step, so Undo reverses it. Editing a read-only document raises an error.

Messages, input and more

PythonJavaScriptWhat it does
message(text, kind="info")message(text, kind)Shows a short message. kind is info, warning or error.
prompt(text, value="", title=None)prompt(text, {value, title})Asks for a line of text. Returns None/null if cancelled.
set_clipboard(text)setClipboard(text)Copies text.
run_action(action)runAction(action)Runs one of Ettin Edit's own commands (see below).
ui_language()uiLanguage()The language Ettin Edit's menus are in, like "en" or "de" (see below).
log(*values)log(...values)Writes a line to the plugin log.

run_action takes the name of an Ettin Edit command, such as "Duplicate", "SelectAll", "Save", "FindNext" or "ToggleWordWrap". Commands that need options take an object, such as {"SortLines": {"kind": "IgnoreCase", "desc": false}} or {"ConvertCase": "Upper"}. The names are the ones in Ettin Edit's src/actions.rs.

Translating your plugin

Ettin Edit doesn't translate plugins, but it tells them which language its own menus are in, so a plugin can pick its own wording. ui_language() / uiLanguage() returns a language code such as "en", "de" or "pt-BR". Keep your strings in the plugin, with English as the fallback:

from ettin import active, command, message, ui_language, run

TEXT = {
    "en": {"title": "Count Words", "result": "{} words"},
    "de": {"title": "Wörter zählen", "result": "{} Wörter"},
}
lang = ui_language()
strings = TEXT.get(lang) or TEXT.get(lang.split("-")[0]) or TEXT["en"]

@command(strings["title"])
def count():
    message(strings["result"].format(len(active().text.split())))

run()

Command titles are set when the plugin starts. If the user changes the language in Preferences, the new titles appear after Plugins > Reload Plugins or the next start; messages that call ui_language() when they run follow the change straight away.

Panels

A panel is a side or bottom panel that your plugin describes as a list of items. Ettin Edit draws it. When the user clicks or changes something, your handler is called.

from ettin import ui

ettin.show_panel("todo", "To Do", [
    ui.input("task", hint="New task"),
    ui.button("add", "Add"),
    ui.table("list", ["Task", "Done"], [["Write docs", "no"]]),
])

@ettin.on_panel("todo")
def todo(event):
    if event["item"] == "add":
        ettin.message("Adding " + event["values"]["task"])
const { ui } = ettin;
await ettin.showPanel('todo', {
  title: 'To Do',
  items: [ui.input('task', { hint: 'New task' }), ui.button('add', 'Add')],
});
ettin.onPanel('todo', (e) => {
  if (e.item === 'add') ettin.message(`Adding ${e.values.task}`);
});

Calling show_panel again with the same id updates the panel in place, keeping where it is scrolled to; pass scroll_to_top=True (scrollToTop: true in JavaScript) to go back to the start, for example when the panel now shows something else. position is "right" (the default) or "bottom". close_panel(id) / closePanel(id) closes it.

Items:

HelperJSONNotes
ui.heading(text){"type": "heading", "text"}
ui.label(text, weak, mono){"type": "label", "text", "weak", "mono"}weak dims it; mono uses the code font.
ui.separator(){"type": "separator"}
ui.button(id, label){"type": "button", "id", "label"}Sends click.
ui.input(id, label, value, hint, multiline){"type": "input", ...}Sends submit when Enter is pressed.
ui.checkbox(id, label, value){"type": "checkbox", ...}Sends change with true or false.
ui.select(id, options, value, label){"type": "select", ...}A drop-down list. Sends change with the option.
ui.row(*items){"type": "row", "items"}Puts items side by side.
ui.tree(id, nodes, selected){"type": "tree", "id", "nodes", "selected"}Sends select with the node's id. selected (optional) is a node id to highlight; when it changes, the tree opens to it and scrolls it into view. In JavaScript: ui.tree(id, nodes, { selected }).
ui.node(label, id, detail, children, open){"label", "id", "detail", "children", "open"}A tree node. detail is dimmed text after the label.
ui.table(id, columns, rows){"type": "table", "id", "columns", "rows"}Click a header to sort. Sends select with the row's index in your rows.
ui.markdown(text, id, base, doc, line){"type": "markdown", "id", "text", "base", "doc", "line"}Markdown, drawn like the user manual: headings, lists, tables, quotes, code blocks with a Copy button, links. Web links open in the browser and #heading links scroll to the heading; any other link sends link with the link as value. id is optional. base (1.9) is the folder images with relative paths are in; without it, only the descriptions of images are shown. doc (1.9, a document or its id) makes the panel scroll along with that tab, and line is the tab's line (from 0) the text starts on, if you left some out at the top. In JavaScript: ui.markdown(text, { id, base, doc, line }). Needs Ettin Edit 1.5.

The handler gets: item (the item's id), event (click, change, submit, select, link or close), value, and values (every input, checkbox and select, by id). close means the user closed the panel.

A Markdown panel that follows the text, as the Markdown Preview sample does it, needs only a few lines:

@ettin.on("changed")
def changed(doc):
    folder = os.path.dirname(doc.path) if doc.path else None
    ettin.show_panel("preview", "Preview",
                     [ui.markdown(doc.get_text(), base=folder, doc=doc)])

Sending the same id again updates the panel and keeps its scroll position, so the preview doesn't jump while you type. With doc, the panel follows the tab's scrolling instead, and it only moves when the tab scrolls or the text changes, so the reader can still scroll it by hand.

Updating a panel keeps what the user typed in a field, unless you send a different value for it.

The protocol

You can write a plugin in another language by speaking the protocol directly. Ettin Edit starts main and sends JSON-RPC 2.0 messages on its standard input, one per line, UTF-8. The plugin sends requests and notifications on its standard output, one per line. Standard error goes to the log. Python plugins are run with python3 -u main.py and JavaScript plugins with node main.js, in the plugin's folder.

Ettin Edit sends these notifications:

  • initialize {plugin, ettin, api, language}. Always first. api is 1. language is the interface language, like en or de.
  • command {id}.
  • event {event, doc}.
  • panel {panel, item, event, value, values}.
  • shutdown {}. Finish within a second, or the plugin is stopped.

The plugin can call these methods. doc is a document id; it defaults to the active tab.

MethodParamsResult
commands.registerid, title, shortcut?, icon?{shortcut, warning}
events.subscribeevents: [names]
documents.list / documents.active / documents.infodoc?document info
documents.openpathdocument info
documents.newtext?, language?document info
documents.activate / documents.closedoc?
documents.savedoc?true if saved
text.getdoc?, start?, end?string
text.setdoc?, text
text.replacedoc?, start, end, text
text.insertdoc?, text
selection.getdoc?[{start, end, anchor, head, text}]
selection.setdoc?, ranges: [[start, end]]
selection.replacedoc?, text or texts
editor.gotodoc?, line, column?
editor.runActionaction
ui.messagetext, kind?
ui.promptprompt, value?, title?string or null
clipboard.settext
app.languagethe interface language, like "de"
panel.showid, title?, items, position?
panel.closeid

Notifications the plugin can send: log {text, level?} and error {message}, which also shows a short message to the user.

Files, folders and the command line

The settings folder

Ettin Edit keeps everything it remembers in one folder:

  • Linux: ~/.config/EttinEdit (or $XDG_CONFIG_HOME/EttinEdit if you set XDG_CONFIG_HOME)
  • Windows: %APPDATA%\EttinEdit, usually C:\Users\<you>\AppData\Roaming\EttinEdit
In itWhat it holds
settings.jsonYour preferences, recent files, saved macros, changed shortcuts, and the schemas picked for XML files
toolbar.jsonYour toolbar layout, once you've changed it
session.jsonThe tabs that were open, with their carets, encodings and split view
backup/Backups of unsaved changes, so they survive a crash
themes/Every theme as a .tmTheme file (Themes). .builtin-themes.json tracks which built-in themes you haven't edited.
languages/Your own languages (Languages)
api/Your own completion lists (Languages)
translations/Your own translations, one .ftl file per language, and an English copy to start from (Translations)
plugins/Your plugins, one folder each (Using plugins). .sdk/ holds the plugin SDKs, kept up to date by Ettin Edit.
instance.jsonHow a second Ettin Edit finds the running one

The Open … Folder commands in the Theme, Language and Plugins menus, and Open Translations Folder in Preferences, open these folders for you, creating them if needed.

Backing up or moving your settings

Close Ettin Edit and copy the whole folder. To start afresh, close Ettin Edit and rename the folder; Ettin Edit makes a new one with the defaults next time it starts.

The command line

ettin-edit [--multi-instance] [file ...]
  • Each file opens in a tab. A file that can't be opened, for example because it doesn't exist, is reported and skipped.
  • If Ettin Edit is already running, the files open in its window (unless Settings > Single Window is off).
  • --multi-instance (or -multiInst, as in Notepad++) always starts a new window.

On Windows, the installer can add Ettin Edit to the PATH so this works in any terminal. On Linux the packages put ettin-edit on the PATH.

Plugins' environment

Plugins run as separate programs. They get the ETTIN_VERSION environment variable with Ettin Edit's version; see Writing plugins.

Troubleshooting and FAQ

Ettin Edit won't start on Linux

Run ettin-edit in a terminal to see the error. The usual cause is a missing desktop library when using the .tar.gz: install OpenGL and, on X11, libxkbcommon-x11 (sudo apt install libxkbcommon-x11-0 libgl1 on Debian and Ubuntu). The .deb and Arch packages install these for you.

The software centre says "No software repository included" or "Unknown licence"

That's a .deb from before 1.4.0, which had no package information for software centres. Install the latest .deb once: it shows the licence and release notes, and adds the Ettin Edit repository so updates arrive through your software updater. See Getting updates on Debian and Ubuntu.

A file opened in the running window instead of a new one

That's the Single Window setting. Turn it off in the Settings menu, or start Ettin Edit with --multi-instance, to get separate windows. See One window or several.

The text looks garbled: é instead of é

Ettin Edit guessed the wrong encoding. Choose Encoding > Reopen With and pick the right one; for files from older Windows programs it's usually Windows-1252. See Encodings.

Saving says a character can't be saved

The file's encoding can't hold that character (for example € in ISO-8859-1). Choose Encoding > UTF-8 and save again, or remove the character. Nothing is lost while you decide.

Chinese, Japanese or Korean text shows as boxes

Install a CJK font, such as Noto Sans CJK (noto-fonts-cjk on Arch, fonts-noto-cjk on Debian and Ubuntu), and restart Ettin Edit.

A shortcut doesn't work

  • Open the command palette (F1) and find the command: it shows the shortcut actually in use.
  • Check the Shortcut Mapper for a clash with another command or a plugin.
  • Your desktop may be using the keys itself. GNOME, KDE and Windows all reserve a few Ctrl+Alt combinations. Pick another shortcut for the command.

A plugin doesn't run

  1. Open Plugins > Manage Plugins… and look under the plugin's name for the reason.
  2. Check Plugins > Plugin Log for errors.
  3. Make sure Python 3 or Node.js is installed, or set its path in Preferences > Plugins.
  4. If you chose Don't Allow earlier, turn the plugin back on in Manage Plugins.

The update check says it couldn't reach GitHub

Ettin Edit needs to reach api.github.com to check for updates, and github.com to download them. Behind a proxy or firewall that blocks it, check the releases page in your browser instead, and turn off Help > Check for Updates Automatically.

Update Now says the install failed

  • "needs an administrator password, and none was given": the password prompt was closed. Click Try Again.
  • pacman says it couldn't lock the database: another package manager is running (a system update, perhaps). Let it finish, then Try Again.
  • "didn't match its checksum": the download was damaged or changed on the way. Try again later, or download the file from the release page.
  • Can't write to the folder: a .tar.gz or .zip copy unpacked somewhere only an administrator can change (such as /opt) can't replace itself. Download the new version from the release page, or move Ettin Edit to a folder of your own.

The scroll bar settles after resizing a huge file

With word wrap on, resizing the window wraps the lines you can see straight away and the rest of the file in the background, so the window never freezes. In a file with hundreds of thousands of long lines that takes a second or two, and until it finishes the scroll bar's size and the document map can shift a little. The text at the top of the view stays where it is.

I closed a file without saving

If Remember Unsaved Changes on Exit is on (the default), quitting never throws changes away. Closing a single tab does ask first, though, and Don't Save really doesn't save. If the file was saved at some point, your file manager's trash or your backups may still have an older copy.

Where do I report a bug or ask for a feature?

On the issues page. Say which version you have (Help > About Ettin Edit) and which system you use, and attach the plugin log if a plugin is involved.

Is Ettin Edit Notepad++?

No. It's inspired by Notepad++ and shares none of its code; every line was written for Ettin Edit. It's free and open source under the MIT licence.

Who gets the spoon?

Still being decided. Please don't open an issue about it.