Skip to content

Commit

Permalink
Move indentationRules back to onEnterRules.
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsnowcurrently committed Aug 12, 2019
1 parent 8b49156 commit b9a2cf3
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 128 deletions.
111 changes: 49 additions & 62 deletions src/client/language/languageConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
// Licensed under the MIT License.
'use strict';

import { IndentAction } from 'vscode';
import { IndentAction, LanguageConfiguration } from 'vscode';
import { verboseRegExp } from '../common/utils/regexp';

// tslint:disable:no-multiline-string

// tslint:disable-next-line:max-func-body-length
export function getLanguageConfiguration() {
export function getLanguageConfiguration(): LanguageConfiguration {
return {
onEnterRules: [
// multi-line separator
Expand All @@ -33,7 +33,49 @@ export function getLanguageConfiguration() {
appendText: '# '
}
},
// outdent on enter
// indent on enter (block-beginning statements)
{
/**
* This does not handle all cases. However, it does handle nearly all usage.
* Here's what it does not cover:
* - the statement is split over multiple lines (and hence the ":" is on a different line)
* - the code block is inlined (after the ":")
* - there are multiple statements on the line (separated by semicolons)
* Also note that `lambda` is purposefully excluded.
*/
beforeText: verboseRegExp(`
^
\\s*
(?:
(?:
(?:
class |
def |
async \\s+ def |
except |
for |
if |
elif |
while |
with
)
\\b .*
) |
else |
try |
finally
)
\\s*
[:]
\\s*
(?: [#] .* )?
$
`),
action: {
indentAction: IndentAction.Indent
}
},
// outdent on enter (block-ending statements)
{
beforeText: verboseRegExp(`
^
Expand Down Expand Up @@ -62,64 +104,9 @@ export function getLanguageConfiguration() {
indentAction: IndentAction.Outdent
}
}
],
indentationRules: {
/**
* This does not handle all cases. However, it does handle nearly all usage.
* Here's what it does not cover:
* - the statement is split over multiple lines (and hence the ":" is on a different line)
* - the code block is inlined (after the ":")
* - there are multiple statements on the line (separated by semicolons)
* Also note that `lambda` is purposefully excluded.
*/
increaseIndentPattern: verboseRegExp(`
^
\\s*
(?:
(?:
(?:
async \\s+ def |
class |
def |
except |
for |
if |
elif |
while |
with
)
\\b .*
) |
else |
try |
finally
)
\\s*
[:]
\\s*
(?: [#] .* )?
$
`),
decreaseIndentPattern: verboseRegExp(`
^
\\s*
(?:
(?:
(?:
elif |
except
)
\\b .*
) |
else |
finally
)
\\s*
[:]
\\s*
(?: [#] .* )?
$
`)
}
// Note that we do not currently have an auto-dedent
// solution for "elif", "else", "except", and "finally".
// We had one but had to remove it (see issue #6886).
]
};
}
153 changes: 87 additions & 66 deletions src/test/language/languageConfiguration.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const NEEDS_INDENT = [
/^raise$/, // only re-raise
/^return\b/
];
const INDENT_ON_MATCH = [
const INDENT_ON_ENTER = [ // block-beginning statements
/^async\s+def\b/,
/^class\b/,
/^def\b/,
Expand All @@ -31,13 +31,7 @@ const INDENT_ON_MATCH = [
/^elif\b/,
/^else\b/
];
const DEDENT_ON_MATCH = [
/^elif\b/,
/^else\b/,
/^except\b/,
/^finally\b/
];
const DEDENT_ON_ENTER = [
const DEDENT_ON_ENTER = [ // block-ending statements
/^break$/,
/^continue$/,
/^raise\b/,
Expand All @@ -55,15 +49,76 @@ function isMember(line: string, regexes: RegExp[]): boolean {
return false;
}

suite('Language configuration regexes', () => {
const cfg = getLanguageConfiguration();
const MULTILINE_SEPARATOR_INDENT_REGEX = cfg.onEnterRules[0].beforeText;
const DECREASE_INDENT_REGEX = cfg.indentationRules.decreaseIndentPattern;
const INCREASE_INDENT_REGEX = cfg.indentationRules.increaseIndentPattern;
const OUTDENT_ONENTER_REGEX = cfg.onEnterRules[2].beforeText;
// To see the actual (non-verbose) regex patterns, un-comment here:
//console.log(DECREASE_INDENT_REGEX.source);
//console.log(INCREASE_INDENT_REGEX.source);
function resolveExample(
base: string,
leading: string,
postKeyword: string,
preColon: string,
trailing: string
): [string | undefined, string | undefined, boolean] {
let invalid: string | undefined;
if (base.trim() === '') {
invalid = 'blank line';
} else if (leading === '' && isMember(base, NEEDS_INDENT)) {
invalid = 'expected indent';
} else if (leading.trim() !== '') {
invalid = 'look-alike - pre-keyword';
} else if (postKeyword.trim() !== '') {
invalid = 'look-alike - post-keyword';
}

let resolvedBase = base;
if (postKeyword !== '') {
if (resolvedBase.includes(' ')) {
const kw = resolvedBase.split(' ', 1)[0];
const remainder = resolvedBase.substring(kw.length);
resolvedBase = `${kw}${postKeyword} ${remainder}`;
} else {
if (resolvedBase.endsWith(':')) {
resolvedBase = `${resolvedBase.substring(0, resolvedBase.length - 1)}${postKeyword}:`;
} else {
resolvedBase = `${resolvedBase}${postKeyword}`;
}
}
}
if (preColon !== '') {
if (resolvedBase.endsWith(':')) {
resolvedBase = `${resolvedBase.substring(0, resolvedBase.length - 1)}${preColon}:`;
} else {
return [undefined, undefined, true];
}
}
const example = `${leading}${resolvedBase}${trailing}`;
return [example, invalid, false];
}

const cfg = getLanguageConfiguration();

suite('Language configuration - brackets', () => {
test('brackets is not defined', () => {
expect(cfg.brackets).to.be.equal(undefined, 'missing tests');
});
});

suite('Language configuration - comments', () => {
test('comments is not defined', () => {
expect(cfg.comments).to.be.equal(undefined, 'missing tests');
});
});

suite('Language configuration - indentationRules', () => {
test('indentationRules is not defined', () => {
expect(cfg.indentationRules).to.be.equal(undefined, 'missing tests');
});
});

suite('Language configuration - onEnterRules', () => {
const MULTILINE_SEPARATOR_INDENT_REGEX = cfg.onEnterRules![0].beforeText;
const INDENT_ONENTER_REGEX = cfg.onEnterRules![2].beforeText;
const OUTDENT_ONENTER_REGEX = cfg.onEnterRules![3].beforeText;
// To see the actual (non-verbose) regex patterns, un-comment
// the following lines:
//console.log(INDENT_ONENTER_REGEX.source);
//console.log(OUTDENT_ONENTER_REGEX.source);

test('Multiline separator indent regex should not pick up strings with no multiline separator', async () => {
Expand Down Expand Up @@ -147,46 +202,17 @@ suite('Language configuration regexes', () => {
['', '', '', ' # ...']
].forEach(whitespace => {
const [leading, postKeyword, preColon, trailing] = whitespace;
let invalid: string | undefined;
if (base.trim() === '') {
invalid = 'blank line';
} else if (leading === '' && isMember(base, NEEDS_INDENT)) {
invalid = 'expected indent';
} else if (leading.trim() !== '') {
invalid = 'look-alike - pre-keyword';
} else if (postKeyword.trim() !== '') {
invalid = 'look-alike - post-keyword';
}

let resolvedBase = base;
if (postKeyword !== '') {
if (resolvedBase.includes(' ')) {
const kw = resolvedBase.split(' ', 1)[0];
const remainder = resolvedBase.substring(kw.length);
resolvedBase = `${kw}${postKeyword} ${remainder}`;
} else {
if (resolvedBase.endsWith(':')) {
resolvedBase = `${resolvedBase.substring(0, resolvedBase.length - 1)}${postKeyword}:`;
} else {
resolvedBase = `${resolvedBase}${postKeyword}`;
}
}
}
if (preColon !== '') {
if (resolvedBase.endsWith(':')) {
resolvedBase = `${resolvedBase.substring(0, resolvedBase.length - 1)}${preColon}:`;
} else {
return;
}
const [_example, invalid, ignored] = resolveExample(base, leading, postKeyword, preColon, trailing);
if (ignored) {
return;
}
const example = `${leading}${resolvedBase}${trailing}`;
const example = _example!;

if (invalid) {
test(`Line "${example}" ignored (${invalid})`, () => {
let result = INCREASE_INDENT_REGEX.test(example);
expect(result).to.be.equal(false, 'unexpected match');
let result: boolean;

result = DECREASE_INDENT_REGEX.test(example);
result = INDENT_ONENTER_REGEX.test(example);
expect(result).to.be.equal(false, 'unexpected match');

result = OUTDENT_ONENTER_REGEX.test(example);
Expand All @@ -195,24 +221,13 @@ suite('Language configuration regexes', () => {
return;
}

test(`Check indent-on-match for line "${example}"`, () => {
let expected = false;
if (isMember(base, INDENT_ON_MATCH)) {
expected = true;
}

const result = INCREASE_INDENT_REGEX.test(example);

expect(result).to.be.equal(expected, 'unexpected result');
});

test(`Check dedent-on-match for line "${example}"`, () => {
test(`Check indent-on-enter for line "${example}"`, () => {
let expected = false;
if (isMember(base, DEDENT_ON_MATCH)) {
if (isMember(base, INDENT_ON_ENTER)) {
expected = true;
}

const result = DECREASE_INDENT_REGEX.test(example);
const result = INDENT_ONENTER_REGEX.test(example);

expect(result).to.be.equal(expected, 'unexpected result');
});
Expand All @@ -230,3 +245,9 @@ suite('Language configuration regexes', () => {
});
});
});

suite('Language configuration - wordPattern', () => {
test('wordPattern is not defined', () => {
expect(cfg.wordPattern).to.be.equal(undefined, 'missing tests');
});
});

0 comments on commit b9a2cf3

Please sign in to comment.