From ee3570d8c6385c138a2610dd6adfd54f6f936ff7 Mon Sep 17 00:00:00 2001 From: Talv Date: Mon, 17 Sep 2018 10:36:56 +0200 Subject: [PATCH] completions: suggest files for include statement --- src/compiler/parser.ts | 12 +++++----- src/compiler/scanner.ts | 4 ++++ src/service/completions.ts | 46 ++++++++++++++++++++++++++++++++++---- src/service/store.ts | 39 ++++++++++++++++++++++++++------ 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 3efe244..71b2436 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -464,12 +464,12 @@ export class Parser { if (!kind) { kind = this.token(); } - const node = this.createNode(kind); - this.parseExpected(kind, undefined, false); - node.value = this.scanner.getTokenValue(); - node.text = this.scanner.getTokenText(); - this.nextToken(); - return this.finishNode(node); + const node = this.createNode(kind, undefined, false); + node.end = this.scanner.getCurrentPos(); + node.value = this.scanner.getTokenValue() || ''; + node.text = this.scanner.getTokenText() || ''; + this.parseExpected(kind); + return node; } private parseInclude(): Types.IncludeStatement { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index b798d20..aa38015 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -721,6 +721,10 @@ export class Scanner { return this.pos - this.char; } + public getCurrentPos(): number { + return this.pos; + } + public getStartPos(): number { return this.startPos; } diff --git a/src/service/completions.ts b/src/service/completions.ts index fdc21c3..9d27a2f 100644 --- a/src/service/completions.ts +++ b/src/service/completions.ts @@ -12,7 +12,7 @@ import * as trig from '../sc2mod/trigger'; function isInComment(sourceFile: gt.SourceFile, pos: number) { const comment = sourceFile.commentsLineMap.get(getLineAndCharacterOfPosition(sourceFile, pos).line); - return comment && pos > comment.pos; + return comment && pos >= comment.pos; } export const enum CompletionFunctionExpand { @@ -230,11 +230,9 @@ export class CompletionsProvider extends AbstractProvider { } // trigger handlers - if (currentToken && currentToken.kind === gt.SyntaxKind.StringLiteral) { + if (currentToken && currentToken.kind === gt.SyntaxKind.StringLiteral && currentToken.parent.kind === gt.SyntaxKind.CallExpression) { const callExpr = currentToken.parent; - // trigger handlers if ( - callExpr.kind === gt.SyntaxKind.CallExpression && callExpr.expression.kind === gt.SyntaxKind.Identifier && ((callExpr.expression)).name === "TriggerCreate" ) { @@ -245,6 +243,46 @@ export class CompletionsProvider extends AbstractProvider { } } + // include + if (currentToken && currentToken.kind === gt.SyntaxKind.StringLiteral && currentToken.pos <= position && currentToken.end >= position && currentToken.parent.kind === gt.SyntaxKind.IncludeStatement) { + const inclStmt = currentToken.parent; + const offset = position - currentToken.pos; + query = (currentToken).text.substr(1, offset - 1).replace(/(\/*)[^\/]+$/, '$1'); + const imap = new Map(); + + if ((currentToken).text.match(/[^"]$/) || currentToken.end != position) { + for (const uri of this.store.documents.keys()) { + const meta = this.store.getDocumentMeta(uri); + if (!meta.relativeName) continue; + if (query && !meta.relativeName.toLowerCase().startsWith(query.toLowerCase())) continue; + const itemPart = meta.relativeName.substr(query.length).split('/'); + if (itemPart.length > 1) { + imap.set(itemPart[0], { + kind: lsp.CompletionItemKind.Folder, + label: itemPart[0], + insertText: itemPart[0] + '/', + detail: meta.archive ? meta.archive.name : null, + data: {}, + }); + } + else { + imap.set(itemPart[0], { + kind: lsp.CompletionItemKind.File, + label: itemPart[0] + '.galaxy', + insertText: itemPart[0], + detail: meta.relativeName + '.galaxy', + documentation: meta.archive ? meta.archive.name : null, + data: {}, + }); + } + } + return { + items: Array.from(imap.values()), + isIncomplete: false, + }; + } + } + // presets if (currentToken && this.store.s2metadata) { const elementType = this.store.s2metadata.getElementTypeOfNode(currentToken); diff --git a/src/service/store.ts b/src/service/store.ts index 033ab7b..70ec8c3 100644 --- a/src/service/store.ts +++ b/src/service/store.ts @@ -139,6 +139,12 @@ export async function findWorkspaceArchive(rootPath: string) { return null; } +export interface SourceFileMeta { + absoluteName: string; + relativeName?: string; + archive?: SC2Archive; +} + export class Store { private parser = new Parser(); public rootPath?: string; @@ -190,24 +196,43 @@ export class Store { await this.s2metadata.build(lang); } - public isUriInWorkspace(documentUri: string) { + public getDocumentMeta(documentUri: string) { let documentPath = URI.parse(documentUri).fsPath; + let meta: SourceFileMeta = { + absoluteName: documentPath, + }; + const isWin = process.platform === 'win32'; if (isWin) { documentPath = documentPath.toLowerCase(); } - if (this.rootPath && !this.s2workspace.rootArchive && documentPath.startsWith((isWin ? this.rootPath.toLowerCase() : this.rootPath) + path.sep)) { - return true; + if (this.rootPath && (!this.s2workspace || !this.s2workspace.rootArchive) && documentPath.startsWith((isWin ? this.rootPath.toLowerCase() : this.rootPath) + path.sep)) { + meta.relativeName = documentPath.substr(this.rootPath.length + 1); } - - if (this.s2workspace) { + else if (this.s2workspace) { for (const archive of this.s2workspace.allArchives) { - if (documentPath.startsWith((isWin ? archive.directory.toLowerCase() : archive.directory) + path.sep)) return true; + if (documentPath.startsWith((isWin ? archive.directory.toLowerCase() : archive.directory) + path.sep)) { + meta.relativeName = documentPath.substr(archive.directory.length + 1); + meta.relativeName = meta.relativeName.replace(/^base\.sc2data[\/\\]/i, ''); + meta.archive = archive; + break; + } } } - return false; + if (meta.relativeName) { + meta.relativeName = meta.relativeName.replace(/\.galaxy$/i, ''); + if (isWin) { + meta.relativeName = meta.relativeName.replace(/\\/g, '/'); + } + } + + return meta; + } + + public isUriInWorkspace(documentUri: string) { + return typeof this.getDocumentMeta(documentUri).relativeName !== 'undefined'; } public resolveGlobalSymbol(name: string): gt.Symbol | undefined {