Skip to content

Commit eed66ef

Browse files
committed
add information for language features
1 parent 43be652 commit eed66ef

15 files changed

Lines changed: 119 additions & 49 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [0.0.10] - 2019-08-15
2+
Breaking changes:
3+
- :formControl now accept both a variable and a string value, so current usge will break and all you need to do is to convert this :formControl="MyControlName" to :formControl="'MyControlName'".
4+
15
## [0.0.8] - 2019-07-27
26
- Added language features:
37
- Code completion

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "XML Layout for Flutter",
44
"description": "XML Layout for Flutter. Brings Angular's style to Flutter!",
55
"publisher": "WaseemDev",
6-
"version": "0.0.8",
6+
"version": "0.0.10",
77
"icon": "images/logo.png",
88
"repository": {
99
"type": "github",

src/dart/extension/providers/dart_completion_item_provider.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export class DartCompletionItemProvider implements CompletionItemProvider, IAmDi
168168
});
169169

170170
const cachedResults = await this.getCachedResults(xmlDocument, token, nextCharacter, enableCommitCharacters, insertArgumentPlaceholders, xmlDocument.offsetAt(xmlPosition), resp);
171-
return [...includedResults, ...cachedResults, ...(isTag ? this.getWrapperPropertiesElementsCompletionItems() : this.getWrapperPropertiesCompletionItems())];
171+
return [...includedResults, ...cachedResults, ...(isTag ? this.getWrapperPropertiesElementsCompletionItems(xmlDocument, xmlPosition) : this.getWrapperPropertiesCompletionItems(xmlDocument, xmlPosition))];
172172
}
173173

174174
private getAttributeCompletionsForAttribute(elementTag: string, document: TextDocument, position: Position): vs.CompletionItem[] {
@@ -178,79 +178,88 @@ export class DartCompletionItemProvider implements CompletionItemProvider, IAmDi
178178
.filter((k) => handlers[k].isElement && elementTag === k)
179179
.forEach((k) => {
180180
handlers[k].elementAttributes.forEach((a) => {
181-
items.push(this.createCompletionItem(a, vs.CompletionItemKind.Variable));
181+
items.push(this.createCompletionItem(document, position, a.name, vs.CompletionItemKind.Variable, false, '="' + a.snippet + '"'));
182182
});
183183
});
184184
return items;
185185
}
186186

