Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit 0918490

Browse files
authored
Merge pull request #311 from rubyide/code_cleanup
Code Cleanup - first pass
2 parents 0df353f + 448da69 commit 0918490

File tree

8 files changed

+285
-266
lines changed

8 files changed

+285
-266
lines changed

.vscode/settings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
"eslint.enable": false,
66
"editor.insertSpaces": false,
77
"[javascript]": {
8-
"editor.formatOnSave": true
8+
"editor.formatOnSave": false
99
},
1010
"[typescript]": {
11-
"editor.formatOnSave": true
11+
"editor.formatOnSave": false
1212
},
1313
"typescript.tsdk": "node_modules/typescript/lib"
1414
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@
8080
"test-debugger": "node ./node_modules/mocha/bin/mocha --timeout 15000 -u tdd ./out/debugger/tests/*.js",
8181
"postinstall": "node ./node_modules/vscode/bin/install",
8282
"update-all-grammars": "node scripts/update-all-grammars",
83-
"update-grammar": "node scripts/update-grammar atom/language-ruby"
83+
"update-grammar": "node scripts/update-grammar atom/language-ruby",
84+
"lint": "tslint -c tslint.json 'src/**/*.ts'"
8485
},
8586
"activationEvents": [
8687
"onLanguage:ruby",

src/providers/completion.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import * as vscode from 'vscode';
2+
import { ExtensionContext } from 'vscode';
3+
import * as cp from 'child_process';
4+
5+
export function registerCompletionProvider(ctx: ExtensionContext) {
6+
if (vscode.workspace.getConfiguration('ruby').codeCompletion == 'rcodetools') {
7+
const completeCommand = function (args) {
8+
let rctCompletePath = vscode.workspace.getConfiguration('ruby.rctComplete').get('commandPath', 'rct-complete');
9+
args.push('--interpreter');
10+
args.push(vscode.workspace.getConfiguration('ruby.interpreter').get('commandPath', 'ruby'));
11+
if (process.platform === 'win32')
12+
return cp.spawn('cmd', ['/c', rctCompletePath].concat(args));
13+
return cp.spawn(rctCompletePath, args);
14+
}
15+
16+
const completeTest = completeCommand(['--help']);
17+
completeTest.on('exit', () => {
18+
ctx.subscriptions.push(
19+
vscode.languages.registerCompletionItemProvider(
20+
/** selector */'ruby',
21+
/** provider */{
22+
provideCompletionItems: function completionProvider(document, position, token) {
23+
return new Promise((resolve, reject) => {
24+
const line = position.line + 1;
25+
const column = position.character;
26+
let child = completeCommand([
27+
'--completion-class-info',
28+
'--dev',
29+
'--fork',
30+
'--line=' + line,
31+
'--column=' + column
32+
]);
33+
let outbuf = [],
34+
errbuf = [];
35+
child.stderr.on('data', (data) => errbuf.push(data));
36+
child.stdout.on('data', (data) => outbuf.push(data));
37+
child.stdout.on('end', () => {
38+
if (errbuf.length > 0) return reject(Buffer.concat(errbuf).toString());
39+
let completionItems = [];
40+
Buffer.concat(outbuf).toString().split('\n').forEach(function (elem) {
41+
let items = elem.split('\t');
42+
if (/^[^\w]/.test(items[0])) return;
43+
if (items[0].trim().length === 0) return;
44+
let completionItem = new vscode.CompletionItem(items[0]);
45+
completionItem.detail = items[1];
46+
completionItem.documentation = items[1];
47+
completionItem.filterText = items[0];
48+
completionItem.insertText = items[0];
49+
completionItem.label = items[0];
50+
completionItem.kind = vscode.CompletionItemKind.Method;
51+
completionItems.push(completionItem);
52+
}, this);
53+
if (completionItems.length === 0)
54+
return reject([]);
55+
return resolve(completionItems);
56+
});
57+
child.stdin.end(document.getText());
58+
});
59+
}
60+
},
61+
/** triggerCharacters */ ...['.']
62+
)
63+
)
64+
});
65+
completeTest.on('error', () => 0);
66+
}
67+
}

src/providers/formatter.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { ExtensionContext } from 'vscode';
2+
import { RubyDocumentFormattingEditProvider } from '../format/rubyFormat';
3+
4+
export function registerFormatter(ctx: ExtensionContext) {
5+
new RubyDocumentFormattingEditProvider().register(ctx);
6+
}

src/providers/highlight.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import * as vscode from 'vscode';
2+
import { ExtensionContext } from 'vscode';
3+
4+
export function registerHighlightProvider(ctx: ExtensionContext) {
5+
// highlight provider
6+
let pairedEnds = [];
7+
8+
const getEnd = function (line) {
9+
//end must be on a line by itself, or followed directly by a dot
10+
let match = line.text.match(/^(\s*)end\b[\.\s#]?\s*$/);
11+
if (match) {
12+
return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + 3);
13+
}
14+
}
15+
16+
const getEntry = function(line) {
17+
let match = line.text.match(/^(.*\b)(begin|class|def|for|if|module|unless|until|case|while)\b[^;]*$/);
18+
if (match) {
19+
return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + match[2].length);
20+
} else {
21+
//check for do
22+
match = line.text.match(/\b(do)\b\s*(\|.*\|[^;]*)?$/);
23+
if (match) {
24+
return new vscode.Range(line.lineNumber, match.index, line.lineNumber, match.index + 2);
25+
}
26+
}
27+
}
28+
29+
const balancePairs = function (doc) {
30+
pairedEnds = [];
31+
if (doc.languageId !== 'ruby') return;
32+
33+
let waitingEntries = [];
34+
let entry, end;
35+
for (let i = 0; i < doc.lineCount; i++) {
36+
if ((entry = getEntry(doc.lineAt(i)))) {
37+
waitingEntries.push(entry);
38+
} else if (waitingEntries.length && (end = getEnd(doc.lineAt(i)))) {
39+
pairedEnds.push({
40+
entry: waitingEntries.pop(),
41+
end: end
42+
});
43+
}
44+
}
45+
}
46+
47+
const balanceEvent = function (event) {
48+
if (event && event.document) balancePairs(event.document);
49+
}
50+
51+
ctx.subscriptions.push(vscode.languages.registerDocumentHighlightProvider('ruby', {
52+
provideDocumentHighlights: (doc, pos) => {
53+
let result = pairedEnds.find(pair => (
54+
pair.entry.start.line === pos.line ||
55+
pair.end.start.line === pos.line));
56+
if (result) {
57+
return [new vscode.DocumentHighlight(result.entry, 2), new vscode.DocumentHighlight(result.end, 2)];
58+
}
59+
}
60+
}));
61+
62+
ctx.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(balanceEvent));
63+
ctx.subscriptions.push(vscode.workspace.onDidChangeTextDocument(balanceEvent));
64+
ctx.subscriptions.push(vscode.workspace.onDidOpenTextDocument(balancePairs));
65+
if (vscode.window && vscode.window.activeTextEditor) {
66+
balancePairs(vscode.window.activeTextEditor.document);
67+
}
68+
}

