diff --git a/javascript/_utils.js b/javascript/_utils.js index f42cd80..a02cbc4 100644 --- a/javascript/_utils.js +++ b/javascript/_utils.js @@ -309,7 +309,11 @@ function toNgrams(inputArray, size) { ); } -function escapeRegExp(string) { +function escapeRegExp(string, wildcardMatching = false) { + if (wildcardMatching) { + // Escape all characters except asterisks and ?, which should be treated separately as placeholders. + return string.replace(/[-[\]{}()+.,\\^$|#\s]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.'); + } return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string } function escapeHTML(unsafeText) { diff --git a/javascript/ext_chants.js b/javascript/ext_chants.js index 30de964..c32cc85 100644 --- a/javascript/ext_chants.js +++ b/javascript/ext_chants.js @@ -7,7 +7,10 @@ class ChantParser extends BaseTagParser { let tempResults = []; if (tagword !== "<" && tagword !== " x.terms.toLowerCase().includes(searchTerm) || x.name.toLowerCase().includes(searchTerm); + let filterCondition = x => { + let regex = new RegExp(escapeRegExp(searchTerm, true), 'i'); + return regex.test(x.terms.toLowerCase()) || regex.test(x.name.toLowerCase()); + }; tempResults = chants.filter(x => filterCondition(x)); // Filter by tagword } else { tempResults = chants; @@ -51,4 +54,4 @@ PARSERS.push(new ChantParser(CHANT_TRIGGER)); // Add our utility functions to their respective queues QUEUE_FILE_LOAD.push(load); QUEUE_SANITIZE.push(sanitize); -QUEUE_AFTER_CONFIG_CHANGE.push(load); \ No newline at end of file +QUEUE_AFTER_CONFIG_CHANGE.push(load); diff --git a/javascript/ext_embeddings.js b/javascript/ext_embeddings.js index 1a7ae86..bc0ade8 100644 --- a/javascript/ext_embeddings.js +++ b/javascript/ext_embeddings.js @@ -16,7 +16,10 @@ class EmbeddingParser extends BaseTagParser { searchTerm = searchTerm.slice(3); } - let filterCondition = x => x[0].toLowerCase().includes(searchTerm) || x[0].toLowerCase().replaceAll(" ", "_").includes(searchTerm); + let filterCondition = x => { + let regex = new RegExp(escapeRegExp(searchTerm, true), 'i'); + return regex.test(x[0].toLowerCase()) || regex.test(x[0].toLowerCase().replaceAll(" ", "_")); + }; if (versionString) tempResults = embeddings.filter(x => filterCondition(x) && x[2] && x[2].toLowerCase() === versionString.toLowerCase()); // Filter by tagword @@ -29,7 +32,11 @@ class EmbeddingParser extends BaseTagParser { // Add final results let finalResults = []; tempResults.forEach(t => { - let result = new AutocompleteResult(t[0].trim(), ResultType.embedding) + let lastDot = t[0].lastIndexOf(".") > -1 ? t[0].lastIndexOf(".") : t[0].length; + let lastSlash = t[0].lastIndexOf("/") > -1 ? t[0].lastIndexOf("/") : -1; + let name = t[0].trim().substring(lastSlash + 1, lastDot); + + let result = new AutocompleteResult(name, ResultType.embedding) result.sortKey = t[1]; result.meta = t[2] + " Embedding"; finalResults.push(result); @@ -62,4 +69,4 @@ PARSERS.push(new EmbeddingParser(EMB_TRIGGER)); // Add our utility functions to their respective queues QUEUE_FILE_LOAD.push(load); -QUEUE_SANITIZE.push(sanitize); \ No newline at end of file +QUEUE_SANITIZE.push(sanitize); diff --git a/javascript/ext_hypernets.js b/javascript/ext_hypernets.js index 3613b2a..8d6031a 100644 --- a/javascript/ext_hypernets.js +++ b/javascript/ext_hypernets.js @@ -7,7 +7,10 @@ class HypernetParser extends BaseTagParser { let tempResults = []; if (tagword !== "<" && tagword !== " x.toLowerCase().includes(searchTerm) || x.toLowerCase().replaceAll(" ", "_").includes(searchTerm); + let filterCondition = x => { + let regex = new RegExp(escapeRegExp(searchTerm, true), 'i'); + return regex.test(x.toLowerCase()) || regex.test(x.toLowerCase().replaceAll(" ", "_")); + }; tempResults = hypernetworks.filter(x => filterCondition(x[0])); // Filter by tagword } else { tempResults = hypernetworks; @@ -49,4 +52,4 @@ PARSERS.push(new HypernetParser(HYP_TRIGGER)); // Add our utility functions to their respective queues QUEUE_FILE_LOAD.push(load); -QUEUE_SANITIZE.push(sanitize); \ No newline at end of file +QUEUE_SANITIZE.push(sanitize); diff --git a/javascript/ext_loras.js b/javascript/ext_loras.js index 22c879c..da01d24 100644 --- a/javascript/ext_loras.js +++ b/javascript/ext_loras.js @@ -7,7 +7,10 @@ class LoraParser extends BaseTagParser { let tempResults = []; if (tagword !== "<" && tagword !== " x.toLowerCase().includes(searchTerm) || x.toLowerCase().replaceAll(" ", "_").includes(searchTerm); + let filterCondition = x => { + let regex = new RegExp(escapeRegExp(searchTerm, true), 'i'); + return regex.test(x.toLowerCase()) || regex.test(x.toLowerCase().replaceAll(" ", "_")); + }; tempResults = loras.filter(x => filterCondition(x[0])); // Filter by tagword } else { tempResults = loras; @@ -61,4 +64,4 @@ PARSERS.push(new LoraParser(LORA_TRIGGER)); // Add our utility functions to their respective queues QUEUE_FILE_LOAD.push(load); -QUEUE_SANITIZE.push(sanitize); \ No newline at end of file +QUEUE_SANITIZE.push(sanitize); diff --git a/javascript/ext_lycos.js b/javascript/ext_lycos.js index 94d5fe2..0e4ee3c 100644 --- a/javascript/ext_lycos.js +++ b/javascript/ext_lycos.js @@ -7,7 +7,10 @@ class LycoParser extends BaseTagParser { let tempResults = []; if (tagword !== "<" && tagword !== " x.toLowerCase().includes(searchTerm) || x.toLowerCase().replaceAll(" ", "_").includes(searchTerm); + let filterCondition = x => { + let regex = new RegExp(escapeRegExp(searchTerm, true), 'i'); + return regex.test(x.toLowerCase()) || regex.test(x.toLowerCase().replaceAll(" ", "_")); + }; tempResults = lycos.filter(x => filterCondition(x[0])); // Filter by tagword } else { tempResults = lycos; @@ -62,4 +65,4 @@ PARSERS.push(new LycoParser(LYCO_TRIGGER)); // Add our utility functions to their respective queues QUEUE_FILE_LOAD.push(load); -QUEUE_SANITIZE.push(sanitize); \ No newline at end of file +QUEUE_SANITIZE.push(sanitize); diff --git a/javascript/ext_styles.js b/javascript/ext_styles.js index 0401e9c..a12edf5 100644 --- a/javascript/ext_styles.js +++ b/javascript/ext_styles.js @@ -18,7 +18,10 @@ class StyleParser extends BaseTagParser { if (tagword !== matchGroups[1]) { let searchTerm = tagword.replace(matchGroups[1], ""); - let filterCondition = x => x[0].toLowerCase().includes(searchTerm) || x[0].toLowerCase().replaceAll(" ", "_").includes(searchTerm); + let filterCondition = x => { + let regex = new RegExp(escapeRegExp(searchTerm, true), 'i'); + return regex.test(x[0].toLowerCase()) || regex.test(x[0].toLowerCase().replaceAll(" ", "_")); + }; tempResults = styleNames.filter(x => filterCondition(x)); // Filter by tagword } else { tempResults = styleNames; @@ -64,4 +67,4 @@ PARSERS.push(new StyleParser(STYLE_TRIGGER)); // Add our utility functions to their respective queues QUEUE_FILE_LOAD.push(load); -QUEUE_SANITIZE.push(sanitize); \ No newline at end of file +QUEUE_SANITIZE.push(sanitize); diff --git a/javascript/tagAutocomplete.js b/javascript/tagAutocomplete.js index 78f9c0d..e221831 100644 --- a/javascript/tagAutocomplete.js +++ b/javascript/tagAutocomplete.js @@ -220,7 +220,7 @@ async function syncOptions() { includeEmbeddingsInNormalResults: opts["tac_includeEmbeddingsInNormalResults"], useHypernetworks: opts["tac_useHypernetworks"], useLoras: opts["tac_useLoras"], - useLycos: opts["tac_useLycos"], + useLycos: opts["tac_useLycos"], useLoraPrefixForLycos: opts["tac_useLoraPrefixForLycos"], showWikiLinks: opts["tac_showWikiLinks"], showExtraNetworkPreviews: opts["tac_showExtraNetworkPreviews"], @@ -1241,12 +1241,17 @@ function navigateInList(textArea, event) { if (!validKeys.includes(event.key)) return; if (!isVisible(textArea)) return - // Return if ctrl key is pressed to not interfere with weight editing shortcut - if (event.ctrlKey || event.altKey || event.shiftKey || event.metaKey) return; + // Add modifier keys to base as text+. + let modKey = ""; + if (event.ctrlKey) modKey += "Ctrl+"; + if (event.altKey) modKey += "Alt+"; + if (event.shiftKey) modKey += "Shift+"; + if (event.metaKey) modKey += "Meta+"; + modKey += event.key; oldSelectedTag = selectedTag; - switch (event.key) { + switch (modKey) { case keys["MoveUp"]: if (selectedTag === null) { selectedTag = resultCount - 1; @@ -1317,6 +1322,8 @@ function navigateInList(textArea, event) { case keys["Close"]: hideResults(textArea); break; + default: + if (event.ctrlKey || event.altKey || event.shiftKey || event.metaKey) return; } let moveKeys = [keys["MoveUp"], keys["MoveDown"], keys["JumpUp"], keys["JumpDown"], keys["JumpToStart"], keys["JumpToEnd"]]; if (selectedTag === resultCount - 1 && moveKeys.includes(event.key)) { diff --git a/scripts/tag_autocomplete_helper.py b/scripts/tag_autocomplete_helper.py index 2130a77..981bd5d 100644 --- a/scripts/tag_autocomplete_helper.py +++ b/scripts/tag_autocomplete_helper.py @@ -202,15 +202,15 @@ def get_embeddings(sd_model): continue if emb.shape is None: - emb_unknown.append((Path(emb.filename), key, "")) + emb_unknown.append((Path(emb.filename), Path(emb.filename).relative_to(EMB_PATH).as_posix(), "")) elif emb.shape == V1_SHAPE: - emb_v1.append((Path(emb.filename), key, "v1")) + emb_v1.append((Path(emb.filename), Path(emb.filename).relative_to(EMB_PATH).as_posix(), "v1")) elif emb.shape == V2_SHAPE: - emb_v2.append((Path(emb.filename), key, "v2")) + emb_v2.append((Path(emb.filename), Path(emb.filename).relative_to(EMB_PATH).as_posix(), "v2")) elif emb.shape == VXL_SHAPE: - emb_vXL.append((Path(emb.filename), key, "vXL")) + emb_vXL.append((Path(emb.filename), Path(emb.filename).relative_to(EMB_PATH).as_posix(), "vXL")) else: - emb_unknown.append((Path(emb.filename), key, "")) + emb_unknown.append((Path(emb.filename), Path(emb.filename).relative_to(EMB_PATH).as_posix(), "")) results = sort_models(emb_v1) + sort_models(emb_v2) + sort_models(emb_vXL) + sort_models(emb_unknown) except AttributeError: