diff --git a/README.md b/README.md index cde11bd..01461b5 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,53 @@ # Discord Presence -> Update your discord status with the newly added rich presence. +> Update your discord status with a rich presence.

- VS Code Marketplace + Visual Studio Marketplace Version + + + Visual Studio Marketplace Downloads + + + Visual Studio Marketplace Rating Discord server

+

+ + Open VSX Version + + + Open VSX Downloads + + + Open VSX Rating + +

## Features -- Shows what you are editing in VSCode with no bullsh\*t involved -- Support for over 130 of the most popular languages +- Shows what you are editing in VSCode +- Support for over 140 of the most popular languages - Enable/Disable Rich Presence for individual workspaces (enabled by default) - Custom string support -- Respects Discords 15sec limit when it comes to updating your status - Stable or Insiders build detection - Debug mode detection - Easily manually reconnect to Discord -- VSCode Live Share support ## Troubleshooting -### Can't connect to Discord? Check those: +**Windows:** Do not run your VSCode or Discord as admin, there is no reason to and it just further complicates everything down the line. +**Linux:** Discord versions installed using `flatpak` or `snap` need modifications in order to support IPC. In order to avoid this (and as Discord itself suggests) you should download it from [discord.com](https://discord.com/download) + +References: +https://github.com/flathub/com.discordapp.Discord/issues/29 https://github.com/iCrawl/discord-vscode/issues/77#issuecomment-435622205 https://github.com/iCrawl/discord-vscode/issues/85#issuecomment-417895483 diff --git a/package-lock.json b/package-lock.json index b235845..0fc62e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,10 +11,12 @@ "bufferutil": "^4.0.3", "dayjs": "^1.10.4", "discord-rpc": "^3.1.4", + "lodash-es": "^4.17.20", "tslib": "^2.1.0", "utf-8-validate": "^5.0.4" }, "devDependencies": { + "@types/lodash-es": "^4.17.4", "@types/node": "^14.14.25", "@types/vscode": "^1.53.0", "@typescript-eslint/eslint-plugin": "^4.15.0", @@ -195,6 +197,21 @@ "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.168", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", + "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==", + "dev": true + }, + "node_modules/@types/lodash-es": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.4.tgz", + "integrity": "sha512-BBz79DCJbD2CVYZH67MBeHZRX++HF+5p8Mo5MzjZi64Wac39S3diedJYHZtScbRVf4DjZyN6LzA0SB0zy+HSSQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -1963,6 +1980,11 @@ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, + "node_modules/lodash-es": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.20.tgz", + "integrity": "sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3317,6 +3339,21 @@ "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, + "@types/lodash": { + "version": "4.14.168", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", + "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==", + "dev": true + }, + "@types/lodash-es": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.4.tgz", + "integrity": "sha512-BBz79DCJbD2CVYZH67MBeHZRX++HF+5p8Mo5MzjZi64Wac39S3diedJYHZtScbRVf4DjZyN6LzA0SB0zy+HSSQ==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -4780,6 +4817,11 @@ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, + "lodash-es": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.20.tgz", + "integrity": "sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA==" + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", diff --git a/package.json b/package.json index abde837..7bbb1fa 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "discord-vscode", "displayName": "Discord Presence", "version": "5.0.0", - "description": "Update your discord status with the newly added rich presence.", + "description": "Update your discord status with a rich presence.", "private": true, "author": { "name": "iCrawl", @@ -62,67 +62,62 @@ "default": true, "description": "Controls if the Discord Presence should show across all workspaces" }, - "discord.details_idling": { + "discord.detailsIdling": { "type": "string", "default": "Idling", "description": "Custom string for the details section of the rich presence when idling\n\t- '{empty}' will be replaced with an empty space." }, - "discord.details_editing": { + "discord.detailsEditing": { "type": "string", "default": "Editing {file_name}", "description": "Custom string for the details section of the rich presence\n\t- '{empty}' will be replaced with an empty space.\n\t- '{file_name}' will be replaced with the current file name.\n\t- '{dir_name}' will get replaced with the folder name that has the current file.\n\t- '{full_dir_name}' will get replaced with the full directory name without the current file name.\n\t- '{workspace}' will be replaced with the current workspace name, if any.\n\t- '{workspace_folder}' will be replaced with the currently accessed workspace folder, if any.\n\t- '{workspace_and_folder} will be replaced with the currently accessed workspace and workspace folder like this: 'Workspace - WorkspaceFolder'\n\t- '{current_column}' will get replaced with the current column of the current line.\n\t- '{current_line}' will get replaced with the current line number.\n\t- '{total_lines}' will get replaced with the total line number.\n\t- '{file_size}' will get replaced with the current file's size.\n\t- '{git_repo_name}' will be replaced with the active Git repository name (from the git URL)\n\t- '{git_branch}' will be replaced with the current active branch name." }, - "discord.details_debugging": { + "discord.detailsDebugging": { "type": "string", "default": "Debugging {file_name}", "description": "Custom string for the details section of the rich presence when debugging\n\t- '{empty}' will be replaced with an empty space.\n\t- '{file_name}' will be replaced with the current file name.\n\t- '{dir_name}' will get replaced with the folder name that has the current file.\n\t- '{full_dir_name}' will get replaced with the full directory name without the current file name.\n\t- '{workspace}' will be replaced with the current workspace name, if any.\n\t- '{workspace_folder}' will be replaced with the currently accessed workspace folder, if any.\n\t- '{workspace_and_folder} will be replaced with the currently accessed workspace and workspace folder like this: 'Workspace - WorkspaceFolder'\n\t- '{current_column}' will get replaced with the current column of the current line.\n\t- '{current_line}' will get replaced with the current line number.\n\t- '{total_lines}' will get replaced with the total line number.\n\t- '{file_size}' will get replaced with the current file's size.\n\t- '{git_repo_name}' will be replaced with the active Git repository name (from the git URL)\n\t- '{git_branch}' will be replaced with the current active branch name." }, - "discord.lower_details_idling": { + "discord.lowerDetailsIdling": { "type": "string", "default": "Idling", "description": "Custom string for the state section of the rich presence when idling\n\t- '{empty}' will be replaced with an empty space." }, - "discord.lower_details_editing": { + "discord.lowerDetailsEditing": { "type": "string", "default": "Workspace: {workspace}", "description": "Custom string for the state section of the rich presence\n\t- '{empty}' will be replaced with an empty space.\n\t- '{file_name}' will be replaced with the current file name.\n\t- '{dir_name}' will get replaced with the folder name that has the current file.\n\t- '{full_dir_name}' will get replaced with the full directory name without the current file name.\n\t- '{workspace}' will be replaced with the current workspace name, if any.\n\t- '{workspace_folder}' will be replaced with the currently accessed workspace folder, if any.\n\t- '{workspace_and_folder} will be replaced with the currently accessed workspace and workspace folder like this: 'Workspace - WorkspaceFolder'\n\t- '{current_column}' will get replaced with the current column of the current line.\n\t- '{current_line}' will get replaced with the current line number.\n\t- '{total_lines}' will get replaced with the total line number.\n\t- '{file_size}' will get replaced with the current file's size.\n\t- '{git_repo_name}' will be replaced with the active Git repository name (from the git URL)\n\t- '{git_branch}' will be replaced with the current active branch name." }, - "discord.lower_details_debugging": { + "discord.lowerDetailsDebugging": { "type": "string", "default": "Debugging: {workspace}", "description": "Custom string for the state section of the rich presence when debugging\n\t- '{empty}' will be replaced with an empty space.\n\t- '{file_name}' will be replaced with the current file name.\n\t- '{dir_name}' will get replaced with the folder name that has the current file.\n\t- '{full_dir_name}' will get replaced with the full directory name without the current file name.\n\t- '{workspace}' will be replaced with the current workspace name, if any.\n\t- '{workspace_folder}' will be replaced with the currently accessed workspace folder, if any.\n\t- '{workspace_and_folder} will be replaced with the currently accessed workspace and workspace folder like this: 'Workspace - WorkspaceFolder'\n\t- '{current_column}' will get replaced with the current column of the current line.\n\t- '{current_line}' will get replaced with the current line number.\n\t- '{total_lines}' will get replaced with the total line number.\n\t- '{file_size}' will get replaced with the current file's size.\n\t- '{git_repo_name}' will be replaced with the active Git repository name (from the git URL)\n\t- '{git_branch}' will be replaced with the current active branch name." }, - "discord.lower_details_no_workspace_found": { + "discord.lowerDetailsNoWorkspaceFound": { "type": "string", "default": "No workspace.", "description": "Custom string for the state section of the rich presence when no workspace is found.\nIf set to '{empty}', this will be an empty space.\n\t- '{current_line}' will get replaced with the current line number.\n\t- '{total_lines}' will get replaced with the total line number.\n\t- '{file_size}' will get replaced with the current file's size." }, - "discord.large_image_idling": { + "discord.largeImageIdling": { "type": "string", "default": "Idling", "description": "Custom string for the largeImageText section of the rich presence when idling" }, - "discord.large_image": { + "discord.largeImage": { "type": "string", "default": "Editing a {LANG} file", "description": "Custom string for the largeImageText section of the rich presence.\n\t- '{lang}' will be replaced with the lowercased language ID\n\t- '{LANG}' will be replaced with the uppercased language ID" }, - "discord.small_image": { + "discord.smallImage": { "type": "string", "default": "{app_name}", "description": "Custom string for the smallImageText section of the rich presence\n\t- '{app_name}' will get replaced with the current Visual Studio Code version." }, - "discord.suppress_notifications": { + "discord.suppressNotifications": { "type": "boolean", "default": false, "description": "Decides if error messages are shown to the user" }, - "discord.workspace_elapsed_time": { - "type": "boolean", - "default": true, - "description": "Decides whether to display elapsed time for a workspace or a single file" - }, - "discord.workspace_exclude_patterns": { + "discord.workspaceExcludePatterns": { "type": "array", "items": { "type": "string" @@ -162,10 +157,12 @@ "bufferutil": "^4.0.3", "dayjs": "^1.10.4", "discord-rpc": "^3.1.4", + "lodash-es": "^4.17.20", "tslib": "^2.1.0", "utf-8-validate": "^5.0.4" }, "devDependencies": { + "@types/lodash-es": "^4.17.4", "@types/node": "^14.14.25", "@types/vscode": "^1.53.0", "@typescript-eslint/eslint-plugin": "^4.15.0", diff --git a/src/activity.ts b/src/activity.ts index 41cd962..8ec193c 100644 --- a/src/activity.ts +++ b/src/activity.ts @@ -8,6 +8,8 @@ import { FILE_SIZES, IDLE_IMAGE_KEY, REPLACE_KEYS, + UNKNOWN_GIT_BRANCH, + UNKNOWN_GIT_REPO_NAME, VSCODE_IMAGE_KEY, VSCODE_INSIDERS_IMAGE_KEY, } from './constants'; @@ -16,7 +18,7 @@ import { log, LogLevel } from './logger'; import { getConfig, resolveFileIcon, toLower, toTitle, toUpper } from './util'; interface ActivityPayload { - details: string; + details?: string; state?: string; startTimestamp?: number | null; largeImageKey?: string; @@ -32,7 +34,7 @@ interface ActivityPayload { instance?: boolean; } -export async function activity() { +export async function activity(previous: ActivityPayload = {}) { const config = getConfig(); const appName = env.appName; @@ -49,7 +51,7 @@ export async function activity() { CONFIG_KEYS.LowerDetailsEditing, CONFIG_KEYS.LowerDetailsDebugging, ), - startTimestamp: null, + startTimestamp: previous.startTimestamp ?? Date.now(), largeImageKey: IDLE_IMAGE_KEY, largeImageText: config[CONFIG_KEYS.LargeImageIdling], smallImageKey: defaultSmallImageKey, @@ -57,6 +59,10 @@ export async function activity() { }; if (window.activeTextEditor) { + if (window.activeTextEditor.document.languageId === 'Log') { + return state; + } + const largeImageKey = resolveFileIcon(window.activeTextEditor.document); const largeImageText = config[CONFIG_KEYS.LargeImage] .replace(REPLACE_KEYS.LanguageLowerCase, toLower(largeImageKey)) @@ -75,9 +81,11 @@ export async function activity() { largeImageKey, largeImageText, }; + + log(LogLevel.Trace, `VSCode language id: ${window.activeTextEditor.document.languageId}`); } - log(LogLevel.Debug, JSON.stringify(state, null, 2)); + log(LogLevel.Debug, `Discord Presence being sent to discord:\n${JSON.stringify(state, null, 2)}`); return state; } @@ -171,7 +179,7 @@ async function fileDetails(_raw: string, document: TextDocument, selection: Sele git.repositories.find((repo) => repo.ui.selected)?.state.HEAD?.name ?? EMPTY, ); } else { - raw = raw.replace(REPLACE_KEYS.GitBranch, 'Unknown'); + raw = raw.replace(REPLACE_KEYS.GitBranch, UNKNOWN_GIT_BRANCH); } } @@ -185,7 +193,7 @@ async function fileDetails(_raw: string, document: TextDocument, selection: Sele .replace('.git', '') ?? EMPTY, ); } else { - raw = raw.replace(REPLACE_KEYS.GitRepoName, 'Unknown'); + raw = raw.replace(REPLACE_KEYS.GitRepoName, UNKNOWN_GIT_REPO_NAME); } } diff --git a/src/constants.ts b/src/constants.ts index 5bee0e7..592b0d8 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -13,6 +13,9 @@ export const DEBUG_IMAGE_KEY = 'debug'; export const VSCODE_IMAGE_KEY = 'vscode'; export const VSCODE_INSIDERS_IMAGE_KEY = 'vscode-insiders'; +export const UNKNOWN_GIT_BRANCH = 'Unknown.'; +export const UNKNOWN_GIT_REPO_NAME = 'Unknown.'; + export const enum REPLACE_KEYS { Empty = '{empty}', FileName = '{file_name}', @@ -35,17 +38,16 @@ export const enum REPLACE_KEYS { export const enum CONFIG_KEYS { Enabled = 'enabled', - DetailsIdling = 'details_idling', - DetailsEditing = 'details_editing', - DetailsDebugging = 'details_debugging', - LowerDetailsIdling = 'lower_details_idling', - LowerDetailsEditing = 'lower_details_editing', - LowerDetailsDebugging = 'lower_details_debugging', - LowerDetailsNoWorkspaceFound = 'lower_details_no_workspace_found', - LargeImageIdling = 'large_image_idling', - LargeImage = 'large_image', - SmallImage = 'small_image', - SuppressNotifications = 'suppress_notifications', - WorkspaceElapsedTime = 'workspace_elapsed_time', - WorkspaceExcludePatterns = 'workspace_exclude_patterns', + DetailsIdling = 'detailsIdling', + DetailsEditing = 'detailsEditing', + DetailsDebugging = 'detailsDebugging', + LowerDetailsIdling = 'lowerDetailsIdling', + LowerDetailsEditing = 'lowerDetailsEditing', + LowerDetailsDebugging = 'lowerDetailsDebugging', + LowerDetailsNoWorkspaceFound = 'lowerDetailsNoWorkspaceFound', + LargeImageIdling = 'largeImageIdling', + LargeImage = 'largeImage', + SmallImage = 'smallImage', + SuppressNotifications = 'suppressNotifications', + WorkspaceExcludePatterns = 'workspaceExcludePatterns', } diff --git a/src/extension.ts b/src/extension.ts index feaee46..db98f24 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,8 +9,9 @@ import { extensions, debug, } from 'vscode'; -import { activity } from './activity'; +import throttle from 'lodash-es/throttle'; +import { activity } from './activity'; import { CLIENT_ID, CONFIG_KEYS } from './constants'; import { GitExtension } from './git'; import { log, LogLevel } from './logger'; @@ -22,8 +23,13 @@ statusBarIcon.text = '$(pulse) Connecting to Discord...'; const rpc = new Client({ transport: 'ipc' }); const config = getConfig(); +let state = {}; + async function sendActivity() { - rpc.setActivity(await activity()); + state = { + ...(await activity(state)), + }; + rpc.setActivity(state); } async function login(context: ExtensionContext) { @@ -33,9 +39,8 @@ async function login(context: ExtensionContext) { statusBarIcon.text = '$(globe) Connected to Discord'; statusBarIcon.tooltip = 'Connected to Discord'; - void sendActivity(); const onChangeActiveTextEditor = window.onDidChangeActiveTextEditor(() => sendActivity()); - const onChangeTextDocument = workspace.onDidChangeTextDocument(() => sendActivity()); + const onChangeTextDocument = workspace.onDidChangeTextDocument(throttle(() => sendActivity(), 1000)); const onStartDebugSession = debug.onDidStartDebugSession(() => sendActivity()); const onTerminateDebugSession = debug.onDidTerminateDebugSession(() => sendActivity()); diff --git a/src/util.ts b/src/util.ts index 57fa778..1cf0f0a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -5,19 +5,18 @@ import { KNOWN_EXTENSIONS, KNOWN_LANGUAGES } from './constants'; type WorkspaceExtensionConfigurationuration = WorkspaceConfiguration & { enabled: boolean; - details_editing: string; - details_debugging: string; - details_idling: string; - lower_details_editing: string; - lower_details_debugging: string; - lower_details_idling: string; - lower_details_no_workspace_found: string; - large_image: string; - large_image_idling: string; - small_image: string; - suppress_notifications: boolean; - workspace_elapsed_time: boolean; - workspace_exclude_patterns: string[]; + detailsIdling: string; + detailsEditing: string; + detailsDebugging: string; + lowerDetailsIdling: string; + lowerDetailsEditing: string; + lowerDetailsDebugging: string; + lowerDetailsNoWorkspaceFound: string; + largeImageIdling: string; + largeImage: string; + smallImage: string; + suppressNotifications: boolean; + workspaceExcludePatterns: string[]; }; export function getConfig() {