src/providers/intellisense.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import * as vscode from 'vscode';
2+
import { ExtensionContext, SymbolKind, SymbolInformation } from 'vscode';
3+
import * as Locate from '../locate/locate';
4+
5+
export function registerIntellisenseProvider(ctx: ExtensionContext) {
6+
// for locate: if it's a project, use the root, othewise, don't bother
7+
if (vscode.workspace.getConfiguration('ruby').intellisense == 'rubyLocate') {
8+
if (vscode.workspace.rootPath) {
9+
const refreshLocate = () => {
10+
let progressOptions = { location: vscode.ProgressLocation.Window, title: 'Indexing Ruby source files' };
11+
vscode.window.withProgress(progressOptions, () => locate.walk());
12+
};
13+
const settings: any = vscode.workspace.getConfiguration("ruby.locate") || {};
14+
let locate = new Locate(vscode.workspace.rootPath, settings);
15+
refreshLocate();
16+
ctx.subscriptions.push(vscode.commands.registerCommand('ruby.reloadProject', refreshLocate));
17+
18+
const watch = vscode.workspace.createFileSystemWatcher(settings.include);
19+
watch.onDidChange(uri => locate.parse(uri.fsPath));
20+
watch.onDidCreate(uri => locate.parse(uri.fsPath));
21+
watch.onDidDelete(uri => locate.rm(uri.fsPath));
22+
const locationConverter = match => new vscode.Location(vscode.Uri.file(match.file), new vscode.Position(match.line, match.char));
23+
const defProvider = {
24+
provideDefinition: (doc, pos) => {
25+
const txt = doc.getText(doc.getWordRangeAtPosition(pos));
26+
return locate.find(txt).then(matches => matches.map(locationConverter));
27+
}
28+
};
29+
ctx.subscriptions.push(vscode.languages.registerDefinitionProvider(['ruby', 'erb'], defProvider));
30+
const symbolKindTable = {
31+
class: () => SymbolKind.Class,
32+
module: () => SymbolKind.Module,
33+
method: symbolInfo => symbolInfo.name === 'initialize' ? SymbolKind.Constructor : SymbolKind.Method,
34+
classMethod: () => SymbolKind.Method,
35+
};
36+
const defaultSymbolKind = symbolInfo => {
37+
console.warn(`Unknown symbol type: ${symbolInfo.type}`);
38+
return SymbolKind.Variable;
39+
};
40+
// NOTE: Workaround for high CPU usage on IPC (channel.onread) when too many symbols returned.
41+
// For channel.onread see issue like this: https://github.com/Microsoft/vscode/issues/6026
42+
const numOfSymbolLimit = 3000;
43+
const symbolsConverter = matches => matches.slice(0, numOfSymbolLimit).map(match => {
44+
const symbolKind = (symbolKindTable[match.type] || defaultSymbolKind)(match);
45+
return new SymbolInformation(match.name, symbolKind, match.containerName, locationConverter(match));
46+
});
47+
const docSymbolProvider = {
48+
provideDocumentSymbols: (document, token) => {
49+
return locate.listInFile(document.fileName).then(symbolsConverter);
50+
}
51+
};
52+
ctx.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(['ruby', 'erb'], docSymbolProvider));
53+
const workspaceSymbolProvider = {
54+
provideWorkspaceSymbols: (query, token) => {
55+
return locate.query(query).then(symbolsConverter);
56+
}
57+
};
58+
ctx.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(workspaceSymbolProvider));
59+
} else {
60+
var rubyLocateUnavailable = () => {
61+
vscode.window.showInformationMessage('There is not an open workspace for rubyLocate to reload.');
62+
};
63+
ctx.subscriptions.push(vscode.commands.registerCommand('ruby.reloadProject', rubyLocateUnavailable));
64+
}
65+
} else {
66+
var rubyLocateDisabled = () => {
67+
vscode.window.showInformationMessage('The `ruby.intellisense` configuration is not set to use rubyLocate.')
68+
};
69+
ctx.subscriptions.push(vscode.commands.registerCommand('ruby.reloadProject', rubyLocateDisabled));
70+
}
71+
}

src/providers/linters.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import * as vscode from 'vscode';
2+
import { ExtensionContext } from 'vscode';
3+
import * as debounce from 'lodash/debounce';
4+
5+
import { LintCollection } from '../lint/lintCollection';
6+
import { Config as LintConfig } from '../lint/lintConfig';
7+
8+
function getGlobalLintConfig() : LintConfig {
9+
let globalConfig = new LintConfig();
10+
11+
let pathToRuby = vscode.workspace.getConfiguration("ruby.interpreter").commandPath;
12+
if (pathToRuby) {
13+
globalConfig.pathToRuby = pathToRuby;
14+
}
15+
16+
let useBundler = vscode.workspace.getConfiguration("ruby").get<boolean | null>("useBundler");
17+
if (useBundler !== null) {
18+
globalConfig.useBundler = useBundler;
19+
}
20+
21+
let pathToBundler = vscode.workspace.getConfiguration("ruby").pathToBundler;
22+
if (pathToBundler) {
23+
globalConfig.pathToBundler = pathToBundler;
24+
}
25+
return globalConfig;
26+
}
27+
28+
export function registerLinters(ctx: ExtensionContext) {
29+
const globalConfig = getGlobalLintConfig();
30+
const linters = new LintCollection(globalConfig, vscode.workspace.getConfiguration("ruby").lint, vscode.workspace.rootPath);
31+
ctx.subscriptions.push(linters);
32+
33+
function executeLinting(e: vscode.TextEditor | vscode.TextDocumentChangeEvent) {
34+
if (!e) return;
35+
linters.run(e.document);
36+
}
37+
38+
// Debounce linting to prevent running on every keypress, only run when typing has stopped
39+
const lintDebounceTime = vscode.workspace.getConfiguration('ruby').lintDebounceTime;
40+
const executeDebouncedLinting = debounce(executeLinting, lintDebounceTime);
41+
42+
ctx.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(executeLinting));
43+
ctx.subscriptions.push(vscode.workspace.onDidChangeTextDocument(executeDebouncedLinting));
44+
ctx.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => {
45+
const docs = vscode.window.visibleTextEditors.map(editor => editor.document);
46+
console.log("Config changed. Should lint:", docs.length);
47+
const globalConfig = getGlobalLintConfig();
48+
linters.cfg(vscode.workspace.getConfiguration("ruby").lint, globalConfig);
49+
docs.forEach(doc => linters.run(doc));
50+
}));
51+
52+
// run against all of the current open files
53+
vscode.window.visibleTextEditors.forEach(executeLinting);
54+
}

0 commit comments

Comments
 (0)