Skip to content

Commit

Permalink
fix: Auto-Suggestion for fields and values for structure LG (#2681)
Browse files Browse the repository at this point in the history
* init

* improvement

* change suggestion item kind

* add fixedOverflowWidgets to base editor options

Co-authored-by: Andy Brown <asbrown002@gmail.com>
  • Loading branch information
cosmicshuai and a-b-r-o-w-n authored Apr 18, 2020
1 parent 52d04c9 commit 3558910
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 52 deletions.
1 change: 1 addition & 0 deletions Composer/packages/lib/code-editor/src/BaseEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const defaultOptions = {
folding: false,
renderLineHighlight: 'none',
formatOnType: true,
fixedOverflowWidgets: true,
};

const styles = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
updateTemplate,
cardTypes,
cardPropDict,
cardPropPossibleValueType,
} from './utils';

// define init methods call from client
Expand Down Expand Up @@ -344,22 +345,62 @@ export class LGServer {
const position = params.position;
const range = Range.create(0, 0, position.line, position.character);
const lines = document.getText(range).split('\n');
let lastLine = '';
const keyValueRegex = /.+=.+/;
let cardName = '';
for (const line of lines) {
if (line.trim().startsWith('#')) {
state.push(TEMPLATENAME);
} else if (line.trim().startsWith('-')) {
state.push(TEMPLATEBODY);
} else if ((state[state.length - 1] === TEMPLATENAME || templateId) && line.trim().startsWith('[')) {
state.push(STRUCTURELG);
lastLine = line;
} else if (state[state.length - 1] === STRUCTURELG && line.trim() === '') {
return lastLine.trim().substring(1);
cardName = line.trim().substring(1);
} else if (state[state.length - 1] === STRUCTURELG && (line.trim() === '' || keyValueRegex.test(line))) {
state.push(STRUCTURELG);
} else {
state.push(ROOT);
}
}

if (state[state.length - 1] === STRUCTURELG) {
return cardName;
}

return undefined;
}

private findLastStructureLGProps(
params: TextDocumentPositionParams,
templateId: string | undefined
): string[] | undefined {
const state: LGCursorState[] = [];
const document = this.documents.get(params.textDocument.uri);
if (!document) return;
const position = params.position;
const range = Range.create(0, 0, position.line, position.character);
const lines = document.getText(range).split('\n');
const keyValueRegex = /.+=.+/;
let props: string[] = [];
for (const line of lines) {
if (line.trim().startsWith('#')) {
state.push(TEMPLATENAME);
} else if (line.trim().startsWith('-')) {
state.push(TEMPLATEBODY);
} else if ((state[state.length - 1] === TEMPLATENAME || templateId) && line.trim().startsWith('[')) {
state.push(STRUCTURELG);
props = [];
} else if (state[state.length - 1] === STRUCTURELG && (line.trim() === '' || keyValueRegex.test(line))) {
state.push(STRUCTURELG);
props.push(line.split('=')[0].trim());
} else {
state.push(ROOT);
}
}

if (state[state.length - 1] === STRUCTURELG) {
return props;
}

return undefined;
}

Expand Down Expand Up @@ -504,6 +545,7 @@ export class LGServer {
const lgDoc = this.getLGDocument(document);
const lgFile = lgDoc?.index();
const templateId = lgDoc?.templateId;
const lines = document.getText(range).split('\n');
if (!lgFile) {
return Promise.resolve(null);
}
Expand Down Expand Up @@ -552,59 +594,55 @@ export class LGServer {
}

const cardType = this.matchCardTypeState(params, templateId);
const propsList = this.findLastStructureLGProps(params, templateId);
const cardNameRegex = /^\s*\[[\w]+/;
const lastLine = lines[lines.length - 2];
const paddingIndent = cardNameRegex.test(lastLine) ? '\t' : '';
const normalCardTypes = ['CardAction', 'Suggestions', 'Attachment'];
if (cardType && cardTypes.includes(cardType)) {
let item: CompletionItem | undefined = undefined;
if (cardType === 'CardAction') {
let insertStr = '';
insertStr = cardPropDict[cardType].map(u => `\t${u} = `).join('\r\n');
item = {
label: `Properties for ${cardType}`,
kind: CompletionItemKind.Keyword,
insertText: insertStr,
documentation: `Suggested properties for Card: ${cardType}`,
};
} else if (cardType === 'Suggestions') {
let insertStr = '';
insertStr = cardPropDict[cardType].map(u => `\t${u} = `).join('\r\n');
item = {
label: `Properties for ${cardType}`,
kind: CompletionItemKind.Keyword,
insertText: insertStr,
documentation: `Suggested properties for Card: ${cardType}`,
};
} else if (cardType === 'Attachment') {
let insertStr = '';
insertStr = cardPropDict[cardType].map(u => `\t${u} = `).join('\r\n');
item = {
label: `Properties for ${cardType}`,
kind: CompletionItemKind.Keyword,
insertText: insertStr,
documentation: `Suggested properties for Card: ${cardType}`,
};
const items: CompletionItem[] = [];
if (normalCardTypes.includes(cardType)) {
cardPropDict[cardType].forEach(u => {
if (!propsList?.includes(u)) {
const item = {
label: `${u}: ${cardPropPossibleValueType[u]}`,
kind: CompletionItemKind.Snippet,
insertText: `${paddingIndent}${u} = ${cardPropPossibleValueType[u]}`,
documentation: `Suggested propertiy ${u} in ${cardType}`,
};
items.push(item);
}
});
} else if (cardType.endsWith('Card')) {
let insertStr = '';
insertStr = cardPropDict.Cards.map(u => `\t${u} = `).join('\r\n');
item = {
label: `Properties for ${cardType}`,
kind: CompletionItemKind.Keyword,
insertText: insertStr,
documentation: `Suggested properties for Card: ${cardType}`,
};
cardPropDict.Cards.forEach(u => {
if (!propsList?.includes(u)) {
const item = {
label: `${u}: ${cardPropPossibleValueType[u]}`,
kind: CompletionItemKind.Snippet,
insertText: `${paddingIndent}${u} = ${cardPropPossibleValueType[u]}`,
documentation: `Suggested propertiy ${u} in ${cardType}`,
};
items.push(item);
}
});
} else {
let insertStr = '';
insertStr = cardPropDict.Others.map(u => `\t${u} = `).join('\r\n');
item = {
label: `Properties for ${cardType}`,
kind: CompletionItemKind.Keyword,
insertText: insertStr,
documentation: `Suggested properties for Card: ${cardType}`,
};
cardPropDict.Others.forEach(u => {
if (!propsList?.includes(u)) {
const item = {
label: `${u}: ${cardPropPossibleValueType[u]}`,
kind: CompletionItemKind.Snippet,
insertText: `${paddingIndent}${u} = ${cardPropPossibleValueType[u]}`,
documentation: `Suggested propertiy ${u} in ${cardType}`,
};
items.push(item);
}
});
}

if (item) {
if (items.length > 0) {
return Promise.resolve({
isIncomplete: true,
items: [item],
items: items,
});
}
}
Expand Down Expand Up @@ -639,8 +677,29 @@ export class LGServer {
const range = Range.create(0, 0, position.line, position.character);
const lines = document.getText(range).split('\n');
const isInStructureLGMode = this.matchStructureLG(lines);
if (key === '\n' && isInStructureLGMode) {
const deleteRange = Range.create(position.line, 0, position.line, 4);
const lgDoc = this.getLGDocument(document);
const templateId = lgDoc?.templateId;
const cardType = this.matchCardTypeState(params, templateId);
const propsList = this.findLastStructureLGProps(params, templateId);
const normalCardTypes = ['CardAction', 'Suggestions', 'Attachment'];
let expectedPropsList: string[] = [];
let matchedAllProps = false;
if (cardType) {
if (normalCardTypes.includes(cardType)) {
expectedPropsList = cardPropDict[cardType];
} else if (cardType.endsWith('Card')) {
expectedPropsList = cardPropDict.Cards;
} else {
expectedPropsList = cardPropDict.Others;
}
}

if (expectedPropsList.length > 0 && propsList !== undefined && this.isSubList(expectedPropsList, propsList)) {
matchedAllProps = true;
}
if (key === '\n' && isInStructureLGMode && matchedAllProps) {
const length = templateId ? 4 : 2;
const deleteRange = Range.create(position.line, 0, position.line, length);
const deleteItem: TextEdit = TextEdit.del(deleteRange);
if (document.getText(deleteRange).trim() === '') {
edits.push(deleteItem);
Expand Down Expand Up @@ -671,6 +730,16 @@ export class LGServer {
return true;
}

private isSubList(list1: string[], list2: string[]): boolean {
for (const item of list1) {
if (!list2.includes(item)) {
return false;
}
}

return true;
}

protected validate(document: TextDocument): void {
this.cleanPendingValidation(document);
this.pendingValidationRequests.set(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,20 @@ export const cardTypes = [
'Activity',
];

export const cardPropPossibleValueType = {
title: 'An Example Card',
type: 'Action Type',
value: 'Some Value',
SuggestionActions: 'Text | ${Some_CardAction}',
subtitle: 'An Example Subtitle',
text: 'Some text',
image: 'https://example.com/demo.jpg',
buttons: 'Text | ${Some_CardAction}',
contenttype: 'adaptivecard',
content: '${json(fromFile("../../card.json"))}',
name: 'An Example Name',
};

export const cardPropDict = {
CardAction: ['title', 'type', 'value'],
Suggestions: ['SuggestionActions'],
Expand Down

0 comments on commit 3558910

Please sign in to comment.