Skip to content

Commit

Permalink
go to defintion for self object
Browse files Browse the repository at this point in the history
  • Loading branch information
daimor committed Feb 8, 2019
1 parent 4216eb7 commit f07928c
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- some small fixes in the highlighting, and selecting words/variables
- Intellisense. Show list of methods for ##class(SomeClass)
- Go to macros definition
- Go to definition for methods and properties for self object like `..Name`, `..SomeMethod()`

## [0.7.7]

Expand Down
40 changes: 29 additions & 11 deletions providers/ObjectScriptCompletionItemProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import systemFunctions = require('./completion/systemFunctions.json');
import systemVariables = require('./completion/systemVariables.json');
import structuredSystemVariables = require('./completion/structuredSystemVariables.json');
import { ClassDefinition } from '../utils/classDefinition.js';
import { currentFile } from '../utils/index.js';

export class ObjectScriptCompletionItemProvider implements vscode.CompletionItemProvider {
provideCompletionItems(
Expand Down Expand Up @@ -193,23 +194,40 @@ export class ObjectScriptCompletionItemProvider implements vscode.CompletionItem
): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
let range = document.getWordRangeAtPosition(position, /%?\b\w+[\w\d]*\b/) || new vscode.Range(position, position);
let textBefore = document.getText(new vscode.Range(new vscode.Position(position.line, 0), range.start));
let curFile = currentFile();

const method = el => ({
label: el.name,
documentation: el.desc.length ? new vscode.MarkdownString(el.desc.join('')) : null,
kind: vscode.CompletionItemKind.Method,
insertText: new vscode.SnippetString(`${el.name}($0)`)
});

const property = el => ({
label: el.name,
documentation: el.desc.length ? new vscode.MarkdownString(el.desc.join('')) : null,
kind: vscode.CompletionItemKind.Property,
insertText: new vscode.SnippetString(`${el.name}`)
});

let classRef = textBefore.match(/##class\(([^)]+)\)\.$/i);
if (classRef) {
let [, className] = classRef;
let classDef = new ClassDefinition(className);
return classDef.methods('class').then(methods => {
let completion = [
...methods.map(el => ({
label: el.name,
documentation: el.desc.length ? new vscode.MarkdownString(el.desc.join('')) : null,
kind: vscode.CompletionItemKind.Method,
insertText: new vscode.SnippetString(`${el.name}($0)`)
}))
];
return completion;
});
return classDef.methods('class').then(data => data.map(method));
}

if (curFile.fileName.endsWith('cls')) {
let selfRef = textBefore.match(/(?<!\.)\.\.$/i);
if (selfRef) {
let classDef = new ClassDefinition(curFile.name);
return Promise.all([classDef.methods(), classDef.properties()]).then(data => {
let [methods, properties] = data;
return [...methods.map(method), ...properties.map(property)];
});
}
}

return null;
}
}
8 changes: 8 additions & 0 deletions providers/ObjectScriptDefinitionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ export class ObjectScriptDefinitionProvider implements vscode.DefinitionProvider
token: vscode.CancellationToken
): vscode.ProviderResult<vscode.Location | vscode.Location[] | vscode.DefinitionLink[]> {
let lineText = document.lineAt(position.line).text;
let file = currentFile();

let selfRef = document.getWordRangeAtPosition(position, /\.\.%?[a-zA-Z][a-zA-Z0-9]+(?:\.[a-zA-Z][a-zA-Z0-9]+)*/);
if (selfRef) {
let selfEntity = document.getText(selfRef).substr(2);
let classDefinition = new ClassDefinition(file.name);
return classDefinition.getPosition(selfEntity, document);
}

let macroRange = document.getWordRangeAtPosition(position);
let macroText = macroRange ? document.getText(macroRange) : '';
Expand Down
80 changes: 74 additions & 6 deletions utils/classDefinition.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import * as vscode from 'vscode';
import { AtelierAPI } from '../api';
import { onlyUnique } from '.';
import { DocumentContentProvider } from '../providers/DocumentContentProvider';

export class ClassDefinition {
private _className: string;
Expand All @@ -15,7 +18,7 @@ export class ClassDefinition {
this._classFileName = ClassDefinition.normalizeClassName(className, true);
}

async methods(scope: 'any' | 'class' | 'instance'): Promise<any[]> {
async methods(scope: 'any' | 'class' | 'instance' = 'any'): Promise<any[]> {
let methods = [];
let filterScope = method => scope === 'any' || method.scope === scope;
const api = new AtelierAPI();
Expand All @@ -28,23 +31,43 @@ export class ClassDefinition {
if (extend.length) {
return api.actionIndex(extend).then(data => getMethods(data.result.content));
}
return methods.filter(filterScope);
return methods
.filter(filterScope)
.filter(onlyUnique)
.sort();
};
return api.actionIndex([this._classFileName]).then(data => getMethods(data.result.content));
}

async properties(): Promise<any[]> {
let properties = [];
const api = new AtelierAPI();
const getProperties = content => {
let extend = [];
content.forEach(el => {
properties.push(...el.content.properties);
extend.push(...el.content.super.map(extendName => ClassDefinition.normalizeClassName(extendName, true)));
});
if (extend.length) {
return api.actionIndex(extend).then(data => getProperties(data.result.content));
}
return properties.filter(onlyUnique).sort();
};
return api.actionIndex([this._classFileName]).then(data => getProperties(data.result.content));
}

async super(): Promise<string[]> {
const api = new AtelierAPI();
let sql = `SELECT PrimarySuper FROM %Dictionary.CompiledClass WHERE Name = ?`;
return api
.actionQuery(sql, [this._className])
.then(data =>
return api.actionQuery(sql, [this._className]).then(
data =>
data.result.content.reduce(
(list: string[], el: { PrimarySuper: string }) =>
list.concat(el.PrimarySuper.split('~').filter(el => el.length)),
[]
)
);
// .filter(name => !['%Library.Base', '%Library.SystemBase'].includes(name))
);
}

async includeCode(): Promise<string[]> {
Expand All @@ -61,4 +84,49 @@ export class ClassDefinition {
)
);
}

async getPosition(name: string, document: vscode.TextDocument): Promise<vscode.Location[]> {
let pattern = `((Class)?Method|Property|RelationShip) ${name}(?!\w)`;
let foundLine;
if (document) {
for (let i = 0; i < document.lineCount; i++) {
let line = document.lineAt(i);
if (line.text.match(pattern)) {
foundLine = i;
break;
}
}
}
let result: vscode.Location[] = [];
if (foundLine) {
result.push({
uri: DocumentContentProvider.getUri(this._classFileName),
range: new vscode.Range(foundLine, 0, foundLine, 0)
});
}
let extendList = await this.super();
let api = new AtelierAPI();
let docs = [];
extendList.forEach(async docName => {
docName = ClassDefinition.normalizeClassName(docName, true);
docs.push(api.getDoc(docName));
});
return Promise.all(docs).then((docs: any[]) => {
for (let doc of docs) {
if (doc && doc.result.content) {
let docName = doc.result.name;
let content = doc.result.content;
for (let line of content.keys()) {
if (content[line].match(pattern)) {
result.push({
uri: DocumentContentProvider.getUri(docName),
range: new vscode.Range(line, 0, line, 0)
});
}
}
}
}
return result;
});
}
}
7 changes: 7 additions & 0 deletions utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,10 @@ export function currentWorkspaceFolder(): string {
export function workspaceFolderUri(workspaceFolder: string): vscode.Uri {
return vscode.workspace.workspaceFolders.find(el => el.name.toLowerCase() === workspaceFolder.toLowerCase()).uri;
}

export function onlyUnique(value: any, index: number, self: any) {
if (value && value.name) {
return self.findIndex(el => el.name === value.name) === index;
}
return self.indexOf(value) === index;
}

0 comments on commit f07928c

Please sign in to comment.