Skip to content

Commit

Permalink
Merge branch 'release-1.0.0' into alias-semantic-tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
TwitchBronBron committed May 15, 2024
2 parents f9a06d7 + 8a2e54e commit 8c4de7d
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 28 deletions.
3 changes: 3 additions & 0 deletions src/LanguageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ export class LanguageServer {
void this.sendBusyStatus(status);
});

//disable logger colors when running in LSP mode
logger.enableColor = false;

//listen to all of the output log events and pipe them into the debug channel in the extension
this.loggerSubscription = logger.subscribe((message) => {
this.connection.tracer.log(message.argsText);
Expand Down
3 changes: 3 additions & 0 deletions src/PluginInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export default class PluginInterface<T extends CompilerPlugin = CompilerPlugin>
if (!this.logger) {
this.logger = createLogger();
}
if (!this.logger) {
this.logger = createLogger();
}
}

private plugins: CompilerPlugin[] = [];
Expand Down
71 changes: 71 additions & 0 deletions src/bscPlugin/completions/CompletionsProcessor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2259,4 +2259,75 @@ describe('CompletionsProcessor', () => {
}]);
});
});

describe('alias', () => {
it('includes aliases', () => {
program.setFile('source/main.bs', `
alias APerson = Person
alias APi = Pi
namespace alpha
sub test()
print
end sub
sub pi()
print "Magnum"
end sub
enum Person
tall
short
end enum
end namespace
function Person()
return "John Doe"
end function
const PI = 3.14
`);
program.validate();
// print |
let completions = program.getCompletions('source/main.bs', util.createPosition(6, 31));
expectCompletionsIncludes(completions, [{
label: 'APi',
kind: CompletionItemKind.Constant
}, {
label: 'APerson',
kind: CompletionItemKind.Function
}]);
});


it('includes runtime and typetime symbols on RHS', () => {
program.setFile('source/main.bs', `
alias myAlias = a
function getPersonName()
return "John Doe"
end function
const PI = 3.14
interface SomeInterface
name as string
end interface
`);
program.validate();
// alias myAlias = a|
let completions = program.getCompletions('source/main.bs', util.createPosition(1, 33));
expectCompletionsIncludes(completions, [{
label: 'getPersonName',
kind: CompletionItemKind.Function
}, {
label: 'PI',
kind: CompletionItemKind.Constant
}, {
label: 'SomeInterface',
kind: CompletionItemKind.Interface
}]);
});

});
});
55 changes: 40 additions & 15 deletions src/bscPlugin/completions/CompletionsProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isBrsFile, isCallableType, isClassStatement, isClassType, isComponentType, isConstStatement, isEnumMemberType, isEnumType, isFunctionExpression, isInterfaceType, isMethodStatement, isNamespaceStatement, isNamespaceType, isNativeType, isTypedFunctionType, isXmlFile, isXmlScope } from '../../astUtils/reflection';
import type { FileReference, ProvideCompletionsEvent } from '../../interfaces';
import { isAliasStatement, isBrsFile, isCallableType, isClassStatement, isClassType, isComponentType, isConstStatement, isEnumMemberType, isEnumType, isFunctionExpression, isInterfaceType, isMethodStatement, isNamespaceStatement, isNamespaceType, isNativeType, isTypedFunctionType, isXmlFile, isXmlScope } from '../../astUtils/reflection';
import type { ExtraSymbolData, FileReference, ProvideCompletionsEvent } from '../../interfaces';
import type { BscFile } from '../../files/BscFile';
import { AllowedTriviaTokens, DeclarableTypes, Keywords, TokenKind } from '../../lexer/TokenKind';
import type { XmlScope } from '../../XmlScope';
Expand All @@ -18,7 +18,7 @@ import { BooleanType } from '../../types/BooleanType';
import { InvalidType } from '../../types/InvalidType';
import type { BscType } from '../../types/BscType';
import type { AstNode } from '../../parser/AstNode';
import type { ClassStatement, FunctionStatement, NamespaceStatement } from '../../parser/Statement';
import type { ClassStatement, FunctionStatement, NamespaceStatement, AliasStatement } from '../../parser/Statement';
import type { Token } from '../../lexer/Token';
import { createIdentifier } from '../../astUtils/creators';
import type { FunctionExpression } from '../../parser/Expression';
Expand Down Expand Up @@ -168,24 +168,29 @@ export class CompletionsProcessor {
return this.getLabelCompletion(functionScope);
}


