diff --git a/web/js/autocompleter.js b/web/js/autocompleter.js index 20d6920..0872260 100644 --- a/web/js/autocompleter.js +++ b/web/js/autocompleter.js @@ -326,7 +326,6 @@ app.registerExtension({ $el("td", [ $el("label", { for: id.replaceAll(".", "-"), - textContent: name, }), ]), $el("td", [ @@ -483,12 +482,36 @@ app.registerExtension({ }, onchange: (event) => { const value = +event.target.value; - TextAreaAutoComplete.suggestionCount = value;; + TextAreaAutoComplete.suggestionCount = value; localStorage.setItem(id + ".SuggestionCount", TextAreaAutoComplete.suggestionCount); }, }), ] ), + $el( + "label", + { + textContent: "Prompt delimiters: ", + style: { + display: "block", + }, + }, + [ + $el("input", { + type: "text", + value: TextAreaAutoComplete.promptDelimiters, + style: { + width: "80px", + fontFamily: "monospace" + }, + onchange: (event) => { + const delimiters = event.target.value; + TextAreaAutoComplete.promptDelimiters = delimiters; + localStorage.setItem(id + ".PromptDelimiters", TextAreaAutoComplete.promptDelimiters); + }, + }), + ] + ), $el("button", { textContent: "Manage Custom Words", onclick: () => { @@ -526,6 +549,7 @@ app.registerExtension({ TextAreaAutoComplete.insertOnEnter = localStorage.getItem(id + ".InsertOnEnter") !== "false"; TextAreaAutoComplete.lorasEnabled = localStorage.getItem(id + ".ShowLoras") === "true"; TextAreaAutoComplete.suggestionCount = +localStorage.getItem(id + ".SuggestionCount") || 20; + TextAreaAutoComplete.promptDelimiters = localStorage.getItem(id + ".PromptDelimiters") || ',;\"|{}()\n'; }, setup() { async function addEmbeddings() { diff --git a/web/js/common/autocomplete.js b/web/js/common/autocomplete.js index ac5fb1d..c1b7645 100644 --- a/web/js/common/autocomplete.js +++ b/web/js/common/autocomplete.js @@ -356,6 +356,9 @@ export class TextAreaAutoComplete { static replacer = undefined; static lorasEnabled = false; static suggestionCount = 20; + static promptDelimiters = ',;"|{}()\n'; + static #cachedRegex = null; + static #lastDelimiters = ""; /** @type {Record>} */ static groups = {}; @@ -536,15 +539,33 @@ export class TextAreaAutoComplete { #update() { let before = this.helper.getBeforeCursor(); if (before?.length) { - const m = before.match(/([^,;"|{}()\n]+)$/); - if (m) { - before = m[0] - .replace(/^\s+/, "") - .replace(/\s/g, "_") || null; - } else { - before = null; - } - } + // Get delimiters from config or fallback to default + const delims = TextAreaAutoComplete.promptDelimiters || ',;"|{}()\\n'; + + // Re-new regex if delimiters have changed + if (delims !== TextAreaAutoComplete.#lastDelimiters) { + try { + const safeDelims = delims.replace(/]/g, '\\]'); + TextAreaAutoComplete.#cachedRegex = new RegExp(`([^${safeDelims}]+)$`); + TextAreaAutoComplete.#lastDelimiters = delims; + } catch (e) { + console.error("Regex compilation failed:", e); + TextAreaAutoComplete.#cachedRegex = null; + } + } + + if (TextAreaAutoComplete.#cachedRegex) { + const match = before.match(TextAreaAutoComplete.#cachedRegex); + if (match) { + // Normalize: remove leading space and convert interior spaces to underscores + before = match[0].replace(/^\s+/, "").replace(/\s/g, "_") || null; + } else { + before = null; + } + } else { + before = null; + } + } if (!before) { this.#hide();