Skip to content

Commit

Permalink
feat: folding range provider for {ts,js,gts,gjs} files (#360)
Browse files Browse the repository at this point in the history
* complete handlebars folding support

* improve tests
  • Loading branch information
lifeart committed Feb 11, 2022
1 parent 89e722c commit 645c300
Show file tree
Hide file tree
Showing 5 changed files with 614 additions and 22 deletions.
47 changes: 40 additions & 7 deletions src/folding-provider/entry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import TemplateFoldingProvider from './template-folding-provider';
import { FoldingRangeParams, FoldingRange } from 'vscode-languageserver';
import { Server } from '..';
import { getFileRanges, RangeWalker } from '../utils/glimmer-script';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { searchAndExtractHbs } from '@lifeart/ember-extract-inline-templates';
import { parseScriptFile } from 'ember-meta-explorer';

export default class FoldingProvider {
constructor(private server: Server) {}
Expand All @@ -12,14 +16,43 @@ export default class FoldingProvider {
return null;
}

if (document.languageId !== 'handlebars') {
return null;
}
if (document.uri.endsWith('.hbs')) {
try {
return this.templateFoldingProvider.handle(document);
} catch (e) {
return null;
}
} else if (document.uri.endsWith('.gts') || document.uri.endsWith('.gjs')) {
try {
const ranges = getFileRanges(document.getText());
const templatesData = new RangeWalker(ranges).templates(true);
const documents = templatesData.map((tpl) => TextDocument.create(document.uri, 'handlebars', document.version, tpl.absoluteContent));
const results: FoldingRange[] = [];

try {
return this.templateFoldingProvider.handle(document);
} catch (e) {
return null;
documents.forEach((d) => {
this.templateFoldingProvider.handle(d).forEach((result) => {
results.push(result);
});
});

return results;
} catch (e) {
return null;
}
} else if (document.uri.endsWith('.js') || document.uri.endsWith('.ts')) {
try {
const text = searchAndExtractHbs(document.getText(), {
parse(source: string) {
return parseScriptFile(source);
},
});

return this.templateFoldingProvider.handle(TextDocument.create(document.uri, 'handlebars', document.version, text));
} catch (e) {
return null;
}
}

return null;
}
}
28 changes: 15 additions & 13 deletions src/folding-provider/template-folding-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,34 @@ import { TextDocument } from 'vscode-languageserver-textdocument';
import { preprocess, traverse, ASTv1 } from '@glimmer/syntax';

export default class TemplateFoldingProvider {
handle(document: TextDocument): FoldingRange[] | null {
handle(document: TextDocument): FoldingRange[] {
const content = document.getText();
const ast = preprocess(content);
const results: FoldingRange[] = [];

function nodeToResults(node: ASTv1.Block | ASTv1.BlockStatement | ASTv1.ElementNode | ASTv1.MustacheCommentStatement) {
const loc = node.loc.toJSON();

if (loc.start.line !== loc.end.line) {
const kind = node.type === 'MustacheCommentStatement' ? FoldingRangeKind.Comment : FoldingRangeKind.Region;

results.push(FoldingRange.create(loc.start.line - 1, loc.end.line - 1, loc.start.column, loc.end.column, kind));
}
}

traverse(ast, {
BlockStatement(node: ASTv1.BlockStatement) {
const loc = node.loc.toJSON();

results.push(FoldingRange.create(loc.start.line - 1, loc.end.line - 1, loc.start.column, loc.end.column, FoldingRangeKind.Region));
nodeToResults(node);

if (node.inverse) {
const loc = node.inverse.loc.toJSON();

results.push(FoldingRange.create(loc.start.line - 1, loc.end.line - 1, loc.start.column, loc.end.column, FoldingRangeKind.Region));
nodeToResults(node.inverse);
}
},
MustacheCommentStatement(node: ASTv1.MustacheCommentStatement) {
const loc = node.loc.toJSON();

results.push(FoldingRange.create(loc.start.line - 1, loc.end.line - 1, loc.start.column, loc.end.column, FoldingRangeKind.Comment));
nodeToResults(node);
},
ElementNode(node: ASTv1.ElementNode) {
const loc = node.loc.toJSON();

results.push(FoldingRange.create(loc.start.line - 1, loc.end.line - 1, loc.start.column, loc.end.column, FoldingRangeKind.Region));
nodeToResults(node);
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`has folding range support for handlebars language folding range for [.gts] files able to provide folding ranges 1`] = `
Object {
"addonsMeta": Array [],
"registry": Object {
"component": Object {
"hello": Array [
"app/components/hello/index.gts",
],
},
},
"response": Array [
Object {
"endCharacter": 31,
"endLine": 9,
"kind": "region",
"startCharacter": 20,
"startLine": 1,
},
Object {
"endCharacter": 30,
"endLine": 8,
"kind": "region",
"startCharacter": 24,
"startLine": 2,
},
Object {
"endCharacter": 35,
"endLine": 7,
"kind": "region",
"startCharacter": 28,
"startLine": 3,
},
Object {
"endCharacter": 28,
"endLine": 7,
"kind": "region",
"startCharacter": 36,
"startLine": 5,
},
],
}
`;

exports[`has folding range support for handlebars language folding range for [.hbs] files able to provide folding ranges 1`] = `
Object {
"addonsMeta": Array [],
"registry": Object {
"component": Object {
"hello": Array [
"app/components/hello/index.hbs",
],
},
},
"response": Array [
Object {
"endCharacter": 16,
"endLine": 6,
"kind": "region",
"startCharacter": 0,
"startLine": 0,
},
Object {
"endCharacter": 19,
"endLine": 5,
"kind": "region",
"startCharacter": 12,
"startLine": 1,
},
Object {
"endCharacter": 12,
"endLine": 5,
"kind": "region",
"startCharacter": 20,
"startLine": 3,
},
],
}
`;

exports[`has folding range support for handlebars language folding range for [.hbs] files able to provide folding ranges for blocks 1`] = `
Object {
"addonsMeta": Array [],
"registry": Object {
"component": Object {
"hello": Array [
"app/components/hello/index.hbs",
],
},
},
"response": Array [
Object {
"endCharacter": 19,
"endLine": 2,
"kind": "region",
"startCharacter": 0,
"startLine": 0,
},
],
}
`;

exports[`has folding range support for handlebars language folding range for [.hbs] files able to provide folding ranges for comments 1`] = `
Object {
"addonsMeta": Array [],
"registry": Object {
"component": Object {
"hello": Array [
"app/components/hello/index.hbs",
],
},
},
"response": Array [
Object {
"endCharacter": 16,
"endLine": 6,
"kind": "comment",
"startCharacter": 0,
"startLine": 0,
},
],
}
`;

exports[`has folding range support for handlebars language folding range for [.hbs] files able to provide folding ranges for inverse blocks 1`] = `
Object {
"addonsMeta": Array [],
"registry": Object {
"component": Object {
"hello": Array [
"app/components/hello/index.hbs",
],
},
},
"response": Array [
Object {
"endCharacter": 19,
"endLine": 4,
"kind": "region",
"startCharacter": 0,
"startLine": 0,
},
Object {
"endCharacter": 12,
"endLine": 4,
"kind": "region",
"startCharacter": 20,
"startLine": 2,
},
],
}
`;

exports[`has folding range support for handlebars language folding range for [.hbs] files able to provide folding ranges for tags 1`] = `
Object {
"addonsMeta": Array [],
"registry": Object {
"component": Object {
"hello": Array [
"app/components/hello/index.hbs",
],
},
},
"response": Array [
Object {
"endCharacter": 26,
"endLine": 2,
"kind": "region",
"startCharacter": 0,
"startLine": 0,
},
],
}
`;

exports[`has folding range support for handlebars language folding range for [.ts] files able to provide folding ranges 1`] = `
Object {
"addonsMeta": Array [],
"registry": Object {
"component": Object {
"hello": Array [
"app/components/hello/index.ts",
],
},
},
"response": Array [
Object {
"endCharacter": 18,
"endLine": 7,
"kind": "region",
"startCharacter": 28,
"startLine": 1,
},
Object {
"endCharacter": 21,
"endLine": 6,
"kind": "region",
"startCharacter": 14,
"startLine": 2,
},
Object {
"endCharacter": 14,
"endLine": 6,
"kind": "region",
"startCharacter": 22,
"startLine": 4,
},
],
}
`;

0 comments on commit 645c300

Please sign in to comment.