diff --git a/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js b/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js index a59e584c26d..67ff7fe22d2 100644 --- a/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js +++ b/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js @@ -1,36 +1,69 @@ -// Stable Diffusion WebUI - Bracket checker -// By Hingashi no Florin/Bwin4L & @akx +// Stable Diffusion WebUI - Bracket Checker +// By @Bwin4L, @akx, @w-e-w, @Haoming02 // Counts open and closed brackets (round, square, curly) in the prompt and negative prompt text boxes in the txt2img and img2img tabs. -// If there's a mismatch, the keyword counter turns red and if you hover on it, a tooltip tells you what's wrong. +// If there's a mismatch, the keyword counter turns red, and if you hover on it, a tooltip tells you what's wrong. + +function checkBrackets(textArea, counterElem) { + const pairs = [ + ['(', ')', 'round brackets'], + ['[', ']', 'square brackets'], + ['{', '}', 'curly brackets'] + ]; -function checkBrackets(textArea, counterElt) { const counts = {}; - textArea.value.matchAll(/(? { - counts[bracket[1]] = (counts[bracket[1]] || 0) + 1; - }); - const errors = []; - - function checkPair(open, close, kind) { - if (counts[open] !== counts[close]) { - errors.push( - `${open}...${close} - Detected ${counts[open] || 0} opening and ${counts[close] || 0} closing ${kind}.` - ); + const errors = new Set(); + let i = 0; + + while (i < textArea.value.length) { + let char = textArea.value[i]; + let escaped = false; + while (char === '\\' && i + 1 < textArea.value.length) { + escaped = !escaped; + i++; + char = textArea.value[i]; + } + + if (escaped) { + i++; + continue; + } + + for (const [open, close, label] of pairs) { + if (char === open) { + counts[label] = (counts[label] || 0) + 1; + } else if (char === close) { + counts[label] = (counts[label] || 0) - 1; + if (counts[label] < 0) { + errors.add(`Incorrect order of ${label}.`); + } + } + } + + i++; + } + + for (const [open, close, label] of pairs) { + if (counts[label] == undefined) { + continue; + } + + if (counts[label] > 0) { + errors.add(`${open} ... ${close} - Detected ${counts[label]} more opening than closing ${label}.`); + } else if (counts[label] < 0) { + errors.add(`${open} ... ${close} - Detected ${-counts[label]} more closing than opening ${label}.`); } } - checkPair('(', ')', 'round brackets'); - checkPair('[', ']', 'square brackets'); - checkPair('{', '}', 'curly brackets'); - counterElt.title = errors.join('\n'); - counterElt.classList.toggle('error', errors.length !== 0); + counterElem.title = [...errors].join('\n'); + counterElem.classList.toggle('error', errors.size !== 0); } function setupBracketChecking(id_prompt, id_counter) { - var textarea = gradioApp().querySelector("#" + id_prompt + " > label > textarea"); - var counter = gradioApp().getElementById(id_counter); + const textarea = gradioApp().querySelector(`#${id_prompt} > label > textarea`); + const counter = gradioApp().getElementById(id_counter); if (textarea && counter) { - textarea.addEventListener("input", () => checkBrackets(textarea, counter)); + onEdit(`${id_prompt}_BracketChecking`, textarea, 400, () => checkBrackets(textarea, counter)); } }