From f112de508ba11484cc08150878503877b2c986bc Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sat, 10 Oct 2026 19:08:08 +0100 Subject: [PATCH] feat(notes): commandes sur plusieurs lignes recollees en une seule Fin de ligne en \ (bash), ` (PowerShell) ou ^ (cmd) : la ligne suivante est rattachee, et la commande part sur une ligne - un retour a la ligne tape dans un terminal la lancerait a moitie ecrite. Teste. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 6 ++++++ js/app.js | 17 ++++++++++++++--- js/tests/commands.test.js | 29 +++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e346987..03db378 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1587,6 +1587,12 @@ après chaque `DELETE /attachments/{id}`. Un petit vault sain ne paie rien. (`ssh ••••••••••••.11`), une fin de 6 caracteres ou moins est masquee en entier. Affichage seulement : filtre, copie et remplissage voient le vrai texte. L'oeil re-declenche `input` sur le textarea pour redessiner la liste. + **Lignes continuees** : une ligne finie par `\`, `` ` `` ou `^` se recolle a + la suivante (sans le caractere) - une seule commande, sur UNE ligne, car un + retour a la ligne tape dans un terminal vaut Entree. Ligne vide ou fin du + texte = fin de la commande ; un `#` apres une continuation reste du texte. + Limite : un chemin Windows fini par `\` en fin de ligne passe pour une + continuation. - **Settings search** : `#settingsSearch` filtre les `.setting-row` par texte ; match sur le label de section garde toute la section. Esc dans la search avec query = clear ; Esc vide = ferme Settings. diff --git a/js/app.js b/js/app.js index 3084146..b5e9a28 100644 --- a/js/app.js +++ b/js/app.js @@ -4038,15 +4038,26 @@ const ENTRY_TEMPLATES = { // DECOUPE D'UNE NOTE DE COMMANDES. "# titre" ouvre un groupe, toute autre ligne // non vide est une commande, les lignes vides sont ignorees. Rend // [{group, cmd}] dans l'ordre du texte. Pur : tests/commands.test.js. +// LIGNE CONTINUEE : une ligne finie par \ (bash), ` (PowerShell) ou ^ (cmd) +// se recolle a la suivante, sans le caractere ni le retour a la ligne. Le +// resultat tient sur UNE ligne : tapee dans un terminal, une fin de ligne vaut +// Entree et lancerait une commande a moitie ecrite. Une ligne vide ou la fin du +// texte termine la commande en cours. function parseCommandNote(text) { const out = []; let group = ''; + let pending = ''; + const flush = () => { if (pending) out.push({ group, cmd: pending }); pending = ''; }; for (const raw of String(text || '').split(/\r?\n/)) { const line = raw.trim(); - if (!line) continue; - if (line.startsWith('#')) { group = line.replace(/^#+\s*/, ''); continue; } - out.push({ group, cmd: line }); + if (!line) { flush(); continue; } + if (!pending && line.startsWith('#')) { group = line.replace(/^#+\s*/, ''); continue; } + const cont = /[\\`^]$/.test(line); + const part = cont ? line.slice(0, -1).trimEnd() : line; + pending = pending ? pending + ' ' + part : part; + if (!cont) flush(); } + flush(); return out; } diff --git a/js/tests/commands.test.js b/js/tests/commands.test.js index 8680cfe..32bf2ed 100644 --- a/js/tests/commands.test.js +++ b/js/tests/commands.test.js @@ -36,6 +36,35 @@ test('masque : fin courte masquee en entier, pas d\'espace', () => { assert.equal(T.maskCommand(''), ''); }); +test('lignes continuees (\\, `, ^) : une seule commande, sur une ligne', () => { + const note = [ + '# D', + 'docker run -d \\', + ' -p 8080:80 \\', + ' nginx', + 'Get-Item a `', + ' -Force', + 'dir ^', + ' /s', + ].join('\n'); + const r = T.parseCommandNote(note); + assert.deepEqual(plain(r).map(x => x.cmd), [ + 'docker run -d -p 8080:80 nginx', + 'Get-Item a -Force', + 'dir /s', + ]); + assert.equal(r[0].group, 'D'); +}); + +test('continuation coupee par une ligne vide ou la fin du texte', () => { + assert.deepEqual(plain(T.parseCommandNote('a \\\n\nb')).map(x => x.cmd), ['a', 'b']); + assert.deepEqual(plain(T.parseCommandNote('a \\')).map(x => x.cmd), ['a']); +}); + +test('un "#" apres une continuation fait partie de la commande', () => { + assert.equal(T.parseCommandNote('echo \\\n#x')[0].cmd, 'echo #x'); +}); + test('texte vide ou absent', () => { assert.equal(T.parseCommandNote('').length, 0); assert.equal(T.parseCommandNote(null).length, 0);