提交 04b42cf0 编写于 作者: A Alex Dima

Fixes #53899

上级 c90755b6
...@@ -468,13 +468,31 @@ export class WordOperations { ...@@ -468,13 +468,31 @@ export class WordOperations {
export function _lastWordPartEnd(str: string, startIndex: number = str.length - 1): number { export function _lastWordPartEnd(str: string, startIndex: number = str.length - 1): number {
let ignoreUpperCase = !strings.isLowerAsciiLetter(str.charCodeAt(startIndex + 1)); let ignoreUpperCase = !strings.isLowerAsciiLetter(str.charCodeAt(startIndex + 1));
for (let i = startIndex; i >= 0; i--) { for (let i = startIndex; i >= 0; i--) {
let chCode = str.charCodeAt(i); const chCode = str.charCodeAt(i);
if (chCode === CharCode.Space || chCode === CharCode.Tab || (!ignoreUpperCase && strings.isUpperAsciiLetter(chCode)) || chCode === CharCode.Underline) { if (chCode === CharCode.Space || chCode === CharCode.Tab) {
if (i === 0) {
return 0;
}
const prevChCode = str.charCodeAt(i - 1);
if (prevChCode !== CharCode.Space && prevChCode !== CharCode.Tab) {
return i - 1;
}
}
if (!ignoreUpperCase && strings.isUpperAsciiLetter(chCode)) {
return i - 1; return i - 1;
} }
if (ignoreUpperCase && i < startIndex && strings.isLowerAsciiLetter(chCode)) { if (ignoreUpperCase && i < startIndex && strings.isLowerAsciiLetter(chCode)) {
return i; return i;
} }
if (chCode === CharCode.Underline) {
if (i === 0) {
return 0;
}
const prevChCode = str.charCodeAt(i - 1);
if (prevChCode !== CharCode.Underline) {
return i - 1;
}
}
ignoreUpperCase = ignoreUpperCase && strings.isUpperAsciiLetter(chCode); ignoreUpperCase = ignoreUpperCase && strings.isUpperAsciiLetter(chCode);
} }
return -1; return -1;
...@@ -490,7 +508,16 @@ export function _nextWordPartBegin(str: string, startIndex: number = 0): number ...@@ -490,7 +508,16 @@ export function _nextWordPartBegin(str: string, startIndex: number = 0): number
let ignoreUpperCase = strings.isUpperAsciiLetter(chCode); let ignoreUpperCase = strings.isUpperAsciiLetter(chCode);
for (let i = startIndex; i < str.length; ++i) { for (let i = startIndex; i < str.length; ++i) {
chCode = str.charCodeAt(i); chCode = str.charCodeAt(i);
if (chCode === CharCode.Space || chCode === CharCode.Tab || (!ignoreUpperCase && strings.isUpperAsciiLetter(chCode))) { if (chCode === CharCode.Space || chCode === CharCode.Tab) {
if (i + 1 >= str.length) {
return i + 1;
}
const nextChCode = str.charCodeAt(i + 1);
if (nextChCode !== CharCode.Space && nextChCode !== CharCode.Tab) {
return i + 2;
}
}
if (!ignoreUpperCase && strings.isUpperAsciiLetter(chCode)) {
return i + 1; return i + 1;
} }
if (ignoreUpperCase && strings.isLowerAsciiLetter(chCode)) { if (ignoreUpperCase && strings.isLowerAsciiLetter(chCode)) {
...@@ -498,7 +525,13 @@ export function _nextWordPartBegin(str: string, startIndex: number = 0): number ...@@ -498,7 +525,13 @@ export function _nextWordPartBegin(str: string, startIndex: number = 0): number
} }
ignoreUpperCase = ignoreUpperCase && strings.isUpperAsciiLetter(chCode); ignoreUpperCase = ignoreUpperCase && strings.isUpperAsciiLetter(chCode);
if (chCode === CharCode.Underline) { if (chCode === CharCode.Underline) {
return i + 2; if (i + 1 >= str.length) {
return i + 1;
}
const nextChCode = str.charCodeAt(i + 1);
if (nextChCode !== CharCode.Underline) {
return i + 2;
}
} }
} }
return str.length + 1; return str.length + 1;
......
...@@ -69,6 +69,10 @@ export function testRepeatedActionAndExtractPositions(text: string, initialPosit ...@@ -69,6 +69,10 @@ export function testRepeatedActionAndExtractPositions(text: string, initialPosit
if (stopCondition(editor)) { if (stopCondition(editor)) {
break; break;
} }
if (actualStops.length > 1000) {
throw new Error(`Endless loop detected!`);
}
} }
}); });
return actualStops; return actualStops;
......
...@@ -36,7 +36,7 @@ suite('WordPartOperations', () => { ...@@ -36,7 +36,7 @@ suite('WordPartOperations', () => {
test('move word part left basic', () => { test('move word part left basic', () => {
const EXPECTED = [ const EXPECTED = [
'|start| |line|', '|start| |line|',
'|this|Is|A|Camel|Case|Var| | |this|_is|_a|_snake|_case|_var| |THIS|_IS|_CAPS|_SNAKE| |this|_IS|Mixed|Use|', '|this|Is|A|Camel|Case|Var| |this|_is|_a|_snake|_case|_var| |THIS|_IS|_CAPS|_SNAKE| |this|_IS|Mixed|Use|',
'|end| |line' '|end| |line'
].join('\n'); ].join('\n');
const [text,] = deserializePipePositions(EXPECTED); const [text,] = deserializePipePositions(EXPECTED);
...@@ -51,10 +51,38 @@ suite('WordPartOperations', () => { ...@@ -51,10 +51,38 @@ suite('WordPartOperations', () => {
assert.deepEqual(actual, EXPECTED); assert.deepEqual(actual, EXPECTED);
}); });
test('issue #53899: move word part left whitespace', () => {
const EXPECTED = '|myvar| |=| |\'|demonstration| |of| |selection| |with| |space\'';
const [text,] = deserializePipePositions(EXPECTED);
const actualStops = testRepeatedActionAndExtractPositions(
text,
new Position(1000, 1000),
ed => moveWordPartLeft(ed),
ed => ed.getPosition(),
ed => ed.getPosition().equals(new Position(1, 1))
);
const actual = serializePipePositions(text, actualStops);
assert.deepEqual(actual, EXPECTED);
});
test('issue #53899: move word part left underscores', () => {
const EXPECTED = '|myvar| |=| |\'|demonstration|_____of| |selection| |with| |space\'';
const [text,] = deserializePipePositions(EXPECTED);
const actualStops = testRepeatedActionAndExtractPositions(
text,
new Position(1000, 1000),
ed => moveWordPartLeft(ed),
ed => ed.getPosition(),
ed => ed.getPosition().equals(new Position(1, 1))
);
const actual = serializePipePositions(text, actualStops);
assert.deepEqual(actual, EXPECTED);
});
test('move word part right basic', () => { test('move word part right basic', () => {
const EXPECTED = [ const EXPECTED = [
'start| |line|', 'start| |line|',
'|this|Is|A|Camel|Case|Var| | |this_|is_|a_|snake_|case_|var| |THIS_|IS_|CAPS_|SNAKE| |this_|IS|Mixed|Use|', '|this|Is|A|Camel|Case|Var| |this_|is_|a_|snake_|case_|var| |THIS_|IS_|CAPS_|SNAKE| |this_|IS|Mixed|Use|',
'|end| |line|' '|end| |line|'
].join('\n'); ].join('\n');
const [text,] = deserializePipePositions(EXPECTED); const [text,] = deserializePipePositions(EXPECTED);
...@@ -69,6 +97,34 @@ suite('WordPartOperations', () => { ...@@ -69,6 +97,34 @@ suite('WordPartOperations', () => {
assert.deepEqual(actual, EXPECTED); assert.deepEqual(actual, EXPECTED);
}); });
test('issue #53899: move word part right whitespace', () => {
const EXPECTED = 'myvar| =| \'demonstration| |of| |selection| |with| |space|\'|';
const [text,] = deserializePipePositions(EXPECTED);
const actualStops = testRepeatedActionAndExtractPositions(
text,
new Position(1, 1),
ed => moveWordPartRight(ed),
ed => ed.getPosition(),
ed => ed.getPosition().equals(new Position(1, 52))
);
const actual = serializePipePositions(text, actualStops);
assert.deepEqual(actual, EXPECTED);
});
test('issue #53899: move word part right underscores', () => {
const EXPECTED = 'myvar| =| \'demonstration_____|of| |selection| |with| |space|\'|';
const [text,] = deserializePipePositions(EXPECTED);
const actualStops = testRepeatedActionAndExtractPositions(
text,
new Position(1, 1),
ed => moveWordPartRight(ed),
ed => ed.getPosition(),
ed => ed.getPosition().equals(new Position(1, 52))
);
const actual = serializePipePositions(text, actualStops);
assert.deepEqual(actual, EXPECTED);
});
test('delete word part left basic', () => { test('delete word part left basic', () => {
const EXPECTED = '| |/*| |Just| |some| |text| |a|+=| |3| |+|5|-|3| |*/| |this|Is|A|Camel|Case|Var| |this|_is|_a|_snake|_case|_var| |THIS|_IS|_CAPS|_SNAKE| |this|_IS|Mixed|Use'; const EXPECTED = '| |/*| |Just| |some| |text| |a|+=| |3| |+|5|-|3| |*/| |this|Is|A|Camel|Case|Var| |this|_is|_a|_snake|_case|_var| |THIS|_IS|_CAPS|_SNAKE| |this|_IS|Mixed|Use';
const [text,] = deserializePipePositions(EXPECTED); const [text,] = deserializePipePositions(EXPECTED);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册