abcls-kak
v0.1.0
Published
ABC notation editing for Kakoune
Maintainers
Readme
ABC Kakoune Plugin
This plugin integrates ABC notation selectors with Kakoune, enabling AST-level pattern matching as native multi-selections.
Features
- AST-based selection of ABC musical elements (notes, chords, rests)
- Selector narrowing and composition
- Integration with kak-lsp for standard LSP features (diagnostics, completions, hover, formatting)
Installation
- Build the bundled LSP server:
cd /path/to/abc_parse
npm install
npm run build:kakThis creates abc-kak/dist/server.js, a self-contained bundle with all dependencies.
- Add to your kakrc:
hook -once global WinSetOption filetype=(abc|abcx) %{
source "/path/to/abc-kak/rc/abc.kak"
}The plugin auto-configures kak-lsp with the bundled server.
Configuration
To customize options, pre-declare them in your kakrc before the plugin is sourced. Kakoune's declare-option is idempotent, so your values are preserved when the plugin loads.
declare-option str abc_client_path "" # Path to abc-kak-client.js (auto-detected)
declare-option str abc_server_path "" # Path to LSP server (auto-detected)
declare-option str abc_socket_path "" # Unix socket path (auto-computed)
declare-option int abc_timeout 5000 # Request timeout in milliseconds
declare-option bool abc_auto_preview false # Open browser preview on file open
declare-option str abc_select_key "h" # Key for select mode (empty to disable)
declare-option str abc_transform_key "k" # Key for transform mode (empty to disable)Commands
Type Selectors
abc-select-chords: Select all chord nodesabc-select-notes: Select all note nodesabc-select-non-chord-notes: Select notes not inside chordsabc-select-chord-notes: Select notes inside chordsabc-select-rests: Select all rest nodes
Rhythm Selectors
abc-select-rhythm: Select all rhythm expressions (e.g., /2, 3, 3/2)abc-select-rhythm-parent: Select notes, chords, rests, or spacers with explicit rhythm
Structure Selectors
abc-select-tune: Select individual tunes (for multi-tune files)
Chord Note Selectors
abc-select-top: Select the top note of each chordabc-select-bottom: Select the bottom note of each chordabc-select-nth-from-top N: Select the Nth note from top (0-indexed)abc-select-all-but-top: Select all notes except the top of each chordabc-select-all-but-bottom: Select all notes except the bottom of each chord
State Management
abc-select-reset: Clear stored cursor node IDs (breaks narrowing chain)
Selector Narrowing
Selectors can be chained to narrow results:
abc-select-chords- Select all chordsabc-select-top- Narrow to top note of each selected chord- (edit as needed)
The narrowing chain is automatically cleared when:
- The buffer is modified
- Selections change (user moves cursor or uses standard Kakoune motions)
Use abc-select-reset to manually clear the narrowing state.
Limitations
- Selectors only work with
.abcfiles, not.abcxfiles - Requires kak-lsp for full LSP integration
- The first Kakoune session to open an ABC file owns the socket; closing that session may affect selectors in other sessions
Testing
Tests use Mocha/Chai with a custom KakouneSession helper that runs Kakoune in headless daemon mode.
Running Tests
# From monorepo root
npm test -w abc-kak
# Or from abc-kak directory
npm testHow It Works
Because Kakoune requires a TTY for its UI, we cannot run it directly for automated testing. Instead, we use a headless daemon pattern:
- Start a Kakoune daemon:
kak -d -s <session> - Send commands via:
kak -p <session> - Capture results via a named FIFO (blocking read for synchronization)
The KakouneSession class in test/helpers/kakoune-session.ts wraps this pattern:
import { KakouneSession } from './helpers/kakoune-session';
describe('my test', () => {
let kak: KakouneSession;
let testFile: string;
beforeEach(() => {
kak = new KakouneSession();
testFile = `/tmp/test-${kak.session}.abc`;
kak.start();
});
afterEach(() => {
kak.cleanup();
unlinkSync(testFile);
});
it('selects a note', () => {
writeFileSync(testFile, 'X:1\nK:C\nCDEF\n');
kak.edit(testFile);
// executeAndQuery combines key execution with state query
// in a single call to preserve selection state
const selection = kak.executeAndQuery('gg2j', '$kak_selection');
expect(selection).to.equal('C');
});
});Key Methods
start()/cleanup()- session lifecycleedit(path)- open a file (sets current buffer context)executeKeys(keys)- run execute-keys in buffer contextexecuteAndQuery(keys, expr)- execute keys and query state in a single callgetSelection()/getSelections()/getSelectionsDesc()- query helpers
Legacy kak-spec Tests
The spec/ directory contains older kak-spec tests. To run them:
kak-spec spec/*.kak-spec