From f879520eb6774d13a8167ba6ef62c7ac21d6da7b Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 19:38:20 +0530 Subject: [PATCH 01/11] Add support to parse string versions --- src/helpers/bg3/Version.ts | 36 ++++++++++++++++++++++++++---------- src/test/extension.test.ts | 20 ++++++++++++++++++-- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/helpers/bg3/Version.ts b/src/helpers/bg3/Version.ts index 1fce614..2e6a355 100644 --- a/src/helpers/bg3/Version.ts +++ b/src/helpers/bg3/Version.ts @@ -13,18 +13,34 @@ export class Version { /** Regular expression to match the version line in `meta.lsx` */ public static readonly lsxRegex = //; - /** - * Parse the Version number - * @param num The long Int64 Version number as specified in the `meta.lsx` file - */ - constructor(num: bigint) { - this.major = Number(num >> 55n); - this.minor = Number((num >> 47n) & 0xFFn); - this.revision = Number((num >> 31n) & 0xFFFFn); - this.build = Number(num & 0xFFFFFFn); + /** Parse the Version number */ + constructor(x: bigint); + constructor(x: string); + constructor(x: bigint | string) { + if (typeof x === 'string') { + const v = x.split("."); + this.major = parseInt(v[0]); + this.minor = parseInt(v[1]); + this.revision = parseInt(v[2]); + this.build = parseInt(v[3]); + } else { + this.major = Number(x >> 55n); + this.minor = Number((x >> 47n) & 0xFFn); + this.revision = Number((x >> 31n) & 0xFFFFn); + this.build = Number(x & 0xFFFFFFn); + } } - /** Return the string representation of the Version number. (e.g `1.0.0.0`) */ + /** @returns Int64 representation of the version number */ + toInt64(): bigint { + const major = BigInt(this.major) << 55n; + const minor = (BigInt(this.minor) << 47n) & 0xFFn; + const revision = (BigInt(this.revision) << 31n) & 0xFFFFn; + const build = (BigInt(this.build)) & 0xFFFFFFn; + return major + minor + revision + build; + } + + /** @returns String representation of the Version number. (e.g `1.0.0.0`) */ toString(): string { return `${this.major}.${this.minor}.${this.revision}.${this.build}`; } diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 1d234f5..eb606ed 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -48,7 +48,7 @@ suite('Extension Test Suite', () => { test('Conversion of Version Numbers', () => { - const testSuite = [ + const testSuite1 = [ { int64Version: 36028797018963968n, expected: "1.0.0.0" @@ -56,11 +56,27 @@ suite('Extension Test Suite', () => { // TODO: Add more tests here ... ]; - for (const t of testSuite) { + for (const t of testSuite1) { const version = new bg3.Version(t.int64Version); const actual = version.toString(); assert.strictEqual(actual, t.expected); } + const testSuite2 = [ + { + stringVersion: "1.0.0.0", + expected: 36028797018963968n + } + // TODO: Add more tests here ... + + ]; + + for (const t of testSuite2) { + const version = new bg3.Version(t.stringVersion); + const actual = version.toInt64(); + assert.strictEqual(actual, t.expected); + } + + }); }); From 630aca6b135e56d5174f69dec633687a12155d18 Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 20:02:13 +0530 Subject: [PATCH 02/11] Create Version Number Command --- package.json | 5 +++++ src/commands/generateVersionNumber.ts | 26 ++++++++++++++++++++++++++ src/commands/index.ts | 6 +++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/commands/generateVersionNumber.ts diff --git a/package.json b/package.json index 6ef6089..162ffa3 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,11 @@ "command": "bg3-modding.generateHandle", "title": "Generate Handle and insert at selection", "category": "BG3" + }, + { + "command": "bg3-modding.generateVersionNumber", + "title": "Generate the Int64 Version Number", + "category": "BG3" } ], "jsonValidation": [ diff --git a/src/commands/generateVersionNumber.ts b/src/commands/generateVersionNumber.ts new file mode 100644 index 0000000..a4ae728 --- /dev/null +++ b/src/commands/generateVersionNumber.ts @@ -0,0 +1,26 @@ +// Library +import * as vscode from 'vscode'; + +// Helpers +import { bg3, editor } from '../helpers'; + +export async function generateVersionNumber() { + + const v = await vscode.window.showInputBox({ + title: "Version", + prompt: "The version number string", + placeHolder: '1.0.0.0', + validateInput: (value) => { + if (!(/\d\.\d\.\d\.\d/.test(value))) { + return "Invalid Version Number! Format: {Major}.{Minor}.{Revision}.{Build}"; + } + } + }); + + if (!v) { return; }; + + const version = new bg3.Version(v); + const result = version.toInt64().toString(); + + editor.insertAtSelection(result); +} diff --git a/src/commands/index.ts b/src/commands/index.ts index bba6afe..58e3019 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -7,15 +7,19 @@ import * as vscode from 'vscode'; import { generateUUID } from "./generateUUID"; import { generateHandle } from './generateHandle'; +import { generateVersionNumber } from './generateVersionNumber'; + /** Enumeration of the command IDs */ enum Command { GenerateUUID = "bg3-modding.generateUUID", GenerateHandle = "bg3-modding.generateHandle", + GenerateVersionNumber = "bg3-modding.generateVersionNumber" } /** An array of disposables for the registered commands */ export const commands: vscode.Disposable[] = [ vscode.commands.registerCommand(Command.GenerateUUID, generateUUID), - vscode.commands.registerCommand(Command.GenerateHandle, generateHandle) + vscode.commands.registerCommand(Command.GenerateHandle, generateHandle), + vscode.commands.registerCommand(Command.GenerateVersionNumber, generateVersionNumber), ]; From 1c0503249fefb4d7127ea37cc409fc285280a718 Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 21:24:12 +0530 Subject: [PATCH 03/11] Handle two way conversions --- src/commands/generateVersionNumber.ts | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/commands/generateVersionNumber.ts b/src/commands/generateVersionNumber.ts index a4ae728..8c10730 100644 --- a/src/commands/generateVersionNumber.ts +++ b/src/commands/generateVersionNumber.ts @@ -4,23 +4,37 @@ import * as vscode from 'vscode'; // Helpers import { bg3, editor } from '../helpers'; +/** Convert Int64 version number to string format or vice-versa */ export async function generateVersionNumber() { + // Prompt the user for the version number const v = await vscode.window.showInputBox({ title: "Version", - prompt: "The version number string", - placeHolder: '1.0.0.0', + prompt: "Version Number", + placeHolder: 'Example: 1.0.0.0 or 36028797018963968', validateInput: (value) => { - if (!(/\d\.\d\.\d\.\d/.test(value))) { - return "Invalid Version Number! Format: {Major}.{Minor}.{Revision}.{Build}"; + if (value.includes(".")) { // String version format (1.0.0.0) + if (!(/\d+\.\d+\.\d+\.\d+/.test(value))) { // Try parsing major.minor.revision.build + return "Invalid Version Number! Format: {Major}.{Minor}.{Revision}.{Build}"; + } + } else { // BigInt format (36028797018963968) + try { + BigInt(value); // Try parsing as BigInt ... + } catch (e) { // ... if that fails, the input is invalid as it doesn't match either format + return "Invalid Version Number! Example: 1.0.0.0 or 36028797018963968"; + } } } }); - if (!v) { return; }; + // Return early if the input is empty + if (!v) { return; } - const version = new bg3.Version(v); - const result = version.toInt64().toString(); + // Convert the version from one format to the other + const result = v.includes(".") + ? new bg3.Version(v).toInt64().toString() + : new bg3.Version(BigInt(v)).toString(); + // Insert the version at the cursor selection editor.insertAtSelection(result); } From 6fa5482a4b6fd5a32f62c98a5971596f7b75e0f7 Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 21:25:43 +0530 Subject: [PATCH 04/11] Rename `generateVersionNumber` to `convertVersionNumber` to better reflect the functionality --- package.json | 4 ++-- .../{generateVersionNumber.ts => convertVersionNumber.ts} | 2 +- src/commands/index.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/commands/{generateVersionNumber.ts => convertVersionNumber.ts} (96%) diff --git a/package.json b/package.json index 162ffa3..5b1b6a0 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "category": "BG3" }, { - "command": "bg3-modding.generateVersionNumber", - "title": "Generate the Int64 Version Number", + "command": "bg3-modding.convertVersionNumber", + "title": "Convert BG3 Version Number", "category": "BG3" } ], diff --git a/src/commands/generateVersionNumber.ts b/src/commands/convertVersionNumber.ts similarity index 96% rename from src/commands/generateVersionNumber.ts rename to src/commands/convertVersionNumber.ts index 8c10730..d1be9ca 100644 --- a/src/commands/generateVersionNumber.ts +++ b/src/commands/convertVersionNumber.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import { bg3, editor } from '../helpers'; /** Convert Int64 version number to string format or vice-versa */ -export async function generateVersionNumber() { +export async function convertVersionNumber() { // Prompt the user for the version number const v = await vscode.window.showInputBox({ diff --git a/src/commands/index.ts b/src/commands/index.ts index 58e3019..e165a96 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { generateUUID } from "./generateUUID"; import { generateHandle } from './generateHandle'; -import { generateVersionNumber } from './generateVersionNumber'; +import { convertVersionNumber } from './convertVersionNumber'; /** Enumeration of the command IDs */ @@ -21,5 +21,5 @@ enum Command { export const commands: vscode.Disposable[] = [ vscode.commands.registerCommand(Command.GenerateUUID, generateUUID), vscode.commands.registerCommand(Command.GenerateHandle, generateHandle), - vscode.commands.registerCommand(Command.GenerateVersionNumber, generateVersionNumber), + vscode.commands.registerCommand(Command.GenerateVersionNumber, convertVersionNumber), ]; From 091294a9e8e649b7c1919161f2a1ac2ef779f0e8 Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 22:18:39 +0530 Subject: [PATCH 05/11] Consolidate Command Registration --- src/commands/index.ts | 16 +++++++--------- src/constants.ts | 5 +++++ 2 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 src/constants.ts diff --git a/src/commands/index.ts b/src/commands/index.ts index e165a96..45f11aa 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,5 +1,6 @@ // Library import * as vscode from 'vscode'; +import * as constants from '../constants'; // ======== // COMMANDS @@ -9,17 +10,14 @@ import { generateUUID } from "./generateUUID"; import { generateHandle } from './generateHandle'; import { convertVersionNumber } from './convertVersionNumber'; - -/** Enumeration of the command IDs */ -enum Command { - GenerateUUID = "bg3-modding.generateUUID", - GenerateHandle = "bg3-modding.generateHandle", - GenerateVersionNumber = "bg3-modding.generateVersionNumber" +/** Registers the command to VS Code */ +function registerCommand(command: (...args: any[]) => any): vscode.Disposable { + return vscode.commands.registerCommand(`${constants.EXTENSION_ID}.${command.name}`, command); } /** An array of disposables for the registered commands */ export const commands: vscode.Disposable[] = [ - vscode.commands.registerCommand(Command.GenerateUUID, generateUUID), - vscode.commands.registerCommand(Command.GenerateHandle, generateHandle), - vscode.commands.registerCommand(Command.GenerateVersionNumber, convertVersionNumber), + registerCommand(generateUUID), + registerCommand(generateHandle), + registerCommand(convertVersionNumber), ]; diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..e0b6983 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,5 @@ +// ========= +// CONSTANTS +// ========= + +export const EXTENSION_ID = "bg3-modding"; From 20a5215c6b34d776fb79c7619e9695b22d1886ab Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 22:27:42 +0530 Subject: [PATCH 06/11] Prefill the input value based on the selection --- src/commands/convertVersionNumber.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/commands/convertVersionNumber.ts b/src/commands/convertVersionNumber.ts index d1be9ca..be80196 100644 --- a/src/commands/convertVersionNumber.ts +++ b/src/commands/convertVersionNumber.ts @@ -12,6 +12,9 @@ export async function convertVersionNumber() { title: "Version", prompt: "Version Number", placeHolder: 'Example: 1.0.0.0 or 36028797018963968', + // Pre-fill the value with the currently selected text + value: vscode.window.activeTextEditor?.document.getText(vscode.window.activeTextEditor.selection), + // Perform validation on the input value validateInput: (value) => { if (value.includes(".")) { // String version format (1.0.0.0) if (!(/\d+\.\d+\.\d+\.\d+/.test(value))) { // Try parsing major.minor.revision.build From d419ce55133af6c3647d3bcf4182f64cdda4000b Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 22:30:24 +0530 Subject: [PATCH 07/11] Create `getSelection` helper for the editor --- src/helpers/editor.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/helpers/editor.ts b/src/helpers/editor.ts index 9341e17..fe3e4e8 100644 --- a/src/helpers/editor.ts +++ b/src/helpers/editor.ts @@ -23,3 +23,11 @@ export function insertAtSelection(text: string) { }); }); } + +/** + * Returns the currently selected text in the editor. Returns `undefined` + * if nothing has been selected. + */ +export function getSelection(): string | undefined { + return vscode.window.activeTextEditor?.document.getText(vscode.window.activeTextEditor.selection); +} From 35f3696b8ad65a553cf006cad9d01158baeaea5a Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 22:30:50 +0530 Subject: [PATCH 08/11] Make use of the `getSelection` helper function --- src/commands/convertVersionNumber.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/convertVersionNumber.ts b/src/commands/convertVersionNumber.ts index be80196..eed5176 100644 --- a/src/commands/convertVersionNumber.ts +++ b/src/commands/convertVersionNumber.ts @@ -13,7 +13,7 @@ export async function convertVersionNumber() { prompt: "Version Number", placeHolder: 'Example: 1.0.0.0 or 36028797018963968', // Pre-fill the value with the currently selected text - value: vscode.window.activeTextEditor?.document.getText(vscode.window.activeTextEditor.selection), + value: editor.getSelection(), // Perform validation on the input value validateInput: (value) => { if (value.includes(".")) { // String version format (1.0.0.0) From e3f0f057f31690b78611922011bdaa5aa536fa6f Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 22:41:21 +0530 Subject: [PATCH 09/11] Refactor: Legibility --- src/commands/convertVersionNumber.ts | 3 +++ src/constants.ts | 1 + src/helpers/bg3/Version.ts | 7 ++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/commands/convertVersionNumber.ts b/src/commands/convertVersionNumber.ts index eed5176..6c5a7f6 100644 --- a/src/commands/convertVersionNumber.ts +++ b/src/commands/convertVersionNumber.ts @@ -12,8 +12,10 @@ export async function convertVersionNumber() { title: "Version", prompt: "Version Number", placeHolder: 'Example: 1.0.0.0 or 36028797018963968', + // Pre-fill the value with the currently selected text value: editor.getSelection(), + // Perform validation on the input value validateInput: (value) => { if (value.includes(".")) { // String version format (1.0.0.0) @@ -40,4 +42,5 @@ export async function convertVersionNumber() { // Insert the version at the cursor selection editor.insertAtSelection(result); + } diff --git a/src/constants.ts b/src/constants.ts index e0b6983..a22599b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,4 +2,5 @@ // CONSTANTS // ========= +/** ID of the extension. Must match the `package.json` */ export const EXTENSION_ID = "bg3-modding"; diff --git a/src/helpers/bg3/Version.ts b/src/helpers/bg3/Version.ts index 2e6a355..0c05e73 100644 --- a/src/helpers/bg3/Version.ts +++ b/src/helpers/bg3/Version.ts @@ -17,18 +17,23 @@ export class Version { constructor(x: bigint); constructor(x: string); constructor(x: bigint | string) { + + // Use the string constructor ... if (typeof x === 'string') { const v = x.split("."); this.major = parseInt(v[0]); this.minor = parseInt(v[1]); this.revision = parseInt(v[2]); this.build = parseInt(v[3]); - } else { + } + // ... else, use the bigint constructor. + else { this.major = Number(x >> 55n); this.minor = Number((x >> 47n) & 0xFFn); this.revision = Number((x >> 31n) & 0xFFFFn); this.build = Number(x & 0xFFFFFFn); } + } /** @returns Int64 representation of the version number */ From 8da9a08829049bb39b3a029cabf4004e9e4f1088 Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 22:48:53 +0530 Subject: [PATCH 10/11] Add more tests --- src/test/extension.test.ts | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index eb606ed..8377ed2 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -43,40 +43,53 @@ suite('Extension Test Suite', () => { const actualHandle = bg3.convertToHandle(t.testUUID); assert.strictEqual(actualHandle, t.expectedHandle); } + }); test('Conversion of Version Numbers', () => { - const testSuite1 = [ + const testSuiteInt64 = [ { int64Version: 36028797018963968n, expected: "1.0.0.0" + }, + { + int64Version: 36310278438125572n, + expected: "1.2.3.4" + }, + { + int64Version: 36451024516415602n, + expected: "1.3.7.114" } - // TODO: Add more tests here ... ]; - for (const t of testSuite1) { + for (const t of testSuiteInt64) { const version = new bg3.Version(t.int64Version); const actual = version.toString(); assert.strictEqual(actual, t.expected); } - const testSuite2 = [ + const testSuiteStrings = [ { stringVersion: "1.0.0.0", expected: 36028797018963968n + }, + { + stringVersion: "1.2.3.4", + expected: 36310278438125572n + }, + { + stringVersion: "1.3.7.114", + expected: 36451024516415602n } - // TODO: Add more tests here ... - ]; - for (const t of testSuite2) { + for (const t of testSuiteStrings) { const version = new bg3.Version(t.stringVersion); const actual = version.toInt64(); assert.strictEqual(actual, t.expected); } - }); }); From 0977df775adbecda1fc77a65f6a3268ae1a52f1a Mon Sep 17 00:00:00 2001 From: Shresht Srivastav <59516096+Shresht7@users.noreply.github.com> Date: Mon, 25 Dec 2023 22:48:56 +0530 Subject: [PATCH 11/11] Fix: Failed conversion of version number to `Int64` --- src/helpers/bg3/Version.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers/bg3/Version.ts b/src/helpers/bg3/Version.ts index 0c05e73..2887b73 100644 --- a/src/helpers/bg3/Version.ts +++ b/src/helpers/bg3/Version.ts @@ -39,9 +39,9 @@ export class Version { /** @returns Int64 representation of the version number */ toInt64(): bigint { const major = BigInt(this.major) << 55n; - const minor = (BigInt(this.minor) << 47n) & 0xFFn; - const revision = (BigInt(this.revision) << 31n) & 0xFFFFn; - const build = (BigInt(this.build)) & 0xFFFFFFn; + const minor = (BigInt(this.minor) << 47n); + const revision = (BigInt(this.revision) << 31n); + const build = (BigInt(this.build)); return major + minor + revision + build; }