mirror of
https://github.com/vladmandic/automatic
synced 2026-09-18 16:54:33 +02:00
feat(autocomplete): apply keep-underscores setting to insertion
Rename `autocomplete_replace_underscores` to `autocomplete_keep_underscores` (default false) so both autocomplete toggles read as "keep" semantics. `insertTag` now honors the setting for both tag and artist modes, matching the dropdown display. Embedding insertion always preserves underscores because the names are filesystem identifiers. - ui_definitions: rename option, flip default, update label - scripts/autocomplete: rename handler, checkbox, and config-bridge keys - javascript/autocomplete: invert render polarity; insertTag takes a `kind` parameter; drop the artist-mode hardcoded underscore replacement so the setting controls tags and artists uniformly Closes #4827
This commit is contained in:
+13
-11
@@ -358,7 +358,7 @@ function insertExtraNetwork(textarea, item, kind) {
|
||||
}
|
||||
|
||||
/** Insert a tag at the current word position, replacing the typed prefix. */
|
||||
function insertTag(textarea, tagName) {
|
||||
function insertTag(textarea, tagName, kind = 'tag') {
|
||||
const info = getCurrentWord(textarea);
|
||||
if (!info || (info.mode !== 'tag' && info.mode !== 'artist')) return;
|
||||
const { value } = textarea;
|
||||
@@ -371,13 +371,13 @@ function insertTag(textarea, tagName) {
|
||||
const prefix = needsSepBefore ? `${sep} ` : '';
|
||||
let suffix = `${sep} `;
|
||||
if (after.length > 0 && after.trimStart().startsWith(',')) suffix = ' ';
|
||||
// Artist mode: optionally keep the `@` prefix (Anima syntax); always convert underscores to spaces
|
||||
// since Anima requires space-separated artist names. The `@` is consumed for non-Anima models.
|
||||
// Embedding names are file-system identifiers, so underscores must be preserved regardless of the user setting.
|
||||
// Tags and artists honor `autocomplete_keep_underscores`; default is to swap `_` for space.
|
||||
const keepUnderscores = window.opts?.autocomplete_keep_underscores ?? false;
|
||||
let body = tagName;
|
||||
if (info.mode === 'artist') {
|
||||
body = body.replace(/_/g, ' ');
|
||||
if (window.opts?.autocomplete_at_prefix_artist) body = `@${body}`;
|
||||
}
|
||||
if (kind !== 'embed' && !keepUnderscores) body = body.replace(/_/g, ' ');
|
||||
// Artist mode optionally keeps the `@` prefix (Anima syntax). The `@` is consumed for non-Anima models.
|
||||
if (info.mode === 'artist' && window.opts?.autocomplete_at_prefix_artist) body = `@${body}`;
|
||||
const insertion = `${prefix}${escapeParensForPrompt(body)}${suffix}`;
|
||||
textarea.value = before.trimEnd() + (before.trimEnd().length > 0 ? ' ' : '') + insertion + after.trimStart();
|
||||
// Position cursor after the inserted tag + separator
|
||||
@@ -447,7 +447,7 @@ const dropdown = {
|
||||
},
|
||||
|
||||
render() {
|
||||
const replaceUnderscores = window.opts?.autocomplete_replace_underscores ?? true;
|
||||
const keepUnderscores = window.opts?.autocomplete_keep_underscores ?? false;
|
||||
const queryNorm = this.query.toLowerCase().replace(/ /g, '_');
|
||||
this.listEl.replaceChildren();
|
||||
this.results.forEach((tag, i) => {
|
||||
@@ -462,7 +462,9 @@ const dropdown = {
|
||||
dot.title = kind === 'tag' ? (engine.categoryNames[tag.category] || '') : kind;
|
||||
const name = document.createElement('span');
|
||||
name.className = 'autocomplete-tag';
|
||||
const tagText = replaceUnderscores ? tag.display.replace(/_/g, ' ') : tag.display;
|
||||
// Embeddings are file-name identifiers, so they always render as-is to match how they get inserted.
|
||||
const swapForKind = kind !== 'embed';
|
||||
const tagText = (swapForKind && !keepUnderscores) ? tag.display.replace(/_/g, ' ') : tag.display;
|
||||
const canonicalMatch = tag.name.indexOf(queryNorm);
|
||||
if (canonicalMatch >= 0 && queryNorm.length > 0) {
|
||||
const mark = document.createElement('mark');
|
||||
@@ -480,7 +482,7 @@ const dropdown = {
|
||||
if (tag.matchedVia === 'alias') annotationTerm = tag.matchedAlias;
|
||||
else if (tag.matchedVia === 'translation') annotationTerm = tag.matchedTerm;
|
||||
if (annotationTerm) {
|
||||
const annotationDisplay = replaceUnderscores ? annotationTerm.replace(/_/g, ' ') : annotationTerm;
|
||||
const annotationDisplay = (swapForKind && !keepUnderscores) ? annotationTerm.replace(/_/g, ' ') : annotationTerm;
|
||||
const annotationLower = annotationTerm.toLowerCase();
|
||||
const annotationMatch = annotationLower.indexOf(queryNorm);
|
||||
const prefix = tag.matchedVia === 'translation' ? ' \u{1F310} ' : ' (';
|
||||
@@ -561,7 +563,7 @@ const dropdown = {
|
||||
insertExtraNetwork(this.textarea, result, result.kind);
|
||||
} else {
|
||||
// 'embed' kind and untagged tag results both go through insertTag (comma-aware, paren-escaped).
|
||||
insertTag(this.textarea, result.display ?? result.name);
|
||||
insertTag(this.textarea, result.display ?? result.name, result.kind);
|
||||
}
|
||||
}
|
||||
this.hide();
|
||||
|
||||
Reference in New Issue
Block a user