187-
private getWrapperPropertiesCompletionItems(): vs.CompletionItem[] {
187+
private getWrapperPropertiesCompletionItems(document: TextDocument, position: Position): vs.CompletionItem[] {
188188
const handlers = this.propertyHandlerProvider.getAll();
189189
const items = Object.keys(handlers)
190190
.filter((k) => !handlers[k].isElement)
191191
.map((k) => {
192-
return this.createCompletionItem(k, vs.CompletionItemKind.Variable);
192+
return this.createCompletionItem(document, position, k, vs.CompletionItemKind.Variable, false, handlers[k].valueSnippet);
193193
});
194194
return items;
195195
}
196196

197-
private getWrapperPropertiesElementsCompletionItems(): vs.CompletionItem[] {
197+
private getWrapperPropertiesElementsCompletionItems(document: TextDocument, position: Position): vs.CompletionItem[] {
198198
const handlers = this.propertyHandlerProvider.getAll();
199199
const items = Object.keys(handlers)
200200
.filter((k) => handlers[k].isElement)
201201
.map((k) => {
202-
return this.createCompletionItem(k, vs.CompletionItemKind.Variable, true);
202+
return this.createCompletionItem(document, position, k, vs.CompletionItemKind.Variable, true, handlers[k].valueSnippet);
203203
});
204204
return items;
205205
}
206206

207207
private getTopLevelElementAttributesCompletions(document: TextDocument, position: Position): vs.CompletionItem[] {
208208
return [
209-
this.createCompletionItem('xmlns', vs.CompletionItemKind.Variable),
210-
this.createCompletionItem('controller', vs.CompletionItemKind.Variable),
211-
this.createCompletionItem('routeAware', vs.CompletionItemKind.Variable),
209+
this.createCompletionItem(document, position, 'xmlns', vs.CompletionItemKind.Variable),
210+
this.createCompletionItem(document, position, 'controller', vs.CompletionItemKind.Variable),
211+
this.createCompletionItem(document, position, 'routeAware', vs.CompletionItemKind.Variable),
212212
];
213213
}
214214

215215
private getSecondLevelElementCompletions(document: TextDocument, position: Position): vs.CompletionItem[] {
216216
return [
217-
this.createCompletionItem('provider', vs.CompletionItemKind.Class),
218-
this.createCompletionItem('with', vs.CompletionItemKind.Class),
219-
this.createCompletionItem('var', vs.CompletionItemKind.Class),
220-
this.createCompletionItem('param', vs.CompletionItemKind.Class),
217+
this.createCompletionItem(document, position, 'provider', vs.CompletionItemKind.Class, true, ' type="$0" name="$1">$2'),
218+
this.createCompletionItem(document, position, 'with', vs.CompletionItemKind.Class, true, ' mixin="$0">$1'),
219+
this.createCompletionItem(document, position, 'var', vs.CompletionItemKind.Class, true, ' name="$0" value="$1">$2'),
220+
this.createCompletionItem(document, position, 'param', vs.CompletionItemKind.Class, true, ' type="$0" name="$1">$2'),
221221
];
222222
}
223223

224224
private getSecondLevelElementAttributesCompletions(elementTag: string, document: TextDocument, position: Position): vs.CompletionItem[] {
225225
const elements: { [name: string]: vs.CompletionItem[] } = {
226226
'provider': [
227-
this.createCompletionItem('type', vs.CompletionItemKind.Variable),
228-
this.createCompletionItem('name', vs.CompletionItemKind.Variable),
227+
this.createCompletionItem(document, position, 'type', vs.CompletionItemKind.Variable),
228+
this.createCompletionItem(document, position, 'name', vs.CompletionItemKind.Variable),
229229
],
230230
'with': [
231-
this.createCompletionItem('mixin', vs.CompletionItemKind.Variable),
231+
this.createCompletionItem(document, position, 'mixin', vs.CompletionItemKind.Variable),
232232
],
233233
'var': [
234-
this.createCompletionItem('type', vs.CompletionItemKind.Variable),
235-
this.createCompletionItem('name', vs.CompletionItemKind.Variable),
236-
this.createCompletionItem('value', vs.CompletionItemKind.Variable),
234+
this.createCompletionItem(document, position, 'type', vs.CompletionItemKind.Variable),
235+
this.createCompletionItem(document, position, 'name', vs.CompletionItemKind.Variable),
236+
this.createCompletionItem(document, position, 'value', vs.CompletionItemKind.Variable),
237237
],
238238
'param': [
239-
this.createCompletionItem('type', vs.CompletionItemKind.Variable),
240-
this.createCompletionItem('name', vs.CompletionItemKind.Variable),
239+
this.createCompletionItem(document, position, 'type', vs.CompletionItemKind.Variable),
240+
this.createCompletionItem(document, position, 'name', vs.CompletionItemKind.Variable),
241241
],
242242
};
243243

244244
return elements[elementTag];
245245
}
246246

247-
private createCompletionItem(label: string, kind: vs.CompletionItemKind, isTag = false): vs.CompletionItem {
247+
private createCompletionItem(document: TextDocument, position: Position, label: string, kind: vs.CompletionItemKind, isTag = false, snippet?: string): vs.CompletionItem {
248248
let insertText = '';
249-
if (kind === vs.CompletionItemKind.Variable && !isTag) {
249+
const nextChar = document.getText(new Range(position, new Position(position.line, position.character + 1)));
250+
if (snippet) {
251+
if (kind === vs.CompletionItemKind.Variable && !isTag) {
252+
insertText = label + '="' + snippet + '"';
253+
}
254+
else {
255+
insertText = label + ' ' + snippet + (nextChar === '>' ? '' : '>');
256+
}
257+
}
258+
else if (kind === vs.CompletionItemKind.Variable && !isTag) {
250259
insertText = label + '="$0"';
251260
}
252261
else {
253-
insertText = label + '>$0';
262+
insertText = label + (nextChar === '>' ? '' : '>') + '$0';
254263
}
255264

256265
const item = new vs.CompletionItem(label, kind);

src/dart/utils.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,24 @@ export async function getDartCodeIndex(xmlDocument: TextDocument, xmlPosition: P
4141
let dartOffset = -1;
4242

4343
if (isAttribute(xmlDocument, xmlPosition)) {
44-
const tag = xPath[xPath.length - 1];
45-
let count = countWords(xml, '<' + tag + ' ', offset + tag.length);
46-
count += countWords(xml, '<' + tag + '>', offset + tag.length);
47-
const classIndex = wordIndexAfter(dart, ' ' + tag + '(', count) + 2; // 2 = space + (
48-
dartOffset = classIndex;
49-
if (wordRange) {
50-
const attrName = xmlDocument.getText(wordRange);
51-
dartOffset = dart.indexOf(attrName, classIndex);
52-
}
44+
const tag = xPath[xPath.length - 1];
45+
let count = countWords(xml, '<' + tag + ' ', offset + tag.length);
46+
count += countWords(xml, '<' + tag + '>', offset + tag.length);
47+
let classIndex = wordIndexAfter(dart, ' ' + tag + '(', count) + 2; // 2 = space + (
48+
if (classIndex === tag.length + 3) {
49+
// e.g. Class.namedCtor(...)
50+
const namedCtorIndex = wordIndexAfter(xml, ':use="', count) + 6;
51+
if (namedCtorIndex > 6) {
52+
const namedCtorPos = xmlDocument.positionAt(namedCtorIndex);
53+
const namedCtor = xmlDocument.getText(new Range(namedCtorPos, new Position(namedCtorPos.line, namedCtorPos.character + 50))).split('"\'')[0];
54+
classIndex = wordIndexAfter(dart, ' ' + tag + '.' + namedCtor + '(', count) + 3 + namedCtor.length; // 2 = space + (
55+
}
56+
}
57+
dartOffset = classIndex;
58+
if (wordRange) {
59+
const attrName = xmlDocument.getText(wordRange);
60+
dartOffset = dart.indexOf(attrName, classIndex);
61+
}
5362
}
5463
else if (isTagName(xmlDocument, xmlPosition) || (includeCloseTag && isClosingTagName(xmlDocument, xmlPosition))) {
5564
if (wordRange) {
@@ -66,7 +75,10 @@ export async function getDartCodeIndex(xmlDocument: TextDocument, xmlPosition: P
6675
else {
6776
let count = countWords(xml, '<' + tag + ' ', offset + tag.length);
6877
count += countWords(xml, '<' + tag + '>', offset + tag.length);
69-
const classIndex = wordIndexAfter(dart, ' ' + tag + '(', count) + 2; // 2 = space + (
78+
let classIndex = wordIndexAfter(dart, ' ' + tag + '(', count) + 2; // 2 = space + (
79+
if (classIndex == tag.length + 3) {
80+
classIndex = wordIndexAfter(dart, ' ' + tag + '.', count) + 2; // 2 = space + (
81+
}
7082
dartOffset = classIndex - 3;
7183
}
7284
}

src/models/models.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,8 @@ export interface AttributeModel {
103103
// isEvent?: boolean;
104104
// isBound?: boolean;
105105
}
106+
107+
export interface AttributeInfo {
108+
name: string;
109+
snippet?: string;
110+
}

src/property-handlers/builder.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
import { CustomPropertyHandler, PropertyResolveResult } from "../providers/property-handler-provider";
1+
import { CustomPropertyHandler, PropertyResolveResult, WidgetResolveResult } from "../providers/property-handler-provider";
22
import * as parseXml from '../parser/types';
3-
import { WidgetModel, ExtraDataModel, AttributeModel, PropertyModel } from '../models/models';
3+
import { WidgetModel, ExtraDataModel, AttributeModel, PropertyModel, AttributeInfo } from '../models/models';
44
import { extractForLoopParams, makeTabs, sortProperties } from "../utils";
55
import { PropertyResolver } from "../resolvers/property-resolver";
66

77
export class BuilderHandler extends CustomPropertyHandler {
88
priority = -100000; // lowest priority
99
isElement = true;
10-
elementAttributes: string[] = ['name', 'data', 'params'];
10+
elementAttributes: AttributeInfo[] = [
11+
{ name: 'name' },
12+
{ name: 'data', snippet: 'item of ${0:items}' },
13+
{ name: 'params' }
14+
];
15+
valueSnippet = 'name="${0:builderName}" data="${1:item of ${2:items}}" params="${3:context}"';
1116

1217
constructor(private readonly propertyResolver: PropertyResolver) {
1318
super();
@@ -17,9 +22,17 @@ export class BuilderHandler extends CustomPropertyHandler {
1722
return true;
1823
}
1924

20-
canResolvePropertyElement(): boolean {
21-
return true;
22-
}
25+
// canResolvePropertyElement(): boolean {
26+
// return true;
27+
// }
28+
29+
// resolvePropertyElement(element: parseXml.Element, widgetResolveResult: WidgetResolveResult, parent: parseXml.Element, parentChildren: parseXml.Element[], resolveWidget: (element: parseXml.Element, parent: parseXml.Element) => WidgetResolveResult): WidgetModel | null {
30+
// const res = this.resolve(element, {
31+
// value: { value: widgetResolveResult.propertyElementProperties.filter(a => a.name === 'data')[0].value },
32+
// name: widgetResolveResult.propertyElementProperties.filter(a => a.name === 'name')[0].value || 'builder'
33+
// } as any, widgetResolveResult.widget);
34+
// return res.wrapperWidget;
35+
// }
2336

2437
resolve(element: parseXml.Element, attr: AttributeModel, widget: WidgetModel): PropertyResolveResult {
2538
let wrapperWidget: WidgetModel | null = null;

src/property-handlers/child-builder.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { PropertyResolver } from "../resolvers/property-resolver";
66

77
export class ChildBuilderHandler extends CustomPropertyHandler {
88
priority = -100000; // lowest priority
9+
valueSnippet = 'item of ${0:items}';
910

1011
constructor(private readonly propertyResolver: PropertyResolver) {
1112
super();

src/property-handlers/if-element.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { CustomPropertyHandler, WidgetResolveResult } from "../providers/property-handler-provider";
22
import * as parseXml from '../parser/types';
3-
import { WidgetModel, PropertyModel } from '../models/models';
3+
import { WidgetModel, PropertyModel, AttributeInfo } from '../models/models';
44
import { makeTabs } from "../utils";
55
import { PropertyResolver } from "../resolvers/property-resolver";
66

@@ -11,7 +11,10 @@ interface IfModel {
1111

1212
export class IfElementHandler extends CustomPropertyHandler {
1313
isElement = true;
14-
elementAttributes: string[] = ['value'];
14+
elementAttributes: AttributeInfo[] = [
15+
{ name: 'value' }
16+
];
17+
valueSnippet = 'value="${0:condition}"';
1518

1619
constructor(private readonly propertyResolver: PropertyResolver) {
1720
super();

src/property-handlers/if.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { PropertyResolver } from "../resolvers/property-resolver";
66

77
export class IfHandler extends CustomPropertyHandler {
88
priority = 100000;
9+
valueSnippet = '${0:condition}';
910

1011
constructor(private readonly propertyResolver: PropertyResolver) {
1112
super();

src/property-handlers/item-builder-property.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ItemBuilderHandler } from "./item-builder";
33

44
export class ItemBuilderPropertyHandler extends ItemBuilderHandler {
55
isElement = false;
6+
valueSnippet = 'item of ${0:items}';
67

78
protected resolveValueProperty(widget: WidgetModel, attr: AttributeModel): { grandparentWidget: WidgetModel | null, hasIndex: boolean | null, indexName: string } {
89
let grandparentWidget = null;

0 commit comments

Comments
 (0)