diff --git a/.gitignore b/.gitignore index 052afbc54035..cc941e968ccb 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ coverage/ .venv pythonFiles/experimental/ptvsd/** debug_coverage*/** +analysis/** diff --git a/src/client/extension.ts b/src/client/extension.ts index 4788030e98de..1a2eb6b7cb19 100644 --- a/src/client/extension.ts +++ b/src/client/extension.ts @@ -6,10 +6,12 @@ if ((Reflect as any).metadata === undefined) { require('reflect-metadata'); } import { Container } from 'inversify'; -import * as vscode from 'vscode'; -import { Disposable, Memento, OutputChannel, window } from 'vscode'; +import { + debug, Disposable, DocumentFilter, ExtensionContext, + extensions, IndentAction, languages, Memento, + OutputChannel, window +} from 'vscode'; import { PythonSettings } from './common/configSettings'; -import * as settings from './common/configSettings'; import { STANDARD_OUTPUT_CHANNEL } from './common/constants'; import { FeatureDeprecationManager } from './common/featureDeprecationManager'; import { createDeferred } from './common/helpers'; @@ -61,12 +63,12 @@ import * as tests from './unittests/main'; import { registerTypes as unitTestsRegisterTypes } from './unittests/serviceRegistry'; import { WorkspaceSymbols } from './workspaceSymbols/main'; -const PYTHON: vscode.DocumentFilter = { language: 'python' }; +const PYTHON: DocumentFilter = { language: 'python' }; const activationDeferred = createDeferred(); export const activated = activationDeferred.promise; // tslint:disable-next-line:max-func-body-length -export async function activate(context: vscode.ExtensionContext) { +export async function activate(context: ExtensionContext) { const cont = new Container(); const serviceManager = new ServiceManager(cont); const serviceContainer = new ServiceContainer(cont); @@ -95,7 +97,7 @@ export async function activate(context: vscode.ExtensionContext) { serviceManager.get(ICodeExecutionManager).registerCommands(); const persistentStateFactory = serviceManager.get(IPersistentStateFactory); - const pythonSettings = settings.PythonSettings.getInstance(); + const pythonSettings = PythonSettings.getInstance(); // tslint:disable-next-line:no-floating-promises sendStartupTelemetry(activated, serviceContainer); @@ -125,60 +127,60 @@ export async function activate(context: vscode.ExtensionContext) { // Enable indentAction // tslint:disable-next-line:no-non-null-assertion - vscode.languages.setLanguageConfiguration(PYTHON.language!, { + languages.setLanguageConfiguration(PYTHON.language!, { onEnterRules: [ { beforeText: /^\s*(?:def|class|for|if|elif|else|while|try|with|finally|except|async)\b.*/, - action: { indentAction: vscode.IndentAction.Indent } + action: { indentAction: IndentAction.Indent } }, { beforeText: /^\s*#.*/, afterText: /.+$/, - action: { indentAction: vscode.IndentAction.None, appendText: '# ' } + action: { indentAction: IndentAction.None, appendText: '# ' } }, { beforeText: /^\s+(continue|break|return)\b.*/, afterText: /\s+$/, - action: { indentAction: vscode.IndentAction.Outdent } + action: { indentAction: IndentAction.Outdent } } ] }); context.subscriptions.push(jediFactory); - context.subscriptions.push(vscode.languages.registerRenameProvider(PYTHON, new PythonRenameProvider(serviceContainer))); + context.subscriptions.push(languages.registerRenameProvider(PYTHON, new PythonRenameProvider(serviceContainer))); const definitionProvider = new PythonDefinitionProvider(jediFactory); - context.subscriptions.push(vscode.languages.registerDefinitionProvider(PYTHON, definitionProvider)); - context.subscriptions.push(vscode.languages.registerHoverProvider(PYTHON, new PythonHoverProvider(jediFactory))); - context.subscriptions.push(vscode.languages.registerReferenceProvider(PYTHON, new PythonReferenceProvider(jediFactory))); - context.subscriptions.push(vscode.languages.registerCompletionItemProvider(PYTHON, new PythonCompletionItemProvider(jediFactory, serviceContainer), '.')); - context.subscriptions.push(vscode.languages.registerCodeLensProvider(PYTHON, serviceContainer.get(IShebangCodeLensProvider))); + context.subscriptions.push(languages.registerDefinitionProvider(PYTHON, definitionProvider)); + context.subscriptions.push(languages.registerHoverProvider(PYTHON, new PythonHoverProvider(jediFactory))); + context.subscriptions.push(languages.registerReferenceProvider(PYTHON, new PythonReferenceProvider(jediFactory))); + context.subscriptions.push(languages.registerCompletionItemProvider(PYTHON, new PythonCompletionItemProvider(jediFactory, serviceContainer), '.')); + context.subscriptions.push(languages.registerCodeLensProvider(PYTHON, serviceContainer.get(IShebangCodeLensProvider))); const symbolProvider = new PythonSymbolProvider(jediFactory); - context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(PYTHON, symbolProvider)); + context.subscriptions.push(languages.registerDocumentSymbolProvider(PYTHON, symbolProvider)); if (pythonSettings.devOptions.indexOf('DISABLE_SIGNATURE') === -1) { - context.subscriptions.push(vscode.languages.registerSignatureHelpProvider(PYTHON, new PythonSignatureProvider(jediFactory), '(', ',')); + context.subscriptions.push(languages.registerSignatureHelpProvider(PYTHON, new PythonSignatureProvider(jediFactory), '(', ',')); } if (pythonSettings.formatting.provider !== 'none') { const formatProvider = new PythonFormattingEditProvider(context, serviceContainer); - context.subscriptions.push(vscode.languages.registerDocumentFormattingEditProvider(PYTHON, formatProvider)); - context.subscriptions.push(vscode.languages.registerDocumentRangeFormattingEditProvider(PYTHON, formatProvider)); + context.subscriptions.push(languages.registerDocumentFormattingEditProvider(PYTHON, formatProvider)); + context.subscriptions.push(languages.registerDocumentRangeFormattingEditProvider(PYTHON, formatProvider)); } const linterProvider = new LinterProvider(context, serviceContainer); context.subscriptions.push(linterProvider); - const jupyterExtension = vscode.extensions.getExtension('donjayamanne.jupyter'); + const jupyterExtension = extensions.getExtension('donjayamanne.jupyter'); const lintingEngine = serviceContainer.get(ILintingEngine); lintingEngine.linkJupiterExtension(jupyterExtension).ignoreErrors(); tests.activate(context, unitTestOutChannel, symbolProvider, serviceContainer); context.subscriptions.push(new WorkspaceSymbols(serviceContainer)); - context.subscriptions.push(vscode.languages.registerOnTypeFormattingEditProvider(PYTHON, new BlockFormatProviders(), ':')); - context.subscriptions.push(vscode.languages.registerOnTypeFormattingEditProvider(PYTHON, new OnEnterFormatter(), '\n')); + context.subscriptions.push(languages.registerOnTypeFormattingEditProvider(PYTHON, new BlockFormatProviders(), ':')); + context.subscriptions.push(languages.registerOnTypeFormattingEditProvider(PYTHON, new OnEnterFormatter(), '\n')); serviceContainer.getAll(IDebugConfigurationProvider).forEach(debugConfig => { - context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider(debugConfig.debugType, debugConfig)); + context.subscriptions.push(debug.registerDebugConfigurationProvider(debugConfig.debugType, debugConfig)); }); activationDeferred.resolve(); diff --git a/src/client/language/tokenizer.ts b/src/client/language/tokenizer.ts index ecd382d96541..c481c4201ac0 100644 --- a/src/client/language/tokenizer.ts +++ b/src/client/language/tokenizer.ts @@ -34,10 +34,10 @@ export class Tokenizer implements ITokenizer { // 'not', 'or', 'pass', 'print', 'raise', 'return', 'True', 'try', // 'while', 'with', 'yield' // ]; - private cs: ICharacterStream; + private cs: ICharacterStream = new CharacterStream(''); private tokens: IToken[] = []; private floatRegex = /[-+]?(?:(?:\d*\.\d+)|(?:\d+\.?))(?:[Ee][+-]?\d+)?/; - private mode: TokenizerMode; + private mode = TokenizerMode.Full; constructor() { //this.floatRegex.compile(); @@ -287,7 +287,7 @@ export class Tokenizer implements ITokenizer { } else if (nextChar === Char.Less) { length = this.cs.lookAhead(2) === Char.Equal ? 3 : 2; } else { - length = 1; + length = nextChar === Char.Equal ? 2 : 1; } break; @@ -295,7 +295,7 @@ export class Tokenizer implements ITokenizer { if (nextChar === Char.Greater) { length = this.cs.lookAhead(2) === Char.Equal ? 3 : 2; } else { - length = 1; + length = nextChar === Char.Equal ? 2 : 1; } break; diff --git a/src/client/providers/completionSource.ts b/src/client/providers/completionSource.ts index 3496f38a6f99..5a2064c9338c 100644 --- a/src/client/providers/completionSource.ts +++ b/src/client/providers/completionSource.ts @@ -61,7 +61,7 @@ export class CompletionSource { const sourceText = `${document.getText(leadingRange)}${itemString}`; const range = new vscode.Range(leadingRange.end, leadingRange.end.translate(0, itemString.length)); - return await this.itemInfoSource.getItemInfoFromText(document.uri, document.fileName, range, sourceText, token); + return this.itemInfoSource.getItemInfoFromText(document.uri, document.fileName, range, sourceText, token); } private async getCompletionResult(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) @@ -90,7 +90,7 @@ export class CompletionSource { source: source }; - return await this.jediFactory.getJediProxyHandler(document.uri).sendCommand(cmd, token); + return this.jediFactory.getJediProxyHandler(document.uri).sendCommand(cmd, token); } private toVsCodeCompletions(documentPosition: DocumentPosition, data: proxy.ICompletionResult, resource: vscode.Uri): vscode.CompletionItem[] { diff --git a/src/client/providers/providerUtilities.ts b/src/client/providers/providerUtilities.ts index 4b113c61eceb..0a4f8274144d 100644 --- a/src/client/providers/providerUtilities.ts +++ b/src/client/providers/providerUtilities.ts @@ -13,10 +13,19 @@ export function getDocumentTokens(document: vscode.TextDocument, tokenizeTo: vsc export function isPositionInsideStringOrComment(document: vscode.TextDocument, position: vscode.Position): boolean { const tokenizeTo = position.translate(1, 0); const tokens = getDocumentTokens(document, tokenizeTo, TokenizerMode.CommentsAndStrings); - const index = tokens.getItemContaining(document.offsetAt(position)); + const offset = document.offsetAt(position); + let index = tokens.getItemContaining(offset); if (index >= 0) { const token = tokens.getItemAt(index); return token.type === TokenType.String || token.type === TokenType.Comment; } + if (offset > 0) { + // In case position is at the every end of the comment or unterminated string + index = tokens.getItemContaining(offset - 1); + if (index >= 0) { + const token = tokens.getItemAt(index); + return token.end === offset && token.type === TokenType.Comment; + } + } return false; } diff --git a/src/test/autocomplete/base.test.ts b/src/test/autocomplete/base.test.ts index bf07ac4fd783..4c4b8fd65992 100644 --- a/src/test/autocomplete/base.test.ts +++ b/src/test/autocomplete/base.test.ts @@ -195,10 +195,11 @@ suite('Autocomplete', () => { new vscode.Position(3, 0), // false new vscode.Position(4, 2), // false new vscode.Position(4, 8), // false - new vscode.Position(5, 4) // false + new vscode.Position(5, 4), // false + new vscode.Position(5, 10) // false ]; const expected = [ - false, true, false, false, false, false, false, false, false, false + false, true, false, false, false, false, false, false, false, false, false ]; const textDocument = await vscode.workspace.openTextDocument(fileSuppress); await vscode.window.showTextDocument(textDocument); diff --git a/src/test/language/tokenizer.test.ts b/src/test/language/tokenizer.test.ts index e2a5b3f6defb..1d2bf15d2b7b 100644 --- a/src/test/language/tokenizer.test.ts +++ b/src/test/language/tokenizer.test.ts @@ -180,7 +180,7 @@ suite('Language.Tokenizer', () => { }); test('Operators', async () => { const text = '< <> << <<= ' + - '== != > >> >>= ' + + '== != > >> >>= >= <=' + '+ -' + '* ** / /= //=' + '*= += -= **= ' + @@ -188,7 +188,7 @@ suite('Language.Tokenizer', () => { const tokens = new Tokenizer().tokenize(text); const lengths = [ 1, 2, 2, 3, - 2, 2, 1, 2, 3, + 2, 2, 1, 2, 3, 2, 2, 1, 1, 1, 2, 1, 2, 3, 2, 2, 2, 3, diff --git a/tslint.json b/tslint.json index 2746486ce48a..600e28f64075 100644 --- a/tslint.json +++ b/tslint.json @@ -59,6 +59,7 @@ ], "no-unnecessary-type-assertion": false, "no-submodule-imports": false, - "no-redundant-jsdoc": false + "no-redundant-jsdoc": false, + "binary-expression-operand-order": false } -} +} \ No newline at end of file