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 before = ta.value.slice(0, start);
|
||||||
var after = ta.value.slice(end);
|
var after = ta.value.slice(end);
|
||||||
|
|
||||||
// Smart insertion: if we matched a prefix, replace it
|
// Lazy-load detectContext for smart insertion
|
||||||
var lineStart = before.lastIndexOf('\n') + 1;
|
import('/static/js/autocomplete.js').then(function(m) {
|
||||||
var lineBefore = before.slice(lineStart);
|
var lineStart = before.lastIndexOf('\n') + 1;
|
||||||
var ctx = detectContext(ta.value, start);
|
var ctx = m.detectContext(ta.value, start);
|
||||||
|
|
||||||
if (ctx.type === 'wikilink') {
|
if (ctx.type === 'wikilink') {
|
||||||
// Replace [[partial with [[filename]]
|
var bracketPos = before.lastIndexOf('[[');
|
||||||
var bracketPos = before.lastIndexOf('[[');
|
if (bracketPos >= 0) {
|
||||||
if (bracketPos >= 0) {
|
before = before.slice(0, bracketPos) + '[[' + item.insert;
|
||||||
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;
|
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);
|
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();
|
hideAutocomplete();
|
||||||
ta.focus();
|
ta.focus();
|
||||||
markDirty();
|
markDirty();
|
||||||
autoHeight();
|
autoHeight();
|
||||||
updateLineNumbers();
|
updateLineNumbers();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerAutocomplete() {
|
function triggerAutocomplete() {
|
||||||
var result = suggest(ta.value, ta.selectionStart);
|
// Lazy-load the autocomplete module on first use
|
||||||
if (result.async) {
|
var loadAndTrigger = function() {
|
||||||
// Wikilink: fetch file list
|
|
||||||
import('/static/js/autocomplete.js').then(function(m) {
|
import('/static/js/autocomplete.js').then(function(m) {
|
||||||
m.searchWikilinks(result.partial || '', function(items) {
|
var result = m.suggest(ta.value, ta.selectionStart);
|
||||||
showAutocomplete(items, 'Wikilinks');
|
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 = {
|
loadAndTrigger();
|
||||||
mermaid: 'Mermaid', code: 'Code', fence_open: 'Langage',
|
|
||||||
frontmatter: 'Frontmatter', markdown: 'Markdown'
|
|
||||||
};
|
|
||||||
showAutocomplete(result.items, ctxLabels[result.context] || result.context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCaretCoordinates(textarea) {
|
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(); }
|
else if (e.key === 'Escape') { e.preventDefault(); hideAutocomplete(); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Alt+\ : force autocomplete
|
// Alt+\ : force autocomplete (key may be '\' or 'Backslash' depending on browser)
|
||||||
if (e.altKey && !e.ctrlKey && !e.metaKey && e.key === '\\') {
|
if (e.altKey && !e.ctrlKey && !e.metaKey && (e.key === '\\' || e.key === 'Backslash')) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
triggerAutocomplete();
|
triggerAutocomplete();
|
||||||
return;
|
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 before = ta.value.slice(0, ta.selectionStart);
|
||||||
var after = ta.value.slice(ta.selectionEnd);
|
var after = ta.value.slice(ta.selectionEnd);
|
||||||
var lineStart = before.lastIndexOf('\n') + 1;
|
var lineStart = before.lastIndexOf('\n') + 1;
|
||||||
var currentLine = before.slice(lineStart);
|
// Reconstruct FULL current line (before cursor + after cursor until newline)
|
||||||
var indent = (currentLine.match(/^(\s*)/) || [''])[0];
|
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
|
// Ordered list: 1. 2. 3. etc
|
||||||
var olMatch = currentLine.match(/^(\s*)(\d+)\.\s/);
|
var olMatch = fullLine.match(/^(\s*)(\d+)\.\s/);
|
||||||
// Unordered list: - * +
|
// Unordered list: - * +
|
||||||
var ulMatch = currentLine.match(/^(\s*)([-*+])\s/);
|
var ulMatch = fullLine.match(/^(\s*)([-*+])\s/);
|
||||||
// Task checkbox: - [ ] or - [x]
|
// Task checkbox: - [ ] or - [x]
|
||||||
var taskMatch = currentLine.match(/^(\s*)([-*+])\s+\[([ xX])\]\s/);
|
var taskMatch = fullLine.match(/^(\s*)([-*+])\s+\[([ xX])\]\s/);
|
||||||
|
|
||||||
if (taskMatch) {
|
if (taskMatch) {
|
||||||
var afterTaskTrim = currentLine.slice(taskMatch[0].length).trim();
|
var textAfterMarker = fullLine.slice(taskMatch[0].length);
|
||||||
if (afterTaskTrim.length === 0) {
|
// Only continue if cursor is at or after the marker text
|
||||||
// Empty checkbox: break list (remove this line)
|
if (cursorInLine < taskMatch[0].length) return; // cursor in prefix, let browser handle
|
||||||
|
if (textAfterMarker.trim().length === 0) {
|
||||||
|
// Empty checkbox: break list
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
ta.value = before.slice(0, lineStart) + after;
|
ta.value = before.slice(0, lineStart) + after.slice(restOfLine.length);
|
||||||
ta.setSelectionRange(lineStart, lineStart);
|
ta.setSelectionRange(lineStart, lineStart);
|
||||||
} else {
|
} else {
|
||||||
// Continue checkbox (empty, unchecked)
|
// Continue checkbox
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
ta.value = before + '\n' + indent + taskMatch[2] + ' [ ] ';
|
ta.value = before + '\n' + indent + taskMatch[2] + ' [ ] ';
|
||||||
ta.setSelectionRange(ta.value.length, ta.value.length);
|
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();
|
markDirty(); autoHeight(); updateLineNumbers();
|
||||||
return;
|
return;
|
||||||
} else if (olMatch) {
|
} else if (olMatch) {
|
||||||
|
if (cursorInLine < olMatch[0].length) return;
|
||||||
// Auto-increment ordered list
|
// Auto-increment ordered list
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var num = parseInt(olMatch[2]) + 1;
|
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();
|
markDirty(); autoHeight(); updateLineNumbers();
|
||||||
return;
|
return;
|
||||||
} else if (ulMatch) {
|
} else if (ulMatch) {
|
||||||
var afterTrim = currentLine.slice(ulMatch[0].length).trim();
|
if (cursorInLine < ulMatch[0].length) return;
|
||||||
if (afterTrim.length === 0) {
|
var textAfter = fullLine.slice(ulMatch[0].length);
|
||||||
// Empty bullet: remove it and break list
|
if (textAfter.trim().length === 0) {
|
||||||
|
// Empty bullet: break list
|
||||||
e.preventDefault();
|
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);
|
ta.setSelectionRange(lineStart, lineStart);
|
||||||
} else {
|
} else {
|
||||||
// Continue bullet
|
// Continue bullet
|
||||||
|
|||||||
Reference in New Issue
Block a user