From ab37cd2753a737f57ba2c72141217f017f4cb044 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Tue, 10 Apr 2018 09:03:15 -0700 Subject: [PATCH] Restricting language services to local files --- src/format/rubyFormat.ts | 4 +- src/providers/completion.ts | 6 +- src/providers/formatter.ts | 6 +- src/providers/highlight.ts | 6 +- src/providers/intellisense.ts | 105 ++++++++++++++++------------------ src/ruby.ts | 22 ++++--- src/task/rake.ts | 4 -- 7 files changed, 75 insertions(+), 78 deletions(-) diff --git a/src/format/rubyFormat.ts b/src/format/rubyFormat.ts index 5bd654f20..4ea84a250 100644 --- a/src/format/rubyFormat.ts +++ b/src/format/rubyFormat.ts @@ -6,7 +6,7 @@ import { AutoCorrect } from './RuboCop'; export class RubyDocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider { private autoCorrect: AutoCorrect; - public register(ctx: vscode.ExtensionContext) { + public register(ctx: vscode.ExtensionContext, documentSelector: vscode.DocumentSelector) { // only attempt to format if ruby.format is set to rubocop if (vscode.workspace.getConfiguration("ruby").get("format") !== "rubocop") { return; @@ -15,7 +15,7 @@ export class RubyDocumentFormattingEditProvider implements vscode.DocumentFormat this.autoCorrect = new AutoCorrect(); this.autoCorrect.test().then( () => ctx.subscriptions.push( - vscode.languages.registerDocumentFormattingEditProvider('ruby', this) + vscode.languages.registerDocumentFormattingEditProvider(documentSelector, this) ) // silent failure - AutoCorrect will handle error messages ); diff --git a/src/providers/completion.ts b/src/providers/completion.ts index 446698c07..4fc72ab5b 100644 --- a/src/providers/completion.ts +++ b/src/providers/completion.ts @@ -1,8 +1,8 @@ import * as vscode from 'vscode'; -import { ExtensionContext } from 'vscode'; +import { DocumentSelector, ExtensionContext } from 'vscode'; import * as cp from 'child_process'; -export function registerCompletionProvider(ctx: ExtensionContext) { +export function registerCompletionProvider(ctx: ExtensionContext, documentSelector: DocumentSelector) { if (vscode.workspace.getConfiguration('ruby').codeCompletion == 'rcodetools') { const completeCommand = function (args) { let rctCompletePath = vscode.workspace.getConfiguration('ruby.rctComplete').get('commandPath', 'rct-complete'); @@ -17,7 +17,7 @@ export function registerCompletionProvider(ctx: ExtensionContext) { completeTest.on('exit', () => { ctx.subscriptions.push( vscode.languages.registerCompletionItemProvider( - /** selector */'ruby', + /** selector */documentSelector, /** provider */{ provideCompletionItems: function completionProvider(document, position, token) { return new Promise((resolve, reject) => { diff --git a/src/providers/formatter.ts b/src/providers/formatter.ts index 71cc36c70..c80ee54c0 100644 --- a/src/providers/formatter.ts +++ b/src/providers/formatter.ts @@ -1,6 +1,6 @@ -import { ExtensionContext } from 'vscode'; +import { DocumentSelector, ExtensionContext } from 'vscode'; import { RubyDocumentFormattingEditProvider } from '../format/rubyFormat'; -export function registerFormatter(ctx: ExtensionContext) { - new RubyDocumentFormattingEditProvider().register(ctx); +export function registerFormatter(ctx: ExtensionContext, documentSelector: DocumentSelector) { + new RubyDocumentFormattingEditProvider().register(ctx, documentSelector); } diff --git a/src/providers/highlight.ts b/src/providers/highlight.ts index 6103af9e1..e3c7d5cdf 100644 --- a/src/providers/highlight.ts +++ b/src/providers/highlight.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; -import { ExtensionContext } from 'vscode'; +import { DocumentSelector, ExtensionContext } from 'vscode'; -export function registerHighlightProvider(ctx: ExtensionContext) { +export function registerHighlightProvider(ctx: ExtensionContext, documentSelector: DocumentSelector) { // highlight provider let pairedEnds = []; @@ -48,7 +48,7 @@ export function registerHighlightProvider(ctx: ExtensionContext) { if (event && event.document) balancePairs(event.document); } - ctx.subscriptions.push(vscode.languages.registerDocumentHighlightProvider('ruby', { + ctx.subscriptions.push(vscode.languages.registerDocumentHighlightProvider(documentSelector, { provideDocumentHighlights: (doc, pos) => { let result = pairedEnds.find(pair => ( pair.entry.start.line === pos.line || diff --git a/src/providers/intellisense.ts b/src/providers/intellisense.ts index 4d3ac0cb6..0e7b3e984 100644 --- a/src/providers/intellisense.ts +++ b/src/providers/intellisense.ts @@ -5,63 +5,56 @@ import * as Locate from '../locate/locate'; export function registerIntellisenseProvider(ctx: ExtensionContext) { // for locate: if it's a project, use the root, othewise, don't bother if (vscode.workspace.getConfiguration('ruby').intellisense == 'rubyLocate') { - if (vscode.workspace.rootPath) { - const refreshLocate = () => { - let progressOptions = { location: vscode.ProgressLocation.Window, title: 'Indexing Ruby source files' }; - vscode.window.withProgress(progressOptions, () => locate.walk()); - }; - const settings: any = vscode.workspace.getConfiguration("ruby.locate") || {}; - let locate = new Locate(vscode.workspace.rootPath, settings); - refreshLocate(); - ctx.subscriptions.push(vscode.commands.registerCommand('ruby.reloadProject', refreshLocate)); + const refreshLocate = () => { + let progressOptions = { location: vscode.ProgressLocation.Window, title: 'Indexing Ruby source files' }; + vscode.window.withProgress(progressOptions, () => locate.walk()); + }; + const settings: any = vscode.workspace.getConfiguration("ruby.locate") || {}; + let locate = new Locate(vscode.workspace.rootPath, settings); + refreshLocate(); + ctx.subscriptions.push(vscode.commands.registerCommand('ruby.reloadProject', refreshLocate)); - const watch = vscode.workspace.createFileSystemWatcher(settings.include); - watch.onDidChange(uri => locate.parse(uri.fsPath)); - watch.onDidCreate(uri => locate.parse(uri.fsPath)); - watch.onDidDelete(uri => locate.rm(uri.fsPath)); - const locationConverter = match => new vscode.Location(vscode.Uri.file(match.file), new vscode.Position(match.line, match.char)); - const defProvider = { - provideDefinition: (doc, pos) => { - const txt = doc.getText(doc.getWordRangeAtPosition(pos)); - return locate.find(txt).then(matches => matches.map(locationConverter)); - } - }; - ctx.subscriptions.push(vscode.languages.registerDefinitionProvider(['ruby', 'erb'], defProvider)); - const symbolKindTable = { - class: () => SymbolKind.Class, - module: () => SymbolKind.Module, - method: symbolInfo => symbolInfo.name === 'initialize' ? SymbolKind.Constructor : SymbolKind.Method, - classMethod: () => SymbolKind.Method, - }; - const defaultSymbolKind = symbolInfo => { - console.warn(`Unknown symbol type: ${symbolInfo.type}`); - return SymbolKind.Variable; - }; - // NOTE: Workaround for high CPU usage on IPC (channel.onread) when too many symbols returned. - // For channel.onread see issue like this: https://github.com/Microsoft/vscode/issues/6026 - const numOfSymbolLimit = 3000; - const symbolsConverter = matches => matches.slice(0, numOfSymbolLimit).map(match => { - const symbolKind = (symbolKindTable[match.type] || defaultSymbolKind)(match); - return new SymbolInformation(match.name, symbolKind, match.containerName, locationConverter(match)); - }); - const docSymbolProvider = { - provideDocumentSymbols: (document, token) => { - return locate.listInFile(document.fileName).then(symbolsConverter); - } - }; - ctx.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(['ruby', 'erb'], docSymbolProvider)); - const workspaceSymbolProvider = { - provideWorkspaceSymbols: (query, token) => { - return locate.query(query).then(symbolsConverter); - } - }; - ctx.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(workspaceSymbolProvider)); - } else { - var rubyLocateUnavailable = () => { - vscode.window.showInformationMessage('There is not an open workspace for rubyLocate to reload.'); - }; - ctx.subscriptions.push(vscode.commands.registerCommand('ruby.reloadProject', rubyLocateUnavailable)); - } + const watch = vscode.workspace.createFileSystemWatcher(settings.include); + watch.onDidChange(uri => locate.parse(uri.fsPath)); + watch.onDidCreate(uri => locate.parse(uri.fsPath)); + watch.onDidDelete(uri => locate.rm(uri.fsPath)); + const locationConverter = match => new vscode.Location(vscode.Uri.file(match.file), new vscode.Position(match.line, match.char)); + const defProvider = { + provideDefinition: (doc, pos) => { + const txt = doc.getText(doc.getWordRangeAtPosition(pos)); + return locate.find(txt).then(matches => matches.map(locationConverter)); + } + }; + ctx.subscriptions.push(vscode.languages.registerDefinitionProvider(['ruby', 'erb'], defProvider)); + const symbolKindTable = { + class: () => SymbolKind.Class, + module: () => SymbolKind.Module, + method: symbolInfo => symbolInfo.name === 'initialize' ? SymbolKind.Constructor : SymbolKind.Method, + classMethod: () => SymbolKind.Method, + }; + const defaultSymbolKind = symbolInfo => { + console.warn(`Unknown symbol type: ${symbolInfo.type}`); + return SymbolKind.Variable; + }; + // NOTE: Workaround for high CPU usage on IPC (channel.onread) when too many symbols returned. + // For channel.onread see issue like this: https://github.com/Microsoft/vscode/issues/6026 + const numOfSymbolLimit = 3000; + const symbolsConverter = matches => matches.slice(0, numOfSymbolLimit).map(match => { + const symbolKind = (symbolKindTable[match.type] || defaultSymbolKind)(match); + return new SymbolInformation(match.name, symbolKind, match.containerName, locationConverter(match)); + }); + const docSymbolProvider = { + provideDocumentSymbols: (document, token) => { + return locate.listInFile(document.fileName).then(symbolsConverter); + } + }; + ctx.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(['ruby', 'erb'], docSymbolProvider)); + const workspaceSymbolProvider = { + provideWorkspaceSymbols: (query, token) => { + return locate.query(query).then(symbolsConverter); + } + }; + ctx.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(workspaceSymbolProvider)); } else { var rubyLocateDisabled = () => { vscode.window.showInformationMessage('The `ruby.intellisense` configuration is not set to use rubyLocate.') diff --git a/src/ruby.ts b/src/ruby.ts index 0bf385392..b243a19c9 100644 --- a/src/ruby.ts +++ b/src/ruby.ts @@ -1,6 +1,6 @@ 'use strict'; -import { ExtensionContext, languages } from 'vscode'; +import { ExtensionContext, languages, workspace } from 'vscode'; import * as utils from './utils'; @@ -11,6 +11,11 @@ import { registerIntellisenseProvider } from './providers/intellisense'; import { registerLinters } from './providers/linters'; import { registerTaskProvider } from './task/rake'; +const DOCUMENT_SELECTOR = [ + { language: 'ruby', scheme: 'file' }, + { language: 'ruby', scheme: 'untitled' } +]; + export function activate(context: ExtensionContext) { const subs = context.subscriptions; @@ -24,12 +29,15 @@ export function activate(context: ExtensionContext) { }); // Register providers - registerHighlightProvider(context); - registerLinters(context); - registerCompletionProvider(context); - registerFormatter(context); - registerIntellisenseProvider(context); - registerTaskProvider(context); + registerHighlightProvider(context, DOCUMENT_SELECTOR); + registerCompletionProvider(context, DOCUMENT_SELECTOR); + registerFormatter(context, DOCUMENT_SELECTOR); + + if (workspace.rootPath) { + registerLinters(context); + registerIntellisenseProvider(context); + registerTaskProvider(context); + } utils.loadEnv(); } diff --git a/src/task/rake.ts b/src/task/rake.ts index e9104688d..86807097d 100644 --- a/src/task/rake.ts +++ b/src/task/rake.ts @@ -8,10 +8,6 @@ import { getOutputChannel, exec } from '../utils'; let rakeFiles: Set = new Set(); export async function registerTaskProvider(ctx: vscode.ExtensionContext) { - let workspaceRoot = vscode.workspace.rootPath; - if (!workspaceRoot) { - return; - } let rakePromise: Thenable | undefined = undefined; let files = await vscode.workspace.findFiles("**/[rR]akefile{,.rb}"); for (let i = 0; i < files.length; i++) {