if (file.getPreviousToken(currentToken)?.kind === TokenKind.Dot || file.isTokenNextToTokenKind(currentToken, TokenKind.Dot)) {
const dotToken = currentToken.kind === TokenKind.Dot ? currentToken : file.getTokenBefore(currentToken, TokenKind.Dot);
if (this.isTokenAdjacentTo(file, currentToken, TokenKind.Dot)) {
const dotToken = this.getAdjacentToken(file, currentToken, TokenKind.Dot);
beforeDotToken = file.getTokenBefore(dotToken);
expression = file.getClosestExpression(beforeDotToken?.range.end);
shouldLookForMembers = true;
} else if (file.getPreviousToken(currentToken)?.kind === TokenKind.Callfunc || file.isTokenNextToTokenKind(currentToken, TokenKind.Callfunc)) {
const dotToken = currentToken.kind === TokenKind.Callfunc ? currentToken : file.getTokenBefore(currentToken, TokenKind.Callfunc);
} else if (this.isTokenAdjacentTo(file, currentToken, TokenKind.Callfunc)) {
const dotToken = this.getAdjacentToken(file, currentToken, TokenKind.Callfunc);
beforeDotToken = file.getTokenBefore(dotToken);
expression = file.getClosestExpression(beforeDotToken?.range.end);
shouldLookForCallFuncMembers = true;
} else if (file.getPreviousToken(currentToken)?.kind === TokenKind.As || file.isTokenNextToTokenKind(currentToken, TokenKind.As)) {

} else if (this.isTokenAdjacentTo(file, currentToken, TokenKind.As)) {
if (file.parseMode === ParseMode.BrightScript) {
return NativeTypeCompletions;
}
expression = file.getClosestExpression(this.event.position);
symbolTableLookupFlag = SymbolTypeFlag.typetime;
} else if (this.isTokenAdjacentTo(file, currentToken, TokenKind.Equal)) {
expression = file.getClosestExpression(this.event.position);
if (expression.findAncestor<AliasStatement>(isAliasStatement)) {
// allow runtime and typetime lookups in alias statements
// eslint-disable-next-line no-bitwise
symbolTableLookupFlag = SymbolTypeFlag.runtime | SymbolTypeFlag.typetime;
}
} else {
expression = file.getClosestExpression(this.event.position);
}
Expand Down Expand Up @@ -326,10 +331,12 @@ export class CompletionsProcessor {
private getScopeSymbolCompletions(file: BrsFile, scope: Scope, symbolTableLookupFlag: SymbolTypeFlag) {
// get all scope available symbols

let scopeSymbols = file.parseMode === ParseMode.BrighterScript
const scopeSymbols = file.parseMode === ParseMode.BrighterScript
? [...scope.symbolTable.getOwnSymbols(symbolTableLookupFlag), ...scope.allNamespaceTypeTable.getOwnSymbols(symbolTableLookupFlag)]
: scope.symbolTable.getOwnSymbols(symbolTableLookupFlag);

const fileSymbols = file.ast.getSymbolTable().getOwnSymbols(symbolTableLookupFlag);
scopeSymbols.push(...fileSymbols);

const scopeAvailableSymbols = scopeSymbols.filter(sym => {
if (file.parseMode === ParseMode.BrighterScript) {
Expand Down Expand Up @@ -372,10 +379,20 @@ export class CompletionsProcessor {


private getCompletionKindFromSymbol(symbol: BscSymbol, areMembers = false) {
const type = symbol?.type;
let type = symbol?.type;
const extraData = symbol?.data;
const isInstance = extraData?.isInstance;
if (isConstStatement(extraData?.definingNode)) {
let definingNode = extraData?.definingNode;
let isAlias = extraData?.isAlias;
let isInstance = extraData?.isInstance;

if (isAliasStatement(extraData?.definingNode)) {
isAlias = true;
const aliasExtraData: ExtraSymbolData = {};
type = extraData.definingNode.value.getType({ flags: symbol.flags, data: aliasExtraData });
definingNode = aliasExtraData?.definingNode;
}

if (isConstStatement(definingNode)) {
return CompletionItemKind.Constant;
} else if (isClassType(type) && !isInstance) {
return CompletionItemKind.Class;
Expand All @@ -388,7 +405,7 @@ export class CompletionsProcessor {
nameMatchesType = true;
}
}
if (nameMatchesType) {
if (nameMatchesType || isAlias) {
return areMembers ? CompletionItemKind.Method : CompletionItemKind.Function;
}
} else if (isInterfaceType(type) && !isInstance) {
Expand Down Expand Up @@ -609,6 +626,14 @@ export class CompletionsProcessor {
}
return false;
}

private isTokenAdjacentTo(file: BrsFile, currentToken: Token, targetKind: TokenKind) {
return file.getPreviousToken(currentToken)?.kind === targetKind || file.isTokenNextToTokenKind(currentToken, targetKind);
}

private getAdjacentToken(file: BrsFile, currentToken: Token, targetKind: TokenKind) {
return currentToken.kind === targetKind ? currentToken : file.getTokenBefore(currentToken, targetKind);
}
}

/**
Expand Down
2 changes: 0 additions & 2 deletions src/bscPlugin/symbols/DocumentSymbolProcessor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { rootDir } from '../../testHelpers.spec';
import type { DocumentSymbol } from 'vscode-languageserver-types';
import { SymbolKind } from 'vscode-languageserver-types';
import type { BrsFile } from '../../files/BrsFile';

let sinon = createSandbox();

describe('DocumentSymbolProcessor', () => {
Expand Down Expand Up @@ -44,7 +43,6 @@ describe('DocumentSymbolProcessor', () => {
let node = file.ast.statements[0];
//delete the token at the given path
for (let i = 0; i < nameTokenPath.length - 1; i++) {

node = node[nameTokenPath[i]];
}

Expand Down
30 changes: 23 additions & 7 deletions src/files/BrsFile.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { CodeWithSourceMap } from 'source-map';
import { SourceNode } from 'source-map';
import type { CompletionItem, Position, Location } from 'vscode-languageserver';
import { CancellationTokenSource, CompletionItemKind } from 'vscode-languageserver';
import { CancellationTokenSource } from 'vscode-languageserver';
import { CompletionItemKind } from 'vscode-languageserver';
import chalk from 'chalk';
import * as path from 'path';
import { DiagnosticCodeMap, diagnosticCodes, DiagnosticMessages } from '../DiagnosticMessages';
Expand All @@ -17,7 +18,6 @@ import type { Program } from '../Program';
import { DynamicType } from '../types/DynamicType';
import { standardizePath as s, util } from '../util';
import { BrsTranspileState } from '../parser/BrsTranspileState';
import { LogLevel } from '../Logger';
import { serializeError } from 'serialize-error';
import { isClassStatement, isDottedGetExpression, isFunctionExpression, isFunctionStatement, isNamespaceStatement, isVariableExpression, isImportStatement, isEnumStatement, isConstStatement, isAnyReferenceType, isNamespaceType, isReferenceType, isCallableType, isBrsFile } from '../astUtils/reflection';
import { createVisitor, WalkMode } from '../astUtils/visitors';
Expand All @@ -26,19 +26,21 @@ import { CommentFlagProcessor } from '../CommentFlagProcessor';
import type { AstNode, Expression } from '../parser/AstNode';
import { ReferencesProvider } from '../bscPlugin/references/ReferencesProvider';
import { DocumentSymbolProcessor } from '../bscPlugin/symbols/DocumentSymbolProcessor';
import type { BscFile } from './BscFile';
import type { BscFileLike } from '../astUtils/CachedLookups';
import { CachedLookups } from '../astUtils/CachedLookups';
import { WorkspaceSymbolProcessor } from '../bscPlugin/symbols/WorkspaceSymbolProcessor';
import type { UnresolvedSymbol, AssignedSymbol } from '../AstValidationSegmenter';
import { AstValidationSegmenter } from '../AstValidationSegmenter';
import { LogLevel } from '../Logger';
import type { BscSymbol } from '../SymbolTable';
import { SymbolTable } from '../SymbolTable';
import { SymbolTypeFlag } from '../SymbolTypeFlag';
import type { BscFileLike } from '../astUtils/CachedLookups';
import { CachedLookups } from '../astUtils/CachedLookups';
import { Editor } from '../astUtils/Editor';
import { getBsConst } from '../preprocessor/Manifest';
import type { BscType } from '../types';
import { NamespaceType } from '../types';
import { getBsConst } from '../preprocessor/Manifest';
import { WorkspaceSymbolProcessor } from '../bscPlugin/symbols/WorkspaceSymbolProcessor';
import type { BscFile } from './BscFile';
import { DefinitionProvider } from '../bscPlugin/definition/DefinitionProvider';

export type ProvidedSymbolMap = Map<SymbolTypeFlag, Map<string, BscSymbol>>;
export type ChangedSymbolMap = Map<SymbolTypeFlag, Set<string>>;
Expand Down Expand Up @@ -853,6 +855,20 @@ export class BrsFile implements BscFile {
}).process();
}

/**
* Given a position in a file, if the position is sitting on some type of identifier,
* go to the definition of that identifier (where this thing was first defined)
* @deprecated use `DefinitionProvider.process()` instead
*/
public getDefinition(position: Position): Location[] {
return new DefinitionProvider({
program: this.program,
file: this,
position: position,
definitions: []
}).process();
}

public getClassMemberDefinitions(textToSearchFor: string, file: BrsFile): Location[] {
let results: Location[] = [];
//get class fields and members
Expand Down
4 changes: 1 addition & 3 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Range, Diagnostic, CodeAction, Position, CompletionItem, Location, DocumentSymbol } from 'vscode-languageserver-protocol';
import type { Range, Diagnostic, CodeAction, Position, CompletionItem, Location, DocumentSymbol, WorkspaceSymbol } from 'vscode-languageserver-protocol';
import type { Scope } from './Scope';
import type { BrsFile } from './files/BrsFile';
import type { XmlFile } from './files/XmlFile';
Expand All @@ -21,7 +21,6 @@ import type { FileFactory } from './files/Factory';
import type { LazyFileData } from './files/LazyFileData';
import { TokenKind } from './lexer/TokenKind';
import type { BscTypeKind } from './types/BscTypeKind';
import type { WorkspaceSymbol } from 'vscode-languageserver-types';
import { createToken } from './astUtils/creators';

export interface BsDiagnostic extends Diagnostic {
Expand Down Expand Up @@ -322,7 +321,6 @@ export interface CompilerPlugin {
*/
afterProvideWorkspaceSymbols?(event: AfterProvideWorkspaceSymbolsEvent): any;


//scope events
onScopeValidate?(event: OnScopeValidateEvent): any;
afterScopeValidate?(event: BeforeScopeValidateEvent): any;
Expand Down
2 changes: 1 addition & 1 deletion src/parser/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ import {
import type { Diagnostic, Range } from 'vscode-languageserver';
import type { Logger } from '../logging';
import { createLogger } from '../logging';
import { isAnnotationExpression, isCallExpression, isCallfuncExpression, isConditionalCompileStatement, isDottedGetExpression, isIfStatement, isIndexedGetExpression, isLiteralBoolean, isTypecastExpression, isVariableExpression } from '../astUtils/reflection';
import { isAnnotationExpression, isCallExpression, isCallfuncExpression, isDottedGetExpression, isIfStatement, isIndexedGetExpression, isVariableExpression, isConditionalCompileStatement, isLiteralBoolean, isTypecastExpression } from '../astUtils/reflection';
import { createStringLiteral, createToken } from '../astUtils/creators';
import type { Expression, Statement } from './AstNode';
import type { DeepWriteable } from '../interfaces';
Expand Down

0 comments on commit 8c4de7d

Please sign in to comment.