data tree: first steps

This commit is contained in:
Joao Moreno
2018-10-03 15:25:30 +01:00
parent 90a6b23b48
commit 26ebe97ddd
5 changed files with 282 additions and 50 deletions
+110 -39
View File
@@ -37,56 +37,118 @@
require.config({ baseUrl: '/static' });
require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { TreeVisibility }, { iter }) => {
const delegate = {
getHeight() { return 22; },
getTemplateId() { return 'template'; }
};
require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/dataTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { DataTree }, { TreeVisibility }, { iter }) => {
function createIndexTree() {
const delegate = {
getHeight() { return 22; },
getTemplateId() { return 'template'; }
};
const renderer = {
templateId: 'template',
renderTemplate(container) { return container; },
renderElement(element, index, container) {
container.textContent = element;
},
disposeTemplate() { }
};
const renderer = {
templateId: 'template',
renderTemplate(container) { return container; },
renderElement(element, index, container) {
container.textContent = element;
},
disposeTemplate() { }
};
const treeFilter = new class {
constructor() {
this.pattern = null;
let timeout;
filter.oninput = () => {
clearTimeout(timeout);
timeout = setTimeout(() => this.updatePattern(), 300);
};
}
updatePattern() {
if (!filter.value) {
const treeFilter = new class {
constructor() {
this.pattern = null;
} else {
this.pattern = new RegExp(filter.value, 'i');
let timeout;
filter.oninput = () => {
clearTimeout(timeout);
timeout = setTimeout(() => this.updatePattern(), 300);
};
}
updatePattern() {
if (!filter.value) {
this.pattern = null;
} else {
this.pattern = new RegExp(filter.value, 'i');
}
perf('refilter', () => tree.refilter());
}
filter(el) {
return (this.pattern ? this.pattern.test(el) : true) ? TreeVisibility.Visible : TreeVisibility.Recurse;
}
};
const tree = new IndexTree(container, delegate, [renderer], { filter: treeFilter });
return { tree, treeFilter };
}
function createDataTree() {
const delegate = {
getHeight() { return 22; },
getTemplateId() { return 'template'; }
};
const renderer = {
templateId: 'template',
renderTemplate(container) { return container; },
renderElement(element, index, container) { container.textContent = element.name; },
disposeTemplate() { }
};
const treeFilter = new class {
constructor() {
this.pattern = null;
let timeout;
filter.oninput = () => {
clearTimeout(timeout);
timeout = setTimeout(() => this.updatePattern(), 300);
};
}
perf('refilter', () => tree.refilter());
}
filter(el) {
return (this.pattern ? this.pattern.test(el) : true) ? TreeVisibility.Visible : TreeVisibility.Recurse;
}
};
updatePattern() {
if (!filter.value) {
this.pattern = null;
} else {
this.pattern = new RegExp(filter.value, 'i');
}
const tree = new IndexTree(container, delegate, [renderer], { filter: treeFilter });
perf('refilter', () => tree.refilter());
}
filter(el) {
return (this.pattern ? this.pattern.test(el.name) : true) ? TreeVisibility.Visible : TreeVisibility.Recurse;
}
};
function setModel(model) {
performance.mark('before splice');
const start = performance.now();
;
console.log('splice took', performance.now() - start);
performance.mark('after splice');
const dataSource = new class {
hasChildren(element) {
return element === null || element.type === 'dir';
}
getChildren(element) {
return new Promise((c, e) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', element ? `/api/readdir?path=${element.path}` : '/api/readdir');
xhr.send();
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
const els = JSON.parse(this.responseText).map(element => ({
element,
collapsible: element.type === 'dir'
}));
c(els);
}
};
});
}
}
const tree = new DataTree(container, delegate, [renderer], dataSource, { filter: treeFilter });
return { tree, treeFilter };
}
switch (location.search) {
case '?problems': {
const { tree, treeFilter } = createIndexTree();
const files = [];
for (let i = 0; i < 10000; i++) {
const errors = [];
@@ -101,7 +163,16 @@
perf('splice', () => tree.splice([0], 0, files));
break;
}
case '?data': {
const { tree, treeFilter } = createDataTree();
tree.refresh(null);
break;
}
default:
const { tree, treeFilter } = createIndexTree();
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/ls?path=');
xhr.send();
+30 -1
View File
@@ -26,6 +26,29 @@ async function getTree(fsPath, level) {
return { element, collapsible: true, collapsed: false, children };
}
async function readdir(relativePath) {
const absolutePath = relativePath ? path.join(root, relativePath) : root;
const childNames = await fs.readdir(absolutePath);
const childStats = await Promise.all(childNames.map(async name => await fs.stat(path.join(absolutePath, name))));
const result = [];
for (let i = 0; i < childNames.length; i++) {
const name = childNames[i];
const path = relativePath ? `${relativePath}/${name}` : name;
const stat = childStats[i];
if (stat.isFile()) {
result.push({ type: 'file', name, path });
} else if (!stat.isDirectory() || name === '.git' || name === '.build') {
continue;
} else {
result.push({ type: 'dir', name, path });
}
}
return result;
}
app.use(serve('public'));
app.use(mount('/static', serve('../../out')));
app.use(_.get('/api/ls', async ctx => {
@@ -33,7 +56,13 @@ app.use(_.get('/api/ls', async ctx => {
const absolutePath = path.join(root, relativePath);
ctx.body = await getTree(absolutePath, 0);
}))
}));
app.use(_.get('/api/readdir', async ctx => {
const relativePath = ctx.query.path;
ctx.body = await readdir(relativePath);
}));
app.listen(3000);
console.log('http://localhost:3000');