Skip to content

Commit eb6b298

Browse files
committed
refactor!: rename slot → cell throughout the codebase
Eliminates the collision between grigson's "beat slot" concept and the Web Components slot="" attribute. "Cell" also reinforces the CSS Grid metaphor in the HTML renderer. Breaking changes: - Types: ChordSlot→ChordCell, DotSlot→DotCell, BeatSlot→BeatCell, AnnotatedChordSlot→AnnotatedChordCell, AnalysedBeatSlot→AnalysedBeatCell, SlotLayout→CellLayout - Properties: Bar.slots→Bar.cells, TonalityHintItem.beforeSlotIndex→beforeCellIndex, BarLayout.cells, CellLayout.sourceCellIdx, ZoneSpec.cellIndices - CSS part names: part="slot"→part="cell", part="slot bar-start"→part="cell bar-start" - Grammar rules: BeatSlotList→BeatCellList, BeatSlotItem→BeatCellItem, BeatSlot→BeatCell - Tree-sitter: beat_slot→beat_cell - Diagnostic messages: "slot(s)"→"cell(s)"
1 parent 0de0391 commit eb6b298

58 files changed

Lines changed: 618 additions & 563 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/grigson-grille-harmonique-renderer/src/patterns.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export function detectPattern(bar: Bar, activeTSig: TimeSignature): BarPattern {
99
);
1010
}
1111

12-
const chordCount = bar.slots.filter((s) => s.type === 'chord').length;
13-
const hasDots = bar.slots.some((s) => s.type === 'dot');
12+
const chordCount = bar.cells.filter((s) => s.type === 'chord').length;
13+
const hasDots = bar.cells.some((s) => s.type === 'dot');
1414
const isEvenDivision = 4 % chordCount === 0;
1515
const rawBeatsPerChord = isEvenDivision ? 4 / chordCount : 1;
1616

