mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-29 08:58:53 -03:00
fix(autocomplete): make accept key behavior configurable (#863)
This commit is contained in:
@@ -69,6 +69,9 @@ describe('AutoComplete widget interactions', () => {
|
|||||||
if (key === 'loramanager.autocomplete_append_comma') {
|
if (key === 'loramanager.autocomplete_append_comma') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (key === 'loramanager.autocomplete_accept_key') {
|
||||||
|
return 'both';
|
||||||
|
}
|
||||||
if (key === 'loramanager.prompt_tag_autocomplete') {
|
if (key === 'loramanager.prompt_tag_autocomplete') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -210,6 +213,157 @@ describe('AutoComplete widget interactions', () => {
|
|||||||
expect(insertSelectionSpy).toHaveBeenCalledWith('example_completion');
|
expect(insertSelectionSpy).toHaveBeenCalledWith('example_completion');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('prefers the latest best match when Tab is pressed before debounced suggestions fully refresh', async () => {
|
||||||
|
caretHelperInstance.getBeforeCursor.mockReturnValue('loop');
|
||||||
|
|
||||||
|
const input = document.createElement('textarea');
|
||||||
|
input.value = 'loop';
|
||||||
|
input.selectionStart = input.value.length;
|
||||||
|
input.focus = vi.fn();
|
||||||
|
input.setSelectionRange = vi.fn();
|
||||||
|
document.body.append(input);
|
||||||
|
|
||||||
|
const { AutoComplete } = await import(AUTOCOMPLETE_MODULE);
|
||||||
|
const autoComplete = new AutoComplete(input,'prompt', { showPreview: false, minChars: 1 });
|
||||||
|
|
||||||
|
autoComplete.searchType = 'custom_words';
|
||||||
|
autoComplete.items = [
|
||||||
|
{ tag_name: 'looking_to_the_side', category: 0, post_count: 1000 },
|
||||||
|
{ tag_name: 'loop', category: 0, post_count: 500 },
|
||||||
|
];
|
||||||
|
autoComplete.currentSearchTerm = 'loo';
|
||||||
|
autoComplete.selectedIndex = 0;
|
||||||
|
autoComplete.isVisible = true;
|
||||||
|
const insertSelectionSpy = vi.spyOn(autoComplete,'insertSelection').mockResolvedValue();
|
||||||
|
|
||||||
|
const tabEvent = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true });
|
||||||
|
input.dispatchEvent(tabEvent);
|
||||||
|
|
||||||
|
expect(tabEvent.defaultPrevented).toBe(true);
|
||||||
|
expect(autoComplete.selectedIndex).toBe(1);
|
||||||
|
expect(insertSelectionSpy).toHaveBeenCalledWith('loop');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts the first available suggestion with Tab even if delayed auto-selection has not happened yet', async () => {
|
||||||
|
caretHelperInstance.getBeforeCursor.mockReturnValue('loop');
|
||||||
|
|
||||||
|
const input = document.createElement('textarea');
|
||||||
|
input.value = 'loop';
|
||||||
|
input.selectionStart = input.value.length;
|
||||||
|
input.focus = vi.fn();
|
||||||
|
input.setSelectionRange = vi.fn();
|
||||||
|
document.body.append(input);
|
||||||
|
|
||||||
|
const { AutoComplete } = await import(AUTOCOMPLETE_MODULE);
|
||||||
|
const autoComplete = new AutoComplete(input,'custom_words', { showPreview: false });
|
||||||
|
|
||||||
|
autoComplete.items = ['loop'];
|
||||||
|
autoComplete.selectedIndex = -1;
|
||||||
|
autoComplete.isVisible = true;
|
||||||
|
const insertSelectionSpy = vi.spyOn(autoComplete,'insertSelection').mockResolvedValue();
|
||||||
|
|
||||||
|
const tabEvent = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true });
|
||||||
|
input.dispatchEvent(tabEvent);
|
||||||
|
|
||||||
|
expect(tabEvent.defaultPrevented).toBe(true);
|
||||||
|
expect(autoComplete.selectedIndex).toBe(0);
|
||||||
|
expect(insertSelectionSpy).toHaveBeenCalledWith('loop');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only accepts with Tab when autocomplete accept key is set to tab_only', async () => {
|
||||||
|
settingGetMock.mockImplementation((key) => {
|
||||||
|
if (key === 'loramanager.autocomplete_append_comma') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key === 'loramanager.autocomplete_accept_key') {
|
||||||
|
return 'tab_only';
|
||||||
|
}
|
||||||
|
if (key === 'loramanager.prompt_tag_autocomplete') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key === 'loramanager.tag_space_replacement') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
caretHelperInstance.getBeforeCursor.mockReturnValue('example');
|
||||||
|
|
||||||
|
const input = document.createElement('textarea');
|
||||||
|
input.value = 'example';
|
||||||
|
input.selectionStart = input.value.length;
|
||||||
|
input.focus = vi.fn();
|
||||||
|
input.setSelectionRange = vi.fn();
|
||||||
|
document.body.append(input);
|
||||||
|
|
||||||
|
const { AutoComplete } = await import(AUTOCOMPLETE_MODULE);
|
||||||
|
const autoComplete = new AutoComplete(input,'custom_words', { showPreview: false });
|
||||||
|
|
||||||
|
autoComplete.items = ['example_completion'];
|
||||||
|
autoComplete.selectedIndex = 0;
|
||||||
|
autoComplete.isVisible = true;
|
||||||
|
const insertSelectionSpy = vi.spyOn(autoComplete,'insertSelection').mockResolvedValue();
|
||||||
|
|
||||||
|
const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true });
|
||||||
|
input.dispatchEvent(enterEvent);
|
||||||
|
|
||||||
|
expect(enterEvent.defaultPrevented).toBe(false);
|
||||||
|
expect(insertSelectionSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
const tabEvent = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true });
|
||||||
|
input.dispatchEvent(tabEvent);
|
||||||
|
|
||||||
|
expect(tabEvent.defaultPrevented).toBe(true);
|
||||||
|
expect(insertSelectionSpy).toHaveBeenCalledWith('example_completion');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only accepts with Enter when autocomplete accept key is set to enter_only', async () => {
|
||||||
|
settingGetMock.mockImplementation((key) => {
|
||||||
|
if (key === 'loramanager.autocomplete_append_comma') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key === 'loramanager.autocomplete_accept_key') {
|
||||||
|
return 'enter_only';
|
||||||
|
}
|
||||||
|
if (key === 'loramanager.prompt_tag_autocomplete') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key === 'loramanager.tag_space_replacement') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
caretHelperInstance.getBeforeCursor.mockReturnValue('example');
|
||||||
|
|
||||||
|
const input = document.createElement('textarea');
|
||||||
|
input.value = 'example';
|
||||||
|
input.selectionStart = input.value.length;
|
||||||
|
input.focus = vi.fn();
|
||||||
|
input.setSelectionRange = vi.fn();
|
||||||
|
document.body.append(input);
|
||||||
|
|
||||||
|
const { AutoComplete } = await import(AUTOCOMPLETE_MODULE);
|
||||||
|
const autoComplete = new AutoComplete(input,'custom_words', { showPreview: false });
|
||||||
|
|
||||||
|
autoComplete.items = ['example_completion'];
|
||||||
|
autoComplete.selectedIndex = 0;
|
||||||
|
autoComplete.isVisible = true;
|
||||||
|
const insertSelectionSpy = vi.spyOn(autoComplete,'insertSelection').mockResolvedValue();
|
||||||
|
|
||||||
|
const tabEvent = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true });
|
||||||
|
input.dispatchEvent(tabEvent);
|
||||||
|
|
||||||
|
expect(tabEvent.defaultPrevented).toBe(false);
|
||||||
|
expect(insertSelectionSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true });
|
||||||
|
input.dispatchEvent(enterEvent);
|
||||||
|
|
||||||
|
expect(enterEvent.defaultPrevented).toBe(true);
|
||||||
|
expect(insertSelectionSpy).toHaveBeenCalledWith('example_completion');
|
||||||
|
});
|
||||||
|
|
||||||
it('does not intercept Tab when the dropdown is not visible', async () => {
|
it('does not intercept Tab when the dropdown is not visible', async () => {
|
||||||
caretHelperInstance.getBeforeCursor.mockReturnValue('example');
|
caretHelperInstance.getBeforeCursor.mockReturnValue('example');
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { app } from "../../scripts/app.js";
|
|||||||
import { TextAreaCaretHelper } from "./textarea_caret_helper.js";
|
import { TextAreaCaretHelper } from "./textarea_caret_helper.js";
|
||||||
import {
|
import {
|
||||||
getAutocompleteAppendCommaPreference,
|
getAutocompleteAppendCommaPreference,
|
||||||
|
getAutocompleteAcceptKeyPreference,
|
||||||
getPromptTagAutocompletePreference,
|
getPromptTagAutocompletePreference,
|
||||||
getTagSpaceReplacementPreference,
|
getTagSpaceReplacementPreference,
|
||||||
} from "./settings.js";
|
} from "./settings.js";
|
||||||
@@ -121,6 +122,24 @@ function formatAutocompleteInsertion(text = '') {
|
|||||||
return getAutocompleteAppendCommaPreference() ? `${trimmed},` : `${trimmed} `;
|
return getAutocompleteAppendCommaPreference() ? `${trimmed},` : `${trimmed} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldAcceptAutocompleteKey(key) {
|
||||||
|
const mode = getAutocompleteAcceptKeyPreference();
|
||||||
|
|
||||||
|
if (mode === 'tab_only') {
|
||||||
|
return key === 'Tab';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === 'enter_only') {
|
||||||
|
return key === 'Enter';
|
||||||
|
}
|
||||||
|
|
||||||
|
return key === 'Tab' || key === 'Enter';
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAutocompleteMatchText(text = '') {
|
||||||
|
return text.toLowerCase().replace(/[-_\s']/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
const AUTOCOMPLETE_METADATA_VERSION = 1;
|
const AUTOCOMPLETE_METADATA_VERSION = 1;
|
||||||
|
|
||||||
function createAutocompleteMetadataBase(textWidgetName = 'text') {
|
function createAutocompleteMetadataBase(textWidgetName = 'text') {
|
||||||
@@ -873,6 +892,92 @@ class AutoComplete {
|
|||||||
return { matched: false, isExactMatch: false };
|
return { matched: false, isExactMatch: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getLiveSearchTermForAcceptance() {
|
||||||
|
const rawSearchTerm = this.getSearchTerm(this.inputElement.value);
|
||||||
|
|
||||||
|
if (this.modelType === 'embeddings') {
|
||||||
|
const match = rawSearchTerm.match(/^emb:(.*)$/i);
|
||||||
|
return (match?.[1] || '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.modelType === 'prompt') {
|
||||||
|
const embeddingMatch = rawSearchTerm.match(/^emb:(.*)$/i);
|
||||||
|
if (embeddingMatch) {
|
||||||
|
return (embeddingMatch[1] || '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandResult = this._parseCommandInput(rawSearchTerm);
|
||||||
|
return commandResult.searchTerm ?? rawSearchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawSearchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getPreferredSelectedIndex(searchTerm = '') {
|
||||||
|
if (!this.items?.length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.showingCommands) {
|
||||||
|
if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) {
|
||||||
|
return this.selectedIndex;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmedSearchTerm = searchTerm.trim();
|
||||||
|
if (!trimmedSearchTerm) {
|
||||||
|
if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) {
|
||||||
|
return this.selectedIndex;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchLower = trimmedSearchTerm.toLowerCase();
|
||||||
|
const normalizedSearch = normalizeAutocompleteMatchText(trimmedSearchTerm);
|
||||||
|
let bestIndex = -1;
|
||||||
|
let bestScore = -Infinity;
|
||||||
|
|
||||||
|
this.items.forEach((item, index) => {
|
||||||
|
const displayText = this._getDisplayText(item);
|
||||||
|
const textLower = displayText.toLowerCase();
|
||||||
|
const normalizedText = normalizeAutocompleteMatchText(displayText);
|
||||||
|
let score = -1;
|
||||||
|
|
||||||
|
if (textLower === searchLower) {
|
||||||
|
score = 5000;
|
||||||
|
} else if (normalizedText === normalizedSearch) {
|
||||||
|
score = 4500;
|
||||||
|
} else if (textLower.startsWith(searchLower)) {
|
||||||
|
score = 4000;
|
||||||
|
} else if (normalizedText.startsWith(normalizedSearch)) {
|
||||||
|
score = 3500;
|
||||||
|
} else if (textLower.includes(searchLower)) {
|
||||||
|
score = 3000;
|
||||||
|
} else if (normalizedText.includes(normalizedSearch)) {
|
||||||
|
score = 2500;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > -1) {
|
||||||
|
score -= index;
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bestIndex !== -1) {
|
||||||
|
return bestIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) {
|
||||||
|
return this.selectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
async search(term = '', endpoint = null) {
|
async search(term = '', endpoint = null) {
|
||||||
try {
|
try {
|
||||||
this.currentSearchTerm = term;
|
this.currentSearchTerm = term;
|
||||||
@@ -1135,9 +1240,9 @@ class AutoComplete {
|
|||||||
lastChild.style.borderBottom = 'none';
|
lastChild.style.borderBottom = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-select first item
|
// Auto-select immediately so accept keys remain stable.
|
||||||
if (this.items.length > 0) {
|
if (this.items.length > 0) {
|
||||||
setTimeout(() => this.selectItem(0), 100);
|
this.selectItem(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update virtual scroll height for virtual scrolling mode
|
// Update virtual scroll height for virtual scrolling mode
|
||||||
@@ -1300,11 +1405,10 @@ class AutoComplete {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-select the first item with a small delay
|
// Auto-select immediately so accept keys do not fall through
|
||||||
|
// to native focus traversal while the dropdown is visible.
|
||||||
if (this.items.length > 0) {
|
if (this.items.length > 0) {
|
||||||
setTimeout(() => {
|
|
||||||
this.selectItem(0);
|
this.selectItem(0);
|
||||||
}, 100);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1989,8 +2093,20 @@ class AutoComplete {
|
|||||||
|
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
case 'Tab':
|
case 'Tab':
|
||||||
e.preventDefault();
|
if (!shouldAcceptAutocompleteKey(e.key)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const liveSearchTerm = this._getLiveSearchTermForAcceptance();
|
||||||
|
const preferredIndex = this._getPreferredSelectedIndex(liveSearchTerm);
|
||||||
|
if (preferredIndex !== -1 && preferredIndex !== this.selectedIndex) {
|
||||||
|
this.selectItem(preferredIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) {
|
if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) {
|
||||||
|
e.preventDefault();
|
||||||
if (this.showingCommands) {
|
if (this.showingCommands) {
|
||||||
// Insert command
|
// Insert command
|
||||||
this._insertCommand(this.items[this.selectedIndex].command);
|
this._insertCommand(this.items[this.selectedIndex].command);
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ const PROMPT_TAG_AUTOCOMPLETE_DEFAULT = true;
|
|||||||
const AUTOCOMPLETE_APPEND_COMMA_SETTING_ID = "loramanager.autocomplete_append_comma";
|
const AUTOCOMPLETE_APPEND_COMMA_SETTING_ID = "loramanager.autocomplete_append_comma";
|
||||||
const AUTOCOMPLETE_APPEND_COMMA_DEFAULT = true;
|
const AUTOCOMPLETE_APPEND_COMMA_DEFAULT = true;
|
||||||
|
|
||||||
|
const AUTOCOMPLETE_ACCEPT_KEY_SETTING_ID = "loramanager.autocomplete_accept_key";
|
||||||
|
const AUTOCOMPLETE_ACCEPT_KEY_DEFAULT = "both";
|
||||||
|
const AUTOCOMPLETE_ACCEPT_KEY_OPTION_BOTH = "Tab or Enter";
|
||||||
|
const AUTOCOMPLETE_ACCEPT_KEY_OPTION_TAB_ONLY = "Tab only";
|
||||||
|
const AUTOCOMPLETE_ACCEPT_KEY_OPTION_ENTER_ONLY = "Enter only";
|
||||||
|
|
||||||
const TAG_SPACE_REPLACEMENT_SETTING_ID = "loramanager.tag_space_replacement";
|
const TAG_SPACE_REPLACEMENT_SETTING_ID = "loramanager.tag_space_replacement";
|
||||||
const TAG_SPACE_REPLACEMENT_DEFAULT = false;
|
const TAG_SPACE_REPLACEMENT_DEFAULT = false;
|
||||||
|
|
||||||
@@ -186,6 +192,41 @@ const getAutocompleteAppendCommaPreference = (() => {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
const getAutocompleteAcceptKeyPreference = (() => {
|
||||||
|
let settingsUnavailableLogged = false;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const settingManager = app?.extensionManager?.setting;
|
||||||
|
if (!settingManager || typeof settingManager.get !== "function") {
|
||||||
|
if (!settingsUnavailableLogged) {
|
||||||
|
console.warn("LoRA Manager: settings API unavailable, using default autocomplete accept key setting.");
|
||||||
|
settingsUnavailableLogged = true;
|
||||||
|
}
|
||||||
|
return AUTOCOMPLETE_ACCEPT_KEY_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const value = settingManager.get(AUTOCOMPLETE_ACCEPT_KEY_SETTING_ID);
|
||||||
|
if (value === AUTOCOMPLETE_ACCEPT_KEY_OPTION_TAB_ONLY) {
|
||||||
|
return "tab_only";
|
||||||
|
}
|
||||||
|
if (value === AUTOCOMPLETE_ACCEPT_KEY_OPTION_ENTER_ONLY) {
|
||||||
|
return "enter_only";
|
||||||
|
}
|
||||||
|
if (value === AUTOCOMPLETE_ACCEPT_KEY_OPTION_BOTH || value == null) {
|
||||||
|
return AUTOCOMPLETE_ACCEPT_KEY_DEFAULT;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
} catch (error) {
|
||||||
|
if (!settingsUnavailableLogged) {
|
||||||
|
console.warn("LoRA Manager: unable to read autocomplete accept key setting, using default.", error);
|
||||||
|
settingsUnavailableLogged = true;
|
||||||
|
}
|
||||||
|
return AUTOCOMPLETE_ACCEPT_KEY_DEFAULT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
const getTagSpaceReplacementPreference = (() => {
|
const getTagSpaceReplacementPreference = (() => {
|
||||||
let settingsUnavailableLogged = false;
|
let settingsUnavailableLogged = false;
|
||||||
|
|
||||||
@@ -332,7 +373,20 @@ app.registerExtension({
|
|||||||
type: "boolean",
|
type: "boolean",
|
||||||
defaultValue: AUTOCOMPLETE_APPEND_COMMA_DEFAULT,
|
defaultValue: AUTOCOMPLETE_APPEND_COMMA_DEFAULT,
|
||||||
tooltip: "When enabled, accepted autocomplete suggestions append ', ' to the inserted text.",
|
tooltip: "When enabled, accepted autocomplete suggestions append ', ' to the inserted text.",
|
||||||
category: ["LoRA Manager", "Autocomplete", "Behavior"],
|
category: ["LoRA Manager", "Autocomplete", "Append comma"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: AUTOCOMPLETE_ACCEPT_KEY_SETTING_ID,
|
||||||
|
name: "Autocomplete accept key",
|
||||||
|
type: "combo",
|
||||||
|
options: [
|
||||||
|
AUTOCOMPLETE_ACCEPT_KEY_OPTION_BOTH,
|
||||||
|
AUTOCOMPLETE_ACCEPT_KEY_OPTION_TAB_ONLY,
|
||||||
|
AUTOCOMPLETE_ACCEPT_KEY_OPTION_ENTER_ONLY,
|
||||||
|
],
|
||||||
|
defaultValue: AUTOCOMPLETE_ACCEPT_KEY_OPTION_BOTH,
|
||||||
|
tooltip: "Choose which key accepts the selected autocomplete suggestion. Keys not selected here keep their normal textarea behavior.",
|
||||||
|
category: ["LoRA Manager", "Autocomplete", "Accept key"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: TAG_SPACE_REPLACEMENT_SETTING_ID,
|
id: TAG_SPACE_REPLACEMENT_SETTING_ID,
|
||||||
@@ -451,6 +505,7 @@ export {
|
|||||||
getWheelSensitivity,
|
getWheelSensitivity,
|
||||||
getAutoPathCorrectionPreference,
|
getAutoPathCorrectionPreference,
|
||||||
getAutocompleteAppendCommaPreference,
|
getAutocompleteAppendCommaPreference,
|
||||||
|
getAutocompleteAcceptKeyPreference,
|
||||||
getPromptTagAutocompletePreference,
|
getPromptTagAutocompletePreference,
|
||||||
getTagSpaceReplacementPreference,
|
getTagSpaceReplacementPreference,
|
||||||
getUsageStatisticsPreference,
|
getUsageStatisticsPreference,
|
||||||
|
|||||||
Reference in New Issue
Block a user