mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-15 07:28:05 +00:00
Merge pull request #287150 from lucas-gomes-santana/fix/snippet-unicode-support
Improve snippet case transforms suport for non-Latin scripts (fix: #286165)
This commit is contained in:
@@ -400,13 +400,15 @@ export class FormatString extends Marker {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: word-based case transforms rely on uppercase/lowercase distinctions.
|
||||
// For scripts without case, transforms are effectively no-ops.
|
||||
private _toKebabCase(value: string): string {
|
||||
const match = value.match(/[a-z0-9]+/gi);
|
||||
const match = value.match(/[\p{L}0-9]+/gu);
|
||||
if (!match) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!value.match(/[a-z0-9]/)) {
|
||||
if (!value.match(/[\p{L}0-9]/u)) {
|
||||
return value
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
@@ -414,12 +416,16 @@ export class FormatString extends Marker {
|
||||
.replace(/[\s_]+/g, '-');
|
||||
}
|
||||
|
||||
const match2 = value
|
||||
.trim()
|
||||
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g);
|
||||
const cleaned = value.trim().replace(/^_+|_+$/g, '');
|
||||
|
||||
const match2 = cleaned.match(/\p{Lu}{2,}(?=\p{Lu}\p{Ll}+[0-9]*|[\s_-]|$)|\p{Lu}?\p{Ll}+[0-9]*|\p{Lu}(?=\p{Lu}\p{Ll})|\p{Lu}(?=[\s_-]|$)|[0-9]+/gu);
|
||||
|
||||
if (!match2) {
|
||||
return value;
|
||||
return cleaned
|
||||
.split(/[\s_-]+/)
|
||||
.filter(word => word.length > 0)
|
||||
.map(word => word.toLowerCase())
|
||||
.join('-');
|
||||
}
|
||||
|
||||
return match2
|
||||
@@ -428,7 +434,7 @@ export class FormatString extends Marker {
|
||||
}
|
||||
|
||||
private _toPascalCase(value: string): string {
|
||||
const match = value.match(/[a-z0-9]+/gi);
|
||||
const match = value.match(/[\p{L}0-9]+/gu);
|
||||
if (!match) {
|
||||
return value;
|
||||
}
|
||||
@@ -439,7 +445,7 @@ export class FormatString extends Marker {
|
||||
}
|
||||
|
||||
private _toCamelCase(value: string): string {
|
||||
const match = value.match(/[a-z0-9]+/gi);
|
||||
const match = value.match(/[\p{L}0-9]+/gu);
|
||||
if (!match) {
|
||||
return value;
|
||||
}
|
||||
@@ -453,7 +459,7 @@ export class FormatString extends Marker {
|
||||
}
|
||||
|
||||
private _toSnakeCase(value: string): string {
|
||||
return value.replace(/([a-z])([A-Z])/g, '$1_$2')
|
||||
return value.replace(/(\p{Ll})(\p{Lu})/gu, '$1_$2')
|
||||
.replace(/[\s\-]+/g, '_')
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import assert from 'assert';
|
||||
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
|
||||
import { Choice, FormatString, Marker, Placeholder, Scanner, SnippetParser, Text, TextmateSnippet, TokenType, Transform, Variable } from '../../browser/snippetParser.js';
|
||||
import { Choice, FormatString, Marker, Placeholder, Scanner, SnippetParser, Text, TextmateSnippet, TokenType, Transform, Variable, VariableResolver } from '../../browser/snippetParser.js';
|
||||
|
||||
suite('SnippetParser', () => {
|
||||
|
||||
@@ -700,6 +700,44 @@ suite('SnippetParser', () => {
|
||||
assert.strictEqual(new FormatString(1, undefined, 'bar', 'foo').resolve('baz'), 'bar');
|
||||
});
|
||||
|
||||
test('Unicode Variable Transformations', () => {
|
||||
const resolver = new class implements VariableResolver {
|
||||
resolve(variable: Variable): string | undefined {
|
||||
const values: { [key: string]: string } = {
|
||||
'RUSSIAN': 'одинДва',
|
||||
'GREEK': 'έναςΔύο',
|
||||
'TURKISH': 'istanbulLı',
|
||||
'JAPANESE': 'こんにちは'
|
||||
};
|
||||
return values[variable.name];
|
||||
}
|
||||
};
|
||||
|
||||
function assertTransform(transformName: string, varName: string, expected: string) {
|
||||
const p = new SnippetParser();
|
||||
const snippet = p.parse(`\${${varName}/(.*)/\${1:/${transformName}}/}`);
|
||||
const variable = snippet.children[0] as Variable;
|
||||
variable.resolve(resolver);
|
||||
const resolved = variable.toString();
|
||||
assert.strictEqual(resolved, expected, `${transformName} failed for ${varName}`);
|
||||
}
|
||||
|
||||
assertTransform('kebabcase', 'RUSSIAN', 'один-два');
|
||||
assertTransform('kebabcase', 'GREEK', 'ένας-δύο');
|
||||
assertTransform('snakecase', 'RUSSIAN', 'один_два');
|
||||
assertTransform('snakecase', 'GREEK', 'ένας_δύο');
|
||||
assertTransform('camelcase', 'RUSSIAN', 'одинДва');
|
||||
assertTransform('camelcase', 'GREEK', 'έναςΔύο');
|
||||
assertTransform('pascalcase', 'RUSSIAN', 'ОдинДва');
|
||||
assertTransform('pascalcase', 'GREEK', 'ΈναςΔύο');
|
||||
assertTransform('upcase', 'RUSSIAN', 'ОДИНДВА');
|
||||
assertTransform('downcase', 'RUSSIAN', 'одиндва');
|
||||
assertTransform('kebabcase', 'TURKISH', 'istanbul-lı');
|
||||
assertTransform('pascalcase', 'TURKISH', 'IstanbulLı');
|
||||
assertTransform('upcase', 'JAPANESE', 'こんにちは');
|
||||
assertTransform('kebabcase', 'JAPANESE', 'こんにちは');
|
||||
});
|
||||
|
||||
test('Snippet variable transformation doesn\'t work if regex is complicated and snippet body contains \'$$\' #55627', function () {
|
||||
const snippet = new SnippetParser().parse('const fileName = "${TM_FILENAME/(.*)\\..+$/$1/}"');
|
||||
assert.strictEqual(snippet.toTextmateString(), 'const fileName = "${TM_FILENAME/(.*)\\..+$/${1}/}"');
|
||||
|
||||
Reference in New Issue
Block a user