From 9746efff7be5088c4704c629beafe4624cd47447 Mon Sep 17 00:00:00 2001 From: Fred Snyder Date: Tue, 6 Mar 2018 10:19:04 -0500 Subject: [PATCH 1/4] Remove castwide.solargraph dependency --- package.json | 15 --------------- src/ruby.ts | 8 ++------ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 2c59faef5..8fa99f08e 100644 --- a/package.json +++ b/package.json @@ -69,9 +69,6 @@ "vscode": "^1.1.4", "vscode-debugadapter-testsupport": "^1.19.0" }, - "extensionDependencies": [ - "castwide.solargraph" - ], "scripts": { "vscode:prepublish": "tsc -p ./src", "compile": "tsc -p ./src", @@ -133,18 +130,6 @@ "description": "Path to the Ruby interpreter. Set this to an absolute path to select from multiple installed Ruby versions.", "isExecutable": true }, - "ruby.codeCompletion": { - "type": "string", - "enum": ["solargraph", "rcodetools", "none"], - "default": "solargraph", - "description": "Method to use for code completion." - }, - "ruby.intellisense": { - "type": "string", - "enum": ["solargraph", "rubyLocate", "none"], - "default": "solargraph", - "description": "Method to use for intellisense (go to definition, etc.)." - }, "ruby.useBundler": { "type": ["boolean", "null"], "default": null, diff --git a/src/ruby.ts b/src/ruby.ts index 00db5da4b..da27f9c3a 100644 --- a/src/ruby.ts +++ b/src/ruby.ts @@ -25,13 +25,9 @@ export function activate(context: ExtensionContext) { registerHighlightProvider(context); registerLinters(context); - if (vscode.workspace.getConfiguration('ruby').codeCompletion == 'rcodetools') { - registerCompletionProvider(context); - } + registerCompletionProvider(context); registerFormatter(context); - if (vscode.workspace.getConfiguration('ruby').intellisense == 'rubyLocate') { - registerIntellisenseProvider(context); - } + registerIntellisenseProvider(context); registerTaskProvider(context); utils.loadEnv(); } From c058e637b126696a4e334db47cbda242df1dcd85 Mon Sep 17 00:00:00 2001 From: Fred Snyder Date: Thu, 8 Mar 2018 10:43:39 -0500 Subject: [PATCH 2/4] codeCompletion and intellisense provider settings --- package.json | 13 ++++++++++++- src/ruby.ts | 8 ++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8fa99f08e..c4e7eb42a 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,18 @@ "description": "Path to the Ruby interpreter. Set this to an absolute path to select from multiple installed Ruby versions.", "isExecutable": true }, - "ruby.useBundler": { + "ruby.codeCompletion": { + "type": "string", + "enum": ["rcodetools", "other"], + "default": "rcodetools", + "description": "Method to use for code completion. Use `other` if another extension provides this feature." + }, + "ruby.intellisense": { + "type": "string", + "enum": ["rubyLocate", "other"], + "default": "rubyLocate", + "description": "Method to use for intellisense (go to definition, etc.). Use `other` if another extension provides this feature." +}, "ruby.useBundler": { "type": ["boolean", "null"], "default": null, "description": "Whether ruby tools should be started using Bundler" diff --git a/src/ruby.ts b/src/ruby.ts index da27f9c3a..00db5da4b 100644 --- a/src/ruby.ts +++ b/src/ruby.ts @@ -25,9 +25,13 @@ export function activate(context: ExtensionContext) { registerHighlightProvider(context); registerLinters(context); - registerCompletionProvider(context); + if (vscode.workspace.getConfiguration('ruby').codeCompletion == 'rcodetools') { + registerCompletionProvider(context); + } registerFormatter(context); - registerIntellisenseProvider(context); + if (vscode.workspace.getConfiguration('ruby').intellisense == 'rubyLocate') { + registerIntellisenseProvider(context); + } registerTaskProvider(context); utils.loadEnv(); } From 1f6c18a296524357f25b32f8e677bab26d03ae0f Mon Sep 17 00:00:00 2001 From: Fred Snyder Date: Wed, 28 Mar 2018 08:34:08 -0400 Subject: [PATCH 3/4] Use `false` to disable codeCompletion and intellisense. Informative messages for disabled ruby.reloadProject command. --- package.json | 18 ++-- src/ruby.ts | 232 +++++++++++++++++++++++++++------------------------ 2 files changed, 130 insertions(+), 120 deletions(-) diff --git a/package.json b/package.json index b306be9a8..489598f7a 100644 --- a/package.json +++ b/package.json @@ -131,16 +131,16 @@ "isExecutable": true }, "ruby.codeCompletion": { - "type": "string", - "enum": ["rcodetools", "other"], - "default": "rcodetools", - "description": "Method to use for code completion. Use `other` if another extension provides this feature." + "type": ["boolean", "string"], + "enum": [false, "rcodetools"], + "default": false, + "description": "Method to use for code completion. Use `false` to disable or if another extension provides this feature." }, "ruby.intellisense": { - "type": "string", - "enum": ["solargraph", "rubyLocate", "none"], - "default": "solargraph", - "description": "Method to use for intellisense (go to definition, etc.)." + "type": ["boolean", "string"], + "enum": [false, "rubyLocate"], + "default": false, + "description": "Method to use for intellisense (go to definition, etc.). Use `false` to disable or if another extension provides this feature." }, "ruby.useBundler": { "type": "boolean", @@ -286,7 +286,7 @@ "type": [ "boolean", "string" ], "enum": [ false, "rubocop" ], "default": false, - "description": "Which system to use for formatting, or false for no formatting" + "description": "Which system to use for formatting. Use `false` to disable or if another extension provides this feature." } } }, diff --git a/src/ruby.ts b/src/ruby.ts index 00db5da4b..1c12523b5 100644 --- a/src/ruby.ts +++ b/src/ruby.ts @@ -25,13 +25,9 @@ export function activate(context: ExtensionContext) { registerHighlightProvider(context); registerLinters(context); - if (vscode.workspace.getConfiguration('ruby').codeCompletion == 'rcodetools') { - registerCompletionProvider(context); - } + registerCompletionProvider(context); registerFormatter(context); - if (vscode.workspace.getConfiguration('ruby').intellisense == 'rubyLocate') { - registerIntellisenseProvider(context); - } + registerIntellisenseProvider(context); registerTaskProvider(context); utils.loadEnv(); } @@ -151,65 +147,67 @@ function registerLinters(ctx: ExtensionContext) { } function registerCompletionProvider(ctx: ExtensionContext) { - const completeCommand = function(args) { - let rctCompletePath = vscode.workspace.getConfiguration('ruby.rctComplete').get('commandPath', 'rct-complete'); - args.push('--interpreter'); - args.push(vscode.workspace.getConfiguration('ruby.interpreter').get('commandPath', 'ruby')); - if (process.platform === 'win32') - return cp.spawn('cmd', ['/c', rctCompletePath].concat(args)); - return cp.spawn(rctCompletePath, args); - } + if (vscode.workspace.getConfiguration('ruby').codeCompletion == 'rcodetools') { + const completeCommand = function (args) { + let rctCompletePath = vscode.workspace.getConfiguration('ruby.rctComplete').get('commandPath', 'rct-complete'); + args.push('--interpreter'); + args.push(vscode.workspace.getConfiguration('ruby.interpreter').get('commandPath', 'ruby')); + if (process.platform === 'win32') + return cp.spawn('cmd', ['/c', rctCompletePath].concat(args)); + return cp.spawn(rctCompletePath, args); + } - const completeTest = completeCommand(['--help']); - completeTest.on('exit', () => { - ctx.subscriptions.push( - vscode.languages.registerCompletionItemProvider( - /** selector */'ruby', - /** provider */{ - provideCompletionItems: function completionProvider(document, position, token) { - return new Promise((resolve, reject) => { - const line = position.line + 1; - const column = position.character; - let child = completeCommand([ - '--completion-class-info', - '--dev', - '--fork', - '--line=' + line, - '--column=' + column - ]); - let outbuf = [], - errbuf = []; - child.stderr.on('data', (data) => errbuf.push(data)); - child.stdout.on('data', (data) => outbuf.push(data)); - child.stdout.on('end', () => { - if (errbuf.length > 0) return reject(Buffer.concat(errbuf).toString()); - let completionItems = []; - Buffer.concat(outbuf).toString().split('\n').forEach(function (elem) { - let items = elem.split('\t'); - if (/^[^\w]/.test(items[0])) return; - if (items[0].trim().length === 0) return; - let completionItem = new vscode.CompletionItem(items[0]); - completionItem.detail = items[1]; - completionItem.documentation = items[1]; - completionItem.filterText = items[0]; - completionItem.insertText = items[0]; - completionItem.label = items[0]; - completionItem.kind = vscode.CompletionItemKind.Method; - completionItems.push(completionItem); - }, this); - if (completionItems.length === 0) - return reject([]); - return resolve(completionItems); + const completeTest = completeCommand(['--help']); + completeTest.on('exit', () => { + ctx.subscriptions.push( + vscode.languages.registerCompletionItemProvider( + /** selector */'ruby', + /** provider */{ + provideCompletionItems: function completionProvider(document, position, token) { + return new Promise((resolve, reject) => { + const line = position.line + 1; + const column = position.character; + let child = completeCommand([ + '--completion-class-info', + '--dev', + '--fork', + '--line=' + line, + '--column=' + column + ]); + let outbuf = [], + errbuf = []; + child.stderr.on('data', (data) => errbuf.push(data)); + child.stdout.on('data', (data) => outbuf.push(data)); + child.stdout.on('end', () => { + if (errbuf.length > 0) return reject(Buffer.concat(errbuf).toString()); + let completionItems = []; + Buffer.concat(outbuf).toString().split('\n').forEach(function (elem) { + let items = elem.split('\t'); + if (/^[^\w]/.test(items[0])) return; + if (items[0].trim().length === 0) return; + let completionItem = new vscode.CompletionItem(items[0]); + completionItem.detail = items[1]; + completionItem.documentation = items[1]; + completionItem.filterText = items[0]; + completionItem.insertText = items[0]; + completionItem.label = items[0]; + completionItem.kind = vscode.CompletionItemKind.Method; + completionItems.push(completionItem); + }, this); + if (completionItems.length === 0) + return reject([]); + return resolve(completionItems); + }); + child.stdin.end(document.getText()); }); - child.stdin.end(document.getText()); - }); - } - }, - /** triggerCharacters */ ...['.'] + } + }, + /** triggerCharacters */ ...['.'] + ) ) - ) - }); - completeTest.on('error', () => 0); + }); + completeTest.on('error', () => 0); + } } function registerFormatter(ctx: ExtensionContext) { @@ -218,56 +216,68 @@ function registerFormatter(ctx: ExtensionContext) { function registerIntellisenseProvider(ctx: ExtensionContext) { // for locate: if it's a project, use the root, othewise, don't bother - 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)); + 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 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); - } + 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)); + } + } else { + var rubyLocateDisabled = () => { + vscode.window.showInformationMessage('The `ruby.intellisense` configuration is not set to use rubyLocate.') }; - ctx.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(workspaceSymbolProvider)); + ctx.subscriptions.push(vscode.commands.registerCommand('ruby.reloadProject', rubyLocateDisabled)); } } From 4f5dd88af9e354d5c3135566831af4a1d126c507 Mon Sep 17 00:00:00 2001 From: Fred Snyder Date: Wed, 28 Mar 2018 09:13:16 -0400 Subject: [PATCH 4/4] Updated readme --- readme.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/readme.md b/readme.md index 51dbe51b1..e1127cb48 100644 --- a/readme.md +++ b/readme.md @@ -152,33 +152,29 @@ Rufo is an alternative Ruby formatting tool. See the [VS Code Rufo Extension](ht ## Autocomplete -The `ruby.codeCompletion` setting lets you select a method for code completion and other intellisense features. Valid options are `solargraph`, `rcodetools`, and `none`. +The `ruby.codeCompletion` setting lets you select a method for code completion and other intellisense features. Valid options are `rcodetools` and `false`. -To enable method completion in Ruby, run `gem install solargraph` or `gem install rcodetools` based on the `ruby.codeCompletion` setting. You may need to restart Visual Studio Code the first time. +### rcodetools + +To enable method completion in Ruby, run `gem install rcodetools`. You may need to restart Visual Studio Code the first time. ```ruby [1, 2, 3].e #<= Press CTRL-Space here ``` -For more information about using Solargraph, refer to the [Solargraph extension](https://marketplace.visualstudio.com/items?itemName=castwide.solargraph). - -## Intellisense (Go to/Peek Definition) - -Use the `ruby.intellisense` setting to select a `go to/peek definition` method. Valid options are `solargraph`, `rubyLocate`, and `none`. +### Solargraph -### Solargraph Intellisense +Solargraph is an alternative Ruby code completion tool. See the [Solargraph extension](https://marketplace.visualstudio.com/items?itemName=castwide.solargraph) if you want to try it. -Make sure the solargraph gem installed: +For more information about using Solargraph, refer to the [Solargraph extension](https://marketplace.visualstudio.com/items?itemName=castwide.solargraph). -``` -gem install solargraph -``` +## Intellisense (Go to/Peek Definition) -Solargraph's features now extend to providing go to/peek definition. See the [Solargraph extension](https://marketplace.visualstudio.com/items?itemName=castwide.solargraph) for more information. +Use the `ruby.intellisense` setting to select a `go to/peek definition` method. Valid options are `rubyLocate`, and `false`. -### RubyLocate Intellisense +### rubyLocate -Now includes workspace parsing functionality. Allows VS Code to `go to definition` and `peak definition` for modules, classes, and methods defined within the same workspace. You can set glob patterns to match including and excluding particular files. The exclude match also runs against directories on initial load, to reduce latency. +The `rubyLocate` option includes workspace parsing functionality. It allows VS Code to `go to definition` and `peak definition` for modules, classes, and methods defined within the same workspace. You can set glob patterns to match including and excluding particular files. The exclude match also runs against directories on initial load, to reduce latency. The default settings are: @@ -195,6 +191,10 @@ If you change these settings, currently you will need to reload your workspace. We now provide go to definition within `erb` files, as well as syntax highlighting for `erb`. +### Solargraph + +Solargraph now includes go to/peek definition and other language features. See the [Solargraph extension](https://marketplace.visualstudio.com/items?itemName=castwide.solargraph) for more information. + ## TODO - Unit/Integration tests debugging