@@ -19,9 +19,9 @@ export function detectPattern(bar: Bar, activeTSig: TimeSignature): BarPattern {
1919
(!hasDots ||
2020
(() => {
2121
for (let i = 0; i < 4; i++) {
22-
const slot = bar.slots[i];
22+
const cell = bar.cells[i];
2323
const expectChord = i % rawBeatsPerChord === 0;
24-
const isChord = slot !== undefined && slot.type === 'chord';
24+
const isChord = cell !== undefined && cell.type === 'chord';
2525
if (expectChord !== isChord) return false;
2626
}
2727
return true;
@@ -37,8 +37,8 @@ export function detectPattern(bar: Bar, activeTSig: TimeSignature): BarPattern {
3737
// Normalize to 4 positions: 'C' for chord, '.' for dot/implicit
3838
const positions: string[] = [];
3939
for (let i = 0; i < 4; i++) {
40-
const slot = bar.slots[i];
41-
positions.push(slot !== undefined && slot.type === 'chord' ? 'C' : '.');
40+
const cell = bar.cells[i];
41+
positions.push(cell !== undefined && cell.type === 'chord' ? 'C' : '.');
4242
}
4343
const pattern = positions.join('');
4444

@@ -58,6 +58,6 @@ export function detectPattern(bar: Bar, activeTSig: TimeSignature): BarPattern {
5858
case 'CCCC':
5959
return '1+1+1+1';
6060
default:
61-
throw new Error(`Unsupported bar slot pattern: ${pattern}`);
61+
throw new Error(`Unsupported bar cell pattern: ${pattern}`);
6262
}
6363
}

packages/grigson-grille-harmonique-renderer/src/render.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import render from './render.js';
1010
const SIG_44: TimeSignature = { numerator: 4, denominator: 4 };
1111
const SIG_34: TimeSignature = { numerator: 3, denominator: 4 };
1212

13-
function chord(root: string): Bar['slots'][number] {
13+
function chord(root: string): Bar['cells'][number] {
1414
return { type: 'chord', chord: { type: 'chord', root, quality: 'major' } };
1515
}
16-
const dot = (): Bar['slots'][number] => ({ type: 'dot' });
16+
const dot = (): Bar['cells'][number] => ({ type: 'dot' });
1717

18-
function bar(...slots: Bar['slots']): Bar {
19-
return { type: 'bar', slots, closeBarline: { kind: 'single' } };
18+
function bar(...cells: Bar['cells']): Bar {
19+
return { type: 'bar', cells, closeBarline: { kind: 'single' } };
2020
}
2121

2222
function simpleSong(bars: Bar[]): Song {
@@ -86,8 +86,8 @@ describe('detectPattern', () => {
8686
expect(() => detectPattern(bar(chord('C')), SIG_34)).toThrow('4/4');
8787
});
8888

89-
it('throws for unsupported slot pattern', () => {
90-
// .C.. — dot-first slot pattern has no valid mapping
89+
it('throws for unsupported cell pattern', () => {
90+
// .C.. — dot-first cell pattern has no valid mapping
9191
expect(() => detectPattern(bar(dot(), chord('G'), dot(), dot()), SIG_44)).toThrow();
9292
});
9393
});

packages/grigson-grille-harmonique-renderer/src/render.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Song, Bar, Chord, TimeSignature, Section, Row, ChordSlot } from 'grigson';
1+
import type { Song, Bar, Chord, TimeSignature, Section, Row, ChordCell } from 'grigson';
22
import {
33
reflowSong,
44
resolvePreset,
@@ -79,11 +79,11 @@ function ariaLabel(chord: Chord, beats: number, isWhole: boolean): string {
7979
// Simile detection
8080
// ---------------------------------------------------------------------------
8181

82-
function slotsEqual(a: Bar, b: Bar): boolean {
83-
if (a.slots.length !== b.slots.length) return false;
84-
for (let i = 0; i < a.slots.length; i++) {
85-
const sa = a.slots[i];
86-
const sb = b.slots[i];
82+
function cellsEqual(a: Bar, b: Bar): boolean {
83+
if (a.cells.length !== b.cells.length) return false;
84+
for (let i = 0; i < a.cells.length; i++) {
85+
const sa = a.cells[i];
86+
const sb = b.cells[i];
8787
if (sa.type !== sb.type) return false;
8888
if (sa.type === 'chord' && sb.type === 'chord') {
8989
if (sa.chord.root !== sb.chord.root) return false;
@@ -112,9 +112,9 @@ function rowsOfSection(section: Section): Row[] {
112112
interface ZoneSpec {
113113
lineParts: string[];
114114
chordParts: string[];
115-
// Maps each chordParts entry to a chord slot index. Defaults to [0,1,2,...].
116-
// Allows a slot to be rendered in multiple positions (e.g. 1+2+1 duplicates the middle chord into N and S).
117-
slotIndices?: number[];
115+
// Maps each chordParts entry to a chord cell index. Defaults to [0,1,2,...].
116+
// Allows a cell to be rendered in multiple positions (e.g. 1+2+1 duplicates the middle chord into N and S).
117+
cellIndices?: number[];
118118
}
119119

120120
const PATTERN_ZONES: Record<BarPattern, ZoneSpec> = {
@@ -144,7 +144,7 @@ const PATTERN_ZONES: Record<BarPattern, ZoneSpec> = {
144144
// Beat order: W | N+S | E. Rendered as four quadrants with the spanning chord duplicated into N and S.
145145
lineParts: ['line line-diag', 'line line-anti'],
146146
chordParts: ['chord chord-left', 'chord chord-top', 'chord chord-bottom', 'chord chord-right'],
147-
slotIndices: [0, 1, 1, 2],
147+
cellIndices: [0, 1, 1, 2],
148148
},
149149
'1+1+2': {
150150
// Beat order: W (left) | N (top) | S+E (br). "/" splits W+N from S+E; "\" half splits W from N.
@@ -180,7 +180,7 @@ function renderBar(
180180
mode: 'unicode' | 'ascii',
181181
prevBar: Bar | null,
182182
): string {
183-
const isSimile = prevBar !== null && slotsEqual(bar, prevBar);
183+
const isSimile = prevBar !== null && cellsEqual(bar, prevBar);
184184

185185
if (isSimile) {
186186
return `<div part="bar bar-simile"><span part="chord chord-simile" aria-label="repeat bar">%</span></div>`;
@@ -189,20 +189,20 @@ function renderBar(
189189
const pattern = detectPattern(bar, activeTSig);
190190
const spec = PATTERN_ZONES[pattern];
191191
const beats = PATTERN_BEATS[pattern];
192-
const chordSlots = bar.slots.filter((s): s is ChordSlot => s.type === 'chord');
192+
const chordCells = bar.cells.filter((s): s is ChordCell => s.type === 'chord');
193193

194194
const zones = spec.lineParts.map((p) => `<div part="${p}"></div>`).join('');
195195

196196
const chords = spec.chordParts
197197
.map((chordPart, i) => {
198-
const slotIdx = spec.slotIndices ? spec.slotIndices[i] : i;
199-
const slot = chordSlots[slotIdx ?? i];
200-
if (!slot) return '';
201-
const slotBeats = beats[i] ?? 1;
202-
const isWhole = slotBeats === 4;
203-
const label = ariaLabel(slot.chord, slotBeats, isWhole);
204-
const html = renderChordHtml(slot.chord, preset, mode);
205-
const hasBass = slot.chord.bass != null;
198+
const cellIdx = spec.cellIndices ? spec.cellIndices[i] : i;
199+
const cell = chordCells[cellIdx ?? i];
200+
if (!cell) return '';
201+
const cellBeats = beats[i] ?? 1;
202+
const isWhole = cellBeats === 4;
203+
const label = ariaLabel(cell.chord, cellBeats, isWhole);
204+
const html = renderChordHtml(cell.chord, preset, mode);
205+
const hasBass = cell.chord.bass != null;
206206
const partStr = hasBass ? `${chordPart} chord-slash` : chordPart;
207207
return `<span part="${partStr}" aria-label="${label}">${html}</span>`;
208208
})

packages/grigson/documentation/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Grigson source files use the `.chart` extension.
1414
- **Plain text that resembles output.** The pipe character `|` represents a bar line. Time signatures look like time signatures. Chord names are written as you would write them on a lead sheet.
1515
- **Left-aligned, ragged right.** Unlike some chord chart tools that stretch rows to fill the page width, grigson renders rows at their natural width. A bar with four beats takes up twice as much space as a bar with two beats. The space a passage occupies on the page reflects how long it lasts in time.
1616
- **Explicit row layout.** Each line in the source becomes a row in the output. You control the layout by how you arrange your source text.
17-
- **Simple rhythm.** Grigson does not use a rhythm staff or per-chord duration notation. Rhythmic information is conveyed through beat-slot notation (see below).
17+
- **Simple rhythm.** Grigson does not use a rhythm staff or per-chord duration notation. Rhythmic information is conveyed through beat-cell notation (see below).
1818
- **Key per section.** Songs that modulate between sections (e.g. verse in Eb, chorus in Ab) can specify a key for each section independently.
1919

2020
---
@@ -244,13 +244,13 @@ Hints are separated from the beat grid. The `Bar` type has an optional `tonality
244244

245245
```typescript
246246
interface TonalityHintItem {
247-
beforeSlotIndex: number; // hint applies from this beat-slot index onward within the bar
247+
beforeCellIndex: number; // hint applies from this beat-cell index onward within the bar
248248
key: string; // e.g. "Ab major", "D dorian"; "" = reset to home
249249
loc?: SourceRange;
250250
}
251251
```
252252

253-
Tonality hints do not occupy a beat slot — they are a side channel on `Bar`. The `slots` array contains only `ChordSlot` and `DotSlot` entries, as before.
253+
Tonality hints do not occupy a beat cell — they are a side channel on `Bar`. The `cells` array contains only `ChordCell` and `DotCell` entries, as before.
254254

255255
---
256256

@@ -357,7 +357,7 @@ To use the extension during development, open the `packages/vscode-extension` di
357357

358358
## What Grigson Does Not Support (by design)
359359

360-
- **Rhythm notation.** There is no staff, no note durations on individual chords, no ties or triplets beyond what beat-slot notation can express.
360+
- **Rhythm notation.** There is no staff, no note durations on individual chords, no ties or triplets beyond what beat-cell notation can express.
361361
- **Navigation signs.** Coda, Segno, Da Capo, Dal Segno, and Fine are not supported in v1. Use repeat barlines and volta brackets instead, or write the song out in full.
362362
- **Lyrics.** Grigson is a chord chart tool, not a lead sheet tool.
363363
- **Auto-reflow.** Row layout is always controlled explicitly by the source text.

packages/grigson/documentation/cli.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,11 @@ The error points to the exact position in the input (`line:character`).
351351

352352
#### Semantic warning — beat balance
353353

354-
Parse errors catch syntax problems; semantic warnings catch musical logic errors that the parser accepts. A bar with dot slots must have exactly as many slots as the time signature's numerator:
354+
Parse errors catch syntax problems; semantic warnings catch musical logic errors that the parser accepts. A bar with dot cells must have exactly as many cells as the time signature's numerator:
355355

356356
```sh
357357
$ echo '| (4/4) C . . G . |' | grigson validate
358-
<stdin>:1:3: warning: Bar has 5 slots but time signature is 4/4 (expected 4)
358+
<stdin>:1:3: warning: Bar has 5 cells but time signature is 4/4 (expected 4)
359359
$ echo $?
360360
1
361361
```
@@ -368,7 +368,7 @@ $ echo $?
368368

369369
```sh
370370
$ echo '| C | Am | F | G |' | grigson-html-renderer
371-
<div part="song" style="--beat-cols: 16; --min-beat-width: 1.00em"><div part="song-grid"><section part="section" style="display: contents"><div part="row" style="grid-column: 1 / 34"><span part="barline barline-single barline-position-start" aria-hidden="true" style="grid-column: 1"></span><span part="slot bar-start" style="grid-column: 2 / span 7"><span part="chord" aria-label="C, whole bar"><span part="chord-root" aria-hidden="true">C</span></span></span></div></section></div></div>
371+
<div part="song" style="--beat-cols: 16; --min-beat-width: 1.00em"><div part="song-grid"><section part="section" style="display: contents"><div part="row" style="grid-column: 1 / 34"><span part="barline barline-single barline-position-start" aria-hidden="true" style="grid-column: 1"></span><span part="cell bar-start" style="grid-column: 2 / span 7"><span part="chord" aria-label="C, whole bar"><span part="chord-root" aria-hidden="true">C</span></span></span></div></section></div></div>
372372
```
373373

374374
The output is unstyled markup. It can be piped into a file and served alongside the grigson stylesheet, or it can be passed through a normalise/transpose step first:

packages/grigson/documentation/harmonic-analysis.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,11 @@ interface AnnotatedChordSlot {
178178
loc?: SourceRange;
179179
}
180180

181-
type AnalysedBeatSlot = AnnotatedChordSlot | DotSlot;
181+
type AnalysedBeatCell = AnnotatedChordCell | DotCell;
182182

183183
interface AnalysedBar {
184184
type: 'bar';
185-
slots: AnalysedBeatSlot[];
185+
cells: AnalysedBeatCell[];
186186
timeSignature?: TimeSignature;
187187
tonalityHints?: TonalityHintItem[];
188188
closeBarline: Barline;
@@ -227,12 +227,12 @@ interface AnalysedSong {
227227

228228
### Tonality hints
229229

230-
Tonality hints appear as `TonalityHintItem` entries on `Bar.tonalityHints`. The `beforeSlotIndex` field records which chord slot in the bar the hint precedes, enabling correct key-region splitting.
230+
Tonality hints appear as `TonalityHintItem` entries on `Bar.tonalityHints`. The `beforeCellIndex` field records which chord cell in the bar the hint precedes, enabling correct key-region splitting.
231231

232232
```
233233
{Ab major} C Am | F G
234234
235-
hint before slot 0 → C and Am analysed in Ab major
235+
hint before cell 0 → C and Am analysed in Ab major
236236
F and G (next bar, no hint) → same Ab major region continues
237237
```
238238

packages/grigson/documentation/renderer.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,15 @@ The renderer produces a hierarchy of elements, each with a `part` attribute:
9898

9999
<!-- bar 1: 4/4, 2 chords → 2 beats each -->
100100
<!-- time-sig shown because bar.timeSignature is set on this bar -->
101-
<span part="slot" style="grid-column: 2 / span 2">
101+
<span part="cell" style="grid-column: 2 / span 2">
102102
<span part="time-sig">
103103
<!-- Math Bold digits: U+1D7D2 = 𝟒, rendered via GrigsonTimeSig @font-face -->
104104
<span part="time-sig-num">𝟒</span>
105105
<span part="time-sig-den">𝟒</span>
106106
</span>
107107
<span part="chord"><span part="chord-root">C</span></span>
108108
</span>
109-
<span part="slot" style="grid-column: 4 / span 2">
109+
<span part="cell" style="grid-column: 4 / span 2">
110110
<span part="chord">
111111
<span part="chord-root">A<span part="chord-accidental" data-glyph="unicode">♭</span></span>
112112
<span part="chord-quality">m</span>
@@ -140,7 +140,7 @@ The `song-grid` element defines a CSS Grid whose column count equals the longest
140140
</span>
141141
```
142142

143-
#### Dot slot (beat continuation)
143+
#### Dot cell (beat continuation)
144144

145145
```html
146146
<span part="dot" style="grid-column: 5 / span 1">/</span>
@@ -175,7 +175,7 @@ The `song-grid` element defines a CSS Grid whose column count equals the longest
175175
| `barline-endRepeat` || End-repeat barline `:\|\|` |
176176
| `barline-endRepeatStartRepeat` || Turn-around barline `:\|\|:` |
177177
| `barline-repeat-count` | `<span>` | Repeat count label, e.g. "×3", inside an end-repeat barline |
178-
| `slot` | `<span>` | One chord slot; carries `grid-column` positioning |
178+
| `cell` | `<span>` | One chord cell; carries `grid-column` positioning |
179179
| `dot` | `<span>` | A beat-continuation dot rendered as `/` |
180180
| `simile` | `<span>` | Single-bar repeat mark (SMuFL U+E1E7 from Bravura); spans the full bar width |
181181
| `time-sig` | `<span>` | Time signature stacked fraction; uses the `GrigsonTimeSig` @font-face for digit glyphs |
@@ -909,7 +909,7 @@ class MyRenderer {
909909
// section.label — e.g. "Verse", or null if unlabelled
910910
// section.rows — array of Row objects
911911
// row.bars — array of Bar objects
912-
// bar.slots — array of BeatSlot (ChordSlot | DotSlot)
912+
// bar.cells — array of BeatCell (ChordCell | DotCell)
913913
// bar.timeSignature — { numerator, denominator } or undefined
914914
}
915915
}

packages/grigson/documentation/source-locations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const bar = song.sections[0].rows[0].bars[0];
4646
console.log(bar.loc);
4747
// { start: { line: 0, character: 2 }, end: { line: 0, character: 6 } }
4848

49-
console.log(bar.slots[0].loc);
49+
console.log(bar.cells[0].loc);
5050
// { start: { line: 0, character: 2 }, end: { line: 0, character: 4 } }
5151
```
5252

packages/grigson/documentation/testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ The parser is the highest-value layer to test. Tests cover each grammar rule in
4949
expect(parseChord('Cm7')).toEqual({ root: 'C', quality: 'minor', extensions: ['7'] });
5050
expect(parseChord('F#/A#')).toEqual({ root: 'F#', quality: 'major', bass: 'A#' });
5151

52-
// Beat slot notation
52+
// Beat cell notation
5353
expect(parseBar('C . . G')).toEqual([
5454
{ type: 'chord', value: 'C', beats: 3 },
5555
{ type: 'chord', value: 'G', beats: 1 },

0 commit comments

Comments
 (0)