diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4f37590 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.defaultFormatter": "biomejs.biome" +} diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..2eb0751 --- /dev/null +++ b/biome.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": [] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + } +} diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..89c9bd6 Binary files /dev/null and b/bun.lockb differ diff --git a/package.json b/package.json index 0145bd4..922f587 100644 --- a/package.json +++ b/package.json @@ -19,15 +19,11 @@ "main": "./dist/extension", "scripts": { "build": "npm run lint && webpack --mode production", - "lint": "prettier --check . && eslint src --ext mjs,js,ts", - "format": "prettier --write . && eslint src --ext mjs,js,ts --fix" + "lint": "npx @biomejs/biome check", + "format": "npx @biomejs/biome format --write" }, - "activationEvents": [ - "*" - ], - "extensionKind": [ - "ui" - ], + "activationEvents": ["*"], + "extensionKind": ["ui"], "contributes": { "commands": [ { @@ -165,17 +161,8 @@ "bugs": { "url": "https://github.com/iCrawl/discord-vscode/issues" }, - "keywords": [ - "discord", - "vscode", - "rich", - "presence", - "rich presence", - "rpc" - ], - "categories": [ - "Other" - ], + "keywords": ["discord", "vscode", "rich", "presence", "rich presence", "rpc"], + "categories": ["Other"], "homepage": "https://github.com/iCrawl/discord-vscode#readme", "icon": "assets/icon.png", "galleryBanner": { @@ -191,6 +178,7 @@ "utf-8-validate": "^5.0.9" }, "devDependencies": { + "@biomejs/biome": "^1.9.4", "@types/lodash-es": "^4.17.6", "@types/node": "^17.0.41", "@types/vscode": "^1.67.0", diff --git a/src/activity.ts b/src/activity.ts index a354456..09a507b 100644 --- a/src/activity.ts +++ b/src/activity.ts @@ -1,5 +1,12 @@ -import { basename, parse, sep } from 'path'; -import { debug, env, Selection, TextDocument, window, workspace } from 'vscode'; +import { basename, parse, sep } from "node:path"; +import { + type Selection, + type TextDocument, + debug, + env, + window, + workspace, +} from "vscode"; import { CONFIG_KEYS, @@ -13,9 +20,16 @@ import { UNKNOWN_GIT_REPO_NAME, VSCODE_IMAGE_KEY, VSCODE_INSIDERS_IMAGE_KEY, -} from './constants'; -import { log, LogLevel } from './logger'; -import { getConfig, getGit, resolveFileIcon, toLower, toTitle, toUpper } from './util'; +} from "./constants"; +import { LogLevel, log } from "./logger"; +import { + getConfig, + getGit, + resolveFileIcon, + toLower, + toTitle, + toUpper, +} from "./util"; interface ActivityPayload { details?: string | undefined; @@ -35,19 +49,32 @@ interface ActivityPayload { instance?: boolean | undefined; } -async function fileDetails(_raw: string, document: TextDocument, selection: Selection) { +async function fileDetails( + _raw: string, + document: TextDocument, + selection: Selection, +) { let raw = _raw.slice(); if (raw.includes(REPLACE_KEYS.TotalLines)) { - raw = raw.replace(REPLACE_KEYS.TotalLines, document.lineCount.toLocaleString()); + raw = raw.replace( + REPLACE_KEYS.TotalLines, + document.lineCount.toLocaleString(), + ); } if (raw.includes(REPLACE_KEYS.CurrentLine)) { - raw = raw.replace(REPLACE_KEYS.CurrentLine, (selection.active.line + 1).toLocaleString()); + raw = raw.replace( + REPLACE_KEYS.CurrentLine, + (selection.active.line + 1).toLocaleString(), + ); } if (raw.includes(REPLACE_KEYS.CurrentColumn)) { - raw = raw.replace(REPLACE_KEYS.CurrentColumn, (selection.active.character + 1).toLocaleString()); + raw = raw.replace( + REPLACE_KEYS.CurrentColumn, + (selection.active.character + 1).toLocaleString(), + ); } if (raw.includes(REPLACE_KEYS.FileSize)) { @@ -70,7 +97,9 @@ async function fileDetails(_raw: string, document: TextDocument, selection: Sele raw = raw.replace( REPLACE_KEYS.FileSize, - `${originalSize > 1000 ? size.toFixed(2) : size}${FILE_SIZES[currentDivision]}`, + `${originalSize > 1000 ? size.toFixed(2) : size}${ + FILE_SIZES[currentDivision] + }`, ); } @@ -80,7 +109,8 @@ async function fileDetails(_raw: string, document: TextDocument, selection: Sele if (git?.repositories.length) { raw = raw.replace( REPLACE_KEYS.GitBranch, - git.repositories.find((repo) => repo.ui.selected)?.state.HEAD?.name ?? FAKE_EMPTY, + git.repositories.find((repo) => repo.ui.selected)?.state.HEAD?.name ?? + FAKE_EMPTY, ); } else { raw = raw.replace(REPLACE_KEYS.GitBranch, UNKNOWN_GIT_BRANCH); @@ -93,8 +123,8 @@ async function fileDetails(_raw: string, document: TextDocument, selection: Sele REPLACE_KEYS.GitRepoName, git.repositories .find((repo) => repo.ui.selected) - ?.state.remotes[0].fetchUrl?.split('/')[1] - .replace('.git', '') ?? FAKE_EMPTY, + ?.state.remotes[0].fetchUrl?.split("/")[1] + .replace(".git", "") ?? FAKE_EMPTY, ); } else { raw = raw.replace(REPLACE_KEYS.GitRepoName, UNKNOWN_GIT_REPO_NAME); @@ -104,7 +134,11 @@ async function fileDetails(_raw: string, document: TextDocument, selection: Sele return raw; } -async function details(idling: CONFIG_KEYS, editing: CONFIG_KEYS, debugging: CONFIG_KEYS) { +async function details( + idling: CONFIG_KEYS, + editing: CONFIG_KEYS, + debugging: CONFIG_KEYS, +) { const config = getConfig(); let raw = (config[idling] as string).replace(REPLACE_KEYS.Empty, FAKE_EMPTY); @@ -114,12 +148,18 @@ async function details(idling: CONFIG_KEYS, editing: CONFIG_KEYS, debugging: CON const split = dir.split(sep); const dirName = split[split.length - 1]; - const noWorkspaceFound = config[CONFIG_KEYS.LowerDetailsNoWorkspaceFound].replace(REPLACE_KEYS.Empty, FAKE_EMPTY); - const workspaceFolder = workspace.getWorkspaceFolder(window.activeTextEditor.document.uri); + const noWorkspaceFound = config[ + CONFIG_KEYS.LowerDetailsNoWorkspaceFound + ].replace(REPLACE_KEYS.Empty, FAKE_EMPTY); + const workspaceFolder = workspace.getWorkspaceFolder( + window.activeTextEditor.document.uri, + ); const workspaceFolderName = workspaceFolder?.name ?? noWorkspaceFound; - const workspaceName = workspace.name?.replace(REPLACE_KEYS.VSCodeWorkspace, EMPTY) ?? workspaceFolderName; + const workspaceName = + workspace.name?.replace(REPLACE_KEYS.VSCodeWorkspace, EMPTY) ?? + workspaceFolderName; const workspaceAndFolder = `${workspaceName}${ - workspaceFolderName === FAKE_EMPTY ? '' : ` - ${workspaceFolderName}` + workspaceFolderName === FAKE_EMPTY ? "" : ` - ${workspaceFolderName}` }`; const fileIcon = resolveFileIcon(window.activeTextEditor.document); @@ -132,15 +172,27 @@ async function details(idling: CONFIG_KEYS, editing: CONFIG_KEYS, debugging: CON if (workspaceFolder) { const { name } = workspaceFolder; - const relativePath = workspace.asRelativePath(window.activeTextEditor.document.fileName).split(sep); + const relativePath = workspace + .asRelativePath(window.activeTextEditor.document.fileName) + .split(sep); relativePath.splice(-1, 1); - raw = raw.replace(REPLACE_KEYS.FullDirName, `${name}${sep}${relativePath.join(sep)}`); + raw = raw.replace( + REPLACE_KEYS.FullDirName, + `${name}${sep}${relativePath.join(sep)}`, + ); } try { - raw = await fileDetails(raw, window.activeTextEditor.document, window.activeTextEditor.selection); + raw = await fileDetails( + raw, + window.activeTextEditor.document, + window.activeTextEditor.selection, + ); } catch (error) { - log(LogLevel.Error, `Failed to generate file details: ${error as string}`); + log( + LogLevel.Error, + `Failed to generate file details: ${error as string}`, + ); } raw = raw .replace(REPLACE_KEYS.FileName, fileName) @@ -163,10 +215,13 @@ export async function activity(previous: ActivityPayload = {}) { const appName = env.appName; const defaultSmallImageKey = debug.activeDebugSession ? DEBUG_IMAGE_KEY - : appName.includes('Insiders') - ? VSCODE_INSIDERS_IMAGE_KEY - : VSCODE_IMAGE_KEY; - const defaultSmallImageText = config[CONFIG_KEYS.SmallImage].replace(REPLACE_KEYS.AppName, appName); + : appName.includes("Insiders") + ? VSCODE_INSIDERS_IMAGE_KEY + : VSCODE_IMAGE_KEY; + const defaultSmallImageText = config[CONFIG_KEYS.SmallImage].replace( + REPLACE_KEYS.AppName, + appName, + ); const defaultLargeImageText = config[CONFIG_KEYS.LargeImageIdling]; const removeDetails = config[CONFIG_KEYS.RemoveDetails]; const removeLowerDetails = config[CONFIG_KEYS.RemoveLowerDetails]; @@ -177,8 +232,14 @@ export async function activity(previous: ActivityPayload = {}) { let state: ActivityPayload = { details: removeDetails ? undefined - : await details(CONFIG_KEYS.DetailsIdling, CONFIG_KEYS.DetailsEditing, CONFIG_KEYS.DetailsDebugging), - startTimestamp: config[CONFIG_KEYS.RemoveTimestamp] ? undefined : previous.startTimestamp ?? Date.now(), + : await details( + CONFIG_KEYS.DetailsIdling, + CONFIG_KEYS.DetailsEditing, + CONFIG_KEYS.DetailsDebugging, + ), + startTimestamp: config[CONFIG_KEYS.RemoveTimestamp] + ? undefined + : (previous.startTimestamp ?? Date.now()), largeImageKey: IDLE_IMAGE_KEY, largeImageText: defaultLargeImageText, smallImageKey: defaultSmallImageKey, @@ -196,18 +257,25 @@ export async function activity(previous: ActivityPayload = {}) { } if (!removeRemoteRepository && git?.repositories.length) { - let repo = git.repositories.find((repo) => repo.ui.selected)?.state.remotes[0]?.fetchUrl; + let repo = git.repositories.find((repo) => repo.ui.selected)?.state + .remotes[0]?.fetchUrl; if (repo) { - if (repo.startsWith('git@') || repo.startsWith('ssh://')) { - repo = repo.replace('ssh://', '').replace(':', '/').replace('git@', 'https://').replace('.git', ''); + if (repo.startsWith("git@") || repo.startsWith("ssh://")) { + repo = repo + .replace("ssh://", "") + .replace(":", "/") + .replace("git@", "https://") + .replace(".git", ""); } else { - repo = repo.replace(/(https:\/\/)([^@]*)@(.*?$)/, '$1$3').replace('.git', ''); + repo = repo + .replace(/(https:\/\/)([^@]*)@(.*?$)/, "$1$3") + .replace(".git", ""); } state = { ...state, - buttons: [{ label: 'View Repository', url: repo }], + buttons: [{ label: "View Repository", url: repo }], }; } } @@ -224,14 +292,18 @@ export async function activity(previous: ActivityPayload = {}) { ...state, details: removeDetails ? undefined - : await details(CONFIG_KEYS.DetailsIdling, CONFIG_KEYS.DetailsEditing, CONFIG_KEYS.DetailsDebugging), + : await details( + CONFIG_KEYS.DetailsIdling, + CONFIG_KEYS.DetailsEditing, + CONFIG_KEYS.DetailsDebugging, + ), state: removeLowerDetails ? undefined : await details( CONFIG_KEYS.LowerDetailsIdling, CONFIG_KEYS.LowerDetailsEditing, CONFIG_KEYS.LowerDetailsDebugging, - ), + ), }; if (swapBigAndSmallImage) { @@ -248,7 +320,10 @@ export async function activity(previous: ActivityPayload = {}) { }; } - log(LogLevel.Trace, `VSCode language id: ${window.activeTextEditor.document.languageId}`); + log( + LogLevel.Trace, + `VSCode language id: ${window.activeTextEditor.document.languageId}`, + ); } return state; diff --git a/src/constants.ts b/src/constants.ts index 84ddb8b..4f3575a 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,61 +1,63 @@ -import LANG from './data/languages.json'; +import LANG from "./data/languages.json"; -export const CLIENT_ID = '383226320970055681' as const; +export const CLIENT_ID = "383226320970055681" as const; -export const KNOWN_EXTENSIONS: { [key: string]: { image: string } } = LANG.KNOWN_EXTENSIONS; -export const KNOWN_LANGUAGES: { language: string; image: string }[] = LANG.KNOWN_LANGUAGES; +export const KNOWN_EXTENSIONS: { [key: string]: { image: string } } = + LANG.KNOWN_EXTENSIONS; +export const KNOWN_LANGUAGES: { language: string; image: string }[] = + LANG.KNOWN_LANGUAGES; -export const EMPTY = '' as const; -export const FAKE_EMPTY = '\u200b\u200b' as const; -export const FILE_SIZES = [' bytes', 'KB', 'MB', 'GB', 'TB'] as const; +export const EMPTY = "" as const; +export const FAKE_EMPTY = "\u200b\u200b" as const; +export const FILE_SIZES = [" bytes", "KB", "MB", "GB", "TB"] as const; -export const IDLE_IMAGE_KEY = 'vscode-big' as const; -export const DEBUG_IMAGE_KEY = 'debug' as const; -export const VSCODE_IMAGE_KEY = 'vscode' as const; -export const VSCODE_INSIDERS_IMAGE_KEY = 'vscode-insiders' as const; +export const IDLE_IMAGE_KEY = "vscode-big" as const; +export const DEBUG_IMAGE_KEY = "debug" as const; +export const VSCODE_IMAGE_KEY = "vscode" as const; +export const VSCODE_INSIDERS_IMAGE_KEY = "vscode-insiders" as const; -export const UNKNOWN_GIT_BRANCH = 'Unknown' as const; -export const UNKNOWN_GIT_REPO_NAME = 'Unknown' as const; +export const UNKNOWN_GIT_BRANCH = "Unknown" as const; +export const UNKNOWN_GIT_REPO_NAME = "Unknown" as const; -export const enum REPLACE_KEYS { - Empty = '{empty}', - FileName = '{file_name}', - DirName = '{dir_name}', - FullDirName = '{full_dir_name}', - Workspace = '{workspace}', - VSCodeWorkspace = '(Workspace)', - WorkspaceFolder = '{workspace_folder}', - WorkspaceAndFolder = '{workspace_and_folder}', - LanguageLowerCase = '{lang}', - LanguageTitleCase = '{Lang}', - LanguageUpperCase = '{LANG}', - TotalLines = '{total_lines}', - CurrentLine = '{current_line}', - CurrentColumn = '{current_column}', - FileSize = '{file_size}', - AppName = '{app_name}', - GitRepoName = '{git_repo_name}', - GitBranch = '{git_branch}', +export enum REPLACE_KEYS { + Empty = "{empty}", + FileName = "{file_name}", + DirName = "{dir_name}", + FullDirName = "{full_dir_name}", + Workspace = "{workspace}", + VSCodeWorkspace = "(Workspace)", + WorkspaceFolder = "{workspace_folder}", + WorkspaceAndFolder = "{workspace_and_folder}", + LanguageLowerCase = "{lang}", + LanguageTitleCase = "{Lang}", + LanguageUpperCase = "{LANG}", + TotalLines = "{total_lines}", + CurrentLine = "{current_line}", + CurrentColumn = "{current_column}", + FileSize = "{file_size}", + AppName = "{app_name}", + GitRepoName = "{git_repo_name}", + GitBranch = "{git_branch}", } -export const enum CONFIG_KEYS { - Enabled = 'enabled', - DetailsIdling = 'detailsIdling', - DetailsEditing = 'detailsEditing', - DetailsDebugging = 'detailsDebugging', - LowerDetailsIdling = 'lowerDetailsIdling', - LowerDetailsEditing = 'lowerDetailsEditing', - LowerDetailsDebugging = 'lowerDetailsDebugging', - LowerDetailsNoWorkspaceFound = 'lowerDetailsNoWorkspaceFound', - LargeImageIdling = 'largeImageIdling', - LargeImage = 'largeImage', - SmallImage = 'smallImage', - SuppressNotifications = 'suppressNotifications', - WorkspaceExcludePatterns = 'workspaceExcludePatterns', - SwapBigAndSmallImage = 'swapBigAndSmallImage', - RemoveDetails = 'removeDetails', - RemoveLowerDetails = 'removeLowerDetails', - RemoveTimestamp = 'removeTimestamp', - RemoveRemoteRepository = 'removeRemoteRepository', - IdleTimeout = 'idleTimeout', +export enum CONFIG_KEYS { + Enabled = "enabled", + DetailsIdling = "detailsIdling", + DetailsEditing = "detailsEditing", + DetailsDebugging = "detailsDebugging", + LowerDetailsIdling = "lowerDetailsIdling", + LowerDetailsEditing = "lowerDetailsEditing", + LowerDetailsDebugging = "lowerDetailsDebugging", + LowerDetailsNoWorkspaceFound = "lowerDetailsNoWorkspaceFound", + LargeImageIdling = "largeImageIdling", + LargeImage = "largeImage", + SmallImage = "smallImage", + SuppressNotifications = "suppressNotifications", + WorkspaceExcludePatterns = "workspaceExcludePatterns", + SwapBigAndSmallImage = "swapBigAndSmallImage", + RemoveDetails = "removeDetails", + RemoveLowerDetails = "removeLowerDetails", + RemoveTimestamp = "removeTimestamp", + RemoveRemoteRepository = "removeRemoteRepository", + IdleTimeout = "idleTimeout", } diff --git a/src/data/languages.json b/src/data/languages.json index 6c6ba5a..56ea3a4 100644 --- a/src/data/languages.json +++ b/src/data/languages.json @@ -82,11 +82,15 @@ ".asmx": { "image": "asp" }, ".aspx": { "image": "asp" }, ".axd": { "image": "asp" }, - "/\\.(l?a|[ls]?o|out|s|a51|asm|axf|elf|prx|puff|z80)$/i": { "image": "assembly" }, + "/\\.(l?a|[ls]?o|out|s|a51|asm|axf|elf|prx|puff|z80)$/i": { + "image": "assembly" + }, ".agc": { "image": "assembly" }, ".ko": { "image": "assembly" }, ".lst": { "image": "assembly" }, - "/\\.((c([+px]{2}?)?-?)?objdump|bsdiff|bin|dat|pak|pdb)$/i": { "image": "assembly" }, + "/\\.((c([+px]{2}?)?-?)?objdump|bsdiff|bin|dat|pak|pdb)$/i": { + "image": "assembly" + }, ".d-objdump": { "image": "assembly" }, "/\\.gcode|\\.gco/i": { "image": "assembly" }, "/\\.rpy[bc]$/i": { "image": "assembly" }, @@ -150,7 +154,9 @@ ".dm": { "image": "dm" }, ".dme": { "image": "dm" }, ".dmm": { "image": "dm" }, - "/^(Dockerfile|docker-compose)|\\.docker(file|ignore)$/i": { "image": "docker" }, + "/^(Dockerfile|docker-compose)|\\.docker(file|ignore)$/i": { + "image": "docker" + }, "/^docker-sync\\.yml$/i": { "image": "docker" }, ".editorconfig": { "image": "editorconfig" }, ".ejs": { "image": "ejs" }, @@ -274,13 +280,19 @@ "/^pkginfo$/": { "image": "manifest" }, "/^mime\\.types$/i": { "image": "manifest" }, "/^METADATA\\.pb$/": { "image": "manifest" }, - "/[\\/\\\\](?:magic[\\/\\\\]Magdir|file[\\/\\\\]magic)[\\/\\\\][-.\\w]+$/i": { "image": "manifest" }, - "/(\\\\|\\/)dev[-\\w]+\\1(?:[^\\\\\\/]+\\1)*(?!DESC|NOTES)(?:[A-Z][-A-Z]*)(?:\\.in)?$/": { "image": "manifest" }, + "/[\\/\\\\](?:magic[\\/\\\\]Magdir|file[\\/\\\\]magic)[\\/\\\\][-.\\w]+$/i": { + "image": "manifest" + }, + "/(\\\\|\\/)dev[-\\w]+\\1(?:[^\\\\\\/]+\\1)*(?!DESC|NOTES)(?:[A-Z][-A-Z]*)(?:\\.in)?$/": { + "image": "manifest" + }, "lib/icons/.icondb.js": { "image": "manifest" }, "/\\.git[\\/\\\\](.*[\\/\\\\])?(HEAD|ORIG_HEAD|packed-refs|logs[\\/\\\\](.+[\\/\\\\])?[^\\/\\\\]+)$/": { "image": "manifest" }, - "/\\.(md|mdown|markdown|mkd|mkdown|mdwn|mkdn|rmd|ron|pmd)$/i": { "image": "markdown" }, + "/\\.(md|mdown|markdown|mkd|mkdown|mdwn|mkdn|rmd|ron|pmd)$/i": { + "image": "markdown" + }, ".mdx": { "image": "markdownx" }, ".marko": { "image": "marko" }, ".nim": { "image": "nim" }, @@ -329,7 +341,9 @@ ".psm1": { "image": "powershell" }, ".ps1xml": { "image": "powershell" }, ".prettierignore": { "image": "prettier" }, - "/\\.prettier((rc)|(\\.(toml|yml|yaml|json|js))?$){2}/i": { "image": "prettier" }, + "/\\.prettier((rc)|(\\.(toml|yml|yaml|json|js))?$){2}/i": { + "image": "prettier" + }, "prettier.config.js": { "image": "prettier" }, "prisma.yml": { "image": "prisma" }, ".pde": { "image": "processing" }, @@ -359,7 +373,9 @@ "/\\.(r|Rprofile|rsx|rd)$/i": { "image": "r" }, ".rkt": { "image": "racket" }, "/\\.res?i?$/i": { "image": "reasonml" }, - "/\\.(rb|ru|ruby|erb|gemspec|god|mspec|pluginspec|podspec|rabl|rake|opal)$/i": { "image": "ruby" }, + "/\\.(rb|ru|ruby|erb|gemspec|god|mspec|pluginspec|podspec|rabl|rake|opal)$/i": { + "image": "ruby" + }, "/^\\.?(irbrc|gemrc|pryrc|ruby-(gemset|version))$/i": { "image": "ruby" }, "/^(Appraisals|(Rake|[bB]uild|Cap|Danger|Deliver|Fast|Guard|Jar|Maven|Pod|Puppet|Snap)file(\\.lock)?)$/": { "image": "ruby" @@ -377,13 +393,19 @@ }, "/\\.(ksh|mksh|pdksh)$/i": { "image": "shell" }, ".sh-session": { "image": "shell" }, - "/\\.zsh(-theme|_history)?$|^\\.?(antigen|zpreztorc|zlogin|zlogout|zprofile|zshenv|zshrc)$/i": { "image": "shell" }, + "/\\.zsh(-theme|_history)?$|^\\.?(antigen|zpreztorc|zlogin|zlogout|zprofile|zshenv|zshrc)$/i": { + "image": "shell" + }, "/\\.fish$|^\\.fishrc$/i": { "image": "shell" }, "/^\\.?(login|profile)$/": { "image": "shell" }, ".inputrc": { "image": "shell" }, ".tmux": { "image": "shell" }, - "/^(configure|config\\.(guess|rpath|status|sub)|depcomp|libtool|compile)$/": { "image": "shell" }, - "/^\\/(private\\/)?etc\\/([^\\/]+\\/)*(profile$|nanorc$|rc\\.|csh\\.)/i": { "image": "shell" }, + "/^(configure|config\\.(guess|rpath|status|sub)|depcomp|libtool|compile)$/": { + "image": "shell" + }, + "/^\\/(private\\/)?etc\\/([^\\/]+\\/)*(profile$|nanorc$|rc\\.|csh\\.)/i": { + "image": "shell" + }, "/^\\.?cshrc$/i": { "image": "shell" }, ".profile": { "image": "shell" }, ".tcsh": { "image": "shell" }, diff --git a/src/extension.ts b/src/extension.ts index 4f58f44..343188a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,28 +1,40 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ -const { Client } = require('discord-rpc'); // eslint-disable-line -import { commands, ExtensionContext, StatusBarAlignment, StatusBarItem, window, workspace, debug } from 'vscode'; -import throttle from 'lodash-es/throttle'; +const { Client } = require("discord-rpc"); // eslint-disable-line +import throttle from "lodash-es/throttle"; +import { + type ExtensionContext, + StatusBarAlignment, + type StatusBarItem, + commands, + debug, + window, + workspace, +} from "vscode"; -import { activity } from './activity'; -import { CLIENT_ID, CONFIG_KEYS } from './constants'; -import { log, LogLevel } from './logger'; -import { getConfig, getGit } from './util'; +import { activity } from "./activity"; +import { CLIENT_ID, CONFIG_KEYS } from "./constants"; +import { LogLevel, log } from "./logger"; +import { getConfig, getGit } from "./util"; -const statusBarIcon: StatusBarItem = window.createStatusBarItem(StatusBarAlignment.Left); -statusBarIcon.text = '$(pulse) Connecting to Discord...'; +const statusBarIcon: StatusBarItem = window.createStatusBarItem( + StatusBarAlignment.Left, +); +statusBarIcon.text = "$(pulse) Connecting to Discord..."; // eslint-disable-next-line -let rpc = new Client({ transport: 'ipc' }); +let rpc = new Client({ transport: "ipc" }); const config = getConfig(); let state = {}; let idle: NodeJS.Timeout | undefined; -let listeners: { dispose: () => any }[] = []; +let listeners: { dispose: () => void }[] = []; export function cleanUp() { // eslint-disable-next-line @typescript-eslint/no-unsafe-return - listeners.forEach((listener) => listener.dispose()); + for (const listener of listeners) { + listener.dispose(); + } listeners = []; } @@ -34,50 +46,70 @@ async function sendActivity() { } async function login() { - log(LogLevel.Info, 'Creating discord-rpc client'); - rpc = new Client({ transport: 'ipc' }); + log(LogLevel.Info, "Creating discord-rpc client"); + rpc = new Client({ transport: "ipc" }); - rpc.on('ready', () => { - log(LogLevel.Info, 'Successfully connected to Discord'); + rpc.on("ready", () => { + log(LogLevel.Info, "Successfully connected to Discord"); cleanUp(); - statusBarIcon.text = '$(globe) Connected to Discord'; - statusBarIcon.tooltip = 'Connected to Discord'; + statusBarIcon.text = "$(globe) Connected to Discord"; + statusBarIcon.tooltip = "Connected to Discord"; void sendActivity(); - const onChangeActiveTextEditor = window.onDidChangeActiveTextEditor(() => sendActivity()); - const onChangeTextDocument = workspace.onDidChangeTextDocument(throttle(() => sendActivity(), 2000)); - const onStartDebugSession = debug.onDidStartDebugSession(() => sendActivity()); - const onTerminateDebugSession = debug.onDidTerminateDebugSession(() => sendActivity()); + const onChangeActiveTextEditor = window.onDidChangeActiveTextEditor(() => + sendActivity(), + ); + const onChangeTextDocument = workspace.onDidChangeTextDocument( + throttle(() => sendActivity(), 2000), + ); + const onStartDebugSession = debug.onDidStartDebugSession(() => + sendActivity(), + ); + const onTerminateDebugSession = debug.onDidTerminateDebugSession(() => + sendActivity(), + ); - listeners.push(onChangeActiveTextEditor, onChangeTextDocument, onStartDebugSession, onTerminateDebugSession); + listeners.push( + onChangeActiveTextEditor, + onChangeTextDocument, + onStartDebugSession, + onTerminateDebugSession, + ); }); - rpc.on('disconnected', () => { + rpc.on("disconnected", () => { cleanUp(); rpc.destroy(); - statusBarIcon.text = '$(pulse) Reconnect to Discord'; - statusBarIcon.command = 'discord.reconnect'; + statusBarIcon.text = "$(pulse) Reconnect to Discord"; + statusBarIcon.command = "discord.reconnect"; }); try { await rpc.login({ clientId: CLIENT_ID }); } catch (error) { - log(LogLevel.Error, `Encountered following error while trying to login:\n${error as string}`); + log( + LogLevel.Error, + `Encountered following error while trying to login:\n${error as string}`, + ); cleanUp(); rpc.destroy(); if (!config[CONFIG_KEYS.SuppressNotifications]) { // @ts-expect-error - if (error?.message?.includes('ENOENT')) void window.showErrorMessage('No Discord client detected'); - else void window.showErrorMessage(`Couldn't connect to Discord via RPC: ${error as string}`); + if (error?.message?.includes("ENOENT")) + void window.showErrorMessage("No Discord client detected"); + else + void window.showErrorMessage( + `Couldn't connect to Discord via RPC: ${error as string}`, + ); } - statusBarIcon.text = '$(pulse) Reconnect to Discord'; - statusBarIcon.command = 'discord.reconnect'; + statusBarIcon.text = "$(pulse) Reconnect to Discord"; + statusBarIcon.command = "discord.reconnect"; } } export async function activate(context: ExtensionContext) { - log(LogLevel.Info, 'Discord Presence activated'); + log(LogLevel.Info, "Discord Presence activated"); let isWorkspaceExcluded = false; for (const pattern of config[CONFIG_KEYS.WorkspaceExcludePatterns]) { @@ -93,52 +125,62 @@ export async function activate(context: ExtensionContext) { const enable = async (update = true) => { if (update) { try { - await config.update('enabled', true); + await config.update("enabled", true); } catch {} } - log(LogLevel.Info, 'Enable: Cleaning up old listeners'); + log(LogLevel.Info, "Enable: Cleaning up old listeners"); cleanUp(); - statusBarIcon.text = '$(pulse) Connecting to Discord...'; + statusBarIcon.text = "$(pulse) Connecting to Discord..."; statusBarIcon.show(); - log(LogLevel.Info, 'Enable: Attempting to recreate login'); + log(LogLevel.Info, "Enable: Attempting to recreate login"); void login(); }; const disable = async (update = true) => { if (update) { try { - await config.update('enabled', false); + await config.update("enabled", false); } catch {} } - log(LogLevel.Info, 'Disable: Cleaning up old listeners'); + log(LogLevel.Info, "Disable: Cleaning up old listeners"); cleanUp(); void rpc?.destroy(); - log(LogLevel.Info, 'Disable: Destroyed the rpc instance'); + log(LogLevel.Info, "Disable: Destroyed the rpc instance"); statusBarIcon.hide(); }; - const enabler = commands.registerCommand('discord.enable', async () => { + const enabler = commands.registerCommand("discord.enable", async () => { await disable(); await enable(); - await window.showInformationMessage('Enabled Discord Presence for this workspace'); + await window.showInformationMessage( + "Enabled Discord Presence for this workspace", + ); }); - const disabler = commands.registerCommand('discord.disable', async () => { + const disabler = commands.registerCommand("discord.disable", async () => { await disable(); - await window.showInformationMessage('Disabled Discord Presence for this workspace'); + await window.showInformationMessage( + "Disabled Discord Presence for this workspace", + ); }); - const reconnecter = commands.registerCommand('discord.reconnect', async () => { - await disable(false); - await enable(false); - }); + const reconnecter = commands.registerCommand( + "discord.reconnect", + async () => { + await disable(false); + await enable(false); + }, + ); - const disconnect = commands.registerCommand('discord.disconnect', async () => { - await disable(false); - statusBarIcon.text = '$(pulse) Reconnect to Discord'; - statusBarIcon.command = 'discord.reconnect'; - statusBarIcon.show(); - }); + const disconnect = commands.registerCommand( + "discord.disconnect", + async () => { + await disable(false); + statusBarIcon.text = "$(pulse) Reconnect to Discord"; + statusBarIcon.command = "discord.reconnect"; + statusBarIcon.show(); + }, + ); context.subscriptions.push(enabler, disabler, reconnecter, disconnect); diff --git a/src/git.d.ts b/src/git.d.ts index d9892ac..6fdce9e 100644 --- a/src/git.d.ts +++ b/src/git.d.ts @@ -12,8 +12,8 @@ * -------------------------------------------------------------------------------------------- */ -import { Uri, Event, Disposable, ProviderResult } from 'vscode'; -export { ProviderResult } from 'vscode'; +import type { Disposable, Event, ProviderResult, Uri } from "vscode"; +export { ProviderResult } from "vscode"; export interface Git { readonly path: string; @@ -23,15 +23,15 @@ export interface InputBox { value: string; } -export const enum ForcePushMode { - Force, - ForceWithLease, +export enum ForcePushMode { + Force = "Force", + ForceWithLease = "ForceWithLease", } -export const enum RefType { - Head, - RemoteHead, - Tag, +export enum RefType { + Head = "Head", + RemoteHead = "RemoteHead", + Tag = "Tag", } export interface Ref { @@ -75,26 +75,26 @@ export interface Remote { readonly isReadOnly: boolean; } -export const enum Status { - INDEX_MODIFIED, - INDEX_ADDED, - INDEX_DELETED, - INDEX_RENAMED, - INDEX_COPIED, +export enum Status { + INDEX_MODIFIED = "INDEX_MODIFIED", + INDEX_ADDED = "INDEX_ADDED", + INDEX_DELETED = "INDEX_DELETED", + INDEX_RENAMED = "INDEX_RENAMED", + INDEX_COPIED = "INDEX_COPIED", - MODIFIED, - DELETED, - UNTRACKED, - IGNORED, - INTENT_TO_ADD, + MODIFIED = "MODIFIED", + DELETED = "DELETED", + UNTRACKED = "UNTRACKED", + IGNORED = "IGNORED", + INTENT_TO_ADD = "INTENT_TO_ADD", - ADDED_BY_US, - ADDED_BY_THEM, - DELETED_BY_US, - DELETED_BY_THEM, - BOTH_ADDED, - BOTH_DELETED, - BOTH_MODIFIED, + ADDED_BY_US = "ADDED_BY_US", + ADDED_BY_THEM = "ADDED_BY_THEM", + DELETED_BY_US = "DELETED_BY_US", + DELETED_BY_THEM = "DELETED_BY_THEM", + BOTH_ADDED = "BOTH_ADDED", + BOTH_DELETED = "BOTH_DELETED", + BOTH_MODIFIED = "BOTH_MODIFIED", } export interface Change { @@ -138,7 +138,7 @@ export interface LogOptions { } export interface CommitOptions { - all?: boolean | 'tracked'; + all?: boolean | "tracked"; amend?: boolean; signoff?: boolean; signCommit?: boolean; @@ -173,8 +173,13 @@ export interface Repository { setConfig(key: string, value: string): Promise; getGlobalConfig(key: string): Promise; - getObjectDetails(treeish: string, path: string): Promise<{ mode: string; object: string; size: number }>; - detectObjectType(object: string): Promise<{ mimetype: string; encoding?: string }>; + getObjectDetails( + treeish: string, + path: string, + ): Promise<{ mode: string; object: string; size: number }>; + detectObjectType( + object: string, + ): Promise<{ mimetype: string; encoding?: string }>; buffer(ref: string, path: string): Promise; show(ref: string, path: string): Promise; getCommit(ref: string): Promise; @@ -215,7 +220,12 @@ export interface Repository { fetch(options?: FetchOptions): Promise; fetch(remote?: string, ref?: string, depth?: number): Promise; pull(unshallow?: boolean): Promise; - push(remoteName?: string, branchName?: string, setUpstream?: boolean, force?: ForcePushMode): Promise; + push( + remoteName?: string, + branchName?: string, + setUpstream?: boolean, + force?: ForcePushMode, + ): Promise; blame(path: string): Promise; log(options?: LogOptions): Promise; @@ -256,7 +266,7 @@ export interface PushErrorHandler { ): Promise; } -export type APIState = 'uninitialized' | 'initialized'; +export type APIState = "uninitialized" | "initialized"; export interface PublishEvent { repository: Repository; @@ -299,40 +309,40 @@ export interface GitExtension { getAPI(version: 1): API; } -export const enum GitErrorCodes { - BadConfigFile = 'BadConfigFile', - AuthenticationFailed = 'AuthenticationFailed', - NoUserNameConfigured = 'NoUserNameConfigured', - NoUserEmailConfigured = 'NoUserEmailConfigured', - NoRemoteRepositorySpecified = 'NoRemoteRepositorySpecified', - NotAGitRepository = 'NotAGitRepository', - NotAtRepositoryRoot = 'NotAtRepositoryRoot', - Conflict = 'Conflict', - StashConflict = 'StashConflict', - UnmergedChanges = 'UnmergedChanges', - PushRejected = 'PushRejected', - RemoteConnectionError = 'RemoteConnectionError', - DirtyWorkTree = 'DirtyWorkTree', - CantOpenResource = 'CantOpenResource', - GitNotFound = 'GitNotFound', - CantCreatePipe = 'CantCreatePipe', - PermissionDenied = 'PermissionDenied', - CantAccessRemote = 'CantAccessRemote', - RepositoryNotFound = 'RepositoryNotFound', - RepositoryIsLocked = 'RepositoryIsLocked', - BranchNotFullyMerged = 'BranchNotFullyMerged', - NoRemoteReference = 'NoRemoteReference', - InvalidBranchName = 'InvalidBranchName', - BranchAlreadyExists = 'BranchAlreadyExists', - NoLocalChanges = 'NoLocalChanges', - NoStashFound = 'NoStashFound', - LocalChangesOverwritten = 'LocalChangesOverwritten', - NoUpstreamBranch = 'NoUpstreamBranch', - IsInSubmodule = 'IsInSubmodule', - WrongCase = 'WrongCase', - CantLockRef = 'CantLockRef', - CantRebaseMultipleBranches = 'CantRebaseMultipleBranches', - PatchDoesNotApply = 'PatchDoesNotApply', - NoPathFound = 'NoPathFound', - UnknownPath = 'UnknownPath', +export enum GitErrorCodes { + BadConfigFile = "BadConfigFile", + AuthenticationFailed = "AuthenticationFailed", + NoUserNameConfigured = "NoUserNameConfigured", + NoUserEmailConfigured = "NoUserEmailConfigured", + NoRemoteRepositorySpecified = "NoRemoteRepositorySpecified", + NotAGitRepository = "NotAGitRepository", + NotAtRepositoryRoot = "NotAtRepositoryRoot", + Conflict = "Conflict", + StashConflict = "StashConflict", + UnmergedChanges = "UnmergedChanges", + PushRejected = "PushRejected", + RemoteConnectionError = "RemoteConnectionError", + DirtyWorkTree = "DirtyWorkTree", + CantOpenResource = "CantOpenResource", + GitNotFound = "GitNotFound", + CantCreatePipe = "CantCreatePipe", + PermissionDenied = "PermissionDenied", + CantAccessRemote = "CantAccessRemote", + RepositoryNotFound = "RepositoryNotFound", + RepositoryIsLocked = "RepositoryIsLocked", + BranchNotFullyMerged = "BranchNotFullyMerged", + NoRemoteReference = "NoRemoteReference", + InvalidBranchName = "InvalidBranchName", + BranchAlreadyExists = "BranchAlreadyExists", + NoLocalChanges = "NoLocalChanges", + NoStashFound = "NoStashFound", + LocalChangesOverwritten = "LocalChangesOverwritten", + NoUpstreamBranch = "NoUpstreamBranch", + IsInSubmodule = "IsInSubmodule", + WrongCase = "WrongCase", + CantLockRef = "CantLockRef", + CantRebaseMultipleBranches = "CantRebaseMultipleBranches", + PatchDoesNotApply = "PatchDoesNotApply", + NoPathFound = "NoPathFound", + UnknownPath = "UnknownPath", } diff --git a/src/logger.ts b/src/logger.ts index 5e8e8c5..749ce5b 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,22 +1,24 @@ -import { window } from 'vscode'; -import dayjs from 'dayjs'; +import dayjs from "dayjs"; +import { window } from "vscode"; -const outputChannel = window.createOutputChannel('Discord Presence'); +const outputChannel = window.createOutputChannel("Discord Presence"); -export const enum LogLevel { - Trace = 'TRACE', - Debug = 'DEBUG', - Info = 'INFO', - Warn = 'WARN', - Error = 'ERROR', +export enum LogLevel { + Trace = "TRACE", + Debug = "DEBUG", + Info = "INFO", + Warn = "WARN", + Error = "ERROR", } function send(level: string, message: string) { - outputChannel.appendLine(`[${dayjs().format('DD/MM/YYYY HH:mm:ss')} - ${level}] ${message}`); + outputChannel.appendLine( + `[${dayjs().format("DD/MM/YYYY HH:mm:ss")} - ${level}] ${message}`, + ); } export function log(level: LogLevel, message: string | Error) { - if (typeof message === 'string') { + if (typeof message === "string") { send(level, message); } else if (message instanceof Error) { send(level, message.message); @@ -24,7 +26,7 @@ export function log(level: LogLevel, message: string | Error) { if (message.stack) { send(level, message.stack); } - } else if (typeof message === 'object') { + } else if (typeof message === "object") { try { const json = JSON.stringify(message, null, 2); send(level, json); diff --git a/src/util.ts b/src/util.ts index 9bd24df..c9090c9 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,9 +1,14 @@ -import { basename } from 'path'; -import { TextDocument, workspace, extensions, WorkspaceConfiguration } from 'vscode'; +import { basename } from "node:path"; +import { + type TextDocument, + type WorkspaceConfiguration, + extensions, + workspace, +} from "vscode"; -import { KNOWN_EXTENSIONS, KNOWN_LANGUAGES } from './constants'; -import type { API, GitExtension } from './git'; -import { log, LogLevel } from './logger'; +import { KNOWN_EXTENSIONS, KNOWN_LANGUAGES } from "./constants"; +import type { API, GitExtension } from "./git"; +import { LogLevel, log } from "./logger"; let git: API | null | undefined; @@ -30,14 +35,17 @@ type WorkspaceExtensionConfiguration = WorkspaceConfiguration & { }; export function getConfig() { - return workspace.getConfiguration('discord') as WorkspaceExtensionConfiguration; + return workspace.getConfiguration( + "discord", + ) as WorkspaceExtensionConfiguration; } export const toLower = (str: string) => str.toLocaleLowerCase(); export const toUpper = (str: string) => str.toLocaleUpperCase(); -export const toTitle = (str: string) => toLower(str).replace(/^\w/, (c) => toUpper(c)); +export const toTitle = (str: string) => + toLower(str).replace(/^\w/, (c) => toUpper(c)); export function resolveFileIcon(document: TextDocument) { const filename = basename(document.fileName); @@ -54,14 +62,16 @@ export function resolveFileIcon(document: TextDocument) { const regex = new RegExp(match[1], match[2]); return regex.test(filename); }); - const findKnownLanguage = KNOWN_LANGUAGES.find((key) => key.language === document.languageId); + const findKnownLanguage = KNOWN_LANGUAGES.find( + (key) => key.language === document.languageId, + ); const fileIcon = findKnownExtension ? KNOWN_EXTENSIONS[findKnownExtension] : findKnownLanguage - ? findKnownLanguage.image - : null; + ? findKnownLanguage.image + : null; - return typeof fileIcon === 'string' ? fileIcon : fileIcon?.image ?? 'text'; + return typeof fileIcon === "string" ? fileIcon : (fileIcon?.image ?? "text"); } export async function getGit() { @@ -70,16 +80,19 @@ export async function getGit() { } try { - log(LogLevel.Debug, 'Loading git extension'); - const gitExtension = extensions.getExtension('vscode.git'); + log(LogLevel.Debug, "Loading git extension"); + const gitExtension = extensions.getExtension("vscode.git"); if (!gitExtension?.isActive) { - log(LogLevel.Trace, 'Git extension not activated, activating...'); + log(LogLevel.Trace, "Git extension not activated, activating..."); await gitExtension?.activate(); } git = gitExtension?.exports.getAPI(1); } catch (error) { git = null; - log(LogLevel.Error, `Failed to load git extension, is git installed?; ${error as string}`); + log( + LogLevel.Error, + `Failed to load git extension, is git installed?; ${error as string}`, + ); } return git; diff --git a/webpack.config.js b/webpack.config.js index 349b25f..e34ab4a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,25 +1,25 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-require-imports */ -const { CleanWebpackPlugin } = require('clean-webpack-plugin'); -const TerserPlugin = require('terser-webpack-plugin'); -const path = require('path'); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); +const path = require("node:path"); /** @type {import('webpack').Configuration} */ module.exports = { - target: 'node', - entry: './src/extension.ts', + target: "node", + entry: "./src/extension.ts", output: { - filename: 'extension.js', - libraryTarget: 'commonjs2', - path: path.resolve(process.cwd(), 'dist'), + filename: "extension.js", + libraryTarget: "commonjs2", + path: path.resolve(process.cwd(), "dist"), }, - devtool: 'source-map', + devtool: "source-map", externals: { - vscode: 'commonjs vscode', + vscode: "commonjs vscode", }, resolve: { - extensions: ['.ts', '.js', '.json'], + extensions: [".ts", ".js", ".json"], }, plugins: [new CleanWebpackPlugin()], optimization: { @@ -42,7 +42,7 @@ module.exports = { rules: [ { test: /\.ts$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ],