Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix indentation after string literals containing escaped characters #6440

1 change: 1 addition & 0 deletions news/2 Fixes/4241.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix indentation after string literals containing escaped characters.
29 changes: 3 additions & 26 deletions src/client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
Disposable,
ExtensionContext,
extensions,
IndentAction,
languages,
Memento,
OutputChannel,
Expand All @@ -41,7 +40,7 @@ import { registerTypes as appRegisterTypes } from './application/serviceRegistry
import { IApplicationDiagnostics } from './application/types';
import { DebugService } from './common/application/debugService';
import { IApplicationShell, ICommandManager, IWorkspaceService } from './common/application/types';
import { Commands, isTestExecution, PYTHON, PYTHON_LANGUAGE, STANDARD_OUTPUT_CHANNEL } from './common/constants';
import { Commands, isTestExecution, PYTHON, STANDARD_OUTPUT_CHANNEL } from './common/constants';
import { registerTypes as registerDotNetTypes } from './common/dotnet/serviceRegistry';
import { registerTypes as installerRegisterTypes } from './common/installer/serviceRegistry';
import { traceError } from './common/logger';
Expand Down Expand Up @@ -86,6 +85,7 @@ import { registerTypes as interpretersRegisterTypes } from './interpreter/servic
import { ServiceContainer } from './ioc/container';
import { ServiceManager } from './ioc/serviceManager';
import { IServiceContainer, IServiceManager } from './ioc/types';
import { setLanguageConfiguration } from './language/languageConfiguration';
import { LinterCommands } from './linters/linterCommands';
import { registerTypes as lintersRegisterTypes } from './linters/serviceRegistry';
import { ILintingEngine } from './linters/types';
Expand Down Expand Up @@ -173,30 +173,7 @@ async function activateUnsafe(context: ExtensionContext): Promise<IExtensionApi>
const linterProvider = new LinterProvider(context, serviceManager);
context.subscriptions.push(linterProvider);

// Enable indentAction
// tslint:disable-next-line:no-non-null-assertion
languages.setLanguageConfiguration(PYTHON_LANGUAGE, {
onEnterRules: [
{
beforeText: /^\s*(?:def|class|for|if|elif|else|while|try|with|finally|except|async)\b.*:\s*/,
action: { indentAction: IndentAction.Indent }
},
{
beforeText: /^(?!\s+\\)[^#\n]+\\\s*/,
action: { indentAction: IndentAction.Indent }
},
{
beforeText: /^\s*#.*/,
afterText: /.+$/,
action: { indentAction: IndentAction.None, appendText: '# ' }
},
{
beforeText: /^\s+(continue|break|return)\b.*/,
afterText: /\s+$/,
action: { indentAction: IndentAction.Outdent }
}
]
});
setLanguageConfiguration();

if (pythonSettings && pythonSettings.formatting && pythonSettings.formatting.provider !== 'internalConsole') {
const formatProvider = new PythonFormattingEditProvider(context, serviceContainer);
Expand Down
34 changes: 34 additions & 0 deletions src/client/language/languageConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';

import { IndentAction, languages } from 'vscode';
import { PYTHON_LANGUAGE } from '../common/constants';

export const MULTILINE_SEPARATOR_INDENT_REGEX = /^(?!\s+\\)[^#\n]+\\$/;

export function setLanguageConfiguration() {
// Enable indentAction
languages.setLanguageConfiguration(PYTHON_LANGUAGE, {
onEnterRules: [
{
beforeText: /^\s*(?:def|class|for|if|elif|else|while|try|with|finally|except|async)\b.*:\s*/,
action: { indentAction: IndentAction.Indent }
},
{
beforeText: MULTILINE_SEPARATOR_INDENT_REGEX,
action: { indentAction: IndentAction.Indent }
},
{
beforeText: /^\s*#.*/,
afterText: /.+$/,
action: { indentAction: IndentAction.None, appendText: '# ' }
},
{
beforeText: /^\s+(continue|break|return)\b.*/,
afterText: /\s+$/,
action: { indentAction: IndentAction.Outdent }
}
]
});
}
23 changes: 23 additions & 0 deletions src/test/language/languageConfiguration.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

'use strict';

import { expect } from 'chai';

import { MULTILINE_SEPARATOR_INDENT_REGEX } from '../../client/language/languageConfiguration';

suite('Language configuration regexes', () => {
test('Multiline separator indent regex should not pick up strings with no multiline separator', async () => {
const result = MULTILINE_SEPARATOR_INDENT_REGEX.test('a = "test"');
expect (result).to.be.equal(false, 'Multiline separator indent regex for regular strings should not have matches');
});
test('Multiline separator indent regex should not pick up strings with escaped characters', async () => {
const result = MULTILINE_SEPARATOR_INDENT_REGEX.test('a = \'hello \\n\'');
expect (result).to.be.equal(false, 'Multiline separator indent regex for strings with escaped characters should not have matches');
});
test('Multiline separator indent regex should pick up strings ending with a multiline separator', async () => {
const result = MULTILINE_SEPARATOR_INDENT_REGEX.test('a = \'multiline \\');
expect (result).to.be.equal(true, 'Multiline separator indent regex for strings with newline separator should have matches');
});
});