├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml └── workflows │ └── release.yml ├── .gitignore ├── .npmrc ├── README.md ├── esbuild.config.mjs ├── main.ts ├── manifest.json ├── package.json ├── pnpm-lock.yaml ├── src ├── Config.ts ├── Gutters.ts ├── LinesState.ts ├── Overlay.ts ├── diagnostics.ts ├── index.ts ├── linebasedstate.ts ├── selections.ts ├── text.ts └── types.ts ├── styles.css ├── tsconfig.json ├── version-bump.mjs └── versions.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_style = tab 9 | indent_size = 4 10 | tab_width = 4 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | npm node_modules 2 | build -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "env": { "node": true }, 5 | "plugins": [ 6 | "@typescript-eslint" 7 | ], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended" 12 | ], 13 | "parserOptions": { 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | "no-unused-vars": "off", 18 | "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], 19 | "@typescript-eslint/ban-ts-comment": "off", 20 | "no-prototype-builtins": "off", 21 | "@typescript-eslint/no-empty-function": "off" 22 | } 23 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Bug]: " 4 | labels: [ "bug" ] 5 | body: 6 | - type: textarea 7 | id: bug-description 8 | attributes: 9 | label: Bug Description 10 | description: A clear and concise description of the bug. 11 | validations: 12 | required: true 13 | - type: textarea 14 | id: screenshot 15 | attributes: 16 | label: Relevant Screenshot 17 | description: If applicable, add screenshots or a screen recording to help explain your problem. 18 | - type: textarea 19 | id: reproduction-steps 20 | attributes: 21 | label: To Reproduce 22 | description: Steps to reproduce the problem 23 | placeholder: | 24 | For example: 25 | 1. Go to '...' 26 | 2. Click on '...' 27 | 3. Scroll down to '...' 28 | - type: input 29 | id: obsi-version 30 | attributes: 31 | label: Obsidian Version 32 | description: You can find the version in the *About* Tab of the settings. 33 | placeholder: 0.13.19 34 | validations: 35 | required: true 36 | - type: checkboxes 37 | id: checklist 38 | attributes: 39 | label: Checklist 40 | options: 41 | - label: I updated to the latest version of the plugin. 42 | required: true 43 | 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea 3 | title: "Feature Request: " 4 | labels: [ "feature request" ] 5 | body: 6 | - type: textarea 7 | id: feature-requested 8 | attributes: 9 | label: Feature Requested 10 | description: A clear and concise description of the feature. 11 | validations: 12 | required: true 13 | - type: textarea 14 | id: screenshot 15 | attributes: 16 | label: Relevant Screenshot 17 | description: If applicable, add screenshots or a screen recording to help explain the request. 18 | - type: checkboxes 19 | id: checklist 20 | attributes: 21 | label: Checklist 22 | options: 23 | - label: The feature would be useful to more users than just me. 24 | required: true 25 | 26 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Obsidian plugin 2 | 3 | on: 4 | release: 5 | types: [ created ] 6 | 7 | env: 8 | PLUGIN_NAME: obsidian-canvas-presentation 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Use Node.js 16 | uses: actions/setup-node@v3 17 | with: 18 | node-version: 16 19 | - name: Build 20 | id: build 21 | run: | 22 | npm install 23 | npm run build 24 | mkdir ${{ env.PLUGIN_NAME }} 25 | cp main.js manifest.json styles.css ${{ env.PLUGIN_NAME }} 26 | zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }} 27 | ls 28 | echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)" 29 | - name: Upload zip file 30 | id: upload-zip 31 | uses: actions/upload-release-asset@v1 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | with: 35 | upload_url: ${{ github.event.release.upload_url }} 36 | asset_path: ./${{ env.PLUGIN_NAME }}.zip 37 | asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip 38 | asset_content_type: application/zip 39 | 40 | - name: Upload main.js 41 | id: upload-main 42 | uses: actions/upload-release-asset@v1 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | with: 46 | upload_url: ${{ github.event.release.upload_url }} 47 | asset_path: ./main.js 48 | asset_name: main.js 49 | asset_content_type: text/javascript 50 | 51 | - name: Upload manifest.json 52 | id: upload-manifest 53 | uses: actions/upload-release-asset@v1 54 | env: 55 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 | with: 57 | upload_url: ${{ github.event.release.upload_url }} 58 | asset_path: ./manifest.json 59 | asset_name: manifest.json 60 | asset_content_type: application/json 61 | 62 | - name: Upload styles.css 63 | id: upload-css 64 | uses: actions/upload-release-asset@v1 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | with: 68 | upload_url: ${{ github.event.release.upload_url }} 69 | asset_path: ./styles.css 70 | asset_name: styles.css 71 | asset_content_type: text/css 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # vscode 2 | .vscode 3 | 4 | # Intellij 5 | *.iml 6 | .idea 7 | 8 | # npm 9 | node_modules 10 | 11 | # Don't include the compiled main.js file in the repo. 12 | # They should be uploaded to GitHub releases instead. 13 | main.js 14 | 15 | # Exclude sourcemaps 16 | *.map 17 | 18 | # obsidian 19 | data.json 20 | 21 | # Exclude macOS Finder (System Explorer) View States 22 | .DS_Store 23 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | tag-version-prefix="" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Note Minimap 2 | 3 | - Based on package: https://github.com/replit/codemirror-minimap 4 | -------------------------------------------------------------------------------- /esbuild.config.mjs: -------------------------------------------------------------------------------- 1 | import esbuild from "esbuild"; 2 | import process from "process"; 3 | import builtins from 'builtin-modules' 4 | 5 | const banner = 6 | `/* 7 | THIS IS A GENERATED/BUNDLED FILE BY ESBUILD 8 | if you want to view the source, please visit the github repository of this plugin 9 | */ 10 | `; 11 | 12 | const prod = (process.argv[2] === 'production'); 13 | 14 | esbuild.build({ 15 | banner: { 16 | js: banner, 17 | }, 18 | entryPoints: ['main.ts'], 19 | bundle: true, 20 | external: [ 21 | 'obsidian', 22 | 'electron', 23 | '@codemirror/autocomplete', 24 | '@codemirror/collab', 25 | '@codemirror/commands', 26 | '@codemirror/language', 27 | '@codemirror/lint', 28 | '@codemirror/search', 29 | '@codemirror/state', 30 | '@codemirror/view', 31 | '@lezer/common', 32 | '@lezer/highlight', 33 | '@lezer/lr', 34 | ...builtins], 35 | format: 'cjs', 36 | watch: !prod, 37 | target: 'es2018', 38 | logLevel: "info", 39 | sourcemap: prod ? false : 'inline', 40 | treeShaking: true, 41 | outfile: 'main.js', 42 | }).catch(() => process.exit(1)); 43 | -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from 'obsidian'; 2 | import { showMinimap } from "./src"; 3 | 4 | export default class MyPlugin extends Plugin { 5 | 6 | async onload() { 7 | this.registerEditorExtension([ 8 | showMinimap.compute(['doc'], (state) => { 9 | let create = () => { 10 | const dom = createEl('div'); 11 | return {dom}; 12 | }; 13 | 14 | return { 15 | create, 16 | /* optional */ 17 | displayText: 'blocks', 18 | showOverlay: 'always', 19 | gutters: [{1: '#00FF00', 2: '#00FF00'}], 20 | }; 21 | }) 22 | ]); 23 | } 24 | 25 | onunload() { 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "minimap", 3 | "name": "Minimap", 4 | "version": "0.0.1", 5 | "minAppVersion": "0.15.0", 6 | "description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.", 7 | "author": "Boninall", 8 | "authorUrl": "https://github.com/Quorafind", 9 | "fundingUrl": { 10 | "Buy Me a Coffee": "https://www.buymeacoffee.com/boninall", 11 | "爱发电": "https://afdian.net/a/boninall", 12 | "支付宝": "https://cdn.jsdelivr.net/gh/Quorafind/.github@main/IMAGE/%E6%94%AF%E4%BB%98%E5%AE%9D%E4%BB%98%E6%AC%BE%E7%A0%81.jpg" 13 | }, 14 | "isDesktopOnly": false 15 | } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minimap", 3 | "version": "0.0.1", 4 | "description": "This is a sample plugin for Obsidian (https://obsidian.md)", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "node esbuild.config.mjs", 8 | "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", 9 | "version": "node version-bump.mjs && git add manifest.json versions.json" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "@codemirror/autocomplete": "^6.0.0", 16 | "@codemirror/basic-setup": "^0.20.0", 17 | "@codemirror/commands": "^6.0.0", 18 | "@codemirror/lang-css": "^6.0.0", 19 | "@codemirror/lang-html": "^6.0.0", 20 | "@codemirror/language": "https://github.com/lishid/cm-language", 21 | "@codemirror/lint": "^6.0.0", 22 | "@codemirror/rangeset": "^0.19.1", 23 | "@codemirror/search": "^6.0.0", 24 | "@codemirror/state": "^6.0.0", 25 | "@codemirror/stream-parser": "https://github.com/lishid/stream-parser", 26 | "@codemirror/view": "^6.0.0", 27 | "@lezer/common": "^1.2.1", 28 | "@lezer/highlight": "^1.2.0", 29 | "@types/node": "^16.11.6", 30 | "@typescript-eslint/eslint-plugin": "5.29.0", 31 | "@typescript-eslint/parser": "5.29.0", 32 | "builtin-modules": "3.3.0", 33 | "codemirror": "^6.0.0", 34 | "crelt": "^1.0.6", 35 | "esbuild": "0.14.47", 36 | "obsidian": "latest", 37 | "tslib": "2.4.0", 38 | "typescript": "4.7.4" 39 | }, 40 | "dependencies": { 41 | "@replit/codemirror-minimap": "^0.5.2" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@replit/codemirror-minimap': 9 | specifier: ^0.5.2 10 | version: 0.5.2(@codemirror/language@6.10.1)(@codemirror/lint@6.5.0)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0) 11 | 12 | devDependencies: 13 | '@codemirror/autocomplete': 14 | specifier: ^6.0.0 15 | version: 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1) 16 | '@codemirror/basic-setup': 17 | specifier: ^0.20.0 18 | version: 0.20.0 19 | '@codemirror/commands': 20 | specifier: ^6.0.0 21 | version: 6.3.3 22 | '@codemirror/lang-css': 23 | specifier: ^6.0.0 24 | version: 6.2.1(@codemirror/view@6.26.3) 25 | '@codemirror/lang-html': 26 | specifier: ^6.0.0 27 | version: 6.4.9 28 | '@codemirror/language': 29 | specifier: https://github.com/lishid/cm-language 30 | version: git@github.com+lishid/cm-language/2644bfc27afda707a7e1f3aedaf3ca7120f63cd9 31 | '@codemirror/lint': 32 | specifier: ^6.0.0 33 | version: 6.5.0 34 | '@codemirror/rangeset': 35 | specifier: ^0.19.1 36 | version: 0.19.9 37 | '@codemirror/search': 38 | specifier: ^6.0.0 39 | version: 6.5.6 40 | '@codemirror/state': 41 | specifier: ^6.0.0 42 | version: 6.4.1 43 | '@codemirror/stream-parser': 44 | specifier: https://github.com/lishid/stream-parser 45 | version: git@github.com+lishid/stream-parser/26c8edae7bdf63dc34d358d1de640bdd12e7b09f 46 | '@codemirror/view': 47 | specifier: ^6.0.0 48 | version: 6.26.3 49 | '@lezer/common': 50 | specifier: ^1.2.1 51 | version: 1.2.1 52 | '@lezer/highlight': 53 | specifier: ^1.2.0 54 | version: 1.2.0 55 | '@types/node': 56 | specifier: ^16.11.6 57 | version: 16.18.96 58 | '@typescript-eslint/eslint-plugin': 59 | specifier: 5.29.0 60 | version: 5.29.0(@typescript-eslint/parser@5.29.0)(eslint@8.57.0)(typescript@4.7.4) 61 | '@typescript-eslint/parser': 62 | specifier: 5.29.0 63 | version: 5.29.0(eslint@8.57.0)(typescript@4.7.4) 64 | builtin-modules: 65 | specifier: 3.3.0 66 | version: 3.3.0 67 | codemirror: 68 | specifier: ^6.0.0 69 | version: 6.0.1(@lezer/common@1.2.1) 70 | crelt: 71 | specifier: ^1.0.6 72 | version: 1.0.6 73 | esbuild: 74 | specifier: 0.14.47 75 | version: 0.14.47 76 | obsidian: 77 | specifier: latest 78 | version: 1.5.7-1(@codemirror/state@6.4.1)(@codemirror/view@6.26.3) 79 | tslib: 80 | specifier: 2.4.0 81 | version: 2.4.0 82 | typescript: 83 | specifier: 4.7.4 84 | version: 4.7.4 85 | 86 | packages: 87 | 88 | /@aashutoshrathi/word-wrap@1.2.6: 89 | resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} 90 | engines: {node: '>=0.10.0'} 91 | dev: true 92 | 93 | /@codemirror/autocomplete@0.20.3: 94 | resolution: {integrity: sha512-lYB+NPGP+LEzAudkWhLfMxhTrxtLILGl938w+RcFrGdrIc54A+UgmCoz+McE3IYRFp4xyQcL4uFJwo+93YdgHw==} 95 | dependencies: 96 | '@codemirror/language': 0.20.2 97 | '@codemirror/state': 0.20.1 98 | '@codemirror/view': 0.20.7 99 | '@lezer/common': 0.16.1 100 | dev: true 101 | 102 | /@codemirror/autocomplete@6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1): 103 | resolution: {integrity: sha512-P/LeCTtZHRTCU4xQsa89vSKWecYv1ZqwzOd5topheGRf+qtacFgBeIMQi3eL8Kt/BUNvxUWkx+5qP2jlGoARrg==} 104 | peerDependencies: 105 | '@codemirror/language': ^6.0.0 106 | '@codemirror/state': ^6.0.0 107 | '@codemirror/view': ^6.0.0 108 | '@lezer/common': ^1.0.0 109 | dependencies: 110 | '@codemirror/language': git@github.com+lishid/cm-language/2644bfc27afda707a7e1f3aedaf3ca7120f63cd9 111 | '@codemirror/state': 6.4.1 112 | '@codemirror/view': 6.26.3 113 | '@lezer/common': 1.2.1 114 | dev: true 115 | 116 | /@codemirror/basic-setup@0.20.0: 117 | resolution: {integrity: sha512-W/ERKMLErWkrVLyP5I8Yh8PXl4r+WFNkdYVSzkXYPQv2RMPSkWpr2BgggiSJ8AHF/q3GuApncDD8I4BZz65fyg==} 118 | deprecated: In version 6.0, this package has been renamed to just 'codemirror' 119 | dependencies: 120 | '@codemirror/autocomplete': 0.20.3 121 | '@codemirror/commands': 0.20.0 122 | '@codemirror/language': 0.20.2 123 | '@codemirror/lint': 0.20.3 124 | '@codemirror/search': 0.20.1 125 | '@codemirror/state': 0.20.1 126 | '@codemirror/view': 0.20.7 127 | dev: true 128 | 129 | /@codemirror/commands@0.20.0: 130 | resolution: {integrity: sha512-v9L5NNVA+A9R6zaFvaTbxs30kc69F6BkOoiEbeFw4m4I0exmDEKBILN6mK+GksJtvTzGBxvhAPlVFTdQW8GB7Q==} 131 | dependencies: 132 | '@codemirror/language': 0.20.2 133 | '@codemirror/state': 0.20.1 134 | '@codemirror/view': 0.20.7 135 | '@lezer/common': 0.16.1 136 | dev: true 137 | 138 | /@codemirror/commands@6.3.3: 139 | resolution: {integrity: sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==} 140 | dependencies: 141 | '@codemirror/language': 6.10.1 142 | '@codemirror/state': 6.4.1 143 | '@codemirror/view': 6.26.3 144 | '@lezer/common': 1.2.1 145 | dev: true 146 | 147 | /@codemirror/lang-css@6.2.1(@codemirror/view@6.26.3): 148 | resolution: {integrity: sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==} 149 | dependencies: 150 | '@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1) 151 | '@codemirror/language': 6.10.1 152 | '@codemirror/state': 6.4.1 153 | '@lezer/common': 1.2.1 154 | '@lezer/css': 1.1.8 155 | transitivePeerDependencies: 156 | - '@codemirror/view' 157 | dev: true 158 | 159 | /@codemirror/lang-html@6.4.9: 160 | resolution: {integrity: sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==} 161 | dependencies: 162 | '@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1) 163 | '@codemirror/lang-css': 6.2.1(@codemirror/view@6.26.3) 164 | '@codemirror/lang-javascript': 6.2.2 165 | '@codemirror/language': 6.10.1 166 | '@codemirror/state': 6.4.1 167 | '@codemirror/view': 6.26.3 168 | '@lezer/common': 1.2.1 169 | '@lezer/css': 1.1.8 170 | '@lezer/html': 1.3.9 171 | dev: true 172 | 173 | /@codemirror/lang-javascript@6.2.2: 174 | resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==} 175 | dependencies: 176 | '@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1) 177 | '@codemirror/language': 6.10.1 178 | '@codemirror/lint': 6.5.0 179 | '@codemirror/state': 6.4.1 180 | '@codemirror/view': 6.26.3 181 | '@lezer/common': 1.2.1 182 | '@lezer/javascript': 1.4.14 183 | dev: true 184 | 185 | /@codemirror/language@0.19.10: 186 | resolution: {integrity: sha512-yA0DZ3RYn2CqAAGW62VrU8c4YxscMQn45y/I9sjBlqB1e2OTQLg4CCkMBuMSLXk4xaqjlsgazeOQWaJQOKfV8Q==} 187 | dependencies: 188 | '@codemirror/state': 0.19.9 189 | '@codemirror/text': 0.19.6 190 | '@codemirror/view': 0.19.48 191 | '@lezer/common': 0.15.12 192 | '@lezer/lr': 0.15.8 193 | dev: true 194 | 195 | /@codemirror/language@0.20.2: 196 | resolution: {integrity: sha512-WB3Bnuusw0xhVvhBocieYKwJm04SOk5bPoOEYksVHKHcGHFOaYaw+eZVxR4gIqMMcGzOIUil0FsCmFk8yrhHpw==} 197 | dependencies: 198 | '@codemirror/state': 0.20.1 199 | '@codemirror/view': 0.20.7 200 | '@lezer/common': 0.16.1 201 | '@lezer/highlight': 0.16.0 202 | '@lezer/lr': 0.16.3 203 | style-mod: 4.1.2 204 | dev: true 205 | 206 | /@codemirror/language@6.10.1: 207 | resolution: {integrity: sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==} 208 | dependencies: 209 | '@codemirror/state': 6.4.1 210 | '@codemirror/view': 6.26.3 211 | '@lezer/common': 1.2.1 212 | '@lezer/highlight': 1.2.0 213 | '@lezer/lr': 1.4.0 214 | style-mod: 4.1.2 215 | dev: true 216 | 217 | /@codemirror/lint@0.20.3: 218 | resolution: {integrity: sha512-06xUScbbspZ8mKoODQCEx6hz1bjaq9m8W8DxdycWARMiiX1wMtfCh/MoHpaL7ws/KUMwlsFFfp2qhm32oaCvVA==} 219 | dependencies: 220 | '@codemirror/state': 0.20.1 221 | '@codemirror/view': 0.20.7 222 | crelt: 1.0.6 223 | dev: true 224 | 225 | /@codemirror/lint@6.5.0: 226 | resolution: {integrity: sha512-+5YyicIaaAZKU8K43IQi8TBy6mF6giGeWAH7N96Z5LC30Wm5JMjqxOYIE9mxwMG1NbhT2mA3l9hA4uuKUM3E5g==} 227 | dependencies: 228 | '@codemirror/state': 6.4.1 229 | '@codemirror/view': 6.26.3 230 | crelt: 1.0.6 231 | 232 | /@codemirror/rangeset@0.19.9: 233 | resolution: {integrity: sha512-V8YUuOvK+ew87Xem+71nKcqu1SXd5QROMRLMS/ljT5/3MCxtgrRie1Cvild0G/Z2f1fpWxzX78V0U4jjXBorBQ==} 234 | deprecated: As of 0.20.0, this package has been merged into @codemirror/state 235 | dependencies: 236 | '@codemirror/state': 0.19.9 237 | dev: true 238 | 239 | /@codemirror/search@0.20.1: 240 | resolution: {integrity: sha512-ROe6gRboQU5E4z6GAkNa2kxhXqsGNbeLEisbvzbOeB7nuDYXUZ70vGIgmqPu0tB+1M3F9yWk6W8k2vrFpJaD4Q==} 241 | dependencies: 242 | '@codemirror/state': 0.20.1 243 | '@codemirror/view': 0.20.7 244 | crelt: 1.0.6 245 | dev: true 246 | 247 | /@codemirror/search@6.5.6: 248 | resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} 249 | dependencies: 250 | '@codemirror/state': 6.4.1 251 | '@codemirror/view': 6.26.3 252 | crelt: 1.0.6 253 | dev: true 254 | 255 | /@codemirror/state@0.19.9: 256 | resolution: {integrity: sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw==} 257 | dependencies: 258 | '@codemirror/text': 0.19.6 259 | dev: true 260 | 261 | /@codemirror/state@0.20.1: 262 | resolution: {integrity: sha512-ms0tlV5A02OK0pFvTtSUGMLkoarzh1F8mr6jy1cD7ucSC2X/VLHtQCxfhdSEGqTYlQF2hoZtmLv+amqhdgbwjQ==} 263 | dev: true 264 | 265 | /@codemirror/state@6.4.1: 266 | resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} 267 | 268 | /@codemirror/text@0.19.6: 269 | resolution: {integrity: sha512-T9jnREMIygx+TPC1bOuepz18maGq/92q2a+n4qTqObKwvNMg+8cMTslb8yxeEDEq7S3kpgGWxgO1UWbQRij0dA==} 270 | deprecated: As of 0.20.0, this package has been merged into @codemirror/state 271 | dev: true 272 | 273 | /@codemirror/view@0.19.48: 274 | resolution: {integrity: sha512-0eg7D2Nz4S8/caetCTz61rK0tkHI17V/d15Jy0kLOT8dTLGGNJUponDnW28h2B6bERmPlVHKh8MJIr5OCp1nGw==} 275 | dependencies: 276 | '@codemirror/rangeset': 0.19.9 277 | '@codemirror/state': 0.19.9 278 | '@codemirror/text': 0.19.6 279 | style-mod: 4.1.2 280 | w3c-keyname: 2.2.8 281 | dev: true 282 | 283 | /@codemirror/view@0.20.7: 284 | resolution: {integrity: sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ==} 285 | dependencies: 286 | '@codemirror/state': 0.20.1 287 | style-mod: 4.1.2 288 | w3c-keyname: 2.2.8 289 | dev: true 290 | 291 | /@codemirror/view@6.26.3: 292 | resolution: {integrity: sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==} 293 | dependencies: 294 | '@codemirror/state': 6.4.1 295 | style-mod: 4.1.2 296 | w3c-keyname: 2.2.8 297 | 298 | /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): 299 | resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} 300 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 301 | peerDependencies: 302 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 303 | dependencies: 304 | eslint: 8.57.0 305 | eslint-visitor-keys: 3.4.3 306 | dev: true 307 | 308 | /@eslint-community/regexpp@4.10.0: 309 | resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} 310 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 311 | dev: true 312 | 313 | /@eslint/eslintrc@2.1.4: 314 | resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} 315 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 316 | dependencies: 317 | ajv: 6.12.6 318 | debug: 4.3.4 319 | espree: 9.6.1 320 | globals: 13.24.0 321 | ignore: 5.3.1 322 | import-fresh: 3.3.0 323 | js-yaml: 4.1.0 324 | minimatch: 3.1.2 325 | strip-json-comments: 3.1.1 326 | transitivePeerDependencies: 327 | - supports-color 328 | dev: true 329 | 330 | /@eslint/js@8.57.0: 331 | resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} 332 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 333 | dev: true 334 | 335 | /@humanwhocodes/config-array@0.11.14: 336 | resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} 337 | engines: {node: '>=10.10.0'} 338 | dependencies: 339 | '@humanwhocodes/object-schema': 2.0.3 340 | debug: 4.3.4 341 | minimatch: 3.1.2 342 | transitivePeerDependencies: 343 | - supports-color 344 | dev: true 345 | 346 | /@humanwhocodes/module-importer@1.0.1: 347 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 348 | engines: {node: '>=12.22'} 349 | dev: true 350 | 351 | /@humanwhocodes/object-schema@2.0.3: 352 | resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} 353 | dev: true 354 | 355 | /@lezer/common@0.15.12: 356 | resolution: {integrity: sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==} 357 | dev: true 358 | 359 | /@lezer/common@0.16.1: 360 | resolution: {integrity: sha512-qPmG7YTZ6lATyTOAWf8vXE+iRrt1NJd4cm2nJHK+v7X9TsOF6+HtuU/ctaZy2RCrluxDb89hI6KWQ5LfQGQWuA==} 361 | dev: true 362 | 363 | /@lezer/common@1.2.1: 364 | resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==} 365 | 366 | /@lezer/css@1.1.8: 367 | resolution: {integrity: sha512-7JhxupKuMBaWQKjQoLtzhGj83DdnZY9MckEOG5+/iLKNK2ZJqKc6hf6uc0HjwCX7Qlok44jBNqZhHKDhEhZYLA==} 368 | dependencies: 369 | '@lezer/common': 1.2.1 370 | '@lezer/highlight': 1.2.0 371 | '@lezer/lr': 1.4.0 372 | dev: true 373 | 374 | /@lezer/highlight@0.16.0: 375 | resolution: {integrity: sha512-iE5f4flHlJ1g1clOStvXNLbORJoiW4Kytso6ubfYzHnaNo/eo5SKhxs4wv/rtvwZQeZrK3we8S9SyA7OGOoRKQ==} 376 | dependencies: 377 | '@lezer/common': 0.16.1 378 | dev: true 379 | 380 | /@lezer/highlight@1.2.0: 381 | resolution: {integrity: sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==} 382 | dependencies: 383 | '@lezer/common': 1.2.1 384 | 385 | /@lezer/html@1.3.9: 386 | resolution: {integrity: sha512-MXxeCMPyrcemSLGaTQEZx0dBUH0i+RPl8RN5GwMAzo53nTsd/Unc/t5ZxACeQoyPUM5/GkPLRUs2WliOImzkRA==} 387 | dependencies: 388 | '@lezer/common': 1.2.1 389 | '@lezer/highlight': 1.2.0 390 | '@lezer/lr': 1.4.0 391 | dev: true 392 | 393 | /@lezer/javascript@1.4.14: 394 | resolution: {integrity: sha512-GEdUyspTRgc5dwIGebUk+f3BekvqEWVIYsIuAC3pA8e8wcikGwBZRWRa450L0s8noGWuULwnmi4yjxTnYz9PpA==} 395 | dependencies: 396 | '@lezer/common': 1.2.1 397 | '@lezer/highlight': 1.2.0 398 | '@lezer/lr': 1.4.0 399 | dev: true 400 | 401 | /@lezer/lr@0.15.8: 402 | resolution: {integrity: sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==} 403 | dependencies: 404 | '@lezer/common': 0.15.12 405 | dev: true 406 | 407 | /@lezer/lr@0.16.3: 408 | resolution: {integrity: sha512-pau7um4eAw94BEuuShUIeQDTf3k4Wt6oIUOYxMmkZgDHdqtIcxWND4LRxi8nI9KuT4I1bXQv67BCapkxt7Ywqw==} 409 | dependencies: 410 | '@lezer/common': 0.16.1 411 | dev: true 412 | 413 | /@lezer/lr@1.4.0: 414 | resolution: {integrity: sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==} 415 | dependencies: 416 | '@lezer/common': 1.2.1 417 | 418 | /@nodelib/fs.scandir@2.1.5: 419 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 420 | engines: {node: '>= 8'} 421 | dependencies: 422 | '@nodelib/fs.stat': 2.0.5 423 | run-parallel: 1.2.0 424 | dev: true 425 | 426 | /@nodelib/fs.stat@2.0.5: 427 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 428 | engines: {node: '>= 8'} 429 | dev: true 430 | 431 | /@nodelib/fs.walk@1.2.8: 432 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 433 | engines: {node: '>= 8'} 434 | dependencies: 435 | '@nodelib/fs.scandir': 2.1.5 436 | fastq: 1.17.1 437 | dev: true 438 | 439 | /@replit/codemirror-minimap@0.5.2(@codemirror/language@6.10.1)(@codemirror/lint@6.5.0)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0): 440 | resolution: {integrity: sha512-eNAtpr0hOG09/5zqAQ5PkgZEb3V/MHi30zentCxiR73r+utR2m9yVMCpBmfsWbb8mWxUWhMGPiHxM5hFtnscQA==} 441 | peerDependencies: 442 | '@codemirror/language': ^6.9.1 443 | '@codemirror/lint': ^6.4.2 444 | '@codemirror/state': ^6.3.1 445 | '@codemirror/view': ^6.21.3 446 | '@lezer/common': ^1.1.0 447 | '@lezer/highlight': ^1.1.6 448 | dependencies: 449 | '@codemirror/language': git@github.com+lishid/cm-language/2644bfc27afda707a7e1f3aedaf3ca7120f63cd9 450 | '@codemirror/lint': 6.5.0 451 | '@codemirror/state': 6.4.1 452 | '@codemirror/view': 6.26.3 453 | '@lezer/common': 1.2.1 454 | '@lezer/highlight': 1.2.0 455 | crelt: 1.0.6 456 | dev: false 457 | 458 | /@types/codemirror@5.60.8: 459 | resolution: {integrity: sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==} 460 | dependencies: 461 | '@types/tern': 0.23.9 462 | dev: true 463 | 464 | /@types/estree@1.0.5: 465 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 466 | dev: true 467 | 468 | /@types/json-schema@7.0.15: 469 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 470 | dev: true 471 | 472 | /@types/node@16.18.96: 473 | resolution: {integrity: sha512-84iSqGXoO+Ha16j8pRZ/L90vDMKX04QTYMTfYeE1WrjWaZXuchBehGUZEpNgx7JnmlrIHdnABmpjrQjhCnNldQ==} 474 | dev: true 475 | 476 | /@types/tern@0.23.9: 477 | resolution: {integrity: sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==} 478 | dependencies: 479 | '@types/estree': 1.0.5 480 | dev: true 481 | 482 | /@typescript-eslint/eslint-plugin@5.29.0(@typescript-eslint/parser@5.29.0)(eslint@8.57.0)(typescript@4.7.4): 483 | resolution: {integrity: sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==} 484 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 485 | peerDependencies: 486 | '@typescript-eslint/parser': ^5.0.0 487 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 488 | typescript: '*' 489 | peerDependenciesMeta: 490 | typescript: 491 | optional: true 492 | dependencies: 493 | '@typescript-eslint/parser': 5.29.0(eslint@8.57.0)(typescript@4.7.4) 494 | '@typescript-eslint/scope-manager': 5.29.0 495 | '@typescript-eslint/type-utils': 5.29.0(eslint@8.57.0)(typescript@4.7.4) 496 | '@typescript-eslint/utils': 5.29.0(eslint@8.57.0)(typescript@4.7.4) 497 | debug: 4.3.4 498 | eslint: 8.57.0 499 | functional-red-black-tree: 1.0.1 500 | ignore: 5.3.1 501 | regexpp: 3.2.0 502 | semver: 7.6.0 503 | tsutils: 3.21.0(typescript@4.7.4) 504 | typescript: 4.7.4 505 | transitivePeerDependencies: 506 | - supports-color 507 | dev: true 508 | 509 | /@typescript-eslint/parser@5.29.0(eslint@8.57.0)(typescript@4.7.4): 510 | resolution: {integrity: sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==} 511 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 512 | peerDependencies: 513 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 514 | typescript: '*' 515 | peerDependenciesMeta: 516 | typescript: 517 | optional: true 518 | dependencies: 519 | '@typescript-eslint/scope-manager': 5.29.0 520 | '@typescript-eslint/types': 5.29.0 521 | '@typescript-eslint/typescript-estree': 5.29.0(typescript@4.7.4) 522 | debug: 4.3.4 523 | eslint: 8.57.0 524 | typescript: 4.7.4 525 | transitivePeerDependencies: 526 | - supports-color 527 | dev: true 528 | 529 | /@typescript-eslint/scope-manager@5.29.0: 530 | resolution: {integrity: sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==} 531 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 532 | dependencies: 533 | '@typescript-eslint/types': 5.29.0 534 | '@typescript-eslint/visitor-keys': 5.29.0 535 | dev: true 536 | 537 | /@typescript-eslint/type-utils@5.29.0(eslint@8.57.0)(typescript@4.7.4): 538 | resolution: {integrity: sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==} 539 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 540 | peerDependencies: 541 | eslint: '*' 542 | typescript: '*' 543 | peerDependenciesMeta: 544 | typescript: 545 | optional: true 546 | dependencies: 547 | '@typescript-eslint/utils': 5.29.0(eslint@8.57.0)(typescript@4.7.4) 548 | debug: 4.3.4 549 | eslint: 8.57.0 550 | tsutils: 3.21.0(typescript@4.7.4) 551 | typescript: 4.7.4 552 | transitivePeerDependencies: 553 | - supports-color 554 | dev: true 555 | 556 | /@typescript-eslint/types@5.29.0: 557 | resolution: {integrity: sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==} 558 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 559 | dev: true 560 | 561 | /@typescript-eslint/typescript-estree@5.29.0(typescript@4.7.4): 562 | resolution: {integrity: sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==} 563 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 564 | peerDependencies: 565 | typescript: '*' 566 | peerDependenciesMeta: 567 | typescript: 568 | optional: true 569 | dependencies: 570 | '@typescript-eslint/types': 5.29.0 571 | '@typescript-eslint/visitor-keys': 5.29.0 572 | debug: 4.3.4 573 | globby: 11.1.0 574 | is-glob: 4.0.3 575 | semver: 7.6.0 576 | tsutils: 3.21.0(typescript@4.7.4) 577 | typescript: 4.7.4 578 | transitivePeerDependencies: 579 | - supports-color 580 | dev: true 581 | 582 | /@typescript-eslint/utils@5.29.0(eslint@8.57.0)(typescript@4.7.4): 583 | resolution: {integrity: sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==} 584 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 585 | peerDependencies: 586 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 587 | dependencies: 588 | '@types/json-schema': 7.0.15 589 | '@typescript-eslint/scope-manager': 5.29.0 590 | '@typescript-eslint/types': 5.29.0 591 | '@typescript-eslint/typescript-estree': 5.29.0(typescript@4.7.4) 592 | eslint: 8.57.0 593 | eslint-scope: 5.1.1 594 | eslint-utils: 3.0.0(eslint@8.57.0) 595 | transitivePeerDependencies: 596 | - supports-color 597 | - typescript 598 | dev: true 599 | 600 | /@typescript-eslint/visitor-keys@5.29.0: 601 | resolution: {integrity: sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==} 602 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 603 | dependencies: 604 | '@typescript-eslint/types': 5.29.0 605 | eslint-visitor-keys: 3.4.3 606 | dev: true 607 | 608 | /@ungap/structured-clone@1.2.0: 609 | resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} 610 | dev: true 611 | 612 | /acorn-jsx@5.3.2(acorn@8.11.3): 613 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 614 | peerDependencies: 615 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 616 | dependencies: 617 | acorn: 8.11.3 618 | dev: true 619 | 620 | /acorn@8.11.3: 621 | resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} 622 | engines: {node: '>=0.4.0'} 623 | hasBin: true 624 | dev: true 625 | 626 | /ajv@6.12.6: 627 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 628 | dependencies: 629 | fast-deep-equal: 3.1.3 630 | fast-json-stable-stringify: 2.1.0 631 | json-schema-traverse: 0.4.1 632 | uri-js: 4.4.1 633 | dev: true 634 | 635 | /ansi-regex@5.0.1: 636 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 637 | engines: {node: '>=8'} 638 | dev: true 639 | 640 | /ansi-styles@4.3.0: 641 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 642 | engines: {node: '>=8'} 643 | dependencies: 644 | color-convert: 2.0.1 645 | dev: true 646 | 647 | /argparse@2.0.1: 648 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 649 | dev: true 650 | 651 | /array-union@2.1.0: 652 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 653 | engines: {node: '>=8'} 654 | dev: true 655 | 656 | /balanced-match@1.0.2: 657 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 658 | dev: true 659 | 660 | /brace-expansion@1.1.11: 661 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 662 | dependencies: 663 | balanced-match: 1.0.2 664 | concat-map: 0.0.1 665 | dev: true 666 | 667 | /braces@3.0.2: 668 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 669 | engines: {node: '>=8'} 670 | dependencies: 671 | fill-range: 7.0.1 672 | dev: true 673 | 674 | /builtin-modules@3.3.0: 675 | resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} 676 | engines: {node: '>=6'} 677 | dev: true 678 | 679 | /callsites@3.1.0: 680 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 681 | engines: {node: '>=6'} 682 | dev: true 683 | 684 | /chalk@4.1.2: 685 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 686 | engines: {node: '>=10'} 687 | dependencies: 688 | ansi-styles: 4.3.0 689 | supports-color: 7.2.0 690 | dev: true 691 | 692 | /codemirror@6.0.1(@lezer/common@1.2.1): 693 | resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} 694 | dependencies: 695 | '@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1) 696 | '@codemirror/commands': 6.3.3 697 | '@codemirror/language': 6.10.1 698 | '@codemirror/lint': 6.5.0 699 | '@codemirror/search': 6.5.6 700 | '@codemirror/state': 6.4.1 701 | '@codemirror/view': 6.26.3 702 | transitivePeerDependencies: 703 | - '@lezer/common' 704 | dev: true 705 | 706 | /color-convert@2.0.1: 707 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 708 | engines: {node: '>=7.0.0'} 709 | dependencies: 710 | color-name: 1.1.4 711 | dev: true 712 | 713 | /color-name@1.1.4: 714 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 715 | dev: true 716 | 717 | /concat-map@0.0.1: 718 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 719 | dev: true 720 | 721 | /crelt@1.0.6: 722 | resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} 723 | 724 | /cross-spawn@7.0.3: 725 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 726 | engines: {node: '>= 8'} 727 | dependencies: 728 | path-key: 3.1.1 729 | shebang-command: 2.0.0 730 | which: 2.0.2 731 | dev: true 732 | 733 | /debug@4.3.4: 734 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 735 | engines: {node: '>=6.0'} 736 | peerDependencies: 737 | supports-color: '*' 738 | peerDependenciesMeta: 739 | supports-color: 740 | optional: true 741 | dependencies: 742 | ms: 2.1.2 743 | dev: true 744 | 745 | /deep-is@0.1.4: 746 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 747 | dev: true 748 | 749 | /dir-glob@3.0.1: 750 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 751 | engines: {node: '>=8'} 752 | dependencies: 753 | path-type: 4.0.0 754 | dev: true 755 | 756 | /doctrine@3.0.0: 757 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} 758 | engines: {node: '>=6.0.0'} 759 | dependencies: 760 | esutils: 2.0.3 761 | dev: true 762 | 763 | /esbuild-android-64@0.14.47: 764 | resolution: {integrity: sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==} 765 | engines: {node: '>=12'} 766 | cpu: [x64] 767 | os: [android] 768 | requiresBuild: true 769 | dev: true 770 | optional: true 771 | 772 | /esbuild-android-arm64@0.14.47: 773 | resolution: {integrity: sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==} 774 | engines: {node: '>=12'} 775 | cpu: [arm64] 776 | os: [android] 777 | requiresBuild: true 778 | dev: true 779 | optional: true 780 | 781 | /esbuild-darwin-64@0.14.47: 782 | resolution: {integrity: sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==} 783 | engines: {node: '>=12'} 784 | cpu: [x64] 785 | os: [darwin] 786 | requiresBuild: true 787 | dev: true 788 | optional: true 789 | 790 | /esbuild-darwin-arm64@0.14.47: 791 | resolution: {integrity: sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==} 792 | engines: {node: '>=12'} 793 | cpu: [arm64] 794 | os: [darwin] 795 | requiresBuild: true 796 | dev: true 797 | optional: true 798 | 799 | /esbuild-freebsd-64@0.14.47: 800 | resolution: {integrity: sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==} 801 | engines: {node: '>=12'} 802 | cpu: [x64] 803 | os: [freebsd] 804 | requiresBuild: true 805 | dev: true 806 | optional: true 807 | 808 | /esbuild-freebsd-arm64@0.14.47: 809 | resolution: {integrity: sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==} 810 | engines: {node: '>=12'} 811 | cpu: [arm64] 812 | os: [freebsd] 813 | requiresBuild: true 814 | dev: true 815 | optional: true 816 | 817 | /esbuild-linux-32@0.14.47: 818 | resolution: {integrity: sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==} 819 | engines: {node: '>=12'} 820 | cpu: [ia32] 821 | os: [linux] 822 | requiresBuild: true 823 | dev: true 824 | optional: true 825 | 826 | /esbuild-linux-64@0.14.47: 827 | resolution: {integrity: sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==} 828 | engines: {node: '>=12'} 829 | cpu: [x64] 830 | os: [linux] 831 | requiresBuild: true 832 | dev: true 833 | optional: true 834 | 835 | /esbuild-linux-arm64@0.14.47: 836 | resolution: {integrity: sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==} 837 | engines: {node: '>=12'} 838 | cpu: [arm64] 839 | os: [linux] 840 | requiresBuild: true 841 | dev: true 842 | optional: true 843 | 844 | /esbuild-linux-arm@0.14.47: 845 | resolution: {integrity: sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==} 846 | engines: {node: '>=12'} 847 | cpu: [arm] 848 | os: [linux] 849 | requiresBuild: true 850 | dev: true 851 | optional: true 852 | 853 | /esbuild-linux-mips64le@0.14.47: 854 | resolution: {integrity: sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==} 855 | engines: {node: '>=12'} 856 | cpu: [mips64el] 857 | os: [linux] 858 | requiresBuild: true 859 | dev: true 860 | optional: true 861 | 862 | /esbuild-linux-ppc64le@0.14.47: 863 | resolution: {integrity: sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==} 864 | engines: {node: '>=12'} 865 | cpu: [ppc64] 866 | os: [linux] 867 | requiresBuild: true 868 | dev: true 869 | optional: true 870 | 871 | /esbuild-linux-riscv64@0.14.47: 872 | resolution: {integrity: sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==} 873 | engines: {node: '>=12'} 874 | cpu: [riscv64] 875 | os: [linux] 876 | requiresBuild: true 877 | dev: true 878 | optional: true 879 | 880 | /esbuild-linux-s390x@0.14.47: 881 | resolution: {integrity: sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==} 882 | engines: {node: '>=12'} 883 | cpu: [s390x] 884 | os: [linux] 885 | requiresBuild: true 886 | dev: true 887 | optional: true 888 | 889 | /esbuild-netbsd-64@0.14.47: 890 | resolution: {integrity: sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==} 891 | engines: {node: '>=12'} 892 | cpu: [x64] 893 | os: [netbsd] 894 | requiresBuild: true 895 | dev: true 896 | optional: true 897 | 898 | /esbuild-openbsd-64@0.14.47: 899 | resolution: {integrity: sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==} 900 | engines: {node: '>=12'} 901 | cpu: [x64] 902 | os: [openbsd] 903 | requiresBuild: true 904 | dev: true 905 | optional: true 906 | 907 | /esbuild-sunos-64@0.14.47: 908 | resolution: {integrity: sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==} 909 | engines: {node: '>=12'} 910 | cpu: [x64] 911 | os: [sunos] 912 | requiresBuild: true 913 | dev: true 914 | optional: true 915 | 916 | /esbuild-windows-32@0.14.47: 917 | resolution: {integrity: sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==} 918 | engines: {node: '>=12'} 919 | cpu: [ia32] 920 | os: [win32] 921 | requiresBuild: true 922 | dev: true 923 | optional: true 924 | 925 | /esbuild-windows-64@0.14.47: 926 | resolution: {integrity: sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==} 927 | engines: {node: '>=12'} 928 | cpu: [x64] 929 | os: [win32] 930 | requiresBuild: true 931 | dev: true 932 | optional: true 933 | 934 | /esbuild-windows-arm64@0.14.47: 935 | resolution: {integrity: sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==} 936 | engines: {node: '>=12'} 937 | cpu: [arm64] 938 | os: [win32] 939 | requiresBuild: true 940 | dev: true 941 | optional: true 942 | 943 | /esbuild@0.14.47: 944 | resolution: {integrity: sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==} 945 | engines: {node: '>=12'} 946 | hasBin: true 947 | requiresBuild: true 948 | optionalDependencies: 949 | esbuild-android-64: 0.14.47 950 | esbuild-android-arm64: 0.14.47 951 | esbuild-darwin-64: 0.14.47 952 | esbuild-darwin-arm64: 0.14.47 953 | esbuild-freebsd-64: 0.14.47 954 | esbuild-freebsd-arm64: 0.14.47 955 | esbuild-linux-32: 0.14.47 956 | esbuild-linux-64: 0.14.47 957 | esbuild-linux-arm: 0.14.47 958 | esbuild-linux-arm64: 0.14.47 959 | esbuild-linux-mips64le: 0.14.47 960 | esbuild-linux-ppc64le: 0.14.47 961 | esbuild-linux-riscv64: 0.14.47 962 | esbuild-linux-s390x: 0.14.47 963 | esbuild-netbsd-64: 0.14.47 964 | esbuild-openbsd-64: 0.14.47 965 | esbuild-sunos-64: 0.14.47 966 | esbuild-windows-32: 0.14.47 967 | esbuild-windows-64: 0.14.47 968 | esbuild-windows-arm64: 0.14.47 969 | dev: true 970 | 971 | /escape-string-regexp@4.0.0: 972 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 973 | engines: {node: '>=10'} 974 | dev: true 975 | 976 | /eslint-scope@5.1.1: 977 | resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} 978 | engines: {node: '>=8.0.0'} 979 | dependencies: 980 | esrecurse: 4.3.0 981 | estraverse: 4.3.0 982 | dev: true 983 | 984 | /eslint-scope@7.2.2: 985 | resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} 986 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 987 | dependencies: 988 | esrecurse: 4.3.0 989 | estraverse: 5.3.0 990 | dev: true 991 | 992 | /eslint-utils@3.0.0(eslint@8.57.0): 993 | resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} 994 | engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} 995 | peerDependencies: 996 | eslint: '>=5' 997 | dependencies: 998 | eslint: 8.57.0 999 | eslint-visitor-keys: 2.1.0 1000 | dev: true 1001 | 1002 | /eslint-visitor-keys@2.1.0: 1003 | resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} 1004 | engines: {node: '>=10'} 1005 | dev: true 1006 | 1007 | /eslint-visitor-keys@3.4.3: 1008 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 1009 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1010 | dev: true 1011 | 1012 | /eslint@8.57.0: 1013 | resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} 1014 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1015 | hasBin: true 1016 | dependencies: 1017 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) 1018 | '@eslint-community/regexpp': 4.10.0 1019 | '@eslint/eslintrc': 2.1.4 1020 | '@eslint/js': 8.57.0 1021 | '@humanwhocodes/config-array': 0.11.14 1022 | '@humanwhocodes/module-importer': 1.0.1 1023 | '@nodelib/fs.walk': 1.2.8 1024 | '@ungap/structured-clone': 1.2.0 1025 | ajv: 6.12.6 1026 | chalk: 4.1.2 1027 | cross-spawn: 7.0.3 1028 | debug: 4.3.4 1029 | doctrine: 3.0.0 1030 | escape-string-regexp: 4.0.0 1031 | eslint-scope: 7.2.2 1032 | eslint-visitor-keys: 3.4.3 1033 | espree: 9.6.1 1034 | esquery: 1.5.0 1035 | esutils: 2.0.3 1036 | fast-deep-equal: 3.1.3 1037 | file-entry-cache: 6.0.1 1038 | find-up: 5.0.0 1039 | glob-parent: 6.0.2 1040 | globals: 13.24.0 1041 | graphemer: 1.4.0 1042 | ignore: 5.3.1 1043 | imurmurhash: 0.1.4 1044 | is-glob: 4.0.3 1045 | is-path-inside: 3.0.3 1046 | js-yaml: 4.1.0 1047 | json-stable-stringify-without-jsonify: 1.0.1 1048 | levn: 0.4.1 1049 | lodash.merge: 4.6.2 1050 | minimatch: 3.1.2 1051 | natural-compare: 1.4.0 1052 | optionator: 0.9.3 1053 | strip-ansi: 6.0.1 1054 | text-table: 0.2.0 1055 | transitivePeerDependencies: 1056 | - supports-color 1057 | dev: true 1058 | 1059 | /espree@9.6.1: 1060 | resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} 1061 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1062 | dependencies: 1063 | acorn: 8.11.3 1064 | acorn-jsx: 5.3.2(acorn@8.11.3) 1065 | eslint-visitor-keys: 3.4.3 1066 | dev: true 1067 | 1068 | /esquery@1.5.0: 1069 | resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} 1070 | engines: {node: '>=0.10'} 1071 | dependencies: 1072 | estraverse: 5.3.0 1073 | dev: true 1074 | 1075 | /esrecurse@4.3.0: 1076 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 1077 | engines: {node: '>=4.0'} 1078 | dependencies: 1079 | estraverse: 5.3.0 1080 | dev: true 1081 | 1082 | /estraverse@4.3.0: 1083 | resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} 1084 | engines: {node: '>=4.0'} 1085 | dev: true 1086 | 1087 | /estraverse@5.3.0: 1088 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 1089 | engines: {node: '>=4.0'} 1090 | dev: true 1091 | 1092 | /esutils@2.0.3: 1093 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 1094 | engines: {node: '>=0.10.0'} 1095 | dev: true 1096 | 1097 | /fast-deep-equal@3.1.3: 1098 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1099 | dev: true 1100 | 1101 | /fast-glob@3.3.2: 1102 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} 1103 | engines: {node: '>=8.6.0'} 1104 | dependencies: 1105 | '@nodelib/fs.stat': 2.0.5 1106 | '@nodelib/fs.walk': 1.2.8 1107 | glob-parent: 5.1.2 1108 | merge2: 1.4.1 1109 | micromatch: 4.0.5 1110 | dev: true 1111 | 1112 | /fast-json-stable-stringify@2.1.0: 1113 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 1114 | dev: true 1115 | 1116 | /fast-levenshtein@2.0.6: 1117 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 1118 | dev: true 1119 | 1120 | /fastq@1.17.1: 1121 | resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} 1122 | dependencies: 1123 | reusify: 1.0.4 1124 | dev: true 1125 | 1126 | /file-entry-cache@6.0.1: 1127 | resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} 1128 | engines: {node: ^10.12.0 || >=12.0.0} 1129 | dependencies: 1130 | flat-cache: 3.2.0 1131 | dev: true 1132 | 1133 | /fill-range@7.0.1: 1134 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 1135 | engines: {node: '>=8'} 1136 | dependencies: 1137 | to-regex-range: 5.0.1 1138 | dev: true 1139 | 1140 | /find-up@5.0.0: 1141 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 1142 | engines: {node: '>=10'} 1143 | dependencies: 1144 | locate-path: 6.0.0 1145 | path-exists: 4.0.0 1146 | dev: true 1147 | 1148 | /flat-cache@3.2.0: 1149 | resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} 1150 | engines: {node: ^10.12.0 || >=12.0.0} 1151 | dependencies: 1152 | flatted: 3.3.1 1153 | keyv: 4.5.4 1154 | rimraf: 3.0.2 1155 | dev: true 1156 | 1157 | /flatted@3.3.1: 1158 | resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} 1159 | dev: true 1160 | 1161 | /fs.realpath@1.0.0: 1162 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1163 | dev: true 1164 | 1165 | /functional-red-black-tree@1.0.1: 1166 | resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} 1167 | dev: true 1168 | 1169 | /glob-parent@5.1.2: 1170 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1171 | engines: {node: '>= 6'} 1172 | dependencies: 1173 | is-glob: 4.0.3 1174 | dev: true 1175 | 1176 | /glob-parent@6.0.2: 1177 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 1178 | engines: {node: '>=10.13.0'} 1179 | dependencies: 1180 | is-glob: 4.0.3 1181 | dev: true 1182 | 1183 | /glob@7.2.3: 1184 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1185 | dependencies: 1186 | fs.realpath: 1.0.0 1187 | inflight: 1.0.6 1188 | inherits: 2.0.4 1189 | minimatch: 3.1.2 1190 | once: 1.4.0 1191 | path-is-absolute: 1.0.1 1192 | dev: true 1193 | 1194 | /globals@13.24.0: 1195 | resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} 1196 | engines: {node: '>=8'} 1197 | dependencies: 1198 | type-fest: 0.20.2 1199 | dev: true 1200 | 1201 | /globby@11.1.0: 1202 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 1203 | engines: {node: '>=10'} 1204 | dependencies: 1205 | array-union: 2.1.0 1206 | dir-glob: 3.0.1 1207 | fast-glob: 3.3.2 1208 | ignore: 5.3.1 1209 | merge2: 1.4.1 1210 | slash: 3.0.0 1211 | dev: true 1212 | 1213 | /graphemer@1.4.0: 1214 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 1215 | dev: true 1216 | 1217 | /has-flag@4.0.0: 1218 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1219 | engines: {node: '>=8'} 1220 | dev: true 1221 | 1222 | /ignore@5.3.1: 1223 | resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} 1224 | engines: {node: '>= 4'} 1225 | dev: true 1226 | 1227 | /import-fresh@3.3.0: 1228 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 1229 | engines: {node: '>=6'} 1230 | dependencies: 1231 | parent-module: 1.0.1 1232 | resolve-from: 4.0.0 1233 | dev: true 1234 | 1235 | /imurmurhash@0.1.4: 1236 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1237 | engines: {node: '>=0.8.19'} 1238 | dev: true 1239 | 1240 | /inflight@1.0.6: 1241 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1242 | dependencies: 1243 | once: 1.4.0 1244 | wrappy: 1.0.2 1245 | dev: true 1246 | 1247 | /inherits@2.0.4: 1248 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1249 | dev: true 1250 | 1251 | /is-extglob@2.1.1: 1252 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1253 | engines: {node: '>=0.10.0'} 1254 | dev: true 1255 | 1256 | /is-glob@4.0.3: 1257 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1258 | engines: {node: '>=0.10.0'} 1259 | dependencies: 1260 | is-extglob: 2.1.1 1261 | dev: true 1262 | 1263 | /is-number@7.0.0: 1264 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1265 | engines: {node: '>=0.12.0'} 1266 | dev: true 1267 | 1268 | /is-path-inside@3.0.3: 1269 | resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} 1270 | engines: {node: '>=8'} 1271 | dev: true 1272 | 1273 | /isexe@2.0.0: 1274 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1275 | dev: true 1276 | 1277 | /js-yaml@4.1.0: 1278 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 1279 | hasBin: true 1280 | dependencies: 1281 | argparse: 2.0.1 1282 | dev: true 1283 | 1284 | /json-buffer@3.0.1: 1285 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 1286 | dev: true 1287 | 1288 | /json-schema-traverse@0.4.1: 1289 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1290 | dev: true 1291 | 1292 | /json-stable-stringify-without-jsonify@1.0.1: 1293 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1294 | dev: true 1295 | 1296 | /keyv@4.5.4: 1297 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 1298 | dependencies: 1299 | json-buffer: 3.0.1 1300 | dev: true 1301 | 1302 | /levn@0.4.1: 1303 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1304 | engines: {node: '>= 0.8.0'} 1305 | dependencies: 1306 | prelude-ls: 1.2.1 1307 | type-check: 0.4.0 1308 | dev: true 1309 | 1310 | /locate-path@6.0.0: 1311 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 1312 | engines: {node: '>=10'} 1313 | dependencies: 1314 | p-locate: 5.0.0 1315 | dev: true 1316 | 1317 | /lodash.merge@4.6.2: 1318 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 1319 | dev: true 1320 | 1321 | /lru-cache@6.0.0: 1322 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1323 | engines: {node: '>=10'} 1324 | dependencies: 1325 | yallist: 4.0.0 1326 | dev: true 1327 | 1328 | /merge2@1.4.1: 1329 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1330 | engines: {node: '>= 8'} 1331 | dev: true 1332 | 1333 | /micromatch@4.0.5: 1334 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 1335 | engines: {node: '>=8.6'} 1336 | dependencies: 1337 | braces: 3.0.2 1338 | picomatch: 2.3.1 1339 | dev: true 1340 | 1341 | /minimatch@3.1.2: 1342 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1343 | dependencies: 1344 | brace-expansion: 1.1.11 1345 | dev: true 1346 | 1347 | /moment@2.29.4: 1348 | resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} 1349 | dev: true 1350 | 1351 | /ms@2.1.2: 1352 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1353 | dev: true 1354 | 1355 | /natural-compare@1.4.0: 1356 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1357 | dev: true 1358 | 1359 | /obsidian@1.5.7-1(@codemirror/state@6.4.1)(@codemirror/view@6.26.3): 1360 | resolution: {integrity: sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng==} 1361 | peerDependencies: 1362 | '@codemirror/state': ^6.0.0 1363 | '@codemirror/view': ^6.0.0 1364 | dependencies: 1365 | '@codemirror/state': 6.4.1 1366 | '@codemirror/view': 6.26.3 1367 | '@types/codemirror': 5.60.8 1368 | moment: 2.29.4 1369 | dev: true 1370 | 1371 | /once@1.4.0: 1372 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1373 | dependencies: 1374 | wrappy: 1.0.2 1375 | dev: true 1376 | 1377 | /optionator@0.9.3: 1378 | resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} 1379 | engines: {node: '>= 0.8.0'} 1380 | dependencies: 1381 | '@aashutoshrathi/word-wrap': 1.2.6 1382 | deep-is: 0.1.4 1383 | fast-levenshtein: 2.0.6 1384 | levn: 0.4.1 1385 | prelude-ls: 1.2.1 1386 | type-check: 0.4.0 1387 | dev: true 1388 | 1389 | /p-limit@3.1.0: 1390 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1391 | engines: {node: '>=10'} 1392 | dependencies: 1393 | yocto-queue: 0.1.0 1394 | dev: true 1395 | 1396 | /p-locate@5.0.0: 1397 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1398 | engines: {node: '>=10'} 1399 | dependencies: 1400 | p-limit: 3.1.0 1401 | dev: true 1402 | 1403 | /parent-module@1.0.1: 1404 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1405 | engines: {node: '>=6'} 1406 | dependencies: 1407 | callsites: 3.1.0 1408 | dev: true 1409 | 1410 | /path-exists@4.0.0: 1411 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1412 | engines: {node: '>=8'} 1413 | dev: true 1414 | 1415 | /path-is-absolute@1.0.1: 1416 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 1417 | engines: {node: '>=0.10.0'} 1418 | dev: true 1419 | 1420 | /path-key@3.1.1: 1421 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1422 | engines: {node: '>=8'} 1423 | dev: true 1424 | 1425 | /path-type@4.0.0: 1426 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 1427 | engines: {node: '>=8'} 1428 | dev: true 1429 | 1430 | /picomatch@2.3.1: 1431 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1432 | engines: {node: '>=8.6'} 1433 | dev: true 1434 | 1435 | /prelude-ls@1.2.1: 1436 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1437 | engines: {node: '>= 0.8.0'} 1438 | dev: true 1439 | 1440 | /punycode@2.3.1: 1441 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1442 | engines: {node: '>=6'} 1443 | dev: true 1444 | 1445 | /queue-microtask@1.2.3: 1446 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1447 | dev: true 1448 | 1449 | /regexpp@3.2.0: 1450 | resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} 1451 | engines: {node: '>=8'} 1452 | dev: true 1453 | 1454 | /resolve-from@4.0.0: 1455 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1456 | engines: {node: '>=4'} 1457 | dev: true 1458 | 1459 | /reusify@1.0.4: 1460 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1461 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1462 | dev: true 1463 | 1464 | /rimraf@3.0.2: 1465 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1466 | hasBin: true 1467 | dependencies: 1468 | glob: 7.2.3 1469 | dev: true 1470 | 1471 | /run-parallel@1.2.0: 1472 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1473 | dependencies: 1474 | queue-microtask: 1.2.3 1475 | dev: true 1476 | 1477 | /semver@7.6.0: 1478 | resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} 1479 | engines: {node: '>=10'} 1480 | hasBin: true 1481 | dependencies: 1482 | lru-cache: 6.0.0 1483 | dev: true 1484 | 1485 | /shebang-command@2.0.0: 1486 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1487 | engines: {node: '>=8'} 1488 | dependencies: 1489 | shebang-regex: 3.0.0 1490 | dev: true 1491 | 1492 | /shebang-regex@3.0.0: 1493 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1494 | engines: {node: '>=8'} 1495 | dev: true 1496 | 1497 | /slash@3.0.0: 1498 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 1499 | engines: {node: '>=8'} 1500 | dev: true 1501 | 1502 | /strip-ansi@6.0.1: 1503 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1504 | engines: {node: '>=8'} 1505 | dependencies: 1506 | ansi-regex: 5.0.1 1507 | dev: true 1508 | 1509 | /strip-json-comments@3.1.1: 1510 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1511 | engines: {node: '>=8'} 1512 | dev: true 1513 | 1514 | /style-mod@4.1.2: 1515 | resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} 1516 | 1517 | /supports-color@7.2.0: 1518 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1519 | engines: {node: '>=8'} 1520 | dependencies: 1521 | has-flag: 4.0.0 1522 | dev: true 1523 | 1524 | /text-table@0.2.0: 1525 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 1526 | dev: true 1527 | 1528 | /to-regex-range@5.0.1: 1529 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1530 | engines: {node: '>=8.0'} 1531 | dependencies: 1532 | is-number: 7.0.0 1533 | dev: true 1534 | 1535 | /tslib@1.14.1: 1536 | resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} 1537 | dev: true 1538 | 1539 | /tslib@2.4.0: 1540 | resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} 1541 | dev: true 1542 | 1543 | /tsutils@3.21.0(typescript@4.7.4): 1544 | resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} 1545 | engines: {node: '>= 6'} 1546 | peerDependencies: 1547 | typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' 1548 | dependencies: 1549 | tslib: 1.14.1 1550 | typescript: 4.7.4 1551 | dev: true 1552 | 1553 | /type-check@0.4.0: 1554 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1555 | engines: {node: '>= 0.8.0'} 1556 | dependencies: 1557 | prelude-ls: 1.2.1 1558 | dev: true 1559 | 1560 | /type-fest@0.20.2: 1561 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} 1562 | engines: {node: '>=10'} 1563 | dev: true 1564 | 1565 | /typescript@4.7.4: 1566 | resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==} 1567 | engines: {node: '>=4.2.0'} 1568 | hasBin: true 1569 | dev: true 1570 | 1571 | /uri-js@4.4.1: 1572 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1573 | dependencies: 1574 | punycode: 2.3.1 1575 | dev: true 1576 | 1577 | /w3c-keyname@2.2.8: 1578 | resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} 1579 | 1580 | /which@2.0.2: 1581 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1582 | engines: {node: '>= 8'} 1583 | hasBin: true 1584 | dependencies: 1585 | isexe: 2.0.0 1586 | dev: true 1587 | 1588 | /wrappy@1.0.2: 1589 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1590 | dev: true 1591 | 1592 | /yallist@4.0.0: 1593 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1594 | dev: true 1595 | 1596 | /yocto-queue@0.1.0: 1597 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1598 | engines: {node: '>=10'} 1599 | dev: true 1600 | 1601 | git@github.com+lishid/cm-language/2644bfc27afda707a7e1f3aedaf3ca7120f63cd9: 1602 | resolution: {commit: 2644bfc27afda707a7e1f3aedaf3ca7120f63cd9, repo: git@github.com:lishid/cm-language.git, type: git} 1603 | name: '@codemirror/language' 1604 | version: 6.10.1 1605 | prepare: true 1606 | requiresBuild: true 1607 | dependencies: 1608 | '@codemirror/state': 6.4.1 1609 | '@codemirror/view': 6.26.3 1610 | '@lezer/common': 1.2.1 1611 | '@lezer/highlight': 1.2.0 1612 | '@lezer/lr': 1.4.0 1613 | style-mod: 4.1.2 1614 | 1615 | git@github.com+lishid/stream-parser/26c8edae7bdf63dc34d358d1de640bdd12e7b09f: 1616 | resolution: {commit: 26c8edae7bdf63dc34d358d1de640bdd12e7b09f, repo: git@github.com:lishid/stream-parser.git, type: git} 1617 | name: '@codemirror/stream-parser' 1618 | version: 0.19.6 1619 | prepare: true 1620 | requiresBuild: true 1621 | dependencies: 1622 | '@codemirror/language': 0.19.10 1623 | '@codemirror/state': 0.19.9 1624 | '@codemirror/text': 0.19.6 1625 | '@lezer/common': 0.15.12 1626 | '@lezer/lr': 0.15.8 1627 | dev: true 1628 | -------------------------------------------------------------------------------- /src/Config.ts: -------------------------------------------------------------------------------- 1 | import { Facet, combineConfig } from "@codemirror/state"; 2 | import { DOMEventMap, EditorView } from "@codemirror/view"; 3 | import { MinimapConfig } from "."; 4 | import { Gutter } from "./Gutters"; 5 | 6 | type EventHandler = ( 7 | e: DOMEventMap[event], 8 | v: EditorView 9 | ) => void; 10 | 11 | type Options = { 12 | /** 13 | * Controls whether the minimap should be hidden on mouseout. 14 | * Defaults to `false`. 15 | */ 16 | autohide?: boolean; 17 | 18 | enabled: boolean; 19 | 20 | /** 21 | * Determines how to render text. Defaults to `characters`. 22 | */ 23 | displayText?: "blocks" | "characters"; 24 | 25 | /** 26 | * Attach event handlers to the minimap container element. 27 | */ 28 | eventHandlers?: { 29 | [event in keyof DOMEventMap]?: EventHandler; 30 | }; 31 | 32 | /** 33 | * The overlay shows the portion of the file currently in the viewport. 34 | * Defaults to `always`. 35 | */ 36 | showOverlay?: "always" | "mouse-over"; 37 | 38 | /** 39 | * Enables a gutter to be drawn on the given line to the left 40 | * of the minimap, with the given color. Accepts all valid CSS 41 | * color values. 42 | */ 43 | gutters?: Array; 44 | }; 45 | 46 | const Config = Facet.define>({ 47 | combine: (c) => { 48 | const configs: Array = []; 49 | for (let config of c) { 50 | if (!config) { 51 | continue; 52 | } 53 | 54 | const {create, gutters, ...rest} = config; 55 | 56 | configs.push({ 57 | ...rest, 58 | enabled: true, 59 | gutters: gutters 60 | ? gutters.filter((v) => Object.keys(v).length > 0) 61 | : undefined, 62 | }); 63 | } 64 | 65 | return combineConfig(configs, { 66 | enabled: configs.length > 0, 67 | displayText: "characters", 68 | eventHandlers: {}, 69 | showOverlay: "always", 70 | gutters: [], 71 | autohide: false, 72 | }); 73 | }, 74 | }); 75 | 76 | const Scale = { 77 | // Multiply the number of canvas pixels 78 | PixelMultiplier: 2, 79 | // Downscale the editor contents by this ratio 80 | SizeRatio: 4, 81 | // Maximum width of the minimap in pixels 82 | MaxWidth: 120, 83 | } as const; 84 | 85 | // @ts-ignore 86 | export { Config, Options, Scale }; 87 | -------------------------------------------------------------------------------- /src/Gutters.ts: -------------------------------------------------------------------------------- 1 | import { DrawContext } from "./types"; 2 | 3 | const GUTTER_WIDTH = 4; 4 | 5 | type Line = number; 6 | type Color = string; 7 | export type Gutter = Record; 8 | 9 | 10 | /** 11 | * Draws a gutter to the canvas context for the given line number 12 | */ 13 | function drawLineGutter(gutter: Record, ctx: DrawContext, lineNumber: number) { 14 | const color = gutter[lineNumber]; 15 | if (!color) { 16 | return; 17 | } 18 | 19 | ctx.context.fillStyle = color; 20 | ctx.context.globalAlpha = 1; 21 | ctx.context.beginPath(); 22 | ctx.context.rect(ctx.offsetX, ctx.offsetY, GUTTER_WIDTH, ctx.lineHeight); 23 | ctx.context.fill(); 24 | } 25 | 26 | 27 | export { GUTTER_WIDTH, drawLineGutter }; 28 | -------------------------------------------------------------------------------- /src/LinesState.ts: -------------------------------------------------------------------------------- 1 | import { foldEffect, foldedRanges, unfoldEffect } from "@codemirror/language"; 2 | import { StateField, EditorState, Transaction } from "@codemirror/state"; 3 | import { Config } from "./Config"; 4 | 5 | type Span = { from: number; to: number; folded: boolean }; 6 | type Line = Array; 7 | type Lines = Array; 8 | 9 | function computeLinesState(state: EditorState): Lines { 10 | console.log(state.facet(Config)); 11 | if (!state.facet(Config).enabled) { 12 | return []; 13 | } 14 | 15 | const lines: Lines = []; 16 | 17 | const lineCursor = state.doc.iterLines(); 18 | const foldedRangeCursor = foldedRanges(state).iter(); 19 | 20 | let textOffset = 0; 21 | lineCursor.next(); 22 | 23 | while (!lineCursor.done) { 24 | const lineText = lineCursor.value; 25 | let from = textOffset; 26 | let to = from + lineText.length; 27 | 28 | // Iterate through folded ranges until we're at or past the current line 29 | while (foldedRangeCursor.value && foldedRangeCursor.to < from) { 30 | foldedRangeCursor.next(); 31 | } 32 | const {from: foldFrom, to: foldTo} = foldedRangeCursor; 33 | 34 | const lineStartInFold = from >= foldFrom && from < foldTo; 35 | const lineEndsInFold = to > foldFrom && to <= foldTo; 36 | 37 | if (lineStartInFold) { 38 | let lastLine = lines.pop() ?? []; 39 | let lastRange = lastLine.pop(); 40 | 41 | // If the last range is folded, we extend the folded range 42 | if (lastRange && lastRange.folded) { 43 | lastRange.to = foldTo; 44 | } 45 | 46 | // If we popped the last range, add it back 47 | if (lastRange) { 48 | lastLine.push(lastRange); 49 | } 50 | 51 | // If we didn't have a previous range, or the previous range wasn't folded add a new range 52 | if (!lastRange || !lastRange.folded) { 53 | lastLine.push({from: foldFrom, to: foldTo, folded: true}); 54 | } 55 | 56 | // If the line doesn't end in a fold, we add another token for the unfolded section 57 | if (!lineEndsInFold) { 58 | lastLine.push({from: foldTo, to, folded: false}); 59 | } 60 | 61 | lines.push(lastLine); 62 | } else if (lineEndsInFold) { 63 | lines.push([ 64 | {from, to: foldFrom, folded: false}, 65 | {from: foldFrom, to: foldTo, folded: true}, 66 | ]); 67 | } else { 68 | lines.push([{from, to, folded: false}]); 69 | } 70 | 71 | textOffset = to + 1; 72 | lineCursor.next(); 73 | } 74 | 75 | return lines; 76 | } 77 | 78 | const LinesState = StateField.define({ 79 | create: (state) => computeLinesState(state), 80 | update: (current, tr) => { 81 | if (foldsChanged([tr]) || tr.docChanged) { 82 | return computeLinesState(tr.state); 83 | } 84 | 85 | return current; 86 | }, 87 | }); 88 | 89 | /** Returns if the folds have changed in this update */ 90 | function foldsChanged(transactions: readonly Transaction[]) { 91 | return transactions.find((tr) => 92 | tr.effects.find((ef) => ef.is(foldEffect) || ef.is(unfoldEffect)) 93 | ); 94 | } 95 | 96 | // @ts-ignore 97 | export { foldsChanged, LinesState, Lines }; 98 | -------------------------------------------------------------------------------- /src/Overlay.ts: -------------------------------------------------------------------------------- 1 | import { EditorView, ViewPlugin, ViewUpdate } from "@codemirror/view"; 2 | import { Config, Scale } from "./Config"; 3 | import crelt from "crelt"; 4 | 5 | const Theme = EditorView.theme({ 6 | ".cm-minimap-overlay-container": { 7 | position: "absolute", 8 | top: 0, 9 | height: "100%", 10 | width: "100%", 11 | "&.cm-minimap-overlay-mouse-over": { 12 | opacity: 0, 13 | transition: "visibility 0s linear 300ms, opacity 300ms", 14 | }, 15 | "&.cm-minimap-overlay-mouse-over:hover": { 16 | opacity: 1, 17 | transition: "visibility 0s linear 0ms, opacity 300ms", 18 | }, 19 | "&.cm-minimap-overlay-off": { 20 | display: "none", 21 | }, 22 | "& .cm-minimap-overlay": { 23 | background: "var(--background-modifier-border-focus)", 24 | opacity: "0.2", 25 | position: "absolute", 26 | right: 0, 27 | top: 0, 28 | width: "100%", 29 | transition: "top 0s ease-in 0ms", 30 | "&:hover": { 31 | opacity: "0.3", 32 | }, 33 | }, 34 | "&.cm-minimap-overlay-active": { 35 | opacity: 1, 36 | visibility: "visible", 37 | transition: "visibility 0s linear 0ms, opacity 300ms", 38 | "& .cm-minimap-overlay": { 39 | opacity: "0.4", 40 | }, 41 | }, 42 | }, 43 | }); 44 | 45 | const SCALE = Scale.PixelMultiplier * Scale.SizeRatio; 46 | 47 | const OverlayView = ViewPlugin.fromClass( 48 | class { 49 | private container: HTMLElement | undefined; 50 | private dom: HTMLElement | undefined; 51 | 52 | private _isDragging: boolean = false; 53 | private _dragStartY: number | undefined; 54 | 55 | public constructor(private view: EditorView) { 56 | if (view.state.facet(Config).enabled) { 57 | this.create(view); 58 | } 59 | } 60 | 61 | private create(view: EditorView) { 62 | this.container = crelt("div", {class: "cm-minimap-overlay-container"}); 63 | this.dom = crelt("div", {class: "cm-minimap-overlay"}); 64 | this.container.appendChild(this.dom); 65 | 66 | // Attach event listeners for overlay 67 | this.container.addEventListener("mousedown", this.onMouseDown.bind(this)); 68 | window.addEventListener("mouseup", this.onMouseUp.bind(this)); 69 | window.addEventListener("mousemove", this.onMouseMove.bind(this)); 70 | 71 | // Attach the overlay elements to the minimap 72 | const inner = view.dom.querySelector(".cm-minimap-inner"); 73 | if (inner) { 74 | inner.appendChild(this.container); 75 | } 76 | 77 | // Initially set overlay configuration styles, height, top 78 | this.computeShowOverlay(); 79 | this.computeHeight(); 80 | this.computeTop(); 81 | } 82 | 83 | private remove() { 84 | if (this.container) { 85 | this.container.removeEventListener("mousedown", this.onMouseDown); 86 | window.removeEventListener("mouseup", this.onMouseUp); 87 | window.removeEventListener("mousemove", this.onMouseMove); 88 | this.container.remove(); 89 | } 90 | } 91 | 92 | update(update: ViewUpdate) { 93 | const prev = update.startState.facet(Config).enabled; 94 | const now = update.state.facet(Config).enabled; 95 | 96 | if (prev && !now) { 97 | this.remove(); 98 | return; 99 | } 100 | 101 | if (!prev && now) { 102 | this.create(update.view); 103 | } 104 | 105 | if (now) { 106 | this.computeShowOverlay(); 107 | 108 | if (update.geometryChanged) { 109 | this.computeHeight(); 110 | this.computeTop(); 111 | } 112 | } 113 | } 114 | 115 | public computeHeight() { 116 | if (!this.dom) { 117 | return; 118 | } 119 | 120 | const height = this.view.dom.clientHeight / SCALE; 121 | this.dom.style.height = height + "px"; 122 | } 123 | 124 | public computeTop() { 125 | if (!this._isDragging && this.dom) { 126 | const {clientHeight, scrollHeight, scrollTop} = this.view.scrollDOM; 127 | 128 | const maxScrollTop = scrollHeight - clientHeight; 129 | const topForNonOverflowing = scrollTop / SCALE; 130 | 131 | const height = clientHeight / SCALE; 132 | const maxTop = clientHeight - height; 133 | let scrollRatio = scrollTop / maxScrollTop; 134 | if (isNaN(scrollRatio)) scrollRatio = 0; 135 | const topForOverflowing = maxTop * scrollRatio; 136 | 137 | const top = Math.min(topForOverflowing, topForNonOverflowing); 138 | this.dom.style.top = top + "px"; 139 | } 140 | } 141 | 142 | public computeShowOverlay() { 143 | if (!this.container) { 144 | return; 145 | } 146 | 147 | const {showOverlay} = this.view.state.facet(Config); 148 | 149 | if (showOverlay === "mouse-over") { 150 | this.container.classList.add("cm-minimap-overlay-mouse-over"); 151 | } else { 152 | this.container.classList.remove("cm-minimap-overlay-mouse-over"); 153 | } 154 | 155 | const {clientHeight, scrollHeight} = this.view.scrollDOM; 156 | if (clientHeight === scrollHeight) { 157 | this.container.classList.add("cm-minimap-overlay-off"); 158 | } else { 159 | this.container.classList.remove("cm-minimap-overlay-off"); 160 | } 161 | } 162 | 163 | private onMouseDown(event: MouseEvent) { 164 | if (!this.container) { 165 | return; 166 | } 167 | 168 | // Ignore right click 169 | if (event.button === 2) { 170 | return; 171 | } 172 | 173 | // If target is the overlay start dragging 174 | const {clientY, target} = event; 175 | if (target === this.dom) { 176 | this._dragStartY = event.clientY; 177 | this._isDragging = true; 178 | this.container.classList.add("cm-minimap-overlay-active"); 179 | return; 180 | } 181 | 182 | // Updates the scroll position of the EditorView based on the 183 | // position of the MouseEvent on the minimap canvas 184 | const {clientHeight, scrollHeight, scrollTop} = this.view.scrollDOM; 185 | const targetTop = (target as HTMLElement).getBoundingClientRect().top; 186 | const deltaY = (clientY - targetTop) * SCALE; 187 | 188 | const scrollRatio = scrollTop / (scrollHeight - clientHeight); 189 | const visibleRange = clientHeight * SCALE - clientHeight; 190 | const visibleTop = visibleRange * scrollRatio; 191 | 192 | const top = Math.max(0, scrollTop - visibleTop); 193 | this.view.scrollDOM.scrollTop = top + deltaY - clientHeight / 2; 194 | } 195 | 196 | private onMouseUp(_event: MouseEvent) { 197 | // Stop dragging on mouseup 198 | if (this._isDragging && this.container) { 199 | this._dragStartY = undefined; 200 | this._isDragging = false; 201 | this.container.classList.remove("cm-minimap-overlay-active"); 202 | } 203 | } 204 | 205 | private onMouseMove(event: MouseEvent) { 206 | if (!this._isDragging || !this.dom) { 207 | return; 208 | } 209 | 210 | event.preventDefault(); 211 | event.stopPropagation(); 212 | 213 | // Without an existing position, we're just beginning to drag. 214 | if (!this._dragStartY) { 215 | this._dragStartY = event.clientY; 216 | return; 217 | } 218 | 219 | const deltaY = event.clientY - this._dragStartY; 220 | const movingUp = deltaY < 0; 221 | const movingDown = deltaY > 0; 222 | 223 | // Update drag position for the next tick 224 | this._dragStartY = event.clientY; 225 | 226 | const canvasHeight = this.dom.getBoundingClientRect().height; 227 | const canvasAbsTop = this.dom.getBoundingClientRect().y; 228 | const canvasAbsBot = canvasAbsTop + canvasHeight; 229 | const canvasRelTopDouble = parseFloat(this.dom.style.top); 230 | 231 | const scrollPosition = this.view.scrollDOM.scrollTop; 232 | const editorHeight = this.view.scrollDOM.clientHeight; 233 | const contentHeight = this.view.scrollDOM.scrollHeight; 234 | 235 | const atTop = scrollPosition === 0; 236 | const atBottom = 237 | Math.round(scrollPosition) >= Math.round(contentHeight - editorHeight); 238 | 239 | // We allow over-dragging past the top/bottom, but the overlay just sticks 240 | // to the top or bottom of its range. These checks prevent us from immediately 241 | // moving the overlay when the drag changes direction. We should wait until 242 | // the cursor has returned to, and begun to pass the bottom/top of the range 243 | if ((atTop && movingUp) || (atTop && event.clientY < canvasAbsTop)) { 244 | return; 245 | } 246 | if ( 247 | (atBottom && movingDown) || 248 | (atBottom && event.clientY > canvasAbsBot) 249 | ) { 250 | return; 251 | } 252 | 253 | // Set view scroll directly 254 | const scrollHeight = this.view.scrollDOM.scrollHeight; 255 | const clientHeight = this.view.scrollDOM.clientHeight; 256 | 257 | const maxTopNonOverflowing = (scrollHeight - clientHeight) / SCALE; 258 | const maxTopOverflowing = clientHeight - clientHeight / SCALE; 259 | 260 | const change = canvasRelTopDouble + deltaY; 261 | 262 | /** 263 | * ScrollPosOverflowing is calculated by: 264 | * - Calculating the offset (change) relative to the total height of the container 265 | * - Multiplying by the maximum scrollTop position for the scroller 266 | * - The maximum scrollTop position for the scroller is the total scroll height minus the client height 267 | */ 268 | const relativeToMax = change / maxTopOverflowing; 269 | const scrollPosOverflowing = 270 | (scrollHeight - clientHeight) * relativeToMax; 271 | 272 | const scrollPosNonOverflowing = change * SCALE; 273 | this.view.scrollDOM.scrollTop = Math.max( 274 | scrollPosOverflowing, 275 | scrollPosNonOverflowing 276 | ); 277 | 278 | // view.scrollDOM truncates if out of bounds. We need to mimic that behavior here with min/max guard 279 | const top = Math.min( 280 | Math.max(0, change), 281 | Math.min(maxTopOverflowing, maxTopNonOverflowing) 282 | ); 283 | this.dom.style.top = top + "px"; 284 | } 285 | 286 | public destroy() { 287 | this.remove(); 288 | } 289 | }, 290 | { 291 | eventHandlers: { 292 | scroll() { 293 | requestAnimationFrame(() => this.computeTop()); 294 | }, 295 | }, 296 | } 297 | ); 298 | 299 | export const Overlay = [Theme, OverlayView]; 300 | -------------------------------------------------------------------------------- /src/diagnostics.ts: -------------------------------------------------------------------------------- 1 | import { EditorView, ViewUpdate } from "@codemirror/view"; 2 | import { 3 | Diagnostic, 4 | diagnosticCount, 5 | forEachDiagnostic, 6 | setDiagnosticsEffect, 7 | } from "@codemirror/lint"; 8 | 9 | import { LineBasedState } from "./linebasedstate"; 10 | import { DrawContext } from "./types"; 11 | import { Lines, LinesState, foldsChanged } from "./LinesState"; 12 | import { Config } from "./Config"; 13 | 14 | type Severity = Diagnostic["severity"]; 15 | 16 | export class DiagnosticState extends LineBasedState { 17 | private count: number | undefined = undefined; 18 | 19 | public constructor(view: EditorView) { 20 | super(view); 21 | } 22 | 23 | private shouldUpdate(update: ViewUpdate) { 24 | // If the minimap is disabled 25 | if (!update.state.facet(Config).enabled) { 26 | return false; 27 | } 28 | 29 | // If the doc changed 30 | if (update.docChanged) { 31 | return true; 32 | } 33 | 34 | // If the diagnostics changed 35 | for (const tr of update.transactions) { 36 | for (const ef of tr.effects) { 37 | if (ef.is(setDiagnosticsEffect)) { 38 | return true; 39 | } 40 | } 41 | } 42 | 43 | // If the folds changed 44 | if (foldsChanged(update.transactions)) { 45 | return true; 46 | } 47 | 48 | // If the minimap was previously hidden 49 | if (this.count === undefined) { 50 | return true; 51 | } 52 | 53 | return false; 54 | } 55 | 56 | public update(update: ViewUpdate) { 57 | if (!this.shouldUpdate(update)) { 58 | return; 59 | } 60 | 61 | this.map.clear(); 62 | const lines = update.state.field(LinesState); 63 | this.count = diagnosticCount(update.state); 64 | 65 | forEachDiagnostic(update.state, (diagnostic, from, to) => { 66 | // Find the start and end lines for the diagnostic 67 | const lineStart = this.findLine(from, lines); 68 | const lineEnd = this.findLine(to, lines); 69 | 70 | // Populate each line in the range with the highest severity diagnostic 71 | let severity = diagnostic.severity; 72 | for (let i = lineStart; i <= lineEnd; i++) { 73 | const previous = this.get(i); 74 | if (previous) { 75 | severity = [severity, previous] 76 | .sort(this.sort.bind(this)) 77 | .slice(0, 1)[0]; 78 | } 79 | this.set(i, severity); 80 | } 81 | }); 82 | } 83 | 84 | public drawLine(ctx: DrawContext, lineNumber: number) { 85 | const {context, lineHeight, offsetX, offsetY} = ctx; 86 | const severity = this.get(lineNumber); 87 | if (!severity) { 88 | return; 89 | } 90 | 91 | // Draw the full line width rectangle in the background 92 | context.globalAlpha = 0.65; 93 | context.beginPath(); 94 | context.rect( 95 | offsetX, 96 | offsetY /* TODO Scaling causes anti-aliasing in rectangles */, 97 | context.canvas.width - offsetX, 98 | lineHeight 99 | ); 100 | context.fillStyle = this.color(severity); 101 | context.fill(); 102 | 103 | // Draw diagnostic range rectangle in the foreground 104 | // TODO: We need to update the state to have specific ranges 105 | // context.globalAlpha = 1; 106 | // context.beginPath(); 107 | // context.rect(offsetX, offsetY, textWidth, lineHeight); 108 | // context.fillStyle = this.color(severity); 109 | // context.fill(); 110 | } 111 | 112 | /** 113 | * Given a position and a set of line ranges, return 114 | * the line number the position falls within 115 | */ 116 | private findLine(pos: number, lines: Lines) { 117 | const index = lines.findIndex((spans) => { 118 | const start = spans.slice(0, 1)[0]; 119 | const end = spans.slice(-1)[0]; 120 | 121 | if (!start || !end) { 122 | return false; 123 | } 124 | 125 | return start.from <= pos && pos <= end.to; 126 | }); 127 | 128 | // Line numbers begin at 1 129 | return index + 1; 130 | } 131 | 132 | /** 133 | * Colors from @codemirror/lint 134 | * https://github.com/codemirror/lint/blob/e0671b43c02e72766ad1afe1579b7032fdcdb6c1/src/lint.ts#L597 135 | */ 136 | private color(severity: Severity) { 137 | return severity === "error" 138 | ? "#d11" 139 | : severity === "warning" 140 | ? "orange" 141 | : "#999"; 142 | } 143 | 144 | /** Sorts severity from most to least severe */ 145 | private sort(a: Severity, b: Severity) { 146 | return this.score(b) - this.score(a); 147 | } 148 | 149 | /** Assigns a score to severity, with most severe being the highest */ 150 | private score(s: Severity) { 151 | switch (s) { 152 | case "error": { 153 | return 3; 154 | } 155 | case "warning": { 156 | return 2; 157 | } 158 | default: { 159 | return 1; 160 | } 161 | } 162 | } 163 | } 164 | 165 | export function diagnostics(view: EditorView): DiagnosticState { 166 | return new DiagnosticState(view); 167 | } 168 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Facet } from "@codemirror/state"; 2 | import { EditorView, ViewPlugin, ViewUpdate } from "@codemirror/view"; 3 | import { Overlay } from "./Overlay"; 4 | import { Config, Options, Scale } from "./Config"; 5 | import { DiagnosticState, diagnostics } from "./diagnostics"; 6 | import { SelectionState, selections } from "./selections"; 7 | import { TextState, text } from "./text"; 8 | import { LinesState } from "./LinesState"; 9 | import crelt from "crelt"; 10 | import { GUTTER_WIDTH, drawLineGutter } from "./Gutters"; 11 | 12 | const Theme = EditorView.theme({ 13 | "&": { 14 | height: "100%", 15 | overflowY: "auto", 16 | }, 17 | "& .cm-minimap-gutter": { 18 | borderRight: 0, 19 | flexShrink: 0, 20 | left: "unset", 21 | position: "sticky", 22 | right: 0, 23 | top: 0, 24 | }, 25 | '& .cm-minimap-autohide': { 26 | opacity: 0.0, 27 | transition: 'opacity 0.3s', 28 | }, 29 | '& .cm-minimap-autohide:hover': { 30 | opacity: 1.0, 31 | }, 32 | "& .cm-minimap-inner": { 33 | height: "100%", 34 | position: "absolute", 35 | right: 0, 36 | top: 0, 37 | overflowY: "hidden", 38 | "& canvas": { 39 | display: "block", 40 | }, 41 | }, 42 | "& .cm-minimap-box-shadow": { 43 | boxShadow: "12px 0px 20px 5px #6c6c6c", 44 | }, 45 | }); 46 | 47 | const WIDTH_RATIO = 6; 48 | 49 | const minimapClass = ViewPlugin.fromClass( 50 | class { 51 | private dom: HTMLElement | undefined; 52 | private inner: HTMLElement | undefined; 53 | private canvas: HTMLCanvasElement | undefined; 54 | 55 | public text: TextState; 56 | public selection: SelectionState; 57 | public diagnostic: DiagnosticState; 58 | 59 | public constructor(private view: EditorView) { 60 | this.text = text(view); 61 | this.selection = selections(view); 62 | this.diagnostic = diagnostics(view); 63 | 64 | if (view.state.facet(showMinimap)) { 65 | this.create(view); 66 | } 67 | } 68 | 69 | private create(view: EditorView) { 70 | const config = view.state.facet(showMinimap); 71 | if (!config) { 72 | throw Error("Expected nonnull"); 73 | } 74 | 75 | this.inner = crelt("div", {class: "cm-minimap-inner"}); 76 | this.canvas = crelt("canvas") as HTMLCanvasElement; 77 | 78 | this.dom = config.create(view).dom; 79 | this.dom.classList.add("cm-gutters"); 80 | this.dom.classList.add("cm-minimap-gutter"); 81 | 82 | this.inner.appendChild(this.canvas); 83 | this.dom.appendChild(this.inner); 84 | 85 | // For now let's keep this same behavior. We might want to change 86 | // this in the future and have the extension figure out how to mount. 87 | // Or expose some more generic right gutter api and use that 88 | this.view.scrollDOM.insertBefore( 89 | this.dom, 90 | this.view.contentDOM.nextSibling 91 | ); 92 | 93 | for (const key in this.view.state.facet(Config).eventHandlers) { 94 | const handler = this.view.state.facet(Config).eventHandlers[key]; 95 | if (handler) { 96 | this.dom.addEventListener(key, (e) => handler(e, this.view)); 97 | } 98 | } 99 | 100 | if (config.autohide) { 101 | this.dom.classList.add('cm-minimap-autohide'); 102 | } 103 | } 104 | 105 | private remove() { 106 | if (this.dom) { 107 | this.dom.remove(); 108 | } 109 | } 110 | 111 | update(update: ViewUpdate) { 112 | const prev = update.startState.facet(showMinimap); 113 | const now = update.state.facet(showMinimap); 114 | 115 | if (prev && !now) { 116 | this.remove(); 117 | return; 118 | } 119 | 120 | if (!prev && now) { 121 | this.create(update.view); 122 | } 123 | 124 | if (now) { 125 | this.text.update(update); 126 | this.selection.update(update); 127 | this.diagnostic.update(update); 128 | this.render(); 129 | } 130 | } 131 | 132 | getWidth(): number { 133 | const editorWidth = this.view.dom.clientWidth; 134 | if (editorWidth <= Scale.MaxWidth * WIDTH_RATIO) { 135 | const ratio = editorWidth / (Scale.MaxWidth * WIDTH_RATIO); 136 | return Scale.MaxWidth * ratio; 137 | } 138 | return Scale.MaxWidth; 139 | } 140 | 141 | render() { 142 | // If we don't have elements to draw to exit early 143 | if (!this.dom || !this.canvas || !this.inner) { 144 | return; 145 | } 146 | 147 | this.text.beforeDraw(); 148 | 149 | this.updateBoxShadow(); 150 | 151 | this.dom.style.width = this.getWidth() + "px"; 152 | this.canvas.style.maxWidth = this.getWidth() + "px"; 153 | this.canvas.width = this.getWidth() * Scale.PixelMultiplier; 154 | 155 | const domHeight = this.view.dom.getBoundingClientRect().height; 156 | this.inner.style.minHeight = domHeight + "px"; 157 | this.canvas.height = domHeight * Scale.PixelMultiplier; 158 | this.canvas.style.height = domHeight + "px"; 159 | 160 | const context = this.canvas.getContext("2d"); 161 | if (!context) { 162 | return; 163 | } 164 | 165 | context.clearRect(0, 0, this.canvas.width, this.canvas.height); 166 | 167 | /* We need to get the correct font dimensions before this to measure characters */ 168 | const {charWidth, lineHeight} = this.text.measure(context); 169 | 170 | let {startIndex, endIndex, offsetY} = this.canvasStartAndEndIndex( 171 | context, 172 | lineHeight 173 | ); 174 | 175 | const gutters = this.view.state.facet(Config).gutters; 176 | 177 | for (let i = startIndex; i < endIndex; i++) { 178 | const lines = this.view.state.field(LinesState); 179 | if (i >= lines.length) break; 180 | 181 | const drawContext = { 182 | offsetX: 0, 183 | offsetY, 184 | context, 185 | lineHeight, 186 | charWidth, 187 | }; 188 | 189 | if (gutters.length) { 190 | /* Small leading buffer */ 191 | drawContext.offsetX += 2; 192 | 193 | for (let gutter of gutters) { 194 | drawLineGutter(gutter, drawContext, i + 1); 195 | drawContext.offsetX += GUTTER_WIDTH; 196 | } 197 | 198 | /* Small trailing buffer */ 199 | drawContext.offsetX += 2; 200 | } 201 | 202 | this.text.drawLine(drawContext, i + 1); 203 | this.selection.drawLine(drawContext, i + 1); 204 | this.diagnostic.drawLine(drawContext, i + 1); 205 | 206 | offsetY += lineHeight; 207 | } 208 | 209 | context.restore(); 210 | } 211 | 212 | private canvasStartAndEndIndex( 213 | context: CanvasRenderingContext2D, 214 | lineHeight: number 215 | ) { 216 | let {top: pTop, bottom: pBottom} = this.view.documentPadding; 217 | (pTop /= Scale.SizeRatio), (pBottom /= Scale.SizeRatio); 218 | 219 | const canvasHeight = context.canvas.height; 220 | const {clientHeight, scrollHeight, scrollTop} = this.view.scrollDOM; 221 | let scrollPercent = scrollTop / (scrollHeight - clientHeight); 222 | if (isNaN(scrollPercent)) { 223 | scrollPercent = 0; 224 | } 225 | 226 | const lineCount = this.view.state.field(LinesState).length; 227 | const totalHeight = pTop + pBottom + lineCount * lineHeight; 228 | 229 | const canvasTop = Math.max( 230 | 0, 231 | scrollPercent * (totalHeight - canvasHeight) 232 | ); 233 | const offsetY = Math.max(0, pTop - canvasTop); 234 | 235 | const startIndex = Math.round(Math.max(0, canvasTop - pTop) / lineHeight); 236 | const spaceForLines = Math.round((canvasHeight - offsetY) / lineHeight); 237 | 238 | return { 239 | startIndex, 240 | endIndex: startIndex + spaceForLines, 241 | offsetY, 242 | }; 243 | } 244 | 245 | private updateBoxShadow() { 246 | if (!this.canvas) { 247 | return; 248 | } 249 | 250 | const {clientWidth, scrollWidth, scrollLeft} = this.view.scrollDOM; 251 | 252 | if (clientWidth + scrollLeft < scrollWidth) { 253 | this.canvas.classList.add("cm-minimap-box-shadow"); 254 | } else { 255 | this.canvas.classList.remove("cm-minimap-box-shadow"); 256 | } 257 | } 258 | 259 | destroy() { 260 | this.remove(); 261 | } 262 | }, 263 | { 264 | eventHandlers: { 265 | scroll() { 266 | requestAnimationFrame(() => this.render()); 267 | }, 268 | }, 269 | provide: (plugin) => { 270 | return EditorView.scrollMargins.of((view) => { 271 | const width = view.plugin(plugin)?.getWidth(); 272 | if (!width) { 273 | return null; 274 | } 275 | 276 | return {right: width}; 277 | }); 278 | }, 279 | } 280 | ); 281 | 282 | export interface MinimapConfig extends Omit { 283 | /** 284 | * A function that creates the element that contains the minimap 285 | */ 286 | create: (view: EditorView) => { dom: HTMLElement }; 287 | } 288 | 289 | /** 290 | * Facet used to show a minimap in the right gutter of the editor using the 291 | * provided configuration. 292 | * 293 | * If you return `null`, a minimap will not be shown. 294 | */ 295 | const showMinimap = Facet.define({ 296 | combine: (c) => c.find((o) => o !== null) ?? null, 297 | enables: (f) => { 298 | return [ 299 | [ 300 | Config.compute([f], (s) => s.facet(f)), 301 | Theme, 302 | LinesState, 303 | minimapClass, // TODO, codemirror-ify this one better 304 | Overlay, 305 | ], 306 | ]; 307 | }, 308 | }); 309 | 310 | export { showMinimap }; 311 | -------------------------------------------------------------------------------- /src/linebasedstate.ts: -------------------------------------------------------------------------------- 1 | import { EditorView } from "@codemirror/view"; 2 | 3 | // TODO: renamed this file because something's weird with codemirror build 4 | 5 | export abstract class LineBasedState { 6 | protected map: Map; 7 | protected view: EditorView; 8 | 9 | public constructor(view: EditorView) { 10 | this.map = new Map(); 11 | this.view = view; 12 | } 13 | 14 | public get(lineNumber: number): TValue | undefined { 15 | return this.map.get(lineNumber); 16 | } 17 | 18 | protected set(lineNumber: number, value: TValue) { 19 | this.map.set(lineNumber, value); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/selections.ts: -------------------------------------------------------------------------------- 1 | import { LineBasedState } from "./linebasedstate"; 2 | import { EditorView, ViewUpdate } from "@codemirror/view"; 3 | import { LinesState, foldsChanged } from "./LinesState"; 4 | import { DrawContext } from "./types"; 5 | import { Config } from "./Config"; 6 | 7 | type Selection = { from: number; to: number; extends: boolean }; 8 | type DrawInfo = { backgroundColor: string }; 9 | 10 | export class SelectionState extends LineBasedState> { 11 | private _drawInfo: DrawInfo | undefined; 12 | private _themeClasses: string; 13 | 14 | public constructor(view: EditorView) { 15 | super(view); 16 | 17 | this.getDrawInfo(); 18 | this._themeClasses = view.dom.classList.value; 19 | } 20 | 21 | private shouldUpdate(update: ViewUpdate) { 22 | // If the minimap is disabled 23 | if (!update.state.facet(Config).enabled) { 24 | return false; 25 | } 26 | 27 | // If the doc changed 28 | if (update.docChanged) { 29 | return true; 30 | } 31 | 32 | // If the selection changed 33 | if (update.selectionSet) { 34 | return true; 35 | } 36 | 37 | // If the theme changed 38 | if (this._themeClasses !== this.view.dom.classList.value) { 39 | return true; 40 | } 41 | 42 | // If the folds changed 43 | if (foldsChanged(update.transactions)) { 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | 50 | public update(update: ViewUpdate) { 51 | if (!this.shouldUpdate(update)) { 52 | return; 53 | } 54 | 55 | this.map.clear(); 56 | 57 | /* If class list has changed, clear and recalculate the selection style */ 58 | if (this._themeClasses !== this.view.dom.classList.value) { 59 | this._drawInfo = undefined; 60 | this._themeClasses = this.view.dom.classList.value; 61 | } 62 | 63 | const {ranges} = update.state.selection; 64 | 65 | let selectionIndex = 0; 66 | for (const [index, line] of update.state.field(LinesState).entries()) { 67 | const selections: Array = []; 68 | 69 | let offset = 0; 70 | for (const span of line) { 71 | do { 72 | // We've already processed all selections 73 | if (selectionIndex >= ranges.length) { 74 | continue; 75 | } 76 | 77 | // The next selection begins after this span 78 | if (span.to < ranges[selectionIndex].from) { 79 | continue; 80 | } 81 | 82 | // Ignore 0-length selections 83 | if (ranges[selectionIndex].from === ranges[selectionIndex].to) { 84 | selectionIndex++; 85 | continue; 86 | } 87 | 88 | // Build the selection for the current span 89 | const range = ranges[selectionIndex]; 90 | const selection = { 91 | from: offset + Math.max(span.from, range.from) - span.from, 92 | to: offset + Math.min(span.to, range.to) - span.from, 93 | extends: range.to > span.to, 94 | }; 95 | 96 | const lastSelection = selections.slice(-1)[0]; 97 | if (lastSelection && lastSelection.to === selection.from) { 98 | // The selection in this span may just be a continuation of the 99 | // selection in the previous span 100 | 101 | // Adjust `to` depending on if we're in a folded span 102 | let {to} = selection; 103 | if (span.folded && selection.extends) { 104 | to = selection.from + 1; 105 | } else if (span.folded && !selection.extends) { 106 | to = lastSelection.to; 107 | } 108 | 109 | selections[selections.length - 1] = { 110 | ...lastSelection, 111 | to, 112 | extends: selection.extends, 113 | }; 114 | } else if (!span.folded) { 115 | // It's a new selection; if we're not in a folded span we 116 | // should push it onto the stack 117 | selections.push(selection); 118 | } 119 | 120 | // If the selection doesn't end in this span, break out of the loop 121 | if (selection.extends) { 122 | break; 123 | } 124 | 125 | // Otherwise, move to the next selection 126 | selectionIndex++; 127 | } while ( 128 | selectionIndex < ranges.length && 129 | span.to >= ranges[selectionIndex].from 130 | ); 131 | 132 | offset += span.folded ? 1 : span.to - span.from; 133 | } 134 | 135 | // If we don't have any selections on this line, we don't need to store anything 136 | if (selections.length === 0) { 137 | continue; 138 | } 139 | 140 | // Lines are indexed beginning at 1 instead of 0 141 | const lineNumber = index + 1; 142 | this.map.set(lineNumber, selections); 143 | } 144 | } 145 | 146 | public drawLine(ctx: DrawContext, lineNumber: number) { 147 | let { 148 | context, 149 | lineHeight, 150 | charWidth, 151 | offsetX: startOffsetX, 152 | offsetY, 153 | } = ctx; 154 | const selections = this.get(lineNumber); 155 | if (!selections) { 156 | return; 157 | } 158 | 159 | for (const selection of selections) { 160 | const offsetX = startOffsetX + selection.from * charWidth; 161 | const textWidth = (selection.to - selection.from) * charWidth; 162 | const fullWidth = context.canvas.width - offsetX; 163 | 164 | if (selection.extends) { 165 | // Draw the full width rectangle in the background 166 | context.globalAlpha = 0.65; 167 | context.beginPath(); 168 | context.rect(offsetX, offsetY, fullWidth, lineHeight); 169 | context.fillStyle = this.getDrawInfo().backgroundColor; 170 | context.fill(); 171 | } 172 | 173 | // Draw text selection rectangle in the foreground 174 | context.globalAlpha = 1; 175 | context.beginPath(); 176 | context.rect(offsetX, offsetY, textWidth, lineHeight); 177 | context.fillStyle = this.getDrawInfo().backgroundColor; 178 | context.fill(); 179 | } 180 | } 181 | 182 | private getDrawInfo(): DrawInfo { 183 | if (this._drawInfo) { 184 | return this._drawInfo; 185 | } 186 | 187 | // Create a mock selection 188 | const mockToken = document.createElement("span"); 189 | mockToken.setAttribute("class", "cm-selectionBackground"); 190 | this.view.dom.appendChild(mockToken); 191 | 192 | // Get style information 193 | const style = window.getComputedStyle(mockToken); 194 | const result = {backgroundColor: style.backgroundColor}; 195 | 196 | // Store the result for the next update 197 | this._drawInfo = result; 198 | this.view.dom.removeChild(mockToken); 199 | 200 | return result; 201 | } 202 | } 203 | 204 | export function selections(view: EditorView): SelectionState { 205 | return new SelectionState(view); 206 | } 207 | -------------------------------------------------------------------------------- /src/text.ts: -------------------------------------------------------------------------------- 1 | import { LineBasedState } from "./linebasedstate"; 2 | import { Highlighter, highlightTree } from "@lezer/highlight"; 3 | import { ChangedRange, Tree, TreeFragment } from "@lezer/common"; 4 | import { highlightingFor, language } from "@codemirror/language"; 5 | import { EditorView, ViewUpdate } from "@codemirror/view"; 6 | import { DrawContext } from "./types"; 7 | import { Config, Options, Scale } from "./Config"; 8 | import { LinesState, foldsChanged } from "./LinesState"; 9 | import crelt from "crelt"; 10 | import { ChangeSet, EditorState } from "@codemirror/state"; 11 | 12 | type TagSpan = { text: string; tags: string }; 13 | type FontInfo = { color: string; font: string; lineHeight: number }; 14 | 15 | export class TextState extends LineBasedState> { 16 | private _previousTree: Tree | undefined; 17 | private _displayText: Required["displayText"] | undefined; 18 | private _fontInfoMap: Map = new Map(); 19 | private _themeClasses: Set | undefined; 20 | private _highlightingCallbackId: number | undefined; 21 | 22 | public constructor(view: EditorView) { 23 | super(view); 24 | 25 | // @ts-expect-error - This is a private field 26 | this._themeClasses = new Set(view.dom.classList.values()); 27 | 28 | if (view.state.facet(Config).enabled) { 29 | this.updateImpl(view.state); 30 | } 31 | } 32 | 33 | private shouldUpdate(update: ViewUpdate) { 34 | // If the doc changed 35 | if (update.docChanged) { 36 | return true; 37 | } 38 | 39 | // If configuration settings changed 40 | if (update.state.facet(Config) !== update.startState.facet(Config)) { 41 | return true; 42 | } 43 | 44 | // If the theme changed 45 | if (this.themeChanged()) { 46 | return true; 47 | } 48 | 49 | // If the folds changed 50 | if (foldsChanged(update.transactions)) { 51 | return true; 52 | } 53 | 54 | return false; 55 | } 56 | 57 | public update(update: ViewUpdate) { 58 | if (!this.shouldUpdate(update)) { 59 | return; 60 | } 61 | 62 | if (this._highlightingCallbackId) { 63 | typeof window.requestIdleCallback !== "undefined" 64 | ? cancelIdleCallback(this._highlightingCallbackId) 65 | : clearTimeout(this._highlightingCallbackId); 66 | } 67 | 68 | this.updateImpl(update.state, update.changes); 69 | } 70 | 71 | private updateImpl(state: EditorState, changes?: ChangeSet) { 72 | this.map.clear(); 73 | 74 | /* Store display text setting for rendering */ 75 | this._displayText = state.facet(Config).displayText; 76 | 77 | /* If class list has changed, clear and recalculate the font info map */ 78 | if (this.themeChanged()) { 79 | this._fontInfoMap.clear(); 80 | } 81 | 82 | /* Incrementally parse the tree based on previous tree + changes */ 83 | let treeFragments: ReadonlyArray | undefined = undefined; 84 | if (this._previousTree && changes) { 85 | const previousFragments = TreeFragment.addTree(this._previousTree); 86 | 87 | const changedRanges: Array = []; 88 | changes.iterChangedRanges((fromA, toA, fromB, toB) => 89 | changedRanges.push({fromA, toA, fromB, toB}) 90 | ); 91 | 92 | treeFragments = TreeFragment.applyChanges( 93 | previousFragments, 94 | changedRanges 95 | ); 96 | } 97 | 98 | /* Parse the document into a lezer tree */ 99 | const docToString = state.doc.toString(); 100 | // console.log(docToString); 101 | const parser = state.facet(language)?.parser; 102 | 103 | const tree = parser && Object.keys(parser).length > 0 ? parser.parse(docToString || '', treeFragments) : undefined; 104 | this._previousTree = tree; 105 | 106 | /* Highlight the document, and store the text and tags for each line */ 107 | const highlighter: Highlighter = { 108 | style: (tags) => highlightingFor(state, tags), 109 | }; 110 | 111 | let highlights: Array<{ from: number; to: number; tags: string }> = []; 112 | 113 | if (tree) { 114 | /** 115 | * The viewport renders a few extra lines above and below the editor view. To approximate 116 | * the lines visible in the minimap, we multiply the lines in the viewport by the scale multipliers. 117 | * 118 | * Based on the current scroll position, the minimap may show a larger portion of lines above or 119 | * below the lines currently in the editor view. On a long document, when the scroll position is 120 | * near the top of the document, the minimap will show a small number of lines above the lines 121 | * in the editor view, and a large number of lines below the lines in the editor view. 122 | * 123 | * To approximate this ratio, we can use the viewport scroll percentage 124 | * 125 | * ┌─────────────────────┐ 126 | * │ │ 127 | * │ Extra viewport │ 128 | * │ buffer │ 129 | * ├─────────────────────┼───────┐ 130 | * │ │Minimap│ 131 | * │ │Gutter │ 132 | * │ ├───────┤ 133 | * │ Editor View │Scaled │ 134 | * │ │View │ 135 | * │ │Overlay│ 136 | * │ ├───────┤ 137 | * │ │ │ 138 | * │ │ │ 139 | * ├─────────────────────┼───────┘ 140 | * │ │ 141 | * │ Extra viewport │ 142 | * │ buffer │ 143 | * └─────────────────────┘ 144 | * 145 | **/ 146 | 147 | const vpLineTop = state.doc.lineAt(this.view.viewport.from).number; 148 | const vpLineBottom = state.doc.lineAt(this.view.viewport.to).number; 149 | const vpLineCount = vpLineBottom - vpLineTop; 150 | const vpScroll = vpLineTop / (state.doc.lines - vpLineCount); 151 | 152 | const {SizeRatio, PixelMultiplier} = Scale; 153 | const mmLineCount = vpLineCount * SizeRatio * PixelMultiplier; 154 | const mmLineRatio = vpScroll * mmLineCount; 155 | 156 | const mmLineTop = Math.max(1, Math.floor(vpLineTop - mmLineRatio)); 157 | const mmLineBottom = Math.min( 158 | vpLineBottom + Math.floor(mmLineCount - mmLineRatio), 159 | state.doc.lines 160 | ); 161 | 162 | // Highlight the in-view lines synchronously 163 | highlightTree( 164 | tree, 165 | highlighter, 166 | (from, to, tags) => { 167 | highlights.push({from, to, tags}); 168 | }, 169 | state.doc.line(mmLineTop).from, 170 | state.doc.line(mmLineBottom).to 171 | ); 172 | } 173 | 174 | // Update the map 175 | this.updateMapImpl(state, highlights); 176 | 177 | // Highlight the entire tree in an idle callback 178 | highlights = []; 179 | const highlightingCallback = () => { 180 | if (tree) { 181 | highlightTree(tree, highlighter, (from, to, tags) => { 182 | highlights.push({from, to, tags}); 183 | }); 184 | this.updateMapImpl(state, highlights); 185 | this._highlightingCallbackId = undefined; 186 | } 187 | }; 188 | this._highlightingCallbackId = 189 | typeof window.requestIdleCallback !== "undefined" 190 | ? requestIdleCallback(highlightingCallback) 191 | : setTimeout(highlightingCallback) as any; 192 | } 193 | 194 | private updateMapImpl( 195 | state: EditorState, 196 | highlights: Array<{ from: number; to: number; tags: string }> 197 | ) { 198 | this.map.clear(); 199 | 200 | const docToString = state.doc.toString(); 201 | const highlightsIterator = highlights.values(); 202 | let highlightPtr = highlightsIterator.next(); 203 | 204 | for (const [index, line] of state.field(LinesState).entries()) { 205 | const spans: Array = []; 206 | 207 | for (const span of line) { 208 | // Skip if it's a 0-length span 209 | if (span.from === span.to) { 210 | continue; 211 | } 212 | 213 | // Append a placeholder for a folded span 214 | if (span.folded) { 215 | spans.push({text: "…", tags: ""}); 216 | continue; 217 | } 218 | 219 | let position = span.from; 220 | while (!highlightPtr.done && highlightPtr.value.from < span.to) { 221 | const {from, to, tags} = highlightPtr.value; 222 | 223 | // Iterate until our highlight is over the current span 224 | if (to < position) { 225 | highlightPtr = highlightsIterator.next(); 226 | continue; 227 | } 228 | 229 | // Append unstyled text before the highlight begins 230 | if (from > position) { 231 | spans.push({text: docToString.slice(position, from), tags: ""}); 232 | } 233 | 234 | // A highlight may start before and extend beyond the current span 235 | const start = Math.max(from, span.from); 236 | const end = Math.min(to, span.to); 237 | 238 | // Append the highlighted text 239 | spans.push({text: docToString.slice(start, end), tags}); 240 | position = end; 241 | 242 | // If the highlight continues beyond this span, break from this loop 243 | if (to > end) { 244 | break; 245 | } 246 | 247 | // Otherwise, move to the next highlight 248 | highlightPtr = highlightsIterator.next(); 249 | } 250 | 251 | // If there are remaining spans that did not get highlighted, append them unstyled 252 | if (position !== span.to) { 253 | spans.push({ 254 | text: docToString.slice(position, span.to), 255 | tags: "", 256 | }); 257 | } 258 | } 259 | 260 | // Lines are indexed beginning at 1 instead of 0 261 | const lineNumber = index + 1; 262 | this.map.set(lineNumber, spans); 263 | } 264 | } 265 | 266 | public measure(context: CanvasRenderingContext2D): { 267 | charWidth: number; 268 | lineHeight: number; 269 | } { 270 | const {color, font, lineHeight} = this.getFontInfo(""); 271 | 272 | context.textBaseline = "ideographic"; 273 | context.fillStyle = color; 274 | context.font = font; 275 | 276 | return { 277 | charWidth: context.measureText("_").width, 278 | lineHeight: lineHeight, 279 | }; 280 | } 281 | 282 | public beforeDraw() { 283 | this._fontInfoMap.clear(); // TODO: Confirm this worked for theme changes or get rid of it because it's slow 284 | } 285 | 286 | public drawLine(ctx: DrawContext, lineNumber: number) { 287 | const line = this.get(lineNumber); 288 | if (!line) { 289 | return; 290 | } 291 | 292 | let {context, charWidth, lineHeight, offsetX, offsetY} = ctx; 293 | 294 | let prevInfo: FontInfo | undefined; 295 | context.textBaseline = "ideographic"; 296 | 297 | for (const span of line) { 298 | const info = this.getFontInfo(span.tags); 299 | 300 | if (!prevInfo || prevInfo.color !== info.color) { 301 | context.fillStyle = info.color; 302 | } 303 | 304 | if (!prevInfo || prevInfo.font !== info.font) { 305 | context.font = info.font; 306 | } 307 | 308 | prevInfo = info; 309 | 310 | lineHeight = Math.max(lineHeight, info.lineHeight); 311 | 312 | switch (this._displayText) { 313 | case "characters": { 314 | // TODO: `fillText` takes up the majority of profiling time in `render` 315 | // Try speeding it up with `drawImage` 316 | // https://stackoverflow.com/questions/8237030/html5-canvas-faster-filltext-vs-drawimage/8237081 317 | 318 | context.fillText(span.text, offsetX, offsetY + lineHeight); 319 | offsetX += span.text.length * charWidth; 320 | break; 321 | } 322 | 323 | case "blocks": { 324 | const nonWhitespace = /\S+/g; 325 | let start: RegExpExecArray | null; 326 | while ((start = nonWhitespace.exec(span.text)) !== null) { 327 | const startX = offsetX + start.index * charWidth; 328 | let width = (nonWhitespace.lastIndex - start.index) * charWidth; 329 | 330 | // Reached the edge of the minimap 331 | if (startX > context.canvas.width) { 332 | break; 333 | } 334 | 335 | // Limit width to edge of minimap 336 | if (startX + width > context.canvas.width) { 337 | width = context.canvas.width - startX; 338 | } 339 | 340 | // Scaled 2px buffer between lines 341 | const yBuffer = 2 / Scale.SizeRatio; 342 | const height = lineHeight - yBuffer; 343 | 344 | context.fillStyle = info.color; 345 | context.globalAlpha = 0.65; // Make the blocks a bit faded 346 | context.beginPath(); 347 | context.rect(startX, offsetY, width, height); 348 | context.fill(); 349 | } 350 | 351 | offsetX += span.text.length * charWidth; 352 | break; 353 | } 354 | } 355 | } 356 | } 357 | 358 | private getFontInfo(tags: string): FontInfo { 359 | const cached = this._fontInfoMap.get(tags); 360 | if (cached) { 361 | return cached; 362 | } 363 | 364 | // Create a mock token wrapped in a cm-line 365 | const mockToken = crelt("span", {class: tags}); 366 | const mockLine = crelt( 367 | "div", 368 | {class: "cm-line", style: "display: none"}, 369 | mockToken 370 | ); 371 | this.view.contentDOM.appendChild(mockLine); 372 | 373 | // Get style information and store it 374 | const style = window.getComputedStyle(mockToken); 375 | const lineHeight = parseFloat(style.lineHeight) / Scale.SizeRatio; 376 | const result = { 377 | color: style.color, 378 | font: `${style.fontStyle} ${style.fontWeight} ${lineHeight}px ${style.fontFamily}`, 379 | lineHeight, 380 | }; 381 | this._fontInfoMap.set(tags, result); 382 | 383 | // Clean up and return 384 | this.view.contentDOM.removeChild(mockLine); 385 | return result; 386 | } 387 | 388 | private themeChanged(): boolean { 389 | const previous = this._themeClasses; 390 | // @ts-expect-error - This is a private field 391 | const now = new Set(this.view.dom.classList.values()); 392 | this._themeClasses = now as Set; 393 | 394 | if (!previous) { 395 | return true; 396 | } 397 | 398 | // Ignore certain classes being added/removed 399 | previous.delete("cm-focused"); 400 | now.delete("cm-focused"); 401 | 402 | if (previous.size !== now.size) { 403 | return true; 404 | } 405 | 406 | let containsAll = true; 407 | previous.forEach((theme) => { 408 | if (!now.has(theme)) { 409 | containsAll = false; 410 | } 411 | }); 412 | 413 | return !containsAll; 414 | } 415 | } 416 | 417 | export function text(view: EditorView): TextState { 418 | return new TextState(view); 419 | } 420 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type DrawContext = { 2 | context: CanvasRenderingContext2D; 3 | offsetY: number; 4 | lineHeight: number; 5 | charWidth: number; 6 | offsetX: number; 7 | }; 8 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This CSS file will be included with your plugin, and 4 | available in the app when your plugin is enabled. 5 | 6 | If your plugin does not need CSS, delete this file. 7 | 8 | */ 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "inlineSourceMap": true, 5 | "inlineSources": true, 6 | "module": "ESNext", 7 | "target": "ES6", 8 | "allowJs": true, 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "importHelpers": true, 12 | "isolatedModules": true, 13 | "strictNullChecks": true, 14 | "lib": [ 15 | "DOM", 16 | "ES5", 17 | "ES6", 18 | "ES7" 19 | ] 20 | }, 21 | "include": [ 22 | "**/*.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /version-bump.mjs: -------------------------------------------------------------------------------- 1 | import { readFileSync, writeFileSync } from "fs"; 2 | 3 | const targetVersion = process.env.npm_package_version; 4 | 5 | // read minAppVersion from manifest.json and bump version to target version 6 | let manifest = JSON.parse(readFileSync("manifest.json", "utf8")); 7 | const { minAppVersion } = manifest; 8 | manifest.version = targetVersion; 9 | writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t")); 10 | 11 | // update versions.json with target version and minAppVersion from manifest.json 12 | let versions = JSON.parse(readFileSync("versions.json", "utf8")); 13 | versions[targetVersion] = minAppVersion; 14 | writeFileSync("versions.json", JSON.stringify(versions, null, "\t")); 15 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | --------------------------------------------------------------------------------