fix: list continuation ligne complete + autocomplete lazy-load
CI / lint (push) Failing after 2s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / e2e (push) Has been skipped
CI / security (push) Failing after -8s

- Listes: reconstruit fullLine (before+after) pour matcher regex milieu de ligne
- curseur dans le prefixe → laisse le navigateur gerer (pas d'interception)
- Autocomplete: suggest/detectContext charges via import() dynamique
- Alt+Backslash gere les deux variantes de key (\ et Backslash)
This commit is contained in:
2026-06-16 10:29:41 -04:00
parent 36c1546098
commit 4379f0c844
+64 -55
View File
@@ -1703,55 +1703,56 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
var before = ta.value.slice(0, start);
var after = ta.value.slice(end);
// Smart insertion: if we matched a prefix, replace it
var lineStart = before.lastIndexOf('\n') + 1;
var lineBefore = before.slice(lineStart);
var ctx = detectContext(ta.value, start);
// Lazy-load detectContext for smart insertion
import('/static/js/autocomplete.js').then(function(m) {
var lineStart = before.lastIndexOf('\n') + 1;
var ctx = m.detectContext(ta.value, start);
if (ctx.type === 'wikilink') {
// Replace [[partial with [[filename]]
var bracketPos = before.lastIndexOf('[[');
if (bracketPos >= 0) {
before = before.slice(0, bracketPos) + '[[' + item.insert;
if (ctx.type === 'wikilink') {
var bracketPos = before.lastIndexOf('[[');
if (bracketPos >= 0) {
before = before.slice(0, bracketPos) + '[[' + item.insert;
ta.value = before + after;
var newPos = before.length;
ta.setSelectionRange(newPos, newPos);
}
} else if (ctx.type === 'frontmatter') {
before = before.slice(0, lineStart) + item.insert;
ta.value = before + after;
var newPos = before.length;
ta.setSelectionRange(before.length, before.length);
} else {
ta.value = before + item.insert + after;
var newPos = start + item.insert.length;
ta.setSelectionRange(newPos, newPos);
}
} else if (ctx.type === 'frontmatter') {
// Replace current line with the field
before = before.slice(0, lineStart) + item.insert;
ta.value = before + after;
ta.setSelectionRange(before.length, before.length);
} else {
// Standard insert at cursor
ta.value = before + item.insert + after;
var newPos = start + item.insert.length;
ta.setSelectionRange(newPos, newPos);
}
hideAutocomplete();
ta.focus();
markDirty();
autoHeight();
updateLineNumbers();
hideAutocomplete();
ta.focus();
markDirty();
autoHeight();
updateLineNumbers();
});
}
function triggerAutocomplete() {
var result = suggest(ta.value, ta.selectionStart);
if (result.async) {
// Wikilink: fetch file list
// Lazy-load the autocomplete module on first use
var loadAndTrigger = function() {
import('/static/js/autocomplete.js').then(function(m) {
m.searchWikilinks(result.partial || '', function(items) {
showAutocomplete(items, 'Wikilinks');
});
var result = m.suggest(ta.value, ta.selectionStart);
if (result.async) {
m.searchWikilinks(result.partial || '', function(items) {
showAutocomplete(items, 'Wikilinks');
});
} else if (result.items.length > 0) {
var ctxLabels = {
mermaid: 'Mermaid', code: 'Code', fence_open: 'Langage',
frontmatter: 'Frontmatter', markdown: 'Markdown'
};
showAutocomplete(result.items, ctxLabels[result.context] || result.context);
}
});
} else if (result.items.length > 0) {
var ctxLabels = {
mermaid: 'Mermaid', code: 'Code', fence_open: 'Langage',
frontmatter: 'Frontmatter', markdown: 'Markdown'
};
showAutocomplete(result.items, ctxLabels[result.context] || result.context);
}
};
loadAndTrigger();
}
function getCaretCoordinates(textarea) {
@@ -1786,8 +1787,8 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
else if (e.key === 'Escape') { e.preventDefault(); hideAutocomplete(); }
return;
}
// Alt+\ : force autocomplete
if (e.altKey && !e.ctrlKey && !e.metaKey && e.key === '\\') {
// Alt+\ : force autocomplete (key may be '\' or 'Backslash' depending on browser)
if (e.altKey && !e.ctrlKey && !e.metaKey && (e.key === '\\' || e.key === 'Backslash')) {
e.preventDefault();
triggerAutocomplete();
return;
@@ -1801,24 +1802,30 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
var before = ta.value.slice(0, ta.selectionStart);
var after = ta.value.slice(ta.selectionEnd);
var lineStart = before.lastIndexOf('\n') + 1;
var currentLine = before.slice(lineStart);
var indent = (currentLine.match(/^(\s*)/) || [''])[0];
// Reconstruct FULL current line (before cursor + after cursor until newline)
var afterNewline = after.indexOf('\n');
var restOfLine = afterNewline >= 0 ? after.slice(0, afterNewline) : after;
var fullLine = before.slice(lineStart) + restOfLine;
var cursorInLine = ta.selectionStart - lineStart;
var indent = (fullLine.match(/^(\s*)/) || [''])[0];
// Ordered list: 1. 2. 3. etc
var olMatch = currentLine.match(/^(\s*)(\d+)\.\s/);
var olMatch = fullLine.match(/^(\s*)(\d+)\.\s/);
// Unordered list: - * +
var ulMatch = currentLine.match(/^(\s*)([-*+])\s/);
var ulMatch = fullLine.match(/^(\s*)([-*+])\s/);
// Task checkbox: - [ ] or - [x]
var taskMatch = currentLine.match(/^(\s*)([-*+])\s+\[([ xX])\]\s/);
var taskMatch = fullLine.match(/^(\s*)([-*+])\s+\[([ xX])\]\s/);
if (taskMatch) {
var afterTaskTrim = currentLine.slice(taskMatch[0].length).trim();
if (afterTaskTrim.length === 0) {
// Empty checkbox: break list (remove this line)
var textAfterMarker = fullLine.slice(taskMatch[0].length);
// Only continue if cursor is at or after the marker text
if (cursorInLine < taskMatch[0].length) return; // cursor in prefix, let browser handle
if (textAfterMarker.trim().length === 0) {
// Empty checkbox: break list
e.preventDefault();
ta.value = before.slice(0, lineStart) + after;
ta.value = before.slice(0, lineStart) + after.slice(restOfLine.length);
ta.setSelectionRange(lineStart, lineStart);
} else {
// Continue checkbox (empty, unchecked)
// Continue checkbox
e.preventDefault();
ta.value = before + '\n' + indent + taskMatch[2] + ' [ ] ';
ta.setSelectionRange(ta.value.length, ta.value.length);
@@ -1826,6 +1833,7 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
markDirty(); autoHeight(); updateLineNumbers();
return;
} else if (olMatch) {
if (cursorInLine < olMatch[0].length) return;
// Auto-increment ordered list
e.preventDefault();
var num = parseInt(olMatch[2]) + 1;
@@ -1834,11 +1842,12 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
markDirty(); autoHeight(); updateLineNumbers();
return;
} else if (ulMatch) {
var afterTrim = currentLine.slice(ulMatch[0].length).trim();
if (afterTrim.length === 0) {
// Empty bullet: remove it and break list
if (cursorInLine < ulMatch[0].length) return;
var textAfter = fullLine.slice(ulMatch[0].length);
if (textAfter.trim().length === 0) {
// Empty bullet: break list
e.preventDefault();
ta.value = before.slice(0, lineStart) + '\n' + after.slice(after.indexOf('\n') + 1);
ta.value = before.slice(0, lineStart) + after.slice(restOfLine.length);
ta.setSelectionRange(lineStart, lineStart);
} else {
// Continue bullet