Skip to content
This repository has been archived by the owner on Jun 15, 2021. It is now read-only.

Commit

Permalink
feat: add completion service (#74)
Browse files Browse the repository at this point in the history
* feat: add completion service

* fix: simplify snippets
  • Loading branch information
OmarTawfik authored Mar 14, 2019
1 parent f646a36 commit f63976c
Show file tree
Hide file tree
Showing 8 changed files with 387 additions and 79 deletions.
5 changes: 5 additions & 0 deletions scripts/package-vscode.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
"icon": "resources/logo.png",
"activationEvents": ["onLanguage:github-actions"],
"contributes": {
"configurationDefaults": {
"[github-actions]": {
"editor.wordBasedSuggestions": false
}
},
"languages": [
{
"id": "github-actions",
Expand Down
70 changes: 0 additions & 70 deletions src/binding/bound-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,6 @@ import {
} from "../parsing/syntax-nodes";
import { Token } from "../scanning/tokens";

function filterUndefined<T>(...items: (T | undefined)[]): T[] {
const result = Array<T>();

items.forEach(item => {
if (item) {
result.push(item);
}
});

return result;
}

export enum BoundKind {
// Top level
Document,
Expand All @@ -47,8 +35,6 @@ export enum BoundKind {

export abstract class BaseBoundNode {
protected constructor(public readonly kind: BoundKind) {}

public abstract get children(): ReadonlyArray<BaseBoundNode>;
}

export class BoundDocument extends BaseBoundNode {
Expand All @@ -60,20 +46,12 @@ export class BoundDocument extends BaseBoundNode {
) {
super(BoundKind.Document);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return filterUndefined<BaseBoundNode>(this.version, ...this.workflows, ...this.actions);
}
}

export class BoundVersion extends BaseBoundNode {
public constructor(public readonly version: number, public readonly syntax: VersionSyntax) {
super(BoundKind.Version);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return [];
}
}

export class BoundWorkflow extends BaseBoundNode {
Expand All @@ -85,10 +63,6 @@ export class BoundWorkflow extends BaseBoundNode {
) {
super(BoundKind.Workflow);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return filterUndefined<BaseBoundNode>(this.on, this.resolves);
}
}

export class BoundAction extends BaseBoundNode {
Expand All @@ -104,20 +78,12 @@ export class BoundAction extends BaseBoundNode {
) {
super(BoundKind.Action);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return filterUndefined<BaseBoundNode>(this.uses, this.needs, this.runs, this.args, this.env, this.secrets);
}
}

export class BoundOn extends BaseBoundNode {
public constructor(public readonly event: BoundStringValue | undefined, public readonly syntax: BasePropertySyntax) {
super(BoundKind.On);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return filterUndefined(this.event);
}
}

export class BoundResolves extends BaseBoundNode {
Expand All @@ -127,20 +93,12 @@ export class BoundResolves extends BaseBoundNode {
) {
super(BoundKind.Resolves);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return this.actions;
}
}

export class BoundUses extends BaseBoundNode {
public constructor(public readonly value: BoundStringValue | undefined, public readonly syntax: BasePropertySyntax) {
super(BoundKind.Uses);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return filterUndefined(this.value);
}
}

export class BoundNeeds extends BaseBoundNode {
Expand All @@ -150,10 +108,6 @@ export class BoundNeeds extends BaseBoundNode {
) {
super(BoundKind.Needs);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return this.actions;
}
}

export class BoundRuns extends BaseBoundNode {
Expand All @@ -163,10 +117,6 @@ export class BoundRuns extends BaseBoundNode {
) {
super(BoundKind.Runs);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return this.commands;
}
}

export class BoundArgs extends BaseBoundNode {
Expand All @@ -176,10 +126,6 @@ export class BoundArgs extends BaseBoundNode {
) {
super(BoundKind.Args);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return this.args;
}
}

export class BoundEnv extends BaseBoundNode {
Expand All @@ -189,10 +135,6 @@ export class BoundEnv extends BaseBoundNode {
) {
super(BoundKind.Env);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return this.variables;
}
}

export class BoundSecrets extends BaseBoundNode {
Expand All @@ -202,20 +144,12 @@ export class BoundSecrets extends BaseBoundNode {
) {
super(BoundKind.Secrets);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return this.secrets;
}
}

export class BoundStringValue extends BaseBoundNode {
public constructor(public readonly value: string, public readonly syntax: Token) {
super(BoundKind.StringValue);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return [];
}
}

export class BoundObjectMember extends BaseBoundNode {
Expand All @@ -226,8 +160,4 @@ export class BoundObjectMember extends BaseBoundNode {
) {
super(BoundKind.ObjectMember);
}

public get children(): ReadonlyArray<BaseBoundNode> {
return [];
}
}
55 changes: 55 additions & 0 deletions src/parsing/syntax-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/

import { Token, TokenKind, getTokenDescription } from "../scanning/tokens";
import { Range } from "vscode-languageserver-types";
import { comparePositions } from "../util/ranges";

export enum SyntaxKind {
// Top level
Expand All @@ -28,8 +30,29 @@ function assertTokenKind(token: Token | undefined, ...acceptedKinds: TokenKind[]
}
}

function combineRange(...items: (Token | BaseSyntaxNode | undefined)[]): Range {
const validRanges = items.filter(item => !!item).map(item => item!.range);
if (!validRanges.length) {
return Range.create(0, 0, 0, 0);
}

validRanges.sort((a, b) => comparePositions(a.start, b.start));
return Range.create(validRanges[0].start, validRanges[validRanges.length - 1].end);
}

export abstract class BaseSyntaxNode {
private lazyRange: Range | undefined;

protected constructor(public readonly kind: SyntaxKind) {}

public get range(): Range {
if (!this.lazyRange) {
this.lazyRange = this.calculateRange();
}
return this.lazyRange;
}

protected abstract calculateRange(): Range;
}

export class DocumentSyntax extends BaseSyntaxNode {
Expand All @@ -39,6 +62,10 @@ export class DocumentSyntax extends BaseSyntaxNode {
) {
super(SyntaxKind.Document);
}

public calculateRange(): Range {
return combineRange(...this.versions, ...this.blocks);
}
}

export class VersionSyntax extends BaseSyntaxNode {
Expand All @@ -48,6 +75,10 @@ export class VersionSyntax extends BaseSyntaxNode {
assertTokenKind(equal, TokenKind.Equal);
assertTokenKind(integer, TokenKind.IntegerLiteral);
}

public calculateRange(): Range {
return combineRange(this.version, this.equal, this.integer);
}
}

export class BlockSyntax extends BaseSyntaxNode {
Expand All @@ -64,6 +95,10 @@ export class BlockSyntax extends BaseSyntaxNode {
assertTokenKind(openBracket, TokenKind.LeftCurlyBracket);
assertTokenKind(closeBracket, TokenKind.RightCurlyBracket);
}

public calculateRange(): Range {
return combineRange(this.type, this.name, this.openBracket, ...this.properties, this.closeBracket);
}
}

export abstract class BasePropertySyntax extends BaseSyntaxNode {
Expand All @@ -89,6 +124,10 @@ export class StringPropertySyntax extends BasePropertySyntax {
super(SyntaxKind.StringProperty, key, equal);
assertTokenKind(value, TokenKind.StringLiteral);
}

public calculateRange(): Range {
return combineRange(this.key, this.equal, this.value);
}
}

export class ArrayPropertySyntax extends BasePropertySyntax {
Expand All @@ -103,6 +142,10 @@ export class ArrayPropertySyntax extends BasePropertySyntax {
assertTokenKind(openBracket, TokenKind.LeftSquareBracket);
assertTokenKind(closeBracket, TokenKind.RightSquareBracket);
}

public calculateRange(): Range {
return combineRange(this.openBracket, ...this.items, this.closeBracket);
}
}

export class ArrayItemSyntax extends BaseSyntaxNode {
Expand All @@ -111,6 +154,10 @@ export class ArrayItemSyntax extends BaseSyntaxNode {
assertTokenKind(value, TokenKind.StringLiteral);
assertTokenKind(comma, TokenKind.Comma);
}

public calculateRange(): Range {
return combineRange(this.value, this.comma);
}
}

export class ObjectPropertySyntax extends BasePropertySyntax {
Expand All @@ -125,6 +172,10 @@ export class ObjectPropertySyntax extends BasePropertySyntax {
assertTokenKind(openBracket, TokenKind.LeftCurlyBracket);
assertTokenKind(closeBracket, TokenKind.RightCurlyBracket);
}

public calculateRange(): Range {
return combineRange(this.openBracket, ...this.members, this.closeBracket);
}
}

export class ObjectMemberSyntax extends BaseSyntaxNode {
Expand All @@ -134,4 +185,8 @@ export class ObjectMemberSyntax extends BaseSyntaxNode {
assertTokenKind(equal, TokenKind.Equal);
assertTokenKind(value, TokenKind.StringLiteral);
}

public calculateRange(): Range {
return combineRange(this.name, this.equal, this.value);
}
}
12 changes: 6 additions & 6 deletions src/resources/snippets.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
"workflow": {
"prefix": "workflow",
"description": "Insert workflow block",
"body": ["workflow \"${1:NAME}\" {", " on = \"${2:ON}\"", " resolves = [\"${3:RESOLVES}\"]", "}"]
"body": ["workflow \"${1:NAME}\" {", " on = \"${2:ON}\"", " resolves = [ \"${3:RESOLVES}\" ]", "}"]
},
"action": {
"prefix": "action",
"description": "Insert action block",
"body": [
"action \"${1:NAME}\" {",
" uses = \"${2:USES}\"",
" needs = \"${3:NEEDS}\"",
" runs = \"${4:RUNS}\"",
" args = [\"${5:ARGS}\"]",
" env = {\"${6:ENV_KEY}\" = \"${7:ENV_VALUE}\"}",
" secrets = [\"${8:SECRETS}\"]",
" needs = [ ]",
" runs = \"\"",
" args = [ ]",
" env = { }",
" secrets = [ ]",
"}"
]
}
Expand Down
2 changes: 2 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { RenamingService } from "./services/renaming";
import { FindReferencesService } from "./services/find-references";
import { GoToDefinitionService } from "./services/go-to-definition";
import { FormattingService } from "./services/formatting";
import { CompletionService } from "./services/completion";

export interface LanguageService {
activate(connection: IConnection, documents: TextDocuments): void;
Expand All @@ -27,6 +28,7 @@ const connection = createConnection(new IPCMessageReader(process), new IPCMessag
const documents: TextDocuments = new TextDocuments();

const services: ReadonlyArray<LanguageService> = [
new CompletionService(),
new DiagnosticsService(),
new FindReferencesService(),
new FoldingService(),
Expand Down
Loading

0 comments on commit f63976c

Please sign in to comment.