Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: share server's resource to lsp server #1793

Merged
merged 24 commits into from
Jan 8, 2020
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Composer/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

module.exports = {
collectCoverageFrom: [
'**/src/**/*.{js,jsx,ts,tsx}',
Expand Down
2 changes: 1 addition & 1 deletion Composer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -56,17 +56,7 @@ const CodeEditor: React.FC<CodeEditorProps> = 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) : '';
Expand Down Expand Up @@ -150,9 +140,8 @@ const CodeEditor: React.FC<CodeEditorProps> = props => {

const lgOption = template
? {
inline: inlineMode,
content: file?.content ?? '',
template,
fileId,
templateId: template?.name || '',
}
: undefined;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
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 { filterTemplateDiagnostics } from '@bfc/indexers';

import { FormContext } from '../types';

Expand Down Expand Up @@ -62,32 +62,23 @@ export const LgEditorWidget: React.FC<LgEditorWidgetProps> = props => {
return template.name === lgName;
})) || {
name: lgName,
parameters: [],
body: getInitialTemplate(name, value),
range: {
startLineNumber: 0,
endLineNumber: 2,
},
};

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)[0];

const errorMsg = diagnostic
? diagnostic.message.split('error message: ')[diagnostic.message.split('error message: ').length - 1]
: '';
const [localValue, setLocalValue] = useState(template.body);
const lgOption = {
inline: true,
content: get(lgFile, 'content', ''),
template,
fileId: lgFileId,
templateId: lgName,
};

const onChange = (body: string) => {
Expand Down
1 change: 0 additions & 1 deletion Composer/packages/extensions/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"name": "@bfc/extensions",
"license": "MIT",
"version": "1.0.0",
"description": "",
"main": "index.js",
Expand Down
21 changes: 5 additions & 16 deletions Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
20 changes: 10 additions & 10 deletions Composer/packages/lib/code-editor/demo/src/lgEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import React, { useState } from 'react';
import { LgEditor } from '../../src';

const content = `# Hello
-[Welcome(time)] {name}
-@{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,
Expand All @@ -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')}
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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.
Expand Down
1 change: 0 additions & 1 deletion Composer/packages/lib/code-editor/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
16 changes: 4 additions & 12 deletions Composer/packages/lib/code-editor/src/LgEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -53,17 +48,14 @@ 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 });
}
}

export function LgEditor(props: LGLSPEditorProps) {
const options = {
quickSuggestions: true,
wordBasedSuggestions: false,
...props.options,
};

Expand Down
66 changes: 66 additions & 0 deletions Composer/packages/lib/code-editor/src/languages/lg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
};
},
});
}
26 changes: 25 additions & 1 deletion Composer/packages/lib/indexers/src/utils/diagnosticUtil.ts
Original file line number Diff line number Diff line change
@@ -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`;
Expand All @@ -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);
}
Expand Down
1 change: 0 additions & 1 deletion Composer/packages/lib/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"name": "@bfc/libs",
"license": "MIT",
"version": "1.0.0",
"description": "",
"main": "index.js",
Expand Down
3 changes: 2 additions & 1 deletion Composer/packages/server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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();
}

Expand Down
Loading