fix: list continuation ligne complete + autocomplete lazy-load
- 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:
+64
-55
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user