From dc2f4218435e4c09be92b0734aa0175508b4e45e Mon Sep 17 00:00:00 2001 From: Oleg Shilo Date: Sun, 4 Feb 2024 21:04:46 +1100 Subject: [PATCH] Release v1.21.0 - Added support for GO syntax (*.go files). - Added workflow for editing the mapper of the active opened document. - Added workflow for creating a new mapper for the active opened document. - New commands: `codemap.edit_mapper` and `codemap.create_mapper` --- CHANGELOG.md | 5 +- package.json | 30 ++++++- src/extension.ts | 166 ++++++++++++++++++++++++++++++++++++--- src/mapper_cs copy.ts | 176 ------------------------------------------ src/utils.ts | 7 ++ 5 files changed, 196 insertions(+), 188 deletions(-) delete mode 100644 src/mapper_cs copy.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 53bbfa5..6e7f8e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ # Change Log -## Next +## 1.21.0 (5 February 2024) +- Added support for GO syntax (*.go files). - Added workflow for editing the mapper of the active opened document. +- Added workflow for creating a new mapper for the active opened document. +- New commands: `codemap.edit_mapper` and `codemap.create_mapper` ## 1.20.5 (30 January 2024) diff --git a/package.json b/package.json index e60ff39..b165568 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "codemap", "displayName": "CodeMap", "description": "Interactive code map for quick visualization and navigation within code DOM objects (e.g. classes, members).", - "version": "1.20.5", + "version": "1.21.0", "license": "MIT", "publisher": "oleg-shilo", "engines": { @@ -187,6 +187,26 @@ ], "description": "Regex-based definition of the mapping rules for INI file syntax." }, + "codemap.go": { + "type": "array", + "default": [ + { + "pattern": "func (.*?)\\)(.*?){", + "clear": "func|(|{", + "suffix": "", + "role": "function", + "icon": "function" + }, + { + "pattern": "type (.*?) struct(.*?){", + "clear": "type|struct|(|{", + "suffix": "", + "role": "class", + "icon": "class" + } + ], + "description": "Regex-based definition of the mapping rules for GO file syntax." + }, "codemap.r": { "type": "array", "default": [ @@ -396,6 +416,14 @@ "dark": "resources/dark/arrow-both.svg" } }, + { + "command": "codemap.create_mapper", + "title": "CodeMap: Create a mapper for the currently opened file", + "icon": { + "light": "resources/light/arrow-both.svg", + "dark": "resources/dark/arrow-both.svg" + } + }, { "command": "codemap.mappers", "title": "CodeMap: Show mappers configuration" diff --git a/src/extension.ts b/src/extension.ts index cd21551..36ad84c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -11,7 +11,7 @@ import * as cs from "./mapper_cs"; import * as generic from "./mapper_generic"; import * as md from "./mapper_md"; import { SyntaxMapping } from "./mapper_generic"; -import { Utils, config_defaults, } from "./utils"; +import { Utils, config_defaults } from "./utils"; const defaults = new config_defaults(); let treeViewProvider1: FavoritesTreeProvider; @@ -88,10 +88,7 @@ function get_map_items(): MapInfo { } } - if ( - document.toLowerCase().endsWith(".ts") || - document.toLowerCase().endsWith(".js") - ) { + if (document.toLowerCase().endsWith(".ts") || document.toLowerCase().endsWith(".js")) { // dedicated built-in mapper return { sourceFile: document, items: ts.mapper.generate(document) }; } @@ -246,7 +243,7 @@ function get_required_mapper_type() { return null; } -function edit() { +function edit_mapper() { try { @@ -254,14 +251,36 @@ function edit() { if (value_name) { let config = vscode.workspace.getConfiguration("codemap"); - let mapper = config.get("overloaded." + value_name, null); - if (mapper == null) + let settingsFile = path.join(cs.user_dir(), "..", "settings.json"); + let existingMapperIndex = -1; + + if (mapper == null) { mapper = config.get(value_name, defaults.get(value_name)); + let lines = fs.readFileSync(settingsFile, 'utf8').split(/\r?\n/g); + + let rgx = new RegExp('\"codemap\.' + value_name.toLowerCase() + '\":', "g"); + for (let i = 0; i < lines.length; i++) { + if (existingMapperIndex == -1 && lines[i].match(rgx)) { + existingMapperIndex = i; + break; + } + } + } + mapper = get_actual_mapper(mapper); + if (!mapper) { + // dedicated built-in mappers + if (value_name == "ts" || value_name == "js") { + mapper = "mapper_ts.js"; + } else if (value_name == "cs") { + mapper = "mapper_cs.js"; + } + } + if (mapper) { if (typeof mapper == "string") { // custom dedicated mapper (path string) @@ -277,7 +296,17 @@ function edit() { commands.executeCommand('vscode.open', Uri.file(file)); } else { // Generic mapper (an object) - vscode.commands.executeCommand('workbench.action.openSettings', 'codemap.' + value_name); + if (existingMapperIndex != null) { // the mapper is in the user settings file + commands.executeCommand('vscode.open', Uri.file(settingsFile)) + .then(() => { + let editor = vscode.window.activeTextEditor; + let range = editor.document.lineAt(existingMapperIndex).range; + editor.selection = new vscode.Selection(range.start, range.end); + editor.revealRange(range); + }); + } else { + vscode.commands.executeCommand('workbench.action.openSettings', 'codemap.' + value_name); + } } return; } @@ -290,6 +319,122 @@ function edit() { } } +function create_mapper() { + + var mapper_type = get_required_mapper_type(); + var dedicated = 'Dedicated mapper (JS file)'; + var generic = 'Generic mapper (regular expression in the settings file)'; + + vscode.window + .showQuickPick([dedicated, generic]) + .then(selectedItem => { + + if (selectedItem == dedicated) { + var doc = path.join(cs.user_dir(), `mapper_${mapper_type}.js`); + if (fs.existsSync(doc)) { + vscode.window.showErrorMessage( + 'The current document mapper already exists. Opening it instead of creating a new one.'); + } + else { + var code = `"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = require("fs"); +class mapper { + static read_all_lines(file) { + let text = fs.readFileSync(file, 'utf8'); + return text.split(/\\r?\\n/g); + } + static generate(file) { + let members = []; + let line_num = 0; + try { + mapper + .read_all_lines(file) + .forEach(line => { + line_num++; + if(line_num < 3) // demo first 3 lines only + members.push(\`item|\${line_num}|level3\`); + }); + } + catch (error) { + } + return members; + } +} +exports.mapper = mapper;`; + + fs.writeFileSync(doc, code, { encoding: 'utf8' }); + } + commands.executeCommand('vscode.open', Uri.file(doc)); + } + else if (selectedItem == generic) { + + let settingsFile = path.join(cs.user_dir(), "..", "settings.json"); + let lines = fs.readFileSync(settingsFile, 'utf8').split(/\r?\n/g); + + let rgx = new RegExp('\"codemap\.' + mapper_type.toLowerCase() + '\":', "g"); + let firstMapperIndex = -1; + let existingMapperIndex = -1; + for (let i = 0; i < lines.length; i++) { + if (firstMapperIndex == -1 && lines[i].match(/(\s*)\"\w+\.\w+\"\:(\s*)\[/g)) + firstMapperIndex = i; + if (existingMapperIndex == -1 && lines[i].match(rgx)) { + existingMapperIndex = i; + break; + } + } + + let selectedLine = 1; + if (existingMapperIndex == -1) { + selectedLine = firstMapperIndex; + } else { + selectedLine = existingMapperIndex; + } + + commands.executeCommand('vscode.open', Uri.file(settingsFile)) + .then(() => { + + let editor = vscode.window.activeTextEditor; + let range = editor.document.lineAt(selectedLine).range; + + if (existingMapperIndex == -1) { + range = editor.document.lineAt(selectedLine - 1).range; // one line above + editor.selection = new vscode.Selection(range.start, range.start); + + const editRange = editor.document.lineAt(editor.selection.end.line).range.end; + + editor.edit(editBuilder => { + if (editor !== undefined) { + editBuilder.insert(editRange, ` + "codemap.${mapper_type.toLowerCase()}": [ + { + "pattern": "function (.*?)[(|:{]", + "clear": "({", + "suffix": "()", + "role": "function", + "icon": "function" + } + ],`); + } + + }); + range = editor.document.lineAt(selectedLine).range; + editor.selection = new vscode.Selection(range.start, range.end); + } + else { + editor.selection = new vscode.Selection(range.start, range.end); + vscode.window.showErrorMessage( + 'The current document mapper already exists. Opening it instead of creating a new one.'); + } + + editor.revealRange(range); + }); + + } + }); +} + + function quick_pick() { let info = get_map_items(); @@ -352,7 +497,8 @@ export function activate(context: vscode.ExtensionContext) { let treeView1 = vscode.window.createTreeView("codemap-own-view", { treeDataProvider: treeViewProvider1, showCollapseAll: true }); let treeView2 = vscode.window.createTreeView("codemap-explorer-view", { treeDataProvider: treeViewProvider2, showCollapseAll: true }); - vscode.commands.registerCommand("codemap.edit_mapper", edit); + vscode.commands.registerCommand("codemap.edit_mapper", edit_mapper); + vscode.commands.registerCommand("codemap.create_mapper", create_mapper); vscode.commands.registerCommand("codemap.reveal", () => reveal_current_line_in_tree(treeView1, treeView2)); vscode.commands.registerCommand("codemap.quick_pick", quick_pick); diff --git a/src/mapper_cs copy.ts b/src/mapper_cs copy.ts deleted file mode 100644 index 57bf2cb..0000000 --- a/src/mapper_cs copy.ts +++ /dev/null @@ -1,176 +0,0 @@ -/** - * This file is a part of CodeMap distribution. - * It will be overwritten after the extension next update. Thus you may want to make an editable copy of - * this file and add it as a custom dedicated mapper in the settings file. -*/ -import * as vscode from 'vscode'; -import * as fs from 'fs'; -import * as fsx from "fs-extra"; -import * as path from 'path'; -import * as os from 'os'; -import * as net from "net"; -import * as mkdirp from "mkdirp"; -import * as process from "process"; -import * as child_process from "child_process" -import { Uri, commands } from "vscode"; -import { Utils } from './utils'; - -let exec = require('child_process').exec; -let execSync = require('child_process').execSync; -let map = ""; -let map_last_source = ""; - -let SYNTAXER_VERSION = "3.1.2.0"; - -// will be set at the end of this file -let SEVER = ""; -let SEVER_CLI = ""; - -let HOST = '127.0.0.1'; -let PORT = 18002; - -function startServer(): void { - child_process.execFile("dotnet", [SEVER, "-port:" + PORT, "-listen", "-client:" + process.pid, "-timeout:60000"]); -} - -function copy_dir_to_sync(srcDir: string, destDir: string): void { - - try { - fsx.copySync(srcDir, destDir); - } catch (error) { - console.log(error.toString()); - } -} - -function delete_dir(dir: string): void { - try { - - let files = fs.readdirSync(dir); - for (let i = 0; i < files.length; i++) { - - let item_path = path.join(dir, files[i]); - - if (fs.lstatSync(item_path).isFile()) - try { - fs.unlinkSync(item_path); - } catch (error) { - } - else - delete_dir(item_path); - } - fs.rmdir(dir, () => { }); - } catch (error) { - console.log(error); - } -} - - - -export class mapper { - - public static generate(file: string): string[] { - - var stats = fs.statSync(file); - var map_source = file + stats.mtime; - - if (map_source != map_last_source) { - map_last_source = map_source; - map = ""; - } - - if (map == "") { - - // 18000 - Subline Text 3 - // 18001 - Notepad++ - // 18002 - VSCode.CodeMap - - let command = `dotnet "${SEVER_CLI}" ${PORT} -client:${process.pid} -op:codemap_vscode -script:"${file}"`; - - try { - - map = execSync(command).toString(); - - } catch (error) { - console.log(error); - } - } - return map.lines(); - } -} - -export function user_dir(): string { - // ext_context.storagePath cannot be used as it is undefined if no workspace loaded - - // vscode: - // Windows %appdata%\Code\User\settings.json - // Mac $HOME/Library/Application Support/Code/User/settings.json - // Linux $HOME/.config/Code/User/settings.json - - if (os.platform() == 'win32') { - return path.join(process.env.APPDATA, 'Code', 'User', 'codemap.user'); - } - else if (os.platform() == 'darwin') { - return path.join(process.env.HOME, 'Library', 'Application Support', 'Code', 'User', 'codemap.user'); - } - else { - return path.join(process.env.HOME, '.config', 'Code', 'User', 'codemap.user'); - } -} - -function DeploySyntaxer() { - - function create_dir(dir: string): void { - // fs.mkdirSync can only create the top level dir but mkdirp creates all child sub-dirs that do not exist - const allRWEPermissions = parseInt("0777", 8); - mkdirp.sync(dir, allRWEPermissions); - } - - - let fileName = "syntaxer.dll"; - let cliFileName = "syntaxer.cli.dll"; - let ext_dir = path.join(__dirname, "..", ".."); - let sourceDir = path.join(ext_dir, 'bin'); - let destRootDir = path.join(user_dir(), 'syntaxer'); - let destDir = path.join(destRootDir, SYNTAXER_VERSION); - - SEVER = path.join(destDir, fileName); - SEVER_CLI = path.join(destDir, cliFileName); - - fs.readdir(destRootDir, (err, items) => { - - try { - - items.forEach(item => { - try { - - let item_path = path.join(destRootDir, item); - - if (fs.lstatSync(item_path).isDirectory()) { - - if (item != SYNTAXER_VERSION) { // remove old version folder - delete_dir(item_path); - } - } - } catch (error) { - } - - }); - } catch (error) { - } - }); - - - if (!fs.existsSync(SEVER_CLI)) { - copy_dir_to_sync(sourceDir, destDir); - } - else { - fsx.readdirSync(destRootDir, item => { - }); - } - - if (fs.existsSync(SEVER)) { - startServer(); - } -} - -DeploySyntaxer(); \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 62eb717..1d32244 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -154,6 +154,13 @@ export class Utils { fs.writeFileSync(file, lines.join('\n'), { encoding: 'utf8' }); } + public static editor_go_to_line(line: number): void { + let editor = vscode.window.activeTextEditor; + let range = editor.document.lineAt(line - 1).range; + editor.selection = new vscode.Selection(range.start, range.end); + editor.revealRange(range); + } + public static init(): void { // vscode: