Skip to content

Commit 9e2f174

Browse files
Merge pull request #61 from newtextdoc1111/dev
Merge Dev
2 parents f8cbd27 + 199ee05 commit 9e2f174

11 files changed

Lines changed: 203 additions & 31 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ For example, by preparing the following CSV, you can quickly insert correspondin
189189
- **Auto Format Trigger**: Choose when formatting is applied.
190190
- **Auto**: Format automatically when leaving text field
191191
- **Manual**: Format only via keyboard shortcut (default: `Alt+Shift+F`)
192-
- **Use Trailing Comma**: If enabled, ensures all lines end with a trailing comma when formatting. If disabled, removes trailing commas.
192+
- **Use Trailing Comma**: When enabled, ensures all lines end with a trailing comma when formatting. If disabled, removes trailing commas.
193+
- **Trim Surrounding Spaces**: When enabled, trim any blank lines or spaces from the beginning and end of the prompt.
193194

194195
## Advanced Settings
195196

docs/README_jp.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ worst_quality,5,9999999,
187187
- **Auto Format Trigger**: フォーマットを適用するタイミングを選択します
188188
- **自動**: テキスト欄からフォーカスが外れた際に自動でフォーマットします
189189
- **手動**: キーボードショートカットでのみフォーマットします(デフォルト: `Alt+Shift+F`
190-
- **行末にカンマを使用**: 有効にすると、フォーマット時にすべての行末がカンマで終わるようになります。\n無効にすると行末のカンマが削除されます
190+
- **行末にカンマを使用**: 有効時、フォーマット時にすべての行末がカンマで終わるようになります。\n無効にすると行末のカンマが削除されます
191+
- **先頭・末尾の空白を削除**: 有効時、プロンプトの先頭と末尾にある空行やスペースをすべて削除します
191192

192193
## 上級者向け設定
193194

locales/en/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,9 @@
8585
},
8686
"AutocompletePlus_AutoFormatter_EnableAutoFormat": {
8787
"name": "Enable Auto Format"
88+
},
89+
"AutocompletePlus_AutoFormatter_TrimSurroundingSpaces": {
90+
"name": "Trim Surrounding Spaces",
91+
"tooltip": "When enabled, trim any blank lines from the beginning and end of the prompt."
8892
}
8993
}

locales/ja/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,9 @@
8585
},
8686
"AutocompletePlus_AutoFormatter_EnableAutoFormat": {
8787
"name": "自動フォーマット機能の有効化"
88+
},
89+
"AutocompletePlus_AutoFormatter_TrimSurroundingSpaces": {
90+
"name": "先頭・末尾の空白を削除",
91+
"tooltip": "有効時、プロンプトの先頭と末尾にある空行やスペースをすべて削除します。"
8892
}
8993
}

locales/zh-TW/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,9 @@
8585
},
8686
"AutocompletePlus_AutoFormatter_EnableAutoFormat": {
8787
"name": "啟用自動格式化"
88+
},
89+
"AutocompletePlus_AutoFormatter_TrimSurroundingSpaces": {
90+
"name": "去除首尾空白",
91+
"tooltip": "啟用時,清除提示詞開頭和結尾的所有空行和空格。"
8892
}
8993
}

locales/zh/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,9 @@
8585
},
8686
"AutocompletePlus_AutoFormatter_EnableAutoFormat": {
8787
"name": "启用自动格式化"
88+
},
89+
"AutocompletePlus_AutoFormatter_TrimSurroundingSpaces": {
90+
"name": "去除首尾空白",
91+
"tooltip": "启用时,清除提示词开头和结尾的所有空行和空格。"
8892
}
8993
}

package-lock.json

Lines changed: 16 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/js/auto-formatter.test.js

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ describe('AutoFormatter Functions', () => {
1616
inputName
1717
});
1818

