7

When programming a vscode extension... Is there a programmatic way to find the keybinding for a provided command?

I would like to be able to see if a user has updated the key mapping from default for a command so that the UI can display the up-to-date binding. (and if not, look up the default binding)

Here are the APIs I've looked into so far:

  • vscode.workspace.getConfiguration() - I cannot determine how to access the keybindings.json file / perform a lookup.

  • vscode.extensions.getExtension(name/id) allows access to the package.json, but not the command or keybinding override.

  • vscode.getCommands does not provide access to the keybinding values either...

Cœur
  • 37,241
  • 25
  • 195
  • 267
Jon G
  • 165
  • 1
  • 6

2 Answers2

3

You can get keybinding values from the keybindings.json file using NodeJS.

keybindings.json path on diferrent systems:

Windows: %APPDATA%\Code\User\keybindings.json
Mac: $HOME/Library/Application Support/Code/User/keybindings.json
Linux: $HOME/.config/Code/User/keybindings.json

To build the path you'll need to get Environment variables using process.env.{variableName}.

For example for MacOS it'll be:

var process = require('process');
//...
var keybindingsPath = process.env.HOME + "/Library/Application Support/Code/User/keybindings.json";

vscode.workspace.openTextDocument(keybindingsPath).then((document) => {
    let text = document.getText();
    //then use this JSON file for your needs
    //...
});
Nikita Kunevich
  • 587
  • 4
  • 17
  • NB: VSC profile folder location can be specified by parameters, i.e. outside the system user profile folder, see http://stackoverflow.com/q/49667641/ – myf Jun 01 '18 at 20:00
  • For portable version it's `process.env.VSCODE_PORTABLE + "/user-data/User/keybindings.json"` – vanowm Sep 30 '22 at 01:23
  • Now, how do we parse that JSON file? We can't use `JSON.parse()` because it's non-standard - json with comments – vanowm Sep 30 '22 at 01:25
0

Inspired by @nikita-kunevich answer Here is a code I use in autoit extension.

First it gets default keybindings from package.json, then it parses keybindings.json via JSON5 library (can't use JSON.parse() because file may contain comments) and replaces default keys with new keys.

//get keybindings
const keybindings = new Promise(resolve => {
  //default keybindings
  const data = require("../package.json").contributes.keybindings.reduce((a,b)=>(a[b.command]=b.key,a),{});
  const parse = list => {
    for(let i = 0; i < list.length; i++) {
      if (list[i].command in data)
        data[list[i].command] = list[i].key;
    }
    for(let i in data) {
      //capitalize first letter
      data[i] = data[i].replace(/\w+/g, w => (w.substring(0,1).toUpperCase()) + w.substring(1));
      //add spaces around "+"
      // data[i] = data[i].replace(/\+/g, " $& ");
    }

    Object.assign(keybindings, data);
    resolve(data);
  };
  const path = {
    windows: process.env.APPDATA + "/Code",
    macos: process.env.HOME + "/Library/Application Support/Code",
    linux: process.env.HOME + "/config/Code"
  }[{
    aix: "linux",
    darwin: "macos",
    freebsd: "linux",
    linux: "linux",
    openbsd: "linux",
    sunos: "linux",
    win32: "windows"
  }[process.platform]||"windows"];
  const file = ((process.env.VSCODE_PORTABLE ? process.env.VSCODE_PORTABLE + "/user-data/User/" : path) + "/User/keybindings.json")
    .replace(/\//g, process.platform == "win32" ? "\\" : "/");

  //read file
  workspace.openTextDocument(file).then(doc => {
    //we can't use JSON.parse() because file may contain comments
    const JSON5 = require("json5").default;
    parse(JSON5.parse(doc.getText()));
  }).catch(er => {
    parse([]);
  });
});

To install JSON5 package use:

npm install json5

Usage:

keybindings.then(list => {
  console.log(list);
});
vanowm
  • 9,466
  • 2
  • 21
  • 37