From a5efd22b197a52fc1be21f41d56e0df588eac407 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Thu, 19 Dec 2019 11:12:52 +0800 Subject: [PATCH 01/17] update lg syntax --- Composer/packages/lib/code-editor/demo/src/lgEditor.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx b/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx index 24a8986e02..026571d28c 100644 --- a/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx +++ b/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx @@ -9,9 +9,9 @@ const content = `# Hello -[Welcome(time)] {name} # Welcome(time) --IF:{time == 'morning'} +-IF:@{time == 'morning'} - Good morning --ELSEIF:{time == 'evening'} +-ELSEIF:@{time == 'evening'} - Good evening -ELSE: - How are you doing, @@ -23,7 +23,7 @@ const content = `# Hello -What's up bro # ShowTodo --IF:{count(user.todos) > 0} +-IF:@{count(user.todos) > 0} -\`\`\` {HelperFunction()} @{join(foreach(user.todos, x, showSingleTodo(x)), '\n')} From fd90180071499a32450647fd675b924740903cd5 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Thu, 19 Dec 2019 17:39:47 +0800 Subject: [PATCH 02/17] pass botproject service to lsp --- .../lib/code-editor/demo/src/inlineEditor.tsx | 21 ++---- .../packages/lib/code-editor/src/LgEditor.tsx | 15 +---- Composer/packages/server/src/server.ts | 3 +- .../language-generation/package.json | 1 + .../language-generation/src/LGServer.ts | 65 ++++++++++++------- .../language-generation/src/utils.ts | 17 +++-- 6 files changed, 59 insertions(+), 63 deletions(-) diff --git a/Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx b/Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx index 2ba1c011c0..0b493bc11c 100644 --- a/Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx +++ b/Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx @@ -5,28 +5,17 @@ import React, { useState } from 'react'; import { LgEditor } from '../../src'; -const content = `# Greeting1 --Good morning - -# Greeting2 --Good afternoon - -# Greeting3 --Good evening -`; - // body will fill in editor const template = { - name: 'Greeting2', + name: 'Greeting', body: `-Good afternoon --[Greeting3] --[Greeting4]`, +-@{Exit()} +-@{Greeting4()}`, }; const lgOption = { - inline: true, - content, - template, + fileId: 'common', + templateId: 'Greeting', }; export default function App() { diff --git a/Composer/packages/lib/code-editor/src/LgEditor.tsx b/Composer/packages/lib/code-editor/src/LgEditor.tsx index 02d6f69b7d..98c7f60d04 100644 --- a/Composer/packages/lib/code-editor/src/LgEditor.tsx +++ b/Composer/packages/lib/code-editor/src/LgEditor.tsx @@ -18,13 +18,8 @@ const placeholder = `> To learn more about the LG file format, read the document > ${LG_HELP}`; export interface LGOption { - inline: boolean; - content: string; - template?: { - name: string; - parameters?: string[]; - body: string; - }; + fileId: string; + templateId: string; } export interface LGLSPEditorProps extends RichEditorProps { @@ -53,11 +48,7 @@ async function initializeDocuments(lgOption: LGOption | undefined, uri: string) const languageClient = window.monacoLGEditorInstance; if (languageClient) { await languageClient.onReady(); - if (lgOption && lgOption.inline) { - languageClient.sendRequest('initializeDocuments', { ...lgOption, uri }); - } else { - languageClient.sendRequest('initializeDocuments', { uri }); - } + languageClient.sendRequest('initializeDocuments', { uri, lgOption }); } } diff --git a/Composer/packages/server/src/server.ts b/Composer/packages/server/src/server.ts index 2c0e980fa1..f611152ec3 100644 --- a/Composer/packages/server/src/server.ts +++ b/Composer/packages/server/src/server.ts @@ -14,6 +14,7 @@ import * as rpc from 'vscode-ws-jsonrpc'; import { IConnection, createConnection } from 'vscode-languageserver'; import { LGServer } from '@bfc/lg-languageserver'; +import { BotProjectService } from './services/project'; import { getAuthProvider } from './router/auth'; import { apiRouter } from './router/api'; import { BASEURL } from './constants'; @@ -117,7 +118,7 @@ function launchLanguageServer(socket: rpc.IWebSocket) { const reader = new rpc.WebSocketMessageReader(socket); const writer = new rpc.WebSocketMessageWriter(socket); const connection: IConnection = createConnection(reader, writer); - const server = new LGServer(connection); + const server = new LGServer(connection, BotProjectService); server.start(); } diff --git a/Composer/packages/tools/language-servers/language-generation/package.json b/Composer/packages/tools/language-servers/language-generation/package.json index 317bdfa940..b05fb13a4d 100644 --- a/Composer/packages/tools/language-servers/language-generation/package.json +++ b/Composer/packages/tools/language-servers/language-generation/package.json @@ -15,6 +15,7 @@ "lint:typecheck": "tsc --noEmit" }, "dependencies": { + "@bfc/indexers": "*", "botbuilder-lg": "4.7.0-preview.93464", "request-light": "^0.2.2", "vscode-languageserver": "^5.3.0-next" diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index bd023cc83d..453dfff050 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -18,19 +18,19 @@ import { import { TextDocumentPositionParams } from 'vscode-languageserver-protocol'; import get from 'lodash/get'; import { LGTemplate, Diagnostic as LGDiagnostic } from 'botbuilder-lg'; +import { LgFile, lgIndexer } from '@bfc/indexers'; import { buildInfunctionsMap } from './builtinFunctionsMap'; import { getRangeAtPosition, getLGResources, updateTemplateInContent, - getTemplateRange, LGDocument, checkText, checkTemplate, convertDiagnostics, isValid, - TRange, + LGOption, } from './utils'; // define init methods call from client @@ -38,13 +38,16 @@ const InitializeDocumentsMethodName = 'initializeDocuments'; const allowedCompletionStates = ['expression']; +const { parse } = lgIndexer; + export class LGServer { protected workspaceRoot?: URI; protected readonly documents = new TextDocuments(); protected readonly pendingValidationRequests = new Map(); protected LGDocuments: LGDocument[] = []; // LG Documents Store + protected lgFiles: LgFile[] = []; - constructor(protected readonly connection: IConnection) { + constructor(protected readonly connection: IConnection, protected readonly botProjectService) { this.documents.listen(this.connection); this.documents.onDidChangeContent(change => this.validate(change.document)); this.documents.onDidClose(event => { @@ -74,10 +77,16 @@ export class LGServer { this.connection.onCompletion(params => this.completion(params)); this.connection.onHover(params => this.hover(params)); - this.connection.onRequest((method, params) => { + this.connection.onRequest(async (method, params) => { if (InitializeDocumentsMethodName === method) { - const { uri, inline = false, content, template } = params; - this.LGDocuments.push({ uri, inline, content, template }); + const currentProject = this.botProjectService.getCurrentBotProject(); + if (currentProject !== undefined && (await currentProject.exists())) { + await currentProject.index(); + const { lgFiles } = currentProject.getIndexes(); + this.lgFiles = lgFiles; + } + const { uri, lgOption }: { uri: string; lgOption: LGOption } = params; + this.LGDocuments.push({ uri, lgOption }); // run diagnostic const textDocument = this.documents.get(uri); if (textDocument) { @@ -97,9 +106,14 @@ export class LGServer { protected getLGDocumentContent(document: TextDocument): string { const LGDocument = this.LGDocuments.find(item => item.uri === document.uri); const text = document.getText(); - if (LGDocument && LGDocument.inline) { - const { content, template } = LGDocument; - if (!content || !template) return text; + if (LGDocument && LGDocument.lgOption) { + const { fileId, templateId } = LGDocument.lgOption; + const lgFile = this.lgFiles.find(({ id }) => id === fileId); + if (!lgFile) return text; + const { content, templates } = lgFile; + + const template = templates.find(({ name }) => name === templateId); + if (!template) return text; const updatedTemplate = { name: template.name, parameters: template.parameters, @@ -302,7 +316,7 @@ export class LGServer { } protected doValidate(document: TextDocument): void { - let text = document.getText(); + const text = document.getText(); const LGDocument = this.getLGDocument(document); let lgDiagnostics: LGDiagnostic[] = []; let lineOffset = 0; @@ -318,16 +332,14 @@ export class LGServer { } // if inline editor, concat new content for validate - if (LGDocument.inline) { - const { content, template } = LGDocument; - if (!content || !template) return; - const updatedTemplate = { - name: template.name, - parameters: template.parameters, + const { lgOption } = LGDocument; + if (lgOption) { + const { templateId, fileId } = lgOption; + const templateDiags = checkTemplate({ + name: templateId, + parameters: [], body: text, - }; - - const templateDiags = checkTemplate(updatedTemplate); + }); // error in template. if (isValid(templateDiags) === false) { const diagnostics = convertDiagnostics(templateDiags, document); @@ -335,15 +347,18 @@ export class LGServer { return; } - text = updateTemplateInContent(content, updatedTemplate); - const templateRange: TRange = getTemplateRange(content, updatedTemplate); - lineOffset = templateRange.startLineNumber; + const fullText = this.getLGDocumentContent(document); + const template = parse(fullText, fileId).find(({ name }) => name === templateId); + if (!template) return; + lineOffset = template.range.startLineNumber; // filter diagnostics belong to this template. - lgDiagnostics = checkText(text).filter(lgDialg => { + lgDiagnostics = checkText(fullText).filter(lgDialg => { return ( - lgDialg.range.start.line >= templateRange.startLineNumber && - lgDialg.range.end.line <= templateRange.endLineNumber + lgDialg.range && + template.range && + lgDialg.range.start.line >= template.range.startLineNumber && + lgDialg.range.end.line <= template.range.endLineNumber ); }); } else { diff --git a/Composer/packages/tools/language-servers/language-generation/src/utils.ts b/Composer/packages/tools/language-servers/language-generation/src/utils.ts index e9af71c534..70c0f15285 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/utils.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/utils.ts @@ -11,25 +11,24 @@ import { StaticChecker, } from 'botbuilder-lg'; import get from 'lodash/get'; +import { CodeRange } from '@bfc/indexers'; const staticChecker = new StaticChecker(); +export interface LGOption { + fileId: string; + templateId: string; +} + export interface Template { name: string; parameters?: string[]; body: string; } -export interface TRange { - startLineNumber: number; - endLineNumber: number; -} - export interface LGDocument { uri: string; - inline: boolean; - content?: string; - template?: Template; + lgOption?: LGOption; } export function getRangeAtPosition(document: TextDocument, position: Position): Range | undefined { @@ -119,7 +118,7 @@ export function getLGResources(content: string): LGResource { return LGParser.parse(content, ' '); } -export function getTemplateRange(content: string, { name, parameters = [], body }: Template): TRange { +export function getTemplateRange(content: string, { name, parameters = [], body }: Template): CodeRange { const resource = LGParser.parse(content).updateTemplate(name, name, parameters, body); const template = resource.templates.find(item => item.name === name); return { From 0fd7c56058654b1128d0afc2386a2d40b099e5e1 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Fri, 20 Dec 2019 15:35:16 +0800 Subject: [PATCH 03/17] update --- .../lib/code-editor/demo/src/lgEditor.tsx | 14 +-- .../language-generation/src/LGServer.ts | 87 ++++++++++++------- 2 files changed, 64 insertions(+), 37 deletions(-) diff --git a/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx b/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx index 026571d28c..bdee4fd2ed 100644 --- a/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx +++ b/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx @@ -6,7 +6,7 @@ import React, { useState } from 'react'; import { LgEditor } from '../../src'; const content = `# Hello --[Welcome(time)] {name} +-@{Welcome(time)} @{name} # Welcome(time) -IF:@{time == 'morning'} @@ -35,7 +35,7 @@ const content = `# Hello -* {x} # HelperFunction -- IF: {count(user.todos) == 1} +- IF: @{count(user.todos) == 1} - Your most recent @{count(user.todos)} task is - ELSE: - Your most recent @{count(user.todos)} tasks are @@ -46,7 +46,7 @@ const content = `# Hello -Help, we don't need no stinkin' help! # bfdactivity-116673 --Successfully added a todo named {dialog.todo} +-Successfully added a todo named @{dialog.todo} # bfdactivity-832307 -Successfully cleared items in the Todo List. @@ -55,19 +55,19 @@ const content = `# Hello -You don't have any items in the Todo List. # bfdactivity-725469 --Successfully removed a todo named {dialog.todo} +-Successfully removed a todo named @{dialog.todo} # bfdactivity-549615 --{dialog.todo} is not in the Todo List +-@{dialog.todo} is not in the Todo List # bfdactivity-339580 -You have no todos. # bfdactivity-662084 --[ShowTodo] +-@{ShowTodo} # bfdactivity-696707 --[help] +-@{help} # bfdactivity-157674 - Hi! I'm a ToDo bot. Say "add a todo named first" to get started. diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index 453dfff050..b52d96e102 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -18,7 +18,10 @@ import { import { TextDocumentPositionParams } from 'vscode-languageserver-protocol'; import get from 'lodash/get'; import { LGTemplate, Diagnostic as LGDiagnostic } from 'botbuilder-lg'; -import { LgFile, lgIndexer } from '@bfc/indexers'; +import { LgFile, lgIndexer, LgTemplate } from '@bfc/indexers'; + +// import { BotProject } from '../../../../server/src/models/bot/botProject'; +// import { BotProjectService } from '../../../../server/src/services/project'; import { buildInfunctionsMap } from './builtinFunctionsMap'; import { @@ -45,7 +48,6 @@ export class LGServer { protected readonly documents = new TextDocuments(); protected readonly pendingValidationRequests = new Map(); protected LGDocuments: LGDocument[] = []; // LG Documents Store - protected lgFiles: LgFile[] = []; constructor(protected readonly connection: IConnection, protected readonly botProjectService) { this.documents.listen(this.connection); @@ -77,15 +79,9 @@ export class LGServer { this.connection.onCompletion(params => this.completion(params)); this.connection.onHover(params => this.hover(params)); - this.connection.onRequest(async (method, params) => { + this.connection.onRequest((method, params) => { if (InitializeDocumentsMethodName === method) { - const currentProject = this.botProjectService.getCurrentBotProject(); - if (currentProject !== undefined && (await currentProject.exists())) { - await currentProject.index(); - const { lgFiles } = currentProject.getIndexes(); - this.lgFiles = lgFiles; - } - const { uri, lgOption }: { uri: string; lgOption: LGOption } = params; + const { uri, lgOption }: { uri: string; lgOption?: LGOption } = params; this.LGDocuments.push({ uri, lgOption }); // run diagnostic const textDocument = this.documents.get(uri); @@ -96,36 +92,67 @@ export class LGServer { }); } + protected verifyLgOption(lgOption: LGOption) { + const { fileId, templateId } = lgOption; + const lgFile = this.getLGFile(fileId); + if (!lgFile) throw new Error(`File ${fileId}.lg do not exist`); + const { templates } = lgFile; + const template = templates.find(({ name }) => name === templateId); + if (!template) throw new Error(`Template ${fileId}.lg#${templateId} do not exist`); + } + start() { this.connection.listen(); } + protected getLGOption(document: TextDocument): LGOption | undefined { + const LGDocument = this.LGDocuments.find(item => item.uri === document.uri); + if (!LGDocument || !LGDocument.lgOption) return; + const { lgOption } = LGDocument; + return lgOption; + } + + protected getLGFile(fileId: string): LgFile | undefined { + const currentProject = this.botProjectService.getCurrentBotProject(); + if (!currentProject) return; + const { lgFiles } = currentProject.getIndexes(); + return lgFiles.find(({ id }) => id === fileId); + } + + protected getLGTemplate(fileId: string, templateId: string): LgTemplate | undefined { + const lgFile = this.getLGFile(fileId); + if (!lgFile) return; + const { templates } = lgFile; + return templates.find(({ name }) => name === templateId); + } + protected getLGDocument(document: TextDocument): LGDocument | undefined { return this.LGDocuments.find(({ uri }) => uri === document.uri); } protected getLGDocumentContent(document: TextDocument): string { - const LGDocument = this.LGDocuments.find(item => item.uri === document.uri); const text = document.getText(); - if (LGDocument && LGDocument.lgOption) { - const { fileId, templateId } = LGDocument.lgOption; - const lgFile = this.lgFiles.find(({ id }) => id === fileId); - if (!lgFile) return text; - const { content, templates } = lgFile; - - const template = templates.find(({ name }) => name === templateId); - if (!template) return text; - const updatedTemplate = { - name: template.name, - parameters: template.parameters, - body: text, - }; - - const templateDiags = checkTemplate(updatedTemplate); - if (isValid(templateDiags)) { - return updateTemplateInContent(content, updatedTemplate); - } + const lgOption = this.getLGOption(document); + if (!lgOption) return text; + + const { fileId, templateId } = lgOption; + const lgFile = this.getLGFile(fileId); + if (!lgFile) throw new Error(`File ${fileId}.lg do not exist`); + const { content } = lgFile; + + const template = this.getLGTemplate(fileId, templateId); + if (!template) throw new Error(`Template ${fileId}.lg#${templateId} do not exist`); + + const updatedTemplate = { + name: template.name, + parameters: template.parameters, + body: text, + }; + + const templateDiags = checkTemplate(updatedTemplate); + if (isValid(templateDiags)) { + return updateTemplateInContent(content, updatedTemplate); } - return text; + return content; } protected hover(params: TextDocumentPositionParams): Thenable { From 696792c802ee9f7891eb9522476e2a288f7be0ae Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Fri, 20 Dec 2019 15:44:20 +0800 Subject: [PATCH 04/17] resolve merge --- .../client/src/pages/language-generation/code-editor.tsx | 5 ++--- .../obiformeditor/src/Form/widgets/LgEditorWidget.tsx | 6 ++---- .../language-servers/language-generation/src/LGServer.ts | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Composer/packages/client/src/pages/language-generation/code-editor.tsx b/Composer/packages/client/src/pages/language-generation/code-editor.tsx index f0d58d7e52..ebbbcbcb1a 100644 --- a/Composer/packages/client/src/pages/language-generation/code-editor.tsx +++ b/Composer/packages/client/src/pages/language-generation/code-editor.tsx @@ -150,9 +150,8 @@ const CodeEditor: React.FC = props => { const lgOption = template ? { - inline: inlineMode, - content: file?.content ?? '', - template, + fileId, + templateId: template?.name || '', } : undefined; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx index 7b624e35f0..c65bb95a76 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx @@ -4,7 +4,6 @@ import React, { useState, useMemo, useEffect } from 'react'; import { LgEditor } from '@bfc/code-editor'; import { LgMetaData, LgTemplateRef } from '@bfc/shared'; -import get from 'lodash/get'; import debounce from 'lodash/debounce'; import { FormContext } from '../types'; @@ -85,9 +84,8 @@ export const LgEditorWidget: React.FC = props => { : ''; const [localValue, setLocalValue] = useState(template.body); const lgOption = { - inline: true, - content: get(lgFile, 'content', ''), - template, + fileId: lgFileId, + templateId: lgName, }; const onChange = (body: string) => { diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index b52d96e102..87414bbaec 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -377,7 +377,7 @@ export class LGServer { const fullText = this.getLGDocumentContent(document); const template = parse(fullText, fileId).find(({ name }) => name === templateId); if (!template) return; - lineOffset = template.range.startLineNumber; + lineOffset = template.range?.startLineNumber ?? 0; // filter diagnostics belong to this template. lgDiagnostics = checkText(fullText).filter(lgDialg => { From 0045b6627d221fc90a52af982f5887eaa56df197 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Fri, 20 Dec 2019 16:01:31 +0800 Subject: [PATCH 05/17] clean up --- .../language-generation/src/LGServer.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index 87414bbaec..715d9e76b6 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -17,16 +17,12 @@ import { } from 'vscode-languageserver-types'; import { TextDocumentPositionParams } from 'vscode-languageserver-protocol'; import get from 'lodash/get'; -import { LGTemplate, Diagnostic as LGDiagnostic } from 'botbuilder-lg'; +import { Diagnostic as LGDiagnostic } from 'botbuilder-lg'; import { LgFile, lgIndexer, LgTemplate } from '@bfc/indexers'; -// import { BotProject } from '../../../../server/src/models/bot/botProject'; -// import { BotProjectService } from '../../../../server/src/services/project'; - import { buildInfunctionsMap } from './builtinFunctionsMap'; import { getRangeAtPosition, - getLGResources, updateTemplateInContent, LGDocument, checkText, @@ -161,8 +157,7 @@ export class LGServer { return Promise.resolve(null); } const text = this.getLGDocumentContent(document); - const lgResources = getLGResources(text); - const templates = lgResources.templates; + const templates = parse(text); const wordRange = getRangeAtPosition(document, params.position); let word = document.getText(wordRange); const matchItem = templates.find(u => u.name === word); @@ -276,7 +271,6 @@ export class LGServer { return Promise.resolve(null); } const text = this.getLGDocumentContent(document); - let templates: LGTemplate[] = []; const diags = checkText(text); @@ -284,8 +278,7 @@ export class LGServer { return Promise.resolve(null); } - const lgResources = getLGResources(text); - templates = lgResources.templates; + const templates = parse(text); const completionTemplateList: CompletionItem[] = templates.map(template => { return { From 33bb9aff8d59e16ecbf16cc2d45b0caa76fb1549 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Fri, 20 Dec 2019 17:37:54 +0800 Subject: [PATCH 06/17] update parse --- .../language-generation/src/LGServer.ts | 80 ++++++++++++++----- .../language-generation/src/utils.ts | 31 ++++++- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index 715d9e76b6..783152248f 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -14,11 +14,12 @@ import { CompletionItemKind, CompletionItem, Range, + DiagnosticSeverity, } from 'vscode-languageserver-types'; import { TextDocumentPositionParams } from 'vscode-languageserver-protocol'; import get from 'lodash/get'; import { Diagnostic as LGDiagnostic } from 'botbuilder-lg'; -import { LgFile, lgIndexer, LgTemplate } from '@bfc/indexers'; +import { LgFile, LgTemplate } from '@bfc/indexers'; import { buildInfunctionsMap } from './builtinFunctionsMap'; import { @@ -28,8 +29,10 @@ import { checkText, checkTemplate, convertDiagnostics, + generageDiagnostic, isValid, LGOption, + parse, } from './utils'; // define init methods call from client @@ -37,15 +40,18 @@ const InitializeDocumentsMethodName = 'initializeDocuments'; const allowedCompletionStates = ['expression']; -const { parse } = lgIndexer; - export class LGServer { protected workspaceRoot?: URI; protected readonly documents = new TextDocuments(); protected readonly pendingValidationRequests = new Map(); - protected LGDocuments: LGDocument[] = []; // LG Documents Store - - constructor(protected readonly connection: IConnection, protected readonly botProjectService) { + /** + * LG documents infomation store. + * The connection between lgOption and botProjectService. + * Help do inline template editing and server resource passing. + */ + protected LGDocuments: LGDocument[] = []; + + constructor(protected readonly connection: IConnection, protected readonly botProjectService?) { this.documents.listen(this.connection); this.documents.onDidChangeContent(change => this.validate(change.document)); this.documents.onDidClose(event => { @@ -78,23 +84,38 @@ export class LGServer { this.connection.onRequest((method, params) => { if (InitializeDocumentsMethodName === method) { const { uri, lgOption }: { uri: string; lgOption?: LGOption } = params; - this.LGDocuments.push({ uri, lgOption }); + if (this.botProjectService) this.LGDocuments.push({ uri, lgOption }); // run diagnostic const textDocument = this.documents.get(uri); if (textDocument) { + if (lgOption) this.verifyLgOption(lgOption, textDocument); this.validate(textDocument); } } }); } - protected verifyLgOption(lgOption: LGOption) { - const { fileId, templateId } = lgOption; - const lgFile = this.getLGFile(fileId); - if (!lgFile) throw new Error(`File ${fileId}.lg do not exist`); - const { templates } = lgFile; - const template = templates.find(({ name }) => name === templateId); - if (!template) throw new Error(`Template ${fileId}.lg#${templateId} do not exist`); + protected verifyLgOption(lgOption: LGOption, document: TextDocument) { + const diagnostics: string[] = []; + + if (!this.botProjectService) { + diagnostics.push('[Error lgOption] botProjectService is required but not exist.'); + } else { + const { fileId, templateId } = lgOption; + const lgFile = this.getLGFile(fileId); + if (!lgFile) { + diagnostics.push(`[Error lgOption] File ${fileId}.lg do not exist`); + } else { + const { templates } = lgFile; + const template = templates.find(({ name }) => name === templateId); + if (!template) diagnostics.push(`Template ${fileId}.lg#${templateId} do not exist`); + } + } + this.connection.console.log(diagnostics.join('\n')); + this.sendDiagnostics( + document, + diagnostics.map(errorMsg => generageDiagnostic(errorMsg, DiagnosticSeverity.Error, document)) + ); } start() { @@ -109,7 +130,7 @@ export class LGServer { } protected getLGFile(fileId: string): LgFile | undefined { - const currentProject = this.botProjectService.getCurrentBotProject(); + const currentProject = this.botProjectService?.getCurrentBotProject(); if (!currentProject) return; const { lgFiles } = currentProject.getIndexes(); return lgFiles.find(({ id }) => id === fileId); @@ -125,6 +146,14 @@ export class LGServer { protected getLGDocument(document: TextDocument): LGDocument | undefined { return this.LGDocuments.find(({ uri }) => uri === document.uri); } + + /** + * + * @param document + * 1. if !botProjectService, return text; + * 2. if botProjectService && !lgOption, return text; + * 3. if botProjectService + */ protected getLGDocumentContent(document: TextDocument): string { const text = document.getText(); const lgOption = this.getLGOption(document); @@ -132,11 +161,11 @@ export class LGServer { const { fileId, templateId } = lgOption; const lgFile = this.getLGFile(fileId); - if (!lgFile) throw new Error(`File ${fileId}.lg do not exist`); + if (!lgFile) return text; const { content } = lgFile; const template = this.getLGTemplate(fileId, templateId); - if (!template) throw new Error(`Template ${fileId}.lg#${templateId} do not exist`); + if (!template) return content; const updatedTemplate = { name: template.name, @@ -157,7 +186,11 @@ export class LGServer { return Promise.resolve(null); } const text = this.getLGDocumentContent(document); - const templates = parse(text); + const { templates, diagnostics } = parse(text, document); + if (diagnostics.length) { + this.sendDiagnostics(document, diagnostics); + return Promise.resolve(null); + } const wordRange = getRangeAtPosition(document, params.position); let word = document.getText(wordRange); const matchItem = templates.find(u => u.name === word); @@ -278,7 +311,11 @@ export class LGServer { return Promise.resolve(null); } - const templates = parse(text); + const { templates, diagnostics } = parse(text, document); + if (diagnostics.length) { + this.sendDiagnostics(document, diagnostics); + return Promise.resolve(null); + } const completionTemplateList: CompletionItem[] = templates.map(template => { return { @@ -354,7 +391,7 @@ export class LGServer { // if inline editor, concat new content for validate const { lgOption } = LGDocument; if (lgOption) { - const { templateId, fileId } = lgOption; + const { templateId } = lgOption; const templateDiags = checkTemplate({ name: templateId, parameters: [], @@ -368,7 +405,8 @@ export class LGServer { } const fullText = this.getLGDocumentContent(document); - const template = parse(fullText, fileId).find(({ name }) => name === templateId); + const { templates } = parse(text, document); + const template = templates.find(({ name }) => name === templateId); if (!template) return; lineOffset = template.range?.startLineNumber ?? 0; diff --git a/Composer/packages/tools/language-servers/language-generation/src/utils.ts b/Composer/packages/tools/language-servers/language-generation/src/utils.ts index 70c0f15285..bde7a94439 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/utils.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/utils.ts @@ -11,7 +11,7 @@ import { StaticChecker, } from 'botbuilder-lg'; import get from 'lodash/get'; -import { CodeRange } from '@bfc/indexers'; +import { CodeRange, LgTemplate, lgIndexer } from '@bfc/indexers'; const staticChecker = new StaticChecker(); @@ -31,6 +31,11 @@ export interface LGDocument { lgOption?: LGOption; } +export interface LGParsedResource { + templates: LgTemplate[]; + diagnostics: Diagnostic[]; +} + export function getRangeAtPosition(document: TextDocument, position: Position): Range | undefined { const text = document.getText(); const line = position.line; @@ -61,6 +66,30 @@ export function convertSeverity(severity: LGDiagnosticSeverity): DiagnosticSever return severityMap[severity]; } +export function generageDiagnostic(message: string, severity: DiagnosticSeverity, document: TextDocument): Diagnostic { + return { + severity, + range: Range.create(Position.create(0, 0), Position.create(0, 0)), + message, + source: document.uri, + }; +} + +export function parse(content: string, document: TextDocument): LGParsedResource { + try { + const templates = lgIndexer.parse(content); + return { + templates, + diagnostics: [], + }; + } catch (error) { + return { + templates: [], + diagnostics: [generageDiagnostic(error.message, DiagnosticSeverity.Error, document)], + }; + } +} + export function convertDiagnostics(lgDiags: LGDiagnostic[] = [], document: TextDocument, lineOffset = 0): Diagnostic[] { const diagnostics: Diagnostic[] = []; lgDiags.forEach(diag => { From 88c7765672720da0af9c2d54b9eedd3951c26ee0 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Mon, 23 Dec 2019 18:09:36 +0800 Subject: [PATCH 07/17] filter inline template diagnostics --- .../pages/language-generation/code-editor.tsx | 14 ++------ .../src/Form/widgets/LgEditorWidget.tsx | 12 ++----- .../lib/indexers/src/utils/diagnosticUtil.ts | 26 +++++++++++++- .../language-generation/src/LGServer.ts | 34 +++++++------------ .../language-generation/src/utils.ts | 20 ++++------- 5 files changed, 48 insertions(+), 58 deletions(-) diff --git a/Composer/packages/client/src/pages/language-generation/code-editor.tsx b/Composer/packages/client/src/pages/language-generation/code-editor.tsx index ebbbcbcb1a..da516648f3 100644 --- a/Composer/packages/client/src/pages/language-generation/code-editor.tsx +++ b/Composer/packages/client/src/pages/language-generation/code-editor.tsx @@ -8,7 +8,7 @@ import get from 'lodash/get'; import debounce from 'lodash/debounce'; import isEmpty from 'lodash/isEmpty'; import { editor } from '@bfcomposer/monaco-editor/esm/vs/editor/editor.api'; -import { lgIndexer, combineMessage, isValid } from '@bfc/indexers'; +import { lgIndexer, combineMessage, isValid, filterTemplateDiagnostics } from '@bfc/indexers'; import { RouteComponentProps } from '@reach/router'; import querystring from 'query-string'; @@ -56,17 +56,7 @@ const CodeEditor: React.FC = props => { }, [fileId, templateId]); useEffect(() => { - const currentDiagnostics = - inlineMode && template - ? diagnostics.filter(d => { - return ( - d.range && - template.range && - d.range.start.line >= template.range.startLineNumber && - d.range.end.line <= template.range.endLineNumber - ); - }) - : diagnostics; + const currentDiagnostics = inlineMode && template ? filterTemplateDiagnostics(diagnostics, template) : diagnostics; const isInvalid = !isValid(currentDiagnostics); const text = isInvalid ? combineMessage(currentDiagnostics) : ''; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx index c65bb95a76..82fcfe1d9f 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx @@ -5,6 +5,7 @@ import React, { useState, useMemo, useEffect } from 'react'; import { LgEditor } from '@bfc/code-editor'; import { LgMetaData, LgTemplateRef } from '@bfc/shared'; import debounce from 'lodash/debounce'; +import { filterTemplateDiagnostics } from '@bfc/indexers'; import { FormContext } from '../types'; @@ -68,16 +69,7 @@ export const LgEditorWidget: React.FC = props => { }, }; - const diagnostic = - lgFile && - lgFile.diagnostics.find(d => { - return ( - d.range && - template.range && - d.range.start.line >= template.range.startLineNumber && - d.range.end.line <= template.range.endLineNumber - ); - }); + const diagnostic = lgFile && filterTemplateDiagnostics(lgFile.diagnostics, template); const errorMsg = diagnostic ? diagnostic.message.split('error message: ')[diagnostic.message.split('error message: ').length - 1] diff --git a/Composer/packages/lib/indexers/src/utils/diagnosticUtil.ts b/Composer/packages/lib/indexers/src/utils/diagnosticUtil.ts index 02c3bb077d..71960b474a 100644 --- a/Composer/packages/lib/indexers/src/utils/diagnosticUtil.ts +++ b/Composer/packages/lib/indexers/src/utils/diagnosticUtil.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { Diagnostic, DiagnosticSeverity } from '../diagnostic'; +import { Diagnostic, DiagnosticSeverity, Range, Position } from '../diagnostic'; +import { LgTemplate } from '../type'; export function createSingleMessage(d: Diagnostic): string { let msg = `${d.message}\n`; @@ -20,6 +21,29 @@ export function combineMessage(diagnostics: Diagnostic[]): string { }, ''); } +export function offsetRange(range: Range, offset: number): Range { + return new Range( + new Position(range.start.line - offset, range.start.character), + new Position(range.end.line - offset, range.end.character) + ); +} + +export function filterTemplateDiagnostics(diagnostics: Diagnostic[], template: LgTemplate): Diagnostic[] { + const { range } = template; + if (!range) return diagnostics; + const filteredDiags = diagnostics.filter(d => { + return d.range && d.range.start.line >= range.startLineNumber && d.range.end.line <= range.endLineNumber; + }); + const offset = range.startLineNumber; + return filteredDiags.map(d => { + const { range } = d; + if (range) { + d.range = offsetRange(range, offset); + } + return d; + }); +} + export function findErrors(diagnostics: Diagnostic[]): Diagnostic[] { return diagnostics.filter(d => d.severity === DiagnosticSeverity.Error); } diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index 783152248f..125a88cfa8 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -18,23 +18,22 @@ import { } from 'vscode-languageserver-types'; import { TextDocumentPositionParams } from 'vscode-languageserver-protocol'; import get from 'lodash/get'; -import { Diagnostic as LGDiagnostic } from 'botbuilder-lg'; -import { LgFile, LgTemplate } from '@bfc/indexers'; +import { LgFile, LgTemplate, lgIndexer, filterTemplateDiagnostics, isValid } from '@bfc/indexers'; import { buildInfunctionsMap } from './builtinFunctionsMap'; import { getRangeAtPosition, updateTemplateInContent, LGDocument, - checkText, checkTemplate, convertDiagnostics, generageDiagnostic, - isValid, LGOption, parse, } from './utils'; +const { check } = lgIndexer; + // define init methods call from client const InitializeDocumentsMethodName = 'initializeDocuments'; @@ -305,7 +304,7 @@ export class LGServer { } const text = this.getLGDocumentContent(document); - const diags = checkText(text); + const diags = check(text, ''); if (isValid(diags) === false) { return Promise.resolve(null); @@ -375,8 +374,6 @@ export class LGServer { protected doValidate(document: TextDocument): void { const text = document.getText(); const LGDocument = this.getLGDocument(document); - let lgDiagnostics: LGDiagnostic[] = []; - let lineOffset = 0; // uninitialized if (!LGDocument) { @@ -391,7 +388,7 @@ export class LGServer { // if inline editor, concat new content for validate const { lgOption } = LGDocument; if (lgOption) { - const { templateId } = lgOption; + const { templateId, fileId } = lgOption; const templateDiags = checkTemplate({ name: templateId, parameters: [], @@ -399,7 +396,7 @@ export class LGServer { }); // error in template. if (isValid(templateDiags) === false) { - const diagnostics = convertDiagnostics(templateDiags, document); + const diagnostics = convertDiagnostics(templateDiags, document, 1); this.sendDiagnostics(document, diagnostics); return; } @@ -408,22 +405,15 @@ export class LGServer { const { templates } = parse(text, document); const template = templates.find(({ name }) => name === templateId); if (!template) return; - lineOffset = template.range?.startLineNumber ?? 0; // filter diagnostics belong to this template. - lgDiagnostics = checkText(fullText).filter(lgDialg => { - return ( - lgDialg.range && - template.range && - lgDialg.range.start.line >= template.range.startLineNumber && - lgDialg.range.end.line <= template.range.endLineNumber - ); - }); - } else { - lgDiagnostics = checkText(text); + const lgDiagnostics = filterTemplateDiagnostics(check(fullText, fileId), template); + const diagnostics = convertDiagnostics(lgDiagnostics, document, 1); + this.sendDiagnostics(document, diagnostics); + return; } - - const diagnostics = convertDiagnostics(lgDiagnostics, document, lineOffset); + const lgDiagnostics = check(text, ''); + const diagnostics = convertDiagnostics(lgDiagnostics, document); this.sendDiagnostics(document, diagnostics); } diff --git a/Composer/packages/tools/language-servers/language-generation/src/utils.ts b/Composer/packages/tools/language-servers/language-generation/src/utils.ts index bde7a94439..41f72f8c56 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/utils.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/utils.ts @@ -11,7 +11,7 @@ import { StaticChecker, } from 'botbuilder-lg'; import get from 'lodash/get'; -import { CodeRange, LgTemplate, lgIndexer } from '@bfc/indexers'; +import { CodeRange, LgTemplate, lgIndexer, Diagnostic as BFDiagnostic, offsetRange } from '@bfc/indexers'; const staticChecker = new StaticChecker(); @@ -90,15 +90,16 @@ export function parse(content: string, document: TextDocument): LGParsedResource } } -export function convertDiagnostics(lgDiags: LGDiagnostic[] = [], document: TextDocument, lineOffset = 0): Diagnostic[] { +// if template, offset +1 to exclude #TemplateName +export function convertDiagnostics(lgDiags: BFDiagnostic[] = [], document: TextDocument, offset = 0): Diagnostic[] { const diagnostics: Diagnostic[] = []; + const defaultRange = Range.create(Position.create(0, 0), Position.create(0, 0)); lgDiags.forEach(diag => { + // offset +1, lsp start from line:0, but monaco/composer start from line:1 + const range = diag.range ? offsetRange(diag.range, 1 + offset) : defaultRange; const diagnostic: Diagnostic = { severity: convertSeverity(diag.severity), - range: Range.create( - Position.create(diag.range.start.line - 1 - lineOffset, diag.range.start.character), - Position.create(diag.range.end.line - 1 - lineOffset, diag.range.end.character) - ), + range, message: diag.message, source: document.uri, }; @@ -136,13 +137,6 @@ export function checkTemplate(template: Template): LGDiagnostic[] { }); } -export function checkText(text: string): LGDiagnostic[] { - return staticChecker.checkText(text, '', ImportResolver.fileResolver); -} -export function isValid(diagnostics: LGDiagnostic[]): boolean { - return diagnostics.every(d => d.severity !== LGDiagnosticSeverity.Error); -} - export function getLGResources(content: string): LGResource { return LGParser.parse(content, ' '); } From f1699d02a2bad09726257027823df510bddd19c4 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Tue, 24 Dec 2019 12:16:41 +0800 Subject: [PATCH 08/17] update --- .../obiformeditor/src/Form/widgets/LgEditorWidget.tsx | 3 ++- .../tools/language-servers/language-generation/src/LGServer.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx index 82fcfe1d9f..ceae1e2017 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/LgEditorWidget.tsx @@ -62,6 +62,7 @@ export const LgEditorWidget: React.FC = props => { return template.name === lgName; })) || { name: lgName, + parameters: [], body: getInitialTemplate(name, value), range: { startLineNumber: 0, @@ -69,7 +70,7 @@ export const LgEditorWidget: React.FC = props => { }, }; - const diagnostic = lgFile && filterTemplateDiagnostics(lgFile.diagnostics, template); + const diagnostic = lgFile && filterTemplateDiagnostics(lgFile.diagnostics, template)[0]; const errorMsg = diagnostic ? diagnostic.message.split('error message: ')[diagnostic.message.split('error message: ').length - 1] diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index 125a88cfa8..5c6a1e0bda 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -83,7 +83,7 @@ export class LGServer { this.connection.onRequest((method, params) => { if (InitializeDocumentsMethodName === method) { const { uri, lgOption }: { uri: string; lgOption?: LGOption } = params; - if (this.botProjectService) this.LGDocuments.push({ uri, lgOption }); + this.LGDocuments.push({ uri, lgOption }); // run diagnostic const textDocument = this.documents.get(uri); if (textDocument) { From fee84246a89dc83705500f6b3544d6b8d7fa5d64 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Tue, 24 Dec 2019 15:52:13 +0800 Subject: [PATCH 09/17] move code-editor to extenstions/ --- .../packages/{lib => extensions}/code-editor/.eslintrc.js | 0 Composer/packages/{lib => extensions}/code-editor/.gitignore | 0 .../{lib => extensions}/code-editor/demo/.eslintrc.js | 0 .../packages/{lib => extensions}/code-editor/demo/index.html | 0 .../{lib => extensions}/code-editor/demo/src/index.tsx | 0 .../{lib => extensions}/code-editor/demo/src/inlineEditor.tsx | 0 .../{lib => extensions}/code-editor/demo/src/jsonEditor.tsx | 0 .../{lib => extensions}/code-editor/demo/src/lgEditor.tsx | 0 .../{lib => extensions}/code-editor/demo/src/lgJsonEditor.tsx | 0 .../{lib => extensions}/code-editor/demo/src/luEditor.tsx | 0 .../{lib => extensions}/code-editor/demo/src/multiEditors.tsx | 0 .../{lib => extensions}/code-editor/demo/src/richEditor.tsx | 0 .../{lib => extensions}/code-editor/demo/tsconfig.json | 0 .../code-editor/demo/webpack.config.demo.js | 0 .../packages/{lib => extensions}/code-editor/jest.config.js | 0 .../packages/{lib => extensions}/code-editor/package.json | 0 .../{lib => extensions}/code-editor/src/BaseEditor.tsx | 0 .../{lib => extensions}/code-editor/src/JsonEditor.tsx | 0 .../packages/{lib => extensions}/code-editor/src/LgEditor.tsx | 0 .../packages/{lib => extensions}/code-editor/src/LuEditor.tsx | 0 .../{lib => extensions}/code-editor/src/RichEditor.tsx | 0 .../packages/{lib => extensions}/code-editor/src/index.ts | 0 .../{lib => extensions}/code-editor/src/languages/index.ts | 0 .../{lib => extensions}/code-editor/src/languages/lg.ts | 0 .../{lib => extensions}/code-editor/src/utils/common.ts | 0 .../{lib => extensions}/code-editor/src/utils/index.ts | 0 .../{lib => extensions}/code-editor/src/utils/lspUtil.ts | 0 .../{lib => extensions}/code-editor/src/utils/obfuscate.ts | 0 .../{lib => extensions}/code-editor/tsconfig.build.json | 0 .../packages/{lib => extensions}/code-editor/tsconfig.json | 0 Composer/packages/extensions/package.json | 4 ++-- Composer/packages/lib/package.json | 4 +--- 32 files changed, 3 insertions(+), 5 deletions(-) rename Composer/packages/{lib => extensions}/code-editor/.eslintrc.js (100%) rename Composer/packages/{lib => extensions}/code-editor/.gitignore (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/.eslintrc.js (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/index.html (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/src/index.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/src/inlineEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/src/jsonEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/src/lgEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/src/lgJsonEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/src/luEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/src/multiEditors.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/src/richEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/tsconfig.json (100%) rename Composer/packages/{lib => extensions}/code-editor/demo/webpack.config.demo.js (100%) rename Composer/packages/{lib => extensions}/code-editor/jest.config.js (100%) rename Composer/packages/{lib => extensions}/code-editor/package.json (100%) rename Composer/packages/{lib => extensions}/code-editor/src/BaseEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/src/JsonEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/src/LgEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/src/LuEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/src/RichEditor.tsx (100%) rename Composer/packages/{lib => extensions}/code-editor/src/index.ts (100%) rename Composer/packages/{lib => extensions}/code-editor/src/languages/index.ts (100%) rename Composer/packages/{lib => extensions}/code-editor/src/languages/lg.ts (100%) rename Composer/packages/{lib => extensions}/code-editor/src/utils/common.ts (100%) rename Composer/packages/{lib => extensions}/code-editor/src/utils/index.ts (100%) rename Composer/packages/{lib => extensions}/code-editor/src/utils/lspUtil.ts (100%) rename Composer/packages/{lib => extensions}/code-editor/src/utils/obfuscate.ts (100%) rename Composer/packages/{lib => extensions}/code-editor/tsconfig.build.json (100%) rename Composer/packages/{lib => extensions}/code-editor/tsconfig.json (100%) diff --git a/Composer/packages/lib/code-editor/.eslintrc.js b/Composer/packages/extensions/code-editor/.eslintrc.js similarity index 100% rename from Composer/packages/lib/code-editor/.eslintrc.js rename to Composer/packages/extensions/code-editor/.eslintrc.js diff --git a/Composer/packages/lib/code-editor/.gitignore b/Composer/packages/extensions/code-editor/.gitignore similarity index 100% rename from Composer/packages/lib/code-editor/.gitignore rename to Composer/packages/extensions/code-editor/.gitignore diff --git a/Composer/packages/lib/code-editor/demo/.eslintrc.js b/Composer/packages/extensions/code-editor/demo/.eslintrc.js similarity index 100% rename from Composer/packages/lib/code-editor/demo/.eslintrc.js rename to Composer/packages/extensions/code-editor/demo/.eslintrc.js diff --git a/Composer/packages/lib/code-editor/demo/index.html b/Composer/packages/extensions/code-editor/demo/index.html similarity index 100% rename from Composer/packages/lib/code-editor/demo/index.html rename to Composer/packages/extensions/code-editor/demo/index.html diff --git a/Composer/packages/lib/code-editor/demo/src/index.tsx b/Composer/packages/extensions/code-editor/demo/src/index.tsx similarity index 100% rename from Composer/packages/lib/code-editor/demo/src/index.tsx rename to Composer/packages/extensions/code-editor/demo/src/index.tsx diff --git a/Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx b/Composer/packages/extensions/code-editor/demo/src/inlineEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx rename to Composer/packages/extensions/code-editor/demo/src/inlineEditor.tsx diff --git a/Composer/packages/lib/code-editor/demo/src/jsonEditor.tsx b/Composer/packages/extensions/code-editor/demo/src/jsonEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/demo/src/jsonEditor.tsx rename to Composer/packages/extensions/code-editor/demo/src/jsonEditor.tsx diff --git a/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx b/Composer/packages/extensions/code-editor/demo/src/lgEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/demo/src/lgEditor.tsx rename to Composer/packages/extensions/code-editor/demo/src/lgEditor.tsx diff --git a/Composer/packages/lib/code-editor/demo/src/lgJsonEditor.tsx b/Composer/packages/extensions/code-editor/demo/src/lgJsonEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/demo/src/lgJsonEditor.tsx rename to Composer/packages/extensions/code-editor/demo/src/lgJsonEditor.tsx diff --git a/Composer/packages/lib/code-editor/demo/src/luEditor.tsx b/Composer/packages/extensions/code-editor/demo/src/luEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/demo/src/luEditor.tsx rename to Composer/packages/extensions/code-editor/demo/src/luEditor.tsx diff --git a/Composer/packages/lib/code-editor/demo/src/multiEditors.tsx b/Composer/packages/extensions/code-editor/demo/src/multiEditors.tsx similarity index 100% rename from Composer/packages/lib/code-editor/demo/src/multiEditors.tsx rename to Composer/packages/extensions/code-editor/demo/src/multiEditors.tsx diff --git a/Composer/packages/lib/code-editor/demo/src/richEditor.tsx b/Composer/packages/extensions/code-editor/demo/src/richEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/demo/src/richEditor.tsx rename to Composer/packages/extensions/code-editor/demo/src/richEditor.tsx diff --git a/Composer/packages/lib/code-editor/demo/tsconfig.json b/Composer/packages/extensions/code-editor/demo/tsconfig.json similarity index 100% rename from Composer/packages/lib/code-editor/demo/tsconfig.json rename to Composer/packages/extensions/code-editor/demo/tsconfig.json diff --git a/Composer/packages/lib/code-editor/demo/webpack.config.demo.js b/Composer/packages/extensions/code-editor/demo/webpack.config.demo.js similarity index 100% rename from Composer/packages/lib/code-editor/demo/webpack.config.demo.js rename to Composer/packages/extensions/code-editor/demo/webpack.config.demo.js diff --git a/Composer/packages/lib/code-editor/jest.config.js b/Composer/packages/extensions/code-editor/jest.config.js similarity index 100% rename from Composer/packages/lib/code-editor/jest.config.js rename to Composer/packages/extensions/code-editor/jest.config.js diff --git a/Composer/packages/lib/code-editor/package.json b/Composer/packages/extensions/code-editor/package.json similarity index 100% rename from Composer/packages/lib/code-editor/package.json rename to Composer/packages/extensions/code-editor/package.json diff --git a/Composer/packages/lib/code-editor/src/BaseEditor.tsx b/Composer/packages/extensions/code-editor/src/BaseEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/src/BaseEditor.tsx rename to Composer/packages/extensions/code-editor/src/BaseEditor.tsx diff --git a/Composer/packages/lib/code-editor/src/JsonEditor.tsx b/Composer/packages/extensions/code-editor/src/JsonEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/src/JsonEditor.tsx rename to Composer/packages/extensions/code-editor/src/JsonEditor.tsx diff --git a/Composer/packages/lib/code-editor/src/LgEditor.tsx b/Composer/packages/extensions/code-editor/src/LgEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/src/LgEditor.tsx rename to Composer/packages/extensions/code-editor/src/LgEditor.tsx diff --git a/Composer/packages/lib/code-editor/src/LuEditor.tsx b/Composer/packages/extensions/code-editor/src/LuEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/src/LuEditor.tsx rename to Composer/packages/extensions/code-editor/src/LuEditor.tsx diff --git a/Composer/packages/lib/code-editor/src/RichEditor.tsx b/Composer/packages/extensions/code-editor/src/RichEditor.tsx similarity index 100% rename from Composer/packages/lib/code-editor/src/RichEditor.tsx rename to Composer/packages/extensions/code-editor/src/RichEditor.tsx diff --git a/Composer/packages/lib/code-editor/src/index.ts b/Composer/packages/extensions/code-editor/src/index.ts similarity index 100% rename from Composer/packages/lib/code-editor/src/index.ts rename to Composer/packages/extensions/code-editor/src/index.ts diff --git a/Composer/packages/lib/code-editor/src/languages/index.ts b/Composer/packages/extensions/code-editor/src/languages/index.ts similarity index 100% rename from Composer/packages/lib/code-editor/src/languages/index.ts rename to Composer/packages/extensions/code-editor/src/languages/index.ts diff --git a/Composer/packages/lib/code-editor/src/languages/lg.ts b/Composer/packages/extensions/code-editor/src/languages/lg.ts similarity index 100% rename from Composer/packages/lib/code-editor/src/languages/lg.ts rename to Composer/packages/extensions/code-editor/src/languages/lg.ts diff --git a/Composer/packages/lib/code-editor/src/utils/common.ts b/Composer/packages/extensions/code-editor/src/utils/common.ts similarity index 100% rename from Composer/packages/lib/code-editor/src/utils/common.ts rename to Composer/packages/extensions/code-editor/src/utils/common.ts diff --git a/Composer/packages/lib/code-editor/src/utils/index.ts b/Composer/packages/extensions/code-editor/src/utils/index.ts similarity index 100% rename from Composer/packages/lib/code-editor/src/utils/index.ts rename to Composer/packages/extensions/code-editor/src/utils/index.ts diff --git a/Composer/packages/lib/code-editor/src/utils/lspUtil.ts b/Composer/packages/extensions/code-editor/src/utils/lspUtil.ts similarity index 100% rename from Composer/packages/lib/code-editor/src/utils/lspUtil.ts rename to Composer/packages/extensions/code-editor/src/utils/lspUtil.ts diff --git a/Composer/packages/lib/code-editor/src/utils/obfuscate.ts b/Composer/packages/extensions/code-editor/src/utils/obfuscate.ts similarity index 100% rename from Composer/packages/lib/code-editor/src/utils/obfuscate.ts rename to Composer/packages/extensions/code-editor/src/utils/obfuscate.ts diff --git a/Composer/packages/lib/code-editor/tsconfig.build.json b/Composer/packages/extensions/code-editor/tsconfig.build.json similarity index 100% rename from Composer/packages/lib/code-editor/tsconfig.build.json rename to Composer/packages/extensions/code-editor/tsconfig.build.json diff --git a/Composer/packages/lib/code-editor/tsconfig.json b/Composer/packages/extensions/code-editor/tsconfig.json similarity index 100% rename from Composer/packages/lib/code-editor/tsconfig.json rename to Composer/packages/extensions/code-editor/tsconfig.json diff --git a/Composer/packages/extensions/package.json b/Composer/packages/extensions/package.json index 4e1381c5f2..1966406b1c 100644 --- a/Composer/packages/extensions/package.json +++ b/Composer/packages/extensions/package.json @@ -1,6 +1,5 @@ { "name": "@bfc/extensions", - "license": "MIT", "version": "1.0.0", "description": "", "main": "index.js", @@ -10,7 +9,8 @@ "scripts": { "build:visual-designer": "cd visual-designer && yarn build", "build:obiformeditor": "cd obiformeditor && yarn build", - "build:all": "concurrently --kill-others-on-fail \"yarn:build:obiformeditor\" \"yarn:build:visual-designer\"" + "build:code-editor": "cd code-editor && yarn build", + "build:all": "yarn build:code-editor && concurrently --kill-others-on-fail \"yarn:build:obiformeditor\" \"yarn:build:visual-designer\"" }, "author": "", "license": "ISC" diff --git a/Composer/packages/lib/package.json b/Composer/packages/lib/package.json index 39bb9da15f..9a95164c51 100644 --- a/Composer/packages/lib/package.json +++ b/Composer/packages/lib/package.json @@ -1,6 +1,5 @@ { "name": "@bfc/libs", - "license": "MIT", "version": "1.0.0", "description": "", "main": "index.js", @@ -8,10 +7,9 @@ "node": ">=12" }, "scripts": { - "build:code-editor": "cd code-editor && yarn build", "build:shared": "cd shared && yarn build", "build:indexers": "cd indexers && yarn build", - "build:all": "yarn build:indexers && yarn build:shared && yarn build:code-editor" + "build:all": "yarn build:indexers && yarn build:shared" }, "author": "", "license": "ISC" From b58726e5d521a4a5ef6210119e842ecaacd34227 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Tue, 24 Dec 2019 16:12:54 +0800 Subject: [PATCH 10/17] update build sequence --- Composer/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Composer/package.json b/Composer/package.json index 58cde06e03..dce8d3039a 100644 --- a/Composer/package.json +++ b/Composer/package.json @@ -22,7 +22,7 @@ "scripts": { "build": "node scripts/update.js && node scripts/begin.js && yarn build:prod", "build:prod": "yarn build:dev && yarn build:server && yarn build:client", - "build:dev": "yarn build:tools && yarn build:lib && yarn build:extensions", + "build:dev": "yarn build:lib && yarn build:tools && yarn build:extensions", "build:lib": "yarn workspace @bfc/libs build:all", "build:extensions": "yarn workspace @bfc/extensions build:all", "build:server": "yarn workspace @bfc/server build", From 3a750debfddb496ed303a4fad7619f44a4b38351 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Tue, 24 Dec 2019 16:35:29 +0800 Subject: [PATCH 11/17] update path --- Composer/jest.config.js | 5 ++++- Composer/packages/extensions/code-editor/package.json | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Composer/jest.config.js b/Composer/jest.config.js index da2165fe69..28be088dbe 100644 --- a/Composer/jest.config.js +++ b/Composer/jest.config.js @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + module.exports = { collectCoverageFrom: [ '**/src/**/*.{js,jsx,ts,tsx}', @@ -39,7 +42,7 @@ module.exports = { '/packages/server', '/packages/extensions/obiformeditor', '/packages/extensions/visual-designer', - '/packages/lib/code-editor', + '/packages/extensions/code-editor', '/packages/lib/shared', '/packages/tools/language-servers/language-generation', ], diff --git a/Composer/packages/extensions/code-editor/package.json b/Composer/packages/extensions/code-editor/package.json index 23f928d16c..8e242b1169 100644 --- a/Composer/packages/extensions/code-editor/package.json +++ b/Composer/packages/extensions/code-editor/package.json @@ -1,6 +1,5 @@ { "name": "@bfc/code-editor", - "license": "MIT", "version": "0.0.0", "description": "Code editor component that is shared in composer packages", "main": "lib/index.js", From aafd467630284b881d45b549743df8b561bd30ae Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Tue, 24 Dec 2019 18:31:21 +0800 Subject: [PATCH 12/17] precise suggestion --- .../language-generation/src/LGServer.ts | 76 +++++++++---------- .../language-generation/src/utils.ts | 13 ++++ 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index 5c6a1e0bda..48cc1d5baf 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -30,6 +30,7 @@ import { generageDiagnostic, LGOption, parse, + LGCursorState, } from './utils'; const { check } = lgIndexer; @@ -37,7 +38,7 @@ const { check } = lgIndexer; // define init methods call from client const InitializeDocumentsMethodName = 'initializeDocuments'; -const allowedCompletionStates = ['expression']; +const { ROOT, TEMPLATENAME, TEMPLATEBODY, EXPRESSION, COMMENTS, SINGLE, DOUBLE } = LGCursorState; export class LGServer { protected workspaceRoot?: URI; @@ -243,58 +244,66 @@ export class LGServer { return resultArr.join(' ,'); } - private matchedStates(params: TextDocumentPositionParams): { matched: boolean; state: string } | null { - const state: string[] = []; + private matchState(params: TextDocumentPositionParams): LGCursorState | undefined { + const state: LGCursorState[] = []; const document = this.documents.get(params.textDocument.uri); - if (!document) return null; + if (!document) return; const position = params.position; const range = Range.create(position.line, 0, position.line, position.character); const lineContent = document.getText(range); - if (!lineContent.trim().startsWith('-')) { - return { matched: false, state: '' }; - } //initialize the root state to plaintext - state.push('PlainText'); + state.push(ROOT); + if (lineContent.trim().startsWith('#')) { + return TEMPLATENAME; + } else if (lineContent.trim().startsWith('>')) { + return COMMENTS; + } else if (lineContent.trim().startsWith('-')) { + state.push(TEMPLATEBODY); + } else { + return ROOT; + } // find out the context state of current cursor, offer precise suggestion and completion etc. /** + * > To learn more about the LG file format... --- COMMENTS + * # Greeting --- TEMPLATENAME + * - Hello --- TEMPLATEBODY * - Hi, @{name}, what's the meaning of 'state' - * - Hi---------, @{name}--------, what-------' ------s the meaning of "state" - * - , @{<expression>}, <plaintext><single><plaintext>------<double> + * | + * +------------------------------------------- EXPRESSION */ let i = 0; while (i < lineContent.length) { const char = lineContent.charAt(i); if (char === `'`) { - if (state[state.length - 1] === 'expression' || state[state.length - 1] === 'double') { - state.push('single'); + if (state[state.length - 1] === EXPRESSION || state[state.length - 1] === DOUBLE) { + state.push(SINGLE); } else { state.pop(); } } if (char === `"`) { - if (state[state.length - 1] === 'expression' || state[state.length - 1] === 'single') { - state.push('double'); + if (state[state.length - 1] === EXPRESSION || state[state.length - 1] === SINGLE) { + state.push(DOUBLE); } else { state.pop(); } } - if (char === '{' && i >= 1 && state[state.length - 1] !== 'single' && state[state.length - 1] !== 'double') { + if (char === '{' && i >= 1 && state[state.length - 1] !== SINGLE && state[state.length - 1] !== DOUBLE) { if (lineContent.charAt(i - 1) === '@') { - state.push('expression'); + state.push(EXPRESSION); } } - if (char === '}' && state[state.length - 1] === 'expression') { + if (char === '}' && state[state.length - 1] === EXPRESSION) { state.pop(); } i++; } - const finalState = state[state.length - 1]; - return { matched: true, state: finalState }; + return state.pop(); } protected completion(params: TextDocumentPositionParams): Thenable<CompletionList | null> { @@ -303,18 +312,7 @@ export class LGServer { return Promise.resolve(null); } const text = this.getLGDocumentContent(document); - - const diags = check(text, ''); - - if (isValid(diags) === false) { - return Promise.resolve(null); - } - - const { templates, diagnostics } = parse(text, document); - if (diagnostics.length) { - this.sendDiagnostics(document, diagnostics); - return Promise.resolve(null); - } + const { templates } = parse(text, document); const completionTemplateList: CompletionItem[] = templates.map(template => { return { @@ -336,17 +334,11 @@ export class LGServer { }; }); - const completionList = completionTemplateList.concat(completionFunctionList); - - const matchResult = this.matchedStates(params); - // TODO: more precise match - if ( - matchResult && - matchResult.matched && - matchResult.state && - allowedCompletionStates.includes(matchResult.state.toLowerCase()) - ) { - return Promise.resolve({ isIncomplete: true, items: completionList }); + const matchedState = this.matchState(params); + if (matchedState === EXPRESSION) { + return Promise.resolve({ isIncomplete: true, items: completionTemplateList.concat(completionFunctionList) }); + } else if (matchedState === TEMPLATEBODY) { + return Promise.resolve({ isIncomplete: true, items: completionFunctionList }); } else { return Promise.resolve(null); } diff --git a/Composer/packages/tools/language-servers/language-generation/src/utils.ts b/Composer/packages/tools/language-servers/language-generation/src/utils.ts index 41f72f8c56..d6a53cc8f5 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/utils.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/utils.ts @@ -15,6 +15,19 @@ import { CodeRange, LgTemplate, lgIndexer, Diagnostic as BFDiagnostic, offsetRan const staticChecker = new StaticChecker(); +// state should map to tokenizer state +export enum LGCursorState { + ROOT = 'root', + TEMPLATENAME = 'template_name', + TEMPLATEBODY = 'template_body', + COMMENTS = 'comments', + FENCEBLOCK = 'fence_block', + EXPRESSION = 'expression', + STRUCTURELG = 'structure_lg', + SINGLE = 'single', + DOUBLE = 'double', +} + export interface LGOption { fileId: string; templateId: string; From a315f44f917db30cd3e31150940b950573e08e0a Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Thu, 26 Dec 2019 13:50:30 +0800 Subject: [PATCH 13/17] better suggestion --- .../extensions/code-editor/src/LgEditor.tsx | 1 + .../code-editor/src/languages/lg.ts | 66 +++++++++++++++++++ .../language-generation/src/LGServer.ts | 2 - 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/Composer/packages/extensions/code-editor/src/LgEditor.tsx b/Composer/packages/extensions/code-editor/src/LgEditor.tsx index 98c7f60d04..4d641d862a 100644 --- a/Composer/packages/extensions/code-editor/src/LgEditor.tsx +++ b/Composer/packages/extensions/code-editor/src/LgEditor.tsx @@ -55,6 +55,7 @@ async function initializeDocuments(lgOption: LGOption | undefined, uri: string) export function LgEditor(props: LGLSPEditorProps) { const options = { quickSuggestions: true, + wordBasedSuggestions: false, ...props.options, }; diff --git a/Composer/packages/extensions/code-editor/src/languages/lg.ts b/Composer/packages/extensions/code-editor/src/languages/lg.ts index b63c8e1ce1..d57c29d4c0 100644 --- a/Composer/packages/extensions/code-editor/src/languages/lg.ts +++ b/Composer/packages/extensions/code-editor/src/languages/lg.ts @@ -4,6 +4,46 @@ import * as monacoEditor from '@bfcomposer/monaco-editor/esm/vs/editor/editor.api'; +function createKeywordsProposals(range) { + // returning a static list of proposals, not even looking at the prefix (filtering is done by the Monaco editor), + // here you could do a server side lookup + return [ + { + label: 'IF', + kind: monaco.languages.CompletionItemKind.Keyword, + insertText: `IF: @{} +- +- ELSEIF: @{} + - +- ELSE: + - `, + range: range, + }, + { + label: 'ELSEIF', + kind: monaco.languages.CompletionItemKind.Keyword, + insertText: 'ELSEIF:@{}', + range: range, + }, + { + label: 'ELSE', + kind: monaco.languages.CompletionItemKind.Keyword, + insertText: 'ELSE:\n', + range: range, + }, + { + label: 'SWITCH', + kind: monaco.languages.CompletionItemKind.Keyword, + insertText: `SWITCH: @{} +- CASE: @{} + - +- DEFAULT: + - `, + range: range, + }, + ]; +} + export function registerLGLanguage(monaco: typeof monacoEditor) { monaco.languages.setMonarchTokensProvider('botbuilderlg', { ignoreCase: true, @@ -112,4 +152,30 @@ export function registerLGLanguage(monaco: typeof monacoEditor) { { token: 'structure-name', foreground: '00B7C3' }, ], }); + + monaco.languages.registerCompletionItemProvider('botbuilderlg', { + provideCompletionItems: function(model, position) { + const lineText = model.getValueInRange({ + startLineNumber: position.lineNumber, + startColumn: 1, + endLineNumber: position.lineNumber, + endColumn: position.column, + }); + // keywords only be allowed in line start. + if (/\s*-\s*\w*$/.test(lineText) === false) { + return { suggestions: [] }; + } + + const word = model.getWordUntilPosition(position); + const range = { + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + startColumn: word.startColumn, + endColumn: word.endColumn, + }; + return { + suggestions: createKeywordsProposals(range), + }; + }, + }); } diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index 48cc1d5baf..89218b3fb1 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -337,8 +337,6 @@ export class LGServer { const matchedState = this.matchState(params); if (matchedState === EXPRESSION) { return Promise.resolve({ isIncomplete: true, items: completionTemplateList.concat(completionFunctionList) }); - } else if (matchedState === TEMPLATEBODY) { - return Promise.resolve({ isIncomplete: true, items: completionFunctionList }); } else { return Promise.resolve(null); } From 722df2b3fe77cf84a3678c1af454ad7d699e3d42 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Thu, 26 Dec 2019 14:54:56 +0800 Subject: [PATCH 14/17] move code-editor to lib/ --- Composer/jest.config.js | 2 +- Composer/packages/extensions/package.json | 3 +-- Composer/packages/{extensions => lib}/code-editor/.eslintrc.js | 0 Composer/packages/{extensions => lib}/code-editor/.gitignore | 0 .../packages/{extensions => lib}/code-editor/demo/.eslintrc.js | 0 .../packages/{extensions => lib}/code-editor/demo/index.html | 0 .../{extensions => lib}/code-editor/demo/src/index.tsx | 0 .../{extensions => lib}/code-editor/demo/src/inlineEditor.tsx | 0 .../{extensions => lib}/code-editor/demo/src/jsonEditor.tsx | 0 .../{extensions => lib}/code-editor/demo/src/lgEditor.tsx | 0 .../{extensions => lib}/code-editor/demo/src/lgJsonEditor.tsx | 0 .../{extensions => lib}/code-editor/demo/src/luEditor.tsx | 0 .../{extensions => lib}/code-editor/demo/src/multiEditors.tsx | 0 .../{extensions => lib}/code-editor/demo/src/richEditor.tsx | 0 .../{extensions => lib}/code-editor/demo/tsconfig.json | 0 .../code-editor/demo/webpack.config.demo.js | 0 .../packages/{extensions => lib}/code-editor/jest.config.js | 0 Composer/packages/{extensions => lib}/code-editor/package.json | 0 .../{extensions => lib}/code-editor/src/BaseEditor.tsx | 0 .../{extensions => lib}/code-editor/src/JsonEditor.tsx | 0 .../packages/{extensions => lib}/code-editor/src/LgEditor.tsx | 0 .../packages/{extensions => lib}/code-editor/src/LuEditor.tsx | 0 .../{extensions => lib}/code-editor/src/RichEditor.tsx | 0 Composer/packages/{extensions => lib}/code-editor/src/index.ts | 0 .../{extensions => lib}/code-editor/src/languages/index.ts | 0 .../{extensions => lib}/code-editor/src/languages/lg.ts | 0 .../{extensions => lib}/code-editor/src/utils/common.ts | 0 .../{extensions => lib}/code-editor/src/utils/index.ts | 0 .../{extensions => lib}/code-editor/src/utils/lspUtil.ts | 0 .../{extensions => lib}/code-editor/src/utils/obfuscate.ts | 0 .../{extensions => lib}/code-editor/tsconfig.build.json | 0 .../packages/{extensions => lib}/code-editor/tsconfig.json | 0 Composer/packages/lib/package.json | 3 ++- 33 files changed, 4 insertions(+), 4 deletions(-) rename Composer/packages/{extensions => lib}/code-editor/.eslintrc.js (100%) rename Composer/packages/{extensions => lib}/code-editor/.gitignore (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/.eslintrc.js (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/index.html (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/src/index.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/src/inlineEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/src/jsonEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/src/lgEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/src/lgJsonEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/src/luEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/src/multiEditors.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/src/richEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/tsconfig.json (100%) rename Composer/packages/{extensions => lib}/code-editor/demo/webpack.config.demo.js (100%) rename Composer/packages/{extensions => lib}/code-editor/jest.config.js (100%) rename Composer/packages/{extensions => lib}/code-editor/package.json (100%) rename Composer/packages/{extensions => lib}/code-editor/src/BaseEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/src/JsonEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/src/LgEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/src/LuEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/src/RichEditor.tsx (100%) rename Composer/packages/{extensions => lib}/code-editor/src/index.ts (100%) rename Composer/packages/{extensions => lib}/code-editor/src/languages/index.ts (100%) rename Composer/packages/{extensions => lib}/code-editor/src/languages/lg.ts (100%) rename Composer/packages/{extensions => lib}/code-editor/src/utils/common.ts (100%) rename Composer/packages/{extensions => lib}/code-editor/src/utils/index.ts (100%) rename Composer/packages/{extensions => lib}/code-editor/src/utils/lspUtil.ts (100%) rename Composer/packages/{extensions => lib}/code-editor/src/utils/obfuscate.ts (100%) rename Composer/packages/{extensions => lib}/code-editor/tsconfig.build.json (100%) rename Composer/packages/{extensions => lib}/code-editor/tsconfig.json (100%) diff --git a/Composer/jest.config.js b/Composer/jest.config.js index 28be088dbe..3acf2967a6 100644 --- a/Composer/jest.config.js +++ b/Composer/jest.config.js @@ -42,7 +42,7 @@ module.exports = { '<rootDir>/packages/server', '<rootDir>/packages/extensions/obiformeditor', '<rootDir>/packages/extensions/visual-designer', - '<rootDir>/packages/extensions/code-editor', + '<rootDir>/packages/lib/code-editor', '<rootDir>/packages/lib/shared', '<rootDir>/packages/tools/language-servers/language-generation', ], diff --git a/Composer/packages/extensions/package.json b/Composer/packages/extensions/package.json index 1966406b1c..3049abd6eb 100644 --- a/Composer/packages/extensions/package.json +++ b/Composer/packages/extensions/package.json @@ -9,8 +9,7 @@ "scripts": { "build:visual-designer": "cd visual-designer && yarn build", "build:obiformeditor": "cd obiformeditor && yarn build", - "build:code-editor": "cd code-editor && yarn build", - "build:all": "yarn build:code-editor && concurrently --kill-others-on-fail \"yarn:build:obiformeditor\" \"yarn:build:visual-designer\"" + "build:all": "concurrently --kill-others-on-fail \"yarn:build:obiformeditor\" \"yarn:build:visual-designer\"" }, "author": "", "license": "ISC" diff --git a/Composer/packages/extensions/code-editor/.eslintrc.js b/Composer/packages/lib/code-editor/.eslintrc.js similarity index 100% rename from Composer/packages/extensions/code-editor/.eslintrc.js rename to Composer/packages/lib/code-editor/.eslintrc.js diff --git a/Composer/packages/extensions/code-editor/.gitignore b/Composer/packages/lib/code-editor/.gitignore similarity index 100% rename from Composer/packages/extensions/code-editor/.gitignore rename to Composer/packages/lib/code-editor/.gitignore diff --git a/Composer/packages/extensions/code-editor/demo/.eslintrc.js b/Composer/packages/lib/code-editor/demo/.eslintrc.js similarity index 100% rename from Composer/packages/extensions/code-editor/demo/.eslintrc.js rename to Composer/packages/lib/code-editor/demo/.eslintrc.js diff --git a/Composer/packages/extensions/code-editor/demo/index.html b/Composer/packages/lib/code-editor/demo/index.html similarity index 100% rename from Composer/packages/extensions/code-editor/demo/index.html rename to Composer/packages/lib/code-editor/demo/index.html diff --git a/Composer/packages/extensions/code-editor/demo/src/index.tsx b/Composer/packages/lib/code-editor/demo/src/index.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/demo/src/index.tsx rename to Composer/packages/lib/code-editor/demo/src/index.tsx diff --git a/Composer/packages/extensions/code-editor/demo/src/inlineEditor.tsx b/Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/demo/src/inlineEditor.tsx rename to Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx diff --git a/Composer/packages/extensions/code-editor/demo/src/jsonEditor.tsx b/Composer/packages/lib/code-editor/demo/src/jsonEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/demo/src/jsonEditor.tsx rename to Composer/packages/lib/code-editor/demo/src/jsonEditor.tsx diff --git a/Composer/packages/extensions/code-editor/demo/src/lgEditor.tsx b/Composer/packages/lib/code-editor/demo/src/lgEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/demo/src/lgEditor.tsx rename to Composer/packages/lib/code-editor/demo/src/lgEditor.tsx diff --git a/Composer/packages/extensions/code-editor/demo/src/lgJsonEditor.tsx b/Composer/packages/lib/code-editor/demo/src/lgJsonEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/demo/src/lgJsonEditor.tsx rename to Composer/packages/lib/code-editor/demo/src/lgJsonEditor.tsx diff --git a/Composer/packages/extensions/code-editor/demo/src/luEditor.tsx b/Composer/packages/lib/code-editor/demo/src/luEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/demo/src/luEditor.tsx rename to Composer/packages/lib/code-editor/demo/src/luEditor.tsx diff --git a/Composer/packages/extensions/code-editor/demo/src/multiEditors.tsx b/Composer/packages/lib/code-editor/demo/src/multiEditors.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/demo/src/multiEditors.tsx rename to Composer/packages/lib/code-editor/demo/src/multiEditors.tsx diff --git a/Composer/packages/extensions/code-editor/demo/src/richEditor.tsx b/Composer/packages/lib/code-editor/demo/src/richEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/demo/src/richEditor.tsx rename to Composer/packages/lib/code-editor/demo/src/richEditor.tsx diff --git a/Composer/packages/extensions/code-editor/demo/tsconfig.json b/Composer/packages/lib/code-editor/demo/tsconfig.json similarity index 100% rename from Composer/packages/extensions/code-editor/demo/tsconfig.json rename to Composer/packages/lib/code-editor/demo/tsconfig.json diff --git a/Composer/packages/extensions/code-editor/demo/webpack.config.demo.js b/Composer/packages/lib/code-editor/demo/webpack.config.demo.js similarity index 100% rename from Composer/packages/extensions/code-editor/demo/webpack.config.demo.js rename to Composer/packages/lib/code-editor/demo/webpack.config.demo.js diff --git a/Composer/packages/extensions/code-editor/jest.config.js b/Composer/packages/lib/code-editor/jest.config.js similarity index 100% rename from Composer/packages/extensions/code-editor/jest.config.js rename to Composer/packages/lib/code-editor/jest.config.js diff --git a/Composer/packages/extensions/code-editor/package.json b/Composer/packages/lib/code-editor/package.json similarity index 100% rename from Composer/packages/extensions/code-editor/package.json rename to Composer/packages/lib/code-editor/package.json diff --git a/Composer/packages/extensions/code-editor/src/BaseEditor.tsx b/Composer/packages/lib/code-editor/src/BaseEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/src/BaseEditor.tsx rename to Composer/packages/lib/code-editor/src/BaseEditor.tsx diff --git a/Composer/packages/extensions/code-editor/src/JsonEditor.tsx b/Composer/packages/lib/code-editor/src/JsonEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/src/JsonEditor.tsx rename to Composer/packages/lib/code-editor/src/JsonEditor.tsx diff --git a/Composer/packages/extensions/code-editor/src/LgEditor.tsx b/Composer/packages/lib/code-editor/src/LgEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/src/LgEditor.tsx rename to Composer/packages/lib/code-editor/src/LgEditor.tsx diff --git a/Composer/packages/extensions/code-editor/src/LuEditor.tsx b/Composer/packages/lib/code-editor/src/LuEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/src/LuEditor.tsx rename to Composer/packages/lib/code-editor/src/LuEditor.tsx diff --git a/Composer/packages/extensions/code-editor/src/RichEditor.tsx b/Composer/packages/lib/code-editor/src/RichEditor.tsx similarity index 100% rename from Composer/packages/extensions/code-editor/src/RichEditor.tsx rename to Composer/packages/lib/code-editor/src/RichEditor.tsx diff --git a/Composer/packages/extensions/code-editor/src/index.ts b/Composer/packages/lib/code-editor/src/index.ts similarity index 100% rename from Composer/packages/extensions/code-editor/src/index.ts rename to Composer/packages/lib/code-editor/src/index.ts diff --git a/Composer/packages/extensions/code-editor/src/languages/index.ts b/Composer/packages/lib/code-editor/src/languages/index.ts similarity index 100% rename from Composer/packages/extensions/code-editor/src/languages/index.ts rename to Composer/packages/lib/code-editor/src/languages/index.ts diff --git a/Composer/packages/extensions/code-editor/src/languages/lg.ts b/Composer/packages/lib/code-editor/src/languages/lg.ts similarity index 100% rename from Composer/packages/extensions/code-editor/src/languages/lg.ts rename to Composer/packages/lib/code-editor/src/languages/lg.ts diff --git a/Composer/packages/extensions/code-editor/src/utils/common.ts b/Composer/packages/lib/code-editor/src/utils/common.ts similarity index 100% rename from Composer/packages/extensions/code-editor/src/utils/common.ts rename to Composer/packages/lib/code-editor/src/utils/common.ts diff --git a/Composer/packages/extensions/code-editor/src/utils/index.ts b/Composer/packages/lib/code-editor/src/utils/index.ts similarity index 100% rename from Composer/packages/extensions/code-editor/src/utils/index.ts rename to Composer/packages/lib/code-editor/src/utils/index.ts diff --git a/Composer/packages/extensions/code-editor/src/utils/lspUtil.ts b/Composer/packages/lib/code-editor/src/utils/lspUtil.ts similarity index 100% rename from Composer/packages/extensions/code-editor/src/utils/lspUtil.ts rename to Composer/packages/lib/code-editor/src/utils/lspUtil.ts diff --git a/Composer/packages/extensions/code-editor/src/utils/obfuscate.ts b/Composer/packages/lib/code-editor/src/utils/obfuscate.ts similarity index 100% rename from Composer/packages/extensions/code-editor/src/utils/obfuscate.ts rename to Composer/packages/lib/code-editor/src/utils/obfuscate.ts diff --git a/Composer/packages/extensions/code-editor/tsconfig.build.json b/Composer/packages/lib/code-editor/tsconfig.build.json similarity index 100% rename from Composer/packages/extensions/code-editor/tsconfig.build.json rename to Composer/packages/lib/code-editor/tsconfig.build.json diff --git a/Composer/packages/extensions/code-editor/tsconfig.json b/Composer/packages/lib/code-editor/tsconfig.json similarity index 100% rename from Composer/packages/extensions/code-editor/tsconfig.json rename to Composer/packages/lib/code-editor/tsconfig.json diff --git a/Composer/packages/lib/package.json b/Composer/packages/lib/package.json index 9a95164c51..9f86a13046 100644 --- a/Composer/packages/lib/package.json +++ b/Composer/packages/lib/package.json @@ -7,9 +7,10 @@ "node": ">=12" }, "scripts": { + "build:code-editor": "cd code-editor && yarn build", "build:shared": "cd shared && yarn build", "build:indexers": "cd indexers && yarn build", - "build:all": "yarn build:indexers && yarn build:shared" + "build:all": "yarn build:indexers && yarn build:shared && yarn build:code-editor" }, "author": "", "license": "ISC" From 3a98785c1c35b97c12245cfc6c51a374386813c3 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Mon, 30 Dec 2019 17:26:20 +0800 Subject: [PATCH 15/17] use fileResolver instead of whole botService --- .../packages/lib/indexers/src/lgIndexer.ts | 29 ++++++++++++------- Composer/packages/lib/indexers/src/type.ts | 2 ++ Composer/packages/server/src/server.ts | 4 ++- .../packages/server/src/services/project.ts | 6 ++++ .../language-generation/src/LGServer.ts | 23 ++++++--------- 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/Composer/packages/lib/indexers/src/lgIndexer.ts b/Composer/packages/lib/indexers/src/lgIndexer.ts index e7df29bd84..54f3ff0107 100644 --- a/Composer/packages/lib/indexers/src/lgIndexer.ts +++ b/Composer/packages/lib/indexers/src/lgIndexer.ts @@ -50,21 +50,27 @@ function parse(content: string, id?: string): LgTemplate[] { return templates; } +function indexOne(file: FileInfo): LgFile | undefined { + const { name, relativePath, content } = file; + if (!name.endsWith('.lg')) return; + const id = getBaseName(name, '.lg'); + const diagnostics = check(content, id); + let templates: LgTemplate[] = []; + try { + templates = parse(file.content, ''); + } catch (err) { + diagnostics.push(new Diagnostic(err.message, id, DiagnosticSeverity.Error)); + } + return { id, relativePath, content, templates, diagnostics }; +} + function index(files: FileInfo[]): LgFile[] { if (files.length === 0) return []; const lgFiles: LgFile[] = []; for (const file of files) { - const { name, relativePath, content } = file; - if (name.endsWith('.lg')) { - const id = getBaseName(name, '.lg'); - const diagnostics = check(content, id); - let templates: LgTemplate[] = []; - try { - templates = parse(file.content, ''); - } catch (err) { - diagnostics.push(new Diagnostic(err.message, id, DiagnosticSeverity.Error)); - } - lgFiles.push({ id, relativePath, content, templates, diagnostics }); + const indexedFile = indexOne(file); + if (indexedFile) { + lgFiles.push(indexedFile); } } return lgFiles; @@ -74,4 +80,5 @@ export const lgIndexer = { index, parse, check, + indexOne, }; diff --git a/Composer/packages/lib/indexers/src/type.ts b/Composer/packages/lib/indexers/src/type.ts index 86c4883e97..cc053ee425 100644 --- a/Composer/packages/lib/indexers/src/type.ts +++ b/Composer/packages/lib/indexers/src/type.ts @@ -77,3 +77,5 @@ export interface LgFile { diagnostics: Diagnostic[]; templates: LgTemplate[]; } + +export type FileResolver = (id: string) => FileInfo | undefined; diff --git a/Composer/packages/server/src/server.ts b/Composer/packages/server/src/server.ts index f611152ec3..defec8b881 100644 --- a/Composer/packages/server/src/server.ts +++ b/Composer/packages/server/src/server.ts @@ -114,11 +114,13 @@ const wss: ws.Server = new ws.Server({ perMessageDeflate: false, }); +const { fileResolver } = BotProjectService; + function launchLanguageServer(socket: rpc.IWebSocket) { const reader = new rpc.WebSocketMessageReader(socket); const writer = new rpc.WebSocketMessageWriter(socket); const connection: IConnection = createConnection(reader, writer); - const server = new LGServer(connection, BotProjectService); + const server = new LGServer(connection, fileResolver); server.start(); } diff --git a/Composer/packages/server/src/services/project.ts b/Composer/packages/server/src/services/project.ts index fb58e5e822..c16cd676c9 100644 --- a/Composer/packages/server/src/services/project.ts +++ b/Composer/packages/server/src/services/project.ts @@ -3,6 +3,7 @@ import merge from 'lodash/merge'; import find from 'lodash/find'; +import { FileInfo } from '@bfc/indexers'; import { BotProject } from '../models/bot/botProject'; import { LocationRef } from '../models/bot/interface'; @@ -32,6 +33,11 @@ export class BotProjectService { } } + public static fileResolver(id: string): FileInfo | undefined { + BotProjectService.initialize(); + return BotProjectService.currentBotProject?.files.find(({ name }) => id === name); + } + public static getCurrentBotProject(): BotProject | undefined { BotProjectService.initialize(); return BotProjectService.currentBotProject; diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index 89218b3fb1..c01bcba17e 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -18,7 +18,7 @@ import { } from 'vscode-languageserver-types'; import { TextDocumentPositionParams } from 'vscode-languageserver-protocol'; import get from 'lodash/get'; -import { LgFile, LgTemplate, lgIndexer, filterTemplateDiagnostics, isValid } from '@bfc/indexers'; +import { LgFile, LgTemplate, lgIndexer, filterTemplateDiagnostics, isValid, FileResolver } from '@bfc/indexers'; import { buildInfunctionsMap } from './builtinFunctionsMap'; import { @@ -33,7 +33,7 @@ import { LGCursorState, } from './utils'; -const { check } = lgIndexer; +const { check, indexOne } = lgIndexer; // define init methods call from client const InitializeDocumentsMethodName = 'initializeDocuments'; @@ -44,14 +44,9 @@ export class LGServer { protected workspaceRoot?: URI; protected readonly documents = new TextDocuments(); protected readonly pendingValidationRequests = new Map<string, number>(); - /** - * LG documents infomation store. - * The connection between lgOption and botProjectService. - * Help do inline template editing and server resource passing. - */ protected LGDocuments: LGDocument[] = []; - constructor(protected readonly connection: IConnection, protected readonly botProjectService?) { + constructor(protected readonly connection: IConnection, protected readonly resolver?: FileResolver) { this.documents.listen(this.connection); this.documents.onDidChangeContent(change => this.validate(change.document)); this.documents.onDidClose(event => { @@ -98,8 +93,8 @@ export class LGServer { protected verifyLgOption(lgOption: LGOption, document: TextDocument) { const diagnostics: string[] = []; - if (!this.botProjectService) { - diagnostics.push('[Error lgOption] botProjectService is required but not exist.'); + if (!this.resolver) { + diagnostics.push('[Error lgOption] resolver is required but not exist.'); } else { const { fileId, templateId } = lgOption; const lgFile = this.getLGFile(fileId); @@ -130,10 +125,10 @@ export class LGServer { } protected getLGFile(fileId: string): LgFile | undefined { - const currentProject = this.botProjectService?.getCurrentBotProject(); - if (!currentProject) return; - const { lgFiles } = currentProject.getIndexes(); - return lgFiles.find(({ id }) => id === fileId); + if (!this.resolver) return; + const file = this.resolver(fileId); + if (!file) return; + return indexOne(file); } protected getLGTemplate(fileId: string, templateId: string): LgTemplate | undefined { From 1909bca37eb29715682ee997e4915b310c6d6316 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Tue, 31 Dec 2019 15:50:32 +0800 Subject: [PATCH 16/17] clean unused code --- .../language-generation/src/utils.ts | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/Composer/packages/tools/language-servers/language-generation/src/utils.ts b/Composer/packages/tools/language-servers/language-generation/src/utils.ts index d6a53cc8f5..001e74e4f3 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/utils.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/utils.ts @@ -3,15 +3,13 @@ import { TextDocument, Range, Position, DiagnosticSeverity, Diagnostic } from 'vscode-languageserver-types'; import { - LGResource, LGParser, DiagnosticSeverity as LGDiagnosticSeverity, ImportResolver, Diagnostic as LGDiagnostic, StaticChecker, } from 'botbuilder-lg'; -import get from 'lodash/get'; -import { CodeRange, LgTemplate, lgIndexer, Diagnostic as BFDiagnostic, offsetRange } from '@bfc/indexers'; +import { LgTemplate, lgIndexer, Diagnostic as BFDiagnostic, offsetRange } from '@bfc/indexers'; const staticChecker = new StaticChecker(); @@ -134,14 +132,6 @@ export function textFromTemplate(template: Template): string { return textBuilder.join(''); } -export function textFromTemplates(templates: Template[]): string { - return templates - .map(template => { - return textFromTemplate(template); - }) - .join('\n'); -} - export function checkTemplate(template: Template): LGDiagnostic[] { const text = textFromTemplate(template); return staticChecker.checkText(text, '', ImportResolver.fileResolver).filter(diagnostic => { @@ -150,19 +140,6 @@ export function checkTemplate(template: Template): LGDiagnostic[] { }); } -export function getLGResources(content: string): LGResource { - return LGParser.parse(content, ' '); -} - -export function getTemplateRange(content: string, { name, parameters = [], body }: Template): CodeRange { - const resource = LGParser.parse(content).updateTemplate(name, name, parameters, body); - const template = resource.templates.find(item => item.name === name); - return { - startLineNumber: get(template, 'parseTree.start.line', 0), - endLineNumber: get(template, 'parseTree.stop.line', 0), - }; -} - export function updateTemplateInContent(content: string, { name, parameters = [], body }: Template): string { const resource = LGParser.parse(content); return resource.updateTemplate(name, name, parameters, body).toString(); From 86740a6242f316ece3434746ada1a7ad0aaf6b36 Mon Sep 17 00:00:00 2001 From: zhixzhan <49866537+zhixzhan@users.noreply.github.com> Date: Thu, 2 Jan 2020 17:42:11 +0800 Subject: [PATCH 17/17] reform interface --- .../pages/language-generation/code-editor.tsx | 2 +- .../packages/server/src/services/project.ts | 4 +- .../language-generation/src/LGServer.ts | 155 ++++++++---------- .../language-generation/src/utils.ts | 27 +-- 4 files changed, 76 insertions(+), 112 deletions(-) diff --git a/Composer/packages/client/src/pages/language-generation/code-editor.tsx b/Composer/packages/client/src/pages/language-generation/code-editor.tsx index 918b7650af..c5f600bdbf 100644 --- a/Composer/packages/client/src/pages/language-generation/code-editor.tsx +++ b/Composer/packages/client/src/pages/language-generation/code-editor.tsx @@ -140,7 +140,7 @@ const CodeEditor: React.FC<CodeEditorProps> = props => { const lgOption = template ? { - fileId, + fileId: 'common', templateId: template?.name || '', } : undefined; diff --git a/Composer/packages/server/src/services/project.ts b/Composer/packages/server/src/services/project.ts index c16cd676c9..fe26dc5b28 100644 --- a/Composer/packages/server/src/services/project.ts +++ b/Composer/packages/server/src/services/project.ts @@ -33,9 +33,9 @@ export class BotProjectService { } } - public static fileResolver(id: string): FileInfo | undefined { + public static fileResolver(name: string): FileInfo | undefined { BotProjectService.initialize(); - return BotProjectService.currentBotProject?.files.find(({ name }) => id === name); + return BotProjectService.currentBotProject?.files.find(file => file.name === name); } public static getCurrentBotProject(): BotProject | undefined { diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts index c01bcba17e..4308de561e 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts @@ -18,18 +18,16 @@ import { } from 'vscode-languageserver-types'; import { TextDocumentPositionParams } from 'vscode-languageserver-protocol'; import get from 'lodash/get'; -import { LgFile, LgTemplate, lgIndexer, filterTemplateDiagnostics, isValid, FileResolver } from '@bfc/indexers'; +import { lgIndexer, filterTemplateDiagnostics, isValid, FileResolver, FileInfo } from '@bfc/indexers'; import { buildInfunctionsMap } from './builtinFunctionsMap'; import { getRangeAtPosition, - updateTemplateInContent, LGDocument, checkTemplate, convertDiagnostics, generageDiagnostic, LGOption, - parse, LGCursorState, } from './utils'; @@ -79,25 +77,30 @@ export class LGServer { this.connection.onRequest((method, params) => { if (InitializeDocumentsMethodName === method) { const { uri, lgOption }: { uri: string; lgOption?: LGOption } = params; - this.LGDocuments.push({ uri, lgOption }); - // run diagnostic const textDocument = this.documents.get(uri); if (textDocument) { - if (lgOption) this.verifyLgOption(lgOption, textDocument); + this.addLGDocument(textDocument, lgOption); + this.validateLgOption(textDocument, lgOption); this.validate(textDocument); } } }); } - protected verifyLgOption(lgOption: LGOption, document: TextDocument) { + start() { + this.connection.listen(); + } + + protected validateLgOption(document: TextDocument, lgOption?: LGOption) { + if (!lgOption) return; + const diagnostics: string[] = []; if (!this.resolver) { diagnostics.push('[Error lgOption] resolver is required but not exist.'); } else { const { fileId, templateId } = lgOption; - const lgFile = this.getLGFile(fileId); + const lgFile = this.getLGDocument(document)?.index(); if (!lgFile) { diagnostics.push(`[Error lgOption] File ${fileId}.lg do not exist`); } else { @@ -113,77 +116,54 @@ export class LGServer { ); } - start() { - this.connection.listen(); - } - - protected getLGOption(document: TextDocument): LGOption | undefined { - const LGDocument = this.LGDocuments.find(item => item.uri === document.uri); - if (!LGDocument || !LGDocument.lgOption) return; - const { lgOption } = LGDocument; - return lgOption; - } - - protected getLGFile(fileId: string): LgFile | undefined { - if (!this.resolver) return; - const file = this.resolver(fileId); - if (!file) return; - return indexOne(file); - } - - protected getLGTemplate(fileId: string, templateId: string): LgTemplate | undefined { - const lgFile = this.getLGFile(fileId); - if (!lgFile) return; - const { templates } = lgFile; - return templates.find(({ name }) => name === templateId); + protected addLGDocument(document: TextDocument, lgOption?: LGOption) { + const { uri } = document; + const { fileId, templateId } = lgOption || {}; + const index = () => { + let lgFile: FileInfo | undefined; + if (this.resolver && fileId) { + lgFile = this.resolver(`${fileId}.lg`); + if (!lgFile) { + this.sendDiagnostics(document, [ + generageDiagnostic(`lg file: ${fileId}.lg not exist on server`, DiagnosticSeverity.Error, document), + ]); + return; + } + } else { + lgFile = { + name: `${uri}.lg`, + path: '/', + relativePath: './', + content: document.getText(), + }; + } + return indexOne(lgFile); + }; + const lgDocument: LGDocument = { + uri, + fileId, + templateId, + index, + }; + this.LGDocuments.push(lgDocument); } protected getLGDocument(document: TextDocument): LGDocument | undefined { return this.LGDocuments.find(({ uri }) => uri === document.uri); } - /** - * - * @param document - * 1. if !botProjectService, return text; - * 2. if botProjectService && !lgOption, return text; - * 3. if botProjectService - */ - protected getLGDocumentContent(document: TextDocument): string { - const text = document.getText(); - const lgOption = this.getLGOption(document); - if (!lgOption) return text; - - const { fileId, templateId } = lgOption; - const lgFile = this.getLGFile(fileId); - if (!lgFile) return text; - const { content } = lgFile; - - const template = this.getLGTemplate(fileId, templateId); - if (!template) return content; - - const updatedTemplate = { - name: template.name, - parameters: template.parameters, - body: text, - }; - - const templateDiags = checkTemplate(updatedTemplate); - if (isValid(templateDiags)) { - return updateTemplateInContent(content, updatedTemplate); - } - return content; - } - protected hover(params: TextDocumentPositionParams): Thenable<Hover | null> { const document = this.documents.get(params.textDocument.uri); if (!document) { return Promise.resolve(null); } - const text = this.getLGDocumentContent(document); - const { templates, diagnostics } = parse(text, document); + const lgFile = this.getLGDocument(document)?.index(); + if (!lgFile) { + return Promise.resolve(null); + } + const { templates, diagnostics } = lgFile; if (diagnostics.length) { - this.sendDiagnostics(document, diagnostics); + this.sendDiagnostics(document, convertDiagnostics(diagnostics, document)); return Promise.resolve(null); } const wordRange = getRangeAtPosition(document, params.position); @@ -306,8 +286,11 @@ export class LGServer { if (!document) { return Promise.resolve(null); } - const text = this.getLGDocumentContent(document); - const { templates } = parse(text, document); + const lgFile = this.getLGDocument(document)?.index(); + if (!lgFile) { + return Promise.resolve(null); + } + const { templates } = lgFile; const completionTemplateList: CompletionItem[] = templates.map(template => { return { @@ -358,10 +341,13 @@ export class LGServer { protected doValidate(document: TextDocument): void { const text = document.getText(); - const LGDocument = this.getLGDocument(document); - - // uninitialized - if (!LGDocument) { + const lgDoc = this.getLGDocument(document); + if (!lgDoc) { + return; + } + const { fileId, templateId } = lgDoc; + const lgFile = lgDoc.index(); + if (!lgFile) { return; } @@ -370,10 +356,10 @@ export class LGServer { return; } + const { templates, diagnostics } = lgFile; + // if inline editor, concat new content for validate - const { lgOption } = LGDocument; - if (lgOption) { - const { templateId, fileId } = lgOption; + if (fileId && templateId) { const templateDiags = checkTemplate({ name: templateId, parameters: [], @@ -381,25 +367,22 @@ export class LGServer { }); // error in template. if (isValid(templateDiags) === false) { - const diagnostics = convertDiagnostics(templateDiags, document, 1); - this.sendDiagnostics(document, diagnostics); + const lspDiagnostics = convertDiagnostics(templateDiags, document, 1); + this.sendDiagnostics(document, lspDiagnostics); return; } - - const fullText = this.getLGDocumentContent(document); - const { templates } = parse(text, document); const template = templates.find(({ name }) => name === templateId); if (!template) return; // filter diagnostics belong to this template. - const lgDiagnostics = filterTemplateDiagnostics(check(fullText, fileId), template); - const diagnostics = convertDiagnostics(lgDiagnostics, document, 1); - this.sendDiagnostics(document, diagnostics); + const lgDiagnostics = filterTemplateDiagnostics(diagnostics, template); + const lspDiagnostics = convertDiagnostics(lgDiagnostics, document, 1); + this.sendDiagnostics(document, lspDiagnostics); return; } const lgDiagnostics = check(text, ''); - const diagnostics = convertDiagnostics(lgDiagnostics, document); - this.sendDiagnostics(document, diagnostics); + const lspDiagnostics = convertDiagnostics(lgDiagnostics, document); + this.sendDiagnostics(document, lspDiagnostics); } protected cleanDiagnostics(document: TextDocument): void { diff --git a/Composer/packages/tools/language-servers/language-generation/src/utils.ts b/Composer/packages/tools/language-servers/language-generation/src/utils.ts index 001e74e4f3..d6c268eb52 100644 --- a/Composer/packages/tools/language-servers/language-generation/src/utils.ts +++ b/Composer/packages/tools/language-servers/language-generation/src/utils.ts @@ -3,13 +3,12 @@ import { TextDocument, Range, Position, DiagnosticSeverity, Diagnostic } from 'vscode-languageserver-types'; import { - LGParser, DiagnosticSeverity as LGDiagnosticSeverity, ImportResolver, Diagnostic as LGDiagnostic, StaticChecker, } from 'botbuilder-lg'; -import { LgTemplate, lgIndexer, Diagnostic as BFDiagnostic, offsetRange } from '@bfc/indexers'; +import { LgTemplate, Diagnostic as BFDiagnostic, offsetRange, LgFile } from '@bfc/indexers'; const staticChecker = new StaticChecker(); @@ -39,7 +38,9 @@ export interface Template { export interface LGDocument { uri: string; - lgOption?: LGOption; + fileId?: string; + templateId?: string; + index: () => LgFile | undefined; } export interface LGParsedResource { @@ -86,21 +87,6 @@ export function generageDiagnostic(message: string, severity: DiagnosticSeverity }; } -export function parse(content: string, document: TextDocument): LGParsedResource { - try { - const templates = lgIndexer.parse(content); - return { - templates, - diagnostics: [], - }; - } catch (error) { - return { - templates: [], - diagnostics: [generageDiagnostic(error.message, DiagnosticSeverity.Error, document)], - }; - } -} - // if template, offset +1 to exclude #TemplateName export function convertDiagnostics(lgDiags: BFDiagnostic[] = [], document: TextDocument, offset = 0): Diagnostic[] { const diagnostics: Diagnostic[] = []; @@ -139,8 +125,3 @@ export function checkTemplate(template: Template): LGDiagnostic[] { return diagnostic.message.includes('does not have an evaluator') === false; }); } - -export function updateTemplateInContent(content: string, { name, parameters = [], body }: Template): string { - const resource = LGParser.parse(content); - return resource.updateTemplate(name, name, parameters, body).toString(); -}