19+
// Store original setting value to restore after tests
20+
const originalTrimSurroundingSpaces = settingValues.trimSurroundingSpaces;
21+
22+
afterEach(() => {
23+
// Restore original setting after each test
24+
settingValues.trimSurroundingSpaces = originalTrimSurroundingSpaces;
25+
});
26+
1927
test('should return false for empty text', () => {
2028
expect(shouldAutoFormat('', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
2129
expect(shouldAutoFormat(' ', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
@@ -42,20 +50,73 @@ describe('AutoFormatter Functions', () => {
4250
expect(shouldAutoFormat('hello world', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
4351
expect(shouldAutoFormat('tag1 tag2', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
4452
});
53+
54+
describe('blocklist priority with trimSurroundingSpaces', () => {
55+
test('should prioritize blocklist over trimSurroundingSpaces when disabled', () => {
56+
settingValues.trimSurroundingSpaces = false;
57+
58+
// Blocklisted nodes should return false even with surrounding spaces
59+
expect(shouldAutoFormat(' some code ', mockNodeInfo('Power Puter (rgthree)', 'code'))).toBe(false);
60+
expect(shouldAutoFormat('\nsome code\n', mockNodeInfo('Power Puter (rgthree)', 'code'))).toBe(false);
61+
expect(shouldAutoFormat(' 0,0,0,1,1,1 ', mockNodeInfo('LoraLoaderBlockWeight //Inspire', 'block_vector'))).toBe(false);
62+
});
63+
64+
test('should prioritize blocklist over trimSurroundingSpaces when enabled', () => {
65+
settingValues.trimSurroundingSpaces = true;
66+
67+
// Blocklisted nodes should return false even with trimSurroundingSpaces enabled and surrounding spaces
68+
expect(shouldAutoFormat(' some code ', mockNodeInfo('Power Puter (rgthree)', 'code'))).toBe(false);
69+
expect(shouldAutoFormat('\nsome code\n', mockNodeInfo('Power Puter (rgthree)', 'code'))).toBe(false);
70+
expect(shouldAutoFormat(' function() { } ', mockNodeInfo('Power Puter (rgthree)', 'code'))).toBe(false);
71+
expect(shouldAutoFormat(' 0,0,0,1,1,1 ', mockNodeInfo('LoraLoaderBlockWeight //Inspire', 'block_vector'))).toBe(false);
72+
});
73+
});
74+
75+
describe('trimSurroundingSpaces with non-comma-separated text', () => {
76+
test('should return false for non-comma-separated text when trimSurroundingSpaces is disabled', () => {
77+
settingValues.trimSurroundingSpaces = false;
78+
79+
// Text without word+comma pattern should return false
80+
expect(shouldAutoFormat(' hello world ', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
81+
expect(shouldAutoFormat('\nhello world\n', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
82+
expect(shouldAutoFormat(' tag1 tag2 ', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
83+
});
84+
85+
test('should return true for non-comma-separated text with surrounding spaces when trimSurroundingSpaces is enabled', () => {
86+
settingValues.trimSurroundingSpaces = true;
87+
88+
// Text with surrounding spaces should return true to format (trim them)
89+
expect(shouldAutoFormat(' hello world ', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(true);
90+
expect(shouldAutoFormat('\nhello world\n', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(true);
91+
expect(shouldAutoFormat(' tag1 tag2 ', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(true);
92+
expect(shouldAutoFormat(' \nsome text\n ', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(true);
93+
});
94+
95+
test('should return false for text without surrounding spaces even when trimSurroundingSpaces is enabled', () => {
96+
settingValues.trimSurroundingSpaces = true;
97+
98+
// Text without word+comma pattern and without surrounding spaces should return false
99+
expect(shouldAutoFormat('hello world', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
100+
expect(shouldAutoFormat('tag1 tag2', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
101+
});
102+
});
45103
});
46104

47105
describe('formatPromptText', () => {
48106
// Store original setting value to restore after tests
49107
const originalUseTrailingComma = settingValues.useTrailingComma;
108+
const originalTrimSurroundingSpaces = settingValues.trimSurroundingSpaces;
50109

51110
afterEach(() => {
52111
// Restore original setting after each test
53112
settingValues.useTrailingComma = originalUseTrailingComma;
113+
settingValues.trimSurroundingSpaces = originalTrimSurroundingSpaces;
54114
});
55115

56116
describe('with useTrailingComma enabled', () => {
57117
beforeEach(() => {
58118
settingValues.useTrailingComma = true;
119+
settingValues.trimSurroundingSpaces = false;
59120
});
60121

61122
test('should format text by adding comma and space after tags', () => {
@@ -101,6 +162,7 @@ describe('AutoFormatter Functions', () => {
101162
describe('with useTrailingComma disabled', () => {
102163
beforeEach(() => {
103164
settingValues.useTrailingComma = false;
165+
settingValues.trimSurroundingSpaces = false;
104166
});
105167

106168
test('should format text by adding comma and space after tags without trailing comma', () => {
@@ -143,6 +205,59 @@ describe('AutoFormatter Functions', () => {
143205
});
144206
});
145207

208+
describe('with trimSurroundingSpaces enabled', () => {
209+
beforeEach(() => {
210+
settingValues.trimSurroundingSpaces = true;
211+
settingValues.useTrailingComma = false;
212+
});
213+
214+
test('should remove trailing newlines and spaces', () => {
215+
const input = 'tag1, tag2\n\n ';
216+
const expected = 'tag1, tag2';
217+
expect(formatPromptText(input)).toBe(expected);
218+
});
219+
220+
test('should remove leading newlines and spaces', () => {
221+
const input = ' \n\ntag1, tag2';
222+
const expected = 'tag1, tag2';
223+
expect(formatPromptText(input)).toBe(expected);
224+
});
225+
226+
test('should remove both leading and trailing whitespaces but keep middle empty lines', () => {
227+
const input = ' \n\ntag1\n\ntag2\n\n ';
228+
const expected = 'tag1\n\ntag2';
229+
expect(formatPromptText(input)).toBe(expected);
230+
});
231+
232+
test('should return empty string if input is only whitespace', () => {
233+
const input = ' \n ';
234+
expect(formatPromptText(input)).toBe('');
235+
});
236+
});
237+
238+
describe('with trimSurroundingSpaces disabled', () => {
239+
beforeEach(() => {
240+
settingValues.trimSurroundingSpaces = false;
241+
settingValues.useTrailingComma = false;
242+
});
243+
244+
test('should preserve trailing newlines', () => {
245+
const input = 'tag1, tag2\n\n';
246+
const expected = 'tag1, tag2\n\n';
247+
expect(formatPromptText(input)).toBe(expected);
248+
});
249+
250+
test('should preserve leading spaces (as first line content)', () => {
251+
const input = ' \ntag1';
252+
const expected = '\ntag1';
253+
expect(formatPromptText(input)).toBe(expected);
254+
});
255+
256+
test('should handle input with only spaces', () => {
257+
expect(formatPromptText(' ')).toBe(' ');
258+
});
259+
});
260+
146261
test('should handle empty input', () => {
147262
expect(formatPromptText('')).toBe('');
148263
expect(formatPromptText(null)).toBe(null);

web/js/auto-formatter.js

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ import { NodeInfo } from './node-info.js';
77
*
88
* Format conditions:
99
* 1. Skip formatting if node is in blocklist
10-
* 2. Skip formatting if text contains only numbers or single letters (separated by commas)
11-
* 3. Format if text contains "word + comma" pattern at least twice
12-
* 4. Otherwise, don't format
10+
* 2. If text is empty after trimming, format only if trimSurroundingSpaces is enabled, otherwise don't format
11+
* 3. Skip formatting if text contains only numbers or single letters (separated by commas)
12+
* 4. Format if text contains "word + comma" pattern
13+
* 5. Format if trimSurroundingSpaces is enabled and there are surrounding spaces or line breaks
14+
* 6. Otherwise, don't format
1315
*
1416
* @param {NodeInfo} nodeInfo - The node information.
1517
* @returns {boolean} - True if the text should be formatted, false otherwise.
1618
*/
1719
function shouldAutoFormat(text, nodeInfo) {
18-
if (!text || text.trim().length === 0) return false;
20+
if (!text) return false;
1921

2022
// 1. Check if the node name is in the blocklist
2123
const blocklist = [
@@ -34,10 +36,14 @@ function shouldAutoFormat(text, nodeInfo) {
3436
// console.debug(`[Autocomplete-Plus] auto-formatter on blur => nodeType: ${nodeInfo.nodeType}, inputName: ${nodeInfo.inputName}`);
3537
}
3638

37-
3839
const trimmedText = text.trim();
3940

40-
// 2. Check if the text is purely numeric data or single-letter placeholders with commas
41+
// 2. Check if the text is completely empty after trimming
42+
if (trimmedText.length === 0) {
43+
return settingValues.trimSurroundingSpaces;
44+
}
45+
46+
// 3. Check if the text is purely numeric data or single-letter placeholders with commas
4147
// (e.g., "0,0,0,1,1,1" or "0.5, -1.2, 0.8" or "A,B,R" for LoRA Block Weight)
4248
const elements = trimmedText.split(',').map(el => el.trim());
4349
const isSingleLetterOrNumeric = elements.every(el => {
@@ -50,15 +56,18 @@ function shouldAutoFormat(text, nodeInfo) {
5056
return false; // Don't format numeric data or single-letter template patterns
5157
}
5258

53-
// 3. Check if the text contains the pattern "word + comma"
59+
// 4. If text contains "word + comma" pattern, format it
5460
const wordCommaPattern = /\w+\s*,/g;
55-
const matches = trimmedText.match(wordCommaPattern);
56-
57-
if (matches == null) {
58-
return false;
61+
if (trimmedText.match(wordCommaPattern)) {
62+
return true;
5963
}
6064

61-
return true; // Text should be formatted
65+
// 5. If trimSurroundingSpaces is enabled and there are surrounding spaces, format to trim them
66+
if (settingValues.trimSurroundingSpaces && text !== trimmedText) {
67+
return true;
68+
}
69+
70+
return false; // Otherwise, don't format
6271
}
6372

6473
/**
@@ -68,10 +77,27 @@ function shouldAutoFormat(text, nodeInfo) {
6877
* @returns {string} - The formatted text.
6978
*/
7079
export function formatPromptText(text) {
71-
if (!text || text.trim().length === 0) return text;
80+
// Handle null or undefined input
81+
if (text == null) return text;
82+
83+
// If the text is empty or contains only spaces...
84+
if (text.trim().length === 0) {
85+
if (settingValues.trimSurroundingSpaces) {
86+
// ...And trimSurroundingSpaces is enabled, return an empty string
87+
return '';
88+
} else {
89+
// ...Otherwise, return the original text
90+
return text;
91+
}
92+
}
93+
94+
let processedText = text;
95+
if (settingValues.trimSurroundingSpaces) {
96+
processedText = text.trim();
97+
}
7298

7399
// Split text into individual lines for processing
74-
const lines = text.split('\n');
100+
const lines = processedText.split('\n');
75101
const formattedLines = [];
76102

77103
for (const line of lines) {

0 commit comments

Comments
 (0)