From 62dcb3fbe6169db5fa2e330f9cc6938607c07eff Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Tue, 23 Dec 2025 00:09:45 +0530 Subject: [PATCH 1/6] Added support for Keybindings --- .../workflows/pull-request-check-licenses.yml | 5 + code/build/gulpfile.extensions.js | 1 + code/build/npm/dirs.js | 1 + code/extensions/che-keybindings/.vscodeignore | 8 + code/extensions/che-keybindings/README.md | 7 + .../extension.webpack.config.js | 31 ++++ .../images/eclipse-che-logo.png | Bin 0 -> 16725 bytes .../che-keybindings/package-lock.json | 153 ++++++++++++++++++ code/extensions/che-keybindings/package.json | 77 +++++++++ .../che-keybindings/package.nls.json | 4 + code/extensions/che-keybindings/src/cheAPi.ts | 52 ++++++ .../che-keybindings/src/extension.ts | 85 ++++++++++ .../che-keybindings/src/keybindings.ts | 38 +++++ code/extensions/che-keybindings/src/utils.ts | 19 +++ code/extensions/che-keybindings/tsconfig.json | 12 ++ 15 files changed, 493 insertions(+) create mode 100644 code/extensions/che-keybindings/.vscodeignore create mode 100644 code/extensions/che-keybindings/README.md create mode 100644 code/extensions/che-keybindings/extension.webpack.config.js create mode 100644 code/extensions/che-keybindings/images/eclipse-che-logo.png create mode 100644 code/extensions/che-keybindings/package-lock.json create mode 100644 code/extensions/che-keybindings/package.json create mode 100644 code/extensions/che-keybindings/package.nls.json create mode 100644 code/extensions/che-keybindings/src/cheAPi.ts create mode 100644 code/extensions/che-keybindings/src/extension.ts create mode 100644 code/extensions/che-keybindings/src/keybindings.ts create mode 100644 code/extensions/che-keybindings/src/utils.ts create mode 100644 code/extensions/che-keybindings/tsconfig.json diff --git a/.github/workflows/pull-request-check-licenses.yml b/.github/workflows/pull-request-check-licenses.yml index 4c7e75e4521d..6687f739db4e 100644 --- a/.github/workflows/pull-request-check-licenses.yml +++ b/.github/workflows/pull-request-check-licenses.yml @@ -59,3 +59,8 @@ jobs: docker run --rm -t \ -v $PWD/code/extensions/che-terminal:/workspace/project \ quay.io/che-incubator/dash-licenses:next --check + - name: Check che-keybindings dependencies usage restrictions + run: | + docker run --rm -t \ + -v $PWD/code/extensions/che-keybindings:/workspace/project \ + quay.io/che-incubator/dash-licenses:next --check diff --git a/code/build/gulpfile.extensions.js b/code/build/gulpfile.extensions.js index b0bedffacc1f..f0cf9765282f 100644 --- a/code/build/gulpfile.extensions.js +++ b/code/build/gulpfile.extensions.js @@ -37,6 +37,7 @@ const compilations = [ 'extensions/che-terminal/tsconfig.json', 'extensions/che-telemetry/tsconfig.json', 'extensions/che-github-authentication/tsconfig.json', + 'extensions/che-keybindings/tsconfig.json', 'extensions/configuration-editing/tsconfig.json', 'extensions/css-language-features/client/tsconfig.json', 'extensions/css-language-features/server/tsconfig.json', diff --git a/code/build/npm/dirs.js b/code/build/npm/dirs.js index 6a7343daff7d..9841e29a08ce 100644 --- a/code/build/npm/dirs.js +++ b/code/build/npm/dirs.js @@ -18,6 +18,7 @@ const dirs = [ 'extensions/che-resource-monitor', 'extensions/che-terminal', 'extensions/che-github-authentication', + 'extensions/che-keybindings', 'extensions/configuration-editing', 'extensions/css-language-features', 'extensions/css-language-features/server', diff --git a/code/extensions/che-keybindings/.vscodeignore b/code/extensions/che-keybindings/.vscodeignore new file mode 100644 index 000000000000..2b335b58dc58 --- /dev/null +++ b/code/extensions/che-keybindings/.vscodeignore @@ -0,0 +1,8 @@ +build/** +src/** +tests/** +coverage/** +out/** +tsconfig.json +extension.webpack.config.js +yarn.lock diff --git a/code/extensions/che-keybindings/README.md b/code/extensions/che-keybindings/README.md new file mode 100644 index 000000000000..923c41a64801 --- /dev/null +++ b/code/extensions/che-keybindings/README.md @@ -0,0 +1,7 @@ +# Che Workspace Key Bindings for Visual Studio Code + +**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. + +## Features + +This extension handles Key Bindings of Che workspace on Visual Studio Code diff --git a/code/extensions/che-keybindings/extension.webpack.config.js b/code/extensions/che-keybindings/extension.webpack.config.js new file mode 100644 index 000000000000..3ca85deebec4 --- /dev/null +++ b/code/extensions/che-keybindings/extension.webpack.config.js @@ -0,0 +1,31 @@ +/********************************************************************** + * Copyright (c) 2025 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +/* eslint-disable header/header */ + +//@ts-check + +'use strict'; + +import withDefaults from '../shared.webpack.config.mjs'; + +export default withDefaults({ + context: import.meta.dirname, + resolve: { + mainFields: ['module', 'main'] + }, + externals: { + 'bufferutil': 'commonjs bufferutil', // ignored + 'utf-8-validate': 'commonjs utf-8-validate', // ignored + }, + entry: { + extension: './src/extension.ts', + } +}); diff --git a/code/extensions/che-keybindings/images/eclipse-che-logo.png b/code/extensions/che-keybindings/images/eclipse-che-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0571dcdf997efc2111ba264ae8fe0440508abfea GIT binary patch literal 16725 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 bD|-~Xn67ZrZ;eR^{C8DJ1DB_8J>dTUXIfI{ literal 0 HcmV?d00001 diff --git a/code/extensions/che-keybindings/package-lock.json b/code/extensions/che-keybindings/package-lock.json new file mode 100644 index 000000000000..50dce633aaee --- /dev/null +++ b/code/extensions/che-keybindings/package-lock.json @@ -0,0 +1,153 @@ +{ + "name": "keybindings", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "keybindings", + "version": "0.0.1", + "license": "EPL-2.0", + "dependencies": { + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "@types/node": "^20.10.5", + "@types/vscode": "^1.85.0", + "typescript": "^5.3.3" + }, + "engines": { + "vscode": "^1.63.0" + } + }, + "node_modules/@types/node": { + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/vscode": { + "version": "1.107.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.107.0.tgz", + "integrity": "sha512-XS8YE1jlyTIowP64+HoN30OlC1H9xqSlq1eoLZUgFEC8oUTO6euYZxti1xRiLSfZocs4qytTzR6xCBYtioQTCg==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + } + } +} diff --git a/code/extensions/che-keybindings/package.json b/code/extensions/che-keybindings/package.json new file mode 100644 index 000000000000..7829c73fa05b --- /dev/null +++ b/code/extensions/che-keybindings/package.json @@ -0,0 +1,77 @@ +{ + "name": "keybindings", + "displayName": "%displayName%", + "description": "%description%", + "publisher": "eclipse-che", + "license": "EPL-2.0", + "version": "0.0.1", + "engines": { + "vscode": "^1.63.0" + }, + "icon": "images/eclipse-che-logo.png", + "categories": [ + "Other" + ], + "activationEvents": [ + "*" + ], + "capabilities": { + "virtualWorkspaces": true, + "untrustedWorkspaces": { + "supported": true + } + }, + "main": "./out/extension.js", + "scripts": { + "compile": "gulp compile-extension:che-keybindings", + "watch": "gulp watch-extension:che-keybindings", + "vscode:prepublish": "npm run compile", + "lint:fix": "eslint --fix --cache=true --no-error-on-unmatched-pattern=true \"{src,tests}/**/*.{ts,tsx}\"", + "license:generate": "podman run --rm -t -v $PWD:/workspace/project quay.io/che-incubator/dash-licenses:next" + }, + "repository": { + "type": "git", + "url": "https://github.com/che-incubator/che-code.git" + }, + "extensionDependencies": [ + "eclipse-che.api", + "eclipse-che.terminal" + ], + "dependencies": { + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "@types/node": "^20.10.5", + "typescript": "^5.3.3", + "@types/vscode": "^1.85.0" + }, + "contributes": { + "commands": [ + { + "command": "cheKeybindingsSync.pull", + "title": "Keybindings: Pull from Che" + }, + { + "command": "cheKeybindingsSync.push", + "title": "Keybindings: Push to Che" + } + ], + "configuration": { + "title": "Che Keybindings Sync", + "properties": { + "cheKeybindingsSync.storageMode": { + "type": "string", + "enum": [ + "local", + "global" + ], + "default": "global" + }, + "cheKeybindingsSync.namespace": { + "type": "string", + "default": "default" + } + } + } + } +} \ No newline at end of file diff --git a/code/extensions/che-keybindings/package.nls.json b/code/extensions/che-keybindings/package.nls.json new file mode 100644 index 000000000000..7a0d6416523a --- /dev/null +++ b/code/extensions/che-keybindings/package.nls.json @@ -0,0 +1,4 @@ +{ + "displayName": "Eclipse Che Keybindings", + "description": "Provides Keybindings support" +} diff --git a/code/extensions/che-keybindings/src/cheAPi.ts b/code/extensions/che-keybindings/src/cheAPi.ts new file mode 100644 index 000000000000..0fc6ed848a81 --- /dev/null +++ b/code/extensions/che-keybindings/src/cheAPi.ts @@ -0,0 +1,52 @@ +/********************************************************************** + * Copyright (c) 2025 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +/* eslint-disable header/header */ +export type KeybindingsResponse = { + keybindingsJson: string; + meta?: { + resourceVersion?: string; + updatedAt?: string; + }; +}; + +const API_PREFIX = '/api'; + +export async function getKeybindings(namespace: string): Promise { + const res = await fetch( + `${API_PREFIX}/namespace/${namespace}/keybindings`, + { credentials: 'include' } + ); + + if (!res.ok) { + return null; + } + const data = await res.json() as KeybindingsResponse; + return data; +} + +export async function patchKeybindings( + namespace: string, + keybindingsJson: string, + clientId: string +): Promise { + await fetch( + `${API_PREFIX}/namespace/${namespace}/keybindings`, + { + method: 'PATCH', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + keybindingsJson, + meta: { clientId }, + }), + } + ); +} diff --git a/code/extensions/che-keybindings/src/extension.ts b/code/extensions/che-keybindings/src/extension.ts new file mode 100644 index 000000000000..0017625b1f99 --- /dev/null +++ b/code/extensions/che-keybindings/src/extension.ts @@ -0,0 +1,85 @@ +/********************************************************************** + * Copyright (c) 2025 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +/* eslint-disable header/header */ +import * as vscode from 'vscode'; +import { getKeybindings, patchKeybindings } from './cheAPi'; +import { readUserKeybindings, applyUserKeybindings, USER_KEYBINDINGS_URI } from './keybindings'; +import { getOrCreateClientId } from './utils'; + +export async function activate(context: vscode.ExtensionContext) { + const config = vscode.workspace.getConfiguration('cheKeybindingsSync'); + if (config.get('storageMode') !== 'global') { + return; + } + + const namespace = config.get('namespace', 'default'); + const clientId = getOrCreateClientId(context.globalState); + + const output = vscode.window.createOutputChannel('Che Keybindings Sync'); + output.appendLine('Activating Che Keybindings Sync'); + + // ---------- PULL ON STARTUP ---------- + try { + const remote = await getKeybindings(namespace); + if (remote?.keybindingsJson) { + const local = await readUserKeybindings(); + if (local !== remote.keybindingsJson) { + await applyUserKeybindings(remote.keybindingsJson); + output.appendLine('Applied keybindings from Che backend'); + } + } + } catch (e) { + output.appendLine(`Pull failed: ${e}`); + } + + // ---------- AUTO PUSH ON SAVE ---------- + context.subscriptions.push( + vscode.workspace.onDidSaveTextDocument(async (doc) => { + if (doc.uri.toString() !== USER_KEYBINDINGS_URI.toString()) { + return; + } + + try { + await patchKeybindings(namespace, doc.getText(), clientId); + output.appendLine('Pushed keybindings to Che backend'); + } catch (e) { + output.appendLine(`Push failed: ${e}`); + } + }) + ); + + // ---------- COMMANDS ---------- + context.subscriptions.push( + vscode.commands.registerCommand( + 'cheKeybindingsSync.pull', + async () => { + const remote = await getKeybindings(namespace); + if (remote?.keybindingsJson) { + await applyUserKeybindings(remote.keybindingsJson); + vscode.window.showInformationMessage('Keybindings pulled from Che'); + } + } + ) + ); + + context.subscriptions.push( + vscode.commands.registerCommand( + 'cheKeybindingsSync.push', + async () => { + const local = await readUserKeybindings(); + await patchKeybindings(namespace, local, clientId); + vscode.window.showInformationMessage('Keybindings pushed to Che'); + } + ) + ); +} + +export function deactivate() {} \ No newline at end of file diff --git a/code/extensions/che-keybindings/src/keybindings.ts b/code/extensions/che-keybindings/src/keybindings.ts new file mode 100644 index 000000000000..c61316cd5383 --- /dev/null +++ b/code/extensions/che-keybindings/src/keybindings.ts @@ -0,0 +1,38 @@ +/********************************************************************** + * Copyright (c) 2025 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +/* eslint-disable header/header */ + +import * as vscode from 'vscode'; + +export const USER_KEYBINDINGS_URI = + vscode.Uri.parse('vscode-userdata:/User/keybindings.json'); + +export async function readUserKeybindings(): Promise { + const doc = await vscode.workspace.openTextDocument(USER_KEYBINDINGS_URI); + return doc.getText(); +} + +export async function applyUserKeybindings(content: string): Promise { + const doc = await vscode.workspace.openTextDocument(USER_KEYBINDINGS_URI); + + const edit = new vscode.WorkspaceEdit(); + edit.replace( + USER_KEYBINDINGS_URI, + new vscode.Range( + doc.positionAt(0), + doc.positionAt(doc.getText().length) + ), + content + ); + + await vscode.workspace.applyEdit(edit); + await doc.save(); +} diff --git a/code/extensions/che-keybindings/src/utils.ts b/code/extensions/che-keybindings/src/utils.ts new file mode 100644 index 000000000000..f99784ceba70 --- /dev/null +++ b/code/extensions/che-keybindings/src/utils.ts @@ -0,0 +1,19 @@ +/********************************************************************** + * Copyright (c) 2025 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +/* eslint-disable header/header */ +export function getOrCreateClientId(state: any): string { + let id = state.get('clientId'); + if (!id) { + id = Math.random().toString(36).slice(2); + state.update('clientId', id); + } + return id; +} diff --git a/code/extensions/che-keybindings/tsconfig.json b/code/extensions/che-keybindings/tsconfig.json new file mode 100644 index 000000000000..fe4d268ee103 --- /dev/null +++ b/code/extensions/che-keybindings/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out", + "experimentalDecorators": true, + "emitDecoratorMetadata": true + }, + "include": [ + "src/**/*", + "../../src/vscode-dts/vscode.d.ts", + ] +} From d04ab0205c7668322359c0a32727a53207d996ef Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Mon, 6 Jul 2026 11:47:33 +0530 Subject: [PATCH 2/6] added keybinding sync with log --- code/extensions/che-keybindings/src/cheAPi.ts | 110 ++++++++---- .../che-keybindings/src/extension.ts | 91 +++------- .../che-keybindings/src/keybindings.ts | 90 +++++++--- .../che-keybindings/src/syncManager.ts | 166 ++++++++++++++++++ code/extensions/che-keybindings/src/utils.ts | 32 +++- 5 files changed, 360 insertions(+), 129 deletions(-) create mode 100644 code/extensions/che-keybindings/src/syncManager.ts diff --git a/code/extensions/che-keybindings/src/cheAPi.ts b/code/extensions/che-keybindings/src/cheAPi.ts index 0fc6ed848a81..df167cfcffe9 100644 --- a/code/extensions/che-keybindings/src/cheAPi.ts +++ b/code/extensions/che-keybindings/src/cheAPi.ts @@ -9,44 +9,82 @@ ***********************************************************************/ /* eslint-disable header/header */ -export type KeybindingsResponse = { - keybindingsJson: string; - meta?: { - resourceVersion?: string; - updatedAt?: string; - }; -}; - -const API_PREFIX = '/api'; - -export async function getKeybindings(namespace: string): Promise { - const res = await fetch( - `${API_PREFIX}/namespace/${namespace}/keybindings`, - { credentials: 'include' } - ); - - if (!res.ok) { - return null; - } - const data = await res.json() as KeybindingsResponse; - return data; +import * as vscode from "vscode"; + +export interface KeybindingsResponse { + keybindingsJson: string; + + meta?: { + clientId?: string; + resourceVersion?: string; + }; +} + +const API = "/api"; + +export async function getKeybindings( + namespace: string, + output?: vscode.OutputChannel, +): Promise { + output?.appendLine(`[API] GET ${API}/namespace/${namespace}/keybindings`); + + const res = await fetch(`${API}/namespace/${namespace}/keybindings`, { + credentials: "include", + }); + + output?.appendLine(`[API] GET Status: ${res.status}`); + + if (!res.ok) { + output?.appendLine(`[API] GET Failed: ${await res.text()}`); + return null; + } + + const data = (await res.json()) as KeybindingsResponse; + + output?.appendLine( + `[API] GET Success - Received ${data.keybindingsJson.length} bytes`, + ); + + if (data.meta) { + output?.appendLine( + `[API] Meta => clientId=${data.meta.clientId ?? "N/A"}, resourceVersion=${data.meta.resourceVersion ?? "N/A"}`, + ); + } + + return data; } export async function patchKeybindings( - namespace: string, - keybindingsJson: string, - clientId: string + namespace: string, + keybindingsJson: string, + clientId: string, + output?: vscode.OutputChannel, ): Promise { - await fetch( - `${API_PREFIX}/namespace/${namespace}/keybindings`, - { - method: 'PATCH', - credentials: 'include', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - keybindingsJson, - meta: { clientId }, - }), - } - ); + output?.appendLine(`[API] PATCH ${API}/namespace/${namespace}/keybindings`); + output?.appendLine(`[API] Payload Size: ${keybindingsJson.length} bytes`); + output?.appendLine(`[API] Client ID: ${clientId}`); + + const res = await fetch(`${API}/namespace/${namespace}/keybindings`, { + method: "PATCH", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + keybindingsJson, + meta: { + clientId, + }, + }), + }); + + output?.appendLine(`[API] PATCH Status: ${res.status}`); + + if (!res.ok) { + const error = await res.text(); + output?.appendLine(`[API] PATCH Failed: ${error}`); + throw new Error(error); + } + + output?.appendLine("[API] PATCH Successful."); } diff --git a/code/extensions/che-keybindings/src/extension.ts b/code/extensions/che-keybindings/src/extension.ts index 0017625b1f99..a2cb11a97608 100644 --- a/code/extensions/che-keybindings/src/extension.ts +++ b/code/extensions/che-keybindings/src/extension.ts @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2025 Red Hat, Inc. + * Copyright (c) 2026 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -9,77 +9,38 @@ ***********************************************************************/ /* eslint-disable header/header */ -import * as vscode from 'vscode'; -import { getKeybindings, patchKeybindings } from './cheAPi'; -import { readUserKeybindings, applyUserKeybindings, USER_KEYBINDINGS_URI } from './keybindings'; -import { getOrCreateClientId } from './utils'; +import * as vscode from "vscode"; +import { SyncManager } from "./syncManager"; export async function activate(context: vscode.ExtensionContext) { - const config = vscode.workspace.getConfiguration('cheKeybindingsSync'); - if (config.get('storageMode') !== 'global') { - return; - } + const output = vscode.window.createOutputChannel("Che Keybindings Sync"); + context.subscriptions.push(output); - const namespace = config.get('namespace', 'default'); - const clientId = getOrCreateClientId(context.globalState); + output.appendLine("======================================"); + output.appendLine("Che Keybindings Sync Extension"); + output.appendLine(`Activated at: ${new Date().toISOString()}`); + output.appendLine("Creating SyncManager..."); - const output = vscode.window.createOutputChannel('Che Keybindings Sync'); - output.appendLine('Activating Che Keybindings Sync'); + try { + const manager = new SyncManager(context, output); - // ---------- PULL ON STARTUP ---------- - try { - const remote = await getKeybindings(namespace); - if (remote?.keybindingsJson) { - const local = await readUserKeybindings(); - if (local !== remote.keybindingsJson) { - await applyUserKeybindings(remote.keybindingsJson); - output.appendLine('Applied keybindings from Che backend'); - } - } - } catch (e) { - output.appendLine(`Pull failed: ${e}`); - } + output.appendLine("Initializing SyncManager..."); + await manager.initialize(); - // ---------- AUTO PUSH ON SAVE ---------- - context.subscriptions.push( - vscode.workspace.onDidSaveTextDocument(async (doc) => { - if (doc.uri.toString() !== USER_KEYBINDINGS_URI.toString()) { - return; - } + context.subscriptions.push(manager); - try { - await patchKeybindings(namespace, doc.getText(), clientId); - output.appendLine('Pushed keybindings to Che backend'); - } catch (e) { - output.appendLine(`Push failed: ${e}`); - } - }) - ); + output.appendLine("SyncManager initialized successfully."); + output.appendLine("Extension activation completed."); + } catch (err) { + output.appendLine(`Extension activation failed: ${err}`); + vscode.window.showErrorMessage( + `Che Keybindings Sync activation failed. Check Output -> Che Keybindings Sync`, + ); + } - // ---------- COMMANDS ---------- - context.subscriptions.push( - vscode.commands.registerCommand( - 'cheKeybindingsSync.pull', - async () => { - const remote = await getKeybindings(namespace); - if (remote?.keybindingsJson) { - await applyUserKeybindings(remote.keybindingsJson); - vscode.window.showInformationMessage('Keybindings pulled from Che'); - } - } - ) - ); - - context.subscriptions.push( - vscode.commands.registerCommand( - 'cheKeybindingsSync.push', - async () => { - const local = await readUserKeybindings(); - await patchKeybindings(namespace, local, clientId); - vscode.window.showInformationMessage('Keybindings pushed to Che'); - } - ) - ); + output.appendLine("======================================"); } -export function deactivate() {} \ No newline at end of file +export function deactivate() { + console.log("Che Keybindings Sync deactivated."); +} diff --git a/code/extensions/che-keybindings/src/keybindings.ts b/code/extensions/che-keybindings/src/keybindings.ts index c61316cd5383..4a480c23618e 100644 --- a/code/extensions/che-keybindings/src/keybindings.ts +++ b/code/extensions/che-keybindings/src/keybindings.ts @@ -10,29 +10,77 @@ /* eslint-disable header/header */ -import * as vscode from 'vscode'; +import * as vscode from "vscode"; -export const USER_KEYBINDINGS_URI = - vscode.Uri.parse('vscode-userdata:/User/keybindings.json'); +export const USER_KEYBINDINGS_URI = vscode.Uri.parse( + "vscode-userdata:/User/keybindings.json", +); -export async function readUserKeybindings(): Promise { - const doc = await vscode.workspace.openTextDocument(USER_KEYBINDINGS_URI); - return doc.getText(); +export async function readUserKeybindings( + output?: vscode.OutputChannel, +): Promise { + output?.appendLine("[Keybindings] Reading user keybindings..."); + + try { + const doc = await vscode.workspace.openTextDocument(USER_KEYBINDINGS_URI); + + output?.appendLine( + `[Keybindings] Opened: ${USER_KEYBINDINGS_URI.toString()}`, + ); + + const text = doc.getText(); + + output?.appendLine(`[Keybindings] Read successful (${text.length} bytes).`); + + return text; + } catch (err) { + output?.appendLine(`[Keybindings] Failed to read keybindings: ${err}`); + + return "[]"; + } } -export async function applyUserKeybindings(content: string): Promise { - const doc = await vscode.workspace.openTextDocument(USER_KEYBINDINGS_URI); - - const edit = new vscode.WorkspaceEdit(); - edit.replace( - USER_KEYBINDINGS_URI, - new vscode.Range( - doc.positionAt(0), - doc.positionAt(doc.getText().length) - ), - content - ); - - await vscode.workspace.applyEdit(edit); - await doc.save(); +export async function writeUserKeybindings( + text: string, + output?: vscode.OutputChannel, +): Promise { + output?.appendLine("[Keybindings] Writing user keybindings..."); + + const doc = await vscode.workspace.openTextDocument(USER_KEYBINDINGS_URI); + + const current = doc.getText(); + + output?.appendLine(`[Keybindings] Current size: ${current.length} bytes`); + output?.appendLine(`[Keybindings] New size: ${text.length} bytes`); + + if (current === text) { + output?.appendLine("[Keybindings] No changes detected. Skipping write."); + return; + } + + const edit = new vscode.WorkspaceEdit(); + + edit.replace( + USER_KEYBINDINGS_URI, + new vscode.Range(doc.positionAt(0), doc.positionAt(current.length)), + text, + ); + + output?.appendLine("[Keybindings] Applying workspace edit..."); + + const applied = await vscode.workspace.applyEdit(edit); + + output?.appendLine(`[Keybindings] Workspace edit applied: ${applied}`); + + if (!applied) { + throw new Error("Failed to apply workspace edit."); + } + + output?.appendLine("[Keybindings] Saving keybindings.json..."); + + const saved = await doc.save(); + + output?.appendLine(`[Keybindings] Save completed: ${saved}`); + + output?.appendLine("[Keybindings] Write completed successfully."); } diff --git a/code/extensions/che-keybindings/src/syncManager.ts b/code/extensions/che-keybindings/src/syncManager.ts new file mode 100644 index 000000000000..790fb7eb59a3 --- /dev/null +++ b/code/extensions/che-keybindings/src/syncManager.ts @@ -0,0 +1,166 @@ +/********************************************************************** + * Copyright (c) 2026 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +/* eslint-disable header/header */ +import * as vscode from "vscode"; +import { getKeybindings, patchKeybindings } from "./cheAPi"; +import { + readUserKeybindings, + writeUserKeybindings, + USER_KEYBINDINGS_URI, +} from "./keybindings"; +import { getOrCreateClientId } from "./utils"; + +export class SyncManager implements vscode.Disposable { + private suppressPush = false; + + private clientId: string; + + private namespace: string; + + private lastSynced = ""; + + private timer?: NodeJS.Timeout; + + constructor( + private readonly context: vscode.ExtensionContext, + private readonly output: vscode.OutputChannel, + ) { + const cfg = vscode.workspace.getConfiguration("cheKeybindingsSync"); + + this.namespace = cfg.get("namespace", "default"); + this.clientId = getOrCreateClientId(context.globalState); + + this.output.appendLine("===== SyncManager Created ====="); + this.output.appendLine(`Namespace : ${this.namespace}`); + this.output.appendLine(`Client ID : ${this.clientId}`); + } + + async initialize() { + this.output.appendLine("Initializing SyncManager..."); + + try { + await this.pull(); + this.output.appendLine("Initial pull completed."); + } catch (err) { + this.output.appendLine(`Initial pull failed: ${err}`); + } + + this.context.subscriptions.push( + vscode.workspace.onDidSaveTextDocument(this.onSave, this), + ); + + this.output.appendLine("Registered onDidSaveTextDocument listener."); + + this.timer = setInterval(() => { + this.output.appendLine("Polling backend for remote keybindings..."); + this.pull().catch((err) => + this.output.appendLine(`Polling failed: ${err}`), + ); + }, 10000); + + this.output.appendLine("Polling started (every 10 seconds)."); + } + + dispose() { + this.output.appendLine("Disposing SyncManager..."); + + if (this.timer) { + clearInterval(this.timer); + this.output.appendLine("Polling timer stopped."); + } + } + + private async onSave(doc: vscode.TextDocument) { + this.output.appendLine(`Document saved: ${doc.uri.toString()}`); + + if (doc.uri.toString() !== USER_KEYBINDINGS_URI.toString()) { + this.output.appendLine("Not keybindings.json. Ignoring."); + return; + } + + this.output.appendLine("Detected keybindings.json save."); + + if (this.suppressPush) { + this.output.appendLine("Push suppressed (local update from backend)."); + this.suppressPush = false; + return; + } + + const text = doc.getText(); + + if (text === this.lastSynced) { + this.output.appendLine("No changes detected. Skipping push."); + return; + } + + this.output.appendLine( + `Pushing keybindings to backend (${text.length} bytes)...`, + ); + + try { + await patchKeybindings(this.namespace, text, this.clientId); + + this.lastSynced = text; + + this.output.appendLine("Push completed successfully."); + } catch (err) { + this.output.appendLine(`Push failed: ${err}`); + } + } + + async pull() { + this.output.appendLine("Pulling keybindings from backend..."); + + try { + const remote = await getKeybindings(this.namespace); + + if (!remote) { + this.output.appendLine("No response from backend."); + return; + } + + this.output.appendLine( + `Received remote keybindings (${remote.keybindingsJson.length} bytes).`, + ); + + if (remote.meta?.clientId === this.clientId) { + this.output.appendLine( + "Remote update originated from this client. Ignoring.", + ); + return; + } + + const local = await readUserKeybindings(); + + this.output.appendLine( + `Local size: ${local.length}, Remote size: ${remote.keybindingsJson.length}`, + ); + + if (local === remote.keybindingsJson) { + this.output.appendLine("Local keybindings already up-to-date."); + this.lastSynced = local; + return; + } + + this.output.appendLine("Applying remote keybindings..."); + + this.suppressPush = true; + + await writeUserKeybindings(remote.keybindingsJson); + + this.lastSynced = remote.keybindingsJson; + + this.output.appendLine("Remote keybindings applied successfully."); + } catch (err) { + this.output.appendLine(`Pull failed: ${err}`); + } + } +} diff --git a/code/extensions/che-keybindings/src/utils.ts b/code/extensions/che-keybindings/src/utils.ts index f99784ceba70..3253ea18eeb4 100644 --- a/code/extensions/che-keybindings/src/utils.ts +++ b/code/extensions/che-keybindings/src/utils.ts @@ -9,11 +9,29 @@ ***********************************************************************/ /* eslint-disable header/header */ -export function getOrCreateClientId(state: any): string { - let id = state.get('clientId'); - if (!id) { - id = Math.random().toString(36).slice(2); - state.update('clientId', id); - } - return id; +import * as vscode from "vscode"; + +export function getOrCreateClientId( + state: vscode.Memento, + output?: vscode.OutputChannel, +): string { + output?.appendLine("[Utils] Retrieving client ID..."); + + let id = state.get("clientId"); + + if (!id) { + output?.appendLine( + "[Utils] No existing client ID found. Generating a new one...", + ); + + id = Math.random().toString(36).slice(2); + + state.update("clientId", id); + + output?.appendLine(`[Utils] Generated new client ID: ${id}`); + } else { + output?.appendLine(`[Utils] Existing client ID found: ${id}`); + } + + return id; } From cc04a8f8b69ffed9cf611ae46704f9974a308523 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Mon, 6 Jul 2026 15:49:01 +0530 Subject: [PATCH 3/6] removed contributions --- code/extensions/che-keybindings/package.json | 31 +------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/code/extensions/che-keybindings/package.json b/code/extensions/che-keybindings/package.json index 7829c73fa05b..dbed493f65d2 100644 --- a/code/extensions/che-keybindings/package.json +++ b/code/extensions/che-keybindings/package.json @@ -44,34 +44,5 @@ "@types/node": "^20.10.5", "typescript": "^5.3.3", "@types/vscode": "^1.85.0" - }, - "contributes": { - "commands": [ - { - "command": "cheKeybindingsSync.pull", - "title": "Keybindings: Pull from Che" - }, - { - "command": "cheKeybindingsSync.push", - "title": "Keybindings: Push to Che" - } - ], - "configuration": { - "title": "Che Keybindings Sync", - "properties": { - "cheKeybindingsSync.storageMode": { - "type": "string", - "enum": [ - "local", - "global" - ], - "default": "global" - }, - "cheKeybindingsSync.namespace": { - "type": "string", - "default": "default" - } - } - } } -} \ No newline at end of file +} From db19d84713ec9eccecec60d9a571157c07f8c531 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Tue, 7 Jul 2026 16:54:40 +0530 Subject: [PATCH 4/6] upstream vscode --- code/extensions/che-keybindings/package-lock.json | 14 +++++++------- code/extensions/che-keybindings/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/extensions/che-keybindings/package-lock.json b/code/extensions/che-keybindings/package-lock.json index 50dce633aaee..904941d77472 100644 --- a/code/extensions/che-keybindings/package-lock.json +++ b/code/extensions/che-keybindings/package-lock.json @@ -17,13 +17,13 @@ "typescript": "^5.3.3" }, "engines": { - "vscode": "^1.63.0" + "vscode": "^1.88.0" } }, "node_modules/@types/node": { - "version": "20.19.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", - "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", "dev": true, "license": "MIT", "dependencies": { @@ -31,9 +31,9 @@ } }, "node_modules/@types/vscode": { - "version": "1.107.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.107.0.tgz", - "integrity": "sha512-XS8YE1jlyTIowP64+HoN30OlC1H9xqSlq1eoLZUgFEC8oUTO6euYZxti1xRiLSfZocs4qytTzR6xCBYtioQTCg==", + "version": "1.125.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.125.0.tgz", + "integrity": "sha512-0icm/ZQAaism87P0ekHqi4/Ju9du+Tm0RUW+y7vqRsxY2cY0FNRX1nAnaW7nT6npPt2tfHiheZ55Zm9UhqonFA==", "dev": true, "license": "MIT" }, diff --git a/code/extensions/che-keybindings/package.json b/code/extensions/che-keybindings/package.json index dbed493f65d2..3d452b47f45f 100644 --- a/code/extensions/che-keybindings/package.json +++ b/code/extensions/che-keybindings/package.json @@ -6,7 +6,7 @@ "license": "EPL-2.0", "version": "0.0.1", "engines": { - "vscode": "^1.63.0" + "vscode": "^1.88.0" }, "icon": "images/eclipse-che-logo.png", "categories": [ From d716fde9cc7e4d33281458c87a1f5e42dbadb6f1 Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Wed, 8 Jul 2026 00:37:28 +0530 Subject: [PATCH 5/6] added esbuild --- code/extensions/che-keybindings/esbuild.mts | 30 ++++++++++++++++++ .../extension.webpack.config.js | 31 ------------------- code/extensions/che-keybindings/tsconfig.json | 6 +++- 3 files changed, 35 insertions(+), 32 deletions(-) create mode 100644 code/extensions/che-keybindings/esbuild.mts delete mode 100644 code/extensions/che-keybindings/extension.webpack.config.js diff --git a/code/extensions/che-keybindings/esbuild.mts b/code/extensions/che-keybindings/esbuild.mts new file mode 100644 index 000000000000..2678a6515efa --- /dev/null +++ b/code/extensions/che-keybindings/esbuild.mts @@ -0,0 +1,30 @@ +/********************************************************************** + * Copyright (c) 2026 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ +/* + * This file was generated using AI assistance (Cursor AI) + * and reviewed by the maintainers. + */ +import * as path from 'node:path'; +import { run } from '../esbuild-extension-common.mts'; + +const srcDir = path.join(import.meta.dirname, 'src'); +const outDir = path.join(import.meta.dirname, 'dist'); + +run({ + platform: 'node', + entryPoints: { + 'extension': path.join(srcDir, 'extension.ts'), + }, + srcDir, + outdir: outDir, + additionalOptions: { + external: ['vscode', 'bufferutil', 'utf-8-validate'], + }, +}, process.argv); diff --git a/code/extensions/che-keybindings/extension.webpack.config.js b/code/extensions/che-keybindings/extension.webpack.config.js deleted file mode 100644 index 3ca85deebec4..000000000000 --- a/code/extensions/che-keybindings/extension.webpack.config.js +++ /dev/null @@ -1,31 +0,0 @@ -/********************************************************************** - * Copyright (c) 2025 Red Hat, Inc. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - ***********************************************************************/ - -/* eslint-disable header/header */ - -//@ts-check - -'use strict'; - -import withDefaults from '../shared.webpack.config.mjs'; - -export default withDefaults({ - context: import.meta.dirname, - resolve: { - mainFields: ['module', 'main'] - }, - externals: { - 'bufferutil': 'commonjs bufferutil', // ignored - 'utf-8-validate': 'commonjs utf-8-validate', // ignored - }, - entry: { - extension: './src/extension.ts', - } -}); diff --git a/code/extensions/che-keybindings/tsconfig.json b/code/extensions/che-keybindings/tsconfig.json index fe4d268ee103..9b38bf350c87 100644 --- a/code/extensions/che-keybindings/tsconfig.json +++ b/code/extensions/che-keybindings/tsconfig.json @@ -3,7 +3,11 @@ "compilerOptions": { "outDir": "./out", "experimentalDecorators": true, - "emitDecoratorMetadata": true + "emitDecoratorMetadata": true, + "skipLibCheck": true, + "types": [ + "node" + ] }, "include": [ "src/**/*", From 605582f3c00bbed2decbe500a63975cde3f50dfa Mon Sep 17 00:00:00 2001 From: msivasubramaniaan Date: Wed, 8 Jul 2026 13:12:36 +0530 Subject: [PATCH 6/6] check the keybindings uri value --- .../che-keybindings/src/extension.ts | 69 ++++++++++++++----- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/code/extensions/che-keybindings/src/extension.ts b/code/extensions/che-keybindings/src/extension.ts index a2cb11a97608..0da656384466 100644 --- a/code/extensions/che-keybindings/src/extension.ts +++ b/code/extensions/che-keybindings/src/extension.ts @@ -10,37 +10,68 @@ /* eslint-disable header/header */ import * as vscode from "vscode"; -import { SyncManager } from "./syncManager"; +import { USER_KEYBINDINGS_URI } from "./keybindings"; export async function activate(context: vscode.ExtensionContext) { const output = vscode.window.createOutputChannel("Che Keybindings Sync"); context.subscriptions.push(output); + output.show(true); + output.appendLine("======================================"); + output.appendLine("Che Keybindings Investigation"); + output.appendLine(`Activated: ${new Date().toISOString()}`); output.appendLine("======================================"); - output.appendLine("Che Keybindings Sync Extension"); - output.appendLine(`Activated at: ${new Date().toISOString()}`); - output.appendLine("Creating SyncManager..."); try { - const manager = new SyncManager(context, output); - - output.appendLine("Initializing SyncManager..."); - await manager.initialize(); + const doc = await vscode.workspace.openTextDocument(USER_KEYBINDINGS_URI); - context.subscriptions.push(manager); + output.appendLine("Successfully opened keybindings.json"); + output.appendLine(`URI : ${doc.uri.toString()}`); + output.appendLine(`Scheme : ${doc.uri.scheme}`); + output.appendLine(`Path : ${doc.uri.path}`); + output.appendLine(`Length : ${doc.getText().length}`); - output.appendLine("SyncManager initialized successfully."); - output.appendLine("Extension activation completed."); + output.appendLine("----- Current Content -----"); + output.appendLine(doc.getText()); + output.appendLine("---------------------------"); } catch (err) { - output.appendLine(`Extension activation failed: ${err}`); - vscode.window.showErrorMessage( - `Che Keybindings Sync activation failed. Check Output -> Che Keybindings Sync`, - ); + output.appendLine(`Failed to open keybindings.json: ${err}`); } - output.appendLine("======================================"); -} + // Fires whenever keybindings.json is saved + context.subscriptions.push( + vscode.workspace.onDidSaveTextDocument(doc => { + output.appendLine(""); + output.appendLine("===== onDidSaveTextDocument ====="); + output.appendLine(`Saved: ${doc.uri.toString()}`); -export function deactivate() { - console.log("Che Keybindings Sync deactivated."); + if (doc.uri.toString() === USER_KEYBINDINGS_URI.toString()) { + output.appendLine("Detected keybindings.json save"); + output.appendLine(`Length: ${doc.getText().length}`); + output.appendLine(doc.getText()); + } + }), + ); + + // Fires whenever any text document changes + context.subscriptions.push( + vscode.workspace.onDidChangeTextDocument(event => { + if (event.document.uri.toString() === USER_KEYBINDINGS_URI.toString()) { + output.appendLine(""); + output.appendLine("===== onDidChangeTextDocument ====="); + output.appendLine(`Changes: ${event.contentChanges.length}`); + + for (const change of event.contentChanges) { + output.appendLine( + `Range: ${change.rangeOffset}-${change.rangeOffset + change.rangeLength}`, + ); + output.appendLine(`Inserted: ${JSON.stringify(change.text)}`); + } + } + }), + ); + + output.appendLine("Listening for keybindings changes..."); } + +export function deactivate() {}