├── .eslintrc.cjs ├── .github ├── mergify.yml ├── renovate.json5 └── workflows │ ├── cd.yml │ ├── ci.yml │ ├── keybindings.yml │ ├── release-please.yml │ └── website.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── icon.png ├── package-lock.json ├── package.json ├── src ├── config.ts ├── extension.ts ├── glimpse.ts ├── icons.ts ├── keys.ts ├── keys │ ├── comments.ts │ ├── common.ts │ ├── configKeys.ts │ ├── debug.ts │ ├── default_menu.ts │ ├── editor.ts │ ├── errors.ts │ ├── files.ts │ ├── format.ts │ ├── gh_copilot.ts │ ├── git.ts │ ├── go_to.ts │ ├── help.ts │ ├── indent.ts │ ├── peek.ts │ ├── quit.ts │ ├── refactor.ts │ ├── search.ts │ ├── tasks.ts │ ├── text.ts │ ├── toggles.ts │ ├── window.ts │ └── zoom.ts ├── keysToDocs.ts ├── logger.ts ├── prettify.ts └── utf8ToStr.ts ├── tsconfig.json ├── webpack.config.js └── website ├── .gitignore ├── .markdownlint.yaml ├── README.md ├── babel.config.js ├── docs ├── configuration.md ├── img │ ├── double-space.png │ ├── file_keys.png │ └── input_sources.png ├── install.md ├── intro.md ├── keybindings.md ├── troubleshooting.md ├── vim_tricks.md └── why.md ├── docusaurus.config.js ├── package-lock.json ├── package.json ├── sidebars.js ├── src ├── components │ └── HomepageFeatures │ │ ├── index.js │ │ └── styles.module.css ├── css │ └── custom.css └── pages │ ├── index.js │ ├── index.module.css │ └── pricing.md └── static ├── .nojekyll ├── CNAME ├── glimpse.mp4 ├── img ├── favicon.ico ├── glimpse-social-card.png ├── icon.png └── icon_small.png └── js └── posthog.js /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "@typescript-eslint/parser", 4 | parserOptions: { 5 | ecmaVersion: 6, 6 | sourceType: "module", 7 | project: "./tsconfig.json", 8 | }, 9 | extends: [ 10 | "eslint:recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "plugin:@typescript-eslint/recommended-requiring-type-checking", 13 | "plugin:@typescript-eslint/eslint-recommended", 14 | "plugin:@typescript-eslint/strict", 15 | ], 16 | plugins: ["@typescript-eslint"], 17 | rules: { 18 | "@typescript-eslint/naming-convention": "warn", 19 | "@typescript-eslint/semi": "warn", 20 | "@typescript-eslint/consistent-type-definitions": "off", 21 | "@typescript-eslint/sort-type-constituents": "warn", 22 | "@typescript-eslint/no-confusing-void-expression": "warn", 23 | "@typescript-eslint/consistent-type-imports": "warn", 24 | curly: "warn", 25 | eqeqeq: "warn", 26 | "no-throw-literal": "warn", 27 | semi: "off", 28 | }, 29 | ignorePatterns: ["out", "dist", "**/*.d.ts", ".eslintrc.cjs"], 30 | env: { 31 | // needed to solve errors in webpack config 32 | node: true, 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /.github/mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | - name: Automatic merge for Dependabot pull requests 3 | conditions: 4 | - author=dependabot[bot] 5 | actions: 6 | merge: 7 | method: squash 8 | - name: Automatic update to the main branch for pull requests 9 | conditions: 10 | - -conflict # skip PRs with conflicts 11 | - -draft # skip GH draft PRs 12 | - -author=dependabot[bot] # skip dependabot PRs 13 | actions: 14 | update: 15 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | extends: ["config:recommended", ":maintainLockFilesWeekly"], 4 | automerge: true, 5 | packageRules: [ 6 | { 7 | matchCategories: ["javascript", "typescript"], 8 | updateTypes: ["patch"], 9 | // Disable patch updates for single dependencies because patches 10 | // are updated periodically with lockfile maintainance. 11 | enabled: false, 12 | }, 13 | ], 14 | // Receive any update that fixes security vulnerabilities. 15 | // We need this because we disabled "patch" updates for Rust. 16 | // Note: You need to enable "Dependabot alerts" in "Code security" GitHub 17 | // Settings to receive security updates. 18 | // See https://docs.renovatebot.com/configuration-options/#vulnerabilityalerts 19 | vulnerabilityAlerts: { 20 | enabled: true, 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - v* 5 | 6 | name: Publish extension 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Set up node.js 16 | uses: actions/setup-node@v4 17 | with: 18 | # node version used by VS Code 19 | node-version: 16 20 | 21 | - name: Restore dependencies 22 | run: npm ci 23 | 24 | - name: Lint 25 | run: npm run lint 26 | 27 | - name: Format check 28 | run: npm run format:check 29 | 30 | - name: Prepublish 31 | run: npm run vscode:prepublish 32 | 33 | - name: Publish to Open VSX Registry 34 | uses: HaaLeo/publish-vscode-extension@v2 35 | with: 36 | pat: ${{ secrets.OPEN_VSX_TOKEN }} 37 | - name: Publish to Visual Studio Marketplace 38 | uses: HaaLeo/publish-vscode-extension@v2 39 | with: 40 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 41 | registryUrl: https://marketplace.visualstudio.com 42 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Set up node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | # node version used by VS Code 20 | node-version: 16 21 | 22 | - name: Restore dependencies 23 | run: npm ci 24 | 25 | - name: Lint 26 | run: npm run lint 27 | 28 | - name: Format check 29 | run: npm run format:check 30 | 31 | - name: Prepublish 32 | run: npm run vscode:prepublish 33 | -------------------------------------------------------------------------------- /.github/workflows/keybindings.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | permissions: 4 | contents: write 5 | pull-requests: write 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | update-keybindings: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up node.js 20 | uses: actions/setup-node@v4 21 | 22 | - name: Restore dependencies 23 | run: npm ci 24 | 25 | - name: Generate keybindings 26 | run: npm run write-keybindings 27 | 28 | - name: Create Pull Request 29 | uses: peter-evans/create-pull-request@v7 30 | with: 31 | title: "docs: update keybindings" 32 | commit-message: "docs: update keybindings" 33 | body: "Opened by [keybindings.yml](https://github.com/MarcoIeni/glimpse/blob/main/.github/workflows/keybindings.yml) GitHub Action" 34 | token: ${{ secrets.GLIMPSE_RELEASE_PLEASE }} 35 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | permissions: 7 | contents: write 8 | pull-requests: write 9 | 10 | name: release-please 11 | 12 | jobs: 13 | release-please: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: google-github-actions/release-please-action@v4 17 | with: 18 | release-type: node 19 | token: ${{ secrets.GLIMPSE_RELEASE_PLEASE }} 20 | -------------------------------------------------------------------------------- /.github/workflows/website.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | jobs: 15 | deploy: 16 | name: Deploy to GitHub Pages 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version: 18 23 | cache: npm 24 | cache-dependency-path: "website/package-lock.json" 25 | 26 | - name: Install dependencies 27 | run: npm ci 28 | working-directory: ./website 29 | - name: Markdown lint 30 | run: npm run mdlint 31 | working-directory: ./website 32 | - name: Build website 33 | run: npm run build 34 | working-directory: ./website 35 | 36 | # Popular action to deploy to GitHub Pages: 37 | # Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus 38 | - name: Deploy to GitHub Pages 39 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 40 | uses: peaceiris/actions-gh-pages@v4 41 | with: 42 | github_token: ${{ secrets.GITHUB_TOKEN }} 43 | # Build output to publish to the `gh-pages` branch: 44 | publish_dir: ./website/build 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | .DS_Store 7 | .vscode-test-web/ 8 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | out/ 2 | dist/ 3 | node_modules/ 4 | .vscode-test/ 5 | .vscode-test-web/ 6 | 7 | package-lock.json 8 | *.md 9 | posthog.js 10 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tabWidth: 4, 3 | useTabs: false, 4 | singleQuote: false, 5 | printWidth: 100, 6 | }; 7 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": ["--extensionDevelopmentPath=${workspaceFolder}"], 13 | "outFiles": ["${workspaceFolder}/dist/**/*.js"], 14 | "preLaunchTask": "${defaultBuildTask}" 15 | }, 16 | { 17 | "name": "Run Extension Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "args": [ 21 | "--extensionDevelopmentPath=${workspaceFolder}", 22 | "--extensionTestsPath=${workspaceFolder}/dist/test/suite/index-node" 23 | ], 24 | "outFiles": ["${workspaceFolder}/dist/**/*.js"], 25 | "preLaunchTask": "${defaultBuildTask}" 26 | }, 27 | { 28 | "name": "Run Web Extension in VS Code", 29 | "type": "pwa-extensionHost", 30 | "debugWebWorkerHost": true, 31 | "request": "launch", 32 | "args": [ 33 | "--extensionDevelopmentPath=${workspaceFolder}", 34 | "--extensionDevelopmentKind=web" 35 | ], 36 | "outFiles": ["${workspaceFolder}/dist/**/*.js"], 37 | "preLaunchTask": "npm: watch" 38 | }, 39 | { 40 | "name": "Run Extension Tests in VS Code", 41 | "type": "extensionHost", 42 | "debugWebWorkerHost": true, 43 | "request": "launch", 44 | "args": [ 45 | "--extensionDevelopmentPath=${workspaceFolder}", 46 | "--extensionDevelopmentKind=web" 47 | ], 48 | "outFiles": ["${workspaceFolder}/dist/**/*.js"], 49 | "preLaunchTask": "npm: watch" 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": ["$ts-webpack-watch", "$tslint-webpack-watch"], 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .github 2 | .vscode/** 3 | .vscode-test/** 4 | docs/** 5 | src/** 6 | .gitignore 7 | .yarnrc 8 | vsc-extension-quickstart.md 9 | **/tsconfig.json 10 | **/.eslintrc.cjs 11 | **/.prettierignore 12 | **/.prettierrc.js 13 | **/*.map 14 | **/*.ts 15 | website 16 | webpack.config.js 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "glimpse" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [0.16.0](https://github.com/MarcoIeni/glimpse/compare/v0.15.0...v0.16.0) (2024-05-20) 8 | 9 | 10 | ### Features 11 | 12 | * quick search with `s q` ([#338](https://github.com/MarcoIeni/glimpse/issues/338)) ([e96b456](https://github.com/MarcoIeni/glimpse/commit/e96b45672a9b9047d656c7d51db4a4094ed9ad08)) 13 | 14 | ## [0.15.0](https://github.com/MarcoIeni/glimpse/compare/v0.14.1...v0.15.0) (2024-02-29) 15 | 16 | 17 | ### Features 18 | 19 | * **w:** add editor layout bindings ([#298](https://github.com/MarcoIeni/glimpse/issues/298)) ([c04b574](https://github.com/MarcoIeni/glimpse/commit/c04b574aa5fcbfa6543abf47e2eeebb84d337300)) 20 | 21 | ## [0.14.1](https://github.com/MarcoIeni/glimpse/compare/v0.14.0...v0.14.1) (2023-11-05) 22 | 23 | 24 | ### Bug Fixes 25 | 26 | * navigate up, down, right, left with `w` ([#197](https://github.com/MarcoIeni/glimpse/issues/197)) ([b8a1263](https://github.com/MarcoIeni/glimpse/commit/b8a1263480471c94bf8c6ea1fc06a3c23c348dd2)) 27 | 28 | ## [0.14.0](https://github.com/MarcoIeni/glimpse/compare/v0.13.0...v0.14.0) (2023-11-04) 29 | 30 | 31 | ### Features 32 | 33 | * `w M` maximizes group ([#195](https://github.com/MarcoIeni/glimpse/issues/195)) ([129b0b6](https://github.com/MarcoIeni/glimpse/commit/129b0b605a1b031c741bedc77ba1c360ca0e2485)) 34 | 35 | 36 | ### Bug Fixes 37 | 38 | * typo in toggle menu ([c56a8c8](https://github.com/MarcoIeni/glimpse/commit/c56a8c8ec07083fd01bbddd38e1999b169cb7638)) 39 | 40 | ## [0.13.0](https://github.com/MarcoIeni/glimpse/compare/v0.12.0...v0.13.0) (2023-09-26) 41 | 42 | 43 | ### Features 44 | 45 | * `e 1-9` opens editor in group ([#153](https://github.com/MarcoIeni/glimpse/issues/153)) ([caa9510](https://github.com/MarcoIeni/glimpse/commit/caa9510f37377265fa1a2b90af95aada76c06b80)) 46 | 47 | ## [0.12.0](https://github.com/MarcoIeni/glimpse/compare/v0.11.0...v0.12.0) (2023-08-03) 48 | 49 | 50 | ### Features 51 | 52 | * `s E` opens search editor to the side ([3a00c72](https://github.com/MarcoIeni/glimpse/commit/3a00c7273ebcf37e142e374e88ba539f210a5bd8)) 53 | 54 | ## [0.11.0](https://github.com/MarcoIeni/glimpse/compare/v0.10.0...v0.11.0) (2023-07-27) 55 | 56 | 57 | ### Features 58 | 59 | * change editor icons ([799a493](https://github.com/MarcoIeni/glimpse/commit/799a493f0e5239ec8080729b38a9cb0984fe7ec7)) 60 | 61 | ## [0.10.0](https://github.com/MarcoIeni/glimpse/compare/v0.9.0...v0.10.0) (2023-07-27) 62 | 63 | 64 | ### Features 65 | 66 | * `j j` goes to definition ([cd902bc](https://github.com/MarcoIeni/glimpse/commit/cd902bc2423823970500bd037b13f13e75c69543)) 67 | 68 | ## [0.9.0](https://github.com/MarcoIeni/glimpse/compare/v0.8.0...v0.9.0) (2023-07-27) 69 | 70 | 71 | ### Features 72 | 73 | * smaller extension icon ([8ea9597](https://github.com/MarcoIeni/glimpse/commit/8ea95977733f93931ae4fe32dd36d9589f546cd5)) 74 | 75 | ## [0.8.0](https://github.com/MarcoIeni/glimpse/compare/v0.7.0...v0.8.0) (2023-07-27) 76 | 77 | 78 | ### Features 79 | 80 | * remove `project` key bindings ([#102](https://github.com/MarcoIeni/glimpse/issues/102)) ([16e46a1](https://github.com/MarcoIeni/glimpse/commit/16e46a19ca2bc67b36a040a4bc0bca67c3079762)) 81 | 82 | ## [0.7.0](https://github.com/MarcoIeni/glimpse/compare/v0.6.0...v0.7.0) (2023-07-27) 83 | 84 | 85 | ### Features 86 | 87 | * `s e` opens new search editor ([f434647](https://github.com/MarcoIeni/glimpse/commit/f4346476bbe1220cf5850a61a4b30160bf245539)) 88 | 89 | ## [0.6.0](https://github.com/MarcoIeni/glimpse/compare/v0.5.0...v0.6.0) (2023-07-25) 90 | 91 | 92 | ### Features 93 | 94 | * `s c` clears search results ([d598ab9](https://github.com/MarcoIeni/glimpse/commit/d598ab93a44b9d2b5c1efd49ad87316ed65aff96)) 95 | 96 | ## [0.5.0](https://github.com/MarcoIeni/glimpse/compare/v0.4.1...v0.5.0) (2023-07-24) 97 | 98 | 99 | ### Features 100 | 101 | * publish to open vsx ([ee58791](https://github.com/MarcoIeni/glimpse/commit/ee587916ad2841f5abe02c140a842202cf5e0b0a)) 102 | 103 | ## [0.4.1](https://github.com/MarcoIeni/glimpse/compare/v0.4.0...v0.4.1) (2023-07-22) 104 | 105 | 106 | ### Bug Fixes 107 | 108 | * web configuration ([8fd5799](https://github.com/MarcoIeni/glimpse/commit/8fd5799d60026a642e113931456388e1659a270c)) 109 | 110 | ## [0.4.0](https://github.com/MarcoIeni/glimpse/compare/v0.3.0...v0.4.0) (2023-07-21) 111 | 112 | 113 | ### Features 114 | 115 | * add logger ([75e7d6d](https://github.com/MarcoIeni/glimpse/commit/75e7d6d30975fd4174353122fcf242fb22528a55)) 116 | 117 | ## [0.3.0](https://github.com/MarcoIeni/glimpse/compare/v0.2.2...v0.3.0) (2023-07-19) 118 | 119 | 120 | ### Features 121 | 122 | * type checked icons ([#83](https://github.com/MarcoIeni/glimpse/issues/83)) ([de06491](https://github.com/MarcoIeni/glimpse/commit/de06491e6e70ec1febfac08f8cda83dde26a597b)) 123 | 124 | ## [0.2.2](https://github.com/MarcoIeni/glimpse/compare/v0.2.1...v0.2.2) (2023-07-18) 125 | 126 | 127 | ### Bug Fixes 128 | 129 | * **website:** add space ([eaa3470](https://github.com/MarcoIeni/glimpse/commit/eaa347064bb2999f8bc2c6b5c1735b8762f23ecb)) 130 | 131 | ## [0.2.1](https://github.com/MarcoIeni/glimpse/compare/v0.2.0...v0.2.1) (2023-07-15) 132 | 133 | 134 | ### Bug Fixes 135 | 136 | * return default menu if no config ([#75](https://github.com/MarcoIeni/glimpse/issues/75)) ([112a2ef](https://github.com/MarcoIeni/glimpse/commit/112a2efcdaf60d770fab7f7d21cae41f75516bf9)) 137 | 138 | ## [0.2.0](https://github.com/MarcoIeni/glimpse/compare/v0.1.0...v0.2.0) (2023-07-15) 139 | 140 | 141 | ### Features 142 | 143 | * don't close menu if key does not exist ([#69](https://github.com/MarcoIeni/glimpse/issues/69)) ([6a26142](https://github.com/MarcoIeni/glimpse/commit/6a2614247ab0452ba8e9248f298355d433f07032)) 144 | 145 | 146 | ### Bug Fixes 147 | 148 | * async loading javascript config file ([#74](https://github.com/MarcoIeni/glimpse/issues/74)) ([b2b2aed](https://github.com/MarcoIeni/glimpse/commit/b2b2aede5b3cd48b4c31b24f5b1fed8b25fcc51d)) 149 | * display name with capital letter ([8222ded](https://github.com/MarcoIeni/glimpse/commit/8222dedec9260cdbde44abde552421bc43730cd4)) 150 | 151 | ## [0.1.0](https://github.com/MarcoIeni/glimpse/compare/v0.0.6...v0.1.0) (2023-07-10) 152 | 153 | 154 | ### Features 155 | 156 | * add `s r` and `t m` ([9208ecc](https://github.com/MarcoIeni/glimpse/commit/9208ecc73f07ac74e502f16e4a77c30e23c0e8d2)) 157 | * make web compatible ([#49](https://github.com/MarcoIeni/glimpse/issues/49)) ([6f232b0](https://github.com/MarcoIeni/glimpse/commit/6f232b0ba336f24f7a0ae0b935cb9820128d2e43)) 158 | 159 | ## [0.0.6](https://github.com/MarcoIeni/glimpse/compare/v0.0.5...v0.0.6) (2023-07-08) 160 | 161 | 162 | ### Bug Fixes 163 | 164 | * set release-please token ([b218ae8](https://github.com/MarcoIeni/glimpse/commit/b218ae81cb326b30d6777d453dd68f01aba93b26)) 165 | 166 | ## [0.0.5](https://github.com/MarcoIeni/glimpse/compare/v0.0.4...v0.0.5) (2023-07-08) 167 | 168 | 169 | ### Bug Fixes 170 | 171 | * zoom key bindings order ([2f0c9cb](https://github.com/MarcoIeni/glimpse/commit/2f0c9cb9f68a433646d4282c769d7238a7098fb6)) 172 | 173 | ## [Unreleased] 174 | 175 | - Initial release 176 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 1. clone the repository 4 | 2. Run `npm install` 5 | 6 | ## Run the extension locally 7 | 8 | - Press `F5` to open a new window with your extension loaded. 9 | 10 | ## Run the extension in a web environment 11 | 12 | To run the extension in an environment similar to [vscode.dev](https://vscode.dev), run: 13 | 14 | ``` 15 | npm run open-in-browser 16 | ``` 17 | 18 | ## Philosophy 19 | 20 | The extension is built with the following principles in mind: 21 | 22 | - no external dependencies except for the required ones 23 | - performance first: we don't want to slow down the user. That's why we don't use functional programming (like `map`, etc.). 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Marco Ieni 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | [](https://glimpse.ieni.dev) 4 | [](https://marketplace.visualstudio.com/items?itemName=ieni.glimpse) 5 | [](https://marketplace.visualstudio.com/items?itemName=ieni.glimpse) 6 | [](https://marketplace.visualstudio.com/items?itemName=ieni.glimpse) 7 | 8 | Glimpse is a VSCode extension that allows you to run VSCode commands with easy-to-remember key bindings. 9 | 10 | You no longer need to remember complex shortcuts — Glimpse shows the available key bindings as you type. 11 | 12 | Learn more at [glimpse.ieni.dev](https://glimpse.ieni.dev). 13 | 14 | ## Credits 15 | 16 | 17 | Codebase 18 | 19 | Parts of the codebase are inspired by: 20 | - [VSpaceCode](https://github.com/VSpaceCode/VSpaceCode) 21 | - [vscode-which-key](https://github.com/VSpaceCode/vscode-which-key) 22 | 23 | 24 | 25 | Logo 26 | 27 | The logo was generated using [Bing image creator](https://www.bing.com/create). Prompt: 28 | 29 | > orange G letter in the middle of blue and salmon keyboard keys. cute. Comfy. Speedy. Cartoonish. Glamorous. logo. contains shiny stars. 30 | 31 | [Ambra Lucia Colombo](https://www.linkedin.com/in/ambralcolombo/) edited the image to correct AI defects. 32 | 33 | 34 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glimpse", 3 | "displayName": "Glimpse", 4 | "description": "Mnemonic key bindings for VSCode commands", 5 | "version": "0.16.0", 6 | "publisher": "ieni", 7 | "license": "MIT", 8 | "icon": "icon.png", 9 | "engines": { 10 | "vscode": "^1.79.0" 11 | }, 12 | "categories": [ 13 | "Keymaps", 14 | "Other", 15 | "Visualization" 16 | ], 17 | "bugs": { 18 | "url": "https://github.com/MarcoIeni/glimpse/issues" 19 | }, 20 | "activationEvents": [], 21 | "main": "./dist/extension-node", 22 | "browser": "./dist/extension-web", 23 | "contributes": { 24 | "keybindings": [ 25 | { 26 | "key": "tab", 27 | "command": "glimpse.triggerKey", 28 | "args": "\t", 29 | "when": "glimpseVisible" 30 | } 31 | ], 32 | "commands": [ 33 | { 34 | "command": "glimpse.menu", 35 | "title": "Glimpse: Menu" 36 | }, 37 | { 38 | "command": "glimpse.configure", 39 | "title": "Glimpse: Configure" 40 | }, 41 | { 42 | "command": "glimpse.openDocs", 43 | "title": "Glimpse: Open Docs" 44 | } 45 | ] 46 | }, 47 | "repository": { 48 | "type": "git", 49 | "url": "https://github.com/MarcoIeni/glimpse" 50 | }, 51 | "scripts": { 52 | "vscode:prepublish": "webpack --mode production", 53 | "compile": "webpack", 54 | "watch": "webpack --watch", 55 | "pretest": "npm run compile && npm run lint", 56 | "lint": "eslint src --ext ts --max-warnings=0", 57 | "format": "prettier --write .", 58 | "format:check": "prettier --check .", 59 | "open-in-browser": "vscode-test-web --extensionDevelopmentPath=. .", 60 | "write-keybindings": "ts-node src/keysToDocs.ts" 61 | }, 62 | "devDependencies": { 63 | "buffer": "^6.0.3", 64 | "@types/mocha": "^10.0.9", 65 | "@types/node": "22.x", 66 | "@types/vscode": "^1.90.0", 67 | "@types/webpack-env": "^1.18.5", 68 | "@typescript-eslint/eslint-plugin": "^7.18.0", 69 | "@typescript-eslint/parser": "^7.18.0", 70 | "eslint": "^8.57.1", 71 | "mocha": "^11.0.0", 72 | "prettier": "^3.3.3", 73 | "process": "^0.11.10", 74 | "ts-loader": "^9.5.1", 75 | "ts-node": "^10.9.2", 76 | "typescript": "^5.6.3", 77 | "webpack": "^5.95.0", 78 | "webpack-cli": "^6.0.0" 79 | }, 80 | "sponsor": { 81 | "url": "https://github.com/sponsors/MarcoIeni" 82 | }, 83 | "homepage": "https://glimpse.ieni.dev", 84 | "pricing": "Free" 85 | } 86 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { Logger, notifyError } from "./logger"; 3 | 4 | const defaultConfig = `// Edit the default glimpse menu using javascript. 5 | // We use jsdoc to provide autocomplete and type checking. 6 | // If the types are not working as expected, 7 | // delete this file, restart glimpse and run the \`Glimpse: Configure\` command again. 8 | 9 | /** 10 | * A VSCode command. 11 | * @typedef { string | 12 | * { id: string; args: any } 13 | * } Command 14 | */ 15 | 16 | /** 17 | * Glimpse menu. 18 | * @typedef {{ 19 | * transient?: boolean; 20 | * items: UserKey[] 21 | * }} UserMenu 22 | */ 23 | 24 | /** 25 | * Glimpse menu. 26 | * @typedef {{ command: Command } | { commands: Command[] }} CommandAndArgs 27 | */ 28 | 29 | /** 30 | * Glimpse menu. 31 | * @typedef { CommandAndArgs | { menu: UserMenu } | (CommandAndArgs & { menu: UserMenu} ) } UserCommandOrSubmenu 32 | */ 33 | 34 | /** 35 | * Glimpse key. 36 | * @typedef {{ 37 | * icon?: string, 38 | * name: string, 39 | * key: string, 40 | * } & UserCommandOrSubmenu} UserKey 41 | */ 42 | 43 | /** 44 | * @param { UserMenu } menu 45 | * @returns { UserMenu } 46 | */ 47 | module.exports = function editConfig(menu) { 48 | return menu; 49 | }`; 50 | 51 | export function configPath(context: vscode.ExtensionContext): vscode.Uri { 52 | return vscode.Uri.joinPath(context.globalStorageUri, "config.js"); 53 | } 54 | 55 | export async function pathExists(path: vscode.Uri): Promise { 56 | try { 57 | // if path doesn't exist, this will throw an error 58 | await vscode.workspace.fs.stat(path); 59 | return true; 60 | } catch (err) { 61 | return false; 62 | } 63 | } 64 | 65 | export async function glimpseConfigure(context: vscode.ExtensionContext): Promise { 66 | try { 67 | const storageUri = context.globalStorageUri; 68 | await createDirIfDoesntExist(storageUri); 69 | const configFilePath = configPath(context); 70 | await openConfig(configFilePath); 71 | } catch (err) { 72 | const errStr = err as string; 73 | notifyError("Failed to run Glimpse configure" + errStr); 74 | } 75 | } 76 | 77 | async function createDirIfDoesntExist(dir: vscode.Uri): Promise { 78 | const dirExists = await pathExists(dir); 79 | if (!dirExists) { 80 | await vscode.workspace.fs.createDirectory(dir); 81 | } 82 | } 83 | 84 | async function createFileIfDoesntExist(file: vscode.Uri, content: string): Promise { 85 | try { 86 | // if file doesn't exist, this will throw an error 87 | await vscode.workspace.fs.stat(file); 88 | Logger.info("config file already exists"); 89 | } catch (err) { 90 | Logger.info("creating file " + file.toString()); 91 | await vscode.workspace.fs.writeFile(file, Buffer.from(content)); 92 | // wait a while so that we avoid the error "file not found" in vscode 93 | await sleep(1000); 94 | } 95 | } 96 | 97 | function sleep(ms: number): Promise { 98 | return new Promise((resolve) => setTimeout(resolve, ms)); 99 | } 100 | 101 | async function openConfig(configUri: vscode.Uri): Promise { 102 | await createFileIfDoesntExist(configUri, defaultConfig); 103 | // open the file in the editor 104 | await vscode.commands.executeCommand("vscode.open", configUri); 105 | } 106 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { executeKey, glimpseRun as glimpseMenu, newExecutor } from "./glimpse"; 3 | import { glimpseConfigure } from "./config"; 4 | import { Logger, notifyError } from "./logger"; 5 | 6 | // This method is called when the extension is activated. 7 | // The extension is activated the very first time the command is executed. 8 | export async function activate(context: vscode.ExtensionContext): Promise { 9 | Logger.init(); 10 | Logger.info("The Glimpse extension is now active"); 11 | try { 12 | await activateExtension(context); 13 | } catch (err) { 14 | const errStr = err as string; 15 | notifyError("Failed to activate Glimpse: " + errStr); 16 | } 17 | } 18 | 19 | async function activateExtension(context: vscode.ExtensionContext): Promise { 20 | const executor = await newExecutor(context); 21 | 22 | // The commandId parameter must match the command field in package.json 23 | context.subscriptions.push( 24 | vscode.commands.registerCommand("glimpse.menu", () => { 25 | glimpseMenu(executor); 26 | }), 27 | ); 28 | context.subscriptions.push( 29 | vscode.commands.registerCommand("glimpse.configure", () => { 30 | glimpseConfigure(context).catch((err) => { 31 | notifyError("Failed to run async Glimpse configure" + err); 32 | }); 33 | }), 34 | ); 35 | context.subscriptions.push( 36 | vscode.commands.registerCommand("glimpse.triggerKey", () => { 37 | executeKey(executor, "\t").catch((err) => { 38 | notifyError("Failed to run async Glimpse triggerKey" + err); 39 | }); 40 | }), 41 | ); 42 | context.subscriptions.push(vscode.commands.registerCommand("glimpse.openDocs", openDocs)); 43 | } 44 | 45 | // This method is called when the extension is deactivated 46 | export function deactivate(): void { 47 | Logger.info("deactivate Glimpse"); 48 | } 49 | 50 | function openDocs() { 51 | const docsUri = vscode.Uri.parse("https://glimpse.ieni.dev/docs"); 52 | return vscode.env.openExternal(docsUri); 53 | } 54 | -------------------------------------------------------------------------------- /src/glimpse.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { keyDescription, menu, type Command, type Menu } from "./keys"; 3 | import { Logger, notifyError } from "./logger"; 4 | import { prettifyKey } from "./prettify"; 5 | 6 | export type Executor = { 7 | menu: Menu; 8 | /** The menu that the user originally defined. */ 9 | userMenu: Menu; 10 | quickPick: vscode.QuickPick; 11 | }; 12 | 13 | export async function newExecutor(context: vscode.ExtensionContext): Promise { 14 | const userMenu: Menu = await menu(context); 15 | return { 16 | menu: userMenu, 17 | userMenu: userMenu, 18 | // we create the quick pick here just to avoid having to check for null. 19 | // this value will be replaced. 20 | quickPick: vscode.window.createQuickPick(), 21 | }; 22 | } 23 | 24 | export function glimpseRun(executor: Executor): void { 25 | executor.menu = executor.userMenu; 26 | try { 27 | pick(executor, "Glimpse"); 28 | } catch (err) { 29 | const errStr = err as string; 30 | notifyError("Failed to run Glimpse" + errStr); 31 | } 32 | } 33 | 34 | function pick(executor: Executor, menuTitle: string): void { 35 | executor.quickPick = vscode.window.createQuickPick(); 36 | executor.quickPick.title = menuTitle; 37 | 38 | // Fill quick pick options. 39 | const options = []; 40 | for (const [key, value] of executor.menu.items.entries()) { 41 | options.push({ 42 | label: prettifyKey(key), 43 | description: `\t${keyDescription(value)}`, 44 | }); 45 | } 46 | 47 | executor.quickPick.items = options; 48 | // Allow to select action by key press. 49 | executor.quickPick.onDidChangeValue(() => { 50 | onValueChange(executor).catch((err) => { 51 | Logger.error("onDidChangeValue failure" + err); 52 | }); 53 | }); 54 | // Allow to select action with enter key. 55 | executor.quickPick.onDidAccept(() => { 56 | const activeItem = executor.quickPick.activeItems[0]; 57 | executeKey(executor, activeItem.label).catch((err) => { 58 | Logger.error("onDidAccept failure" + err); 59 | }); 60 | }); 61 | executor.quickPick.onDidHide(() => { 62 | executor.quickPick.dispose(); 63 | setGlimpseVisible(false).catch((err) => { 64 | Logger.error("Failed setting Glimpse Invisible" + err); 65 | }); 66 | }); 67 | executor.quickPick.show(); 68 | setGlimpseVisible(true).catch((err) => { 69 | Logger.error("Failed setting Glimpse Visible" + err); 70 | }); 71 | } 72 | 73 | async function onValueChange(executor: Executor): Promise { 74 | const key = executor.quickPick.value; 75 | Logger.info("user typed " + key); 76 | if (key.length !== 0) { 77 | await executeKey(executor, key); 78 | } 79 | } 80 | 81 | export async function executeKey(executor: Executor, key: string): Promise { 82 | const item = executor.menu.items.get(key); 83 | if (item) { 84 | executor.quickPick.dispose(); 85 | if ("commands" in item) { 86 | await executeCommands(item.commands); 87 | if (executor.menu.transient) { 88 | pick(executor, item.name); 89 | } 90 | } 91 | 92 | if ("menu" in item) { 93 | // open the submenu 94 | executor.menu = item.menu; 95 | pick(executor, item.name); 96 | } 97 | } 98 | } 99 | 100 | async function executeCommands(commands: Command[]): Promise { 101 | Logger.info("executing command " + JSON.stringify(commands)); 102 | for (const cmd of commands) { 103 | if (typeof cmd === "string") { 104 | await vscode.commands.executeCommand(cmd); 105 | } else if ("id" in cmd && "args" in cmd) { 106 | const commandId = cmd.id; 107 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 108 | const args = cmd.args; 109 | if (Array.isArray(args)) { 110 | // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 111 | await vscode.commands.executeCommand(commandId, ...args); 112 | } else { 113 | // undefined from the object chainning/indexing or 114 | // null from the json deserialization 115 | await vscode.commands.executeCommand(commandId, args); 116 | } 117 | } else { 118 | throw new Error("Invalid command"); 119 | } 120 | } 121 | } 122 | 123 | async function setGlimpseVisible(value: boolean): Promise { 124 | await vscode.commands.executeCommand("setContext", "glimpseVisible", value); 125 | } 126 | -------------------------------------------------------------------------------- /src/icons.ts: -------------------------------------------------------------------------------- 1 | export type Icon = 2 | | "account" 3 | | "activate-breakpoints" 4 | | "add" 5 | | "alert" 6 | | "archive" 7 | | "array" 8 | | "arrow-both" 9 | | "arrow-circle-down" 10 | | "arrow-circle-left" 11 | | "arrow-circle-right" 12 | | "arrow-circle-up" 13 | | "arrow-down" 14 | | "arrow-left" 15 | | "arrow-right" 16 | | "arrow-small-down" 17 | | "arrow-small-left" 18 | | "arrow-small-right" 19 | | "arrow-small-up" 20 | | "arrow-swap" 21 | | "arrow-up" 22 | | "azure-devops" 23 | | "azure" 24 | | "beaker-stop" 25 | | "beaker" 26 | | "bell-dot" 27 | | "bell" 28 | | "bold" 29 | | "book" 30 | | "bookmark" 31 | | "bracket-dot" 32 | | "bracket-error" 33 | | "bracket" 34 | | "briefcase" 35 | | "broadcast" 36 | | "browser" 37 | | "bug" 38 | | "calendar" 39 | | "call-incoming" 40 | | "call-outgoing" 41 | | "case-sensitive" 42 | | "check-all" 43 | | "check" 44 | | "checklist" 45 | | "chevron-down" 46 | | "chevron-left" 47 | | "chevron-right" 48 | | "chevron-up" 49 | | "chrome-close" 50 | | "chrome-maximize" 51 | | "chrome-minimize" 52 | | "chrome-restore" 53 | | "circle-filled" 54 | | "circle-large-filled" 55 | | "circle-large-outline" 56 | | "circle-outline" 57 | | "circle-slash" 58 | | "circuit-board" 59 | | "clear-all" 60 | | "clippy" 61 | | "clock" 62 | | "clone" 63 | | "close-all" 64 | | "close-dirty" 65 | | "close" 66 | | "cloud-download" 67 | | "cloud-upload" 68 | | "cloud" 69 | | "code" 70 | | "collapse-all" 71 | | "color-mode" 72 | | "combine" 73 | | "comment-add" 74 | | "comment-discussion" 75 | | "comment" 76 | | "compare-changes" 77 | | "compass-active" 78 | | "compass-dot" 79 | | "compass" 80 | | "console" 81 | | "credit-card" 82 | | "dash" 83 | | "dashboard" 84 | | "database" 85 | | "debug-all" 86 | | "debug-alt-small" 87 | | "debug-alt" 88 | | "debug-breakpoint-conditional-disabled" 89 | | "debug-breakpoint-conditional-unverified" 90 | | "debug-breakpoint-conditional" 91 | | "debug-breakpoint-data-disabled" 92 | | "debug-breakpoint-data-unverified" 93 | | "debug-breakpoint-data" 94 | | "debug-breakpoint-disabled" 95 | | "debug-breakpoint-function-disabled" 96 | | "debug-breakpoint-function-unverified" 97 | | "debug-breakpoint-function" 98 | | "debug-breakpoint-log-disabled" 99 | | "debug-breakpoint-log-unverified" 100 | | "debug-breakpoint-log" 101 | | "debug-breakpoint-unsupported" 102 | | "debug-breakpoint-unverified" 103 | | "debug-breakpoint" 104 | | "debug-console" 105 | | "debug-continue-small" 106 | | "debug-continue" 107 | | "debug-coverage" 108 | | "debug-disconnect" 109 | | "debug-hint" 110 | | "debug-line-by-line" 111 | | "debug-pause" 112 | | "debug-rerun" 113 | | "debug-restart-frame" 114 | | "debug-restart" 115 | | "debug-reverse-continue" 116 | | "debug-stackframe-active" 117 | | "debug-stackframe-dot" 118 | | "debug-stackframe-focused" 119 | | "debug-stackframe" 120 | | "debug-start" 121 | | "debug-step-back" 122 | | "debug-step-into" 123 | | "debug-step-out" 124 | | "debug-step-over" 125 | | "debug-stop" 126 | | "debug" 127 | | "desktop-download" 128 | | "device-camera-video" 129 | | "device-camera" 130 | | "device-desktop" 131 | | "device-mobile" 132 | | "diff-added" 133 | | "diff-ignored" 134 | | "diff-modified" 135 | | "diff-removed" 136 | | "diff-renamed" 137 | | "diff" 138 | | "discard" 139 | | "edit" 140 | | "editor-layout" 141 | | "ellipsis" 142 | | "empty-window" 143 | | "error-small" 144 | | "error" 145 | | "exclude" 146 | | "expand-all" 147 | | "export" 148 | | "extensions" 149 | | "eye-closed" 150 | | "eye-unwatch" 151 | | "eye-watch" 152 | | "eye" 153 | | "feedback" 154 | | "file-add" 155 | | "file-binary" 156 | | "file-code" 157 | | "file-directory-create" 158 | | "file-directory" 159 | | "file-media" 160 | | "file-pdf" 161 | | "file-submodule" 162 | | "file-symlink-directory" 163 | | "file-symlink-file" 164 | | "file-text" 165 | | "file-zip" 166 | | "file" 167 | | "files" 168 | | "filter-filled" 169 | | "filter" 170 | | "flame" 171 | | "fold-down" 172 | | "fold-up" 173 | | "fold" 174 | | "folder-active" 175 | | "folder-library" 176 | | "folder-opened" 177 | | "folder" 178 | | "gather" 179 | | "gear" 180 | | "gift" 181 | | "gist-fork" 182 | | "gist-new" 183 | | "gist-private" 184 | | "gist-secret" 185 | | "gist" 186 | | "git-branch-create" 187 | | "git-branch-delete" 188 | | "git-branch" 189 | | "git-commit" 190 | | "git-compare" 191 | | "git-fork-private" 192 | | "git-merge" 193 | | "git-pull-request-abandoned" 194 | | "git-pull-request-closed" 195 | | "git-pull-request-create" 196 | | "git-pull-request-draft" 197 | | "git-pull-request" 198 | | "github-action" 199 | | "github-alt" 200 | | "github-inverted" 201 | | "github" 202 | | "globe" 203 | | "go-to-file" 204 | | "grabber" 205 | | "graph-left" 206 | | "graph-line" 207 | | "graph-scatter" 208 | | "graph" 209 | | "gripper" 210 | | "group-by-ref-type" 211 | | "heart" 212 | | "history" 213 | | "home" 214 | | "horizontal-rule" 215 | | "hubot" 216 | | "inbox" 217 | | "indent" 218 | | "info" 219 | | "inspect" 220 | | "issue-closed" 221 | | "issue-draft" 222 | | "issue-opened" 223 | | "issue-reopened" 224 | | "issues" 225 | | "italic" 226 | | "jersey" 227 | | "json" 228 | | "kebab-horizontal" 229 | | "kebab-vertical" 230 | | "key" 231 | | "keyboard" 232 | | "law" 233 | | "layers-active" 234 | | "layers-dot" 235 | | "layers" 236 | | "layout-activitybar-left" 237 | | "layout-activitybar-right" 238 | | "layout-centered" 239 | | "layout-menubar" 240 | | "layout-panel-center" 241 | | "layout-panel-justify" 242 | | "layout-panel-left" 243 | | "layout-panel-right" 244 | | "layout-panel" 245 | | "layout-sidebar-left" 246 | | "layout-sidebar-right" 247 | | "layout-statusbar" 248 | | "layout" 249 | | "library" 250 | | "light-bulb" 251 | | "lightbulb-autofix" 252 | | "lightbulb" 253 | | "link-external" 254 | | "link" 255 | | "list-filter" 256 | | "list-flat" 257 | | "list-ordered" 258 | | "list-selection" 259 | | "list-tree" 260 | | "list-unordered" 261 | | "live-share" 262 | | "loading" 263 | | "location" 264 | | "lock-small" 265 | | "lock" 266 | | "log-in" 267 | | "log-out" 268 | | "logo-github" 269 | | "magnet" 270 | | "mail-read" 271 | | "mail-reply" 272 | | "mail" 273 | | "mark-github" 274 | | "markdown" 275 | | "megaphone" 276 | | "mention" 277 | | "menu" 278 | | "merge" 279 | | "microscope" 280 | | "milestone" 281 | | "mirror-private" 282 | | "mirror-public" 283 | | "mirror" 284 | | "more" 285 | | "mortar-board" 286 | | "move" 287 | | "multiple-windows" 288 | | "mute" 289 | | "new-file" 290 | | "new-folder" 291 | | "newline" 292 | | "no-newline" 293 | | "note" 294 | | "notebook-template" 295 | | "notebook" 296 | | "octoface" 297 | | "open-preview" 298 | | "organization-filled" 299 | | "organization-outline" 300 | | "organization" 301 | | "output" 302 | | "package" 303 | | "paintcan" 304 | | "pass-filled" 305 | | "pass" 306 | | "pencil" 307 | | "person-add" 308 | | "person-filled" 309 | | "person-follow" 310 | | "person-outline" 311 | | "person" 312 | | "pie-chart" 313 | | "pin" 314 | | "pinned-dirty" 315 | | "pinned" 316 | | "play-circle" 317 | | "play" 318 | | "plug" 319 | | "plus" 320 | | "preserve-case" 321 | | "preview" 322 | | "primitive-dot" 323 | | "primitive-square" 324 | | "project" 325 | | "pulse" 326 | | "question" 327 | | "quote" 328 | | "radio-tower" 329 | | "reactions" 330 | | "record-keys" 331 | | "record-small" 332 | | "record" 333 | | "redo" 334 | | "references" 335 | | "refresh" 336 | | "regex" 337 | | "remote-explorer" 338 | | "remote" 339 | | "remove-close" 340 | | "remove" 341 | | "repl" 342 | | "replace-all" 343 | | "replace" 344 | | "reply" 345 | | "repo-clone" 346 | | "repo-create" 347 | | "repo-delete" 348 | | "repo-force-push" 349 | | "repo-forked" 350 | | "repo-pull" 351 | | "repo-push" 352 | | "repo-sync" 353 | | "repo" 354 | | "report" 355 | | "request-changes" 356 | | "rocket" 357 | | "root-folder-opened" 358 | | "root-folder" 359 | | "rss" 360 | | "ruby" 361 | | "run-above" 362 | | "run-all" 363 | | "run-below" 364 | | "run-errors" 365 | | "run" 366 | | "save-all" 367 | | "save-as" 368 | | "save" 369 | | "screen-full" 370 | | "screen-normal" 371 | | "search-save" 372 | | "search-stop" 373 | | "search" 374 | | "selection" 375 | | "server-environment" 376 | | "server-process" 377 | | "server" 378 | | "settings-gear" 379 | | "settings" 380 | | "shield" 381 | | "sign-in" 382 | | "sign-out" 383 | | "smiley" 384 | | "sort-precedence" 385 | | "source-control" 386 | | "split-horizontal" 387 | | "split-vertical" 388 | | "squirrel" 389 | | "star-add" 390 | | "star-delete" 391 | | "star-empty" 392 | | "star-full" 393 | | "star-half" 394 | | "star" 395 | | "stop-circle" 396 | | "stop" 397 | | "symbol-array" 398 | | "symbol-boolean" 399 | | "symbol-class" 400 | | "symbol-color" 401 | | "symbol-constant" 402 | | "symbol-constructor" 403 | | "symbol-enum-member" 404 | | "symbol-enum" 405 | | "symbol-event" 406 | | "symbol-field" 407 | | "symbol-file" 408 | | "symbol-folder" 409 | | "symbol-function" 410 | | "symbol-interface" 411 | | "symbol-key" 412 | | "symbol-keyword" 413 | | "symbol-method" 414 | | "symbol-misc" 415 | | "symbol-module" 416 | | "symbol-namespace" 417 | | "symbol-null" 418 | | "symbol-number" 419 | | "symbol-numeric" 420 | | "symbol-object" 421 | | "symbol-operator" 422 | | "symbol-package" 423 | | "symbol-parameter" 424 | | "symbol-property" 425 | | "symbol-reference" 426 | | "symbol-ruler" 427 | | "symbol-snippet" 428 | | "symbol-string" 429 | | "symbol-struct" 430 | | "symbol-structure" 431 | | "symbol-text" 432 | | "symbol-type-parameter" 433 | | "symbol-unit" 434 | | "symbol-value" 435 | | "symbol-variable" 436 | | "sync-ignored" 437 | | "sync" 438 | | "tag-add" 439 | | "tag-remove" 440 | | "tag" 441 | | "target" 442 | | "tasklist" 443 | | "telescope" 444 | | "terminal-bash" 445 | | "terminal-cmd" 446 | | "terminal-debian" 447 | | "terminal-linux" 448 | | "terminal-powershell" 449 | | "terminal-tmux" 450 | | "terminal-ubuntu" 451 | | "terminal" 452 | | "text-size" 453 | | "three-bars" 454 | | "thumbsdown" 455 | | "thumbsup" 456 | | "tools" 457 | | "trash" 458 | | "trashcan" 459 | | "triangle-down" 460 | | "triangle-left" 461 | | "triangle-right" 462 | | "triangle-up" 463 | | "twitter" 464 | | "type-hierarchy-sub" 465 | | "type-hierarchy-super" 466 | | "type-hierarchy" 467 | | "unfold" 468 | | "ungroup-by-ref-type" 469 | | "unlock" 470 | | "unmute" 471 | | "unverified" 472 | | "variable" 473 | | "verified-filled" 474 | | "verified" 475 | | "versions" 476 | | "vm-active" 477 | | "vm-connect" 478 | | "vm-outline" 479 | | "vm-running" 480 | | "vm" 481 | | "warning" 482 | | "watch" 483 | | "whitespace" 484 | | "whole-word" 485 | | "window" 486 | | "word-wrap" 487 | | "workspace-trusted" 488 | | "workspace-unknown" 489 | | "workspace-untrusted" 490 | | "wrench-subaction" 491 | | "wrench" 492 | | "x" 493 | | "zap" 494 | | "zoom-in" 495 | | "zoom-out"; 496 | -------------------------------------------------------------------------------- /src/keys.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { configPath, pathExists } from "./config"; 3 | import { defaultMenu } from "./keys/default_menu"; 4 | import { type Icon } from "./icons"; 5 | import { Logger, notifyError } from "./logger"; 6 | import { utf8ArrayToStr } from "./utf8ToStr"; 7 | 8 | export type Key = CommandOrSubmenu & KeyDescription; 9 | 10 | type KeyDescription = { 11 | /** icon displayed in the name */ 12 | icon?: Icon; 13 | /** name of the key */ 14 | name: string; 15 | }; 16 | 17 | type CommandAndArgs = 18 | | { 19 | command: Command; 20 | } 21 | | { 22 | commands: Command[]; 23 | }; 24 | 25 | type CommandOrSubmenu = 26 | // when pressing the key, execute the command AND open another menu 27 | | { 28 | commands: Command[]; 29 | menu: Menu; 30 | } 31 | | { commands: Command[] } 32 | | { menu: Menu }; 33 | 34 | type UserCommandOrSubmenu = 35 | // when pressing the key, execute the command AND open another menu 36 | | CommandAndArgs 37 | | { menu: UserMenu } 38 | | (CommandAndArgs & { 39 | menu: UserMenu; 40 | }); 41 | 42 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 43 | export type Command = string | { id: string; args: any }; 44 | 45 | export function keyDescription(key: Key): string { 46 | let description = ""; 47 | if (key.icon) { 48 | description += `$(${key.icon}) `; 49 | } 50 | if (!("commands" in key)) { 51 | description += "+"; 52 | } 53 | description += key.name; 54 | return description; 55 | } 56 | 57 | export type Menu = { 58 | transient: boolean; 59 | items: Map; 60 | }; 61 | 62 | export type UserMenu = { 63 | transient?: boolean; 64 | items: UserKey[]; 65 | }; 66 | 67 | export type UserKey = UserKeyBase & { 68 | key: string; 69 | }; 70 | 71 | export type UserKeyBase = KeyDescription & UserCommandOrSubmenu; 72 | 73 | export async function menu(context: vscode.ExtensionContext): Promise { 74 | const originalMenu = defaultMenu(); 75 | const configFilePath = configPath(context); 76 | const configExists = await pathExists(configFilePath); 77 | Logger.info("config path " + configFilePath.toString() + " exists: " + configExists); 78 | 79 | if (configExists) { 80 | try { 81 | await vscode.workspace.fs.readFile(configFilePath).then((content) => { 82 | // read the content of configFilePath 83 | const fileContent = utf8ArrayToStr(content); 84 | Logger.debug("config file content: " + fileContent); 85 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 86 | const userModule = eval(fileContent); 87 | // eslint-disable-next-line @typescript-eslint/no-unsafe-call 88 | const userSpecificMenu = userModule(originalMenu) as UserMenu; 89 | return fromUserMenu(userSpecificMenu); 90 | }); 91 | } catch (err) { 92 | const errStr = err as string; 93 | const msg = `Failed to read user configuration. Using default Glimpse configuration. Error: ${errStr}`; 94 | notifyError(msg); 95 | } 96 | } 97 | return fromUserMenu(originalMenu); 98 | } 99 | 100 | function fromUserMenu(userMenu: UserMenu): Menu { 101 | const items = new Map(); 102 | for (const item of userMenu.items) { 103 | if (items.has(item.key)) { 104 | throw new Error(`Duplicate key ${item.key}: ${JSON.stringify(item)}`); 105 | } 106 | items.set(item.key, fromUserKey(item)); 107 | } 108 | let transient = false; 109 | if (userMenu.transient) { 110 | transient = userMenu.transient; 111 | } 112 | return { transient, items }; 113 | } 114 | 115 | function fromUserKey(userKey: UserKey): Key { 116 | const keyDescription: KeyDescription = { name: userKey.name, icon: userKey.icon }; 117 | let commands = null; 118 | if ("command" in userKey) { 119 | commands = [userKey.command]; 120 | } else if ("commands" in userKey) { 121 | commands = []; 122 | for (const command of userKey.commands) { 123 | commands.push(command); 124 | } 125 | } 126 | let menu = null; 127 | if ("menu" in userKey) { 128 | menu = fromUserMenu(userKey.menu); 129 | } 130 | if (menu && commands) { 131 | return { ...keyDescription, commands, menu }; 132 | } else if (commands) { 133 | return { ...keyDescription, commands }; 134 | } else if (menu) { 135 | return { ...keyDescription, menu }; 136 | } else { 137 | throw new Error("Invalid user key"); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/keys/comments.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function commentsKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "f", 8 | name: "Fold all block comments", 9 | icon: "comment", 10 | command: "editor.foldAllBlockComments", 11 | }, 12 | { 13 | key: "b", 14 | name: "Toggle block comment", 15 | icon: "comment", 16 | command: "editor.action.blockComment", 17 | }, 18 | { 19 | key: "l", 20 | name: "Toggle line comment", 21 | icon: "comment", 22 | command: "editor.action.commentLine", 23 | }, 24 | ], 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/keys/common.ts: -------------------------------------------------------------------------------- 1 | import { type UserKeyBase } from "../keys"; 2 | 3 | export const searchSelectionInFiles: UserKeyBase = { 4 | name: "Search Selection in Files", 5 | icon: "selection", 6 | commands: [ 7 | "editor.action.addSelectionToNextFindMatch", 8 | "workbench.action.findInFiles", 9 | "search.action.focusSearchList", 10 | ], 11 | }; 12 | 13 | export const showTerminal: UserKeyBase = { 14 | name: "Show terminal", 15 | icon: "terminal", 16 | command: "workbench.action.terminal.focus", 17 | }; 18 | 19 | export const commentLine: UserKeyBase = { 20 | name: "Toggle comment", 21 | icon: "comment", 22 | command: "editor.action.commentLine", 23 | }; 24 | 25 | export const showProblems: UserKeyBase = { 26 | name: "Show problems", 27 | icon: "error", 28 | command: "workbench.actions.view.problems", 29 | }; 30 | -------------------------------------------------------------------------------- /src/keys/configKeys.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function configKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "c", 8 | name: "Open settings", 9 | icon: "settings", 10 | command: "workbench.action.openGlobalSettings", 11 | }, 12 | { 13 | key: "C", 14 | name: "Open settings JSON", 15 | icon: "json", 16 | command: "workbench.action.openSettingsJson", 17 | }, 18 | { 19 | key: "g", 20 | name: "Glimpse: Configure", 21 | icon: "star", 22 | command: "glimpse.configure", 23 | }, 24 | { 25 | key: "k", 26 | name: "Open global key bindings", 27 | icon: "keyboard", 28 | command: "workbench.action.openGlobalKeybindings", 29 | }, 30 | { 31 | key: "K", 32 | name: "Open global key bindings JSON", 33 | icon: "json", 34 | command: "workbench.action.openGlobalKeybindingsFile", 35 | }, 36 | { 37 | key: "l", 38 | name: "Open language settings", 39 | icon: "code", 40 | command: "workbench.action.configureLanguageBasedSettings", 41 | }, 42 | { 43 | key: "s", 44 | name: "Configure user snippets", 45 | icon: "symbol-snippet", 46 | command: "workbench.action.openSnippets", 47 | }, 48 | { 49 | key: "w", 50 | name: "Open workspace settings", 51 | icon: "edit", 52 | command: "workbench.action.openWorkspaceSettings", 53 | }, 54 | { 55 | key: "W", 56 | name: "Open workspace settings JSON", 57 | icon: "json", 58 | command: "workbench.action.openWorkspaceSettingsFile", 59 | }, 60 | ], 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /src/keys/debug.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function debugKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { key: "b", name: "Breakpoint", icon: "debug-breakpoint", menu: breakpoint() }, 7 | { 8 | key: "c", 9 | name: "Continue debug", 10 | icon: "debug-continue", 11 | command: "workbench.action.debug.continue", 12 | }, 13 | { 14 | key: "C", 15 | name: "Continue to cursor", 16 | icon: "debug-continue", 17 | command: "editor.debug.action.runToCursor", 18 | }, 19 | { 20 | key: "d", 21 | name: "Start debug", 22 | icon: "debug-start", 23 | command: "workbench.action.debug.start", 24 | }, 25 | { 26 | key: "D", 27 | name: "Run without debugging", 28 | icon: "run", 29 | command: "workbench.action.debug.run", 30 | }, 31 | { 32 | key: "i", 33 | name: "Step into", 34 | icon: "debug-step-into", 35 | command: "workbench.action.debug.stepInto", 36 | }, 37 | { 38 | key: "j", 39 | name: "Jump to cursor", 40 | icon: "whole-word", 41 | command: "debug.jumpToCursor", 42 | }, 43 | { 44 | key: "o", 45 | name: "Step out", 46 | icon: "debug-step-out", 47 | command: "workbench.action.debug.stepOut", 48 | }, 49 | { 50 | key: "p", 51 | name: "Pause debug", 52 | icon: "debug-pause", 53 | command: "workbench.action.debug.pause", 54 | }, 55 | { 56 | key: "R", 57 | name: "Restart debug", 58 | icon: "debug-restart", 59 | command: "workbench.action.debug.restart", 60 | }, 61 | { 62 | key: "s", 63 | name: "Step over", 64 | icon: "debug-step-over", 65 | command: "workbench.action.debug.stepOver", 66 | }, 67 | { 68 | key: "S", 69 | name: "Stop debug", 70 | icon: "debug-stop", 71 | command: "workbench.action.debug.stop", 72 | }, 73 | { 74 | key: "v", 75 | name: "REPL", 76 | icon: "debug-console", 77 | command: "workbench.debug.action.toggleRepl", 78 | }, 79 | { 80 | key: "w", 81 | name: "Focus on watch view", 82 | icon: "eye-watch", 83 | command: "workbench.debug.action.focusWatchView", 84 | }, 85 | { 86 | key: "W", 87 | name: "Add to watch", 88 | icon: "add", 89 | command: "editor.debug.action.selectionToWatch", 90 | }, 91 | ], 92 | }; 93 | } 94 | 95 | function breakpoint(): UserMenu { 96 | return { 97 | items: [ 98 | { 99 | key: "b", 100 | name: "Toggle breakpoint", 101 | icon: "activate-breakpoints", 102 | command: "editor.debug.action.toggleBreakpoint", 103 | }, 104 | { 105 | key: "c", 106 | name: "Add conditional breakpoint", 107 | icon: "debug-breakpoint-conditional", 108 | command: "editor.debug.action.conditionalBreakpoint", 109 | }, 110 | { 111 | key: "d", 112 | name: "Delete breakpoint", 113 | icon: "trash", 114 | command: "debug.removeBreakpoint", 115 | }, 116 | { 117 | key: "D", 118 | name: "Delete all breakpoints", 119 | icon: "trash", 120 | command: "workbench.debug.viewlet.action.removeAllBreakpoints", 121 | }, 122 | { 123 | key: "e", 124 | name: "Enable breakpoint", 125 | icon: "debug-breakpoint", 126 | command: "debug.enableOrDisableBreakpoint", 127 | }, 128 | { 129 | key: "E", 130 | name: "Enable all breakpoints", 131 | icon: "expand-all", 132 | command: "workbench.debug.viewlet.action.enableAllBreakpoints", 133 | }, 134 | { 135 | key: "f", 136 | name: "Add function breakpoint", 137 | icon: "debug-breakpoint-function", 138 | command: "workbench.debug.viewlet.action.addFunctionBreakpointAction", 139 | }, 140 | { 141 | key: "i", 142 | name: "Toggle inline breakpoint", 143 | icon: "activate-breakpoints", 144 | command: "editor.debug.action.toggleInlineBreakpoint", 145 | }, 146 | { 147 | key: "n", 148 | name: "Next breakpoint", 149 | icon: "arrow-down", 150 | command: "editor.debug.action.goToNextBreakpoint", 151 | menu: nextPrevBreakPoint(), 152 | }, 153 | { 154 | key: "p", 155 | name: "Previous breakpoint", 156 | icon: "arrow-up", 157 | command: "editor.debug.action.goToPreviousBreakpoint", 158 | menu: nextPrevBreakPoint(), 159 | }, 160 | { 161 | key: "s", 162 | name: "Disable breakpoint", 163 | icon: "debug-breakpoint-disabled", 164 | command: "debug.enableOrDisableBreakpoint", 165 | }, 166 | { 167 | key: "S", 168 | name: "Disable all breakpoints", 169 | icon: "collapse-all", 170 | command: "workbench.debug.viewlet.action.disableAllBreakpoints", 171 | }, 172 | ], 173 | }; 174 | } 175 | 176 | function nextPrevBreakPoint(): UserMenu { 177 | return { 178 | transient: true, 179 | items: [ 180 | { 181 | key: "n", 182 | name: "Next breakpoint", 183 | icon: "arrow-down", 184 | command: "editor.debug.action.goToNextBreakpoint", 185 | }, 186 | { 187 | key: "p", 188 | name: "Previous breakpoint", 189 | icon: "arrow-up", 190 | command: "editor.debug.action.goToPreviousBreakpoint", 191 | }, 192 | ], 193 | }; 194 | } 195 | -------------------------------------------------------------------------------- /src/keys/default_menu.ts: -------------------------------------------------------------------------------- 1 | import { tasksKeys } from "./tasks"; 2 | import { gitKeys } from "./git"; 3 | import { goToKeys } from "./go_to"; 4 | import { helpKeys } from "./help"; 5 | import { searchKeys } from "./search"; 6 | import { zoomKeys } from "./zoom"; 7 | import { filesKeys } from "./files"; 8 | import { errorKeys } from "./errors"; 9 | import { debugKeys } from "./debug"; 10 | import { windowKeys } from "./window"; 11 | import { toggleKeys } from "./toggles"; 12 | import { textKeys } from "./text"; 13 | import { editorKeys } from "./editor"; 14 | import { commentsKeys } from "./comments"; 15 | import { type UserKey, type UserMenu } from "../keys"; 16 | import { configKeys } from "./configKeys"; 17 | import { indentKeys } from "./indent"; 18 | import { formatKeys } from "./format"; 19 | import { peekKeys } from "./peek"; 20 | import { quitKeys } from "./quit"; 21 | import { refactorKeys } from "./refactor"; 22 | import { commentLine, searchSelectionInFiles, showProblems, showTerminal } from "./common"; 23 | import { ghCopilotKeys } from "./gh_copilot"; 24 | 25 | export function defaultMenu(): UserMenu { 26 | const githubCopilotKeys: UserKey[] = []; 27 | const ghCopilot = ghCopilotKeys(); 28 | if (ghCopilot) { 29 | githubCopilotKeys.push({ 30 | key: "G", 31 | name: "GitHub Copilot", 32 | icon: "github", 33 | menu: ghCopilot, 34 | }); 35 | } 36 | 37 | const firstKeys: UserKey[] = [ 38 | { 39 | key: "c", 40 | name: "Configuration", 41 | icon: "gear", 42 | menu: configKeys(), 43 | }, 44 | { 45 | key: "C", 46 | name: "Comment", 47 | icon: "comment", 48 | menu: commentsKeys(), 49 | }, 50 | { 51 | key: "d", 52 | name: "Debug", 53 | icon: "bug", 54 | menu: debugKeys(), 55 | }, 56 | { 57 | key: "D", 58 | name: "Diff/Compare", 59 | icon: "diff", 60 | menu: diffKeys(), 61 | }, 62 | { 63 | key: "e", 64 | name: "Error", 65 | icon: "error", 66 | menu: errorKeys(), 67 | }, 68 | { 69 | key: "E", 70 | name: "Editor", 71 | icon: "file", 72 | menu: editorKeys(), 73 | }, 74 | { 75 | key: "f", 76 | name: "File", 77 | icon: "file", 78 | menu: filesKeys(), 79 | }, 80 | { 81 | key: "F", 82 | name: "Format", 83 | icon: "list-flat", 84 | menu: formatKeys(), 85 | }, 86 | { 87 | key: "g", 88 | name: "Git", 89 | icon: "git-branch", 90 | menu: gitKeys(), 91 | }, 92 | ]; 93 | 94 | const secondKeys: UserKey[] = [ 95 | { 96 | key: "h", 97 | name: "Help", 98 | icon: "question", 99 | menu: helpKeys(), 100 | }, 101 | { 102 | key: "i", 103 | name: "Insert", 104 | icon: "question", 105 | menu: insertKeys(), 106 | }, 107 | { 108 | key: "I", 109 | name: "Indent", 110 | icon: "arrow-right", 111 | menu: indentKeys(), 112 | }, 113 | { 114 | key: "j", 115 | name: "Jump", 116 | icon: "go-to-file", 117 | menu: goToKeys(), 118 | }, 119 | { 120 | key: "p", 121 | name: "Peek", 122 | icon: "eye", 123 | menu: peekKeys(), 124 | }, 125 | { 126 | key: "q", 127 | name: "Quit", 128 | icon: "x", 129 | menu: quitKeys(), 130 | }, 131 | { 132 | key: "r", 133 | name: "Refactor", 134 | icon: "edit", 135 | menu: refactorKeys(), 136 | }, 137 | { 138 | key: "s", 139 | name: "Search", 140 | icon: "search", 141 | menu: searchKeys(), 142 | }, 143 | { 144 | key: "S", 145 | name: "Show", 146 | icon: "info", 147 | menu: show(), 148 | }, 149 | { 150 | key: "t", 151 | name: "Toggle", 152 | icon: "settings", 153 | menu: toggleKeys(), 154 | }, 155 | { 156 | key: "T", 157 | name: "Test", 158 | icon: "beaker", 159 | menu: tests(), 160 | }, 161 | { 162 | key: "w", 163 | name: "Window/Group", 164 | icon: "split-horizontal", 165 | menu: windowKeys(), 166 | }, 167 | { 168 | key: "x", 169 | name: "Text", 170 | icon: "symbol-text", 171 | menu: textKeys(), 172 | }, 173 | { 174 | key: "v", 175 | name: "Select/expand region", 176 | icon: "selection", 177 | command: "editor.action.smartSelect.grow", 178 | menu: selectExpand(), 179 | }, 180 | { key: "z", name: "Zoom/Fold", icon: "zoom-in", menu: zoomKeys() }, 181 | { 182 | key: " ", 183 | name: "Commands", 184 | icon: "rocket", 185 | command: "workbench.action.showCommands", 186 | }, 187 | { 188 | key: "\t", 189 | icon: "go-to-file", 190 | name: "Last editor", 191 | commands: [ 192 | "workbench.action.quickOpenPreviousRecentlyUsedEditorInGroup", 193 | "list.select", 194 | ], 195 | }, 196 | { 197 | ...showTerminal, 198 | key: "!", 199 | }, 200 | { 201 | key: '"', 202 | name: "Open new external terminal", 203 | icon: "chevron-right", 204 | command: "workbench.action.terminal.openNativeConsole", 205 | }, 206 | { 207 | ...showTerminal, 208 | key: "'", 209 | }, 210 | { 211 | ...searchSelectionInFiles, 212 | key: "*", 213 | }, 214 | { 215 | key: "/", 216 | name: "Search in files", 217 | icon: "search", 218 | command: "workbench.action.findInFiles", 219 | }, 220 | { 221 | key: ":", 222 | name: "Task", 223 | icon: "tasklist", 224 | menu: tasksKeys(), 225 | }, 226 | { 227 | ...commentLine, 228 | key: ";", 229 | }, 230 | { 231 | key: "0", 232 | name: "Focus on files explorer", 233 | icon: "list-tree", 234 | command: "workbench.files.action.focusFilesExplorer", 235 | }, 236 | { 237 | key: "1", 238 | name: "Focus 1st editor group", 239 | icon: "files", 240 | command: "workbench.action.focusFirstEditorGroup", 241 | }, 242 | { 243 | key: "2", 244 | name: "Focus 2nd editor group", 245 | icon: "files", 246 | command: "workbench.action.focusSecondEditorGroup", 247 | }, 248 | { 249 | key: "3", 250 | name: "Focus 3rd editor group", 251 | icon: "files", 252 | command: "workbench.action.focusThirdEditorGroup", 253 | }, 254 | { 255 | key: "4", 256 | name: "Focus 4th editor group", 257 | icon: "files", 258 | command: "workbench.action.focusFourthEditorGroup", 259 | }, 260 | { 261 | key: "5", 262 | name: "Focus 5th editor group", 263 | icon: "files", 264 | command: "workbench.action.focusFifthEditorGroup", 265 | }, 266 | { 267 | key: "6", 268 | name: "Focus 6th editor group", 269 | icon: "files", 270 | command: "workbench.action.focusSixthEditorGroup", 271 | }, 272 | { 273 | key: "7", 274 | name: "Focus 7th editor group", 275 | icon: "files", 276 | command: "workbench.action.focusSeventhEditorGroup", 277 | }, 278 | { 279 | key: "8", 280 | name: "Focus 8th editor group", 281 | icon: "files", 282 | command: "workbench.action.focusEighthEditorGroup", 283 | }, 284 | ]; 285 | 286 | const menu: UserMenu = { 287 | items: [...firstKeys, ...githubCopilotKeys, ...secondKeys], 288 | }; 289 | 290 | return menu; 291 | } 292 | 293 | function selectExpand(): UserMenu { 294 | return { 295 | transient: true, 296 | items: [ 297 | { 298 | key: "v", 299 | icon: "add", 300 | name: "Grow selection", 301 | command: "editor.action.smartSelect.grow", 302 | }, 303 | { 304 | key: "V", 305 | icon: "remove", 306 | name: "Shrink selection", 307 | command: "editor.action.smartSelect.shrink", 308 | }, 309 | ], 310 | }; 311 | } 312 | 313 | function diffKeys(): UserMenu { 314 | return { 315 | items: [ 316 | { 317 | key: "c", 318 | name: "Compare active file with clipboard", 319 | icon: "clippy", 320 | command: "workbench.files.action.compareWithClipboard", 321 | }, 322 | { 323 | key: "d", 324 | name: "Compare active file with", 325 | icon: "diff", 326 | command: "workbench.files.action.compareFileWith", 327 | }, 328 | { 329 | key: "s", 330 | name: "Compare active file with saved", 331 | icon: "save-as", 332 | command: "workbench.files.action.compareWithSaved", 333 | }, 334 | { 335 | key: "w", 336 | name: "Toggle ignore trim whitespace", 337 | icon: "whitespace", 338 | command: "toggle.diff.ignoreTrimWhitespace", 339 | }, 340 | ], 341 | }; 342 | } 343 | 344 | function insertKeys(): UserMenu { 345 | return { 346 | items: [ 347 | { 348 | key: "j", 349 | name: "Insert line below", 350 | icon: "arrow-down", 351 | command: "editor.action.insertLineAfter", 352 | }, 353 | { 354 | key: "k", 355 | name: "Insert line above", 356 | icon: "arrow-up", 357 | command: "editor.action.insertLineBefore", 358 | }, 359 | { 360 | key: "p", 361 | name: "Paste as", 362 | icon: "files", 363 | command: "editor.action.pasteAs", 364 | }, 365 | { 366 | key: "s", 367 | name: "Insert snippet", 368 | icon: "symbol-snippet", 369 | command: "editor.action.insertSnippet", 370 | }, 371 | ], 372 | }; 373 | } 374 | 375 | function tests(): UserMenu { 376 | return { 377 | items: [ 378 | { 379 | key: "a", 380 | name: "Run all tests", 381 | icon: "beaker", 382 | command: "testing.runAll", 383 | }, 384 | { 385 | key: "A", 386 | name: "Debug all tests", 387 | icon: "bug", 388 | command: "testing.debugAll", 389 | }, 390 | { 391 | key: "f", 392 | name: "Run current test file", 393 | icon: "file", 394 | command: "testing.runCurrentFile", 395 | }, 396 | { 397 | key: "r", 398 | name: "Re-run failed tests", 399 | icon: "close", 400 | command: "testing.reRunFailTests", 401 | }, 402 | { 403 | key: "t", 404 | name: "Select and run test", 405 | icon: "list-unordered", 406 | command: "testing.runSelected", 407 | }, 408 | { 409 | key: "T", 410 | name: "Select and debug test", 411 | icon: "debug-alt", 412 | command: "testing.debugSelected", 413 | }, 414 | ], 415 | }; 416 | } 417 | 418 | function show(): UserMenu { 419 | return { 420 | items: [ 421 | { 422 | key: "d", 423 | name: "Show debug console", 424 | icon: "debug-console", 425 | command: "workbench.debug.action.toggleRepl", 426 | }, 427 | { 428 | key: "e", 429 | name: "Show explorer", 430 | icon: "list-tree", 431 | command: "workbench.view.explorer", 432 | 433 | // { 434 | // key: "when:sideBarVisible && explorerViewletVisible", 435 | // icon: "three-bars", 436 | // name: "Hide side bar", 437 | // command: "workbench.action.toggleSidebarVisibility", 438 | // }, 439 | }, 440 | { 441 | key: "E", 442 | name: "Show extensions", 443 | icon: "extensions", 444 | command: "workbench.view.extensions", 445 | }, 446 | { 447 | key: "g", 448 | name: "Show source control", 449 | icon: "source-control", 450 | command: "workbench.view.scm", 451 | }, 452 | { 453 | key: "n", 454 | name: "Show notification", 455 | icon: "comment", 456 | command: "notifications.toggleList", 457 | }, 458 | { 459 | key: "o", 460 | name: "Show output", 461 | icon: "output", 462 | command: "workbench.action.output.toggleOutput", 463 | }, 464 | { 465 | ...showProblems, 466 | key: "p", 467 | }, 468 | { 469 | key: "r", 470 | name: "Show remote explorer", 471 | icon: "remote-explorer", 472 | command: "workbench.view.remote", 473 | }, 474 | { 475 | key: "s", 476 | name: "Show search", 477 | icon: "search", 478 | command: "workbench.view.search", 479 | }, 480 | { 481 | key: "t", 482 | name: "Show test", 483 | icon: "beaker", 484 | command: "workbench.view.extension.test", 485 | }, 486 | ], 487 | }; 488 | } 489 | -------------------------------------------------------------------------------- /src/keys/editor.ts: -------------------------------------------------------------------------------- 1 | import { type UserKeyBase, type UserMenu } from "../keys"; 2 | 3 | export function editorKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "c", 8 | name: "Close active editor", 9 | icon: "x", 10 | command: "workbench.action.closeActiveEditor", 11 | }, 12 | { 13 | key: "C", 14 | name: "Close other editors", 15 | icon: "close-all", 16 | command: "workbench.action.closeOtherEditors", 17 | }, 18 | { 19 | key: "e", 20 | name: "Show all editors", 21 | icon: "files", 22 | command: "workbench.action.showAllEditorsByMostRecentlyUsed", 23 | }, 24 | { 25 | key: "E", 26 | name: "Show all editors in active group", 27 | icon: "files", 28 | command: "workbench.action.showEditorsInActiveGroup", 29 | }, 30 | { 31 | ...prevEditor, 32 | key: "h", 33 | }, 34 | { 35 | key: "H", 36 | name: "Move editor into left group", 37 | icon: "triangle-left", 38 | command: "workbench.action.moveEditorToLeftGroup", 39 | }, 40 | { 41 | ...nextEditor, 42 | key: "j", 43 | }, 44 | { 45 | key: "J", 46 | name: "Move editor into below group", 47 | icon: "triangle-down", 48 | command: "workbench.action.moveEditorToBelowGroup", 49 | }, 50 | { 51 | ...prevEditor, 52 | key: "k", 53 | }, 54 | { 55 | key: "K", 56 | name: "Move editor into above group", 57 | icon: "triangle-up", 58 | command: "workbench.action.moveEditorToAboveGroup", 59 | }, 60 | { 61 | ...nextEditor, 62 | key: "l", 63 | }, 64 | { 65 | key: "L", 66 | name: "Move editor into right group", 67 | icon: "triangle-right", 68 | command: "workbench.action.moveEditorToRightGroup", 69 | }, 70 | { 71 | key: "n", 72 | name: "New Untitled Editor", 73 | icon: "file-add", 74 | command: "workbench.action.files.newUntitledFile", 75 | }, 76 | { 77 | key: "N", 78 | name: "New Editor in other Group", 79 | icon: "file-add", 80 | menu: newEditor, 81 | }, 82 | { 83 | key: "p", 84 | name: "Pin editor", 85 | icon: "pin", 86 | command: "workbench.action.pinEditor", 87 | }, 88 | { 89 | key: "P", 90 | name: "Unpin editor", 91 | icon: "pinned", 92 | command: "workbench.action.unpinEditor", 93 | }, 94 | { 95 | key: "r", 96 | name: "Revert the current editor", 97 | icon: "discard", 98 | command: "workbench.action.files.revert", 99 | }, 100 | { 101 | key: "s", 102 | name: "Scratch editor", 103 | icon: "note", 104 | command: "workbench.action.files.newUntitledFile", 105 | }, 106 | { 107 | key: "T", 108 | name: "Reopen closed editor", 109 | icon: "history", 110 | command: "workbench.action.reopenClosedEditor", 111 | }, 112 | { 113 | key: "0", 114 | name: "First editor in group", 115 | icon: "arrow-both", 116 | command: "workbench.action.firstEditorInGroup", 117 | }, 118 | { 119 | key: "1", 120 | name: "First editor in group", 121 | icon: "arrow-both", 122 | command: "workbench.action.openEditorAtIndex1", 123 | }, 124 | { 125 | key: "2", 126 | name: "2nd editor in group", 127 | icon: "arrow-both", 128 | command: "workbench.action.openEditorAtIndex2", 129 | }, 130 | { 131 | key: "3", 132 | name: "3rd editor in group", 133 | icon: "arrow-both", 134 | command: "workbench.action.openEditorAtIndex3", 135 | }, 136 | { 137 | key: "4", 138 | name: "4th editor in group", 139 | icon: "arrow-both", 140 | command: "workbench.action.openEditorAtIndex4", 141 | }, 142 | { 143 | key: "5", 144 | name: "5th editor in group", 145 | icon: "arrow-both", 146 | command: "workbench.action.openEditorAtIndex5", 147 | }, 148 | { 149 | key: "6", 150 | name: "6th editor in group", 151 | icon: "arrow-both", 152 | command: "workbench.action.openEditorAtIndex6", 153 | }, 154 | { 155 | key: "7", 156 | name: "7th editor in group", 157 | icon: "arrow-both", 158 | command: "workbench.action.openEditorAtIndex7", 159 | }, 160 | { 161 | key: "8", 162 | name: "8th editor in group", 163 | icon: "arrow-both", 164 | command: "workbench.action.openEditorAtIndex8", 165 | }, 166 | { 167 | key: "9", 168 | name: "9th editor in group", 169 | icon: "arrow-both", 170 | command: "workbench.action.openEditorAtIndex9", 171 | }, 172 | { 173 | key: "$", 174 | name: "Last editor in group", 175 | icon: "arrow-both", 176 | command: "workbench.action.lastEditorInGroup", 177 | }, 178 | ], 179 | }; 180 | } 181 | 182 | const newEditor: UserMenu = { 183 | items: [ 184 | { 185 | key: "h", 186 | name: "New untitled editor (split left)", 187 | icon: "arrow-small-left", 188 | commands: [ 189 | "workbench.action.splitEditorLeft", 190 | "workbench.action.files.newUntitledFile", 191 | "workbench.action.closeOtherEditors", 192 | ], 193 | }, 194 | { 195 | key: "j", 196 | name: "New untitled editor (split down)", 197 | icon: "arrow-small-down", 198 | commands: [ 199 | "workbench.action.splitEditorDown", 200 | "workbench.action.files.newUntitledFile", 201 | "workbench.action.closeOtherEditors", 202 | ], 203 | }, 204 | { 205 | key: "k", 206 | name: "New untitled editor (split up)", 207 | icon: "arrow-small-up", 208 | commands: [ 209 | "workbench.action.splitEditorUp", 210 | "workbench.action.files.newUntitledFile", 211 | "workbench.action.closeOtherEditors", 212 | ], 213 | }, 214 | { 215 | key: "l", 216 | name: "New untitled editor (split right)", 217 | icon: "arrow-small-right", 218 | commands: [ 219 | "workbench.action.splitEditorRight", 220 | "workbench.action.files.newUntitledFile", 221 | "workbench.action.closeOtherEditors", 222 | ], 223 | }, 224 | ], 225 | }; 226 | 227 | const prevEditor: UserKeyBase = { 228 | name: "Previous editor", 229 | icon: "arrow-left", 230 | command: "workbench.action.previousEditor", 231 | }; 232 | 233 | const nextEditor: UserKeyBase = { 234 | name: "Next editor", 235 | icon: "arrow-right", 236 | command: "workbench.action.nextEditor", 237 | }; 238 | -------------------------------------------------------------------------------- /src/keys/errors.ts: -------------------------------------------------------------------------------- 1 | import { showProblems } from "./common"; 2 | import { type UserMenu } from "../keys"; 3 | 4 | export function errorKeys(): UserMenu { 5 | return { 6 | items: [ 7 | { 8 | key: "e", 9 | name: "Show error", 10 | icon: "error", 11 | command: "editor.action.showHover", 12 | }, 13 | { 14 | ...showProblems, 15 | key: "E", 16 | name: "Show all errors", 17 | icon: "list-flat", 18 | }, 19 | { 20 | key: "f", 21 | name: "Fix error", 22 | icon: "lightbulb-autofix", 23 | command: "editor.action.quickFix", 24 | }, 25 | { 26 | key: "n", 27 | name: "Next error", 28 | icon: "arrow-down", 29 | command: "editor.action.marker.nextInFiles", 30 | }, 31 | { 32 | key: "N", 33 | name: "Previous error", 34 | icon: "arrow-up", 35 | command: "editor.action.marker.prevInFiles", 36 | }, 37 | { 38 | key: "p", 39 | name: "Previous error", 40 | icon: "arrow-up", 41 | command: "editor.action.marker.prevInFiles", 42 | }, 43 | { 44 | key: "t", 45 | name: "Error transient", 46 | icon: "window", 47 | menu: errorTransient(), 48 | }, 49 | ], 50 | }; 51 | } 52 | 53 | function errorTransient(): UserMenu { 54 | return { 55 | transient: true, 56 | items: [ 57 | { 58 | key: "f", 59 | name: "Fix error", 60 | icon: "lightbulb-autofix", 61 | command: "editor.action.quickFix", 62 | }, 63 | { 64 | key: "n", 65 | name: "Next error", 66 | icon: "arrow-down", 67 | command: "editor.action.marker.nextInFiles", 68 | }, 69 | { 70 | key: "p", 71 | name: "Previous error", 72 | icon: "arrow-up", 73 | command: "editor.action.marker.prevInFiles", 74 | }, 75 | { 76 | key: "N", 77 | name: "Previous error", 78 | icon: "arrow-up", 79 | command: "editor.action.marker.prevInFiles", 80 | }, 81 | ], 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /src/keys/files.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function filesKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "d", 8 | name: "Delete current file", 9 | icon: "trash", 10 | commands: ["workbench.files.action.showActiveFileInExplorer", "deleteFile"], 11 | }, 12 | { 13 | key: "e", 14 | name: "Show file in explorer", 15 | icon: "list-tree", 16 | command: "workbench.files.action.showActiveFileInExplorer", 17 | }, 18 | { 19 | key: "f", 20 | name: "Find file", 21 | icon: "file", 22 | command: "workbench.action.quickOpen", 23 | }, 24 | { 25 | key: "l", 26 | name: "Change file language", 27 | icon: "code", 28 | command: "workbench.action.editor.changeLanguageMode", 29 | }, 30 | { 31 | key: "n", 32 | name: "New file", 33 | icon: "new-file", 34 | command: "explorer.newFile", 35 | }, 36 | { 37 | key: "o", 38 | name: "Open with", 39 | icon: "file-code", 40 | command: "explorer.openWith", 41 | }, 42 | { 43 | key: "O", 44 | name: "Open in OS", 45 | icon: "file-symlink-directory", 46 | command: "revealFileInOS", 47 | }, 48 | { 49 | key: "p", 50 | name: "Copy Path of Active File", 51 | icon: "edit", 52 | command: "copyFilePath", 53 | }, 54 | { 55 | key: "P", 56 | name: "Copy Relative Path of Active File", 57 | icon: "edit", 58 | command: "copyRelativeFilePath", 59 | }, 60 | { 61 | key: "r", 62 | name: "Rename file", 63 | icon: "edit", 64 | commands: ["revealInExplorer", "renameFile"], 65 | }, 66 | { 67 | key: "s", 68 | name: "Save file", 69 | icon: "save", 70 | command: "workbench.action.files.save", 71 | }, 72 | { 73 | key: "S", 74 | name: "Save all files", 75 | icon: "save-all", 76 | command: "workbench.action.files.saveAll", 77 | }, 78 | { 79 | key: "w", 80 | name: "Open file in new window", 81 | icon: "window", 82 | command: "workbench.action.files.showOpenedFileInNewWindow", 83 | }, 84 | ], 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /src/keys/format.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function formatKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "c", 8 | name: "Format changes", 9 | icon: "diff", 10 | command: "editor.action.formatChanges", 11 | }, 12 | { 13 | key: "e", 14 | name: "Format Editor", 15 | icon: "file", 16 | command: "editor.action.formatDocument", 17 | }, 18 | { 19 | key: "E", 20 | name: "Format editor with formatter", 21 | icon: "file", 22 | command: "editor.action.formatDocument.multiple", 23 | }, 24 | { 25 | key: "f", 26 | name: "Format region or editor", 27 | icon: "list-flat", 28 | command: "editor.action.format", 29 | }, 30 | { 31 | key: "s", 32 | name: "Format selection", 33 | icon: "selection", 34 | command: "editor.action.formatSelection", 35 | }, 36 | { 37 | key: "S", 38 | name: "Format selection with formatter", 39 | icon: "selection", 40 | command: "editor.action.formatSelection.multiple", 41 | }, 42 | ], 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/keys/gh_copilot.ts: -------------------------------------------------------------------------------- 1 | /// I can't simply import vscode because when building the keybindings.md file, vscode is not available. 2 | let vscode: { extensions: { all: [{ id: string }] } } | null; 3 | try { 4 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 5 | vscode = require("vscode"); 6 | } catch (error) { 7 | // we are building the docs 8 | vscode = null; 9 | } 10 | import { type UserMenu } from "../keys"; 11 | 12 | function isGhCopilotPresent(): boolean { 13 | if (vscode) { 14 | const extensions = vscode.extensions.all; 15 | for (const ext of extensions) { 16 | if (ext.id === "GitHub.copilot-chat") { 17 | return true; 18 | } 19 | } 20 | } else { 21 | // If vscode is not available, it means we are building the keybindings.md file for the docs. 22 | return true; 23 | } 24 | return false; 25 | } 26 | /** 27 | * Returns an object containing the key bindings for GitHub Copilot. 28 | */ 29 | export function ghCopilotKeys(): UserMenu | null { 30 | if (!isGhCopilotPresent()) { 31 | return null; 32 | } 33 | return { 34 | items: [ 35 | { 36 | key: "c", 37 | name: "Copilot Chat", 38 | icon: "comment", 39 | command: "workbench.panel.chatSidebar.copilot", 40 | }, 41 | { 42 | key: "e", 43 | name: "Explain this", 44 | icon: "info", 45 | command: "github.copilot.interactiveEditor.explain", 46 | }, 47 | { 48 | key: "f", 49 | name: "Fix this", 50 | icon: "lightbulb", 51 | command: "github.copilot.interactiveEditor.fix", 52 | }, 53 | { 54 | key: "g", 55 | name: "Generate", 56 | icon: "beaker", 57 | menu: generate, 58 | }, 59 | { 60 | key: "o", 61 | name: "Open Completions Panel", 62 | icon: "octoface", 63 | command: "github.copilot.generate", 64 | }, 65 | { 66 | key: "t", 67 | name: "Toggle (Enable/Disable) Copilot", 68 | icon: "circle-slash", 69 | command: "github.copilot.toggleCopilot", 70 | }, 71 | ], 72 | }; 73 | } 74 | 75 | const generate: UserMenu = { 76 | items: [ 77 | { 78 | key: "d", 79 | name: "Generate Docs", 80 | icon: "book", 81 | command: "github.copilot.interactiveEditor.generateDocs", 82 | }, 83 | { 84 | key: "g", 85 | name: "Generate This", 86 | icon: "beaker", 87 | command: "github.copilot.interactiveEditor.generate", 88 | }, 89 | { 90 | key: "t", 91 | name: "Generate Tests", 92 | icon: "circuit-board", 93 | command: "github.copilot.interactiveEditor.generateTests", 94 | }, 95 | ], 96 | }; 97 | -------------------------------------------------------------------------------- /src/keys/git.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function gitKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "a", 8 | icon: "file-add", 9 | name: "Stage Changes", 10 | command: "git.stageSelectedRanges", 11 | }, 12 | { 13 | key: "A", 14 | icon: "file-add", 15 | name: "Stage Selected Ranges", 16 | command: "git.stageSelectedRanges", 17 | }, 18 | { 19 | key: "b", 20 | name: "Checkout", 21 | icon: "repo", 22 | command: "git.checkout", 23 | }, 24 | { 25 | key: "c", 26 | name: "Commit", 27 | icon: "check", 28 | command: "git.commit", 29 | }, 30 | { 31 | key: "C", 32 | name: "Clone", 33 | icon: "repo-clone", 34 | command: "git.clone", 35 | }, 36 | { 37 | key: "d", 38 | name: "Delete", 39 | icon: "close", 40 | menu: gitDelete(), 41 | }, 42 | { 43 | key: "f", 44 | name: "Fetch", 45 | icon: "refresh", 46 | command: "git.fetch", 47 | }, 48 | { 49 | key: "F", 50 | name: "Pull", 51 | icon: "repo-pull", 52 | command: "git.pull", 53 | }, 54 | { 55 | key: "i", 56 | name: "Initialize repository", 57 | icon: "repo-create", 58 | command: "git.init", 59 | }, 60 | { 61 | key: "l", 62 | name: "Show log/timeline", 63 | icon: "history", 64 | command: "timeline.focus", 65 | }, 66 | { 67 | key: "m", 68 | name: "Merge", 69 | icon: "git-merge", 70 | command: "git.merge", 71 | }, 72 | { 73 | key: "M", 74 | name: "Merge conflict", 75 | icon: "git-merge", 76 | menu: mergeConflict(), 77 | }, 78 | { 79 | key: "p", 80 | name: "Publish", 81 | icon: "repo-push", 82 | command: "git.publish", 83 | }, 84 | { 85 | key: "P", 86 | name: "Push", 87 | icon: "repo-push", 88 | command: "git.push", 89 | }, 90 | { 91 | key: "s", 92 | icon: "preview", 93 | name: "Status", 94 | command: "workbench.view.scm", 95 | }, 96 | { 97 | key: "u", 98 | name: "Unstage", 99 | icon: "file", 100 | command: "git.unstage", 101 | }, 102 | { 103 | key: "U", 104 | name: "Unstage Selected Ranges", 105 | icon: "file", 106 | command: "git.unstageSelectedRanges", 107 | }, 108 | ], 109 | }; 110 | } 111 | 112 | function mergeConflict(): UserMenu { 113 | return { 114 | items: [ 115 | { 116 | key: "b", 117 | name: "Accept both", 118 | icon: "arrow-both", 119 | command: "merge-conflict.accept.both", 120 | }, 121 | { 122 | key: "B", 123 | name: "Accept all both", 124 | icon: "arrow-both", 125 | command: "merge-conflict.accept.all-both", 126 | }, 127 | { 128 | key: "c", 129 | name: "Accept current", 130 | icon: "arrow-small-right", 131 | command: "merge-conflict.accept.current", 132 | }, 133 | { 134 | key: "C", 135 | name: "Accept all current", 136 | icon: "arrow-right", 137 | command: "merge-conflict.accept.all-current", 138 | }, 139 | { 140 | key: "d", 141 | name: "Compare current conflict", 142 | icon: "diff", 143 | command: "merge-conflict.compare", 144 | }, 145 | { 146 | key: "i", 147 | name: "Accept incoming", 148 | icon: "arrow-small-left", 149 | command: "merge-conflict.accept.incoming", 150 | }, 151 | { 152 | key: "I", 153 | name: "Accept all incoming", 154 | icon: "arrow-left", 155 | command: "merge-conflict.accept.all-incoming", 156 | }, 157 | { 158 | key: "n", 159 | name: "Next Conflict", 160 | icon: "arrow-down", 161 | command: "merge-conflict.next", 162 | }, 163 | { 164 | key: "N", 165 | name: "Previous Conflict", 166 | icon: "arrow-up", 167 | command: "merge-conflict.previous", 168 | }, 169 | { 170 | key: "s", 171 | name: "Accept selection", 172 | icon: "selection", 173 | command: "merge-conflict.accept.selection", 174 | }, 175 | ], 176 | }; 177 | } 178 | 179 | function gitDelete(): UserMenu { 180 | return { 181 | items: [ 182 | { 183 | key: "b", 184 | name: "Delete Branch", 185 | icon: "repo", 186 | command: "git.deleteBranch", 187 | }, 188 | { 189 | key: "t", 190 | name: "Delete Tag", 191 | icon: "tag", 192 | command: "git.deleteTag", 193 | }, 194 | { 195 | key: "T", 196 | name: "Delete Remote Tag", 197 | icon: "repo-forked", 198 | command: "git.deleteRemoteTag", 199 | }, 200 | ], 201 | }; 202 | } 203 | -------------------------------------------------------------------------------- /src/keys/go_to.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function goToKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "b", 8 | name: "Go to breadcrumb", 9 | icon: "variable", 10 | command: "breadcrumbs.focusAndSelect", 11 | }, 12 | { 13 | key: "c", 14 | name: "Go to previous change", 15 | icon: "arrow-up", 16 | command: "workbench.action.editor.previousChange", 17 | }, 18 | { 19 | key: "C", 20 | name: "Go to next change", 21 | icon: "arrow-down", 22 | command: "workbench.action.editor.nextChange", 23 | }, 24 | { 25 | key: "d", 26 | name: "Go to declaration", 27 | icon: "symbol-struct", 28 | command: "editor.action.revealDeclaration", 29 | }, 30 | { 31 | key: "j", 32 | name: "Go to definition", 33 | icon: "symbol-function", 34 | command: "editor.action.revealDefinition", 35 | }, 36 | { 37 | key: "h", 38 | name: "Show call hierarchy", 39 | icon: "type-hierarchy", 40 | command: "references-view.showCallHierarchy", 41 | }, 42 | { 43 | key: "i", 44 | name: "Go to implementations", 45 | icon: "symbol-module", 46 | command: "editor.action.goToImplementation", 47 | }, 48 | { 49 | key: "I", 50 | name: "Find implementations", 51 | icon: "symbol-module", 52 | command: "references-view.findImplementations", 53 | }, 54 | { 55 | key: "r", 56 | name: "Go to reference", 57 | icon: "symbol-reference", 58 | command: "editor.action.goToReferences", 59 | }, 60 | { 61 | key: "R", 62 | name: "Find references", 63 | icon: "symbol-reference", 64 | command: "references-view.findReferences", 65 | }, 66 | { 67 | key: "s", 68 | name: "Go to symbol in editor", 69 | icon: "symbol-class", 70 | command: "workbench.action.gotoSymbol", 71 | }, 72 | { 73 | key: "S", 74 | name: "Go to symbol in files", 75 | icon: "symbol-class", 76 | command: "workbench.action.showAllSymbols", 77 | }, 78 | { 79 | key: "t", 80 | name: "Go to type definition", 81 | icon: "symbol-struct", 82 | command: "editor.action.goToTypeDefinition", 83 | }, 84 | ], 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /src/keys/help.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function helpKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "d", 8 | name: "Open VSCode Documentation", 9 | icon: "book", 10 | command: "workbench.action.openDocumentationUrl", 11 | }, 12 | { 13 | key: "g", 14 | name: "Open Glimpse Documentation", 15 | icon: "star", 16 | command: "glimpse.openDocs", 17 | }, 18 | { 19 | key: "h", 20 | name: "Describe thing at point", 21 | icon: "book", 22 | command: "editor.action.showHover", 23 | }, 24 | { 25 | key: "i", 26 | name: "Report VSCode Issue", 27 | icon: "issues", 28 | command: "workbench.action.openIssueReporter", 29 | }, 30 | { 31 | key: "k", 32 | name: "Open global key bindings", 33 | icon: "keyboard", 34 | command: "workbench.action.openGlobalKeybindings", 35 | }, 36 | { 37 | key: "t", 38 | name: "Open VSCode Tutorial", 39 | icon: "lightbulb", 40 | command: "workbench.action.showInteractivePlayground", 41 | }, 42 | ], 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/keys/indent.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function indentKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "d", 8 | name: "Detect indentation", 9 | icon: "whitespace", 10 | command: "editor.action.detectIndentation", 11 | }, 12 | { 13 | key: "i", 14 | name: "Change indentation", 15 | icon: "edit", 16 | command: "changeEditorIndentation", 17 | }, 18 | { 19 | key: "r", 20 | name: "Reindent", 21 | icon: "list-flat", 22 | command: "editor.action.reindentlines", 23 | }, 24 | { 25 | key: "R", 26 | name: "Reindent selected", 27 | icon: "selection", 28 | command: "editor.action.reindentselectedlines", 29 | }, 30 | { 31 | key: "s", 32 | name: "Convert indentation to spaces", 33 | icon: "arrow-small-right", 34 | command: "editor.action.indentationToSpaces", 35 | }, 36 | { 37 | key: "t", 38 | name: "Convert indentation to tabs", 39 | icon: "export", 40 | command: "editor.action.indentationToTabs", 41 | }, 42 | ], 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/keys/peek.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function peekKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "d", 8 | name: "Peek declaration", 9 | icon: "symbol-struct", 10 | command: "editor.action.peekDeclaration", 11 | }, 12 | { 13 | key: "h", 14 | name: "Peek call hierarchy", 15 | icon: "type-hierarchy", 16 | command: "editor.showCallHierarchy", 17 | }, 18 | { 19 | key: "i", 20 | name: "Peek implementations", 21 | icon: "symbol-module", 22 | command: "editor.action.peekImplementation", 23 | }, 24 | { 25 | key: "p", 26 | name: "Peek definition", 27 | icon: "symbol-function", 28 | command: "editor.action.peekDefinition", 29 | }, 30 | { 31 | key: "r", 32 | name: "Peek references", 33 | icon: "symbol-reference", 34 | command: "editor.action.referenceSearch.trigger", 35 | }, 36 | { 37 | key: "R", 38 | name: "Search all references in side bar", 39 | icon: "references", 40 | command: "references-view.find", 41 | }, 42 | { 43 | key: "t", 44 | name: "Peek type definition", 45 | icon: "symbol-struct", 46 | command: "editor.action.peekTypeDefinition", 47 | }, 48 | ], 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /src/keys/quit.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function quitKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "f", 8 | name: "Open recent folder", 9 | icon: "folder", 10 | command: "workbench.action.openRecent", 11 | }, 12 | { 13 | key: "q", 14 | name: "Quit VSCode window", 15 | icon: "close", 16 | command: "workbench.action.closeWindow", 17 | }, 18 | { 19 | key: "Q", 20 | name: "Quit all VSCode windows", 21 | icon: "log-out", 22 | command: "workbench.action.quit", 23 | }, 24 | { 25 | key: "r", 26 | name: "Reload window", 27 | icon: "refresh", 28 | command: "workbench.action.reloadWindow", 29 | }, 30 | { 31 | key: "R", 32 | name: "Reload window with extensions disabled", 33 | icon: "refresh", 34 | command: "workbench.action.reloadWindowWithExtensionsDisabled", 35 | }, 36 | { 37 | key: "s", 38 | name: "Save all and close window", 39 | icon: "save-all", 40 | commands: ["workbench.action.files.saveAll", "workbench.action.closeWindow"], 41 | }, 42 | { 43 | key: "w", 44 | name: "Close workspace", 45 | icon: "close-all", 46 | command: "workbench.action.closeFolder", 47 | }, 48 | ], 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /src/keys/refactor.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function refactorKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: ".", 8 | name: "Quick fix", 9 | icon: "lightbulb-autofix", 10 | command: "editor.action.quickFix", 11 | }, 12 | { 13 | key: "e", 14 | name: "Extract to function or variable", 15 | icon: "gather", 16 | command: { 17 | id: "editor.action.codeAction", 18 | args: { 19 | kind: "refactor.extract", 20 | }, 21 | }, 22 | }, 23 | { 24 | key: "i", 25 | name: "Organize imports", 26 | icon: "edit", 27 | command: "editor.action.organizeImports", 28 | }, 29 | { 30 | key: "r", 31 | name: "Rename Symbol", 32 | icon: "symbol-keyword", 33 | command: "editor.action.rename", 34 | }, 35 | { 36 | key: "R", 37 | name: "Refactor actions", 38 | icon: "edit", 39 | command: "editor.action.refactor", 40 | }, 41 | { 42 | key: "s", 43 | name: "Execute source action", 44 | icon: "lightbulb", 45 | command: "editor.action.sourceAction", 46 | }, 47 | ], 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/keys/search.ts: -------------------------------------------------------------------------------- 1 | import { searchSelectionInFiles } from "./common"; 2 | import { type UserMenu } from "../keys"; 3 | 4 | export function searchKeys(): UserMenu { 5 | return { 6 | items: [ 7 | { 8 | key: "c", 9 | name: "Clear Search Results", 10 | icon: "clear-all", 11 | command: "search.action.clearSearchResults", 12 | }, 13 | { 14 | key: "e", 15 | name: "Search Editor: New", 16 | icon: "search", 17 | command: "search.action.openNewEditor", 18 | }, 19 | { 20 | key: "E", 21 | name: "Search Editor: New to the Side", 22 | icon: "search", 23 | command: "search.action.openNewEditorToSide", 24 | }, 25 | { 26 | key: "h", 27 | name: "Highlight symbol", 28 | icon: "symbol-color", 29 | command: "editor.action.wordHighlight.trigger", 30 | menu: highlight(), 31 | }, 32 | { 33 | key: "q", 34 | name: "Quick search", 35 | icon: "zap", 36 | command: "workbench.action.quickTextSearch", 37 | }, 38 | { 39 | key: "s", 40 | name: "Search", 41 | icon: "search", 42 | command: "actions.find", 43 | }, 44 | { 45 | key: "S", 46 | name: "Search in files", 47 | icon: "search", 48 | command: "workbench.action.findInFiles", 49 | }, 50 | { 51 | key: "r", 52 | name: "Replace", 53 | icon: "replace", 54 | command: "editor.action.startFindReplaceAction", 55 | }, 56 | { 57 | key: "R", 58 | name: "Replace in files", 59 | icon: "replace", 60 | command: "workbench.action.replaceInFiles", 61 | }, 62 | { 63 | ...searchSelectionInFiles, 64 | key: "*", 65 | }, 66 | ], 67 | }; 68 | } 69 | 70 | function highlight(): UserMenu { 71 | return { 72 | transient: true, 73 | items: [ 74 | { 75 | key: "n", 76 | name: "Next occurrence", 77 | icon: "arrow-down", 78 | command: "editor.action.wordHighlight.next", 79 | }, 80 | { 81 | key: "p", 82 | name: "Previous occurrence", 83 | icon: "arrow-up", 84 | command: "editor.action.wordHighlight.prev", 85 | }, 86 | { 87 | key: "N", 88 | name: "Previous occurrence", 89 | icon: "arrow-up", 90 | command: "editor.action.wordHighlight.prev", 91 | }, 92 | ], 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /src/keys/tasks.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function tasksKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: ".", 8 | name: "Rerun last task", 9 | icon: "debug-rerun", 10 | command: "workbench.action.tasks.reRunTask", 11 | }, 12 | { 13 | key: ":", 14 | name: "Run task", 15 | icon: "play", 16 | command: "workbench.action.tasks.runTask", 17 | }, 18 | { 19 | key: "b", 20 | name: "Run build tasks", 21 | icon: "server-process", 22 | command: "workbench.action.tasks.build", 23 | }, 24 | { 25 | key: "c", 26 | name: "Configure task runner", 27 | icon: "gear", 28 | command: "workbench.action.tasks.configureTaskRunner", 29 | }, 30 | { 31 | key: "g", 32 | name: "Show running tasks", 33 | icon: "checklist", 34 | command: "workbench.action.tasks.showTasks", 35 | }, 36 | { 37 | key: "l", 38 | name: "Show task log", 39 | icon: "history", 40 | command: "workbench.action.tasks.showLog", 41 | }, 42 | { 43 | key: "t", 44 | name: "Run test task", 45 | icon: "beaker", 46 | command: "workbench.action.tasks.test", 47 | }, 48 | { 49 | key: "x", 50 | name: "Terminate task", 51 | icon: "trash", 52 | command: "workbench.action.tasks.terminate", 53 | }, 54 | { 55 | key: "R", 56 | name: "Restart running task", 57 | icon: "refresh", 58 | command: "workbench.action.tasks.restartTask", 59 | }, 60 | ], 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /src/keys/text.ts: -------------------------------------------------------------------------------- 1 | import { type UserKey, type UserMenu } from "../keys"; 2 | 3 | export function textKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | ...moveLinesDown(), 8 | menu: moveLines(), 9 | }, 10 | { 11 | ...moveLinesUp(), 12 | menu: moveLines(), 13 | }, 14 | { 15 | key: "l", 16 | name: "Lines", 17 | icon: "list-flat", 18 | menu: linesMenu(), 19 | }, 20 | { 21 | key: "o", 22 | name: "Open link", 23 | icon: "link-external", 24 | command: "editor.action.openLink", 25 | }, 26 | { 27 | key: "u", 28 | name: "To lower case", 29 | icon: "case-sensitive", 30 | command: "editor.action.transformToLowercase", 31 | }, 32 | { 33 | key: "U", 34 | name: "To upper case", 35 | icon: "preserve-case", 36 | command: "editor.action.transformToUppercase", 37 | }, 38 | { 39 | key: "w", 40 | name: "Delete trailing whitespace", 41 | icon: "whitespace", 42 | command: "editor.action.trimTrailingWhitespace", 43 | }, 44 | ], 45 | }; 46 | } 47 | 48 | function linesMenu(): UserMenu { 49 | return { 50 | items: [ 51 | { 52 | key: "d", 53 | name: "Duplicate lines down", 54 | icon: "fold-down", 55 | command: "editor.action.copyLinesDownAction", 56 | }, 57 | { 58 | key: "D", 59 | name: "Duplicate lines up", 60 | icon: "fold-up", 61 | command: "editor.action.copyLinesUpAction", 62 | }, 63 | { 64 | key: "s", 65 | name: "Sort lines in ascending order", 66 | icon: "chevron-left", 67 | command: "editor.action.sortLinesAscending", 68 | }, 69 | { 70 | key: "S", 71 | name: "Sort lines in descending order", 72 | icon: "chevron-right", 73 | command: "editor.action.sortLinesDescending", 74 | }, 75 | ], 76 | }; 77 | } 78 | 79 | function moveLines(): UserMenu { 80 | return { 81 | transient: true, 82 | items: [moveLinesDown(), moveLinesUp()], 83 | }; 84 | } 85 | 86 | function moveLinesDown(): UserKey { 87 | return { 88 | key: "j", 89 | name: "Move lines down", 90 | icon: "triangle-down", 91 | command: "editor.action.moveLinesDownAction", 92 | }; 93 | } 94 | 95 | function moveLinesUp(): UserKey { 96 | return { 97 | key: "k", 98 | name: "Move lines up", 99 | icon: "triangle-up", 100 | command: "editor.action.moveLinesUpAction", 101 | }; 102 | } 103 | -------------------------------------------------------------------------------- /src/keys/toggles.ts: -------------------------------------------------------------------------------- 1 | import { type UserMenu } from "../keys"; 2 | 3 | export function toggleKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | key: "b", 8 | name: "Toggle side bar visibility", 9 | icon: "split-horizontal", 10 | command: "workbench.action.toggleSidebarVisibility", 11 | }, 12 | { 13 | key: "B", 14 | name: "Toggle Activity Bar Visibility", 15 | icon: "tools", 16 | command: "workbench.action.toggleActivityBarVisibility", 17 | }, 18 | { 19 | key: "c", 20 | name: "Toggle centered layout", 21 | icon: "list-flat", 22 | command: "workbench.action.toggleCenteredLayout", 23 | }, 24 | { 25 | key: "C", 26 | name: "Toggle find case sensitive", 27 | icon: "case-sensitive", 28 | command: "toggleFindCaseSensitive", 29 | }, 30 | { 31 | key: "f", 32 | name: "Toggle full screen", 33 | icon: "screen-full", 34 | command: "workbench.action.toggleFullScreen", 35 | }, 36 | { 37 | key: "i", 38 | name: "Select icon theme", 39 | icon: "symbol-misc", 40 | command: "workbench.action.selectIconTheme", 41 | }, 42 | { 43 | key: "m", 44 | name: "Toggle minimap", 45 | icon: "symbol-ruler", 46 | command: "editor.action.toggleMinimap", 47 | }, 48 | { 49 | key: "p", 50 | name: "Toggle panel visibility", 51 | icon: "output", 52 | command: "workbench.action.togglePanel", 53 | }, 54 | { 55 | key: "P", 56 | name: "Toggle maximized panel", 57 | icon: "chevron-up", 58 | command: "workbench.action.toggleMaximizedPanel", 59 | }, 60 | { 61 | key: "t", 62 | name: "Select theme", 63 | icon: "paintcan", 64 | command: "workbench.action.selectTheme", 65 | }, 66 | { 67 | key: "T", 68 | name: "Toggle tab visibility", 69 | icon: "files", 70 | command: "workbench.action.toggleTabsVisibility", 71 | }, 72 | { 73 | key: "w", 74 | name: "Toggle word wrap", 75 | icon: "word-wrap", 76 | command: "editor.action.toggleWordWrap", 77 | }, 78 | { 79 | key: "W", 80 | name: "Toggle render whitespace", 81 | icon: "whitespace", 82 | command: "editor.action.toggleRenderWhitespace", 83 | }, 84 | { 85 | key: "z", 86 | name: "Toggle zen mode", 87 | icon: "eye", 88 | command: "workbench.action.toggleZenMode", 89 | }, 90 | ], 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /src/keys/window.ts: -------------------------------------------------------------------------------- 1 | import { type UserKey, type UserMenu } from "../keys"; 2 | 3 | export function windowKeys(): UserMenu { 4 | return { 5 | items: [ 6 | { 7 | ...enlargeGroup, 8 | menu: resizeGroup, 9 | }, 10 | { 11 | ...enlargeGroup, 12 | key: "=", 13 | menu: resizeGroup, 14 | }, 15 | { 16 | ...shrinkGroup, 17 | menu: resizeGroup, 18 | }, 19 | { 20 | key: "c", 21 | name: "Close group", 22 | icon: "close", 23 | command: "workbench.action.closeEditorsInGroup", 24 | }, 25 | { 26 | key: "C", 27 | name: "Close all other groups", 28 | icon: "close-all", 29 | command: "workbench.action.closeEditorsInOtherGroups", 30 | }, 31 | { 32 | key: "h", 33 | name: "Focus group left", 34 | icon: "arrow-left", 35 | command: "workbench.action.navigateLeft", 36 | }, 37 | { 38 | key: "H", 39 | name: "Move in group left", 40 | icon: "triangle-left", 41 | command: "workbench.action.moveActiveEditorGroupLeft", 42 | }, 43 | { 44 | key: "j", 45 | name: "Focus group down", 46 | icon: "arrow-down", 47 | command: "workbench.action.navigateDown", 48 | }, 49 | { 50 | key: "J", 51 | name: "Move in group down", 52 | icon: "triangle-down", 53 | command: "workbench.action.moveActiveEditorGroupDown", 54 | }, 55 | { 56 | key: "k", 57 | name: "Focus group up", 58 | icon: "arrow-up", 59 | command: "workbench.action.navigateUp", 60 | }, 61 | { 62 | key: "K", 63 | name: "Move in group up", 64 | icon: "triangle-up", 65 | command: "workbench.action.moveActiveEditorGroupUp", 66 | }, 67 | { 68 | key: "l", 69 | name: "Focus group right", 70 | icon: "arrow-right", 71 | command: "workbench.action.navigateRight", 72 | }, 73 | { 74 | key: "L", 75 | name: "Move in group right", 76 | icon: "triangle-right", 77 | command: "workbench.action.moveActiveEditorGroupRight", 78 | }, 79 | { 80 | key: "m", 81 | name: "Maximize editor group", 82 | icon: "chrome-maximize", 83 | command: "workbench.action.toggleEditorWidths", 84 | }, 85 | { 86 | key: "M", 87 | name: "Maximize editor group and hide others", 88 | icon: "screen-full", 89 | command: "workbench.action.toggleMaximizeEditorGroup", 90 | }, 91 | { 92 | key: "n", 93 | name: "Duplicate workspace in new window", 94 | icon: "window", 95 | command: "workbench.action.duplicateWorkspaceInNewWindow", 96 | }, 97 | { 98 | key: "N", 99 | name: "Open new VSCode window", 100 | icon: "empty-window", 101 | command: "workbench.action.newWindow", 102 | }, 103 | { 104 | key: "o", 105 | name: "Switch VSCode window", 106 | icon: "multiple-windows", 107 | command: "workbench.action.quickSwitchWindow", 108 | }, 109 | { 110 | key: "r", 111 | name: "Reset editor widths", 112 | icon: "move", 113 | command: "workbench.action.evenEditorWidths", 114 | }, 115 | { 116 | key: "s", 117 | name: "Split editor down", 118 | icon: "split-vertical", 119 | command: "workbench.action.splitEditorDown", 120 | }, 121 | { 122 | key: "v", 123 | name: "Split editor right", 124 | icon: "split-horizontal", 125 | command: "workbench.action.splitEditor", 126 | }, 127 | { 128 | key: "w", 129 | name: "Focus group right", 130 | icon: "arrow-small-down", 131 | command: "workbench.action.focusNextGroup", 132 | }, 133 | { 134 | key: "W", 135 | name: "Focus group left", 136 | icon: "arrow-small-up", 137 | command: "workbench.action.focusPreviousGroup", 138 | }, 139 | { 140 | key: "x", 141 | name: "Close all groups", 142 | icon: "close-all", 143 | command: "workbench.action.closeAllGroups", 144 | }, 145 | { 146 | key: "z", 147 | name: "Join all groups", 148 | icon: "combine", 149 | command: "workbench.action.joinAllGroups", 150 | }, 151 | { 152 | key: "1", 153 | name: "Single column window layout", 154 | icon: "editor-layout", 155 | command: "workbench.action.editorLayoutSingle", 156 | }, 157 | { 158 | key: "2", 159 | name: "Double column window layout", 160 | icon: "editor-layout", 161 | command: "workbench.action.editorLayoutTwoColumns", 162 | }, 163 | { 164 | key: "3", 165 | name: "Triple column window layout", 166 | icon: "editor-layout", 167 | command: "workbench.action.editorLayoutThreeColumns", 168 | }, 169 | { 170 | key: "4", 171 | name: "Grid window layout", 172 | icon: "editor-layout", 173 | command: "workbench.action.editorLayoutTwoByTwoGrid", 174 | }, 175 | ], 176 | }; 177 | } 178 | 179 | const shrinkGroup: UserKey = { 180 | key: "-", 181 | name: "Shrink group", 182 | icon: "remove", 183 | command: "workbench.action.decreaseViewSize", 184 | }; 185 | 186 | const enlargeGroup: UserKey = { 187 | key: "+", 188 | name: "Enlarge group", 189 | icon: "add", 190 | command: "workbench.action.increaseViewSize", 191 | }; 192 | 193 | const enlargeWithEqual: UserKey = { ...enlargeGroup, key: "=" }; 194 | 195 | const resizeGroup: UserMenu = { 196 | items: [shrinkGroup, enlargeGroup, enlargeWithEqual], 197 | transient: true, 198 | }; 199 | -------------------------------------------------------------------------------- /src/keys/zoom.ts: -------------------------------------------------------------------------------- 1 | import { type Icon } from "../icons"; 2 | import { type UserMenu } from "../keys"; 3 | 4 | export function zoomKeys(): UserMenu { 5 | return { 6 | items: [ 7 | { 8 | ...zoomIn, 9 | key: "+", 10 | menu: zoomTransient, 11 | }, 12 | { 13 | ...zoomIn, 14 | key: "=", 15 | menu: zoomTransient, 16 | }, 17 | { 18 | ...zoomOut, 19 | key: "-", 20 | menu: zoomTransient, 21 | }, 22 | { 23 | key: "0", 24 | name: "Reset zoom", 25 | icon: "search", 26 | command: "workbench.action.zoomReset", 27 | }, 28 | { 29 | key: "i", 30 | name: "Image preview", 31 | icon: "eye", 32 | menu: { 33 | transient: true, 34 | items: [ 35 | { 36 | key: "+", 37 | name: "Zoom in", 38 | icon: "zoom-in", 39 | command: "imagePreview.zoomIn", 40 | }, 41 | { 42 | key: "-", 43 | name: "Zoom out", 44 | icon: "zoom-out", 45 | command: "imagePreview.zoomOut", 46 | }, 47 | { 48 | key: "=", 49 | name: "Zoom in", 50 | icon: "zoom-in", 51 | command: "imagePreview.zoomIn", 52 | }, 53 | ], 54 | }, 55 | }, 56 | { 57 | key: "f", 58 | name: "Font", 59 | icon: "case-sensitive", 60 | menu: { 61 | transient: true, 62 | items: [ 63 | { 64 | ...fontZoomIn, 65 | key: "+", 66 | }, 67 | { 68 | ...fontZoomIn, 69 | key: "=", 70 | }, 71 | { 72 | key: "-", 73 | name: "Zoom out", 74 | icon: "zoom-out", 75 | command: "editor.action.fontZoomOut", 76 | }, 77 | { 78 | key: "0", 79 | name: "Reset zoom", 80 | icon: "search", 81 | command: "editor.action.fontZoomReset", 82 | }, 83 | ], 84 | }, 85 | }, 86 | { 87 | key: "F", 88 | name: "Fold", 89 | icon: "fold", 90 | menu: { 91 | items: [ 92 | { 93 | key: "a", 94 | name: "Toggle: around a point", 95 | icon: "selection", 96 | command: "editor.toggleFold", 97 | }, 98 | { 99 | key: "b", 100 | name: "Close: all block comments", 101 | icon: "fold", 102 | command: "editor.foldAllBlockComments", 103 | }, 104 | { 105 | key: "c", 106 | name: "Close: at a point", 107 | icon: "fold", 108 | command: "editor.fold", 109 | }, 110 | { 111 | key: "g", 112 | name: "Close: all regions", 113 | icon: "fold", 114 | command: "editor.foldAllMarkerRegions", 115 | }, 116 | { 117 | key: "G", 118 | name: "Open: all regions", 119 | icon: "unfold", 120 | command: "editor.unfoldAllMarkerRegions", 121 | }, 122 | { 123 | key: "m", 124 | name: "Close: all", 125 | icon: "fold", 126 | command: "editor.foldAll", 127 | }, 128 | { 129 | key: "o", 130 | name: "Open: at a point", 131 | icon: "unfold", 132 | command: "editor.unfold", 133 | }, 134 | { 135 | key: "O", 136 | name: "Open: recursively", 137 | icon: "unfold", 138 | command: "editor.unfoldRecursively", 139 | }, 140 | { 141 | key: "r", 142 | name: "Open: all", 143 | icon: "unfold", 144 | command: "editor.unfoldAll", 145 | }, 146 | ], 147 | }, 148 | }, 149 | ], 150 | }; 151 | } 152 | 153 | const zoomIn = { 154 | name: "Zoom In", 155 | command: "workbench.action.zoomIn", 156 | icon: "zoom-in" as Icon, 157 | }; 158 | 159 | const zoomOut = { 160 | name: "Zoom Out", 161 | command: "workbench.action.zoomOut", 162 | icon: "zoom-out" as Icon, 163 | }; 164 | 165 | const fontZoomIn = { 166 | name: "Zoom In", 167 | icon: "zoom-in" as Icon, 168 | command: "editor.action.fontZoomIn", 169 | }; 170 | 171 | const zoomTransient: UserMenu = { 172 | transient: true, 173 | items: [ 174 | { ...zoomIn, key: "+" }, 175 | { ...zoomIn, key: "=" }, 176 | { ...zoomOut, key: "-" }, 177 | ], 178 | }; 179 | -------------------------------------------------------------------------------- /src/keysToDocs.ts: -------------------------------------------------------------------------------- 1 | import { type Command, type UserMenu } from "./keys"; 2 | import { defaultMenu } from "./keys/default_menu"; 3 | import * as fs from "fs"; 4 | import { prettifyKey } from "./prettify"; 5 | 6 | function commandToString(command: Command): string { 7 | let result; 8 | if (typeof command === "string") { 9 | result = command; 10 | } else { 11 | result = command.id + ": " + JSON.stringify(command.args); 12 | } 13 | return "`" + result + "`"; 14 | } 15 | 16 | function commandsFromMenu(menu: UserMenu, prevKeys: string[]): string { 17 | let docs = ""; 18 | let headingsAdded = false; 19 | for (const i of menu.items) { 20 | if ("command" in i || "commands" in i) { 21 | if (!headingsAdded) { 22 | docs += "| Key | Name | Command |\n"; 23 | docs += "| --- | ---- | ------- |\n"; 24 | headingsAdded = true; 25 | } 26 | const cmdKeys = prevKeys.concat(i.key); 27 | docs += "| " + cmdKeys.map(prettifyKey).join(" ") + " | " + i.name + " | "; 28 | if ("command" in i) { 29 | docs += commandToString(i.command) + " |\n"; 30 | } 31 | if ("commands" in i) { 32 | docs += "\\[ " + i.commands.map(commandToString).join(", ") + " \\] |\n"; 33 | } 34 | } 35 | } 36 | 37 | return docs; 38 | } 39 | 40 | function submenuFromMenu(menu: UserMenu, hashtagNumber: number, prevKeys: string[]): string { 41 | let docs = ""; 42 | for (const i of menu.items) { 43 | let headingsAdded = false; 44 | if ("menu" in i) { 45 | if (!headingsAdded) { 46 | docs += "\n"; 47 | docs += "#".repeat(hashtagNumber); 48 | docs += " " + i.name + "\n\n"; 49 | headingsAdded = true; 50 | } 51 | const newPrevKeys = prevKeys.concat(i.key); 52 | docs += commandsFromMenu(i.menu, newPrevKeys); 53 | docs += submenuFromMenu(i.menu, hashtagNumber + 1, newPrevKeys); 54 | } 55 | } 56 | return docs; 57 | } 58 | 59 | const menu = defaultMenu(); 60 | let docs = `--- 61 | sidebar_position: 4 62 | --- 63 | 64 | # Key bindings 65 | 66 | Here are the default Glimpse key bindings. 67 | 68 | ## Top level menu 69 | 70 | `; 71 | 72 | // top level menu 73 | docs += commandsFromMenu(menu, []); 74 | docs += submenuFromMenu(menu, 2, []); 75 | 76 | fs.writeFileSync("./website/docs/keybindings.md", docs); 77 | -------------------------------------------------------------------------------- /src/logger.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | // eslint-disable-next-line @typescript-eslint/no-extraneous-class 4 | export class Logger { 5 | private static output: vscode.LogOutputChannel; 6 | 7 | public static init(): void { 8 | Logger.output = vscode.window.createOutputChannel("Glimpse", { log: true }); 9 | } 10 | 11 | public static error(msg: string): void { 12 | Logger.output.error(msg); 13 | } 14 | public static warn(msg: string): void { 15 | Logger.output.warn(msg); 16 | } 17 | public static info(msg: string): void { 18 | Logger.output.info(msg); 19 | } 20 | public static debug(msg: string): void { 21 | Logger.output.debug(msg); 22 | } 23 | public static trace(msg: string): void { 24 | Logger.output.trace(msg); 25 | } 26 | } 27 | 28 | export function notifyError(err: string) { 29 | Logger.error(err); 30 | void vscode.window.showErrorMessage(err); 31 | } 32 | -------------------------------------------------------------------------------- /src/prettify.ts: -------------------------------------------------------------------------------- 1 | export function prettifyKey(key: string): string { 2 | if (key === " ") { 3 | return "␣"; 4 | } else if (key === "\t") { 5 | return "↹"; 6 | } else { 7 | return key; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/utf8ToStr.ts: -------------------------------------------------------------------------------- 1 | // http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt 2 | 3 | /* utf.js - UTF-8 <=> UTF-16 convertion 4 | * 5 | * Copyright (C) 1999 Masanao Izumo 6 | * Version: 1.0 7 | * LastModified: Dec 25 1999 8 | * This library is free. You can redistribute it and/or modify it. 9 | */ 10 | export function utf8ArrayToStr(array: Uint8Array): string { 11 | let out, i, c; 12 | let char2, char3; 13 | 14 | out = ""; 15 | const len = array.length; 16 | i = 0; 17 | while (i < len) { 18 | c = array[i++]; 19 | switch (c >> 4) { 20 | case 0: 21 | case 1: 22 | case 2: 23 | case 3: 24 | case 4: 25 | case 5: 26 | case 6: 27 | case 7: 28 | // 0xxxxxxx 29 | out += String.fromCharCode(c); 30 | break; 31 | case 12: 32 | case 13: 33 | // 110x xxxx 10xx xxxx 34 | char2 = array[i++]; 35 | out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f)); 36 | break; 37 | case 14: 38 | // 1110 xxxx 10xx xxxx 10xx xxxx 39 | char2 = array[i++]; 40 | char3 = array[i++]; 41 | out += String.fromCharCode( 42 | ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0), 43 | ); 44 | break; 45 | } 46 | } 47 | 48 | return out; 49 | } 50 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "outDir": "out", 6 | "lib": ["ES2020"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | // enable all strict type-checking options 10 | "strict": true 11 | /* Additional Checks */ 12 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 13 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 14 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | "use strict"; 3 | 4 | //@ts-check 5 | /** @typedef {import('webpack').Configuration} WebpackConfig **/ 6 | 7 | // eslint-disable-next-line @typescript-eslint/no-var-requires 8 | const path = require("path"); 9 | // eslint-disable-next-line @typescript-eslint/no-var-requires 10 | const webpack = require("webpack"); 11 | 12 | /** @type WebpackConfig */ 13 | const webConfig = { 14 | context: __dirname, 15 | mode: "none", // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 16 | target: "webworker", // web extensions run in a webworker context 17 | entry: { 18 | "extension-web": "./src/extension.ts", // source of the web extension main file 19 | }, 20 | output: { 21 | filename: "[name].js", 22 | path: path.join(__dirname, "./dist"), 23 | libraryTarget: "commonjs", 24 | }, 25 | resolve: { 26 | mainFields: ["browser", "module", "main"], // look for `browser` entry point in imported node modules 27 | extensions: [".ts", ".js"], // support ts-files and js-files 28 | alias: { 29 | // provides alternate implementation for node module and source files 30 | }, 31 | fallback: { 32 | // Webpack 5 no longer polyfills Node.js core modules automatically. 33 | // see https://webpack.js.org/configuration/resolve/#resolvefallback 34 | // for the list of Node.js core module polyfills. 35 | assert: require.resolve("assert"), 36 | // Needed for vscode.dev to read/write the configuration file 37 | buffer: require.resolve("buffer/"), 38 | }, 39 | }, 40 | module: { 41 | rules: [ 42 | { 43 | test: /\.ts$/, 44 | exclude: /node_modules/, 45 | use: [ 46 | { 47 | loader: "ts-loader", 48 | }, 49 | ], 50 | }, 51 | ], 52 | }, 53 | plugins: [ 54 | new webpack.ProvidePlugin({ 55 | process: "process/browser", // provide a shim for the global `process` variable 56 | }), 57 | // Needed for vscode.dev to read/write the configuration file 58 | new webpack.ProvidePlugin({ 59 | // eslint-disable-next-line @typescript-eslint/naming-convention 60 | Buffer: ["buffer", "Buffer"], 61 | }), 62 | ], 63 | externals: { 64 | vscode: "commonjs vscode", // ignored because it doesn't exist 65 | }, 66 | performance: { 67 | hints: false, 68 | }, 69 | devtool: "nosources-source-map", // create a source map that points to the original source file 70 | infrastructureLogging: { 71 | level: "log", // enables logging required for problem matchers 72 | }, 73 | }; 74 | const nodeConfig = /** @type WebpackConfig */ { 75 | context: __dirname, 76 | mode: "none", // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 77 | target: "node", // extensions run in a node context 78 | entry: { 79 | "extension-node": "./src/extension.ts", // source of the node extension main file 80 | }, 81 | output: { 82 | filename: "[name].js", 83 | path: path.join(__dirname, "./dist"), 84 | libraryTarget: "commonjs", 85 | }, 86 | resolve: { 87 | mainFields: ["module", "main"], 88 | extensions: [".ts", ".js"], // support ts-files and js-files 89 | }, 90 | module: { 91 | rules: [ 92 | { 93 | test: /\.ts$/, 94 | exclude: /node_modules/, 95 | use: [ 96 | { 97 | loader: "ts-loader", 98 | }, 99 | ], 100 | }, 101 | ], 102 | }, 103 | externals: { 104 | vscode: "commonjs vscode", // ignored because it doesn't exist 105 | mocha: "commonjs mocha", // don't bundle 106 | "@vscode/test-electron": "commonjs @vscode/test-electron", // don't bundle 107 | "@vscode/test-web": "commonjs @vscode/test-web", // don't bundle 108 | }, 109 | performance: { 110 | hints: false, 111 | }, 112 | devtool: "nosources-source-map", // create a source map that points to the original source file 113 | }; 114 | 115 | module.exports = [webConfig, nodeConfig]; 116 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /website/.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Use `#` for headers 3 | MD003: 4 | style: atx 5 | 6 | # Set maximum line length 7 | MD013: 8 | line_length: 130 9 | 10 | # Use `---` for horizontal rule 11 | MD035: 12 | style: --- 13 | 14 | # Use ``` for code blocks 15 | MD046: 16 | style: fenced 17 | MD048: 18 | style: backtick 19 | # See https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md for 20 | # additional info 21 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/). 4 | 5 | ## Local Development 6 | 7 | ```sh 8 | npm i && npm start 9 | ``` 10 | 11 | This command starts a local development server and opens up a browser window. Most changes are 12 | reflected live without having to restart the server. 13 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve("@docusaurus/core/lib/babel/preset")], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docs/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # Configuration 6 | 7 | You can make Glimpse your own by configuring its key bindings. 8 | 9 | To allow maximum flexibility, Glimpse let you configure its menu by using `javascript`. 10 | 11 | To edit the default configuration file, press `Ctrl+Shift+P` to open the command palette and search 12 | for `Glimpse: Configure`. 13 | 14 | After editing the configuration file, you need to reload the window for the changes to take effect. 15 | To do so, press `Ctrl+Shift+P` to open the command palette and search for 16 | `Developer: Reload Window`, or press `q r` from Glimpse. 17 | 18 | ## Configuration examples 19 | 20 | In the following sections, there are some examples of what you can do with the configuration file. 21 | Remember that you can use any `javascript` code, so the sky is the limit! 22 | 23 | Also, take a look at the [keys](https://github.com/MarcoIeni/glimpse/tree/main/src/keys) 24 | repository directory to take inspiration from the default configuration. 25 | 26 | ### Add a key binding to the top menu 27 | 28 | ```js 29 | module.exports = function editConfig(menu) { 30 | menu.items.push({ 31 | name: "Auto Fix", 32 | key: "a", 33 | icon: "lightbulb", 34 | command: "editor.action.autoFix", 35 | }); 36 | 37 | return menu; 38 | }; 39 | ``` 40 | 41 | The `command` property should be the command ID of the command you want to run. 42 | 43 | To know all the available commands and their IDs: 44 | 45 | - Press `Ctrl+Shift+P` to open the command palette and search for `Preferences: Open Keyboard Shortcuts`. 46 | - Search for the command you are interested in. 47 | - Right-click on the command and select `Copy Command ID`. 48 | 49 | ### Add a key binding a submenu 50 | 51 | ```js 52 | module.exports = function editConfig(menu) { 53 | const errorMenu = subMenu(menu, "e"); 54 | errorMenu.items.push({ 55 | name: "Auto Fix", 56 | key: "a", 57 | icon: "lightbulb", 58 | command: "editor.action.autoFix", 59 | }); 60 | 61 | return menu; 62 | }; 63 | 64 | /** 65 | * @param { UserMenu } userMenu 66 | * @param { string } key 67 | * @returns { UserMenu } 68 | */ 69 | function subMenu(menu, key) { 70 | for (const item of menu.items) { 71 | if (item.key === key && "menu" in item) { 72 | return item.menu; 73 | } 74 | } 75 | throw new Error(`No submenu for key ${key}`); 76 | } 77 | ``` 78 | 79 | ### Delete a key from a menu 80 | 81 | ```js 82 | module.exports = function editConfig(menu) { 83 | deleteKey(menu, "*"); 84 | return menu; 85 | }; 86 | 87 | /** 88 | * Delete a key from a menu 89 | * @param { UserMenu } userMenu 90 | * @param { string } key 91 | * @returns { UserMenu } 92 | */ 93 | function deleteKey(userMenu, key) { 94 | userMenu.items = userMenu.items.filter((item) => item.key !== key); 95 | } 96 | ``` 97 | 98 | ### Sorting menu items alphabetically 99 | 100 | Symbols and numbers first: 101 | 102 | ```js 103 | module.exports = function editConfig(menu) { 104 | // edit menu 105 | menu.items.push({ 106 | name: "Auto Fix", 107 | key: "a", 108 | icon: "lightbulb", 109 | command: "editor.action.autoFix", 110 | }); 111 | 112 | // Sort menu 113 | menu.items.sort((a, b) => a.key.localeCompare(b.key)); 114 | 115 | return menu; 116 | }; 117 | ``` 118 | 119 | Letters first: 120 | 121 | ```js 122 | module.exports = function editConfig(menu) { 123 | menu.items.sort((a, b) => alphabeticalLettersFirst(a.key, b.key)); 124 | 125 | return menu; 126 | }; 127 | 128 | function alphabeticalLettersFirst(a, b) { 129 | if (isKeyLetter(a) && !isKeyLetter(b)) { 130 | return -1; 131 | } else if (!isKeyLetter(a) && isKeyLetter(b)) { 132 | return 1; 133 | } else if (a.toLowerCase() < b.toLowerCase()) { 134 | return -1; 135 | } else if (a.toLowerCase() > b.toLowerCase()) { 136 | return 1; 137 | } else { 138 | return 0; 139 | } 140 | } 141 | 142 | function isKeyLetter(key) { 143 | return (key >= "a" && key <= "z") || (key >= "A" && key <= "Z"); 144 | } 145 | ``` 146 | 147 | ### Overwrite the entire menu 148 | 149 | ```js 150 | module.exports = function editConfig(menu) { 151 | return { 152 | items: [ 153 | { 154 | name: "Auto Fix", 155 | key: "a", 156 | icon: "lightbulb", 157 | command: "editor.action.autoFix", 158 | }, 159 | ], 160 | }; 161 | }; 162 | ``` 163 | 164 | ### Edit a key 165 | 166 | ```js 167 | module.exports = function editConfig(menu) { 168 | getKey(menu, "c").icon = "arrow-left"; 169 | return menu; 170 | }; 171 | 172 | /** 173 | * @param { UserMenu } userMenu 174 | * @param { string } key 175 | * @returns { UserMenu } 176 | */ 177 | function getKey(menu, key) { 178 | for (const item of menu.items) { 179 | if (item.key === key) { 180 | return item; 181 | } 182 | } 183 | throw new Error(`No key ${key}`); 184 | } 185 | ``` 186 | 187 | ## Icons 188 | 189 | Keys have an optional `icon` property. 190 | You can use any icon from [codicon](https://icon-sets.iconify.design/codicon/). 191 | 192 | See also VSCode icons [docs](https://code.visualstudio.com/api/references/icons-in-labels). 193 | -------------------------------------------------------------------------------- /website/docs/img/double-space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/docs/img/double-space.png -------------------------------------------------------------------------------- /website/docs/img/file_keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/docs/img/file_keys.png -------------------------------------------------------------------------------- /website/docs/img/input_sources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/docs/img/input_sources.png -------------------------------------------------------------------------------- /website/docs/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Install 6 | 7 | 1. Install the [Glimpse](https://marketplace.visualstudio.com/items?itemName=ieni.glimpse) 8 | VSCode extension. 9 | If you don't use the VSCode marketplace, you can install the extension from [Open VSX](https://open-vsx.org/extension/ieni/glimpse). 10 | 2. Verify that the extension is correctly installed by pressing `Ctrl+Shift+P` to open the command 11 | palette and searching for `Glimpse: Menu`. 12 | 13 | Congrats, you ran Glimpse for the first time! 🎉 14 | 15 | However, running Glimpse from the command palette isn't ergonomic — 16 | let's configure a shortcut to trigger `Glimpse: Menu`. 17 | 18 | ## Glimpse keyboard shortcut 19 | 20 | In the following, we edit the VSCode configuration to run Glimpse with: 21 | 22 | - `alt+space` key for non-Vim users 23 | - `space` key for Vim users 24 | 25 | Feel free to change the key binding to your liking. 26 | 27 | ### Non-Vim users 28 | 29 | You can set the shortcut in two ways: by editing the JSON configuration file or by using the VSCode UI. 30 | 31 | #### Configuration File 32 | 33 | To set the shortcut via the JSON configuration file: 34 | 35 | - Press `Ctrl+Shift+P` to open the command palette and search for 36 | `Preferences: Open Keyboard Shortcuts (JSON)`. 37 | - Add the following: 38 | 39 | ```json 40 | [ 41 | { 42 | "key": "alt+space", 43 | "command": "glimpse.menu" 44 | } 45 | ] 46 | ``` 47 | 48 | #### VSCode UI 49 | 50 | To set the shortcut the VSCode UI: 51 | 52 | - Press `Ctrl+Shift+P` to open the command palette and search for `Preferences: Open Keyboard Shortcuts`. 53 | - Search for `glimpse.menu`. 54 | - Double click on the row to edit the shortcut. 55 | 56 | ### [VSCodeVim](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim) users 57 | 58 | Press `Ctrl+Shift+P` to open the command palette and search for 59 | `Preferences: Open Keyboard Shortcuts (JSON)`. 60 | Add the following: 61 | 62 | ```json 63 | { 64 | "key": "space", 65 | "command": "glimpse.menu", 66 | "when": "((activeEditorGroupEmpty && focusedView == '') || inWelcome || sideBarFocus) && !inputFocus && !glimpseVisible" 67 | } 68 | ``` 69 | 70 | Press `Ctrl+Shift+P` to open the command palette and search for `Preferences: Open User Settings (JSON)`. 71 | Add the following: 72 | 73 | ```json 74 | { 75 | "vim.normalModeKeyBindingsNonRecursive": [ 76 | { 77 | "before": [ 78 | "" 79 | ], 80 | "commands": [ 81 | "glimpse.menu" 82 | ] 83 | }, 84 | ], 85 | "vim.visualModeKeyBindingsNonRecursive": [ 86 | { 87 | "before": [ 88 | "" 89 | ], 90 | "commands": [ 91 | "glimpse.menu" 92 | ] 93 | }, 94 | ] 95 | } 96 | ``` 97 | 98 | ### [VSCode Neovim](https://marketplace.visualstudio.com/items?itemName=asvetliakov.vscode-neovim) users 99 | 100 | Press `Ctrl+Shift+P` to open the command palette and search for `Preferences: Open Keyboard Shortcuts (JSON)`. 101 | Add the following: 102 | 103 | ```json 104 | { 105 | "command": "glimpse.menu", 106 | "when": "editorTextFocus && neovim.mode != insert", 107 | "key": "space" 108 | } 109 | ``` 110 | 111 | As an alternative, you can either: 112 | 113 | - Add the following to your `init.vim`: 114 | 115 | ```vim 116 | if exists('g:vscode') 117 | " VSCode extension config 118 | nnoremap call VSCodeNotify('glimpse.menu') 119 | vnoremap call VSCodeNotify('glimpse.menu') 120 | else 121 | " ordinary Neovim config 122 | endif 123 | ``` 124 | 125 | - Add the following to your `init.lua`: 126 | 127 | ```lua 128 | if vim.g.vscode then 129 | -- VSCode extension config 130 | vim.keymap.set("n", "", [[call VSCodeNotify('glimpse.menu')]]) 131 | vim.keymap.set("v", "", [[call VSCodeNotify('glimpse.menu')]]) 132 | else 133 | -- ordinary Neovim config 134 | end 135 | ``` 136 | -------------------------------------------------------------------------------- /website/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: '/' 3 | sidebar_position: 1 4 | --- 5 | 6 | # Introduction 7 | 8 | Glimpse is a VSCode extension that allows you to run VSCode commands with easy-to-remember key bindings. 9 | 10 | You no longer need to remember complex shortcuts — Glimpse shows the available key bindings as you type. 11 | E.g. when pressing `f`, Glimpse shows you all the key bindings related to files. 12 | 13 |  14 | 15 | For example, you can press `f d` to delete the current file, or `f n` to create a new one. 16 | 17 | If you don't want to type the letter, you can use the up and down arrow keys to navigate the menu, 18 | and press enter to run the command. 19 | -------------------------------------------------------------------------------- /website/docs/keybindings.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # Key bindings 6 | 7 | Here are the default Glimpse key bindings. 8 | 9 | ## Top level menu 10 | 11 | | Key | Name | Command | 12 | | --- | ---- | ------- | 13 | | v | Select/expand region | `editor.action.smartSelect.grow` | 14 | | ␣ | Commands | `workbench.action.showCommands` | 15 | | ↹ | Last editor | \[ `workbench.action.quickOpenPreviousRecentlyUsedEditorInGroup`, `list.select` \] | 16 | | ! | Show terminal | `workbench.action.terminal.focus` | 17 | | " | Open new external terminal | `workbench.action.terminal.openNativeConsole` | 18 | | ' | Show terminal | `workbench.action.terminal.focus` | 19 | | * | Search Selection in Files | \[ `editor.action.addSelectionToNextFindMatch`, `workbench.action.findInFiles`, `search.action.focusSearchList` \] | 20 | | / | Search in files | `workbench.action.findInFiles` | 21 | | ; | Toggle comment | `editor.action.commentLine` | 22 | | 0 | Focus on files explorer | `workbench.files.action.focusFilesExplorer` | 23 | | 1 | Focus 1st editor group | `workbench.action.focusFirstEditorGroup` | 24 | | 2 | Focus 2nd editor group | `workbench.action.focusSecondEditorGroup` | 25 | | 3 | Focus 3rd editor group | `workbench.action.focusThirdEditorGroup` | 26 | | 4 | Focus 4th editor group | `workbench.action.focusFourthEditorGroup` | 27 | | 5 | Focus 5th editor group | `workbench.action.focusFifthEditorGroup` | 28 | | 6 | Focus 6th editor group | `workbench.action.focusSixthEditorGroup` | 29 | | 7 | Focus 7th editor group | `workbench.action.focusSeventhEditorGroup` | 30 | | 8 | Focus 8th editor group | `workbench.action.focusEighthEditorGroup` | 31 | 32 | ## Configuration 33 | 34 | | Key | Name | Command | 35 | | --- | ---- | ------- | 36 | | c c | Open settings | `workbench.action.openGlobalSettings` | 37 | | c C | Open settings JSON | `workbench.action.openSettingsJson` | 38 | | c g | Glimpse: Configure | `glimpse.configure` | 39 | | c k | Open global key bindings | `workbench.action.openGlobalKeybindings` | 40 | | c K | Open global key bindings JSON | `workbench.action.openGlobalKeybindingsFile` | 41 | | c l | Open language settings | `workbench.action.configureLanguageBasedSettings` | 42 | | c s | Configure user snippets | `workbench.action.openSnippets` | 43 | | c w | Open workspace settings | `workbench.action.openWorkspaceSettings` | 44 | | c W | Open workspace settings JSON | `workbench.action.openWorkspaceSettingsFile` | 45 | 46 | ## Comment 47 | 48 | | Key | Name | Command | 49 | | --- | ---- | ------- | 50 | | C f | Fold all block comments | `editor.foldAllBlockComments` | 51 | | C b | Toggle block comment | `editor.action.blockComment` | 52 | | C l | Toggle line comment | `editor.action.commentLine` | 53 | 54 | ## Debug 55 | 56 | | Key | Name | Command | 57 | | --- | ---- | ------- | 58 | | d c | Continue debug | `workbench.action.debug.continue` | 59 | | d C | Continue to cursor | `editor.debug.action.runToCursor` | 60 | | d d | Start debug | `workbench.action.debug.start` | 61 | | d D | Run without debugging | `workbench.action.debug.run` | 62 | | d i | Step into | `workbench.action.debug.stepInto` | 63 | | d j | Jump to cursor | `debug.jumpToCursor` | 64 | | d o | Step out | `workbench.action.debug.stepOut` | 65 | | d p | Pause debug | `workbench.action.debug.pause` | 66 | | d R | Restart debug | `workbench.action.debug.restart` | 67 | | d s | Step over | `workbench.action.debug.stepOver` | 68 | | d S | Stop debug | `workbench.action.debug.stop` | 69 | | d v | REPL | `workbench.debug.action.toggleRepl` | 70 | | d w | Focus on watch view | `workbench.debug.action.focusWatchView` | 71 | | d W | Add to watch | `editor.debug.action.selectionToWatch` | 72 | 73 | ### Breakpoint 74 | 75 | | Key | Name | Command | 76 | | --- | ---- | ------- | 77 | | d b b | Toggle breakpoint | `editor.debug.action.toggleBreakpoint` | 78 | | d b c | Add conditional breakpoint | `editor.debug.action.conditionalBreakpoint` | 79 | | d b d | Delete breakpoint | `debug.removeBreakpoint` | 80 | | d b D | Delete all breakpoints | `workbench.debug.viewlet.action.removeAllBreakpoints` | 81 | | d b e | Enable breakpoint | `debug.enableOrDisableBreakpoint` | 82 | | d b E | Enable all breakpoints | `workbench.debug.viewlet.action.enableAllBreakpoints` | 83 | | d b f | Add function breakpoint | `workbench.debug.viewlet.action.addFunctionBreakpointAction` | 84 | | d b i | Toggle inline breakpoint | `editor.debug.action.toggleInlineBreakpoint` | 85 | | d b n | Next breakpoint | `editor.debug.action.goToNextBreakpoint` | 86 | | d b p | Previous breakpoint | `editor.debug.action.goToPreviousBreakpoint` | 87 | | d b s | Disable breakpoint | `debug.enableOrDisableBreakpoint` | 88 | | d b S | Disable all breakpoints | `workbench.debug.viewlet.action.disableAllBreakpoints` | 89 | 90 | #### Next breakpoint 91 | 92 | | Key | Name | Command | 93 | | --- | ---- | ------- | 94 | | d b n n | Next breakpoint | `editor.debug.action.goToNextBreakpoint` | 95 | | d b n p | Previous breakpoint | `editor.debug.action.goToPreviousBreakpoint` | 96 | 97 | #### Previous breakpoint 98 | 99 | | Key | Name | Command | 100 | | --- | ---- | ------- | 101 | | d b p n | Next breakpoint | `editor.debug.action.goToNextBreakpoint` | 102 | | d b p p | Previous breakpoint | `editor.debug.action.goToPreviousBreakpoint` | 103 | 104 | ## Diff/Compare 105 | 106 | | Key | Name | Command | 107 | | --- | ---- | ------- | 108 | | D c | Compare active file with clipboard | `workbench.files.action.compareWithClipboard` | 109 | | D d | Compare active file with | `workbench.files.action.compareFileWith` | 110 | | D s | Compare active file with saved | `workbench.files.action.compareWithSaved` | 111 | | D w | Toggle ignore trim whitespace | `toggle.diff.ignoreTrimWhitespace` | 112 | 113 | ## Error 114 | 115 | | Key | Name | Command | 116 | | --- | ---- | ------- | 117 | | e e | Show error | `editor.action.showHover` | 118 | | e E | Show all errors | `workbench.actions.view.problems` | 119 | | e f | Fix error | `editor.action.quickFix` | 120 | | e n | Next error | `editor.action.marker.nextInFiles` | 121 | | e N | Previous error | `editor.action.marker.prevInFiles` | 122 | | e p | Previous error | `editor.action.marker.prevInFiles` | 123 | 124 | ### Error transient 125 | 126 | | Key | Name | Command | 127 | | --- | ---- | ------- | 128 | | e t f | Fix error | `editor.action.quickFix` | 129 | | e t n | Next error | `editor.action.marker.nextInFiles` | 130 | | e t p | Previous error | `editor.action.marker.prevInFiles` | 131 | | e t N | Previous error | `editor.action.marker.prevInFiles` | 132 | 133 | ## Editor 134 | 135 | | Key | Name | Command | 136 | | --- | ---- | ------- | 137 | | E c | Close active editor | `workbench.action.closeActiveEditor` | 138 | | E C | Close other editors | `workbench.action.closeOtherEditors` | 139 | | E e | Show all editors | `workbench.action.showAllEditorsByMostRecentlyUsed` | 140 | | E E | Show all editors in active group | `workbench.action.showEditorsInActiveGroup` | 141 | | E h | Previous editor | `workbench.action.previousEditor` | 142 | | E H | Move editor into left group | `workbench.action.moveEditorToLeftGroup` | 143 | | E j | Next editor | `workbench.action.nextEditor` | 144 | | E J | Move editor into below group | `workbench.action.moveEditorToBelowGroup` | 145 | | E k | Previous editor | `workbench.action.previousEditor` | 146 | | E K | Move editor into above group | `workbench.action.moveEditorToAboveGroup` | 147 | | E l | Next editor | `workbench.action.nextEditor` | 148 | | E L | Move editor into right group | `workbench.action.moveEditorToRightGroup` | 149 | | E n | New Untitled Editor | `workbench.action.files.newUntitledFile` | 150 | | E p | Pin editor | `workbench.action.pinEditor` | 151 | | E P | Unpin editor | `workbench.action.unpinEditor` | 152 | | E r | Revert the current editor | `workbench.action.files.revert` | 153 | | E s | Scratch editor | `workbench.action.files.newUntitledFile` | 154 | | E T | Reopen closed editor | `workbench.action.reopenClosedEditor` | 155 | | E 0 | First editor in group | `workbench.action.firstEditorInGroup` | 156 | | E 1 | First editor in group | `workbench.action.openEditorAtIndex1` | 157 | | E 2 | 2nd editor in group | `workbench.action.openEditorAtIndex2` | 158 | | E 3 | 3rd editor in group | `workbench.action.openEditorAtIndex3` | 159 | | E 4 | 4th editor in group | `workbench.action.openEditorAtIndex4` | 160 | | E 5 | 5th editor in group | `workbench.action.openEditorAtIndex5` | 161 | | E 6 | 6th editor in group | `workbench.action.openEditorAtIndex6` | 162 | | E 7 | 7th editor in group | `workbench.action.openEditorAtIndex7` | 163 | | E 8 | 8th editor in group | `workbench.action.openEditorAtIndex8` | 164 | | E 9 | 9th editor in group | `workbench.action.openEditorAtIndex9` | 165 | | E $ | Last editor in group | `workbench.action.lastEditorInGroup` | 166 | 167 | ### New Editor in other Group 168 | 169 | | Key | Name | Command | 170 | | --- | ---- | ------- | 171 | | E N h | New untitled editor (split left) | \[ `workbench.action.splitEditorLeft`, `workbench.action.files.newUntitledFile`, `workbench.action.closeOtherEditors` \] | 172 | | E N j | New untitled editor (split down) | \[ `workbench.action.splitEditorDown`, `workbench.action.files.newUntitledFile`, `workbench.action.closeOtherEditors` \] | 173 | | E N k | New untitled editor (split up) | \[ `workbench.action.splitEditorUp`, `workbench.action.files.newUntitledFile`, `workbench.action.closeOtherEditors` \] | 174 | | E N l | New untitled editor (split right) | \[ `workbench.action.splitEditorRight`, `workbench.action.files.newUntitledFile`, `workbench.action.closeOtherEditors` \] | 175 | 176 | ## File 177 | 178 | | Key | Name | Command | 179 | | --- | ---- | ------- | 180 | | f d | Delete current file | \[ `workbench.files.action.showActiveFileInExplorer`, `deleteFile` \] | 181 | | f e | Show file in explorer | `workbench.files.action.showActiveFileInExplorer` | 182 | | f f | Find file | `workbench.action.quickOpen` | 183 | | f l | Change file language | `workbench.action.editor.changeLanguageMode` | 184 | | f n | New file | `explorer.newFile` | 185 | | f o | Open with | `explorer.openWith` | 186 | | f O | Open in OS | `revealFileInOS` | 187 | | f p | Copy Path of Active File | `copyFilePath` | 188 | | f P | Copy Relative Path of Active File | `copyRelativeFilePath` | 189 | | f r | Rename file | \[ `revealInExplorer`, `renameFile` \] | 190 | | f s | Save file | `workbench.action.files.save` | 191 | | f S | Save all files | `workbench.action.files.saveAll` | 192 | | f w | Open file in new window | `workbench.action.files.showOpenedFileInNewWindow` | 193 | 194 | ## Format 195 | 196 | | Key | Name | Command | 197 | | --- | ---- | ------- | 198 | | F c | Format changes | `editor.action.formatChanges` | 199 | | F e | Format Editor | `editor.action.formatDocument` | 200 | | F E | Format editor with formatter | `editor.action.formatDocument.multiple` | 201 | | F f | Format region or editor | `editor.action.format` | 202 | | F s | Format selection | `editor.action.formatSelection` | 203 | | F S | Format selection with formatter | `editor.action.formatSelection.multiple` | 204 | 205 | ## Git 206 | 207 | | Key | Name | Command | 208 | | --- | ---- | ------- | 209 | | g a | Stage Changes | `git.stageSelectedRanges` | 210 | | g A | Stage Selected Ranges | `git.stageSelectedRanges` | 211 | | g b | Checkout | `git.checkout` | 212 | | g c | Commit | `git.commit` | 213 | | g C | Clone | `git.clone` | 214 | | g f | Fetch | `git.fetch` | 215 | | g F | Pull | `git.pull` | 216 | | g i | Initialize repository | `git.init` | 217 | | g l | Show log/timeline | `timeline.focus` | 218 | | g m | Merge | `git.merge` | 219 | | g p | Publish | `git.publish` | 220 | | g P | Push | `git.push` | 221 | | g s | Status | `workbench.view.scm` | 222 | | g u | Unstage | `git.unstage` | 223 | | g U | Unstage Selected Ranges | `git.unstageSelectedRanges` | 224 | 225 | ### Delete 226 | 227 | | Key | Name | Command | 228 | | --- | ---- | ------- | 229 | | g d b | Delete Branch | `git.deleteBranch` | 230 | | g d t | Delete Tag | `git.deleteTag` | 231 | | g d T | Delete Remote Tag | `git.deleteRemoteTag` | 232 | 233 | ### Merge conflict 234 | 235 | | Key | Name | Command | 236 | | --- | ---- | ------- | 237 | | g M b | Accept both | `merge-conflict.accept.both` | 238 | | g M B | Accept all both | `merge-conflict.accept.all-both` | 239 | | g M c | Accept current | `merge-conflict.accept.current` | 240 | | g M C | Accept all current | `merge-conflict.accept.all-current` | 241 | | g M d | Compare current conflict | `merge-conflict.compare` | 242 | | g M i | Accept incoming | `merge-conflict.accept.incoming` | 243 | | g M I | Accept all incoming | `merge-conflict.accept.all-incoming` | 244 | | g M n | Next Conflict | `merge-conflict.next` | 245 | | g M N | Previous Conflict | `merge-conflict.previous` | 246 | | g M s | Accept selection | `merge-conflict.accept.selection` | 247 | 248 | ## GitHub Copilot 249 | 250 | | Key | Name | Command | 251 | | --- | ---- | ------- | 252 | | G c | Copilot Chat | `workbench.panel.chatSidebar.copilot` | 253 | | G e | Explain this | `github.copilot.interactiveEditor.explain` | 254 | | G f | Fix this | `github.copilot.interactiveEditor.fix` | 255 | | G o | Open Completions Panel | `github.copilot.generate` | 256 | | G t | Toggle (Enable/Disable) Copilot | `github.copilot.toggleCopilot` | 257 | 258 | ### Generate 259 | 260 | | Key | Name | Command | 261 | | --- | ---- | ------- | 262 | | G g d | Generate Docs | `github.copilot.interactiveEditor.generateDocs` | 263 | | G g g | Generate This | `github.copilot.interactiveEditor.generate` | 264 | | G g t | Generate Tests | `github.copilot.interactiveEditor.generateTests` | 265 | 266 | ## Help 267 | 268 | | Key | Name | Command | 269 | | --- | ---- | ------- | 270 | | h d | Open VSCode Documentation | `workbench.action.openDocumentationUrl` | 271 | | h g | Open Glimpse Documentation | `glimpse.openDocs` | 272 | | h h | Describe thing at point | `editor.action.showHover` | 273 | | h i | Report VSCode Issue | `workbench.action.openIssueReporter` | 274 | | h k | Open global key bindings | `workbench.action.openGlobalKeybindings` | 275 | | h t | Open VSCode Tutorial | `workbench.action.showInteractivePlayground` | 276 | 277 | ## Insert 278 | 279 | | Key | Name | Command | 280 | | --- | ---- | ------- | 281 | | i j | Insert line below | `editor.action.insertLineAfter` | 282 | | i k | Insert line above | `editor.action.insertLineBefore` | 283 | | i p | Paste as | `editor.action.pasteAs` | 284 | | i s | Insert snippet | `editor.action.insertSnippet` | 285 | 286 | ## Indent 287 | 288 | | Key | Name | Command | 289 | | --- | ---- | ------- | 290 | | I d | Detect indentation | `editor.action.detectIndentation` | 291 | | I i | Change indentation | `changeEditorIndentation` | 292 | | I r | Reindent | `editor.action.reindentlines` | 293 | | I R | Reindent selected | `editor.action.reindentselectedlines` | 294 | | I s | Convert indentation to spaces | `editor.action.indentationToSpaces` | 295 | | I t | Convert indentation to tabs | `editor.action.indentationToTabs` | 296 | 297 | ## Jump 298 | 299 | | Key | Name | Command | 300 | | --- | ---- | ------- | 301 | | j b | Go to breadcrumb | `breadcrumbs.focusAndSelect` | 302 | | j c | Go to previous change | `workbench.action.editor.previousChange` | 303 | | j C | Go to next change | `workbench.action.editor.nextChange` | 304 | | j d | Go to declaration | `editor.action.revealDeclaration` | 305 | | j j | Go to definition | `editor.action.revealDefinition` | 306 | | j h | Show call hierarchy | `references-view.showCallHierarchy` | 307 | | j i | Go to implementations | `editor.action.goToImplementation` | 308 | | j I | Find implementations | `references-view.findImplementations` | 309 | | j r | Go to reference | `editor.action.goToReferences` | 310 | | j R | Find references | `references-view.findReferences` | 311 | | j s | Go to symbol in editor | `workbench.action.gotoSymbol` | 312 | | j S | Go to symbol in files | `workbench.action.showAllSymbols` | 313 | | j t | Go to type definition | `editor.action.goToTypeDefinition` | 314 | 315 | ## Peek 316 | 317 | | Key | Name | Command | 318 | | --- | ---- | ------- | 319 | | p d | Peek declaration | `editor.action.peekDeclaration` | 320 | | p h | Peek call hierarchy | `editor.showCallHierarchy` | 321 | | p i | Peek implementations | `editor.action.peekImplementation` | 322 | | p p | Peek definition | `editor.action.peekDefinition` | 323 | | p r | Peek references | `editor.action.referenceSearch.trigger` | 324 | | p R | Search all references in side bar | `references-view.find` | 325 | | p t | Peek type definition | `editor.action.peekTypeDefinition` | 326 | 327 | ## Quit 328 | 329 | | Key | Name | Command | 330 | | --- | ---- | ------- | 331 | | q f | Open recent folder | `workbench.action.openRecent` | 332 | | q q | Quit VSCode window | `workbench.action.closeWindow` | 333 | | q Q | Quit all VSCode windows | `workbench.action.quit` | 334 | | q r | Reload window | `workbench.action.reloadWindow` | 335 | | q R | Reload window with extensions disabled | `workbench.action.reloadWindowWithExtensionsDisabled` | 336 | | q s | Save all and close window | \[ `workbench.action.files.saveAll`, `workbench.action.closeWindow` \] | 337 | | q w | Close workspace | `workbench.action.closeFolder` | 338 | 339 | ## Refactor 340 | 341 | | Key | Name | Command | 342 | | --- | ---- | ------- | 343 | | r . | Quick fix | `editor.action.quickFix` | 344 | | r e | Extract to function or variable | `editor.action.codeAction: {"kind":"refactor.extract"}` | 345 | | r i | Organize imports | `editor.action.organizeImports` | 346 | | r r | Rename Symbol | `editor.action.rename` | 347 | | r R | Refactor actions | `editor.action.refactor` | 348 | | r s | Execute source action | `editor.action.sourceAction` | 349 | 350 | ## Search 351 | 352 | | Key | Name | Command | 353 | | --- | ---- | ------- | 354 | | s c | Clear Search Results | `search.action.clearSearchResults` | 355 | | s e | Search Editor: New | `search.action.openNewEditor` | 356 | | s E | Search Editor: New to the Side | `search.action.openNewEditorToSide` | 357 | | s h | Highlight symbol | `editor.action.wordHighlight.trigger` | 358 | | s q | Quick search | `workbench.action.quickTextSearch` | 359 | | s s | Search | `actions.find` | 360 | | s S | Search in files | `workbench.action.findInFiles` | 361 | | s r | Replace | `editor.action.startFindReplaceAction` | 362 | | s R | Replace in files | `workbench.action.replaceInFiles` | 363 | | s * | Search Selection in Files | \[ `editor.action.addSelectionToNextFindMatch`, `workbench.action.findInFiles`, `search.action.focusSearchList` \] | 364 | 365 | ### Highlight symbol 366 | 367 | | Key | Name | Command | 368 | | --- | ---- | ------- | 369 | | s h n | Next occurrence | `editor.action.wordHighlight.next` | 370 | | s h p | Previous occurrence | `editor.action.wordHighlight.prev` | 371 | | s h N | Previous occurrence | `editor.action.wordHighlight.prev` | 372 | 373 | ## Show 374 | 375 | | Key | Name | Command | 376 | | --- | ---- | ------- | 377 | | S d | Show debug console | `workbench.debug.action.toggleRepl` | 378 | | S e | Show explorer | `workbench.view.explorer` | 379 | | S E | Show extensions | `workbench.view.extensions` | 380 | | S g | Show source control | `workbench.view.scm` | 381 | | S n | Show notification | `notifications.toggleList` | 382 | | S o | Show output | `workbench.action.output.toggleOutput` | 383 | | S p | Show problems | `workbench.actions.view.problems` | 384 | | S r | Show remote explorer | `workbench.view.remote` | 385 | | S s | Show search | `workbench.view.search` | 386 | | S t | Show test | `workbench.view.extension.test` | 387 | 388 | ## Toggle 389 | 390 | | Key | Name | Command | 391 | | --- | ---- | ------- | 392 | | t b | Toggle side bar visibility | `workbench.action.toggleSidebarVisibility` | 393 | | t B | Toggle Activity Bar Visibility | `workbench.action.toggleActivityBarVisibility` | 394 | | t c | Toggle centered layout | `workbench.action.toggleCenteredLayout` | 395 | | t C | Toggle find case sensitive | `toggleFindCaseSensitive` | 396 | | t f | Toggle full screen | `workbench.action.toggleFullScreen` | 397 | | t i | Select icon theme | `workbench.action.selectIconTheme` | 398 | | t m | Toggle minimap | `editor.action.toggleMinimap` | 399 | | t p | Toggle panel visibility | `workbench.action.togglePanel` | 400 | | t P | Toggle maximized panel | `workbench.action.toggleMaximizedPanel` | 401 | | t t | Select theme | `workbench.action.selectTheme` | 402 | | t T | Toggle tab visibility | `workbench.action.toggleTabsVisibility` | 403 | | t w | Toggle word wrap | `editor.action.toggleWordWrap` | 404 | | t W | Toggle render whitespace | `editor.action.toggleRenderWhitespace` | 405 | | t z | Toggle zen mode | `workbench.action.toggleZenMode` | 406 | 407 | ## Test 408 | 409 | | Key | Name | Command | 410 | | --- | ---- | ------- | 411 | | T a | Run all tests | `testing.runAll` | 412 | | T A | Debug all tests | `testing.debugAll` | 413 | | T f | Run current test file | `testing.runCurrentFile` | 414 | | T r | Re-run failed tests | `testing.reRunFailTests` | 415 | | T t | Select and run test | `testing.runSelected` | 416 | | T T | Select and debug test | `testing.debugSelected` | 417 | 418 | ## Window/Group 419 | 420 | | Key | Name | Command | 421 | | --- | ---- | ------- | 422 | | w + | Enlarge group | `workbench.action.increaseViewSize` | 423 | | w = | Enlarge group | `workbench.action.increaseViewSize` | 424 | | w - | Shrink group | `workbench.action.decreaseViewSize` | 425 | | w c | Close group | `workbench.action.closeEditorsInGroup` | 426 | | w C | Close all other groups | `workbench.action.closeEditorsInOtherGroups` | 427 | | w h | Focus group left | `workbench.action.navigateLeft` | 428 | | w H | Move in group left | `workbench.action.moveActiveEditorGroupLeft` | 429 | | w j | Focus group down | `workbench.action.navigateDown` | 430 | | w J | Move in group down | `workbench.action.moveActiveEditorGroupDown` | 431 | | w k | Focus group up | `workbench.action.navigateUp` | 432 | | w K | Move in group up | `workbench.action.moveActiveEditorGroupUp` | 433 | | w l | Focus group right | `workbench.action.navigateRight` | 434 | | w L | Move in group right | `workbench.action.moveActiveEditorGroupRight` | 435 | | w m | Maximize editor group | `workbench.action.toggleEditorWidths` | 436 | | w M | Maximize editor group and hide others | `workbench.action.toggleMaximizeEditorGroup` | 437 | | w n | Duplicate workspace in new window | `workbench.action.duplicateWorkspaceInNewWindow` | 438 | | w N | Open new VSCode window | `workbench.action.newWindow` | 439 | | w o | Switch VSCode window | `workbench.action.quickSwitchWindow` | 440 | | w r | Reset editor widths | `workbench.action.evenEditorWidths` | 441 | | w s | Split editor down | `workbench.action.splitEditorDown` | 442 | | w v | Split editor right | `workbench.action.splitEditor` | 443 | | w w | Focus group right | `workbench.action.focusNextGroup` | 444 | | w W | Focus group left | `workbench.action.focusPreviousGroup` | 445 | | w x | Close all groups | `workbench.action.closeAllGroups` | 446 | | w z | Join all groups | `workbench.action.joinAllGroups` | 447 | | w 1 | Single column window layout | `workbench.action.editorLayoutSingle` | 448 | | w 2 | Double column window layout | `workbench.action.editorLayoutTwoColumns` | 449 | | w 3 | Triple column window layout | `workbench.action.editorLayoutThreeColumns` | 450 | | w 4 | Grid window layout | `workbench.action.editorLayoutTwoByTwoGrid` | 451 | 452 | ### Enlarge group 453 | 454 | | Key | Name | Command | 455 | | --- | ---- | ------- | 456 | | w + - | Shrink group | `workbench.action.decreaseViewSize` | 457 | | w + + | Enlarge group | `workbench.action.increaseViewSize` | 458 | | w + = | Enlarge group | `workbench.action.increaseViewSize` | 459 | 460 | ### Enlarge group 461 | 462 | | Key | Name | Command | 463 | | --- | ---- | ------- | 464 | | w = - | Shrink group | `workbench.action.decreaseViewSize` | 465 | | w = + | Enlarge group | `workbench.action.increaseViewSize` | 466 | | w = = | Enlarge group | `workbench.action.increaseViewSize` | 467 | 468 | ### Shrink group 469 | 470 | | Key | Name | Command | 471 | | --- | ---- | ------- | 472 | | w - - | Shrink group | `workbench.action.decreaseViewSize` | 473 | | w - + | Enlarge group | `workbench.action.increaseViewSize` | 474 | | w - = | Enlarge group | `workbench.action.increaseViewSize` | 475 | 476 | ## Text 477 | 478 | | Key | Name | Command | 479 | | --- | ---- | ------- | 480 | | x j | Move lines down | `editor.action.moveLinesDownAction` | 481 | | x k | Move lines up | `editor.action.moveLinesUpAction` | 482 | | x o | Open link | `editor.action.openLink` | 483 | | x u | To lower case | `editor.action.transformToLowercase` | 484 | | x U | To upper case | `editor.action.transformToUppercase` | 485 | | x w | Delete trailing whitespace | `editor.action.trimTrailingWhitespace` | 486 | 487 | ### Move lines down 488 | 489 | | Key | Name | Command | 490 | | --- | ---- | ------- | 491 | | x j j | Move lines down | `editor.action.moveLinesDownAction` | 492 | | x j k | Move lines up | `editor.action.moveLinesUpAction` | 493 | 494 | ### Move lines up 495 | 496 | | Key | Name | Command | 497 | | --- | ---- | ------- | 498 | | x k j | Move lines down | `editor.action.moveLinesDownAction` | 499 | | x k k | Move lines up | `editor.action.moveLinesUpAction` | 500 | 501 | ### Lines 502 | 503 | | Key | Name | Command | 504 | | --- | ---- | ------- | 505 | | x l d | Duplicate lines down | `editor.action.copyLinesDownAction` | 506 | | x l D | Duplicate lines up | `editor.action.copyLinesUpAction` | 507 | | x l s | Sort lines in ascending order | `editor.action.sortLinesAscending` | 508 | | x l S | Sort lines in descending order | `editor.action.sortLinesDescending` | 509 | 510 | ## Select/expand region 511 | 512 | | Key | Name | Command | 513 | | --- | ---- | ------- | 514 | | v v | Grow selection | `editor.action.smartSelect.grow` | 515 | | v V | Shrink selection | `editor.action.smartSelect.shrink` | 516 | 517 | ## Zoom/Fold 518 | 519 | | Key | Name | Command | 520 | | --- | ---- | ------- | 521 | | z + | Zoom In | `workbench.action.zoomIn` | 522 | | z = | Zoom In | `workbench.action.zoomIn` | 523 | | z - | Zoom Out | `workbench.action.zoomOut` | 524 | | z 0 | Reset zoom | `workbench.action.zoomReset` | 525 | 526 | ### Zoom In 527 | 528 | | Key | Name | Command | 529 | | --- | ---- | ------- | 530 | | z + + | Zoom In | `workbench.action.zoomIn` | 531 | | z + = | Zoom In | `workbench.action.zoomIn` | 532 | | z + - | Zoom Out | `workbench.action.zoomOut` | 533 | 534 | ### Zoom In 535 | 536 | | Key | Name | Command | 537 | | --- | ---- | ------- | 538 | | z = + | Zoom In | `workbench.action.zoomIn` | 539 | | z = = | Zoom In | `workbench.action.zoomIn` | 540 | | z = - | Zoom Out | `workbench.action.zoomOut` | 541 | 542 | ### Zoom Out 543 | 544 | | Key | Name | Command | 545 | | --- | ---- | ------- | 546 | | z - + | Zoom In | `workbench.action.zoomIn` | 547 | | z - = | Zoom In | `workbench.action.zoomIn` | 548 | | z - - | Zoom Out | `workbench.action.zoomOut` | 549 | 550 | ### Image preview 551 | 552 | | Key | Name | Command | 553 | | --- | ---- | ------- | 554 | | z i + | Zoom in | `imagePreview.zoomIn` | 555 | | z i - | Zoom out | `imagePreview.zoomOut` | 556 | | z i = | Zoom in | `imagePreview.zoomIn` | 557 | 558 | ### Font 559 | 560 | | Key | Name | Command | 561 | | --- | ---- | ------- | 562 | | z f + | Zoom In | `editor.action.fontZoomIn` | 563 | | z f = | Zoom In | `editor.action.fontZoomIn` | 564 | | z f - | Zoom out | `editor.action.fontZoomOut` | 565 | | z f 0 | Reset zoom | `editor.action.fontZoomReset` | 566 | 567 | ### Fold 568 | 569 | | Key | Name | Command | 570 | | --- | ---- | ------- | 571 | | z F a | Toggle: around a point | `editor.toggleFold` | 572 | | z F b | Close: all block comments | `editor.foldAllBlockComments` | 573 | | z F c | Close: at a point | `editor.fold` | 574 | | z F g | Close: all regions | `editor.foldAllMarkerRegions` | 575 | | z F G | Open: all regions | `editor.unfoldAllMarkerRegions` | 576 | | z F m | Close: all | `editor.foldAll` | 577 | | z F o | Open: at a point | `editor.unfold` | 578 | | z F O | Open: recursively | `editor.unfoldRecursively` | 579 | | z F r | Open: all | `editor.unfoldAll` | 580 | 581 | ## Task 582 | 583 | | Key | Name | Command | 584 | | --- | ---- | ------- | 585 | | : . | Rerun last task | `workbench.action.tasks.reRunTask` | 586 | | : : | Run task | `workbench.action.tasks.runTask` | 587 | | : b | Run build tasks | `workbench.action.tasks.build` | 588 | | : c | Configure task runner | `workbench.action.tasks.configureTaskRunner` | 589 | | : g | Show running tasks | `workbench.action.tasks.showTasks` | 590 | | : l | Show task log | `workbench.action.tasks.showLog` | 591 | | : t | Run test task | `workbench.action.tasks.test` | 592 | | : x | Terminate task | `workbench.action.tasks.terminate` | 593 | | : R | Restart running task | `workbench.action.tasks.restartTask` | 594 | -------------------------------------------------------------------------------- /website/docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 7 3 | --- 4 | 5 | # Troubleshooting 6 | 7 | ## See Glimpse logs 8 | 9 | 1. Press `Ctrl+Shift+P` and select `Developer: Show Logs...` 10 | 2. Select `Glimpse`. 11 | 12 | ## SPC SPC doesn't work as expected on Mac OS 13 | 14 | When pressing `SPC SPC` quickly on macOS, sometimes Glimpse doesn't recognize it. 15 | 16 | This problem is due to a keyboard setting on macOS that adds a period with double space. 17 | 18 | Open "System Settings" -> "Keyboard" -> "Input Sources" -> "Edit..." 19 | 20 |  21 | 22 | Disable the "Add period with double-space" option. 23 | 24 |  25 | 26 | If you don't use this feature, disabling it should fix this issue. 27 | Otherwise, add `.` to open the glimpse menu in your [configuration](configuration#add-a-key-binding-to-the-top-menu): 28 | 29 | ```js 30 | module.exports = function editConfig(menu) { 31 | menu.items.push({ 32 | name: "Commands", 33 | key: ".", 34 | icon: "rocket", 35 | command: "workbench.action.showCommands", 36 | }); 37 | 38 | return menu; 39 | }; 40 | ``` 41 | 42 | ## Unresponsive menu activation 43 | 44 | If you press `` on an editor and the glimpse menu doesn't appear immediately, you might have 45 | one of the following problems. 46 | 47 | ### Conflicting vim binding 48 | 49 | If in your `settings.json` file you have a vim binding that starts with ``, vim will wait for 50 | the second input when `` is pressed. Example: 51 | 52 | ```json title="settings.json" 53 | "vim.normalModeKeyBindingsNonRecursive": [ 54 | { 55 | "before": [" ", "d"], 56 | "after": ["d", "d"] 57 | }, 58 | { 59 | "before": [""], 60 | "commands": ["glimpse.menu"] 61 | } 62 | ] 63 | ``` 64 | 65 | In order to solve it, remove the conflicting Vim bindings from your `settings.json`. 66 | 67 | ### Virtual Machine or slow hardware 68 | 69 | If you are working on limiting resources consider using [VSCode remote](https://code.visualstudio.com/docs/remote/remote-overview) 70 | 71 | ### Other conflicts 72 | 73 | Try to remove all the extensions except glimpse, and clean your `settings.json` 74 | and `keybindings.json` files to spot some weird conflicts. 75 | -------------------------------------------------------------------------------- /website/docs/vim_tricks.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | 5 | # Vim tricks 6 | 7 | Some tricks and trips for the [VSCodeVim](https://github.com/VSCodeVim/Vim) extension. 8 | 9 | ## Execute Vim key combination 10 | 11 | Put the Vim key combination you want to execute in the command arguments. 12 | 13 | This example changes `SPC y` to run `y y`: 14 | 15 | ```js 16 | module.exports = function editConfig(menu) { 17 | menu.items.push({ 18 | name: "Yank line", 19 | key: "y", 20 | icon: "copy", 21 | command: { 22 | id: "vim.remap", 23 | args: { 24 | after: ["y", "y"], 25 | }, 26 | }, 27 | }); 28 | 29 | return menu; 30 | }; 31 | ``` 32 | 33 | ## Execute vim command 34 | 35 | Put the Vim command you want to execute in the command arguments. 36 | 37 | This example sets `SPC a` to save the file: 38 | 39 | ```js 40 | module.exports = function editConfig(menu) { 41 | menu.items.push({ 42 | name: "Custom command", 43 | key: "a", 44 | icon: "save", 45 | command: { 46 | id: "vim.remap", 47 | args: { 48 | commands: [{ command: ":w" }], 49 | }, 50 | }, 51 | }); 52 | 53 | return menu; 54 | }; 55 | ``` 56 | -------------------------------------------------------------------------------- /website/docs/why.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | 5 | # Why 6 | 7 | > There are too many VSCode extensions already. Why creating another one? 8 | 9 | Hey, I'm [Marco](https://ieni.dev), the author of Glimpse. 👋 10 | I'm glad you asked. 😎 11 | 12 | This story begins in 2018 when I started using [spacemacs](https://www.spacemacs.org/). 13 | I was blown away by the ergonomics and the discoverability of its key bindings, and 14 | I wanted the same experience in the other IDEs. 15 | 16 | Today, I maintain [Intellimacs](https://github.com/MarcoIeni/intellimacs), 17 | [Spaceclipse](https://github.com/MarcoIeni/spaceclipse), and [VSpaceCode], 18 | the plugins emulating Spacemacs respectively in [IntelliJ](https://www.jetbrains.com/), 19 | [Eclipse](https://www.eclipse.org/), and [VSCode](https://code.visualstudio.com/). 20 | 21 | Everything is great: people love these projects because they can switch from Spacemacs to other 22 | IDEs when needed. 23 | However, I have one issue with these plugins: I don't feel like recommending them to non-Spacemacs 24 | users, because 25 | the Spacemacs key bindings make sense only in the context of Spacemacs. 26 | 27 | ## Glimpse key bindings 28 | 29 | For example, let's compare some of the key bindings of [VSpaceCode] and Glimpse: 30 | 31 | - Open VSCode settings: `f e d` (files, emacs, dotfiles) vs `c c` (configuration, configuration) 32 | - Switch VSCode editor: `b b` (buffer, buffer) vs `E e` (editor, editor) 33 | - Show call hierarchy: `m g h` (major, goto, hierarchy) vs `g h` (goto, hierarchy) 34 | 35 | As you can see, Glimpse key bindings don't use emacs terminology (like buffer or major mode), 36 | and they make sense to people who never used Spacemacs. 37 | 38 | ## Glimpse design 39 | 40 | Speaking of [VSpaceCode]: to emulate as many Spacemacs features as possible, 41 | VSpaceCode depends on other 5 VSCode extensions. 42 | This is great for spacemacs users: VSpaceCode is a battery-included solution, just like Spacemacs is. 43 | 44 | However, non-spacemacs users probably don't need all those features, and they would be confused by 45 | the other extensions installed. 46 | That's why Glimpse is just a single extension, that doesn't install anything else. 47 | 48 | [VSpaceCode]: https://github.com/VSpaceCode/VSpaceCode 49 | -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Note: type annotations allow type checking and IDEs autocompletion 3 | 4 | import { themes } from "prism-react-renderer"; 5 | 6 | const lightCodeTheme = themes.github; 7 | const darkCodeTheme = themes.dracula; 8 | const TwitterSvg = 9 | ''; 10 | 11 | /** @type {import('@docusaurus/types').Config} */ 12 | const config = { 13 | title: "Glimpse", 14 | tagline: "Mnemonic key bindings for VSCode commands ⌨️", 15 | favicon: "img/favicon.ico", 16 | 17 | // Set the production url of your site here 18 | url: "https://glimpse.ieni.dev", 19 | // Set the // pathname under which your site is served 20 | // For GitHub pages deployment, it is often '//' 21 | baseUrl: "/", 22 | 23 | // GitHub pages deployment config. 24 | // If you aren't using GitHub pages, you don't need these. 25 | organizationName: "MarcoIeni", // Usually your GitHub org/user name. 26 | projectName: "glimpse", // Usually your repo name. 27 | trailingSlash: false, 28 | 29 | onBrokenLinks: "throw", 30 | onBrokenMarkdownLinks: "warn", 31 | 32 | // Even if you don't use internalization, you can use this field to set useful 33 | // metadata like html lang. For example, if your site is Chinese, you may want 34 | // to replace "en" with "zh-Hans". 35 | i18n: { 36 | defaultLocale: "en", 37 | locales: ["en"], 38 | }, 39 | scripts: [{ src: "/js/posthog.js" }], 40 | themes: [ 41 | [ 42 | require.resolve("@easyops-cn/docusaurus-search-local"), 43 | /** @type {import("@easyops-cn/docusaurus-search-local").PluginOptions} */ 44 | ({ 45 | // ... Your options. 46 | // `hashed` is recommended as long-term-cache of index file is possible. 47 | hashed: true, 48 | // For Docs using Chinese, The `language` is recommended to set to: 49 | // ``` 50 | // language: ["en", "zh"], 51 | // ``` 52 | }), 53 | ], 54 | ], 55 | 56 | presets: [ 57 | [ 58 | "classic", 59 | /** @type {import('@docusaurus/preset-classic').Options} */ 60 | ({ 61 | docs: { 62 | sidebarPath: require.resolve("./sidebars.js"), 63 | // Please change this to your repo. 64 | // Remove this to remove the "edit this page" links. 65 | editUrl: "https://github.com/MarcoIeni/glimpse/tree/main/website/", 66 | }, 67 | theme: { 68 | customCss: require.resolve("./src/css/custom.css"), 69 | }, 70 | }), 71 | ], 72 | ], 73 | 74 | themeConfig: 75 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 76 | ({ 77 | image: "img/glimpse-social-card.png", 78 | announcementBar: { 79 | id: "announcementBar-1", // Increment on change 80 | content: `⭐️ If you like Glimpse, give it a star on GitHub and follow the author on Twitter ${TwitterSvg}`, 81 | }, 82 | navbar: { 83 | title: "Glimpse", 84 | logo: { 85 | alt: "Glimpse Logo", 86 | src: "img/icon_small.png", 87 | }, 88 | items: [ 89 | { 90 | type: "docSidebar", 91 | sidebarId: "tutorialSidebar", 92 | position: "left", 93 | label: "Docs", 94 | }, 95 | { 96 | type: "docSidebar", 97 | sidebarId: "tutorialSidebar", 98 | href: "/pricing", 99 | position: "left", 100 | label: "Pricing", 101 | }, 102 | { 103 | label: "💖 Sponsor", 104 | href: "https://github.com/sponsors/MarcoIeni", 105 | position: "right", 106 | }, 107 | { 108 | href: "https://github.com/MarcoIeni/glimpse", 109 | "aria-label": "GitHub", 110 | className: "header-github-link", 111 | position: "right", 112 | }, 113 | ], 114 | }, 115 | footer: { 116 | style: "dark", 117 | links: [ 118 | { 119 | title: "Docs", 120 | items: [ 121 | { 122 | label: "Tutorial", 123 | to: "/docs", 124 | }, 125 | ], 126 | }, 127 | { 128 | title: "Author", 129 | items: [ 130 | { 131 | label: "Twitter", 132 | href: "https://twitter.com/MarcoIeni", 133 | }, 134 | { 135 | label: "LinkedIn", 136 | href: "https://www.linkedin.com/in/marcoieni/", 137 | }, 138 | ], 139 | }, 140 | { 141 | title: "Download Extension", 142 | items: [ 143 | { 144 | label: "VSCode Marketplace", 145 | href: "https://marketplace.visualstudio.com/items?itemName=ieni.glimpse", 146 | }, 147 | { 148 | label: "Open VSX", 149 | href: "https://open-vsx.org/extension/ieni/glimpse", 150 | }, 151 | ], 152 | }, 153 | ], 154 | copyright: `Copyright © ${new Date().getFullYear()} Glimpse. Built with Docusaurus.`, 155 | }, 156 | prism: { 157 | theme: lightCodeTheme, 158 | darkTheme: darkCodeTheme, 159 | }, 160 | }), 161 | }; 162 | 163 | module.exports = config; 164 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "mdlint": "markdownlint '**/*.md' --config .markdownlint.yaml --ignore node_modules --ignore docs/keybindings.md", 15 | "write-heading-ids": "docusaurus write-heading-ids" 16 | }, 17 | "dependencies": { 18 | "@docusaurus/core": "3.8.0", 19 | "@docusaurus/preset-classic": "3.8.0", 20 | "@easyops-cn/docusaurus-search-local": "^0.49.0", 21 | "@mdx-js/react": "^3.1.0", 22 | "clsx": "^2.1.1", 23 | "prism-react-renderer": "^2.4.0", 24 | "react": "^18.3.1", 25 | "react-dom": "^18.3.1" 26 | }, 27 | "devDependencies": { 28 | "@docusaurus/module-type-aliases": "3.8.0", 29 | "markdownlint-cli": "^0.45.0" 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.5%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "engines": { 44 | "node": ">=18.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{ type: "autogenerated", dirName: "." }], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | 'intro', 23 | 'hello', 24 | { 25 | type: 'category', 26 | label: 'Tutorial', 27 | items: ['tutorial-basics/create-a-document'], 28 | }, 29 | ], 30 | */ 31 | }; 32 | 33 | module.exports = sidebars; 34 | -------------------------------------------------------------------------------- /website/src/components/HomepageFeatures/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import clsx from "clsx"; 3 | import styles from "./styles.module.css"; 4 | 5 | const FeatureList = [ 6 | { 7 | title: "Mnemonic 💡", 8 | description: ( 9 | <> 10 | The most useful VSCode Commands organized by mnemonic keys, like f for{" "} 11 | file and r for refactor. Plus, if you use Vim motions, 12 | you'll feel at home. 13 | > 14 | ), 15 | }, 16 | { 17 | title: "Discoverable 🔎", 18 | description: ( 19 | <> 20 | Discover new VSCode Commands you wish you knew before, and execute them efficiently 21 | from your keyboard. 22 | > 23 | ), 24 | }, 25 | { 26 | title: "Customizable ⚙", 27 | description: ( 28 | <> 29 | No need to learn yet another configuration syntax: edit the Glimpse menu and key 30 | bindings with plain JavaScript. 31 | > 32 | ), 33 | }, 34 | ]; 35 | 36 | function Feature({ title, description }) { 37 | return ( 38 | 39 | 40 | {title} 41 | {description} 42 | 43 | 44 | ); 45 | } 46 | 47 | export default function HomepageFeatures() { 48 | return ( 49 | 50 | 51 | 52 | {FeatureList.map((props, idx) => ( 53 | 54 | ))} 55 | 56 | 57 | 58 | 59 | 60 | 61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /website/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --site-primary-hue-saturation: 189 68%; 10 | --ifm-color-primary: #012e86d1; 11 | --ifm-color-primary-dark: #022366df; 12 | --ifm-color-primary-darker: #022366ec; 13 | --ifm-color-primary-darkest: #022366; 14 | --ifm-color-primary-light: #022366c2; 15 | --ifm-color-primary-lighter: #02236693; 16 | --ifm-color-primary-lightest: #0223667e; 17 | --ifm-code-font-size: 95%; 18 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 19 | } 20 | 21 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 22 | [data-theme="dark"] { 23 | --ifm-color-primary: #5b93ffe3; 24 | --ifm-color-primary-dark: #022366df; 25 | --ifm-color-primary-darker: #022366ec; 26 | --ifm-color-primary-darkest: #022366; 27 | --ifm-color-primary-light: #022366c2; 28 | --ifm-color-primary-lighter: #02236693; 29 | --ifm-color-primary-lightest: #0223667e; 30 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 31 | } 32 | 33 | .header-github-link:hover { 34 | opacity: 0.6; 35 | } 36 | 37 | .header-github-link::before { 38 | content: ""; 39 | width: 24px; 40 | height: 24px; 41 | display: flex; 42 | background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") 43 | no-repeat; 44 | } 45 | 46 | [data-theme="dark"] .header-github-link::before { 47 | background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") 48 | no-repeat; 49 | } 50 | 51 | .indexCtasGitHubButtonWrapper { 52 | display: flex; 53 | } 54 | 55 | .indexCtasGitHubButton { 56 | overflow: hidden; 57 | } 58 | 59 | div[class^="announcementBar_"] { 60 | --site-announcement-bar-stripe-color1: hsl(var(--site-primary-hue-saturation) 85%); 61 | --site-announcement-bar-stripe-color2: hsl(var(--site-primary-hue-saturation) 95%); 62 | background: repeating-linear-gradient( 63 | 35deg, 64 | var(--site-announcement-bar-stripe-color1), 65 | var(--site-announcement-bar-stripe-color1) 20px, 66 | var(--site-announcement-bar-stripe-color2) 10px, 67 | var(--site-announcement-bar-stripe-color2) 40px 68 | ); 69 | font-weight: bold; 70 | } 71 | -------------------------------------------------------------------------------- /website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import clsx from "clsx"; 3 | import Link from "@docusaurus/Link"; 4 | import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; 5 | import Layout from "@theme/Layout"; 6 | import HomepageFeatures from "@site/src/components/HomepageFeatures"; 7 | 8 | import styles from "./index.module.css"; 9 | 10 | function HomepageHeader() { 11 | const { siteConfig } = useDocusaurusContext(); 12 | return ( 13 | 14 | 15 | ✨ {siteConfig.title} ✨ 16 | 21 | 22 | Mnemonic key bindings for VSCode commands ⌨️ 23 | 24 | 25 | 30 | Get Started️ 31 | 32 | 33 | 34 | 35 | ); 36 | } 37 | 38 | export default function Home() { 39 | const { siteConfig } = useDocusaurusContext(); 40 | return ( 41 | 45 | 46 | 47 | 48 | 49 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /website/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | } 12 | 13 | @media screen and (max-width: 996px) { 14 | .heroBanner { 15 | padding: 2rem; 16 | } 17 | } 18 | 19 | .buttons { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | -------------------------------------------------------------------------------- /website/src/pages/pricing.md: -------------------------------------------------------------------------------- 1 | # Pricing 2 | 3 | Just kidding, Glimpse is free and open-source. 💫 4 | 5 | If you want to see Glimpse shine, make your contribution: 6 | 7 | - Tell everyone you like Glimpse on 8 | [Twitter](https://twitter.com/intent/tweet?text=%23GlimpseVSCode%20is%20awesome%21%20Check%20it%20out%20at%20glimpse.ieni.dev), 9 | [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=glimpse.ieni.dev), 10 | etc. with the hashtag `#GlimpseVSCode`. 👯♀️ 11 | - Leave a review on the 12 | [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=ieni.glimpse). 📝 13 | - Star the [GitHub](https://github.com/MarcoIeni/glimpse) repository. ⭐ 14 | - Support Glimpse development, by sponsoring the author on 15 | [GitHub](https://github.com/sponsors/MarcoIeni). ❤️ 16 | - Contribute to the Glimpse project by sharing new 17 | [ideas](https://github.com/MarcoIeni/glimpse/issues) or implementing existing ones. 🚀 18 | 19 | Stay updated on Glimpse news by following the author on 20 | [Twitter](https://twitter.com/MarcoIeni), [GitHub](https://github.com/MarcoIeni), 21 | [LinkedIn](https://linkedin.com/in/MarcoIeni), 22 | [Mastodon](https://hachyderm.io/@MarcoIeni) and [YouTube](https://www.youtube.com/MarcoIeni). 23 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/CNAME: -------------------------------------------------------------------------------- 1 | glimpse.ieni.dev 2 | -------------------------------------------------------------------------------- /website/static/glimpse.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/static/glimpse.mp4 -------------------------------------------------------------------------------- /website/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/static/img/favicon.ico -------------------------------------------------------------------------------- /website/static/img/glimpse-social-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/static/img/glimpse-social-card.png -------------------------------------------------------------------------------- /website/static/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/static/img/icon.png -------------------------------------------------------------------------------- /website/static/img/icon_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcoieni/glimpse/d857229d0d4d0a28658fcd64d8e5a7ebb6241a5e/website/static/img/icon_small.png -------------------------------------------------------------------------------- /website/static/js/posthog.js: -------------------------------------------------------------------------------- 1 | !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys onSessionId".split(" "),n=0;n
f
r
{description}
22 | Mnemonic key bindings for VSCode commands ⌨️ 23 |