diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7dce78bf..9324874c 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -21,6 +21,7 @@ jobs: - name: Check types run: | + node configtypes.js --check npm run check-types - name: Lint diff --git a/configtypes.js b/configtypes.js new file mode 100644 index 00000000..44fc1d61 --- /dev/null +++ b/configtypes.js @@ -0,0 +1,115 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; + +const ROOT = import.meta.dirname; +const PACKAGE_JSON = path.join(ROOT, "package.json"); +const OUT_FILE = path.join(ROOT, "src", "@types", "configtypes.d.ts"); +const OUT_FILE_REL = path.relative(ROOT, OUT_FILE); + +const pkg = JSON.parse(fs.readFileSync(PACKAGE_JSON, "utf8")); +const configurations = pkg.contributes?.configuration ?? []; + +function schemaTypeToTs(schema, nesting = 1) { + if (!schema) return "unknown"; + + if (Array.isArray(schema.type)) { + return schema.type.map((t) => schemaTypeToTs({ type: t })).join(" | "); + } + + if (schema.enum) { + return schema.enum.map((v) => JSON.stringify(v)).join(" | "); + } + + switch (schema.type) { + case "boolean": + return "boolean"; + case "string": + return "string"; + case "number": + return "number"; + case "array": { + const itemType = schema.items ? schemaTypeToTs(schema.items) : "unknown"; + const needsParens = itemType.includes("|"); + return needsParens ? `(${itemType})[]` : `${itemType}[]`; + } + case "object": { + if (!schema.additionalProperties && !schema.properties && !schema.propertyNames) { + return "Record"; + } + const spaceZero = " ".repeat(nesting); + const space = spaceZero + " "; + let obj = "{\n"; + if (schema.additionalProperties) { + const valueType = schemaTypeToTs(schema.additionalProperties); + obj += space + `[key: string]: ${valueType};\n`; + } + if (schema.properties) { + for (const prop in schema.properties) { + const valueType = schemaTypeToTs(schema.properties[prop], nesting + 1); + obj += space + `${prop}: ${valueType};\n`; + } + } + obj += spaceZero + "}"; + return obj; + } + default: + return "unknown"; + } +} + +function getDeprecation(schema) { + if (schema.deprecationMessage) { + return schema.deprecationMessage; + } + if (schema.markdownDeprecationMessage) { + return schema.markdownDeprecationMessage.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/[`#*]/g, ""); + } + return null; +} + +const activeEntries = []; +const deprecatedEntries = []; + +for (const block of configurations) { + const props = block.properties ?? {}; + for (const [key, schema] of Object.entries(props)) { + const tsType = schemaTypeToTs(schema); + const deprecation = getDeprecation(schema); + + if (deprecation) { + deprecatedEntries.push(` /** @deprecated ${deprecation} */`); + deprecatedEntries.push(` ${JSON.stringify(key)}: ${tsType};`); + } else { + activeEntries.push(` ${JSON.stringify(key)}: ${tsType};`); + } + } +} + +const output = `// AUTO-GENERATED FILE +// DO NOT EDIT MANUALLY +// Edit package.json instead and re-run/edit configtypes.js to update +// Generated from package.json contributes.configuration + +export type ExtensionConfigGenerated = { +${activeEntries.join("\n")} +}; + +export type DeprecatedConfigGenerated = { +${deprecatedEntries.join("\n")} +}; +`; + +fs.mkdirSync(path.dirname(OUT_FILE), { recursive: true }); + +if (process.argv.includes("--check")) { + const existing = fs.existsSync(OUT_FILE) ? fs.readFileSync(OUT_FILE, "utf8") : null; + if (existing !== output) { + console.log("%s: OUT OF DATE.", OUT_FILE_REL); + console.log("Regenerate by running 'node configtypes.js' or edit the generator script."); + process.exit(1); + } + console.log("checked", OUT_FILE_REL); +} else { + fs.writeFileSync(OUT_FILE, output, "utf8"); + console.log("generated", OUT_FILE_REL); +} diff --git a/package.json b/package.json index f09724ee..9ffda11b 100644 --- a/package.json +++ b/package.json @@ -44,10 +44,10 @@ "compile": "npm run check-types && npm run lint && node esbuild.js", "watch": "npm-run-all -p watch:*", "watch:esbuild": "node esbuild.js --watch", - "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", + "watch:tsc": "node configtypes.js && tsc --noEmit --watch --project tsconfig.json", "package": "npm run check-types && npm run lint && node esbuild.js --production", "pkg": "vsce package", - "check-types": "tsc --noEmit", + "check-types": "node configtypes.js && tsc --noEmit", "lint": "prettier . --check" }, "dependencies": { diff --git a/src/@types/configtypes.d.ts b/src/@types/configtypes.d.ts new file mode 100644 index 00000000..dd426e7b --- /dev/null +++ b/src/@types/configtypes.d.ts @@ -0,0 +1,296 @@ +// AUTO-GENERATED FILE +// DO NOT EDIT MANUALLY +// Edit package.json instead and re-run/edit configtypes.js to update +// Generated from package.json contributes.configuration + +export type ExtensionConfigGenerated = { + "vscord.enable": boolean; + "vscord.app.name": "Code" | "Visual Studio Code" | "VSCodium" | "Antigravity" | "Cursor" | "Custom"; + "vscord.app.id": string; + "vscord.app.privacyMode.enable": boolean; + "vscord.app.whitelistEnabled": boolean; + "vscord.app.whitelistIsBlacklist": boolean; + "vscord.app.whitelist": string[]; + "vscord.status.showElapsedTime": boolean; + "vscord.status.resetElapsedTimePerFile": boolean; + "vscord.status.problems.enabled": boolean; + "vscord.status.problems.text": string; + "vscord.status.problems.countedSeverities": ("error" | "warning" | "info" | "hint")[]; + "vscord.status.idle.check": boolean; + "vscord.status.idle.enabled": boolean; + "vscord.status.idle.disconnectOnIdle": boolean; + "vscord.status.idle.resetElapsedTime": boolean; + "vscord.status.idle.timeout": number; + "vscord.ignore.workspaces": string[]; + "vscord.ignore.workspacesText": string | Record; + "vscord.ignore.repositories": string[]; + "vscord.ignore.organizations": string[]; + "vscord.ignore.gitHosts": string[]; + "vscord.status.details.enabled": boolean; + "vscord.status.details.idle.enabled": boolean; + "vscord.status.details.text.idle": string; + "vscord.status.details.text.editing": string; + "vscord.status.details.text.debugging": string; + "vscord.status.details.text.viewing": string; + "vscord.status.details.text.notInFile": string; + "vscord.status.details.text.noWorkSpaceText": string; + "vscord.status.state.enabled": boolean; + "vscord.status.state.debugging.enabled": boolean; + "vscord.status.state.idle.enabled": boolean; + "vscord.status.state.text.idle": string; + "vscord.status.state.text.editing": string; + "vscord.status.state.text.debugging": string; + "vscord.status.state.text.viewing": string; + "vscord.status.state.text.notInFile": string; + "vscord.status.state.text.noWorkspaceFound": string; + "vscord.status.image.large.idle.key": string; + "vscord.status.image.large.idle.text": string; + "vscord.status.image.large.viewing.key": string; + "vscord.status.image.large.viewing.text": string; + "vscord.status.image.large.editing.key": string; + "vscord.status.image.large.editing.text": string; + "vscord.status.image.large.debugging.key": string; + "vscord.status.image.large.debugging.text": string; + "vscord.status.image.large.notInFile.key": string; + "vscord.status.image.large.notInFile.text": string; + "vscord.status.image.small.idle.key": string; + "vscord.status.image.small.idle.text": string; + "vscord.status.image.small.viewing.key": string; + "vscord.status.image.small.viewing.text": string; + "vscord.status.image.small.editing.key": string; + "vscord.status.image.small.editing.text": string; + "vscord.status.image.small.debugging.key": string; + "vscord.status.image.small.debugging.text": string; + "vscord.status.image.small.notInFile.key": string; + "vscord.status.image.small.notInFile.text": string; + "vscord.status.buttons": { + button1: { + enabled: boolean; + active: { + enabled: boolean; + label: string; + url: string; + }; + inactive: { + enabled: boolean; + label: string; + url: string; + }; + idle: { + enabled: boolean; + label: string; + url: string; + }; + git: { + active: { + enabled: boolean; + label: string; + url: string; + }; + inactive: { + enabled: boolean; + label: string; + url: string; + }; + idle: { + enabled: boolean; + label: string; + url: string; + }; + }; + }; + button2: { + enabled: boolean; + active: { + enabled: boolean; + label: string; + url: string; + }; + inactive: { + enabled: boolean; + label: string; + url: string; + }; + idle: { + enabled: boolean; + label: string; + url: string; + }; + git: { + active: { + enabled: boolean; + label: string; + url: string; + }; + inactive: { + enabled: boolean; + label: string; + url: string; + }; + idle: { + enabled: boolean; + label: string; + url: string; + }; + }; + }; + }; + "vscord.status.buttons.button1.enabled": boolean; + "vscord.status.buttons.button1.active.enabled": boolean; + "vscord.status.buttons.button1.active.label": string; + "vscord.status.buttons.button1.active.url": string; + "vscord.status.buttons.button1.inactive.enabled": boolean; + "vscord.status.buttons.button1.inactive.label": string; + "vscord.status.buttons.button1.inactive.url": string; + "vscord.status.buttons.button1.idle.enabled": boolean; + "vscord.status.buttons.button1.idle.label": string; + "vscord.status.buttons.button1.idle.url": string; + "vscord.status.buttons.button1.git.active.enabled": boolean; + "vscord.status.buttons.button1.git.active.label": string; + "vscord.status.buttons.button1.git.active.url": string; + "vscord.status.buttons.button1.git.inactive.enabled": boolean; + "vscord.status.buttons.button1.git.inactive.label": string; + "vscord.status.buttons.button1.git.inactive.url": string; + "vscord.status.buttons.button1.git.idle.enabled": boolean; + "vscord.status.buttons.button1.git.idle.label": string; + "vscord.status.buttons.button1.git.idle.url": string; + "vscord.status.buttons.button2.enabled": boolean; + "vscord.status.buttons.button2.active.enabled": boolean; + "vscord.status.buttons.button2.active.label": string; + "vscord.status.buttons.button2.active.url": string; + "vscord.status.buttons.button2.inactive.enabled": boolean; + "vscord.status.buttons.button2.inactive.label": string; + "vscord.status.buttons.button2.inactive.url": string; + "vscord.status.buttons.button2.idle.enabled": boolean; + "vscord.status.buttons.button2.idle.label": string; + "vscord.status.buttons.button2.idle.url": string; + "vscord.status.buttons.button2.git.active.enabled": boolean; + "vscord.status.buttons.button2.git.active.label": string; + "vscord.status.buttons.button2.git.active.url": string; + "vscord.status.buttons.button2.git.inactive.enabled": boolean; + "vscord.status.buttons.button2.git.inactive.label": string; + "vscord.status.buttons.button2.git.inactive.url": string; + "vscord.status.buttons.button2.git.idle.enabled": boolean; + "vscord.status.buttons.button2.git.idle.label": string; + "vscord.status.buttons.button2.git.idle.url": string; + "vscord.file.size.round": number; + "vscord.file.size.spacer": string; + "vscord.behaviour.additionalFileMapping": { + [key: string]: string; + }; + "vscord.behaviour.suppressNotifications": boolean; + "vscord.behaviour.suppressRpcCouldNotConnect": boolean; + "vscord.behaviour.statusBarAlignment": "Right" | "Left"; + "vscord.file.size.humanReadable": boolean; + "vscord.file.size.standard": "iec" | "jedec"; + "vscord.behaviour.debug": boolean; +}; + +export type DeprecatedConfigGenerated = { + /** @deprecated Use the built-in setting */ + "vscord.enabled": boolean; + /** @deprecated Deprecated: Please use vscord.app.id instead. */ + "rpc.id": string; + /** @deprecated Deprecated: Please use vscord.app.name instead. */ + "rpc.appName": string; + /** @deprecated Deprecated: Please use vscord.enabled instead. */ + "rpc.enabled": boolean; + /** @deprecated Deprecated: Please use vscord.status.details.text.editing instead. */ + "rpc.detailsEditing": string; + /** @deprecated Deprecated: Please use vscord.status.details.text.idle instead. */ + "rpc.detailsIdling": string; + /** @deprecated Deprecated: Please use vscord.status.details.text.debugging instead. */ + "rpc.detailsDebugging": string; + /** @deprecated Deprecated: Please use vscord.status.details.text.viewing instead. */ + "rpc.detailsViewing": string; + /** @deprecated Deprecated: Please use vscord.status.state.text.editing instead. */ + "rpc.lowerDetailsEditing": string; + /** @deprecated Deprecated: Please use vscord.status.state.text.idle instead. */ + "rpc.lowerDetailsIdling": string; + /** @deprecated Deprecated: Please use vscord.status.state.text.debugging instead. */ + "rpc.lowerDetailsDebugging": string; + /** @deprecated Deprecated: Please use vscord.status.state.text.viewing instead. */ + "rpc.lowerDetailsViewing": string; + /** @deprecated Deprecated: Please use vscord.status.state.text.noWorkspaceFound instead. */ + "rpc.lowerDetailsNoWorkspaceFound": string; + /** @deprecated Deprecated: Please use vscord.status.image instead. */ + "rpc.baseImageLink": string; + /** @deprecated Deprecated: Please use vscord.status.image instead. */ + "rpc.largeImage": string; + /** @deprecated Deprecated: Please use vscord.status.image.small.idle.key instead. */ + "rpc.largeImageIdling": string; + /** @deprecated Deprecated: Please use vscord.status.image.small instead. */ + "rpc.smallImage": string; + /** @deprecated Deprecated: Please use vscord.status.showElapsedTime instead. */ + "rpc.removeElapsedTime": boolean; + /** @deprecated Deprecated: Please use vscord.status.details.enabled instead. */ + "rpc.removeDetails": boolean; + /** @deprecated Deprecated: Please use vscord.status.details instead. */ + "rpc.removeLowerDetails": boolean; + /** @deprecated Deprecated: Please use vscord.status.details.text.idle instead. */ + "rpc.removeLowerDetailsIdling": boolean; + /** @deprecated Deprecated: Please use vscord.status.problems.enabled instead. */ + "rpc.showProblems": boolean; + /** @deprecated Deprecated: Please use vscord.status.problems.text instead. */ + "rpc.problemsText": string; + /** @deprecated Deprecated: Please use vscord.ignore.workspaces instead. */ + "rpc.ignoreWorkspaces": unknown[]; + /** @deprecated Deprecated: Please use vscord.ignore.workspacesText instead. */ + "rpc.ignoreWorkspacesText": string | Record; + /** @deprecated Deprecated: Please use vscord.status.idle.enabled instead. */ + "rpc.checkIdle": boolean; + /** @deprecated Deprecated: Please use vscord.status.idle.disconnectOnIdle instead. */ + "rpc.disconnectOnIdle": boolean; + /** @deprecated Deprecated: Please use vscord.status.idle.resetElapsedTime instead. */ + "rpc.resetElapsedTimeAfterIdle": boolean; + /** @deprecated Deprecated: Please use vscord.status.idle.timeout instead. */ + "rpc.idleTimeout": number; + /** @deprecated Deprecated: Please use vscord.status.image.small.idle.text instead. */ + "rpc.idleText": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.enabled instead. */ + "rpc.buttonEnabled": boolean; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.active.label instead. */ + "rpc.buttonActiveLabel": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.git.label instead. */ + "vscord.status.button.active.enabled": boolean; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.git.label instead. */ + "vscord.status.button.active.label": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.git.url instead. */ + "vscord.status.button.active.url": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.idle.label instead. */ + "vscord.status.button.idle.enabled": boolean; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.idle.label instead. */ + "vscord.status.button.idle.label": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.idle.url instead. */ + "vscord.status.button.idle.url": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.inactive.label instead. */ + "vscord.status.button.inactive.enabled": boolean; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.inactive.label instead. */ + "vscord.status.button.inactive.label": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.inactive.url instead. */ + "vscord.status.button.inactive.url": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.active.url instead. */ + "rpc.buttonActiveUrl": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.inactive.label instead. */ + "rpc.buttonInactiveLabel": string; + /** @deprecated Deprecated: Please use vscord.status.buttons.button1.inactive.url instead. */ + "rpc.buttonInactiveUrl": string; + /** @deprecated Deprecated: Please use vscord.ignore.repositories instead. */ + "rpc.ignoreRepositories": string[]; + /** @deprecated Deprecated: Please use vscord.ignore.organizations instead. */ + "rpc.ignoreOrganizations": string[]; + /** @deprecated Deprecated: Please use vscord.ignore.gitHosts instead. */ + "rpc.ignoreGitHosts": string[]; + /** @deprecated Deprecated: Please use vscord.behaviour.suppressNotifications instead. */ + "rpc.suppressNotifications": boolean; + /** @deprecated Deprecated */ + "rpc.prioritizeLanguagesOverExtensions": boolean; + /** @deprecated Deprecated: Please use vscord.behaviour.size.humanReadable instead. */ + "rpc.fileSizeHumanReadable": boolean; + /** @deprecated Deprecated: Please use vscord.file.size.standard instead. */ + "rpc.fileSizeSpec": "si" | "iec" | "jedec"; + /** @deprecated Deprecated */ + "rpc.fileSizeFixed": number; + /** @deprecated Deprecated: Please use vscord.file.size.spacer instead. */ + "rpc.fileSizeSpacer": string; +}; diff --git a/src/activity.ts b/src/activity.ts index 9f8262c2..3d666bae 100644 --- a/src/activity.ts +++ b/src/activity.ts @@ -1,7 +1,8 @@ +import type { SetActivity } from "@xhayper/discord-rpc"; +import type { ExtensionConfigGenerated } from "./@types/configtypes.d.ts"; +import type { GatewayActivityButton } from "discord-api-types/v10"; import { resolveLangName, toLower, toTitle, toUpper, getArticle } from "./helpers/resolveLangName"; -import { type GatewayActivityButton } from "discord-api-types/v10"; -import { type SetActivity } from "@xhayper/discord-rpc"; -import { CONFIG_KEYS, FAKE_EMPTY } from "./constants"; +import { FAKE_EMPTY } from "./constants"; import { getFileSize } from "./helpers/getFileSize"; import { isExcluded } from "./helpers/isExcluded"; import { isObject } from "./helpers/isObject"; @@ -28,15 +29,8 @@ export enum CURRENT_STATUS { VIEWING = "viewing" } -export enum PROBLEM_LEVEL { - ERROR = "error", - WARNING = "warning", - INFO = "info", - HINT = "hint" -} - // TODO: move this to data class -const COUNTED_SEVERITIES: { [key in PROBLEM_LEVEL]: number } = { +const COUNTED_SEVERITIES = { error: 0, warning: 0, info: 0, @@ -89,50 +83,50 @@ export const activity = async ( if ( isIdling && - config.get(CONFIG_KEYS.Status.Idle.DisconnectOnIdle) && - config.get(CONFIG_KEYS.Status.Idle.ResetElapsedTime) + config.get("vscord.status.idle.disconnectOnIdle") && + config.get("vscord.status.idle.resetElapsedTime") ) { delete presence.startTimestamp; return {}; } - if (isIdling && !config.get(CONFIG_KEYS.Status.Idle.Enabled)) return {}; + if (isIdling && !config.get("vscord.status.idle.enabled")) return {}; - if (config.get(CONFIG_KEYS.Status.ShowElapsedTime)) { - presence.startTimestamp = config.get(CONFIG_KEYS.Status.ResetElapsedTimePerFile) + if (config.get("vscord.status.showElapsedTime")) { + presence.startTimestamp = config.get("vscord.status.resetElapsedTimePerFile") ? Date.now() : (previous.startTimestamp ?? Date.now()); } else { delete presence.startTimestamp; } - const detailsEnabled = config.get(CONFIG_KEYS.Status.Details.Enabled); - const detailsIdleEnabled = config.get(CONFIG_KEYS.Status.Details.Idle.Enabled); - const stateEnabled = config.get(CONFIG_KEYS.Status.State.Enabled); - const stateIdleEnabled = config.get(CONFIG_KEYS.Status.State.Idle.Enabled); - const privacyModeEnabled = config.get(CONFIG_KEYS.App.PrivacyMode) as boolean; + const detailsEnabled = config.get("vscord.status.details.enabled"); + const detailsIdleEnabled = config.get("vscord.status.details.idle.enabled"); + const stateEnabled = config.get("vscord.status.state.enabled"); + const stateIdleEnabled = config.get("vscord.status.state.idle.enabled"); + const privacyModeEnabled = config.get("vscord.app.privacyMode.enable") ?? false; const gitRepo = dataClass.gitRemoteUrl?.toString("https").replace(/\.git$/, ""); const gitOrg = dataClass.gitRemoteUrl?.organization ?? dataClass.gitRemoteUrl?.owner; const gitHost = dataClass.gitRemoteUrl?.source; - const isRepositoryExcluded = !!gitRepo && isExcluded(config.get(CONFIG_KEYS.Ignore.Repositories)!, gitRepo); - const isOrganizationExcluded = !!gitOrg && isExcluded(config.get(CONFIG_KEYS.Ignore.Organizations)!, gitOrg); - const isGitHostExcluded = !!gitHost && isExcluded(config.get(CONFIG_KEYS.Ignore.GitHosts)!, gitHost); + const isRepositoryExcluded = !!gitRepo && isExcluded(config.get("vscord.ignore.repositories")!, gitRepo); + const isOrganizationExcluded = !!gitOrg && isExcluded(config.get("vscord.ignore.organizations")!, gitOrg); + const isGitHostExcluded = !!gitHost && isExcluded(config.get("vscord.ignore.gitHosts")!, gitHost); const isGitExcluded = isRepositoryExcluded || isOrganizationExcluded || isGitHostExcluded || privacyModeEnabled; let isWorkspaceExcluded = dataClass.workspaceFolder !== undefined && - isExcluded(config.get(CONFIG_KEYS.Ignore.Workspaces)!, dataClass.workspaceFolder.uri.fsPath); + isExcluded(config.get("vscord.ignore.workspaces")!, dataClass.workspaceFolder.uri.fsPath); if (!isWorkspaceExcluded) isWorkspaceExcluded = dataClass.workspaceName !== undefined && - isExcluded(config.get(CONFIG_KEYS.Ignore.Workspaces)!, dataClass.workspaceName); + isExcluded(config.get("vscord.ignore.workspaces")!, dataClass.workspaceName); const isNotInFile = !isWorkspaceExcluded && !dataClass.editor; - const isDebugging = config.get(CONFIG_KEYS.Status.State.Debugging.Enabled) && !!debug.activeDebugSession; + const isDebugging = config.get("vscord.status.state.debugging.enabled") && !!debug.activeDebugSession; isViewing = !isDebugging && isViewing; let status: CURRENT_STATUS; @@ -142,9 +136,9 @@ export const activity = async ( else if (isViewing) status = CURRENT_STATUS.VIEWING; else status = CURRENT_STATUS.EDITING; - const PROBLEMS = config.get(CONFIG_KEYS.Status.Problems.Enabled) + const PROBLEMS = config.get("vscord.status.problems.enabled") ? await replaceFileInfo( - replaceGitInfo(replaceAppInfo(config.get(CONFIG_KEYS.Status.Problems.Text)!), isGitExcluded), + replaceGitInfo(replaceAppInfo(config.get("vscord.status.problems.text") ?? ""), isGitExcluded), isWorkspaceExcluded, dataClass.editor?.document, dataClass.editor?.selection @@ -182,12 +176,12 @@ export const activity = async ( }; let workspaceExcludedText = "No workspace ignore text provided."; - const ignoreWorkspacesText = config.get(CONFIG_KEYS.Ignore.WorkspacesText)!; + const ignoreWorkspacesText = config.get("vscord.ignore.workspacesText") ?? ""; if (isObject(ignoreWorkspacesText)) { workspaceExcludedText = (dataClass.workspaceFolder - ? await replaceAllText(ignoreWorkspacesText[dataClass.workspaceFolder.name]) + ? await replaceAllText(String(ignoreWorkspacesText[dataClass.workspaceFolder.name])) : undefined) ?? workspaceExcludedText; } else { const text = await replaceAllText(ignoreWorkspacesText); @@ -207,68 +201,65 @@ export const activity = async ( case CURRENT_STATUS.IDLE: { if (!isWorkspaceExcluded) { if (detailsIdleEnabled && detailsEnabled) - details = await replaceAllText(config.get(CONFIG_KEYS.Status.Details.Text.Idle)!); + details = await replaceAllText(config.get("vscord.status.details.text.idle")!); if (stateIdleEnabled && stateEnabled) - state = await replaceAllText(config.get(CONFIG_KEYS.Status.State.Text.Idle)!); + state = await replaceAllText(config.get("vscord.status.state.text.idle")!); } - largeImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.Idle.Key)!); - largeImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.Idle.Text)!); - smallImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.Idle.Key)!); - smallImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.Idle.Text)!); + largeImageKey = await replaceAllText(config.get("vscord.status.image.large.idle.key")!); + largeImageText = await replaceAllText(config.get("vscord.status.image.large.idle.text")!); + smallImageKey = await replaceAllText(config.get("vscord.status.image.small.idle.key")!); + smallImageText = await replaceAllText(config.get("vscord.status.image.small.idle.text")!); break; } case CURRENT_STATUS.EDITING: { if (!isWorkspaceExcluded) { - if (detailsEnabled) - details = await replaceAllText(config.get(CONFIG_KEYS.Status.Details.Text.Editing)!); - if (stateEnabled) state = await replaceAllText(config.get(CONFIG_KEYS.Status.State.Text.Editing)!); + if (detailsEnabled) details = await replaceAllText(config.get("vscord.status.details.text.editing")!); + if (stateEnabled) state = await replaceAllText(config.get("vscord.status.state.text.editing")!); } - largeImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.Editing.Key)!); - largeImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.Editing.Text)!); + largeImageKey = await replaceAllText(config.get("vscord.status.image.large.editing.key")!); + largeImageText = await replaceAllText(config.get("vscord.status.image.large.editing.text")!); - smallImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.Editing.Key)!); - smallImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.Editing.Text)!); + smallImageKey = await replaceAllText(config.get("vscord.status.image.small.editing.key")!); + smallImageText = await replaceAllText(config.get("vscord.status.image.small.editing.text")!); break; } case CURRENT_STATUS.DEBUGGING: { if (!isWorkspaceExcluded) { - if (detailsEnabled) - details = await replaceAllText(config.get(CONFIG_KEYS.Status.Details.Text.Debugging)!); - if (stateEnabled) state = await replaceAllText(config.get(CONFIG_KEYS.Status.State.Text.Debugging)!); + if (detailsEnabled) details = await replaceAllText(config.get("vscord.status.details.text.debugging")!); + if (stateEnabled) state = await replaceAllText(config.get("vscord.status.state.text.debugging")!); } - largeImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.Debugging.Key)!); - largeImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.Debugging.Text)!); + largeImageKey = await replaceAllText(config.get("vscord.status.image.large.debugging.key")!); + largeImageText = await replaceAllText(config.get("vscord.status.image.large.debugging.text")!); - smallImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.Debugging.Key)!); - smallImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.Debugging.Text)!); + smallImageKey = await replaceAllText(config.get("vscord.status.image.small.debugging.key")!); + smallImageText = await replaceAllText(config.get("vscord.status.image.small.debugging.text")!); break; } case CURRENT_STATUS.VIEWING: { if (!isWorkspaceExcluded) { - if (detailsEnabled) - details = await replaceAllText(config.get(CONFIG_KEYS.Status.Details.Text.Viewing)!); - if (stateEnabled) state = await replaceAllText(config.get(CONFIG_KEYS.Status.State.Text.Viewing)!); + if (detailsEnabled) details = await replaceAllText(config.get("vscord.status.details.text.viewing")!); + if (stateEnabled) state = await replaceAllText(config.get("vscord.status.state.text.viewing")!); } - largeImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.Viewing.Key)!); - largeImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.Viewing.Text)!); + largeImageKey = await replaceAllText(config.get("vscord.status.image.large.viewing.key")!); + largeImageText = await replaceAllText(config.get("vscord.status.image.large.viewing.text")!); - smallImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.Viewing.Key)!); - smallImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.Viewing.Text)!); + smallImageKey = await replaceAllText(config.get("vscord.status.image.small.viewing.key")!); + smallImageText = await replaceAllText(config.get("vscord.status.image.small.viewing.text")!); break; } case CURRENT_STATUS.NOT_IN_FILE: { - if (detailsEnabled) details = await replaceAllText(config.get(CONFIG_KEYS.Status.Details.Text.NotInFile)!); - if (stateEnabled) state = await replaceAllText(config.get(CONFIG_KEYS.Status.State.Text.NotInFile)!); + if (detailsEnabled) details = await replaceAllText(config.get("vscord.status.details.text.notInFile")!); + if (stateEnabled) state = await replaceAllText(config.get("vscord.status.state.text.notInFile")!); - largeImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.NotInFile.Key)!); - largeImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Large.NotInFile.Text)!); + largeImageKey = await replaceAllText(config.get("vscord.status.image.large.notInFile.key")!); + largeImageText = await replaceAllText(config.get("vscord.status.image.large.notInFile.text")!); - smallImageKey = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.NotInFile.Key)!); - smallImageText = await replaceAllText(config.get(CONFIG_KEYS.Status.Image.Small.NotInFile.Text)!); + smallImageKey = await replaceAllText(config.get("vscord.status.image.small.notInFile.key")!); + smallImageText = await replaceAllText(config.get("vscord.status.image.small.notInFile.text")!); break; } } @@ -301,22 +292,24 @@ async function createButton( currentButton: "Button1" | "Button2" ): Promise { const config = getConfig(); - const currentState = CONFIG_KEYS.Status.Buttons[currentButton]; - const configKeyEnabled = - isGit && state != "Inactive" ? currentState.Git[state].Enabled : currentState[state].Enabled; - const enabled = config.get(configKeyEnabled); + + const b = ({ Button1: "button1", Button2: "button2" } as const)[currentButton]; + const g = isGit ? (".git" as const) : ("" as const); + const s = ({ Idle: "idle", Active: "active", Inactive: "inactive" } as const)[state]; + + const keyEnabled = `vscord.status.buttons.${b}${g}.${s}.enabled` as const satisfies keyof ExtensionConfigGenerated; + const keyLabel = `vscord.status.buttons.${b}${g}.${s}.label` as const satisfies keyof ExtensionConfigGenerated; + const keyUrl = `vscord.status.buttons.${b}${g}.${s}.url` as const satisfies keyof ExtensionConfigGenerated; + + const enabled = config.get(keyEnabled); logInfo("[activity.ts] createButton(): enabled", enabled); if (!enabled) { return undefined; } return { - label: await replaceAllText( - config.get(isGit && state != "Inactive" ? currentState.Git[state].Label : currentState[state].Label)! - ), - url: await replaceAllText( - config.get(isGit && state != "Inactive" ? currentState.Git[state].Url : currentState[state].Url)! - ) + label: await replaceAllText(config.get(keyLabel)!), + url: await replaceAllText(config.get(keyUrl)!) }; } @@ -350,8 +343,8 @@ export const getPresenceButtons = async ( replaceAllText: (text: string) => Promise ): Promise => { const config = getConfig(); - let button1Enabled = config.get(CONFIG_KEYS.Status.Buttons.Button1.Enabled)!; - let button2Enabled = config.get(CONFIG_KEYS.Status.Buttons.Button2.Enabled)!; + let button1Enabled = config.get("vscord.status.buttons.button1.enabled")!; + let button2Enabled = config.get("vscord.status.buttons.button2.enabled")!; let state: "Idle" | "Active" | "Inactive" | undefined = isIdling ? "Idle" : isGitExcluded @@ -369,10 +362,7 @@ export const getPresenceButtons = async ( let button2 = buttonValidation(await createButton(replaceAllText, state, isGit, "Button2"), "Button2"); logInfo("[activity.ts] getPresenceButtons button1:", state, button1); logInfo("[activity.ts] getPresenceButtons button2:", state, button2); - if ( - (button1.validationError || button2.validationError) && - !config.get(CONFIG_KEYS.Behaviour.SuppressNotifications) - ) + if ((button1.validationError || button2.validationError) && !config.get("vscord.behaviour.suppressNotifications")) window.showErrorMessage(`${button1.validationError} ${button2.validationError}`); return [button1.button, button2.button].filter(Boolean) as GatewayActivityButton[]; }; @@ -409,24 +399,26 @@ export const replaceAppInfo = (text: string): string => { return text; }; -export const getTotalProblems = (countedSeverities: PROBLEM_LEVEL[]): number => { +export const getTotalProblems = ( + countedSeverities: ExtensionConfigGenerated["vscord.status.problems.countedSeverities"] +): number => { let totalProblems = 0; for (const severity of countedSeverities) { switch (severity) { - case PROBLEM_LEVEL.ERROR: { + case "error": { totalProblems += COUNTED_SEVERITIES.error; break; } - case PROBLEM_LEVEL.WARNING: { + case "warning": { totalProblems += COUNTED_SEVERITIES.warning; break; } - case PROBLEM_LEVEL.INFO: { + case "info": { totalProblems += COUNTED_SEVERITIES.info; break; } - case PROBLEM_LEVEL.HINT: { + case "hint": { totalProblems += COUNTED_SEVERITIES.hint; break; } @@ -469,14 +461,14 @@ export const replaceFileInfo = async ( const config = getConfig(); text = text.slice(); let workspaceFolderName = - dataClass.workspaceFolder?.name ?? config.get(CONFIG_KEYS.Status.Details.Text.NoWorkspaceText)!; - let workspaceName = dataClass.workspaceName ?? config.get(CONFIG_KEYS.Status.Details.Text.NoWorkspaceText)!; + dataClass.workspaceFolder?.name ?? config.get("vscord.status.details.text.noWorkSpaceText")!; + let workspaceName = dataClass.workspaceName ?? config.get("vscord.status.details.text.noWorkSpaceText")!; let workspaceAndFolder = workspaceName + (workspaceFolderName != FAKE_EMPTY ? ` - ${workspaceFolderName}` : FAKE_EMPTY); workspaceAndFolder = workspaceAndFolder.trim() === "" - ? config.get(CONFIG_KEYS.Status.Details.Text.NoWorkspaceText)! + ? config.get("vscord.status.details.text.noWorkSpaceText")! : workspaceAndFolder; let fullDirectoryName: string = FAKE_EMPTY; @@ -501,8 +493,8 @@ export const replaceFileInfo = async ( relativeFilepath = FAKE_EMPTY; } - const totalProblems = config.get(CONFIG_KEYS.Status.Problems.Enabled) - ? getTotalProblems(config.get(CONFIG_KEYS.Status.Problems.countedSeverities)!) + const totalProblems = config.get("vscord.status.problems.enabled") + ? getTotalProblems(config.get("vscord.status.problems.countedSeverities")!) : 0; const replaceMap = new Map([ @@ -524,7 +516,7 @@ export const replaceFileInfo = async ( ["{a_LANG}", `${getArticle(toUpper(fileIcon))} ${toUpper(fileIcon)}`], [ "{problems_count}", - config.get(CONFIG_KEYS.Status.Problems.Enabled) ? totalProblems.toLocaleString() : FAKE_EMPTY + config.get("vscord.status.problems.enabled") ? totalProblems.toLocaleString() : FAKE_EMPTY ], ["{problems_pluralize}", totalProblems === 1 ? "problem" : "problems"], ["{problems_count_errors}", COUNTED_SEVERITIES.error.toLocaleString()], diff --git a/src/config.ts b/src/config.ts index 5387691b..a62d6adf 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,143 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { type ConfigurationTarget, type WorkspaceConfiguration, workspace } from "vscode"; -import { type PROBLEM_LEVEL } from "./activity"; +import type { ExtensionConfigGenerated } from "./@types/configtypes.d.ts"; export type FileSizeStandard = "iec" | "jedec"; -interface ButtonStatus { - enabled: boolean; - label: string; - url: string; -} - -interface Button { - enabled: boolean; - active: ButtonStatus; - idle: ButtonStatus; - inactive: ButtonStatus; - git: { - active: ButtonStatus; - idle: ButtonStatus; - inactive: ButtonStatus; - }; -} - -interface Buttons { - button1: Button; - button2: Button; -} - -export interface ExtensionConfigurationType { - enable: string; - "app.id": string; - "app.name": "Code" | "Visual Studio Code" | "VSCodium" | "Antigravity" | "Cursor" | "Custom"; - "app.privacyMode.enable": boolean; - "app.whitelistEnabled": boolean; - "app.whitelistIsBlacklist": boolean; - "app.whitelist": string[]; - "status.details.enabled": boolean; - "status.details.idle.enabled": boolean; - "status.details.text.idle": string; - "status.details.text.viewing": string; - "status.details.text.editing": string; - "status.details.text.debugging": string; - "status.details.text.notInFile": string; - "status.details.text.noWorkSpaceText": string; - "status.state.enabled": boolean; - "status.state.debugging.enabled": boolean; - "status.state.idle.enabled": boolean; - "status.state.text.idle": string; - "status.state.text.viewing": string; - "status.state.text.editing": string; - "status.state.text.debugging": string; - "status.state.text.notInFile": string; - "status.state.text.noWorkspaceFound": string; - "status.buttons": Buttons; - "status.buttons.button1.enabled": boolean; - "status.buttons.button1.active.enabled": boolean; - "status.buttons.button1.active.label": string; - "status.buttons.button1.active.url": string; - "status.buttons.button1.inactive.enabled": boolean; - "status.buttons.button1.inactive.label": string; - "status.buttons.button1.inactive.url": string; - "status.buttons.button1.idle.enabled": boolean; - "status.buttons.button1.idle.label": string; - "status.buttons.button1.idle.url": string; - "status.buttons.button1.git.active.enabled": boolean; - "status.buttons.button1.git.active.label": string; - "status.buttons.button1.git.active.url": string; - "status.buttons.button1.git.inactive.enabled": boolean; - "status.buttons.button1.git.inactive.label": string; - "status.buttons.button1.git.inactive.url": string; - "status.buttons.button1.git.idle.enabled": boolean; - "status.buttons.button1.git.idle.label": string; - "status.buttons.button1.git.idle.url": string; - "status.buttons.button2.enabled": boolean; - "status.buttons.button2.active.enabled": boolean; - "status.buttons.button2.active.label": string; - "status.buttons.button2.active.url": string; - "status.buttons.button2.inactive.enabled": boolean; - "status.buttons.button2.inactive.label": string; - "status.buttons.button2.inactive.url": string; - "status.buttons.button2.idle.enabled": boolean; - "status.buttons.button2.idle.label": string; - "status.buttons.button2.idle.url": string; - "status.buttons.button2.git.active.enabled": boolean; - "status.buttons.button2.git.active.label": string; - "status.buttons.button2.git.active.url": string; - "status.buttons.button2.git.inactive.enabled": boolean; - "status.buttons.button2.git.inactive.label": string; - "status.buttons.button2.git.inactive.url": string; - "status.buttons.button2.git.idle.enabled": boolean; - "status.buttons.button2.git.idle.label": string; - "status.buttons.button2.git.idle.url": string; - "status.image.large.idle.key": string; - "status.image.large.idle.text": string; - "status.image.large.viewing.key": string; - "status.image.large.viewing.text": string; - "status.image.large.editing.key": string; - "status.image.large.editing.text": string; - "status.image.large.debugging.key": string; - "status.image.large.debugging.text": string; - "status.image.large.notInFile.key": string; - "status.image.large.notInFile.text": string; - "status.image.small.idle.key": string; - "status.image.small.idle.text": string; - "status.image.small.viewing.key": string; - "status.image.small.viewing.text": string; - "status.image.small.editing.key": string; - "status.image.small.editing.text": string; - "status.image.small.debugging.key": string; - "status.image.small.debugging.text": string; - "status.image.small.notInFile.key": string; - "status.image.small.notInFile.text": string; - "status.image.problems.enabled": boolean; - "status.image.problems.text": string; - "status.problems.enabled": boolean; - "status.problems.text": string; - "status.problems.countedSeverities": Array; - "status.idle.enabled": boolean; - "status.idle.check": boolean; - "status.idle.disconnectOnIdle": boolean; - "status.idle.resetElapsedTime": boolean; - "status.idle.timeout": number; - "status.showElapsedTime": boolean; - "status.resetElapsedTimePerFile": boolean; - "ignore.workspaces": Array; - "ignore.workspacesText": string | Record; - "ignore.repositories": Array; - "ignore.organizations": Array; - "ignore.gitHosts": Array; - "file.size.humanReadable": boolean; - "file.size.standard": FileSizeStandard; - "file.size.round": number; - "file.size.spacer": string; - "behaviour.additionalFileMapping": Record; - "behaviour.suppressNotifications": boolean; - "behaviour.suppressRpcCouldNotConnect": boolean; - "behaviour.statusBarAlignment": "Right" | "Left"; - "behaviour.debug": boolean; -} +// export interface ExtensionConfigurationType was here // Created by hayper1919, you may use it inside your extension /** @@ -318,6 +185,6 @@ export type WorkspaceConfigurationWithType; +export type ExtensionConfiguration = WorkspaceConfigurationWithType; -export const getConfig = () => workspace.getConfiguration("vscord") as ExtensionConfiguration; +export const getConfig = () => workspace.getConfiguration() as ExtensionConfiguration; diff --git a/src/constants.ts b/src/constants.ts index c4b03cbf..6bf948fb 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -7,202 +7,3 @@ export const { KNOWN_EXTENSIONS, KNOWN_LANGUAGES } = lang as { export const EMPTY = ""; export const FAKE_EMPTY = "\u200b\u200b"; - -export const CONFIG_KEYS = { - Enable: "enable" as const, - App: { - Id: "app.id" as const, - Name: "app.name" as const, - PrivacyMode: "app.privacyMode.enable" as const, - WhitelistEnabled: "app.whitelistEnabled" as const, - whitelistIsBlacklist: "app.whitelistIsBlacklist" as const, - Whitelist: "app.whitelist" as const - } as const, - Status: { - Details: { - Enabled: "status.details.enabled" as const, - Idle: { - Enabled: "status.details.idle.enabled" as const - } as const, - Text: { - Idle: "status.details.text.idle" as const, - Editing: "status.details.text.editing" as const, - Viewing: "status.details.text.viewing" as const, - NotInFile: "status.details.text.notInFile" as const, - NoWorkspaceText: "status.details.text.noWorkSpaceText" as const, - Debugging: "status.details.text.debugging" as const - } as const - } as const, - State: { - Enabled: "status.state.enabled" as const, - Debugging: { - Enabled: "status.state.debugging.enabled" as const - } as const, - Idle: { - Enabled: "status.state.idle.enabled" as const - } as const, - Text: { - Idle: "status.state.text.idle" as const, - Editing: "status.state.text.editing" as const, - Debugging: "status.state.text.debugging" as const, - Viewing: "status.state.text.viewing" as const, - NotInFile: "status.state.text.notInFile" as const, - NoWorkspaceFound: "status.state.text.noWorkspaceFound" as const - } as const - } as const, - Buttons: { - Button1: { - Enabled: "status.buttons.button1.enabled" as const, - Active: { - Enabled: "status.buttons.button1.active.enabled" as const, - Label: "status.buttons.button1.active.label" as const, - Url: "status.buttons.button1.active.url" as const - } as const, - Inactive: { - Enabled: "status.buttons.button1.inactive.enabled" as const, - Label: "status.buttons.button1.inactive.label" as const, - Url: "status.buttons.button1.inactive.url" as const - } as const, - Idle: { - Enabled: "status.buttons.button1.idle.enabled" as const, - Label: "status.buttons.button1.idle.label" as const, - Url: "status.buttons.button1.idle.url" as const - } as const, - Git: { - Active: { - Enabled: "status.buttons.button1.git.active.enabled" as const, - Label: "status.buttons.button1.git.active.label" as const, - Url: "status.buttons.button1.git.active.url" as const - } as const, - Inactive: { - Enabled: "status.buttons.button1.git.inactive.enabled" as const, - Label: "status.buttons.button1.git.inactive.label" as const, - Url: "status.buttons.button1.git.inactive.url" as const - } as const, - Idle: { - Enabled: "status.buttons.button1.git.idle.enabled" as const, - Label: "status.buttons.button1.git.idle.label" as const, - Url: "status.buttons.button1.git.idle.url" as const - } as const - } as const - }, - Button2: { - Enabled: "status.buttons.button2.enabled" as const, - Active: { - Enabled: "status.buttons.button2.active.enabled" as const, - Label: "status.buttons.button2.active.label" as const, - Url: "status.buttons.button2.active.url" as const - } as const, - Inactive: { - Enabled: "status.buttons.button2.inactive.enabled" as const, - Label: "status.buttons.button2.inactive.label" as const, - Url: "status.buttons.button2.inactive.url" as const - } as const, - Idle: { - Enabled: "status.buttons.button2.idle.enabled" as const, - Label: "status.buttons.button2.idle.label" as const, - Url: "status.buttons.button2.idle.url" as const - } as const, - Git: { - Active: { - Enabled: "status.buttons.button2.git.active.enabled" as const, - Label: "status.buttons.button2.git.active.label" as const, - Url: "status.buttons.button2.git.active.url" as const - } as const, - Inactive: { - Enabled: "status.buttons.button2.git.inactive.enabled" as const, - Label: "status.buttons.button2.git.inactive.label" as const, - Url: "status.buttons.button2.git.inactive.url" as const - } as const, - Idle: { - Enabled: "status.buttons.button2.git.idle.enabled" as const, - Label: "status.buttons.button2.git.idle.label" as const, - Url: "status.buttons.button2.git.idle.url" as const - } as const - } as const - } - } as const, - Image: { - Large: { - Idle: { - Key: "status.image.large.idle.key" as const, - Text: "status.image.large.idle.text" as const - } as const, - Editing: { - Key: "status.image.large.editing.key" as const, - Text: "status.image.large.editing.text" as const - } as const, - Debugging: { - Key: "status.image.large.debugging.key" as const, - Text: "status.image.large.debugging.text" as const - } as const, - Viewing: { - Key: "status.image.large.viewing.key" as const, - Text: "status.image.large.viewing.text" as const - } as const, - NotInFile: { - Key: "status.image.large.notInFile.key" as const, - Text: "status.image.large.notInFile.text" as const - } as const - } as const, - Small: { - Idle: { - Key: "status.image.small.idle.key" as const, - Text: "status.image.small.idle.text" as const - } as const, - Editing: { - Key: "status.image.small.editing.key" as const, - Text: "status.image.small.editing.text" as const - } as const, - Debugging: { - Key: "status.image.small.debugging.key" as const, - Text: "status.image.small.debugging.text" as const - } as const, - Viewing: { - Key: "status.image.small.viewing.key" as const, - Text: "status.image.small.viewing.text" as const - } as const, - NotInFile: { - Key: "status.image.small.notInFile.key" as const, - Text: "status.image.small.notInFile.text" as const - } as const - } as const - } as const, - Problems: { - Enabled: "status.problems.enabled" as const, - Text: "status.problems.text" as const, - countedSeverities: "status.problems.countedSeverities" as const - } as const, - Idle: { - Enabled: "status.idle.enabled" as const, - Check: "status.idle.check" as const, - DisconnectOnIdle: "status.idle.disconnectOnIdle" as const, - ResetElapsedTime: "status.idle.resetElapsedTime" as const, - Timeout: "status.idle.timeout" as const - } as const, - ShowElapsedTime: "status.showElapsedTime" as const, - ResetElapsedTimePerFile: "status.resetElapsedTimePerFile" as const - } as const, - Ignore: { - Workspaces: "ignore.workspaces" as const, - WorkspacesText: "ignore.workspacesText" as const, - Repositories: "ignore.repositories" as const, - Organizations: "ignore.organizations" as const, - GitHosts: "ignore.gitHosts" as const - } as const, - File: { - Size: { - HumanReadable: "file.size.humanReadable" as const, - Standard: "file.size.standard" as const, - Round: "file.size.round" as const, - Spacer: "file.size.spacer" as const - } as const - } as const, - Behaviour: { - AdditionalFileMapping: "behaviour.additionalFileMapping" as const, - SuppressNotifications: "behaviour.suppressNotifications" as const, - SuppressRpcCouldNotConnect: "behaviour.suppressRpcCouldNotConnect" as const, - StatusBarAlignment: "behaviour.statusBarAlignment" as const, - Debug: "behaviour.debug" as const - } as const -} as const; diff --git a/src/controller.ts b/src/controller.ts index 475b1152..d63309fe 100644 --- a/src/controller.ts +++ b/src/controller.ts @@ -7,7 +7,6 @@ import { StatusBarMode, editor } from "./editor"; import { validURL } from "./helpers/validURL"; import { throttle } from "./helpers/throttle"; import { logError, logInfo } from "./logger"; -import { CONFIG_KEYS } from "./constants"; import { getConfig } from "./config"; import { dataClass } from "./data"; @@ -33,7 +32,7 @@ export class RPCController { const config = getConfig(); this.client = new Client({ clientId }); this.debug = debug; - this.manualIdleMode = config.get(CONFIG_KEYS.Status.Idle.Check) === false; + this.manualIdleMode = config.get("vscord.status.idle.check") === false; editor.setStatusBarItem(StatusBarMode.Pending); @@ -110,8 +109,8 @@ export class RPCController { // fire checkIdle at least once after loading this.checkIdle(window.state); - if (config.get(CONFIG_KEYS.Status.Problems.Enabled)) this.listeners.push(diagnosticsChange); - if (config.get(CONFIG_KEYS.Status.Idle.Check)) this.listeners.push(changeWindowState); + if (config.get("vscord.status.problems.enabled")) this.listeners.push(diagnosticsChange); + if (config.get("vscord.status.idle.check")) this.listeners.push(changeWindowState); this.listeners.push(fileSwitch, fileEdit, fileSelectionChanged, debugStart, debugEnd); } @@ -120,11 +119,11 @@ export class RPCController { const config = getConfig(); let userId = this.client.user?.id; if (!userId) return false; - if (isIdling && config.get(CONFIG_KEYS.Status.Idle.DisconnectOnIdle)) return (this.canSendActivity = false); - let whitelistEnabled = config.get(CONFIG_KEYS.App.WhitelistEnabled); + if (isIdling && config.get("vscord.status.idle.disconnectOnIdle")) return (this.canSendActivity = false); + let whitelistEnabled = config.get("vscord.app.whitelistEnabled"); if (whitelistEnabled) { - let whitelist = config.get(CONFIG_KEYS.App.Whitelist); - if (config.get(CONFIG_KEYS.App.whitelistIsBlacklist)) + let whitelist = config.get("vscord.app.whitelist"); + if (config.get("vscord.app.whitelistIsBlacklist")) if (whitelist!.includes(userId)) return (this.canSendActivity = false); else return (this.canSendActivity = true); else if (!whitelist!.includes(userId)) return (this.canSendActivity = false); @@ -132,23 +131,23 @@ export class RPCController { return (this.canSendActivity = true); } - private checkIdle(windowState: WindowState) { + private async checkIdle(windowState: WindowState) { if (!this.enabled) return; const config = getConfig(); - if (config.get(CONFIG_KEYS.Status.Idle.Timeout) !== 0) { + if (config.get("vscord.status.idle.timeout") !== 0) { if (windowState.focused && this.idleTimeout) { clearTimeout(this.idleTimeout); - void this.activityThrottle.callable(); - } else if (config.get(CONFIG_KEYS.Status.Idle.Check)) { + await this.sendActivity(); + } else if (config.get("vscord.status.idle.check")) { this.idleTimeout = setTimeout( async () => { - if (!config.get(CONFIG_KEYS.Status.Idle.Check)) return; + if (!config.get("vscord.status.idle.check")) return; if ( - config.get(CONFIG_KEYS.Status.Idle.DisconnectOnIdle) && - config.get(CONFIG_KEYS.Status.Idle.ResetElapsedTime) + config.get("vscord.status.idle.disconnectOnIdle") && + config.get("vscord.status.idle.resetElapsedTime") ) { delete this.state.startTimestamp; } @@ -157,7 +156,7 @@ export class RPCController { void this.activityThrottle.callable(false, true); }, - config.get(CONFIG_KEYS.Status.Idle.Timeout)! * 1000 + config.get("vscord.status.idle.timeout")! * 1000 ); } } diff --git a/src/data.ts b/src/data.ts index 10952ee2..e4204ffa 100644 --- a/src/data.ts +++ b/src/data.ts @@ -1,7 +1,6 @@ import type { API as GitApi, GitExtension, Remote, Repository } from "./@types/git"; import { stripCredential } from "./helpers/stripCredential"; import { basename, parse, sep } from "node:path"; -import { CONFIG_KEYS } from "./constants"; import gitUrlParse from "git-url-parse"; import { getConfig } from "./config"; import { logInfo } from "./logger"; @@ -268,7 +267,7 @@ export class Data implements Disposable { // eslint-disable-next-line @typescript-eslint/no-explicit-any private debug(...message: any[]) { - if (!getConfig().get(CONFIG_KEYS.Behaviour.Debug)) return; + if (!getConfig().get("vscord.behaviour.debug")) return; // eslint-disable-next-line @typescript-eslint/no-unsafe-argument logInfo("[data.ts]", ...message); } diff --git a/src/editor.ts b/src/editor.ts index 0d9dd52f..89d7c7ec 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -1,6 +1,6 @@ +import type { ExtensionConfigGenerated } from "./@types/configtypes.d.ts"; import { Disposable, ConfigurationTarget, StatusBarAlignment, StatusBarItem, window, commands } from "vscode"; -import { type ExtensionConfiguration, type ExtensionConfigurationType, getConfig } from "./config"; -import { CONFIG_KEYS } from "./constants"; +import { type ExtensionConfiguration, getConfig } from "./config"; import { logInfo, outputChannel } from "./logger"; export enum StatusBarMode { @@ -15,14 +15,14 @@ class EditorController implements Disposable { statusBarItemMode: StatusBarMode = StatusBarMode.Disabled; #getAlignmentFromConfig(config: ExtensionConfiguration): StatusBarAlignment { - const value = config.get(CONFIG_KEYS.Behaviour.StatusBarAlignment); + const value = config.get("vscord.behaviour.statusBarAlignment"); return StatusBarAlignment[value ?? "Right"]; } setStatusBarItem(mode: StatusBarMode) { this.statusBarItemMode = mode; const config = getConfig(); - if (!config.get(CONFIG_KEYS.Enable)) { + if (!config.get("vscord.enable")) { mode = StatusBarMode.Disabled; } if (!this.statusBarItem) { @@ -60,10 +60,10 @@ class EditorController implements Disposable { toggleStatusBarAlignment(align: StatusBarAlignment = StatusBarAlignment.Right): StatusBarAlignment { const config = getConfig(); - const cfgKey = CONFIG_KEYS.Behaviour.StatusBarAlignment; + const cfgKey = "vscord.behaviour.statusBarAlignment" as const satisfies keyof ExtensionConfigGenerated; const literalAlign = ( align === StatusBarAlignment.Right ? "Right" : "Left" - ) satisfies ExtensionConfigurationType[typeof cfgKey]; + ) satisfies ExtensionConfigGenerated[typeof cfgKey]; config.update(cfgKey, literalAlign); // updateStatusBarFromConfig() // called from config listener @@ -110,7 +110,7 @@ class EditorController implements Disposable { } } errorMessageFailedToConnect(config: ExtensionConfiguration, error?: Error) { - if (config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) { + if (config.get("vscord.behaviour.suppressNotifications")) { return; } @@ -124,7 +124,8 @@ class EditorController implements Disposable { } const configKeyPairs = { - RPC_COULD_NOT_CONNECT: CONFIG_KEYS.Behaviour.SuppressRpcCouldNotConnect + RPC_COULD_NOT_CONNECT: + "vscord.behaviour.suppressRpcCouldNotConnect" satisfies keyof ExtensionConfigGenerated } as const; const errorName = error.name; diff --git a/src/extension.ts b/src/extension.ts index da1ce684..5e4ce948 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,23 +2,19 @@ import { commands, window, workspace, type ExtensionContext } from "vscode"; import { getApplicationId } from "./helpers/getApplicationId"; import { StatusBarMode, editor } from "./editor"; import { RPCController } from "./controller"; -import { CONFIG_KEYS } from "./constants"; import { getConfig } from "./config"; import { logInfo } from "./logger"; import { dataClass } from "./data"; -const controller = new RPCController( - getApplicationId(getConfig()).clientId, - getConfig().get(CONFIG_KEYS.Behaviour.Debug) -); +const controller = new RPCController(getApplicationId(getConfig()).clientId, getConfig().get("vscord.behaviour.debug")); export const registerListeners = (ctx: ExtensionContext) => { const onConfigurationChanged = workspace.onDidChangeConfiguration(async () => { const config = getConfig(); const clientId = getApplicationId(config).clientId; - const isEnabled = config.get(CONFIG_KEYS.Enable); + const isEnabled = config.get("vscord.enable"); - controller.debug = config.get(CONFIG_KEYS.Behaviour.Debug) ?? false; + controller.debug = config.get("vscord.behaviour.debug") ?? false; editor.updateStatusBarFromConfig(); if (controller.client.clientId !== clientId) { @@ -27,7 +23,7 @@ export const registerListeners = (ctx: ExtensionContext) => { if (isEnabled) await controller.enable(); } - controller.manualIdleMode = config.get(CONFIG_KEYS.Status.Idle.Check) === false; + controller.manualIdleMode = config.get("vscord.status.idle.check") === false; }); ctx.subscriptions.push(onConfigurationChanged); @@ -39,7 +35,7 @@ export const registerCommands = (ctx: ExtensionContext) => { const enable = async (update = true) => { if (update) try { - await config.update(CONFIG_KEYS.Enable, true); + await config.update("vscord.enable", true); } catch {} await controller.enable(); @@ -48,7 +44,7 @@ export const registerCommands = (ctx: ExtensionContext) => { const disable = async (update = true) => { if (update) try { - await config.update(CONFIG_KEYS.Enable, false); + await config.update("vscord.enable", false); } catch {} await controller.disable(); @@ -59,7 +55,7 @@ export const registerCommands = (ctx: ExtensionContext) => { const togglePrivacyMode = async (activate: boolean) => { try { - await config.update(CONFIG_KEYS.App.PrivacyMode, activate); + await config.update("vscord.app.privacyMode.enable", activate); } catch {} await controller.sendActivity(dataClass.editor != null); @@ -71,7 +67,7 @@ export const registerCommands = (ctx: ExtensionContext) => { logInfo("Enabled Discord Rich Presence."); - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) await window.showInformationMessage("Enabled Discord Rich Presence"); }); @@ -80,7 +76,7 @@ export const registerCommands = (ctx: ExtensionContext) => { await disable(false); - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) await window.showInformationMessage("Disabled Discord Rich Presence"); }); @@ -90,7 +86,7 @@ export const registerCommands = (ctx: ExtensionContext) => { await disable(); await enable(); - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) await window.showInformationMessage("Enabled Discord Rich Presence for this workspace"); }); @@ -99,7 +95,7 @@ export const registerCommands = (ctx: ExtensionContext) => { await disable(); - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) await window.showInformationMessage("Disabled Discord Rich Presence for this workspace"); }); @@ -112,7 +108,7 @@ export const registerCommands = (ctx: ExtensionContext) => { .login() .then(async () => await controller.enable()) .catch(() => { - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) window.showErrorMessage("Failed to reconnect to Discord Gateway"); editor.setStatusBarItem(StatusBarMode.Disconnected); }); @@ -131,7 +127,7 @@ export const registerCommands = (ctx: ExtensionContext) => { await togglePrivacyMode(true); - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) await window.showInformationMessage("Enabled Privacy Mode."); }); @@ -140,7 +136,7 @@ export const registerCommands = (ctx: ExtensionContext) => { await togglePrivacyMode(false); - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) await window.showInformationMessage("Disabled Privacy Mode."); }); @@ -150,7 +146,7 @@ export const registerCommands = (ctx: ExtensionContext) => { controller.manualIdling = true; await controller.sendActivity(false, true); - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) await window.showInformationMessage("Started Idling."); }); @@ -160,7 +156,7 @@ export const registerCommands = (ctx: ExtensionContext) => { controller.manualIdling = false; await controller.sendActivity(); - if (!config.get(CONFIG_KEYS.Behaviour.SuppressNotifications)) + if (!config.get("vscord.behaviour.suppressNotifications")) await window.showInformationMessage("Stopped Idling."); }); @@ -186,7 +182,7 @@ export async function activate(ctx: ExtensionContext) { registerCommands(ctx); registerListeners(ctx); - if (!getConfig().get(CONFIG_KEYS.Enable)) await controller.disable(); + if (!getConfig().get("vscord.enable")) await controller.disable(); } export async function deactivate() { diff --git a/src/helpers/getApplicationId.ts b/src/helpers/getApplicationId.ts index cc874a65..8ab4b9cd 100644 --- a/src/helpers/getApplicationId.ts +++ b/src/helpers/getApplicationId.ts @@ -1,5 +1,4 @@ import type { ExtensionConfiguration } from "../config"; -import { CONFIG_KEYS } from "../constants"; export const getApplicationId = (config: ExtensionConfiguration) => { const applicationIds = new Map([ @@ -8,12 +7,12 @@ export const getApplicationId = (config: ExtensionConfiguration) => { ["VSCodium", "1031067701474492496"], ["Antigravity", "1441771215290372156"], ["Cursor", "1376937466619232256"], - ["Custom", config.get(CONFIG_KEYS.App.Id)!] + ["Custom", config.get("vscord.app.id")!] ]); - const currentAppName = config.get(CONFIG_KEYS.App.Name)!; + const currentAppName = config.get("vscord.app.name")!; - let clientId = config.get(CONFIG_KEYS.App.Id)!; + let clientId = config.get("vscord.app.id")!; for (const [appName, id] of applicationIds.entries()) { if (currentAppName !== appName) continue; clientId = id; diff --git a/src/helpers/getFileSize.ts b/src/helpers/getFileSize.ts index ac46d1c9..e5ba6b58 100644 --- a/src/helpers/getFileSize.ts +++ b/src/helpers/getFileSize.ts @@ -1,27 +1,26 @@ import type { ExtensionConfiguration, FileSizeStandard } from "../config"; import { FilesizeOptions, filesize } from "filesize"; -import { CONFIG_KEYS } from "../constants"; import type { Data } from "../data"; export const getFileSize = async (config: ExtensionConfiguration, dataClass: Data) => { if (!(await dataClass.fileSize)) return; let round = 2; - if (config.get(CONFIG_KEYS.File.Size.Round) === 0 || config.get(CONFIG_KEYS.File.Size.Round)) - round = config.get(CONFIG_KEYS.File.Size.Round)!; + if (config.get("vscord.file.size.round") === 0 || config.get("vscord.file.size.round")) + round = config.get("vscord.file.size.round")!; let spacer = " "; - if (config.get(CONFIG_KEYS.File.Size.Spacer) === "" || config.get(CONFIG_KEYS.File.Size.Spacer)) - spacer = config.get(CONFIG_KEYS.File.Size.Spacer)!; + if (config.get("vscord.file.size.spacer") === "" || config.get("vscord.file.size.spacer")) + spacer = config.get("vscord.file.size.spacer")!; - const fileSizeStandard: FileSizeStandard = config.get(CONFIG_KEYS.File.Size.Standard) ?? "iec"; + const fileSizeStandard: FileSizeStandard = config.get("vscord.file.size.standard") ?? "iec"; const fileSizeConfig: FilesizeOptions = { round, spacer, standard: fileSizeStandard } as const; - const fileSize = config.get(CONFIG_KEYS.File.Size.HumanReadable) + const fileSize = config.get("vscord.file.size.humanReadable") ? filesize((await dataClass.fileSize) ?? 0, fileSizeConfig).toLocaleString() : `${dataClass.fileSize.toLocaleString()}${fileSizeConfig.spacer ?? " "}B`; diff --git a/src/helpers/resolveLangName.ts b/src/helpers/resolveLangName.ts index 0618b8fd..6d297b5b 100644 --- a/src/helpers/resolveLangName.ts +++ b/src/helpers/resolveLangName.ts @@ -1,4 +1,4 @@ -import { CONFIG_KEYS, KNOWN_EXTENSIONS, KNOWN_LANGUAGES } from "../constants"; +import { KNOWN_EXTENSIONS, KNOWN_LANGUAGES } from "../constants"; import { type TextDocument } from "vscode"; import { getConfig } from "../config"; import { basename } from "node:path"; @@ -38,7 +38,7 @@ export const resolveLangName = (document: TextDocument): string => { const config = getConfig(); const ADDITIONAL_FILE_MAPPING = Object.fromEntries( - Object.entries(config.get(CONFIG_KEYS.Behaviour.AdditionalFileMapping)!).map(([key, value]) => [ + Object.entries(config.get("vscord.behaviour.additionalFileMapping")!).map(([key, value]) => [ key, { image: value } ])