From 0ad9eb966179dad3175d30728b15ac7149bb48d7 Mon Sep 17 00:00:00 2001 From: omemisoglu Date: Sat, 26 Aug 2023 14:07:09 +0300 Subject: [PATCH 1/2] Improving Generic Map by Reworking levelIndent - Implementing hierarchy level by promoting levelIndent to identify not a whitespace indent on files, but a hierarchy level among other mapping rules of a indent dependant programming language file. Non-hiearachy Mapping Rules - If a mapping rule has no hiearchy, it cannot nest other mapping rules. Hierarchy Priority: - Mapping rules with levelIndent property set other than zero (0) can nest lower level hierarchies (lower number, higher hierarchy). Resolving Hierarchy with same Indentation: - When mapping rules with levelIndent has same indentation, higher hierarchy mapping rule will nest lower level hierarchy. TODO: - Implementing mapping rule category: When different categorie mapping rules with same indentation but different hierarchy levels can nest each other. - Supporting non-indent based programming languages by improving hierarchy algorithm. --- src/mapper_generic.ts | 14 ++-- src/tree_view.ts | 169 +++++++++++++++++++++++++++++++++--------- 2 files changed, 145 insertions(+), 38 deletions(-) diff --git a/src/mapper_generic.ts b/src/mapper_generic.ts index 3de9131..407073e 100644 --- a/src/mapper_generic.ts +++ b/src/mapper_generic.ts @@ -74,8 +74,10 @@ export class mapper { if (m) { let level_indent = line.length - code_line.length; + + let level_hierarchy = 0 if (item.levelIndent) - level_indent = item.levelIndent; + level_hierarchy = item.levelIndent; let match = m[0]; @@ -84,8 +86,8 @@ export class mapper { .split('|') .forEach(text => { try { - // match = match.replaceAll(text, ''); // fails to treat arguments as regex :o( - + // match = match.replaceAll(text, ''); // fails to treat arguments as regex :o( +// vscode.workspace.getConfiguration vscode.window.activeTextEditor.options.tabSize match = match.replace(new RegExp(text, 'g'), ''); } catch (error) { @@ -98,7 +100,7 @@ export class mapper { if (item.prefix) match = item.prefix + match; - members.push([line_num, item.role, match, level_indent, item.icon]); + members.push([line_num, item.role, match, level_indent, item.icon, level_hierarchy]); break; } } @@ -120,6 +122,7 @@ export class mapper { let content = item[2]; let indent = item[3]; let icon = item[4]; + let hierarchy = item[5]; let extra_line = ''; if (indent == last_indent && content_type != last_type) @@ -128,7 +131,8 @@ export class mapper { let prefix = ' '.repeat(indent); let lean_content = content.trimStart(); - map = map + extra_line + prefix + lean_content + '|' + String(line) + '|' + icon + '\n'; + map = map + extra_line + prefix + lean_content + '|' + + String(line) + '|' + icon + '|'+ String(hierarchy) + '\n'; last_indent = indent; last_type = content_type; diff --git a/src/tree_view.ts b/src/tree_view.ts index 3af0c6b..e35060c 100644 --- a/src/tree_view.ts +++ b/src/tree_view.ts @@ -100,9 +100,9 @@ export class SettingsTreeProvider implements vscode.TreeDataProvider { return this.Items; } + public static process_node( + node : MapItem, + nodes : MapItem[], + map_hierarchy : MapItem[] + ): void { + let level_indent = node.level_indent; + let level_hierarchy = node.level_hierarchy; + + if (!(map_hierarchy.length)) { + if (level_hierarchy == 0) + { + nodes.push(node); + } + else + { + map_hierarchy.push(node) + } + } + else if (map_hierarchy.length) { + // Let us get parent + let parent : MapItem = map_hierarchy[map_hierarchy.length - 1]; + + if (level_indent > parent.level_indent) + { + if (level_hierarchy) + { + map_hierarchy.push(node); + } + else + { + parent.addChildItem(node); + node.parent = parent; + } + } + else if (level_indent == parent.level_indent) + { + if (level_hierarchy) + { + if (level_hierarchy < parent.level_hierarchy) + { + map_hierarchy.pop() + FavoritesTreeProvider.process_node(node, nodes, map_hierarchy) + } + else if (level_hierarchy == parent.level_hierarchy) + { + nodes.push(parent) + map_hierarchy.pop() + } + else // TODO Implementing outline type, that different types will not + { // TODO race hierarchy (nestable will not nest the other type on same + // TODO indent level) + parent.addChildItem(node); + node.parent = parent; + } + map_hierarchy.push(node) + } + else + { + parent.addChildItem(node); + node.parent = parent; + } + } + else if (level_indent < parent.level_indent) + { + map_hierarchy.pop() + // parent = map_hierarchy[map_hierarchy.length - 1] + FavoritesTreeProvider.process_node(node, nodes, map_hierarchy) + // if (level_hierarchy) + // { + // map_hierarchy.push(node) + // } + // else + // { + // nodes.push(node) + } + } + } + public static parseScriptItems(items: string[], sourceFile: string, nodeTypesToKeep: string[]): MapItem[] { let nodes = []; @@ -251,44 +329,58 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { // https://github.com/patrys/vscode-code-outline/issues/24: Is it possible to disable expand/collapse on click // Until above items are fixed need to go with the plain text. let plainTextMode = vscode.workspace.getConfiguration("codemap").get('textMode', defaults.get('textMode')); - let max_nesting_level = vscode.workspace.getConfiguration("codemap").get('maxNestingLevel', defaults.get('maxNestingLevel')); + let max_hierarchy_level = vscode.workspace.getConfiguration("codemap").get('maxNestingLevel', defaults.get('maxNestingLevel')); // default is empty (non-white space) character U+00A0; to avoid trimming by treeview renderer let levelUnitChar = vscode.workspace.getConfiguration("codemap").get('textModeLevelPrefix', defaults.get('textModeLevelPrefix')); - let levelUnit = null; + // Intelligently taking tab size (in terms of number of spaces) from active text editor + let levelUnit : number; + let levelUnit_t = vscode.window.activeTextEditor.options.tabSize; + if (typeof levelUnit_t === "string") + { + // set indentation according to language or scrape it from document + let editor_language = vscode.window.activeTextEditor.document.languageId + + levelUnit = 4; + } + else + { + levelUnit = levelUnit_t + } let map: { [index: number]: MapItem; } = {}; + let map_hierarchy = []; items.forEach(item => { if (item != '') { let source_file = sourceFile; let tokens = item.split('|'); + let lineNumber = 0; let icon = 'document'; - - let title: string = item; - - let nesting_level = item.length - item.trimStart().length; - - if (nesting_level != 0) { - if (!levelUnit) - levelUnit = nesting_level; - nesting_level = nesting_level / levelUnit; - } - + let title: string; + let level_indent = item.length - item.trimStart().length; + let level_hierarchy:number = 0; if (tokens.length > 1) { try { title = tokens[0]; lineNumber = Number(tokens[1]) - 1; icon = tokens[2]; + level_hierarchy = Number(tokens[3]); } catch (error) { } } else source_file = null; - if (nesting_level > max_nesting_level) + // if (level_indent != 0) { + // if (!levelUnit) + // levelUnit = level_indent; + // level_indent = level_indent / levelUnit; + // } + + if (level_hierarchy > max_hierarchy_level) return; // the normal spaces are collapsed by the tree item renderer @@ -308,7 +400,8 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { let node = new MapItem( title, textModeExpanded ? vscode.TreeItemCollapsibleState.Expanded : vscode.TreeItemCollapsibleState.Collapsed, - nesting_level, + level_indent, + level_hierarchy, { command: on_click_command, title: '', @@ -322,23 +415,29 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { if (nodeTypesToKeep.includes(icon)) { if (plainTextMode) { node.collapsibleState = vscode.TreeItemCollapsibleState.None; - node.label = non_whitespace_empty_char.repeat(nesting_level) + title; + node.label = non_whitespace_empty_char.repeat(Math.floor(level_indent / levelUnit)) + title; nodes.push(node); } else { - if (nesting_level == 0) { - nodes.push(node); - } - else { - let parent = map[node.nesting_level - 1]; - if (!parent) { - for (let key in map) { - parent = map[key]; - } - } - parent.addChildItem(node); - node.parent = parent; - } + + FavoritesTreeProvider.process_node( + node, + nodes, + map_hierarchy + ) + // if (level_indent == 0) { + // nodes.push(node); + // } + // else { + // let parent = map[node.nesting_level - 1]; + // if (!parent) { + // for (let key in map) { + // parent = map[key]; + // } + // } + // parent.addChildItem(node); + // node.parent = parent; + // } } } @@ -358,7 +457,7 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { }; } - map[node.nesting_level] = node; + map[node.level_indent] = node; } }); @@ -383,12 +482,16 @@ function getDefaultSortDirection() { return SortDirection[dir]; } +// TODO Implementing outline type, that different types will not +// TODO race hierarchy (nestable will not nest the other type on same +// TODO indent level) export class MapItem extends vscode.TreeItem { constructor( public readonly title: string, public readonly state: vscode.TreeItemCollapsibleState, - public readonly nesting_level: number, + public readonly level_indent: number, + public readonly level_hierarchy: number, public readonly command?: vscode.Command, public readonly context?: string, public readonly lineNumber?: number) { From 75d1068fd23e094b9c89c76df402e9abd8e428c8 Mon Sep 17 00:00:00 2001 From: omemisoglu Date: Sun, 27 Aug 2023 03:14:10 +0300 Subject: [PATCH 2/2] Improving Hierarchy and Optimizing --- src/mapper_generic.ts | 18 +++++++------ src/tree_view.ts | 61 +++++++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/mapper_generic.ts b/src/mapper_generic.ts index 407073e..4681815 100644 --- a/src/mapper_generic.ts +++ b/src/mapper_generic.ts @@ -42,7 +42,6 @@ export class mapper { public static generate(file: string, mappings: SyntaxMapping[]): string[] { // # Parse - let item_max_length = 0; let members = []; try { @@ -55,8 +54,6 @@ export class mapper { lines = text.split(/\r?\n/g); let line_num = 0; - let last_type = ''; - let last_indent = 0; lines.forEach(line => { @@ -66,15 +63,13 @@ export class mapper { if (line != '') { let code_line = line.trimStart(); + let level_indent = line.length - code_line.length; for (let item of mappings) { let m = line.match(item.regex); if (m) { - - let level_indent = line.length - code_line.length; - let level_hierarchy = 0 if (item.levelIndent) level_hierarchy = item.levelIndent; @@ -87,7 +82,6 @@ export class mapper { .forEach(text => { try { // match = match.replaceAll(text, ''); // fails to treat arguments as regex :o( -// vscode.workspace.getConfiguration vscode.window.activeTextEditor.options.tabSize match = match.replace(new RegExp(text, 'g'), ''); } catch (error) { @@ -99,8 +93,16 @@ export class mapper { match += item.suffix; if (item.prefix) match = item.prefix + match; - + // TODO: We should do the processing here instead. + // Collecting and processing may lead to + // misinterpretation of hierarch, hence + // when we go out of a function and enter + // another indentation and have a mapping, + // this mapping will be nested under functions + // even it is not inside the function + // members.push([line_num, item.role, match, level_indent, item.icon, level_hierarchy]); + break; } } diff --git a/src/tree_view.ts b/src/tree_view.ts index e35060c..4368a50 100644 --- a/src/tree_view.ts +++ b/src/tree_view.ts @@ -252,12 +252,11 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { let level_hierarchy = node.level_hierarchy; if (!(map_hierarchy.length)) { - if (level_hierarchy == 0) - { - nodes.push(node); - } - else + nodes.push(node) + + if (level_hierarchy) { + node = nodes[nodes.length - 1] map_hierarchy.push(node) } } @@ -271,11 +270,10 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { { map_hierarchy.push(node); } - else - { - parent.addChildItem(node); - node.parent = parent; - } + + parent.addChildItem(node); + node.parent = parent; + } else if (level_indent == parent.level_indent) { @@ -284,19 +282,33 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { if (level_hierarchy < parent.level_hierarchy) { map_hierarchy.pop() - FavoritesTreeProvider.process_node(node, nodes, map_hierarchy) + FavoritesTreeProvider.process_node( + node, + nodes, + map_hierarchy + ) } else if (level_hierarchy == parent.level_hierarchy) { - nodes.push(parent) + if (parent.parent) { + parent.parent.addChildItem(node) + node.parent = parent.parent + } + else { + nodes.push(node) + } + map_hierarchy.pop() } - else // TODO Implementing outline type, that different types will not - { // TODO race hierarchy (nestable will not nest the other type on same - // TODO indent level) + else + { + // TODO Implementing outline type, that different types + // TODO will not race hierarchy (nestable will not nest + // TODO the other type on same indent level) parent.addChildItem(node); node.parent = parent; } + map_hierarchy.push(node) } else @@ -308,15 +320,8 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { else if (level_indent < parent.level_indent) { map_hierarchy.pop() - // parent = map_hierarchy[map_hierarchy.length - 1] FavoritesTreeProvider.process_node(node, nodes, map_hierarchy) - // if (level_hierarchy) - // { - // map_hierarchy.push(node) - // } - // else - // { - // nodes.push(node) + } } } @@ -337,10 +342,15 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { // Intelligently taking tab size (in terms of number of spaces) from active text editor let levelUnit : number; let levelUnit_t = vscode.window.activeTextEditor.options.tabSize; + + // Language + let editor_language = vscode.window.activeTextEditor.document.languageId; + if (typeof levelUnit_t === "string") { - // set indentation according to language or scrape it from document - let editor_language = vscode.window.activeTextEditor.document.languageId + // TODO Set indentation according to language or + // TODO scrape it from document + editor_language; levelUnit = 4; } @@ -425,6 +435,7 @@ export class FavoritesTreeProvider implements vscode.TreeDataProvider { nodes, map_hierarchy ) + // if (level_indent == 0) { // nodes.push(node); // }