From daf56eb2ce6c2358ca8feba0d868ce62d85f8c5c Mon Sep 17 00:00:00 2001 From: newtextdoc1111 Date: Sat, 3 May 2025 15:11:11 +0900 Subject: [PATCH] - Refactor autocomplete and similar tags logic to use new normalization functions - Minor improved autocomplete behavior --- web/js/autocomplete.js | 31 ++++++++++++++++++++----------- web/js/similar-tags.js | 13 ++++--------- web/js/utils.js | 35 +++++++++++++++++++---------------- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/web/js/autocomplete.js b/web/js/autocomplete.js index 7943307..e5de355 100644 --- a/web/js/autocomplete.js +++ b/web/js/autocomplete.js @@ -1,10 +1,10 @@ import { autoCompleteData } from './data.js'; import { - escapeParentheses, formatCountHumanReadable, hiraToKata, kataToHira, - swapUnderscoresAndSpaces + normalizeTagToInsert, + normalizeTagToSearch, } from './utils.js'; import { settingValues } from './settings.js'; @@ -119,7 +119,6 @@ class AutocompleteUI { // Get ComfyUI canvas scale if available, otherwise default to 1 const scale = window.app?.canvas?.ds?.scale ?? 1.0; - console.debug(`Canvas scale: ${scale}`); // Initial desired position: below the current text line where the caret is. let topPosition = elOffset.top - (elScroll.top * scale) + ((caretTop - elOffset.top) + caretLineHeight) * scale; @@ -542,7 +541,7 @@ function findCompletionCandidates(query) { const addedTags = new Set(); // Keep track of added tags to avoid duplicates // Generate Hiragana/Katakana variations if applicable - const queryVariations = new Set([lowerQuery, swapUnderscoresAndSpaces(lowerQuery)]); + const queryVariations = new Set([lowerQuery, normalizeTagToSearch(lowerQuery)]); const kataQuery = hiraToKata(lowerQuery); if (kataQuery !== lowerQuery) { queryVariations.add(kataQuery); @@ -617,9 +616,13 @@ function getCurrentPartialTag(inputElement) { const text = inputElement.value; const cursorPos = inputElement.selectionStart; - // Find the last comma before the cursor + // Find the last newline or comma before the cursor + const lastNewLine = text.lastIndexOf('\n', cursorPos - 1); const lastComma = text.lastIndexOf(',', cursorPos - 1); - const start = lastComma === -1 ? 0 : lastComma + 1; + + // Get the position of the last separator (newline or comma) before cursor + const lastSeparator = Math.max(lastNewLine, lastComma); + const start = lastSeparator === -1 ? 0 : lastSeparator + 1; // Extract the text between the last comma (or start) and the cursor const partial = text.substring(start, cursorPos).trimStart(); @@ -645,17 +648,22 @@ function insertTag(inputElement, tagToInsert) { const start = lastSeparator === -1 ? 0 : lastSeparator + 1; // Process the tag: swap underscores/spaces and escape parentheses - const processedTag = swapUnderscoresAndSpaces(tagToInsert); - const normalizedTag = escapeParentheses(processedTag); + const normalizedTag = normalizeTagToInsert(tagToInsert); // Find the start of the word/tag being typed (skip leading whitespace after separator) const currentWordStart = text.substring(start, cursorPos).search(/\S|$/) + start; // Find the end of the word/tag at the cursor position, stopping at comma, newline, or end of string. // Match non-whitespace, non-comma, non-newline characters. - const currentWordEndMatch = text.substring(cursorPos).match(/^([^\s,\n]*)/); // Changed regex to exclude \n + const currentWordEndMatch = text.substring(cursorPos).match(/^([^\s,\n]*)/); // currentWordEnd is the position *after* the matched word part. - const currentWordEnd = currentWordEndMatch ? cursorPos + currentWordEndMatch[1].length : cursorPos; // Use group 1 + // const currentWordEnd = currentWordEndMatch ? cursorPos + currentWordEndMatch[1].length : cursorPos; + let currentWordEnd = cursorPos; + + // If the match was found and the cursor is within the matched word, extend currentWordEnd to include it. + if(currentWordEndMatch && normalizedTag.lastIndexOf(currentWordEndMatch[1]) !== -1){ + currentWordEnd = cursorPos + currentWordEndMatch[1].length; + } // The range to replace is from the start of the current partial tag // up to the end of the word segment at the cursor. @@ -668,7 +676,8 @@ function insertTag(inputElement, tagToInsert) { const prefix = needsSpaceBefore ? ' ' : ''; // Standard separator (comma + space) - const suffix = ', '; + const needsSuffixAfter = text[replaceEnd] !== ',' + const suffix = needsSuffixAfter ? ', ' : ''; // Text to insert (including prefix and suffix) const textToInsertWithAffixes = prefix + normalizedTag + suffix; diff --git a/web/js/similar-tags.js b/web/js/similar-tags.js index 609ca22..c382a11 100644 --- a/web/js/similar-tags.js +++ b/web/js/similar-tags.js @@ -2,12 +2,8 @@ import { settingValues } from './settings.js'; import { autoCompleteData } from './data.js'; import { - hiraToKata, - kataToHira, - formatCountHumanReadable, - swapUnderscoresAndSpaces, - escapeParentheses, - unescapeParentheses + normalizeTagToSearch, + normalizeTagToInsert } from './utils.js'; // --- SimilarTags UI Class --- @@ -396,7 +392,7 @@ function getCurrentTag(inputElement) { if (!tag) return null; // Process the tag: swap underscores/spaces and unescape parentheses - const normalizedTag = unescapeParentheses(swapUnderscoresAndSpaces(tag)); // Use helper functions + const normalizedTag = normalizeTagToSearch(tag); return normalizedTag; } @@ -448,8 +444,7 @@ function insertTag(inputElement, tagToInsert) { effectiveEndPos--; } - // Prepare the tag to be inserted (escape parentheses, replace underscores) - const normalizedTag = escapeParentheses(swapUnderscoresAndSpaces(tagToInsert)); + const normalizedTag = normalizeTagToInsert(tagToInsert); // Text before the insertion point (end of the current tag) const textBefore = text.substring(0, effectiveEndPos); diff --git a/web/js/utils.js b/web/js/utils.js index d8b7a50..ce2a5d3 100644 --- a/web/js/utils.js +++ b/web/js/utils.js @@ -54,22 +54,6 @@ export function formatCountHumanReadable(num) { return (num / si[i].value).toFixed(1).replace(rx, "$1") + si[i].symbol; } -/** - * Swaps underscores and spaces in a given string. - * Example: "hello_world example" becomes "hello world_example" - * @param {string} str The input string. - * @returns {string} The string with underscores and spaces swapped. - */ -export function swapUnderscoresAndSpaces(str) { - if (!str) return str; - // Use a temporary placeholder to avoid conflicts during replacement - const tempPlaceholder = "__TEMP_SWAP__"; - return str - .replace(/_/g, tempPlaceholder) // Replace underscores with placeholder - .replace(/ /g, "_") // Replace spaces with underscores - .replace(new RegExp(tempPlaceholder, 'g'), " "); // Replace placeholder with spaces -} - /** * Escapes parentheses in a string for use in prompts. * Replaces '(' with '\(' and ')' with '\)'. @@ -94,6 +78,25 @@ export function unescapeParentheses(str) { return str.replace(/\\\(/g, '(').replace(/\\\)/g, ')'); } +/** + * Normalizes a tag string for input. + * @param {string} str + * @returns + */ +export function normalizeTagToSearch(str) { + if(!str) return str; + return unescapeParentheses(str.replace(/ /g, "_")); +} + +/** + * Normalizes a tag string for input. + * @param {string} str + * @returns + */ +export function normalizeTagToInsert(str) { + return escapeParentheses(str.replace(/_/g, " ")); +} + // --- End String Helper Functions --- // Function to load a CSS file