├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ ├── CI.yml │ ├── deploy.yml │ ├── update-grammars.yml │ └── update-themes.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── CHANGELOG.md ├── README.md ├── docs ├── languages.md └── themes.md ├── jest.config.js ├── lerna.json ├── netlify.toml ├── package.json ├── packages ├── renderer-svg │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ └── styleAttributes.test.ts │ │ ├── global.d.ts │ │ ├── index.ts │ │ └── measureMonospaceTypeface.ts │ └── tsconfig.json ├── shiki │ ├── README.md │ ├── languages │ │ ├── abap.tmLanguage.json │ │ ├── actionscript-3.tmLanguage.json │ │ ├── ada.tmLanguage.json │ │ ├── apache.tmLanguage.json │ │ ├── apex.tmLanguage.json │ │ ├── apl.tmLanguage.json │ │ ├── applescript.tmLanguage.json │ │ ├── asm.tmLanguage.json │ │ ├── awk.tmLanguage.json │ │ ├── bat.tmLanguage.json │ │ ├── c.tmLanguage.json │ │ ├── clojure.tmLanguage.json │ │ ├── cobol.tmLanguage.json │ │ ├── coffee.tmLanguage.json │ │ ├── cpp-macro.tmLanguage.json │ │ ├── cpp.tmLanguage.json │ │ ├── crystal.tmLanguage.json │ │ ├── csharp.tmLanguage.json │ │ ├── css.tmLanguage.json │ │ ├── d.tmLanguage.json │ │ ├── dart.tmLanguage.json │ │ ├── diff.tmLanguage.json │ │ ├── docker.tmLanguage.json │ │ ├── dream-maker.tmLanguage.json │ │ ├── elixir.tmLanguage.json │ │ ├── elm.tmLanguage.json │ │ ├── erb.tmLanguage.json │ │ ├── erlang.tmLanguage.json │ │ ├── fsharp.tmLanguage.json │ │ ├── gherkin.tmLanguage.json │ │ ├── git-commit.tmLanguage.json │ │ ├── git-rebase.tmLanguage.json │ │ ├── gnuplot.tmLanguage.json │ │ ├── go.tmLanguage.json │ │ ├── graphql.tmLanguage.json │ │ ├── groovy.tmLanguage.json │ │ ├── hack.tmLanguage.json │ │ ├── haml.tmLanguage.json │ │ ├── handlebars.tmLanguage.json │ │ ├── haskell.tmLanguage.json │ │ ├── hcl.tmLanguage.json │ │ ├── hlsl.tmLanguage.json │ │ ├── html.tmLanguage.json │ │ ├── ini.tmLanguage.json │ │ ├── java.tmLanguage.json │ │ ├── javascript.tmLanguage.json │ │ ├── jinja-html.tmLanguage.json │ │ ├── jinja.tmLanguage.json │ │ ├── json.tmLanguage.json │ │ ├── jsonc.tmLanguage.json │ │ ├── jsonnet.tmLanguage.json │ │ ├── jssm.tmLanguage.json │ │ ├── jsx.tmLanguage.json │ │ ├── julia.tmLanguage.json │ │ ├── jupyter.tmLanguage.json │ │ ├── kotlin.tmLanguage.json │ │ ├── latex.tmLanguage.json │ │ ├── less.tmLanguage.json │ │ ├── lisp.tmLanguage.json │ │ ├── logo.tmLanguage.json │ │ ├── lua.tmLanguage.json │ │ ├── make.tmLanguage.json │ │ ├── markdown.tmLanguage.json │ │ ├── matlab.tmLanguage.json │ │ ├── mdx.tmLanguage.json │ │ ├── nginx.tmLanguage.json │ │ ├── nim.tmLanguage.json │ │ ├── nix.tmLanguage.json │ │ ├── objective-c.tmLanguage.json │ │ ├── objective-cpp.tmLanguage.json │ │ ├── ocaml.tmLanguage.json │ │ ├── pascal.tmLanguage.json │ │ ├── perl.tmLanguage.json │ │ ├── php-html.tmLanguage.json │ │ ├── php.tmLanguage.json │ │ ├── plsql.tmLanguage.json │ │ ├── postcss.tmLanguage.json │ │ ├── powershell.tmLanguage.json │ │ ├── prisma.tmLanguage.json │ │ ├── prolog.tmLanguage.json │ │ ├── pug.tmLanguage.json │ │ ├── puppet.tmLanguage.json │ │ ├── purescript.tmLanguage.json │ │ ├── python.tmLanguage.json │ │ ├── r.tmLanguage.json │ │ ├── raku.tmLanguage.json │ │ ├── razor.tmLanguage.json │ │ ├── riscv.tmLanguage.json │ │ ├── ruby.tmLanguage.json │ │ ├── rust.tmLanguage.json │ │ ├── sas.tmLanguage.json │ │ ├── sass.tmLanguage.json │ │ ├── scala.tmLanguage.json │ │ ├── scheme.tmLanguage.json │ │ ├── scss.tmLanguage.json │ │ ├── shaderlab.tmLanguage.json │ │ ├── shellscript.tmLanguage.json │ │ ├── smalltalk.tmLanguage.json │ │ ├── solidity.tmLanguage.json │ │ ├── sparql.tmLanguage.json │ │ ├── sql.tmLanguage.json │ │ ├── ssh-config.tmLanguage.json │ │ ├── stylus.tmLanguage.json │ │ ├── svelte.tmLanguage.json │ │ ├── swift.tmLanguage.json │ │ ├── system-verilog.tmLanguage.json │ │ ├── tcl.tmLanguage.json │ │ ├── tex.tmLanguage.json │ │ ├── toml.tmLanguage.json │ │ ├── tsx.tmLanguage.json │ │ ├── turtle.tmLanguage.json │ │ ├── twig.tmLanguage.json │ │ ├── typescript.tmLanguage.json │ │ ├── vb.tmLanguage.json │ │ ├── verilog.tmLanguage.json │ │ ├── vhdl.tmLanguage.json │ │ ├── viml.tmLanguage.json │ │ ├── vue-html.tmLanguage.json │ │ ├── vue.tmLanguage.json │ │ ├── wasm.tmLanguage.json │ │ ├── wenyan.tmLanguage.json │ │ ├── xml.tmLanguage.json │ │ ├── xsl.tmLanguage.json │ │ └── yaml.tmLanguage.json │ ├── package.json │ ├── rollup.config.js │ ├── samples │ │ ├── c.sample │ │ ├── css.sample │ │ ├── dm.sample │ │ ├── fsl.sample │ │ ├── go.sample │ │ ├── html.sample │ │ ├── java.sample │ │ ├── javascript.sample │ │ ├── jssm.sample │ │ ├── prisma.sample │ │ ├── python.sample │ │ ├── ruby.sample │ │ ├── sparql.sample │ │ ├── tsx.sample │ │ └── turtle.sample │ ├── src │ │ ├── __tests__ │ │ │ ├── 152.test.ts │ │ │ ├── __snapshots__ │ │ │ │ ├── 152.test.ts.snap │ │ │ │ └── simple.test.ts.snap │ │ │ ├── background.test.ts │ │ │ ├── comprehensive.test.ts │ │ │ ├── custom-language │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── customLanguage.test.ts.snap │ │ │ │ ├── customLanguage.test.ts │ │ │ │ ├── rockstar-html.tmLanguage.json │ │ │ │ ├── rockstar-override.tmLanguage.json │ │ │ │ ├── rockstar.rock │ │ │ │ └── rockstar.tmLanguage.json │ │ │ ├── simple.test.ts │ │ │ └── utils.test.ts │ │ ├── global.d.ts │ │ ├── highlighter.ts │ │ ├── index.ts │ │ ├── languages.ts │ │ ├── loader.ts │ │ ├── registry.ts │ │ ├── renderer.ts │ │ ├── resolver.ts │ │ ├── stackElementMetadata.ts │ │ ├── themedTokenizer.ts │ │ ├── themes.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── themes │ │ ├── dark-plus.json │ │ ├── dracula-soft.json │ │ ├── dracula.json │ │ ├── github-dark.json │ │ ├── github-light.json │ │ ├── light-plus.json │ │ ├── material-darker.json │ │ ├── material-default.json │ │ ├── material-lighter.json │ │ ├── material-ocean.json │ │ ├── material-palenight.json │ │ ├── min-dark.json │ │ ├── min-light.json │ │ ├── monokai.json │ │ ├── nord.json │ │ ├── poimandres.json │ │ ├── slack-dark.json │ │ ├── slack-ochin.json │ │ ├── solarized-dark.json │ │ ├── solarized-light.json │ │ ├── vitesse-dark.json │ │ └── vitesse-light.json │ └── tsconfig.json ├── site │ ├── assets │ │ ├── figma-editing.png │ │ ├── leandro-fatih.png │ │ ├── svg-figma-af.jpg │ │ └── vscode-ts.png │ ├── beer.wy │ ├── chinese-svg.svg │ ├── gen-custom-theme.js │ ├── gen-index.js │ ├── gen-mono.js │ ├── gen-palenight.js │ ├── gen-svg-sample.js │ ├── gen-svg.js │ ├── gen-wenyan.js │ ├── index.html │ ├── index.js │ ├── index.md │ ├── jsconfig.json │ ├── mono.html │ ├── mono.md │ ├── monochrome-dark-subtle.json │ ├── package.json │ ├── palenight.html │ ├── palenight.md │ ├── rockstar.html │ ├── rockstar.md │ ├── rockstar.tmLanguage.json │ ├── style.css │ ├── svg.svg │ └── 文言.html ├── tsconfig.json └── vuepress-plugin │ ├── README.md │ ├── index.js │ └── package.json ├── scripts ├── grammarSources.ts ├── grammars │ ├── normalizeGrammarPaths.ts │ ├── pullGrammarsFromGitHub.ts │ └── updateGrammarSourceFiles.ts ├── pullGrammars.sh ├── pullThemes.sh ├── themeSources.ts ├── themes │ ├── normalizeThemePaths.ts │ ├── processVSCThemes.ts │ ├── pullThemesFromGitHub.ts │ ├── pullThemesFromMarketplace.ts │ └── updateThemeSrc.ts ├── tsconfig.json └── util │ └── download.ts ├── tsconfig.json └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | packages/shiki/languages/*.json binary 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [octref] 2 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | test: 12 | runs-on: ${{ matrix.os }} 13 | 14 | strategy: 15 | matrix: 16 | os: [ubuntu-latest, windows-2016] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - uses: actions/setup-node@v2 21 | with: 22 | node-version: '14' 23 | 24 | - name: Get yarn cache directory path 25 | id: yarn-cache-dir-path 26 | run: echo "::set-output name=dir::$(yarn cache dir)" 27 | 28 | - uses: actions/cache@v2 29 | id: yarn-cache 30 | with: 31 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 32 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 33 | restore-keys: | 34 | ${{ runner.os }}-yarn- 35 | 36 | - run: yarn install 37 | - run: yarn build 38 | - run: yarn update 39 | - run: yarn workspace shiki-site gen 40 | 41 | - run: yarn test 42 | env: 43 | CI: true 44 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy npm modules 2 | on: 3 | push: 4 | branches: [main] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: '15.x' 15 | registry-url: 'https://registry.npmjs.org/' 16 | 17 | - run: yarn install 18 | - run: yarn build 19 | - run: yarn update 20 | 21 | - name: Deploy npm Packages 22 | run: npx pleb publish 23 | env: 24 | NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/update-grammars.yml: -------------------------------------------------------------------------------- 1 | name: 'Update Grammars' 2 | 3 | on: 4 | schedule: 5 | - cron: '0 6 * * *' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | update-grammars: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: '12' 18 | 19 | - name: Get yarn cache directory path 20 | id: yarn-cache-dir-path 21 | run: echo "::set-output name=dir::$(yarn cache dir)" 22 | 23 | - uses: actions/cache@v2 24 | id: yarn-cache 25 | with: 26 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 27 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 28 | restore-keys: | 29 | ${{ runner.os }}-yarn- 30 | 31 | - run: yarn install 32 | 33 | - run: yarn run update:grammars 34 | 35 | - name: Build 36 | run: yarn build 37 | - name: Test 38 | run: yarn test 39 | env: 40 | CI: true 41 | 42 | - name: Commit 43 | run: | 44 | if [[ `git status --porcelain` ]]; then 45 | git config user.name "Pine Wu" 46 | git config user.email octref@gmail.com 47 | git status 48 | git add -A 49 | git commit -m "chore: Update grammars" 50 | git push 51 | else 52 | echo "no changes" 53 | fi 54 | -------------------------------------------------------------------------------- /.github/workflows/update-themes.yml: -------------------------------------------------------------------------------- 1 | name: 'Update Themes' 2 | 3 | on: 4 | schedule: 5 | - cron: '0 8 * * *' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | update-themes: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: '12' 18 | 19 | - name: Get yarn cache directory path 20 | id: yarn-cache-dir-path 21 | run: echo "::set-output name=dir::$(yarn cache dir)" 22 | 23 | - uses: actions/cache@v2 24 | id: yarn-cache 25 | with: 26 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 27 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 28 | restore-keys: | 29 | ${{ runner.os }}-yarn- 30 | 31 | - run: yarn install 32 | 33 | - run: yarn run update:themes 34 | 35 | - name: Build 36 | run: yarn build 37 | - name: Test 38 | run: yarn test 39 | env: 40 | CI: true 41 | 42 | - name: Commit 43 | run: | 44 | if [[ `git status --porcelain` ]]; then 45 | git config user.name "Pine Wu" 46 | git config user.email octref@gmail.com 47 | git status 48 | git add -A 49 | git commit -m "chore: Update themes" 50 | git push 51 | else 52 | echo "no changes" 53 | fi 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | tsconfig.tsbuildinfo 4 | tmp 5 | 6 | .DS_Store 7 | 8 | yarn-error.log -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore as they are auto generated 2 | 3 | packages/shiki/src/languages.ts 4 | packages/shiki/src/themes.ts -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "semi": false, 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "arrowParens": "avoid" 7 | } 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### 0.2.7 | 2020-11-13 4 | 5 | - Fix color fallback issues. [#100](https://github.com/shikijs/shiki/issues/100). 6 | - 🙌 Add Applescript grammar. [#99](https://github.com/shikijs/shiki/issues/99). Thanks to contribution from [Arturo Galán](https://github.com/arturogalan). 7 | 8 | ### 0.2.6 | 2020-09-28 9 | 10 | - Upgrade to onigasm 2.2.5. 11 | - Add Erlang grammar. 12 | - 🙌 Add Elixir grammar. [#95](https://github.com/shikijs/shiki/issues/95). Thanks to contribution from [Sebastien Baudray](https://github.com/https://github.com/sbaudray). 13 | - 🙌 Fix wrong escape sequence in vuepress plugin. [#93](https://github.com/shikijs/shiki/issues/93). Thanks to contribution from [Yu Zhang](https://github.com/yzhang-gh). 14 | 15 | ### 0.2.5 | 2020-09-17 16 | 17 | - Reduce dependency size (shiki-themes is 47M). [#94](https://github.com/shikijs/shiki/issues/94). 18 | 19 | ### 0.2.4 | 2020-09-13 20 | 21 | - Fix `RangeError: Invalid array length` in `vuepress-plugin-shiki`. 22 | - 🙌 Wrap line in ``. [#76](https://github.com/shikijs/shiki/issues/76). Thanks to contribution from [Christoph Werner](https://github.com/codepunkt). 23 | 24 | ### 0.2.3 | 2020-09-08 25 | 26 | - Add `文言` language. [#88](https://github.com/shikijs/shiki/issues/88). 27 | - Add `slack-theme-dark-mode` and `slack-theme-ochin` themes. Thanks to contribution from [Christoph Werner](https://github.com/codepunkt). [#78](https://github.com/shikijs/shiki/pull/78). 28 | 29 | ### 0.2.2 | 2020-08-26 30 | 31 | - Fix dark-plus syntax highlighting for uncolored white text. 32 | 33 | ### 0.2.1 | 2020-08-24 34 | 35 | - Allow custom languages for vuepress. [#80](https://github.com/shikijs/shiki/issues/80). 36 | - Fix `php` syntax highlighting. [#21](https://github.com/shikijs/shiki/issues/21). 37 | - Add `jinja-html` language, which embeds `jinja` language. [#24](https://github.com/shikijs/shiki/issues/24). 38 | - Remove `vue-html` language. Either use `vue` or `html` language. 39 | 40 | ### 0.2.0 | 2020-08-24 41 | 42 | - Normalize all theme names to kebab-case. 43 | - Add GitHub light/dark themes. 44 | - Remove less popular themes. 45 | - Add `hlsl`, `asm` (x86 Assembly), `m` (Matlab), `sas`, `d`, `dart`, `plsql`, `logo`, , `pas` (Object Pascal/Delphi), `cobol`, `kt` (Kotlin), `scala`, `abap`, `julia`, `scheme`, `prolog`, `ada`, `lisp`, `apex`, `fortran`, `haskell`, `hcl`, `hack`, `awk`, `as` (ActionScript), `tcl`, `ocaml`, `viml`, `puppet`, `jsonnet`, `smalltalk`, `cr` (Crystal), `wat` (WASM), `nix`, `elm`, `purescript` and `svelte` languages. 46 | - Add `pug` language and make `jade` an alias of it. 47 | - Use GitHub workflow to update grammars periodically. [#72](https://github.com/shikijs/shiki/issues/72). 48 | - Use GitHub workflow to update themes periodically. [#71](https://github.com/shikijs/shiki/issues/71). 49 | - Use theme foreground color when color of token is `undefined`. [#27](https://github.com/shikijs/shiki/issues/27). 50 | - SVG Renderer. [#2](https://github.com/shikijs/shiki/issues/2). 51 | - Fix HTML escaping. [#26](https://github.com/octref/shiki/issues/26) and [#28](https://github.com/octref/shiki/pull/28). Thanks to contribution from [@jackens](https://github.com/jackens). 52 | - 🙌 Add an option to skip generating the explanation text. [#52](https://github.com/shikijs/shiki/pull/52). Thanks to contribution from [Gerrit Birkeland](https://github.com/Gerrit0). 53 | - 🙌 Improve performance by avoiding some unnecessary string copies. [#51](https://github.com/shikijs/shiki/pull/51). Thanks to contribution from [Gerrit Birkeland](https://github.com/Gerrit0). 54 | - 🙌 Allow loading custom `tmLanguage`. [#10](https://github.com/octref/shiki/issues/10) and [#49](https://github.com/octref/shiki/pull/49). Thanks to contribution from [Orta Therox](https://github.com/orta) and [@pngwn](https://github.com/pngwn). 55 | - 🙌 Update Java grammar. [#36](https://github.com/octref/shiki/issues/36) and [#37](https://github.com/octref/shiki/issues/37). Thanks to contribution from [@0xflotus](https://github.com/0xflotus). 56 | 57 | ### 0.1.7 | 2020-04-28 58 | 59 | - Update to latest Dark+/Light+ theme from VS Code. 60 | 61 | ### 0.1.6 | 2019-09-19 62 | 63 | - Add `toml` language from https://github.com/bungcip/better-toml. [#20](https://github.com/octref/shiki/issues/20). 64 | 65 | ### 0.1.5 | 2019-09-09 66 | 67 | - Begin to keep a changelog. [#7](https://github.com/octref/shiki/issues/7). 68 | - Accept `plaintext`, `text` and `txt` as `lang`. Will return `code` as it is. [#16](https://github.com/octref/shiki/issues/16). 69 | - Add `jsonc` language. [#18](https://github.com/octref/shiki/issues/18). 70 | - Add `csharp` language. [#14](https://github.com/octref/shiki/issues/14). 71 | - Add `md` as an alias for `markdown`. 72 | - Add `zsh` as an alias for `bash`. 73 | - Add `yml` as an alias for `yaml`. 74 | - 🙌 Use json5 for parsing theme as JSONC. [#11](https://github.com/octref/shiki/issues/11). Thanks to contribution from [Wes Bos](https://github.com/wesbos). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

Shiki

3 |

4 |

5 | Shiki is a beautiful Syntax Highlighter. Demo. 6 |

7 | 8 | ## Usage 9 | 10 | ```sh 11 | npm i shiki 12 | # yarn add shiki 13 | ``` 14 | 15 | ```js 16 | const shiki = require('shiki') 17 | 18 | shiki 19 | .getHighlighter({ 20 | theme: 'nord' 21 | }) 22 | .then(highlighter => { 23 | console.log(highlighter.codeToHtml(`console.log('shiki');`, 'js')) 24 | }) 25 | 26 | //

27 | //   
28 | // 
29 | ``` 30 | 31 | ```html 32 | 33 | 43 | ``` 44 | 45 | - [Themes](./docs/themes.md) 46 | - [Languages](./docs/languages.md) 47 | - [SVG Renderer](./packages/renderer-svg/README.md) 48 | - [vuepress-plugin-shiki](./packages/vuepress-plugin/README.md) 49 | 50 | Clone [shikijs/shiki-starter](https://github.com/shikijs/shiki-starter) to play with Shiki, or try it out on [Repl.it](https://repl.it/@octref/shiki-starter). 51 | 52 | ## Seen 53 | 54 | - Shiki Docs: https://shiki.matsu.io 55 | - Interactive Demo on CodeSandbox (with Next.js): https://codesandbox.io/s/shiki-next-js-cir0y 56 | - [VS Code website](https://code.visualstudio.com), such as in the [Notebook API page](https://code.visualstudio.com/api/extension-guides/notebook). 57 | - [TypeScript website](https://www.typescriptlang.org), such as in the [Basic Types documentation page](https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple). 58 | - [Markdown Preview Shiki Highlighting](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-Shiki), a VS Code plugin to use Shiki's highlighting in Markdown preview. 59 | - [Shiki LaTeX](https://www.npmjs.com/package/shiki-latex), a Shiki renderer for [LaTeX](https://www.latex-project.org). Compatible with [minted](https://github.com/gpoore/minted), replacing [Pygments](https://pygments.org). 60 | - [Fatih Kalifa's website](https://fatihkalifa.com/typescript-twoslash) 61 | - [Blockstack Documentation](https://docs.blockstack.org/) 62 | - [VPC Shiki](https://github.com/Vap0r1ze/vpc-shiki), Shiki codeblocks on Discord. Powered by [Powercord](http://powercord.dev/) 63 | 64 | ## Contributing 65 | 66 | - [Add a theme](./docs/themes.md#add) 67 | - [Add a language grammar](./docs/languages.md#adding-grammar) 68 | 69 | ## Credits 70 | 71 | - Shiki uses [Onigasm](https://github.com/NeekSandhu/onigasm) by [@NeekSandhu](https://github.com/NeekSandhu) 72 | - A lot of code is based on [vscode-textmate](https://github.com/Microsoft/vscode-textmate) 73 | 74 | ## Sponsorship 75 | 76 | If you find Shiki useful, please consider sponsoring my Open Source development. Thank you 🙏 77 | 78 | https://github.com/sponsors/octref 79 | 80 | ## License 81 | 82 | MIT © [Pine Wu](https://github.com/octref) 83 | -------------------------------------------------------------------------------- /docs/languages.md: -------------------------------------------------------------------------------- 1 | # shiki-languages 2 | 3 | TextMate grammars for Shiki. Grammars are collected from two sources: 4 | 5 | - [VS Code](https://github.com/microsoft/vscode) 6 | - A [handpicked list](/scripts/grammarSources.ts) from GitHub 7 | 8 | A [build script](/scripts/pullGrammars.sh) runs every day to pull latest grammars from the upstream sources. 9 | 10 | ## Adding Grammar 11 | 12 | - Find grammar for a language by searching ` textmate` on GitHub or searching `` on VS Code Marketplace 13 | - Add your grammar to [/scripts/grammarSources.ts](/scripts/grammarSources.ts) 14 | - In [/packages/shiki/samples/](/packages/shiki/samples/), add a code sample file `.sample` for your language. A sample should include a variety of language syntaxes and succinctly capture the idiosyncrasy of a language. Format requirements: 15 | - Space for indentation 16 | - Less than 100 columns if possible 17 | - Link to source in the last line, for example `# From https://poignant.guide/book/chapter-5.html` 18 | - Run `yarn update:grammars` 19 | - Add your language to the language list, below 20 | 21 | ## All Languages 22 | 23 | ```ts 24 | export type Lang = 25 | | 'abap' 26 | | 'actionscript-3' 27 | | 'ada' 28 | | 'apache' 29 | | 'apex' 30 | | 'apl' 31 | | 'applescript' 32 | | 'asm' 33 | | 'awk' 34 | | 'bat' | 'batch' 35 | | 'c' 36 | | 'clojure' | 'clj' 37 | | 'cobol' 38 | | 'coffee' 39 | | 'cpp' 40 | | 'crystal' 41 | | 'csharp' | 'c#' 42 | | 'css' 43 | | 'd' 44 | | 'dart' 45 | | 'diff' 46 | | 'docker' 47 | | 'dream-maker' 48 | | 'elixir' 49 | | 'elm' 50 | | 'erb' 51 | | 'erlang' 52 | | 'fsharp' | 'f#' 53 | | 'gherkin' 54 | | 'git-commit' 55 | | 'git-rebase' 56 | | 'gnuplot' 57 | | 'go' 58 | | 'graphql' 59 | | 'groovy' 60 | | 'hack' 61 | | 'haml' 62 | | 'handlebars' | 'hbs' 63 | | 'haskell' 64 | | 'hcl' 65 | | 'hlsl' 66 | | 'html' 67 | | 'ini' 68 | | 'java' 69 | | 'javascript' | 'js' 70 | | 'jinja-html' 71 | | 'json' 72 | | 'jsonc' 73 | | 'jsonnet' 74 | | 'jssm' | 'fsl' 75 | | 'jsx' 76 | | 'julia' 77 | | 'jupyter' 78 | | 'kotlin' 79 | | 'latex' 80 | | 'less' 81 | | 'lisp' 82 | | 'logo' 83 | | 'lua' 84 | | 'make' | 'makefile' 85 | | 'markdown' | 'md' 86 | | 'matlab' 87 | | 'mdx' 88 | | 'nginx' 89 | | 'nim' 90 | | 'nix' 91 | | 'objective-c' | 'objc' 92 | | 'objective-cpp' 93 | | 'ocaml' 94 | | 'pascal' 95 | | 'perl' 96 | | 'php' 97 | | 'plsql' 98 | | 'postcss' 99 | | 'powershell' | 'ps' | 'ps1' 100 | | 'prisma' 101 | | 'prolog' 102 | | 'pug' | 'jade' 103 | | 'puppet' 104 | | 'purescript' 105 | | 'python' | 'py' 106 | | 'r' 107 | | 'raku' | 'perl6' 108 | | 'razor' 109 | | 'riscv' 110 | | 'ruby' | 'rb' 111 | | 'rust' 112 | | 'sas' 113 | | 'sass' 114 | | 'scala' 115 | | 'scheme' 116 | | 'scss' 117 | | 'shaderlab' | 'shader' 118 | | 'shellscript' | 'shell' | 'bash' | 'sh' | 'zsh' 119 | | 'smalltalk' 120 | | 'solidity' 121 | | 'sparql' 122 | | 'sql' 123 | | 'ssh-config' 124 | | 'stylus' | 'styl' 125 | | 'svelte' 126 | | 'swift' 127 | | 'system-verilog' 128 | | 'tcl' 129 | | 'tex' 130 | | 'toml' 131 | | 'tsx' 132 | | 'turtle' 133 | | 'twig' 134 | | 'typescript' | 'ts' 135 | | 'vb' | 'cmd' 136 | | 'verilog' 137 | | 'vhdl' 138 | | 'viml' 139 | | 'vue' 140 | | 'wasm' 141 | | 'wenyan' | '文言' 142 | | 'xml' 143 | | 'xsl' 144 | | 'yaml' 145 | ``` 146 | -------------------------------------------------------------------------------- /docs/themes.md: -------------------------------------------------------------------------------- 1 | # shiki-themes 2 | 3 | TextMate/vscode themes for Shiki. Themes are collected from three sources: 4 | 5 | - [VS Code](https://github.com/microsoft/vscode) 6 | - A [handpicked list](/scripts/themeSources.ts) from GitHub 7 | - A [handpicked list](/scripts/themeSources.ts) from VS Code marketplace 8 | 9 | A [build script](/scripts/pullThemes.sh) runs every day to pull latest themes from the upstream sources. 10 | 11 | ## Adding Theme 12 | 13 | - Find your theme's repository 14 | - If it has a compiled JSON theme, add its link to `githubThemeSources` in [/scripts/themeSources.ts](/scripts/themeSources.ts) 15 | - If it has a precompilation step, add its link to `marketplaceThemeSources` in [/scripts/themeSources.ts](/scripts/themeSources.ts) 16 | - Run `yarn update:themes` 17 | 18 | ## Loading Theme 19 | 20 | ```js 21 | const shiki = require('shiki') 22 | 23 | const t = shiki.loadTheme('./my-theme.json') 24 | 25 | shiki.getHighlighter({ 26 | theme: t 27 | }) 28 | ``` 29 | 30 | ## All Themes 31 | 32 | ```ts 33 | export type Theme = 34 | | 'dark-plus' 35 | | 'dracula-soft' 36 | | 'dracula' 37 | | 'github-dark' 38 | | 'github-light' 39 | | 'light-plus' 40 | | 'material-darker' 41 | | 'material-default' 42 | | 'material-lighter' 43 | | 'material-ocean' 44 | | 'material-palenight' 45 | | 'min-dark' 46 | | 'min-light' 47 | | 'monokai' 48 | | 'nord' 49 | | 'poimandres' 50 | | 'slack-dark' 51 | | 'slack-ochin' 52 | | 'solarized-dark' 53 | | 'solarized-light' 54 | | 'vitesse-dark' 55 | | 'vitesse-light' 56 | ``` 57 | 58 | You can preview some of these themes on https://vscodethemes.com/. 59 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testMatch: ['/packages/**/__tests__/**/*test.ts'], 4 | testTimeout: 10000, 5 | testEnvironment: 'node', 6 | globals: { 7 | __BROWSER__: false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "version": "0.9.5", 4 | "npmClient": "yarn", 5 | "useWorkspaces": true 6 | } 7 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build.environment] 2 | NODE_VERSION = "14" 3 | 4 | [build] 5 | base = "." 6 | publish = "packages/site" 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "workspaces": [ 4 | "packages/*" 5 | ], 6 | "scripts": { 7 | "build": "lerna run build --include-dependencies", 8 | "watch": "lerna run watch --parallel", 9 | "fmt": "prettier --write packages/**/*.ts", 10 | "test": "cross-env NODE_OPTIONS=--max-old-space-size=4096 jest --colors", 11 | "gen": "yarn workspace shiki-site gen", 12 | "release": "lerna publish", 13 | "update": "npm run update:themes && npm run update:grammars", 14 | "update:themes": "bash ./scripts/pullThemes.sh", 15 | "update:grammars": "bash ./scripts/pullGrammars.sh" 16 | }, 17 | "gitHooks": { 18 | "pre-commit": "lint-staged" 19 | }, 20 | "lint-staged": { 21 | "*.{js,json,yml}": [ 22 | "prettier --write" 23 | ], 24 | "*.ts": [ 25 | "prettier --write" 26 | ] 27 | }, 28 | "devDependencies": { 29 | "@rollup/plugin-commonjs": "^20.0.0", 30 | "@rollup/plugin-node-resolve": "^13.0.4", 31 | "@rollup/plugin-replace": "^3.0.0", 32 | "@types/fs-extra": "^9.0.12", 33 | "@types/jest": "^26.0.24", 34 | "@types/js-yaml": "^4.0.2", 35 | "@types/json5": "^2.2.0", 36 | "@types/node": "^14.17.7", 37 | "@types/unzipper": "^0.10.4", 38 | "chalk": "^4.1.2", 39 | "cross-env": "^7.0.3", 40 | "esno": "^0.5.0", 41 | "fast-plist": "^0.1.2", 42 | "fs-extra": "^9.0.12", 43 | "jest": "^26.6.3", 44 | "json5": "^2.2.0", 45 | "lerna": "^3.22.1", 46 | "lint-staged": "^10.5.4", 47 | "lodash.kebabcase": "^4.1.1", 48 | "prettier": "^2.3.2", 49 | "rollup": "^2.55.1", 50 | "rollup-plugin-copy": "^3.4.0", 51 | "rollup-plugin-dts": "^3.0.2", 52 | "rollup-plugin-terser": "^7.0.2", 53 | "rollup-plugin-typescript2": "^0.29.0", 54 | "ts-jest": "^26.5.6", 55 | "tsup": "^4.12.5", 56 | "typescript": "^4.3.5", 57 | "unzipper": "^0.10.11", 58 | "yorkie": "^2.0.0" 59 | }, 60 | "license": "MIT" 61 | } 62 | -------------------------------------------------------------------------------- /packages/renderer-svg/README.md: -------------------------------------------------------------------------------- 1 | # shiki-renderer-svg 2 | 3 | A SVG renderer for Shiki. 4 | 5 | ## Usage 6 | 7 | ```js 8 | const fs = require('fs') 9 | const shiki = require('shiki') 10 | const { getSVGRenderer } = require('shiki-renderer-svg') 11 | 12 | ;(async () => { 13 | const highlighter = await shiki.getHighlighter({ 14 | theme: 'nord' 15 | }) 16 | 17 | const svgRenderer = await getSVGRenderer({ 18 | bg: '#2E3440', 19 | fontFamily: 'IBM Plex Mono', 20 | fontSize: 14 21 | }) 22 | 23 | const code = fs.readFileSync('gen-svg.js', 'utf-8') 24 | 25 | const tokens = highlighter.codeToThemedTokens(code, 'js') 26 | const out = svgRenderer.renderToSVG(tokens) 27 | 28 | fs.writeFileSync('svg.svg', out) 29 | 30 | console.log('done: svg.svg') 31 | })() 32 | ``` 33 | 34 | ### CDN 35 | 36 | ```html 37 | 38 | 39 | ``` 40 | 41 | ```html 42 | 61 | -------------------------------------------------------------------------------- /packages/renderer-svg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shiki-renderer-svg", 3 | "version": "0.9.5", 4 | "description": "SVG renderer for shiki", 5 | "author": "Pine Wu ", 6 | "homepage": "https://github.com/octref/shiki/tree/main/packages/renderer-svg", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/shikijs/shiki.git" 11 | }, 12 | "main": "dist/index.js", 13 | "module": "dist/index.mjs", 14 | "browser": "dist/index.browser.mjs", 15 | "types": "dist/index.d.ts", 16 | "unpkg": "dist/index.iife.min.js", 17 | "jsdelivr": "dist/index.iife.min.js", 18 | "files": [ 19 | "dist" 20 | ], 21 | "scripts": { 22 | "prepublishOnly": "npm run build", 23 | "build": "rollup -c", 24 | "watch": "rollup -c -w" 25 | }, 26 | "peerDependencies": { 27 | "playwright": "^1.9.2", 28 | "shiki": "^0.9.3" 29 | }, 30 | "devDependencies": { 31 | "@types/node": "^14.17.7", 32 | "playwright": "^1.13.1", 33 | "shiki": "^0.9.5" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/renderer-svg/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { nodeResolve } from '@rollup/plugin-node-resolve' 2 | import commonjs from '@rollup/plugin-commonjs' 3 | import dts from 'rollup-plugin-dts' 4 | import typescript from 'rollup-plugin-typescript2' 5 | import replace from '@rollup/plugin-replace' 6 | import { terser } from 'rollup-plugin-terser' 7 | 8 | const external = ['shiki', 'playwright'] 9 | 10 | export default [ 11 | { 12 | input: 'src/index.ts', 13 | external, 14 | output: [ 15 | { 16 | file: 'dist/index.js', 17 | format: 'cjs' 18 | }, 19 | { 20 | file: 'dist/index.mjs', 21 | format: 'esm' 22 | } 23 | ], 24 | plugins: [ 25 | replace({ 26 | __BROWSER__: JSON.stringify(false) 27 | }), 28 | typescript(), 29 | nodeResolve(), 30 | commonjs() 31 | ] 32 | }, 33 | { 34 | input: 'src/index.ts', 35 | external, 36 | output: [ 37 | { 38 | file: 'dist/index.iife.js', 39 | format: 'iife', 40 | extend: true, 41 | name: 'shiki' 42 | }, 43 | { 44 | file: 'dist/index.iife.min.js', 45 | format: 'iife', 46 | extend: true, 47 | name: 'shiki', 48 | plugins: [terser()] 49 | }, 50 | { 51 | file: 'dist/index.browser.mjs', 52 | format: 'esm' 53 | } 54 | ], 55 | plugins: [ 56 | replace({ 57 | __BROWSER__: JSON.stringify(true) 58 | }), 59 | typescript(), 60 | nodeResolve(), 61 | commonjs() 62 | ] 63 | }, 64 | { 65 | input: 'src/index.ts', 66 | output: [ 67 | { 68 | file: 'dist/index.d.ts', 69 | format: 'es' 70 | } 71 | ], 72 | plugins: [dts()] 73 | } 74 | ] 75 | -------------------------------------------------------------------------------- /packages/renderer-svg/src/__tests__/styleAttributes.test.ts: -------------------------------------------------------------------------------- 1 | import { getSVGRenderer } from '../index' 2 | 3 | test('SVG renderer should generate SVG with correct style attributes', async () => { 4 | const r = getSVGRenderer({ 5 | fontFamily: 'IBM Plex Mono' 6 | }) 7 | 8 | const out = (await r).renderToSVG([[{ content: 'foo', color: '#aabbccff' }]]) 9 | // 0x40 = 64, 0xff = 256. 64/256 = 0.25 10 | expect(out).toContain('opacity="1"') 11 | }) 12 | -------------------------------------------------------------------------------- /packages/renderer-svg/src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare var __BROWSER__: boolean 2 | -------------------------------------------------------------------------------- /packages/renderer-svg/src/measureMonospaceTypeface.ts: -------------------------------------------------------------------------------- 1 | function measureFont([fontName, fontSize]: [string, number]) { 2 | /** 3 | * Measure `M` for width 4 | */ 5 | var c = document.createElement('canvas') 6 | var ctx = c.getContext('2d')! 7 | ctx.font = `${fontSize}px "${fontName}"` 8 | 9 | const capMMeasurement = ctx.measureText('M') 10 | 11 | /** 12 | * Measure A-Z, a-z for height 13 | * A - 65 14 | * Z - 90 15 | * a - 97 16 | * z - 122 17 | */ 18 | const characters = [] 19 | for (let i = 65; i <= 90; i++) { 20 | characters.push(String.fromCharCode(i)) 21 | } 22 | for (let i = 97; i <= 122; i++) { 23 | characters.push(String.fromCharCode(i)) 24 | } 25 | 26 | let highC, lowC 27 | let highestAscent = 0 28 | let lowestDescent = 0 29 | characters.forEach(c => { 30 | const m = ctx.measureText(c) 31 | if (m.actualBoundingBoxAscent > highestAscent) { 32 | highestAscent = m.actualBoundingBoxAscent 33 | highC = c 34 | } 35 | if (m.actualBoundingBoxDescent > lowestDescent) { 36 | lowestDescent = m.actualBoundingBoxDescent 37 | lowC = c 38 | } 39 | }) 40 | 41 | return { 42 | width: capMMeasurement.width, 43 | height: highestAscent + lowestDescent 44 | } 45 | } 46 | 47 | const getDocument = (fontName: string, url: string) => { 48 | return ` 49 | 50 | 51 | 52 | 56 | 57 | 58 |

Test

59 | 60 | 61 | ` 62 | } 63 | 64 | export async function measureMonospaceTypeface( 65 | fontNameStr: string, 66 | fontSize: number, 67 | remoteFontCSSURL?: string 68 | ): Promise<{ width: number; height: number }> { 69 | if (__BROWSER__) { 70 | return measureFont([fontNameStr, fontSize]) 71 | } else { 72 | const playwright = require('playwright') as typeof import('playwright') 73 | const browser = await playwright.chromium.launch({ headless: true }) 74 | 75 | const page = await browser.newPage() 76 | 77 | if (remoteFontCSSURL) { 78 | await page.goto('data:text/html,' + getDocument(fontNameStr, remoteFontCSSURL), { 79 | waitUntil: 'networkidle' 80 | }) 81 | 82 | const measurement = await page.evaluate(measureFont, [fontNameStr, fontSize]) 83 | await browser.close() 84 | return measurement 85 | } else { 86 | const measurement = await page.evaluate(measureFont, [fontNameStr, fontSize]) 87 | 88 | await browser.close() 89 | 90 | return measurement 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /packages/renderer-svg/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "target": "es2017", 5 | "esModuleInterop": true, 6 | "moduleResolution": "node", 7 | "lib": ["esnext", "DOM"], 8 | "sourceMap": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/shiki/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Shiki

3 |

4 |

5 | Shiki is a beautiful Syntax Highlighter. Demo. 6 |

7 | 8 | ## Usage 9 | 10 | ```sh 11 | npm i shiki 12 | # yarn add shiki 13 | ``` 14 | 15 | ```js 16 | const shiki = require('shiki') 17 | 18 | shiki 19 | .getHighlighter({ 20 | theme: 'nord' 21 | }) 22 | .then(highlighter => { 23 | console.log(highlighter.codeToHtml(`console.log('shiki');`, 'js')) 24 | }) 25 | 26 | //

27 | //   
28 | // 
29 | ``` 30 | 31 | ```html 32 | 33 | 43 | ``` 44 | 45 | Clone [shikijs/shiki-starter](https://github.com/shikijs/shiki-starter) to play with Shiki, or try it out on [Repl.it](https://repl.it/@octref/shiki-starter). 46 | 47 | ## Seen 48 | 49 | - Shiki Docs: https://shiki.matsu.io 50 | - Interactive Demo on CodeSandbox (with Next.js): https://codesandbox.io/s/shiki-next-js-cir0y 51 | - [VS Code website](https://code.visualstudio.com), such as in the [Notebook API page](https://code.visualstudio.com/api/extension-guides/notebook). 52 | - [TypeScript website](https://www.typescriptlang.org), such as in the [Basic Types documentation page](https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple). 53 | - [Markdown Preview Shiki Highlighting](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-Shiki), a VS Code plugin to use Shiki's highlighting in Markdown preview. 54 | - [Shiki LaTeX](https://www.npmjs.com/package/shiki-latex), a Shiki renderer for [LaTeX](https://www.latex-project.org). Compatible with [minted](https://github.com/gpoore/minted), replacing [Pygments](https://pygments.org). 55 | - [Fatih Kalifa's website](https://fatihkalifa.com/typescript-twoslash) 56 | - [Blockstack Documentation](https://docs.blockstack.org/) 57 | 58 | ## Contributing 59 | 60 | - [Add a theme](./docs/themes.md#add) 61 | - [Add a language grammar](./docs/languages.md#add) 62 | 63 | ## Credits 64 | 65 | - Shiki uses [Onigasm](https://github.com/NeekSandhu/onigasm) by [@NeekSandhu](https://github.com/NeekSandhu) 66 | - A lot of code is based on [vscode-textmate](https://github.com/Microsoft/vscode-textmate) 67 | 68 | ## Sponsorship 69 | 70 | If you find Shiki useful, please consider sponsoring my Open Source development. Thank you 🙏 71 | 72 | https://github.com/sponsors/octref 73 | 74 | ## License 75 | 76 | MIT © [Pine Wu](https://github.com/octref) 77 | -------------------------------------------------------------------------------- /packages/shiki/languages/diff.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "This file has been converted from https://github.com/textmate/diff.tmbundle/blob/master/Syntaxes/Diff.plist", 4 | "If you want to provide a fix or improvement, please create a pull request against the original repository.", 5 | "Once accepted there, we are happy to receive an update request." 6 | ], 7 | "version": "https://github.com/textmate/diff.tmbundle/commit/0593bb775eab1824af97ef2172fd38822abd97d7", 8 | "name": "diff", 9 | "scopeName": "source.diff", 10 | "patterns": [ 11 | { 12 | "captures": { 13 | "1": { 14 | "name": "punctuation.definition.separator.diff" 15 | } 16 | }, 17 | "match": "^((\\*{15})|(={67})|(-{3}))$\\n?", 18 | "name": "meta.separator.diff" 19 | }, 20 | { 21 | "match": "^\\d+(,\\d+)*(a|d|c)\\d+(,\\d+)*$\\n?", 22 | "name": "meta.diff.range.normal" 23 | }, 24 | { 25 | "captures": { 26 | "1": { 27 | "name": "punctuation.definition.range.diff" 28 | }, 29 | "2": { 30 | "name": "meta.toc-list.line-number.diff" 31 | }, 32 | "3": { 33 | "name": "punctuation.definition.range.diff" 34 | } 35 | }, 36 | "match": "^(@@)\\s*(.+?)\\s*(@@)($\\n?)?", 37 | "name": "meta.diff.range.unified" 38 | }, 39 | { 40 | "captures": { 41 | "3": { 42 | "name": "punctuation.definition.range.diff" 43 | }, 44 | "4": { 45 | "name": "punctuation.definition.range.diff" 46 | }, 47 | "6": { 48 | "name": "punctuation.definition.range.diff" 49 | }, 50 | "7": { 51 | "name": "punctuation.definition.range.diff" 52 | } 53 | }, 54 | "match": "^(((\\-{3}) .+ (\\-{4}))|((\\*{3}) .+ (\\*{4})))$\\n?", 55 | "name": "meta.diff.range.context" 56 | }, 57 | { 58 | "match": "^diff --git a/.*$\\n?", 59 | "name": "meta.diff.header.git" 60 | }, 61 | { 62 | "match": "^diff (-|\\S+\\s+\\S+).*$\\n?", 63 | "name": "meta.diff.header.command" 64 | }, 65 | { 66 | "captures": { 67 | "4": { 68 | "name": "punctuation.definition.from-file.diff" 69 | }, 70 | "6": { 71 | "name": "punctuation.definition.from-file.diff" 72 | }, 73 | "7": { 74 | "name": "punctuation.definition.from-file.diff" 75 | } 76 | }, 77 | "match": "(^(((-{3}) .+)|((\\*{3}) .+))$\\n?|^(={4}) .+(?= - ))", 78 | "name": "meta.diff.header.from-file" 79 | }, 80 | { 81 | "captures": { 82 | "2": { 83 | "name": "punctuation.definition.to-file.diff" 84 | }, 85 | "3": { 86 | "name": "punctuation.definition.to-file.diff" 87 | }, 88 | "4": { 89 | "name": "punctuation.definition.to-file.diff" 90 | } 91 | }, 92 | "match": "(^(\\+{3}) .+$\\n?| (-) .* (={4})$\\n?)", 93 | "name": "meta.diff.header.to-file" 94 | }, 95 | { 96 | "captures": { 97 | "3": { 98 | "name": "punctuation.definition.inserted.diff" 99 | }, 100 | "6": { 101 | "name": "punctuation.definition.inserted.diff" 102 | } 103 | }, 104 | "match": "^(((>)( .*)?)|((\\+).*))$\\n?", 105 | "name": "markup.inserted.diff" 106 | }, 107 | { 108 | "captures": { 109 | "1": { 110 | "name": "punctuation.definition.changed.diff" 111 | } 112 | }, 113 | "match": "^(!).*$\\n?", 114 | "name": "markup.changed.diff" 115 | }, 116 | { 117 | "captures": { 118 | "3": { 119 | "name": "punctuation.definition.deleted.diff" 120 | }, 121 | "6": { 122 | "name": "punctuation.definition.deleted.diff" 123 | } 124 | }, 125 | "match": "^(((<)( .*)?)|((-).*))$\\n?", 126 | "name": "markup.deleted.diff" 127 | }, 128 | { 129 | "begin": "^(#)", 130 | "captures": { 131 | "1": { 132 | "name": "punctuation.definition.comment.diff" 133 | } 134 | }, 135 | "comment": "Git produces unified diffs with embedded comments\"", 136 | "end": "\\n", 137 | "name": "comment.line.number-sign.diff" 138 | }, 139 | { 140 | "match": "^index [0-9a-f]{7,40}\\.\\.[0-9a-f]{7,40}.*$\\n?", 141 | "name": "meta.diff.index.git" 142 | }, 143 | { 144 | "captures": { 145 | "1": { 146 | "name": "punctuation.separator.key-value.diff" 147 | }, 148 | "2": { 149 | "name": "meta.toc-list.file-name.diff" 150 | } 151 | }, 152 | "match": "^Index(:) (.+)$\\n?", 153 | "name": "meta.diff.index" 154 | }, 155 | { 156 | "match": "^Only in .*: .*$\\n?", 157 | "name": "meta.diff.only-in" 158 | } 159 | ] 160 | } 161 | -------------------------------------------------------------------------------- /packages/shiki/languages/docker.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "This file has been converted from https://github.com/moby/moby/blob/master/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage", 4 | "If you want to provide a fix or improvement, please create a pull request against the original repository.", 5 | "Once accepted there, we are happy to receive an update request." 6 | ], 7 | "version": "https://github.com/moby/moby/commit/abd39744c6f3ed854500e423f5fabf952165161f", 8 | "name": "docker", 9 | "scopeName": "source.dockerfile", 10 | "patterns": [ 11 | { 12 | "captures": { 13 | "1": { 14 | "name": "keyword.other.special-method.dockerfile" 15 | }, 16 | "2": { 17 | "name": "keyword.other.special-method.dockerfile" 18 | } 19 | }, 20 | "match": "^\\s*\\b(?i:(FROM))\\b.*?\\b(?i:(AS))\\b" 21 | }, 22 | { 23 | "captures": { 24 | "1": { 25 | "name": "keyword.control.dockerfile" 26 | }, 27 | "2": { 28 | "name": "keyword.other.special-method.dockerfile" 29 | } 30 | }, 31 | "match": "^\\s*(?i:(ONBUILD)\\s+)?(?i:(ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR))\\s" 32 | }, 33 | { 34 | "captures": { 35 | "1": { 36 | "name": "keyword.operator.dockerfile" 37 | }, 38 | "2": { 39 | "name": "keyword.other.special-method.dockerfile" 40 | } 41 | }, 42 | "match": "^\\s*(?i:(ONBUILD)\\s+)?(?i:(CMD|ENTRYPOINT))\\s" 43 | }, 44 | { 45 | "begin": "\"", 46 | "beginCaptures": { 47 | "1": { 48 | "name": "punctuation.definition.string.begin.dockerfile" 49 | } 50 | }, 51 | "end": "\"", 52 | "endCaptures": { 53 | "1": { 54 | "name": "punctuation.definition.string.end.dockerfile" 55 | } 56 | }, 57 | "name": "string.quoted.double.dockerfile", 58 | "patterns": [ 59 | { 60 | "match": "\\\\.", 61 | "name": "constant.character.escaped.dockerfile" 62 | } 63 | ] 64 | }, 65 | { 66 | "begin": "'", 67 | "beginCaptures": { 68 | "1": { 69 | "name": "punctuation.definition.string.begin.dockerfile" 70 | } 71 | }, 72 | "end": "'", 73 | "endCaptures": { 74 | "1": { 75 | "name": "punctuation.definition.string.end.dockerfile" 76 | } 77 | }, 78 | "name": "string.quoted.single.dockerfile", 79 | "patterns": [ 80 | { 81 | "match": "\\\\.", 82 | "name": "constant.character.escaped.dockerfile" 83 | } 84 | ] 85 | }, 86 | { 87 | "captures": { 88 | "1": { 89 | "name": "punctuation.whitespace.comment.leading.dockerfile" 90 | }, 91 | "2": { 92 | "name": "comment.line.number-sign.dockerfile" 93 | }, 94 | "3": { 95 | "name": "punctuation.definition.comment.dockerfile" 96 | } 97 | }, 98 | "comment": "comment.line", 99 | "match": "^(\\s*)((#).*$\\n?)" 100 | } 101 | ] 102 | } 103 | -------------------------------------------------------------------------------- /packages/shiki/languages/erb.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": ["erb", "rhtml", "html.erb"], 3 | "injections": { 4 | "text.html.erb - (meta.embedded.block.erb | meta.embedded.line.erb | comment)": { 5 | "patterns": [ 6 | { 7 | "begin": "(^\\s*)(?=<%+#(?![^%]*%>))", 8 | "beginCaptures": { 9 | "0": { 10 | "name": "punctuation.whitespace.comment.leading.erb" 11 | } 12 | }, 13 | "end": "(?!\\G)(\\s*$\\n)?", 14 | "endCaptures": { 15 | "0": { 16 | "name": "punctuation.whitespace.comment.trailing.erb" 17 | } 18 | }, 19 | "patterns": [ 20 | { 21 | "include": "#comment" 22 | } 23 | ] 24 | }, 25 | { 26 | "begin": "(^\\s*)(?=<%(?![^%]*%>))", 27 | "beginCaptures": { 28 | "0": { 29 | "name": "punctuation.whitespace.embedded.leading.erb" 30 | } 31 | }, 32 | "end": "(?!\\G)(\\s*$\\n)?", 33 | "endCaptures": { 34 | "0": { 35 | "name": "punctuation.whitespace.embedded.trailing.erb" 36 | } 37 | }, 38 | "patterns": [ 39 | { 40 | "include": "#tags" 41 | } 42 | ] 43 | }, 44 | { 45 | "include": "#comment" 46 | }, 47 | { 48 | "include": "#tags" 49 | } 50 | ] 51 | } 52 | }, 53 | "keyEquivalent": "^~H", 54 | "name": "erb", 55 | "patterns": [ 56 | { 57 | "include": "text.html.basic" 58 | } 59 | ], 60 | "repository": { 61 | "comment": { 62 | "patterns": [ 63 | { 64 | "begin": "<%+#", 65 | "beginCaptures": { 66 | "0": { 67 | "name": "punctuation.definition.comment.begin.erb" 68 | } 69 | }, 70 | "end": "%>", 71 | "endCaptures": { 72 | "0": { 73 | "name": "punctuation.definition.comment.end.erb" 74 | } 75 | }, 76 | "name": "comment.block.erb" 77 | } 78 | ] 79 | }, 80 | "tags": { 81 | "patterns": [ 82 | { 83 | "begin": "<%+(?!>)[-=]?(?![^%]*%>)", 84 | "beginCaptures": { 85 | "0": { 86 | "name": "punctuation.section.embedded.begin.erb" 87 | } 88 | }, 89 | "contentName": "source.ruby", 90 | "end": "(-?%)>", 91 | "endCaptures": { 92 | "0": { 93 | "name": "punctuation.section.embedded.end.erb" 94 | }, 95 | "1": { 96 | "name": "source.ruby" 97 | } 98 | }, 99 | "name": "meta.embedded.block.erb", 100 | "patterns": [ 101 | { 102 | "captures": { 103 | "1": { 104 | "name": "punctuation.definition.comment.erb" 105 | } 106 | }, 107 | "match": "(#).*?(?=-?%>)", 108 | "name": "comment.line.number-sign.erb" 109 | }, 110 | { 111 | "include": "source.ruby" 112 | } 113 | ] 114 | }, 115 | { 116 | "begin": "<%+(?!>)[-=]?", 117 | "beginCaptures": { 118 | "0": { 119 | "name": "punctuation.section.embedded.begin.erb" 120 | } 121 | }, 122 | "contentName": "source.ruby", 123 | "end": "(-?%)>", 124 | "endCaptures": { 125 | "0": { 126 | "name": "punctuation.section.embedded.end.erb" 127 | }, 128 | "1": { 129 | "name": "source.ruby" 130 | } 131 | }, 132 | "name": "meta.embedded.line.erb", 133 | "patterns": [ 134 | { 135 | "captures": { 136 | "1": { 137 | "name": "punctuation.definition.comment.erb" 138 | } 139 | }, 140 | "match": "(#).*?(?=-?%>)", 141 | "name": "comment.line.number-sign.erb" 142 | }, 143 | { 144 | "include": "source.ruby" 145 | } 146 | ] 147 | } 148 | ] 149 | } 150 | }, 151 | "scopeName": "text.html.erb", 152 | "uuid": "13FF9439-15D0-4E74-9A8E-83ABF0BAA5E7" 153 | } 154 | -------------------------------------------------------------------------------- /packages/shiki/languages/git-commit.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "This file has been converted from https://github.com/textmate/git.tmbundle/blob/master/Syntaxes/Git%20Commit%20Message.tmLanguage", 4 | "If you want to provide a fix or improvement, please create a pull request against the original repository.", 5 | "Once accepted there, we are happy to receive an update request." 6 | ], 7 | "version": "https://github.com/textmate/git.tmbundle/commit/93897a78c6e52bef13dadc0d4091d203c5facb40", 8 | "name": "git-commit", 9 | "scopeName": "text.git-commit", 10 | "patterns": [ 11 | { 12 | "begin": "\\A(?!# Please enter the commit message)", 13 | "end": "^(?=# Please enter the commit message)", 14 | "name": "meta.scope.message.git-commit", 15 | "patterns": [ 16 | { 17 | "begin": "\\A(?=#)", 18 | "end": "^(?!#)", 19 | "patterns": [ 20 | { 21 | "include": "#comment" 22 | } 23 | ] 24 | }, 25 | { 26 | "begin": "^(?!# Please enter the commit message)", 27 | "end": "^(?=# Please enter the commit message)", 28 | "patterns": [ 29 | { 30 | "begin": "\\G", 31 | "end": "^(?!\\G)", 32 | "name": "meta.scope.subject.git-commit", 33 | "patterns": [ 34 | { 35 | "captures": { 36 | "1": { 37 | "name": "keyword.other.$2.git-commit" 38 | } 39 | }, 40 | "match": "\\G((fixup|squash)!)\\s*" 41 | }, 42 | { 43 | "match": ".{73,}$", 44 | "name": "invalid.illegal.line-too-long.git-commit" 45 | }, 46 | { 47 | "match": ".{51,}$", 48 | "name": "invalid.deprecated.line-too-long.git-commit" 49 | } 50 | ] 51 | }, 52 | { 53 | "begin": "^(?!# Please enter the commit message)", 54 | "end": "^(?=# Please enter the commit message)", 55 | "patterns": [ 56 | { 57 | "include": "#comment" 58 | } 59 | ] 60 | } 61 | ] 62 | } 63 | ] 64 | }, 65 | { 66 | "begin": "^(?=# Please enter the commit message)", 67 | "end": "\\z", 68 | "name": "meta.scope.metadata.git-commit", 69 | "patterns": [ 70 | { 71 | "include": "#metadata" 72 | } 73 | ] 74 | } 75 | ], 76 | "repository": { 77 | "comment": { 78 | "begin": "^(#)", 79 | "captures": { 80 | "1": { 81 | "name": "punctuation.definition.comment.git-commit" 82 | } 83 | }, 84 | "end": "\\n", 85 | "name": "comment.line.number-sign.git-commit" 86 | }, 87 | "metadata": { 88 | "patterns": [ 89 | { 90 | "begin": "(?=^# Changes to be committed:)", 91 | "end": "(?!\\G)((?=^# \\w)|(?!^#))", 92 | "patterns": [ 93 | { 94 | "begin": "(^[ \\t]+)?(?=#)", 95 | "beginCaptures": { 96 | "1": { 97 | "name": "punctuation.whitespace.comment.leading.git-commit" 98 | } 99 | }, 100 | "contentName": "comment.line.number-sign.git-commit", 101 | "end": "(?!\\G)^", 102 | "patterns": [ 103 | { 104 | "match": "\\G#", 105 | "name": "punctuation.definition.comment.git-commit" 106 | }, 107 | { 108 | "match": "((modified|renamed):.*)$\\n?", 109 | "name": "markup.changed.git-commit" 110 | }, 111 | { 112 | "match": "(new file:.*)$\\n?", 113 | "name": "markup.inserted.git-commit" 114 | }, 115 | { 116 | "match": "(deleted:.*)$\\n?", 117 | "name": "markup.deleted.git-commit" 118 | } 119 | ] 120 | } 121 | ] 122 | }, 123 | { 124 | "include": "#comment" 125 | }, 126 | { 127 | "begin": "(?=diff\\ \\-\\-git)", 128 | "comment": "diff presented at the end of the commit message when using commit -v.", 129 | "contentName": "source.diff", 130 | "end": "\\z", 131 | "name": "meta.embedded.diff.git-commit", 132 | "patterns": [ 133 | { 134 | "include": "source.diff" 135 | } 136 | ] 137 | } 138 | ] 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /packages/shiki/languages/git-rebase.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "This file has been converted from https://github.com/textmate/git.tmbundle/blob/master/Syntaxes/Git%20Rebase%20Message.tmLanguage", 4 | "If you want to provide a fix or improvement, please create a pull request against the original repository.", 5 | "Once accepted there, we are happy to receive an update request." 6 | ], 7 | "version": "https://github.com/textmate/git.tmbundle/commit/5870cf3f8abad3a6637bdf69250b5d2ded427dc4", 8 | "name": "git-rebase", 9 | "scopeName": "text.git-rebase", 10 | "patterns": [ 11 | { 12 | "captures": { 13 | "1": { 14 | "name": "punctuation.definition.comment.git-rebase" 15 | } 16 | }, 17 | "match": "^\\s*(#).*$\\n?", 18 | "name": "comment.line.number-sign.git-rebase" 19 | }, 20 | { 21 | "captures": { 22 | "1": { 23 | "name": "support.function.git-rebase" 24 | }, 25 | "2": { 26 | "name": "constant.sha.git-rebase" 27 | }, 28 | "3": { 29 | "name": "meta.commit-message.git-rebase" 30 | } 31 | }, 32 | "match": "^\\s*(pick|p|reword|r|edit|e|squash|s|fixup|f|drop|d)\\s+([0-9a-f]+)\\s+(.*)$", 33 | "name": "meta.commit-command.git-rebase" 34 | }, 35 | { 36 | "captures": { 37 | "1": { 38 | "name": "support.function.git-rebase" 39 | }, 40 | "2": { 41 | "patterns": [ 42 | { 43 | "include": "source.shell" 44 | } 45 | ] 46 | } 47 | }, 48 | "match": "^\\s*(exec|x)\\s+(.*)$", 49 | "name": "meta.commit-command.git-rebase" 50 | }, 51 | { 52 | "captures": { 53 | "1": { 54 | "name": "support.function.git-rebase" 55 | } 56 | }, 57 | "match": "^\\s*(break|b)\\s*$", 58 | "name": "meta.commit-command.git-rebase" 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /packages/shiki/languages/ini.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "This file has been converted from https://github.com/textmate/ini.tmbundle/blob/master/Syntaxes/Ini.plist", 4 | "If you want to provide a fix or improvement, please create a pull request against the original repository.", 5 | "Once accepted there, we are happy to receive an update request." 6 | ], 7 | "version": "https://github.com/textmate/ini.tmbundle/commit/2af0cbb0704940f967152616f2f1ff0aae6287a6", 8 | "name": "ini", 9 | "scopeName": "source.ini", 10 | "patterns": [ 11 | { 12 | "begin": "(^[ \\t]+)?(?=#)", 13 | "beginCaptures": { 14 | "1": { 15 | "name": "punctuation.whitespace.comment.leading.ini" 16 | } 17 | }, 18 | "end": "(?!\\G)", 19 | "patterns": [ 20 | { 21 | "begin": "#", 22 | "beginCaptures": { 23 | "0": { 24 | "name": "punctuation.definition.comment.ini" 25 | } 26 | }, 27 | "end": "\\n", 28 | "name": "comment.line.number-sign.ini" 29 | } 30 | ] 31 | }, 32 | { 33 | "begin": "(^[ \\t]+)?(?=;)", 34 | "beginCaptures": { 35 | "1": { 36 | "name": "punctuation.whitespace.comment.leading.ini" 37 | } 38 | }, 39 | "end": "(?!\\G)", 40 | "patterns": [ 41 | { 42 | "begin": ";", 43 | "beginCaptures": { 44 | "0": { 45 | "name": "punctuation.definition.comment.ini" 46 | } 47 | }, 48 | "end": "\\n", 49 | "name": "comment.line.semicolon.ini" 50 | } 51 | ] 52 | }, 53 | { 54 | "captures": { 55 | "1": { 56 | "name": "keyword.other.definition.ini" 57 | }, 58 | "2": { 59 | "name": "punctuation.separator.key-value.ini" 60 | } 61 | }, 62 | "match": "\\b([a-zA-Z0-9_.-]+)\\b\\s*(=)" 63 | }, 64 | { 65 | "captures": { 66 | "1": { 67 | "name": "punctuation.definition.entity.ini" 68 | }, 69 | "3": { 70 | "name": "punctuation.definition.entity.ini" 71 | } 72 | }, 73 | "match": "^(\\[)(.*?)(\\])", 74 | "name": "entity.name.section.group-title.ini" 75 | }, 76 | { 77 | "begin": "'", 78 | "beginCaptures": { 79 | "0": { 80 | "name": "punctuation.definition.string.begin.ini" 81 | } 82 | }, 83 | "end": "'", 84 | "endCaptures": { 85 | "0": { 86 | "name": "punctuation.definition.string.end.ini" 87 | } 88 | }, 89 | "name": "string.quoted.single.ini", 90 | "patterns": [ 91 | { 92 | "match": "\\\\.", 93 | "name": "constant.character.escape.ini" 94 | } 95 | ] 96 | }, 97 | { 98 | "begin": "\"", 99 | "beginCaptures": { 100 | "0": { 101 | "name": "punctuation.definition.string.begin.ini" 102 | } 103 | }, 104 | "end": "\"", 105 | "endCaptures": { 106 | "0": { 107 | "name": "punctuation.definition.string.end.ini" 108 | } 109 | }, 110 | "name": "string.quoted.double.ini" 111 | } 112 | ] 113 | } 114 | -------------------------------------------------------------------------------- /packages/shiki/languages/jinja-html.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jinja-html", 3 | "scopeName": "text.html.jinja", 4 | "comment": "Jinja HTML Templates", 5 | "firstLineMatch": "^{% extends [\"'][^\"']+[\"'] %}", 6 | "foldingStartMarker": "(<(?i:(head|table|tr|div|style|script|ul|ol|form|dl))\\b.*?>|{%\\s*(block|filter|for|if|macro|raw))", 7 | "foldingStopMarker": "(|{%\\s*(endblock|endfilter|endfor|endif|endmacro|endraw)\\s*%})", 8 | "patterns": [ 9 | { 10 | "include": "source.jinja" 11 | }, 12 | { 13 | "include": "text.html.basic" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/shiki/languages/jssm.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": ["jssm", "jssm_state"], 3 | "name": "jssm", 4 | "patterns": [ 5 | { 6 | "begin": "/\\*", 7 | "captures": { 8 | "0": { 9 | "name": "punctuation.definition.comment.mn" 10 | } 11 | }, 12 | "comment": "block comment", 13 | "end": "\\*/", 14 | "name": "comment.block.jssm" 15 | }, 16 | { 17 | "begin": "//", 18 | "comment": "block comment", 19 | "end": "$", 20 | "name": "comment.line.jssm" 21 | }, 22 | { 23 | "begin": "\\${", 24 | "captures": { 25 | "0": { 26 | "name": "entity.name.function" 27 | } 28 | }, 29 | "comment": "js outcalls", 30 | "end": "}", 31 | "name": "keyword.other" 32 | }, 33 | { 34 | "comment": "semver", 35 | "match": "([0-9]*)(\\.)([0-9]*)(\\.)([0-9]*)", 36 | "name": "constant.numeric" 37 | }, 38 | { 39 | "comment": "jssm language tokens", 40 | "match": "graph_layout(\\s*)(:)", 41 | "name": "constant.language.jssmLanguage" 42 | }, 43 | { 44 | "comment": "jssm language tokens", 45 | "match": "machine_name(\\s*)(:)", 46 | "name": "constant.language.jssmLanguage" 47 | }, 48 | { 49 | "comment": "jssm language tokens", 50 | "match": "machine_version(\\s*)(:)", 51 | "name": "constant.language.jssmLanguage" 52 | }, 53 | { 54 | "comment": "jssm language tokens", 55 | "match": "jssm_version(\\s*)(:)", 56 | "name": "constant.language.jssmLanguage" 57 | }, 58 | { 59 | "comment": "transitions", 60 | "match": "<->", 61 | "name": "keyword.control.transition.jssmArrow.legal_legal" 62 | }, 63 | { 64 | "comment": "transitions", 65 | "match": "<-", 66 | "name": "keyword.control.transition.jssmArrow.legal_none" 67 | }, 68 | { 69 | "comment": "transitions", 70 | "match": "->", 71 | "name": "keyword.control.transition.jssmArrow.none_legal" 72 | }, 73 | { 74 | "comment": "transitions", 75 | "match": "<=>", 76 | "name": "keyword.control.transition.jssmArrow.main_main" 77 | }, 78 | { 79 | "comment": "transitions", 80 | "match": "=>", 81 | "name": "keyword.control.transition.jssmArrow.none_main" 82 | }, 83 | { 84 | "comment": "transitions", 85 | "match": "<=", 86 | "name": "keyword.control.transition.jssmArrow.main_none" 87 | }, 88 | { 89 | "comment": "transitions", 90 | "match": "<~>", 91 | "name": "keyword.control.transition.jssmArrow.forced_forced" 92 | }, 93 | { 94 | "comment": "transitions", 95 | "match": "~>", 96 | "name": "keyword.control.transition.jssmArrow.none_forced" 97 | }, 98 | { 99 | "comment": "transitions", 100 | "match": "<~", 101 | "name": "keyword.control.transition.jssmArrow.forced_none" 102 | }, 103 | { 104 | "comment": "transitions", 105 | "match": "<-=>", 106 | "name": "keyword.control.transition.jssmArrow.legal_main" 107 | }, 108 | { 109 | "comment": "transitions", 110 | "match": "<=->", 111 | "name": "keyword.control.transition.jssmArrow.main_legal" 112 | }, 113 | { 114 | "comment": "transitions", 115 | "match": "<-~>", 116 | "name": "keyword.control.transition.jssmArrow.legal_forced" 117 | }, 118 | { 119 | "comment": "transitions", 120 | "match": "<~->", 121 | "name": "keyword.control.transition.jssmArrow.forced_legal" 122 | }, 123 | { 124 | "comment": "transitions", 125 | "match": "<=~>", 126 | "name": "keyword.control.transition.jssmArrow.main_forced" 127 | }, 128 | { 129 | "comment": "transitions", 130 | "match": "<~=>", 131 | "name": "keyword.control.transition.jssmArrow.forced_main" 132 | }, 133 | { 134 | "comment": "edge probability annotation", 135 | "match": "([0-9]+)%", 136 | "name": "constant.numeric.jssmProbability" 137 | }, 138 | { 139 | "comment": "action annotation", 140 | "match": "\\'[^']*\\'", 141 | "name": "constant.character.jssmAction" 142 | }, 143 | { 144 | "comment": "jssm label annotation", 145 | "match": "\\\"[^\"]*\\\"", 146 | "name": "entity.name.tag.jssmLabel.doublequoted" 147 | }, 148 | { 149 | "comment": "jssm label annotation", 150 | "match": "([a-zA-Z0-9_.+&()#@!?,])", 151 | "name": "entity.name.tag.jssmLabel.atom" 152 | } 153 | ], 154 | "scopeName": "source.jssm", 155 | "uuid": "2bb22b55-e811-4383-9929-ae6d0ab92aca" 156 | } 157 | -------------------------------------------------------------------------------- /packages/shiki/languages/jupyter.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.jupyter", 3 | "patterns": [ 4 | { 5 | "include": "source.json" 6 | } 7 | ], 8 | "name": "jupyter" 9 | } 10 | -------------------------------------------------------------------------------- /packages/shiki/languages/logo.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "Roughed out by Paul Bissex ", 3 | "fileTypes": [], 4 | "keyEquivalent": "^~L", 5 | "name": "logo", 6 | "patterns": [ 7 | { 8 | "match": "^to [\\w.]+", 9 | "name": "entity.name.function.logo" 10 | }, 11 | { 12 | "match": "continue|do\\.until|do\\.while|end|for(each)?|if(else|falsetrue|)|repeat|stop|until", 13 | "name": "keyword.control.logo" 14 | }, 15 | { 16 | "match": "\\b(\\.defmacro|\\.eq|\\.macro|\\.maybeoutput|\\.setbf|\\.setfirst|\\.setitem|\\.setsegmentsize|allopen|allowgetset|and|apply|arc|arctan|arity|array|arrayp|arraytolist|ascii|ashift|back|background|backslashedp|beforep|bitand|bitnot|bitor|bitxor|buried|buriedp|bury|buryall|buryname|butfirst|butfirsts|butlast|bye|cascade|case|caseignoredp|catch|char|clean|clearscreen|cleartext|close|closeall|combine|cond|contents|copydef|cos|count|crossmap|cursor|define|definedp|dequeue|difference|dribble|edall|edit|editfile|edn|edns|edpl|edpls|edps|emptyp|eofp|epspict|equalp|erall|erase|erasefile|ern|erns|erpl|erpls|erps|erract|error|exp|fence|filep|fill|filter|find|first|firsts|forever|form|forward|fput|fullprintp|fullscreen|fulltext|gc|gensym|global|goto|gprop|greaterp|heading|help|hideturtle|home|ignore|int|invoke|iseq|item|keyp|label|last|left|lessp|list|listp|listtoarray|ln|load|loadnoisily|loadpict|local|localmake|log10|lowercase|lput|lshift|macroexpand|macrop|make|map|map.se|mdarray|mditem|mdsetitem|member|memberp|minus|modulo|name|namelist|namep|names|nodes|nodribble|norefresh|not|numberp|openappend|openread|openupdate|openwrite|or|output|palette|parse|pause|pen|pencolor|pendown|pendownp|penerase|penmode|penpaint|penreverse|pensize|penup|pick|plist|plistp|plists|pllist|po|poall|pon|pons|pop|popl|popls|pops|pos|pot|pots|power|pprop|prefix|primitivep|print|printdepthlimit|printwidthlimit|procedurep|procedures|product|push|queue|quoted|quotient|radarctan|radcos|radsin|random|rawascii|readchar|readchars|reader|readlist|readpos|readrawline|readword|redefp|reduce|refresh|remainder|remdup|remove|remprop|repcount|rerandom|reverse|right|round|rseq|run|runparse|runresult|save|savel|savepict|screenmode|scrunch|sentence|setbackground|setcursor|seteditor|setheading|sethelploc|setitem|setlibloc|setmargins|setpalette|setpen|setpencolor|setpensize|setpos|setprefix|setread|setreadpos|setscrunch|settemploc|settextcolor|setwrite|setwritepos|setx|setxy|sety|shell|show|shownp|showturtle|sin|splitscreen|sqrt|standout|startup|step|stepped|steppedp|substringp|sum|tag|test|text|textscreen|thing|throw|towards|trace|traced|tracedp|transfer|turtlemode|type|unbury|unburyall|unburyname|unburyonedit|unstep|untrace|uppercase|usealternatenam|wait|while|window|word|wordp|wrap|writepos|writer|xcor|ycor)\\b", 17 | "name": "keyword.other.logo" 18 | }, 19 | { 20 | "captures": { 21 | "1": { 22 | "name": "punctuation.definition.variable.logo" 23 | } 24 | }, 25 | "match": "(\\:)(?:\\|[^|]*\\||[-\\w.]*)+", 26 | "name": "variable.parameter.logo" 27 | }, 28 | { 29 | "match": "\"(?:\\|[^|]*\\||[-\\w.]*)+", 30 | "name": "string.other.word.logo" 31 | }, 32 | { 33 | "begin": "(^[ \\t]+)?(?=;)", 34 | "beginCaptures": { 35 | "1": { 36 | "name": "punctuation.whitespace.comment.leading.logo" 37 | } 38 | }, 39 | "end": "(?!\\G)", 40 | "patterns": [ 41 | { 42 | "begin": ";", 43 | "beginCaptures": { 44 | "0": { 45 | "name": "punctuation.definition.comment.logo" 46 | } 47 | }, 48 | "end": "\\n", 49 | "name": "comment.line.semicolon.logo" 50 | } 51 | ] 52 | } 53 | ], 54 | "scopeName": "source.logo", 55 | "uuid": "7613EC24-B0F9-4D01-8706-1D54098BFFD8" 56 | } 57 | -------------------------------------------------------------------------------- /packages/shiki/languages/mdx.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", 3 | "name": "mdx", 4 | "patterns": [ 5 | { 6 | "include": "#jsx" 7 | }, 8 | { 9 | "include": "#markdown" 10 | } 11 | ], 12 | "repository": { 13 | "jsx": { 14 | "patterns": [ 15 | { 16 | "include": "#jsx-module" 17 | }, 18 | { 19 | "include": "#jsx-tag" 20 | } 21 | ], 22 | "repository": { 23 | "jsx-module": { 24 | "patterns": [ 25 | { 26 | "begin": "^(?=(import|export)\\b)", 27 | "while": "^(?!\\s*$)", 28 | "contentName": "source.js.jsx", 29 | "patterns": [ 30 | { 31 | "include": "source.js.jsx" 32 | } 33 | ] 34 | } 35 | ] 36 | }, 37 | "jsx-tag": { 38 | "patterns": [ 39 | { 40 | "begin": "^(?=<([a-z]|[A-Z]))", 41 | "end": "(?<=>)", 42 | "contentName": "source.js.jsx", 43 | "patterns": [ 44 | { 45 | "include": "source.js.jsx" 46 | } 47 | ] 48 | } 49 | ] 50 | } 51 | } 52 | }, 53 | "markdown": { 54 | "contentName": "text.html.markdown", 55 | "patterns": [ 56 | { 57 | "include": "text.html.markdown" 58 | } 59 | ] 60 | } 61 | }, 62 | "scopeName": "text.html.markdown.jsx" 63 | } 64 | -------------------------------------------------------------------------------- /packages/shiki/languages/pascal.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": ["pas", "p", "pp", "dfm", "fmx", "dpr", "dpk", "lfm", "lpr"], 3 | "keyEquivalent": "^~P", 4 | "name": "pascal", 5 | "patterns": [ 6 | { 7 | "match": "\\b(?i:(absolute|abstract|all|and_then|array|as|asm|attribute|begin|bindable|case|class|const|contains|default|div|else|end|except|export|exports|external|far|file|finalization|finally|forward|generic|goto|if|implements|import|in|index|inherited|initialization|interrupt|is|label|library|mod|module|name|near|not|object|of|on|only|operator|or_else|otherwise|override|package|packed|pow|private|program|protected|public|published|interface|implementation|qualified|read|record|resident|requires|resourcestring|restricted|segment|set|shl|shr|specialize|stored|strict|then|threadvar|to|try|type|unit|uses|var|view|virtual|dynamic|overload|reintroduce|with|write|xor))\\b", 8 | "name": "keyword.pascal" 9 | }, 10 | { 11 | "captures": { 12 | "1": { 13 | "name": "storage.type.prototype.pascal" 14 | }, 15 | "2": { 16 | "name": "entity.name.function.prototype.pascal" 17 | } 18 | }, 19 | "match": "\\b(?i:(function|procedure|constructor|destructor))\\b\\s+(\\w+(\\.\\w+)?)(\\(.*?\\))?;\\s*(?=(?i:attribute|forward|external))", 20 | "name": "meta.function.prototype.pascal" 21 | }, 22 | { 23 | "captures": { 24 | "1": { 25 | "name": "storage.type.function.pascal" 26 | }, 27 | "2": { 28 | "name": "entity.name.function.pascal" 29 | } 30 | }, 31 | "match": "\\b(?i:(function|procedure|constructor|destructor|property|read|write))\\b\\s+(\\w+(\\.\\w+)?)", 32 | "name": "meta.function.pascal" 33 | }, 34 | { 35 | "match": "\\b(?i:(self|result))\\b", 36 | "name": "token.variable" 37 | }, 38 | { 39 | "match": "\\b(?i:(and|or))\\b", 40 | "name": "keyword.operator.pascal" 41 | }, 42 | { 43 | "match": "\\b(?i:(break|continue|exit|abort|while|do|for|raise|repeat|until))\\b", 44 | "name": "keyword.control.pascal" 45 | }, 46 | { 47 | "begin": "\\{\\$", 48 | "captures": { 49 | "0": { 50 | "name": "string.regexp" 51 | } 52 | }, 53 | "end": "\\}", 54 | "name": "string.regexp" 55 | }, 56 | { 57 | "match": "\\b(?i:(ansichar|ansistring|boolean|byte|cardinal|char|comp|currency|double|dword|extended|file|integer|int64|longint|longword|nativeint|nativeuint|olevariant|pansichar|pchar|pwidechar|pointer|real|shortint|shortstring|single|smallint|string|uint64|variant|widechar|widestring|word|wordbool))\\b", 58 | "name": "storage.support.type.pascal" 59 | }, 60 | { 61 | "match": "\\b(\\d+)|(\\d*\\.\\d+([eE][\\-+]?\\d+)?)\\b", 62 | "name": "constant.numeric.pascal" 63 | }, 64 | { 65 | "match": "\\$[0-9a-fA-F]{1,16}\\b", 66 | "name": "constant.numeric.hex.pascal" 67 | }, 68 | { 69 | "match": "\\b(?i:(true|false|nil))\\b", 70 | "name": "constant.language.pascal" 71 | }, 72 | { 73 | "match": "\\b(?i:(Assert))\\b", 74 | "name": "keyword.control" 75 | }, 76 | { 77 | "begin": "(^[ \\t]+)?(?=//)", 78 | "beginCaptures": { 79 | "1": { 80 | "name": "punctuation.whitespace.comment.leading.pascal" 81 | } 82 | }, 83 | "end": "(?!\\G)", 84 | "patterns": [ 85 | { 86 | "begin": "//", 87 | "beginCaptures": { 88 | "0": { 89 | "name": "punctuation.definition.comment.pascal" 90 | } 91 | }, 92 | "end": "\\n", 93 | "name": "comment.line.double-slash.pascal.two" 94 | } 95 | ] 96 | }, 97 | { 98 | "begin": "\\(\\*", 99 | "captures": { 100 | "0": { 101 | "name": "punctuation.definition.comment.pascal" 102 | } 103 | }, 104 | "end": "\\*\\)", 105 | "name": "comment.block.pascal.one" 106 | }, 107 | { 108 | "begin": "\\{(?!\\$)", 109 | "captures": { 110 | "0": { 111 | "name": "punctuation.definition.comment.pascal" 112 | } 113 | }, 114 | "end": "\\}", 115 | "name": "comment.block.pascal.two" 116 | }, 117 | { 118 | "begin": "'", 119 | "beginCaptures": { 120 | "0": { 121 | "name": "punctuation.definition.string.begin.pascal" 122 | } 123 | }, 124 | "end": "'", 125 | "endCaptures": { 126 | "0": { 127 | "name": "punctuation.definition.string.end.pascal" 128 | } 129 | }, 130 | "name": "string.quoted.single.pascal", 131 | "patterns": [ 132 | { 133 | "match": "''", 134 | "name": "constant.character.escape.apostrophe.pascal" 135 | } 136 | ] 137 | }, 138 | { 139 | "match": "\\#\\d+", 140 | "name": "string.other.pascal" 141 | } 142 | ], 143 | "scopeName": "source.pascal", 144 | "uuid": "F42FA544-6B1C-11D9-9517-000D93589AF6" 145 | } 146 | -------------------------------------------------------------------------------- /packages/shiki/languages/php-html.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "This file has been converted from https://github.com/atom/language-php/blob/master/grammars/html.cson", 4 | "If you want to provide a fix or improvement, please create a pull request against the original repository.", 5 | "Once accepted there, we are happy to receive an update request." 6 | ], 7 | "version": "https://github.com/atom/language-php/commit/2bf736a814e1a58aa63470c1a29590bd02e924e7", 8 | "name": "php-html", 9 | "scopeName": "text.html.php", 10 | "injections": { 11 | "text.html.php - (meta.embedded | meta.tag), L:((text.html.php meta.tag) - (meta.embedded.block.php | meta.embedded.line.php)), L:(source.js - (meta.embedded.block.php | meta.embedded.line.php)), L:(source.css - (meta.embedded.block.php | meta.embedded.line.php))": { 12 | "patterns": [ 13 | { 14 | "include": "#php-tag" 15 | } 16 | ] 17 | } 18 | }, 19 | "patterns": [ 20 | { 21 | "begin": "\\A#!", 22 | "beginCaptures": { 23 | "0": { 24 | "name": "punctuation.definition.comment.php" 25 | } 26 | }, 27 | "end": "$", 28 | "name": "comment.line.shebang.php" 29 | }, 30 | { 31 | "include": "text.html.derivative" 32 | } 33 | ], 34 | "repository": { 35 | "php-tag": { 36 | "patterns": [ 37 | { 38 | "begin": "<\\?(?i:php|=)?(?![^?]*\\?>)", 39 | "beginCaptures": { 40 | "0": { 41 | "name": "punctuation.section.embedded.begin.php" 42 | } 43 | }, 44 | "end": "(\\?)>", 45 | "endCaptures": { 46 | "0": { 47 | "name": "punctuation.section.embedded.end.php" 48 | }, 49 | "1": { 50 | "name": "source.php" 51 | } 52 | }, 53 | "name": "meta.embedded.block.php", 54 | "contentName": "source.php", 55 | "patterns": [ 56 | { 57 | "include": "source.php" 58 | } 59 | ] 60 | }, 61 | { 62 | "begin": "<\\?(?i:php|=)?", 63 | "beginCaptures": { 64 | "0": { 65 | "name": "punctuation.section.embedded.begin.php" 66 | } 67 | }, 68 | "end": "(\\?)>", 69 | "endCaptures": { 70 | "0": { 71 | "name": "punctuation.section.embedded.end.php" 72 | }, 73 | "1": { 74 | "name": "source.php" 75 | } 76 | }, 77 | "name": "meta.embedded.line.php", 78 | "contentName": "source.php", 79 | "patterns": [ 80 | { 81 | "include": "source.php" 82 | } 83 | ] 84 | } 85 | ] 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /packages/shiki/languages/sparql.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sparql", 3 | "scopeName": "source.sparql", 4 | "fileTypes": ["rq", "sparql"], 5 | "patterns": [ 6 | { 7 | "include": "source.turtle" 8 | }, 9 | { 10 | "include": "#query-keyword-operators" 11 | }, 12 | { 13 | "include": "#functions" 14 | }, 15 | { 16 | "include": "#variables" 17 | }, 18 | { 19 | "include": "#expression-operators" 20 | } 21 | ], 22 | "repository": { 23 | "query-keyword-operators": { 24 | "name": "keyword.control.sparql", 25 | "match": "\\b(?i:define|select|distinct|reduced|from|named|construct|ask|describe|where|graph|having|bind|as|filter|optional|union|order|by|group|limit|offset|values|insert data|delete data|with|delete|insert|clear|silent|default|all|create|drop|copy|move|add|to|using|service|not exists|exists|not in|in|minus|load)\\b" 26 | }, 27 | "functions": { 28 | "name": "support.function.sparql", 29 | "match": "\\b(?i:concat|regex|asc|desc|bound|isiri|isuri|isblank|isliteral|isnumeric|str|lang|datatype|sameterm|langmatches|avg|count|group_concat|separator|max|min|sample|sum|iri|uri|bnode|strdt|uuid|struuid|strlang|strlen|substr|ucase|lcase|strstarts|strends|contains|strbefore|strafter|encode_for_uri|replace|abs|round|ceil|floor|rand|now|year|month|day|hours|minutes|seconds|timezone|tz|md5|sha1|sha256|sha384|sha512|coalesce|if)\\b" 30 | }, 31 | "variables": { 32 | "name": "constant.variable.sparql.turtle", 33 | "match": "(?|<=|>=|\\*|/|\\+|-|\\||\\^|\\?|\\!)" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/shiki/languages/ssh-config.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": ["ssh_config", ".ssh/config", "sshd_config"], 3 | "name": "ssh-config", 4 | "patterns": [ 5 | { 6 | "match": "\\b(A(cceptEnv|dd(ressFamily|KeysToAgent)|llow(AgentForwarding|Groups|StreamLocalForwarding|TcpForwarding|Users)|uth(enticationMethods|orized((Keys(Command(User)?|File)|Principals(Command(User)?|File)))))|B(anner|atchMode|ind(Address|Interface))|C(anonical(Domains|ize(FallbackLocal|Hostname|MaxDots|PermittedCNAMEs))|ertificateFile|hallengeResponseAuthentication|heckHostIP|hrootDirectory|iphers?|learAllForwardings|ientAlive(CountMax|Interval)|ompression(Level)?|onnect(Timeout|ionAttempts)|ontrolMaster|ontrolPath|ontrolPersist)|D(eny(Groups|Users)|isableForwarding|ynamicForward)|E(nableSSHKeysign|scapeChar|xitOnForwardFailure|xposeAuthInfo)|F(ingerprintHash|orceCommand|orward(Agent|X11(Timeout|Trusted)?))|G(atewayPorts|SSAPI(Authentication|CleanupCredentials|ClientIdentity|DelegateCredentials|KeyExchange|RenewalForcesRekey|ServerIdentity|StrictAcceptorCheck|TrustDns)|atewayPorts|lobalKnownHostsFile)|H(ashKnownHosts|ost(based(AcceptedKeyTypes|Authentication|KeyTypes|UsesNameFromPacketOnly)|Certificate|Key(Agent|Algorithms|Alias)?|Name))|I(dentit(iesOnly|y(Agent|File))|gnore(Rhosts|Unknown|UserKnownHosts)|nclude|PQoS)|K(bdInteractive(Authentication|Devices)|erberos(Authentication|GetAFSToken|OrLocalPasswd|TicketCleanup)|exAlgorithms)|L(istenAddress|ocal(Command|Forward)|oginGraceTime|ogLevel)|M(ACs|atch|ax(AuthTries|Sessions|Startups))|N(oHostAuthenticationForLocalhost|umberOfPasswordPrompts)|P(KCS11Provider|asswordAuthentication|ermit(EmptyPasswords|LocalCommand|Open|RootLogin|TTY|Tunnel|User(Environment|RC))|idFile|ort|referredAuthentications|rint(LastLog|Motd)|rotocol|roxy(Command|Jump|UseFdpass)|ubkey(AcceptedKeyTypes|Authentication))|R(Domain|SAAuthentication|ekeyLimit|emote(Command|Forward)|equestTTY|evoked(HostKeys|Keys)|hostsRSAAuthentication)|S(endEnv|erverAlive(CountMax|Interval)|treamLocalBind(Mask|Unlink)|trict(HostKeyChecking|Modes)|ubsystem|yslogFacility)|T(CPKeepAlive|rustedUserCAKeys|unnel(Device)?)|U(pdateHostKeys|se(BlacklistedKeys|DNS|Keychain|PAM|PrivilegedPort|r(KnownHostsFile)?))|V(erifyHostKeyDNS|ersionAddendum|isualHostKey)|X(11(DisplayOffset|Forwarding|UseLocalhost)|AuthLocation))\\b", 7 | "name": "keyword.other.ssh-config" 8 | }, 9 | { 10 | "begin": "(^[ \\t]+)?(?=#)", 11 | "beginCaptures": { 12 | "1": { 13 | "name": "punctuation.whitespace.comment.leading.ssh-config" 14 | } 15 | }, 16 | "end": "(?!\\G)", 17 | "patterns": [ 18 | { 19 | "begin": "#", 20 | "beginCaptures": { 21 | "0": { 22 | "name": "punctuation.definition.comment.ssh-config" 23 | } 24 | }, 25 | "end": "\\n", 26 | "name": "comment.line.number-sign.ssh-config" 27 | } 28 | ] 29 | }, 30 | { 31 | "begin": "(^[ \\t]+)?(?=//)", 32 | "beginCaptures": { 33 | "1": { 34 | "name": "punctuation.whitespace.comment.leading.ssh-config" 35 | } 36 | }, 37 | "end": "(?!\\G)", 38 | "patterns": [ 39 | { 40 | "begin": "//", 41 | "beginCaptures": { 42 | "0": { 43 | "name": "punctuation.definition.comment.ssh-config" 44 | } 45 | }, 46 | "end": "\\n", 47 | "name": "comment.line.double-slash.ssh-config" 48 | } 49 | ] 50 | }, 51 | { 52 | "captures": { 53 | "1": { 54 | "name": "storage.type.ssh-config" 55 | }, 56 | "2": { 57 | "name": "entity.name.section.ssh-config" 58 | }, 59 | "3": { 60 | "name": "meta.toc-list.ssh-config" 61 | } 62 | }, 63 | "match": "(?:^| |\\t)(Host)\\s+((.*))$" 64 | }, 65 | { 66 | "match": "\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b", 67 | "name": "constant.numeric.ssh-config" 68 | }, 69 | { 70 | "match": "\\b[0-9]+\\b", 71 | "name": "constant.numeric.ssh-config" 72 | }, 73 | { 74 | "match": "\\b(yes|no)\\b", 75 | "name": "constant.language.ssh-config" 76 | }, 77 | { 78 | "match": "\\b[A-Z_]+\\b", 79 | "name": "constant.language.ssh-config" 80 | } 81 | ], 82 | "scopeName": "source.ssh-config", 83 | "uuid": "B273855C-59D3-4DF3-9B7C-E68E0057D315" 84 | } 85 | -------------------------------------------------------------------------------- /packages/shiki/languages/wenyan.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", 3 | "scopeName": "source.wenyan", 4 | "name": "wenyan", 5 | "patterns": [ 6 | { 7 | "include": "#keywords" 8 | }, 9 | { 10 | "include": "#constants" 11 | }, 12 | { 13 | "include": "#operators" 14 | }, 15 | { 16 | "include": "#symbols" 17 | }, 18 | { 19 | "include": "#expression" 20 | }, 21 | { 22 | "include": "#comment-blocks" 23 | }, 24 | { 25 | "include": "#comment-lines" 26 | } 27 | ], 28 | "repository": { 29 | "expression": { 30 | "patterns": [ 31 | { 32 | "include": "#variables" 33 | } 34 | ] 35 | }, 36 | "keywords": { 37 | "patterns": [ 38 | { 39 | "name": "storage.type", 40 | "match": "數|列|言|術|爻|物|元" 41 | }, 42 | { 43 | "name": "keyword.control", 44 | "match": "乃行是術曰|若其不然者|乃歸空無|欲行是術|乃止是遍|若其然者|其物如是|乃得矣|之術也|必先得|是術曰|恆為是|之物也|乃得|是謂|云云|中之|為是|乃止|若非|或若|之長|其餘" 45 | }, 46 | { 47 | "name": "keyword.control", 48 | "match": "或云|蓋謂" 49 | }, 50 | { 51 | "name": "keyword.operator", 52 | "match": "中有陽乎|中無陰乎|所餘幾何|不等於|不大於|不小於|等於|大於|小於|加|減|乘|除|變|以|於" 53 | }, 54 | { 55 | "name": "keyword.other", 56 | "match": "不知何禍歟|不復存矣|姑妄行此|如事不諧|名之曰|吾嘗觀|之禍歟|乃作罷|吾有|今有|物之|書之|以施|昔之|是矣|之書|方悟|之義|嗚呼|之禍|有|施|曰|噫|取|今|夫|中|豈" 57 | }, 58 | { 59 | "name": "keyword.control", 60 | "match": "也|凡|遍|若|者|之|充|銜" 61 | } 62 | ] 63 | }, 64 | "comment-lines": { 65 | "name": "comment.line", 66 | "begin": "注曰|疏曰|批曰", 67 | "end": "$", 68 | "patterns": [ 69 | { 70 | "name": "constant.character", 71 | "match": "\\\\." 72 | } 73 | ] 74 | }, 75 | "comment-blocks": { 76 | "name": "comment.block", 77 | "begin": "(注曰|疏曰|批曰)。?(「「|『)", 78 | "end": "(」」|』)", 79 | "patterns": [ 80 | { 81 | "name": "constant.character", 82 | "match": "\\\\." 83 | } 84 | ] 85 | }, 86 | "constants": { 87 | "patterns": [ 88 | { 89 | "name": "constant.numeric", 90 | "match": "負|·|又|零|〇|一|二|三|四|五|六|七|八|九|十|百|千|萬|億|兆|京|垓|秭|穰|溝|澗|正|載|極|分|釐|毫|絲|忽|微|纖|沙|塵|埃|渺|漠" 91 | }, 92 | { 93 | "name": "constant.language", 94 | "match": "其|陰|陽" 95 | }, 96 | { 97 | "name": "string.quoted", 98 | "begin": "「「|『", 99 | "end": "」」|』", 100 | "patterns": [ 101 | { 102 | "name": "constant.character", 103 | "match": "\\\\." 104 | } 105 | ] 106 | } 107 | ] 108 | }, 109 | "symbols": { 110 | "patterns": [ 111 | { 112 | "name": "punctuation.separator", 113 | "match": "。|、" 114 | } 115 | ] 116 | }, 117 | "variables": { 118 | "name": "variable.other", 119 | "begin": "「", 120 | "end": "」", 121 | "patterns": [ 122 | { 123 | "name": "constant.character", 124 | "match": "\\\\." 125 | } 126 | ] 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /packages/shiki/languages/xsl.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "This file has been converted from https://github.com/atom/language-xml/blob/master/grammars/xsl.cson", 4 | "If you want to provide a fix or improvement, please create a pull request against the original repository.", 5 | "Once accepted there, we are happy to receive an update request." 6 | ], 7 | "version": "https://github.com/atom/language-xml/commit/507de2ee7daca60cf02e9e21fbeb92bbae73e280", 8 | "name": "xsl", 9 | "scopeName": "text.xml.xsl", 10 | "patterns": [ 11 | { 12 | "begin": "(<)(xsl)((:))(template)", 13 | "captures": { 14 | "1": { 15 | "name": "punctuation.definition.tag.xml" 16 | }, 17 | "2": { 18 | "name": "entity.name.tag.namespace.xml" 19 | }, 20 | "3": { 21 | "name": "entity.name.tag.xml" 22 | }, 23 | "4": { 24 | "name": "punctuation.separator.namespace.xml" 25 | }, 26 | "5": { 27 | "name": "entity.name.tag.localname.xml" 28 | } 29 | }, 30 | "end": "(>)", 31 | "name": "meta.tag.xml.template", 32 | "patterns": [ 33 | { 34 | "captures": { 35 | "1": { 36 | "name": "entity.other.attribute-name.namespace.xml" 37 | }, 38 | "2": { 39 | "name": "entity.other.attribute-name.xml" 40 | }, 41 | "3": { 42 | "name": "punctuation.separator.namespace.xml" 43 | }, 44 | "4": { 45 | "name": "entity.other.attribute-name.localname.xml" 46 | } 47 | }, 48 | "match": " (?:([-_a-zA-Z0-9]+)((:)))?([a-zA-Z-]+)" 49 | }, 50 | { 51 | "include": "#doublequotedString" 52 | }, 53 | { 54 | "include": "#singlequotedString" 55 | } 56 | ] 57 | }, 58 | { 59 | "include": "text.xml" 60 | } 61 | ], 62 | "repository": { 63 | "doublequotedString": { 64 | "begin": "\"", 65 | "beginCaptures": { 66 | "0": { 67 | "name": "punctuation.definition.string.begin.xml" 68 | } 69 | }, 70 | "end": "\"", 71 | "endCaptures": { 72 | "0": { 73 | "name": "punctuation.definition.string.end.xml" 74 | } 75 | }, 76 | "name": "string.quoted.double.xml" 77 | }, 78 | "singlequotedString": { 79 | "begin": "'", 80 | "beginCaptures": { 81 | "0": { 82 | "name": "punctuation.definition.string.begin.xml" 83 | } 84 | }, 85 | "end": "'", 86 | "endCaptures": { 87 | "0": { 88 | "name": "punctuation.definition.string.end.xml" 89 | } 90 | }, 91 | "name": "string.quoted.single.xml" 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /packages/shiki/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shiki", 3 | "version": "0.9.6", 4 | "description": "shiki", 5 | "author": "Pine Wu ", 6 | "homepage": "https://github.com/octref/shiki/tree/main/packages/shiki", 7 | "license": "MIT", 8 | "main": "dist/index.js", 9 | "module": "dist/index.esm.js", 10 | "types": "dist/index.d.ts", 11 | "unpkg": "dist/index.unpkg.iife.js", 12 | "jsdelivr": "dist/index.jsdelivr.iife.js", 13 | "keywords": [ 14 | "shiki", 15 | "syntax-highlighter", 16 | "highlighter" 17 | ], 18 | "files": [ 19 | "dist", 20 | "languages", 21 | "themes", 22 | "samples" 23 | ], 24 | "scripts": { 25 | "prepublishOnly": "npm run build", 26 | "build": "rollup -c", 27 | "watch": "rollup -c -w" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/octref/shiki.git" 32 | }, 33 | "dependencies": { 34 | "json5": "^2.2.0", 35 | "onigasm": "^2.2.5", 36 | "vscode-textmate": "5.2.0" 37 | }, 38 | "browser": { 39 | "fs": false, 40 | "path": false 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/shiki/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { nodeResolve } from '@rollup/plugin-node-resolve' 2 | import commonjs from '@rollup/plugin-commonjs' 3 | import dts from 'rollup-plugin-dts' 4 | import typescript from 'rollup-plugin-typescript2' 5 | import copy from 'rollup-plugin-copy' 6 | import replace from '@rollup/plugin-replace' 7 | import { terser } from 'rollup-plugin-terser' 8 | import { version } from './package.json' 9 | 10 | const external = ['onigasm', 'vscode-textmate'] 11 | 12 | export default [ 13 | { 14 | input: 'src/index.ts', 15 | external, 16 | output: [ 17 | { 18 | file: 'dist/index.js', 19 | format: 'cjs' 20 | }, 21 | { 22 | file: 'dist/index.esm.js', 23 | format: 'esm' 24 | } 25 | ], 26 | plugins: [ 27 | replace({ 28 | __CDN_ROOT__: '', 29 | __BROWSER__: JSON.stringify(false) 30 | }), 31 | typescript(), 32 | nodeResolve(), 33 | commonjs() 34 | ] 35 | }, 36 | { 37 | input: 'src/index.ts', 38 | output: [ 39 | { 40 | file: 'dist/index.browser.mjs', 41 | format: 'esm', 42 | plugins: [ 43 | replace({ 44 | __CDN_ROOT__: '' 45 | }) 46 | ] 47 | }, 48 | { 49 | file: 'dist/index.iife.js', 50 | format: 'iife', 51 | name: 'shiki', 52 | extend: true, 53 | plugins: [ 54 | replace({ 55 | __CDN_ROOT__: '' 56 | }) 57 | ] 58 | }, 59 | { 60 | file: 'dist/index.unpkg.iife.js', 61 | format: 'iife', 62 | name: 'shiki', 63 | extend: true, 64 | plugins: [ 65 | replace({ 66 | __CDN_ROOT__: `https://unpkg.com/shiki@${version}/` 67 | }) 68 | ] 69 | }, 70 | { 71 | file: 'dist/index.jsdelivr.iife.js', 72 | format: 'iife', 73 | name: 'shiki', 74 | extend: true, 75 | plugins: [ 76 | replace({ 77 | __CDN_ROOT__: `https://cdn.jsdelivr.net/npm/shiki@${version}/` 78 | }) 79 | ] 80 | } 81 | ], 82 | plugins: [ 83 | replace({ 84 | __BROWSER__: JSON.stringify(true) 85 | }), 86 | typescript(), 87 | nodeResolve(), 88 | commonjs(), 89 | terser() 90 | ] 91 | }, 92 | { 93 | input: 'src/index.ts', 94 | output: [ 95 | { 96 | file: 'dist/index.d.ts', 97 | format: 'es' 98 | } 99 | ], 100 | plugins: [ 101 | dts(), 102 | copy({ 103 | targets: [{ src: '../../node_modules/onigasm/lib/onigasm.wasm', dest: 'dist' }] 104 | }) 105 | ], 106 | onwarn: (msg, warn) => { 107 | if (!/Circular/.test(msg)) { 108 | warn(msg) 109 | } 110 | } 111 | } 112 | ] 113 | -------------------------------------------------------------------------------- /packages/shiki/samples/c.sample: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ARR_LEN 7 4 | 5 | void qsort(int v[], int left, int right); 6 | void printArr(int v[], int len); 7 | 8 | int main() 9 | { 10 | int i; 11 | int v[ARR_LEN] = { 4, 3, 1, 7, 9, 6, 2 }; 12 | printArr(v, ARR_LEN); 13 | qsort(v, 0, ARR_LEN-1); 14 | printArr(v, ARR_LEN); 15 | return 0; 16 | } 17 | 18 | void qsort(int v[], int left, int right) 19 | { 20 | int i, last; 21 | void swap(int v[], int i, int j); 22 | 23 | if (left >= right) 24 | return; 25 | swap(v, left, (left + right) / 2); 26 | last = left; 27 | for (i = left+1; i <= right; i++) 28 | if (v[i] < v[left]) 29 | swap(v, ++last, i); 30 | swap(v, left, last); 31 | qsort(v, left, last-1); 32 | qsort(v, last+1, right); 33 | } 34 | 35 | void swap(int v[], int i, int j) 36 | { 37 | int temp; 38 | 39 | temp = v[i]; 40 | v[i] = v[j]; 41 | v[j] = temp; 42 | } 43 | 44 | void printArr(int v[], int len) 45 | { 46 | int i; 47 | for (i = 0; i < len; i++) 48 | printf("%d ", v[i]); 49 | printf("\n"); 50 | } 51 | 52 | // From https://github.com/Heatwave/The-C-Programming-Language-2nd-Edition/blob/master/chapter-4-functions-and-program-structure/8.qsort.c -------------------------------------------------------------------------------- /packages/shiki/samples/css.sample: -------------------------------------------------------------------------------- 1 | .Aligner { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | } 6 | 7 | .Aligner-item { 8 | max-width: 50%; 9 | } 10 | 11 | .Aligner-item--top { 12 | align-self: flex-start; 13 | } 14 | 15 | .Aligner-item--bottom { 16 | align-self: flex-end; 17 | } 18 | 19 | /* From https://philipwalton.github.io/solved-by-flexbox/demos/vertical-centering/ */ -------------------------------------------------------------------------------- /packages/shiki/samples/dm.sample: -------------------------------------------------------------------------------- 1 | //Allows you to set a theme for a set of areas without tying them to looping sounds explicitly 2 | /datum/component/area_sound_manager 3 | //area -> looping sound type 4 | var/list/area_to_looping_type = list() 5 | //Current sound loop 6 | var/datum/looping_sound/our_loop 7 | //A list of "acceptable" z levels to be on. If you leave this, we're gonna delete ourselves 8 | var/list/accepted_zs 9 | //The timer id of our current start delay, if it exists 10 | var/timerid 11 | 12 | /datum/component/area_sound_manager/Initialize(area_loop_pairs, change_on, remove_on, acceptable_zs) 13 | if(!ismovable(parent)) 14 | return 15 | area_to_looping_type = area_loop_pairs 16 | accepted_zs = acceptable_zs 17 | change_the_track() 18 | 19 | RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/react_to_move) 20 | RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, .proc/react_to_z_move) 21 | RegisterSignal(parent, change_on, .proc/handle_change) 22 | RegisterSignal(parent, remove_on, .proc/handle_removal) 23 | 24 | /datum/component/area_sound_manager/Destroy(force, silent) 25 | QDEL_NULL(our_loop) 26 | . = ..() 27 | 28 | /datum/component/area_sound_manager/proc/react_to_move(datum/source, atom/oldloc, dir, forced) 29 | SIGNAL_HANDLER 30 | var/list/loop_lookup = area_to_looping_type 31 | if(loop_lookup[get_area(oldloc)] == loop_lookup[get_area(parent)]) 32 | return 33 | change_the_track(TRUE) 34 | 35 | /datum/component/area_sound_manager/proc/react_to_z_move(datum/source, old_z, new_z) 36 | SIGNAL_HANDLER 37 | if(!length(accepted_zs) || (new_z in accepted_zs)) 38 | return 39 | qdel(src) 40 | 41 | /datum/component/area_sound_manager/proc/handle_removal(datum/source) 42 | SIGNAL_HANDLER 43 | qdel(src) 44 | 45 | /datum/component/area_sound_manager/proc/handle_change(datum/source) 46 | SIGNAL_HANDLER 47 | change_the_track() 48 | 49 | /datum/component/area_sound_manager/proc/change_the_track(skip_start = FALSE) 50 | var/time_remaining = 0 51 | 52 | if(our_loop) 53 | var/our_id = our_loop.timerid || timerid 54 | if(our_id) 55 | time_remaining = timeleft(our_id, SSsound_loops) || 0 56 | //Time left will sometimes return negative values, just ignore them and start a new sound loop now 57 | time_remaining = max(time_remaining, 0) 58 | QDEL_NULL(our_loop) 59 | 60 | var/area/our_area = get_area(parent) 61 | var/new_loop_type = area_to_looping_type[our_area] 62 | if(!new_loop_type) 63 | return 64 | 65 | our_loop = new new_loop_type(parent, FALSE, TRUE, skip_start) 66 | 67 | //If we're still playing, wait a bit before changing the sound so we don't double up 68 | if(time_remaining) 69 | timerid = addtimer(CALLBACK(src, .proc/start_looping_sound), time_remaining, TIMER_UNIQUE | TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_NO_HASH_WAIT | TIMER_DELETE_ME, SSsound_loops) 70 | return 71 | timerid = null 72 | our_loop.start() 73 | 74 | /datum/component/area_sound_manager/proc/start_looping_sound() 75 | timerid = null 76 | if(our_loop) 77 | our_loop.start() 78 | -------------------------------------------------------------------------------- /packages/shiki/samples/fsl.sample: -------------------------------------------------------------------------------- 1 | 2 | machine_name : "TCP/IP"; 3 | machine_reference : "http://www.texample.net/tikz/examples/tcp-state-machine/"; 4 | machine_version : 1.0.0; 5 | 6 | machine_author : "John Haugeland "; 7 | machine_license : MIT; 8 | 9 | jssm_version : >= 5.0.0; 10 | 11 | 12 | 13 | Closed 'Passive open' -> Listen; 14 | Closed 'Active Open / SYN' -> SynSent; 15 | 16 | Listen 'Close' -> Closed; 17 | Listen 'Send / SYN' -> SynSent; 18 | Listen 'SYN / SYN+ACK' -> SynRcvd; 19 | 20 | SynSent 'Close' -> Closed; 21 | SynSent 'SYN / SYN+ACK' -> SynRcvd; 22 | SynSent 'SYN+ACK / ACK' -> Established; 23 | 24 | SynRcvd 'Timeout / RST' -> Closed; 25 | SynRcvd 'Close / FIN' -> FinWait1; 26 | SynRcvd 'ACK' -> Established; 27 | 28 | Established 'Close / FIN' -> FinWait1; 29 | Established 'FIN / ACK' -> CloseWait; 30 | 31 | FinWait1 'FIN / ACK' -> Closing; // the source diagram has this action wrong 32 | FinWait1 'FIN+ACK / ACK' -> TimeWait; 33 | FinWait1 'ACK / Nothing' -> FinWait2; // see http://www.cs.odu.edu/~cs779/spring17/lectures/architecture_files/image009.jpg 34 | 35 | FinWait2 'FIN / ACK' -> TimeWait; 36 | 37 | Closing 'ACK' -> TimeWait; 38 | 39 | TimeWait 'Up to 2*MSL' -> Closed; 40 | 41 | CloseWait 'Close / FIN' -> LastAck; 42 | 43 | LastAck 'ACK' -> Closed; 44 | 45 | 46 | 47 | # From https://github.com/StoneCypher/jssm/blob/main/src/machines/linguist/tcp%20ip.fsl -------------------------------------------------------------------------------- /packages/shiki/samples/go.sample: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func handler(w http.ResponseWriter, r *http.Request) { 10 | fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) 11 | } 12 | 13 | func main() { 14 | http.HandleFunc("/", handler) 15 | log.Fatal(http.ListenAndServe(":8080", nil)) 16 | } 17 | 18 | // From https://golang.org/doc/articles/wiki/#tmp_3 -------------------------------------------------------------------------------- /packages/shiki/samples/html.sample: -------------------------------------------------------------------------------- 1 | 20 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/shiki/samples/java.sample: -------------------------------------------------------------------------------- 1 | public class HelloWorld { 2 | 3 | public static void main(String[] args) { 4 | // Prints "Hello, World" to the terminal window. 5 | System.out.println("Hello, World"); 6 | } 7 | 8 | } 9 | 10 | // From https://introcs.cs.princeton.edu/java/11hello/HelloWorld.java.html -------------------------------------------------------------------------------- /packages/shiki/samples/javascript.sample: -------------------------------------------------------------------------------- 1 | // posts will be populated at build time by getStaticProps() 2 | function Blog({ posts }) { 3 | return ( 4 |
    5 | {posts.map((post) => ( 6 |
  • {post.title}
  • 7 | ))} 8 |
9 | ) 10 | } 11 | 12 | // This function gets called at build time on server-side. 13 | export async function getStaticProps() { 14 | const res = await fetch('https://.../posts') 15 | const posts = await res.json() 16 | 17 | return { 18 | props: { 19 | posts 20 | } 21 | } 22 | } 23 | 24 | export default Blog 25 | 26 | // From https://nextjs.org/docs/basic-features/data-fetching 27 | -------------------------------------------------------------------------------- /packages/shiki/samples/jssm.sample: -------------------------------------------------------------------------------- 1 | 2 | machine_name : "BGP"; 3 | machine_reference : "http://www.inetdaemon.com/tutorials/internet/ip/routing/bgp/operation/finite_state_model.shtml"; 4 | machine_version : 1.0.0; 5 | 6 | machine_author : "John Haugeland "; 7 | machine_license : MIT; 8 | 9 | jssm_version : >= 5.0.0; 10 | 11 | 12 | 13 | Idle -> [Idle Connect]; 14 | Connect -> [Idle Connect OpenSent Active]; 15 | Active -> [Idle Connect OpenSent Active]; 16 | OpenSent -> [Idle Active OpenConfirm]; 17 | OpenConfirm -> [Idle OpenSent OpenConfirm Established]; 18 | Established -> [Idle Established]; 19 | 20 | 21 | 22 | # from https://github.com/StoneCypher/jssm/blob/main/src/machines/linguist/bgp.fsl -------------------------------------------------------------------------------- /packages/shiki/samples/prisma.sample: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator client { 7 | provider = "prisma-client-js" 8 | } 9 | 10 | /// Post including an author and content. 11 | model Post { 12 | id Int @default(autoincrement()) @id 13 | content String? 14 | published Boolean @default(false) 15 | author User? @relation(fields: [authorId], references: [id]) 16 | authorId Int? 17 | } 18 | 19 | // Documentation for this model. 20 | model User { 21 | id Int @default(autoincrement()) @id 22 | email String @unique 23 | name String? 24 | posts Post[] 25 | specialName UserName 26 | test Test 27 | } 28 | 29 | /// This is an enum specifying the UserName. 30 | enum UserName { 31 | Fred 32 | Eric 33 | } 34 | 35 | // This is a test enum. 36 | enum Test { 37 | TestUno 38 | TestDue 39 | } 40 | 41 | // taken from https://github.com/prisma/language-tools/blob/master/packages/vscode/testFixture/hover.prisma 42 | -------------------------------------------------------------------------------- /packages/shiki/samples/python.sample: -------------------------------------------------------------------------------- 1 | def fib(n): # write Fibonacci series up to n 2 | """Print a Fibonacci series up to n.""" 3 | a, b = 0, 1 4 | while a < n: 5 | print(a, end=' ') 6 | a, b = b, a+b 7 | print() 8 | 9 | # Now call the function we just defined: 10 | fib(2000) 11 | 12 | # From https://docs.python.org/3/tutorial/controlflow.html#defining-functions -------------------------------------------------------------------------------- /packages/shiki/samples/ruby.sample: -------------------------------------------------------------------------------- 1 | class LotteryTicket 2 | 3 | NUMERIC_RANGE = 1..25 4 | 5 | attr_reader :picks, :purchased 6 | 7 | def initialize( *picks ) 8 | if picks.length != 3 9 | raise ArgumentError, "three numbers must be picked" 10 | elsif picks.uniq.length != 3 11 | raise ArgumentError, "the three picks must be different numbers" 12 | elsif picks.detect { |p| not NUMERIC_RANGE === p } 13 | raise ArgumentError, "the three picks must be numbers between 1 and 25" 14 | end 15 | @picks = picks 16 | @purchased = Time.now 17 | end 18 | 19 | end 20 | 21 | # From https://poignant.guide/book/chapter-5.html -------------------------------------------------------------------------------- /packages/shiki/samples/sparql.sample: -------------------------------------------------------------------------------- 1 | PREFIX foaf: 2 | SELECT ?name (COUNT(?friend) AS ?count) 3 | WHERE { 4 | ?person foaf:name ?name . 5 | ?person foaf:knows ?friend . 6 | } GROUP BY ?person ?name 7 | 8 | # From https://www.w3.org/TR/sparql11-overview/#sparql11-query -------------------------------------------------------------------------------- /packages/shiki/samples/tsx.sample: -------------------------------------------------------------------------------- 1 | // posts will be populated at build time by getStaticProps() 2 | function Blog({ posts }) { 3 | return ( 4 |
    5 | {posts.map((post) => ( 6 |
  • {post.title}
  • 7 | ))} 8 |
9 | ) 10 | } 11 | 12 | // This function gets called at build time on server-side. 13 | export async function getStaticProps() { 14 | const res = await fetch('https://.../posts') 15 | const posts = await res.json() 16 | 17 | return { 18 | props: { 19 | posts 20 | } 21 | } 22 | } 23 | 24 | export default Blog 25 | 26 | // From https://nextjs.org/docs/basic-features/data-fetching 27 | -------------------------------------------------------------------------------- /packages/shiki/samples/turtle.sample: -------------------------------------------------------------------------------- 1 | @prefix foaf: . 2 | @prefix rdfs: . 3 | 4 | a foaf:Person . 5 | foaf:name "Alice" . 6 | foaf:mbox . 7 | foaf:knows . 8 | foaf:knows . 9 | foaf:name "Bob" . 10 | foaf:knows . 11 | foaf:knows . 12 | foaf:name "Charlie" . 13 | foaf:knows . 14 | foaf:name "Snoopy"@en . 15 | 16 | # From https://www.w3.org/TR/sparql11-overview/#Example -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/152.test.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/shikijs/shiki/issues/152 2 | import { getHighlighter } from '../index' 3 | 4 | test('Correctly highlights LaTeX', async () => { 5 | const highlighter = await getHighlighter({ 6 | theme: 'nord', 7 | langs: ['tex', 'latex'] 8 | }) 9 | 10 | const out = highlighter.codeToThemedTokens(`%\\usepackage{pkg}`, 'latex', 'nord', { 11 | includeExplanation: true 12 | }) 13 | expect(out).toMatchSnapshot() 14 | }) 15 | -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/__snapshots__/152.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Correctly highlights LaTeX 1`] = ` 4 | Array [ 5 | Array [ 6 | Object { 7 | "color": "#616E88", 8 | "content": "%\\\\usepackage{pkg}", 9 | "explanation": Array [ 10 | Object { 11 | "content": "%", 12 | "scopes": Array [ 13 | Object { 14 | "scopeName": "text.tex.latex", 15 | "themeMatches": Array [], 16 | }, 17 | Object { 18 | "scopeName": "comment.line.percentage.tex", 19 | "themeMatches": Array [ 20 | Object { 21 | "name": "Comment", 22 | "scope": "comment", 23 | "settings": Object { 24 | "foreground": "#616E88", 25 | }, 26 | }, 27 | ], 28 | }, 29 | Object { 30 | "scopeName": "punctuation.definition.comment.tex", 31 | "themeMatches": Array [ 32 | Object { 33 | "name": "Punctuation", 34 | "scope": "punctuation", 35 | "settings": Object { 36 | "foreground": "#ECEFF4", 37 | }, 38 | }, 39 | Object { 40 | "name": "Punctuation Definition Comment", 41 | "scope": Array [ 42 | "punctuation.definition.comment", 43 | "punctuation.end.definition.comment", 44 | "punctuation.start.definition.comment", 45 | ], 46 | "settings": Object { 47 | "foreground": "#616E88", 48 | }, 49 | }, 50 | ], 51 | }, 52 | ], 53 | }, 54 | Object { 55 | "content": "\\\\usepackage{pkg}", 56 | "scopes": Array [ 57 | Object { 58 | "scopeName": "text.tex.latex", 59 | "themeMatches": Array [], 60 | }, 61 | Object { 62 | "scopeName": "comment.line.percentage.tex", 63 | "themeMatches": Array [ 64 | Object { 65 | "name": "Comment", 66 | "scope": "comment", 67 | "settings": Object { 68 | "foreground": "#616E88", 69 | }, 70 | }, 71 | ], 72 | }, 73 | ], 74 | }, 75 | ], 76 | "fontStyle": 0, 77 | }, 78 | ], 79 | ] 80 | `; 81 | -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/__snapshots__/simple.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Nord highlighter highlights simple JavaScript 1`] = `"
console.log('shiki');
"`; 4 | -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/background.test.ts: -------------------------------------------------------------------------------- 1 | import { getHighlighter } from '../index' 2 | 3 | test(`Token with no color shouldn't generate color: undefined`, async () => { 4 | const highlighter = await getHighlighter({ 5 | theme: 'monokai' 6 | }) 7 | const out = highlighter.codeToHtml(`whatever`, 'txt') 8 | expect(out).not.toContain('undefined') 9 | }) 10 | -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/comprehensive.test.ts: -------------------------------------------------------------------------------- 1 | import { themes } from '../themes' 2 | import { getHighlighter } from '../index' 3 | import { languages } from '../languages' 4 | 5 | describe('validates all themes run some JS', () => { 6 | themes.forEach(theme => { 7 | it(theme, async () => { 8 | const highlighter = await getHighlighter({ theme }) 9 | highlighter.codeToHtml(`console.log('shiki');`, 'js') 10 | }) 11 | }) 12 | }) 13 | 14 | describe('validates all languages can show a hello-world', () => { 15 | languages.forEach(language => { 16 | it(language.id, async () => { 17 | const highlighter = await getHighlighter({ theme: 'nord' }) 18 | highlighter.codeToHtml(`console.log('shiki');`, language.id) 19 | }) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/custom-language/__snapshots__/customLanguage.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Custom language registration can override builtin language: rockstar 1`] = `"
Shiki is "a beautiful Syntax Highlighter"
"`; 4 | 5 | exports[`Highlights custom language - Rockstar 1`] = `"
Shiki is "a beautiful Syntax Highlighter"
"`; 6 | 7 | exports[`Multiple custom language registrations should use last one 1`] = `"
Shiki is "a beautiful Syntax Highlighter"
"`; 8 | -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/custom-language/customLanguage.test.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs' 2 | import { getHighlighter } from '../../index' 3 | import { resolve } from 'path' 4 | 5 | function currentDirPath(p) { 6 | return resolve(__dirname, p) 7 | } 8 | 9 | test('Highlights custom language - Rockstar', async () => { 10 | const highlighter = await getHighlighter({ 11 | theme: 'nord', 12 | langs: [ 13 | { 14 | id: 'rockstar', 15 | scopeName: 'source.rockstar', 16 | path: currentDirPath('./rockstar.tmLanguage.json'), 17 | aliases: [] 18 | } 19 | ] 20 | }) 21 | 22 | const code = readFileSync(currentDirPath('rockstar.rock'), 'utf-8') 23 | const out = highlighter.codeToHtml(code, 'rockstar') 24 | expect(out).toMatchSnapshot() 25 | }) 26 | 27 | test('Multiple custom language registrations should use last one', async () => { 28 | const highlighter = await getHighlighter({ 29 | theme: 'nord', 30 | langs: [ 31 | { 32 | id: 'rockstar', 33 | scopeName: 'source.rockstar', 34 | path: currentDirPath('./rockstar.tmLanguage.json'), 35 | aliases: [] 36 | }, 37 | { 38 | id: 'rockstar', 39 | scopeName: 'source.rockstar', 40 | path: currentDirPath('./rockstar-override.tmLanguage.json'), 41 | aliases: [] 42 | } 43 | ] 44 | }) 45 | 46 | const code = readFileSync(currentDirPath('rockstar.rock'), 'utf-8') 47 | const out = highlighter.codeToHtml(code, 'rockstar') 48 | expect(out).toMatchSnapshot() 49 | }) 50 | 51 | test('Custom language registration can override builtin language', async () => { 52 | const highlighter = await getHighlighter({ 53 | theme: 'nord', 54 | langs: [ 55 | { 56 | id: 'html', 57 | scopeName: 'text.html.basic', 58 | path: currentDirPath('./rockstar-html.tmLanguage.json'), 59 | aliases: [] 60 | } 61 | ] 62 | }) 63 | 64 | const code = readFileSync(currentDirPath('rockstar.rock'), 'utf-8') 65 | const out = highlighter.codeToHtml(code, 'html') 66 | expect(out).toMatchSnapshot('rockstar') 67 | }) 68 | -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/custom-language/rockstar-html.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "_source":"https://github.com/ra100/vscode-rockstar-language", 3 | "_license": "https://github.com/ra100/vscode-rockstar-language/blob/master/LICENSE", 4 | "scopeName": "text.html.basic", 5 | "name": "Rockstar HTML", 6 | "fileTypes": [ 7 | "rock", 8 | "rockstar" 9 | ], 10 | "patterns": [{ 11 | "include": "#proper-variable" 12 | }, { 13 | "include": "#loop" 14 | }, { 15 | "include": "#conditional" 16 | }, { 17 | "include": "#method" 18 | }, { 19 | "include": "#comment" 20 | }, { 21 | "include": "#string" 22 | }, { 23 | "include": "#io" 24 | }, { 25 | "include": "#pronoun" 26 | }, { 27 | "include": "#number" 28 | }, { 29 | "include": "#boolean" 30 | }, { 31 | "include": "#common" 32 | }, { 33 | "include": "#equal" 34 | }, { 35 | "include": "#comparator" 36 | }, { 37 | "include": "#arithmetic" 38 | }, { 39 | "include": "#string-assignment" 40 | }, { 41 | "include": "#null" 42 | }], 43 | "repository": { 44 | "comment": { 45 | "patterns": [{ 46 | "begin": "\\(", 47 | "beginCaptures": { 48 | "0": { 49 | "name": "comment.block.rockstar" 50 | } 51 | }, 52 | "end": "\\)", 53 | "endCaptures": { 54 | "0": { 55 | "name": "comment.block.rockstar" 56 | } 57 | }, 58 | "name": "comment.block.rockstar" 59 | }] 60 | }, 61 | "boolean": { 62 | "patterns": [{ 63 | "match": "(\\b(is|was|were) )?\\b(true|false|right|yes|ok|wrong|no($| +)|lies)\\b", 64 | "name": "keyword.operator.rockstar", 65 | "captures": { 66 | "2": { 67 | "name": "constant.language.rockstar" 68 | }, 69 | "3": { 70 | "name": "constant.language.rockstar" 71 | } 72 | } 73 | }] 74 | }, 75 | "null": { 76 | "patterns": [{ 77 | "match": "(\\b(is|was|were) )?\\b(nothing|nowhere|nobody|null)\\b", 78 | "captures": { 79 | "2": { 80 | "name": "keyword.operator.rockstar" 81 | }, 82 | "3": { 83 | "name": "constant.language.rockstar" 84 | } 85 | } 86 | }] 87 | }, 88 | "pronoun": { 89 | "patterns": [{ 90 | "match": "\\b(it|he|she|him|her|they|them|ze|hir|zie|zir|xe|xem|ve|ver)\\b", 91 | "name": "storage.type.pronoun.rockstar" 92 | }] 93 | }, 94 | "number": { 95 | "patterns": [{ 96 | "match": "\\b(is|was|were) (?!and|as|nothing|nowhere|nobody|null|true|false|right|yes|ok|wrong|no|lies)(([a-z]+($|\\s))+)", 97 | "captures": { 98 | "1": { 99 | "name": "keyword.operator.rockstar" 100 | }, 101 | "2": { 102 | "name": "constant.numeric.rockstar" 103 | } 104 | } 105 | }] 106 | }, 107 | "string": { 108 | "patterns": [{ 109 | "begin": "\"", 110 | "beginCaptures": { 111 | "0": { 112 | "name": "constant.numeric.rockstar" 113 | } 114 | }, 115 | "end": "\"", 116 | "endCaptures": { 117 | "0": { 118 | "name": "constant.numeric.rockstar" 119 | } 120 | }, 121 | "name": "constant.numeric.rockstar" 122 | }, 123 | { 124 | "match": "'\\w*'", 125 | "name": "constant.numeric.rockstar" 126 | }, 127 | { 128 | "match": ",", 129 | "scope": "constant.numeric.rockstar" 130 | } 131 | ] 132 | }, 133 | "equal": { 134 | "patterns": [{ 135 | "match": "\\b('s|is( not($| +))?|ain't|was|were)\\b", 136 | "name": "keyword.operator.rockstar" 137 | }] 138 | }, 139 | "comparator": { 140 | "patterns": [{ 141 | "match": "(higher|greater|bigger|stronger|lower|less|smaller|weaker) than|as (high|great|big|strong|low|little|small|weak) as", 142 | "name": "keyword.operator.rockstar" 143 | }] 144 | }, 145 | "loop": { 146 | "patterns": [{ 147 | "match": "(^| )(While|Until|Continue|Break it down|break|Take it to the top)($| )", 148 | "name": "keyword.control.rockstar" 149 | }] 150 | }, 151 | "conditional": { 152 | "patterns": [{ 153 | "match": "(^| )(If|if|Else|else)", 154 | "name": "keyword.control.conditional.rockstar" 155 | }] 156 | }, 157 | "method": { 158 | "patterns": [{ 159 | "match": "\\b(taking|takes|and|Give back)\\b", 160 | "name": "keyword.other.rockstar" 161 | }] 162 | }, 163 | "io": { 164 | "patterns": [{ 165 | "match": "(^| )(Say|Shout|Whisper|Scream|Listen( to)?)", 166 | "name": "support.function.builtin.rockstar" 167 | }] 168 | }, 169 | "assignment": { 170 | "patterns": [{ 171 | "match": "((^Put\\b)|\\b(into)\\b)", 172 | "name": "keyword.operator.rockstar" 173 | }] 174 | }, 175 | "arithmetic": { 176 | "patterns": [{ 177 | "match": "(Knock | down|Build | up|plus|without|minus|with|times|of|over|by)", 178 | "name": "keyword.operator.arithmetic.rockstar" 179 | }] 180 | }, 181 | "common": { 182 | "patterns": [{ 183 | "match": "(? { 4 | const highlighter = await getHighlighter({ 5 | theme: 'nord' 6 | }) 7 | const out = highlighter.codeToHtml(`console.log('shiki');`, 'js') 8 | expect(out).toMatchSnapshot() 9 | }) 10 | -------------------------------------------------------------------------------- /packages/shiki/src/__tests__/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { trimEndSlash, join, dirname } from '../utils' 2 | 3 | test('trimEndSlash', async () => { 4 | expect(trimEndSlash('/abc')).toBe('/abc') 5 | expect(trimEndSlash('/abc/')).toBe('/abc') 6 | expect(trimEndSlash('/abc//')).toBe('/abc/') 7 | 8 | expect(trimEndSlash('\\abc\\')).toBe('\\abc') 9 | expect(trimEndSlash('\\abc\\\\')).toBe('\\abc\\') 10 | }) 11 | 12 | test('join', async () => { 13 | expect(join('abc', 'a', 'b')).toBe('abc/a/b') 14 | expect(join()).toBe('') 15 | expect(join('a/', 'b/')).toBe('a/b') 16 | expect(join('a', './b')).toBe('a/b') 17 | }) 18 | 19 | test('dirname', async () => { 20 | expect(dirname('a/b/c')).toBe('b') 21 | expect(dirname('a/b/c/')).toBe('c') 22 | expect(dirname('a')).toBe(undefined) 23 | expect(dirname('')).toBe(undefined) 24 | }) 25 | -------------------------------------------------------------------------------- /packages/shiki/src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare var __BROWSER__: boolean 2 | -------------------------------------------------------------------------------- /packages/shiki/src/highlighter.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Highlighter, 3 | HighlighterOptions, 4 | ILanguageRegistration, 5 | IShikiTheme, 6 | IThemeRegistration, 7 | StringLiteralUnion 8 | } from './types' 9 | import { Resolver } from './resolver' 10 | import { tokenizeWithTheme } from './themedTokenizer' 11 | import { renderToHtml } from './renderer' 12 | 13 | import { getOnigasm } from './loader' 14 | import { Lang, languages as BUNDLED_LANGUAGES } from './languages' 15 | import { Registry } from './registry' 16 | import { Theme } from './themes' 17 | 18 | function resolveLang(lang: ILanguageRegistration | Lang) { 19 | return typeof lang === 'string' 20 | ? BUNDLED_LANGUAGES.find(l => l.id === lang || l.aliases?.includes(lang)) 21 | : lang 22 | } 23 | 24 | function resolveOptions(options: HighlighterOptions) { 25 | let _languages: ILanguageRegistration[] = BUNDLED_LANGUAGES 26 | let _themes: IThemeRegistration[] = options.themes || [] 27 | 28 | if (options.langs?.length) { 29 | _languages = options.langs.map(resolveLang) 30 | } 31 | if (options.theme) { 32 | _themes.unshift(options.theme) 33 | } 34 | if (!_themes.length) { 35 | _themes = ['nord'] 36 | } 37 | 38 | return { _languages, _themes } 39 | } 40 | 41 | export async function getHighlighter(options: HighlighterOptions): Promise { 42 | const { _languages, _themes } = resolveOptions(options) 43 | const _resolver = new Resolver(getOnigasm(), 'onigasm') 44 | const _registry = new Registry(_resolver) 45 | 46 | if (options.paths?.themes) { 47 | _registry.themesPath = options.paths.themes 48 | } 49 | 50 | if (options.paths?.languages) { 51 | _resolver.languagesPath = options.paths.languages 52 | } 53 | 54 | const themes = await _registry.loadThemes(_themes) 55 | const _defaultTheme = themes[0] 56 | let _currentTheme: IShikiTheme | undefined 57 | await _registry.loadLanguages(_languages) 58 | 59 | function getTheme(theme?: IThemeRegistration) { 60 | const _theme = theme ? _registry.getTheme(theme) : _defaultTheme 61 | if (!_theme) { 62 | throw Error(`No theme registration for ${theme}`) 63 | } 64 | if (!_currentTheme || _currentTheme.name !== _theme.name) { 65 | _registry.setTheme(_theme) 66 | _currentTheme = _theme 67 | } 68 | const _colorMap = _registry.getColorMap() 69 | return { _theme, _colorMap } 70 | } 71 | 72 | function getGrammer(lang: string) { 73 | const _grammer = _registry.getGrammer(lang) 74 | if (!_grammer) { 75 | throw Error(`No language registration for ${lang}`) 76 | } 77 | return { _grammer } 78 | } 79 | 80 | function codeToThemedTokens( 81 | code: string, 82 | lang = 'text', 83 | theme?: StringLiteralUnion, 84 | options = { includeExplanation: true } 85 | ) { 86 | if (isPlaintext(lang)) { 87 | return [[{ content: code }]] 88 | } 89 | const { _grammer } = getGrammer(lang) 90 | const { _theme, _colorMap } = getTheme(theme) 91 | return tokenizeWithTheme(_theme, _colorMap, code, _grammer, options) 92 | } 93 | 94 | function codeToHtml(code: string, lang = 'text', theme?: StringLiteralUnion) { 95 | const tokens = codeToThemedTokens(code, lang, theme, { 96 | includeExplanation: false 97 | }) 98 | const { _theme } = getTheme(theme) 99 | return renderToHtml(tokens, { 100 | fg: _theme.fg, 101 | bg: _theme.bg 102 | }) 103 | } 104 | 105 | async function loadTheme(theme: IShikiTheme | Theme) { 106 | await _registry.loadTheme(theme) 107 | } 108 | 109 | async function loadLanguage(lang: ILanguageRegistration | Lang) { 110 | const _lang = resolveLang(lang) 111 | _resolver.addLanguage(_lang) 112 | await _registry.loadLanguage(_lang) 113 | } 114 | 115 | function getLoadedThemes() { 116 | return _registry.getLoadedThemes() 117 | } 118 | 119 | function getLoadedLanguages() { 120 | return _registry.getLoadedLanguages() 121 | } 122 | 123 | function getBackgroundColor(theme?: StringLiteralUnion) { 124 | const { _theme } = getTheme(theme) 125 | return _theme.bg 126 | } 127 | 128 | function getForegroundColor(theme?: StringLiteralUnion) { 129 | const { _theme } = getTheme(theme) 130 | return _theme.fg 131 | } 132 | 133 | return { 134 | codeToThemedTokens, 135 | codeToHtml, 136 | getTheme: (theme: IThemeRegistration) => { 137 | return getTheme(theme)._theme 138 | }, 139 | loadTheme, 140 | loadLanguage, 141 | getBackgroundColor, 142 | getForegroundColor, 143 | getLoadedThemes, 144 | getLoadedLanguages 145 | } 146 | } 147 | 148 | function isPlaintext(lang: string | null | undefined) { 149 | return !lang || ['plaintext', 'txt', 'text'].includes(lang) 150 | } 151 | -------------------------------------------------------------------------------- /packages/shiki/src/index.ts: -------------------------------------------------------------------------------- 1 | export { themes as BUNDLED_THEMES, Theme } from './themes' 2 | export { languages as BUNDLED_LANGUAGES, Lang } from './languages' 3 | 4 | export { FontStyle } from './stackElementMetadata' 5 | 6 | export { getHighlighter } from './highlighter' 7 | export { renderToHtml, HtmlRendererOptions } from './renderer' 8 | export { IThemedToken } from './themedTokenizer' 9 | export { setCDN, setOnigasmWASM, fetchTheme as loadTheme } from './loader' 10 | export { 11 | ILanguageRegistration, 12 | IShikiTheme, 13 | IThemeRegistration, 14 | Highlighter, 15 | HighlighterOptions 16 | } from './types' 17 | -------------------------------------------------------------------------------- /packages/shiki/src/registry.ts: -------------------------------------------------------------------------------- 1 | import { IGrammar, Registry as TextMateRegistry } from 'vscode-textmate' 2 | import { IShikiTheme, IThemeRegistration, ILanguageRegistration } from './types' 3 | import { fetchTheme, toShikiTheme } from './loader' 4 | import { Theme } from './themes' 5 | import { Resolver } from './resolver' 6 | import { Lang } from './languages' 7 | 8 | export class Registry extends TextMateRegistry { 9 | public themesPath: string = 'themes/' 10 | 11 | private _resolvedThemes: Record = {} 12 | private _resolvedGrammars: Record = {} 13 | 14 | constructor(private _resolver: Resolver) { 15 | super(_resolver) 16 | } 17 | 18 | public getTheme(theme: Theme | IShikiTheme | string) { 19 | if (typeof theme === 'string') { 20 | return this._resolvedThemes[theme] 21 | } else { 22 | return theme 23 | } 24 | } 25 | 26 | public async loadTheme(theme: Theme | IShikiTheme | string) { 27 | if (typeof theme === 'string') { 28 | if (!this._resolvedThemes[theme]) { 29 | this._resolvedThemes[theme] = await fetchTheme(`${this.themesPath}${theme}.json`) 30 | } 31 | return this._resolvedThemes[theme] 32 | } else { 33 | theme = toShikiTheme(theme) 34 | if (theme.name) { 35 | this._resolvedThemes[theme.name] = theme 36 | } 37 | return theme 38 | } 39 | } 40 | 41 | public async loadThemes(themes: IThemeRegistration[]) { 42 | return await Promise.all(themes.map(theme => this.loadTheme(theme))) 43 | } 44 | 45 | public getLoadedThemes() { 46 | return Object.keys(this._resolvedThemes) as Theme[] 47 | } 48 | 49 | public getGrammer(name: string) { 50 | return this._resolvedGrammars[name] 51 | } 52 | 53 | public async loadLanguage(lang: ILanguageRegistration) { 54 | const g = await this.loadGrammar(lang.scopeName) 55 | this._resolvedGrammars[lang.id] = g 56 | if (lang.aliases) { 57 | lang.aliases.forEach(la => { 58 | this._resolvedGrammars[la] = g 59 | }) 60 | } 61 | } 62 | 63 | public async loadLanguages(langs: ILanguageRegistration[]) { 64 | for (const lang of langs) { 65 | this._resolver.addLanguage(lang) 66 | } 67 | for (const lang of langs) { 68 | await this.loadLanguage(lang) 69 | } 70 | } 71 | 72 | public getLoadedLanguages() { 73 | return Object.keys(this._resolvedGrammars) as Lang[] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /packages/shiki/src/renderer.ts: -------------------------------------------------------------------------------- 1 | import { FontStyle } from './stackElementMetadata' 2 | import { IThemedToken } from './themedTokenizer' 3 | 4 | export interface HtmlRendererOptions { 5 | langId?: string 6 | fg?: string 7 | bg?: string 8 | } 9 | 10 | const FONT_STYLE_TO_CSS = { 11 | [FontStyle.Italic]: 'font-style: italic', 12 | [FontStyle.Bold]: 'font-weight: bold', 13 | [FontStyle.Underline]: 'text-decoration: underline' 14 | } 15 | 16 | export function renderToHtml(lines: IThemedToken[][], options: HtmlRendererOptions = {}) { 17 | const bg = options.bg || '#fff' 18 | 19 | let html = '' 20 | 21 | html += `
`
22 |   if (options.langId) {
23 |     html += `
${options.langId}
` 24 | } 25 | html += `` 26 | 27 | lines.forEach((l: IThemedToken[]) => { 28 | html += `` 29 | 30 | l.forEach(token => { 31 | const cssDeclarations = [`color: ${token.color || options.fg}`] 32 | if (token.fontStyle > FontStyle.None) { 33 | cssDeclarations.push(FONT_STYLE_TO_CSS[token.fontStyle]) 34 | } 35 | html += `${escapeHtml(token.content)}` 36 | }) 37 | html += `\n` 38 | }) 39 | html = html.replace(/\n*$/, '') // Get rid of final new lines 40 | html += `
` 41 | 42 | return html 43 | } 44 | 45 | const htmlEscapes = { 46 | '&': '&', 47 | '<': '<', 48 | '>': '>', 49 | '"': '"', 50 | "'": ''' 51 | } 52 | 53 | function escapeHtml(html: string) { 54 | return html.replace(/[&<>"']/g, chr => htmlEscapes[chr]) 55 | } 56 | -------------------------------------------------------------------------------- /packages/shiki/src/resolver.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 'use strict' 5 | 6 | import { IRawGrammar, IOnigLib, RegistryOptions } from 'vscode-textmate' 7 | import { languages } from './languages' 8 | 9 | import { fetchGrammar } from './loader' 10 | import { ILanguageRegistration } from './types' 11 | 12 | export class Resolver implements RegistryOptions { 13 | public languagesPath: string = 'languages/' 14 | 15 | private readonly languageMap: { [langIdOrAlias: string]: ILanguageRegistration } = {} 16 | private readonly scopeToLangMap: { [scope: string]: ILanguageRegistration } = {} 17 | 18 | private readonly _onigLibPromise: Promise 19 | private readonly _onigLibName: string 20 | 21 | constructor(onigLibPromise: Promise, onigLibName: string) { 22 | this._onigLibPromise = onigLibPromise 23 | this._onigLibName = onigLibName 24 | } 25 | 26 | public get onigLib(): Promise { 27 | return this._onigLibPromise 28 | } 29 | 30 | public getOnigLibName(): string { 31 | return this._onigLibName 32 | } 33 | 34 | public getLangRegistration(langIdOrAlias: string): ILanguageRegistration { 35 | return this.languageMap[langIdOrAlias] 36 | } 37 | 38 | public async loadGrammar(scopeName: string): Promise { 39 | const lang = this.scopeToLangMap[scopeName] 40 | 41 | if (!lang) { 42 | return null 43 | } 44 | 45 | if (lang.grammar) { 46 | return lang.grammar 47 | } 48 | 49 | const g = await fetchGrammar( 50 | languages.includes(lang) ? `${this.languagesPath}${lang.path}` : lang.path 51 | ) 52 | lang.grammar = g 53 | return g 54 | } 55 | 56 | public addLanguage(l: ILanguageRegistration) { 57 | this.languageMap[l.id] = l 58 | if (l.aliases) { 59 | l.aliases.forEach(a => { 60 | this.languageMap[a] = l 61 | }) 62 | } 63 | this.scopeToLangMap[l.scopeName] = l 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/shiki/src/stackElementMetadata.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Helpers to manage the "collapsed" metadata of an entire StackElement stack. 3 | * The following assumptions have been made: 4 | * - languageId < 256 => needs 8 bits 5 | * - unique color count < 512 => needs 9 bits 6 | * 7 | * The binary format is: 8 | * - ------------------------------------------- 9 | * 3322 2222 2222 1111 1111 1100 0000 0000 10 | * 1098 7654 3210 9876 5432 1098 7654 3210 11 | * - ------------------------------------------- 12 | * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 13 | * bbbb bbbb bfff ffff ffFF FTTT LLLL LLLL 14 | * - ------------------------------------------- 15 | * - L = LanguageId (8 bits) 16 | * - T = StandardTokenType (3 bits) 17 | * - F = FontStyle (3 bits) 18 | * - f = foreground color (9 bits) 19 | * - b = background color (9 bits) 20 | */ 21 | export const enum MetadataConsts { 22 | LANGUAGEID_MASK = 0b00000000000000000000000011111111, 23 | TOKEN_TYPE_MASK = 0b00000000000000000000011100000000, 24 | FONT_STYLE_MASK = 0b00000000000000000011100000000000, 25 | FOREGROUND_MASK = 0b00000000011111111100000000000000, 26 | BACKGROUND_MASK = 0b11111111100000000000000000000000, 27 | 28 | LANGUAGEID_OFFSET = 0, 29 | TOKEN_TYPE_OFFSET = 8, 30 | FONT_STYLE_OFFSET = 11, 31 | FOREGROUND_OFFSET = 14, 32 | BACKGROUND_OFFSET = 23 33 | } 34 | 35 | export const enum TemporaryStandardTokenType { 36 | Other = 0, 37 | Comment = 1, 38 | String = 2, 39 | RegEx = 4, 40 | MetaEmbedded = 8 41 | } 42 | 43 | export const enum FontStyle { 44 | NotSet = -1, 45 | None = 0, 46 | Italic = 1, 47 | Bold = 2, 48 | Underline = 4 49 | } 50 | 51 | export const enum StandardTokenType { 52 | Other = 0, 53 | Comment = 1, 54 | String = 2, 55 | RegEx = 4 56 | } 57 | 58 | export class StackElementMetadata { 59 | public static toBinaryStr(metadata: number): string { 60 | let r = metadata.toString(2) 61 | while (r.length < 32) { 62 | r = '0' + r 63 | } 64 | return r 65 | } 66 | 67 | public static printMetadata(metadata: number): void { 68 | let languageId = StackElementMetadata.getLanguageId(metadata) 69 | let tokenType = StackElementMetadata.getTokenType(metadata) 70 | let fontStyle = StackElementMetadata.getFontStyle(metadata) 71 | let foreground = StackElementMetadata.getForeground(metadata) 72 | let background = StackElementMetadata.getBackground(metadata) 73 | 74 | console.log({ 75 | languageId: languageId, 76 | tokenType: tokenType, 77 | fontStyle: fontStyle, 78 | foreground: foreground, 79 | background: background 80 | }) 81 | } 82 | 83 | public static getLanguageId(metadata: number): number { 84 | return (metadata & MetadataConsts.LANGUAGEID_MASK) >>> MetadataConsts.LANGUAGEID_OFFSET 85 | } 86 | 87 | public static getTokenType(metadata: number): number { 88 | return (metadata & MetadataConsts.TOKEN_TYPE_MASK) >>> MetadataConsts.TOKEN_TYPE_OFFSET 89 | } 90 | 91 | public static getFontStyle(metadata: number): number { 92 | return (metadata & MetadataConsts.FONT_STYLE_MASK) >>> MetadataConsts.FONT_STYLE_OFFSET 93 | } 94 | 95 | public static getForeground(metadata: number): number { 96 | return (metadata & MetadataConsts.FOREGROUND_MASK) >>> MetadataConsts.FOREGROUND_OFFSET 97 | } 98 | 99 | public static getBackground(metadata: number): number { 100 | return (metadata & MetadataConsts.BACKGROUND_MASK) >>> MetadataConsts.BACKGROUND_OFFSET 101 | } 102 | 103 | public static set( 104 | metadata: number, 105 | languageId: number, 106 | tokenType: TemporaryStandardTokenType, 107 | fontStyle: FontStyle, 108 | foreground: number, 109 | background: number 110 | ): number { 111 | let _languageId = StackElementMetadata.getLanguageId(metadata) 112 | let _tokenType = StackElementMetadata.getTokenType(metadata) 113 | let _fontStyle = StackElementMetadata.getFontStyle(metadata) 114 | let _foreground = StackElementMetadata.getForeground(metadata) 115 | let _background = StackElementMetadata.getBackground(metadata) 116 | 117 | if (languageId !== 0) { 118 | _languageId = languageId 119 | } 120 | if (tokenType !== TemporaryStandardTokenType.Other) { 121 | _tokenType = 122 | tokenType === TemporaryStandardTokenType.MetaEmbedded ? StandardTokenType.Other : tokenType 123 | } 124 | if (fontStyle !== FontStyle.NotSet) { 125 | _fontStyle = fontStyle 126 | } 127 | if (foreground !== 0) { 128 | _foreground = foreground 129 | } 130 | if (background !== 0) { 131 | _background = background 132 | } 133 | 134 | return ( 135 | ((_languageId << MetadataConsts.LANGUAGEID_OFFSET) | 136 | (_tokenType << MetadataConsts.TOKEN_TYPE_OFFSET) | 137 | (_fontStyle << MetadataConsts.FONT_STYLE_OFFSET) | 138 | (_foreground << MetadataConsts.FOREGROUND_OFFSET) | 139 | (_background << MetadataConsts.BACKGROUND_OFFSET)) >>> 140 | 0 141 | ) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /packages/shiki/src/themes.ts: -------------------------------------------------------------------------------- 1 | export type Theme = 2 | | 'dark-plus' 3 | | 'dracula-soft' 4 | | 'dracula' 5 | | 'github-dark' 6 | | 'github-light' 7 | | 'light-plus' 8 | | 'material-darker' 9 | | 'material-default' 10 | | 'material-lighter' 11 | | 'material-ocean' 12 | | 'material-palenight' 13 | | 'min-dark' 14 | | 'min-light' 15 | | 'monokai' 16 | | 'nord' 17 | | 'poimandres' 18 | | 'slack-dark' 19 | | 'slack-ochin' 20 | | 'solarized-dark' 21 | | 'solarized-light' 22 | | 'vitesse-dark' 23 | | 'vitesse-light' 24 | 25 | export const themes: Theme[] = [ 26 | 'dark-plus', 27 | 'dracula-soft', 28 | 'dracula', 29 | 'github-dark', 30 | 'github-light', 31 | 'light-plus', 32 | 'material-darker', 33 | 'material-default', 34 | 'material-lighter', 35 | 'material-ocean', 36 | 'material-palenight', 37 | 'min-dark', 38 | 'min-light', 39 | 'monokai', 40 | 'nord', 41 | 'poimandres', 42 | 'slack-dark', 43 | 'slack-ochin', 44 | 'solarized-dark', 45 | 'solarized-light', 46 | 'vitesse-dark', 47 | 'vitesse-light' 48 | ] 49 | -------------------------------------------------------------------------------- /packages/shiki/src/types.ts: -------------------------------------------------------------------------------- 1 | import { IRawGrammar, IRawTheme, IRawThemeSetting } from 'vscode-textmate' 2 | import { Lang } from './languages' 3 | import { IThemedToken } from './themedTokenizer' 4 | import { Theme } from './themes' 5 | 6 | export interface HighlighterOptions { 7 | /** 8 | * The theme to load upfront. 9 | */ 10 | theme?: IThemeRegistration 11 | 12 | /** 13 | * A list of themes to load upfront. 14 | * 15 | * Default to: `['dark-plus', 'light-plus']` 16 | */ 17 | themes?: IThemeRegistration[] 18 | 19 | /** 20 | * A list of languages to load upfront. 21 | * 22 | * Default to `['html', 'css', 'javascript']` 23 | */ 24 | langs?: (Lang | ILanguageRegistration)[] 25 | 26 | /** 27 | * Paths for loading themes and langs. Relative to the package's root. 28 | */ 29 | paths?: IHighlighterPaths 30 | } 31 | 32 | export interface Highlighter { 33 | /** 34 | * Convert code to HTML tokens. 35 | * `lang` and `theme` must have been loaded. 36 | */ 37 | codeToHtml( 38 | code: string, 39 | lang?: StringLiteralUnion, 40 | theme?: StringLiteralUnion 41 | ): string 42 | 43 | /** 44 | * Convert code to themed tokens for custom processing. 45 | * `lang` and `theme` must have been loaded. 46 | * You may customize the bundled HTML / SVG renderer or write your own 47 | * renderer for another render target. 48 | */ 49 | codeToThemedTokens( 50 | code: string, 51 | lang?: StringLiteralUnion, 52 | theme?: StringLiteralUnion, 53 | options?: ThemedTokenizerOptions 54 | ): IThemedToken[][] 55 | 56 | /** 57 | * Get the loaded theme 58 | */ 59 | getTheme(theme?: IThemeRegistration): IShikiTheme 60 | 61 | /** 62 | * Load a theme 63 | */ 64 | loadTheme(theme: IThemeRegistration): Promise 65 | 66 | /** 67 | * Load a language 68 | */ 69 | loadLanguage(lang: ILanguageRegistration | Lang): Promise 70 | 71 | /** 72 | * Get all loaded themes 73 | */ 74 | getLoadedThemes(): Theme[] 75 | 76 | /** 77 | * Get all loaded languages 78 | */ 79 | getLoadedLanguages(): Lang[] 80 | 81 | /** 82 | * Get the foreground color for theme. Can be used for CSS `color`. 83 | */ 84 | getForegroundColor(theme?: StringLiteralUnion): string 85 | 86 | /** 87 | * Get the background color for theme. Can be used for CSS `background-color`. 88 | */ 89 | getBackgroundColor(theme?: StringLiteralUnion): string 90 | 91 | // codeToRawHtml?(code: string): string 92 | // getRawCSS?(): string 93 | 94 | // codeToImage?(): string 95 | } 96 | 97 | export interface IHighlighterPaths { 98 | /** 99 | * @default 'themes/' 100 | */ 101 | themes?: string 102 | 103 | /** 104 | * @default 'languages/' 105 | */ 106 | languages?: string 107 | } 108 | 109 | export type ILanguageRegistration = { 110 | id: string 111 | scopeName: string 112 | aliases?: string[] 113 | samplePath?: string 114 | /** 115 | * A list of languages the current language embeds. 116 | * If manually specifying languages to load, make sure to load the embedded 117 | * languages for each parent language. 118 | */ 119 | embeddedLangs?: Lang[] 120 | } & ( 121 | | { 122 | path: string 123 | grammar?: IRawGrammar 124 | } 125 | | { 126 | path?: string 127 | grammar: IRawGrammar 128 | } 129 | ) 130 | 131 | export type IThemeRegistration = IShikiTheme | StringLiteralUnion 132 | 133 | export interface IShikiTheme extends IRawTheme { 134 | /** 135 | * @description theme name 136 | */ 137 | name: string 138 | 139 | /** 140 | * @description light/dark theme 141 | */ 142 | type: 'light' | 'dark' 143 | 144 | /** 145 | * @description tokenColors of the theme file 146 | */ 147 | settings: IRawThemeSetting[] 148 | 149 | /** 150 | * @description text default foreground color 151 | */ 152 | fg: string 153 | 154 | /** 155 | * @description text default background color 156 | */ 157 | bg: string 158 | 159 | /** 160 | * @description relative path of included theme 161 | */ 162 | include?: string 163 | 164 | /** 165 | * 166 | * @description color map of the theme file 167 | */ 168 | colors?: Record 169 | } 170 | 171 | /** 172 | * type StringLiteralUnion<'foo'> = 'foo' | string 173 | * This has auto completion whereas `'foo' | string` doesn't 174 | * Adapted from https://github.com/microsoft/TypeScript/issues/29729 175 | */ 176 | export type StringLiteralUnion = T | (U & {}) 177 | 178 | export interface ThemedTokenizerOptions { 179 | /** 180 | * Whether to include explanation of each token's matching scopes and 181 | * why it's given its color. Default to false to reduce output verbosity. 182 | */ 183 | includeExplanation?: boolean 184 | } 185 | -------------------------------------------------------------------------------- /packages/shiki/src/utils.ts: -------------------------------------------------------------------------------- 1 | export function trimEndSlash(str: string) { 2 | if (str.endsWith('/') || str.endsWith('\\')) return str.slice(0, -1) 3 | return str 4 | } 5 | 6 | export function trimStartDot(str: string) { 7 | if (str.startsWith('./')) return str.slice(2) 8 | return str 9 | } 10 | 11 | export function dirname(str: string) { 12 | const parts = str.split(/[\/\\]/g) 13 | return parts[parts.length - 2] 14 | } 15 | 16 | export function join(...parts: string[]) { 17 | return parts.map(trimEndSlash).map(trimStartDot).join('/') 18 | } 19 | -------------------------------------------------------------------------------- /packages/shiki/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "target": "es2017", 5 | "esModuleInterop": true, 6 | "moduleResolution": "node", 7 | "lib": ["esnext", "DOM", "WebWorker"], 8 | "sourceMap": true 9 | }, 10 | "exclude": ["samples"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/site/assets/figma-editing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyx990803/shiki/d39789ccd42b7d3dffb2b1d1bb53aa751757a806/packages/site/assets/figma-editing.png -------------------------------------------------------------------------------- /packages/site/assets/leandro-fatih.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyx990803/shiki/d39789ccd42b7d3dffb2b1d1bb53aa751757a806/packages/site/assets/leandro-fatih.png -------------------------------------------------------------------------------- /packages/site/assets/svg-figma-af.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyx990803/shiki/d39789ccd42b7d3dffb2b1d1bb53aa751757a806/packages/site/assets/svg-figma-af.jpg -------------------------------------------------------------------------------- /packages/site/assets/vscode-ts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyx990803/shiki/d39789ccd42b7d3dffb2b1d1bb53aa751757a806/packages/site/assets/vscode-ts.png -------------------------------------------------------------------------------- /packages/site/beer.wy: -------------------------------------------------------------------------------- 1 | 吾有一言。曰「「春日宴。」」。書之。 2 | 有數九。名之曰「酒數」。 3 | 4 | 恆為是。若「酒數」等於零者乃止也。 5 | 6 | 吾有三言。曰「「與君」」。曰「酒數」。 7 | 曰「「杯酒。可以窮歡宴。綠酒一杯歌一遍。」」。書之。 8 | 9 | 減「酒數」以一。昔之「酒數」者。今其是矣云云。 10 | 11 | 吾有一言。曰「「綠酒千杯腸已爛。」」。書之。 -------------------------------------------------------------------------------- /packages/site/chinese-svg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 吾有「「春日宴。」」書之 4 | 5 | 6 | 有數名之曰「酒數」 7 | 8 | 9 | 10 | 恆為是「酒數」等於者乃止也 11 | 12 | 13 | 14 | 吾有「「與君」」「酒數」 15 | 16 | 17 | 「「杯酒。可以窮歡宴。綠酒一杯歌一遍。」」書之 18 | 19 | 20 | 21 | 「酒數」昔之「酒數」今其是矣云云 22 | 23 | 24 | 25 | 吾有「「綠酒千杯腸已爛。」」書之 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/site/gen-custom-theme.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const markdown = require('markdown-it') 3 | const shiki = require('shiki') 4 | const path = require('path') 5 | 6 | shiki 7 | .getHighlighter({ 8 | theme: 'nord', 9 | langs: [ 10 | { 11 | id: 'rockstar', 12 | scopeName: 'source.rockstar', 13 | path: path.resolve('./rockstar.tmLanguage.json'), 14 | aliases: [] 15 | } 16 | ] 17 | }) 18 | .then(highlighter => { 19 | const md = markdown({ 20 | highlight: (code, lang) => { 21 | return highlighter.codeToHtml(code, lang) 22 | } 23 | }) 24 | 25 | const result = md.render(fs.readFileSync('rockstar.md', 'utf-8')) 26 | fs.writeFileSync('rockstar.html', result) 27 | 28 | console.log('done: rockstar.html') 29 | }) 30 | -------------------------------------------------------------------------------- /packages/site/gen-index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const markdown = require('markdown-it') 3 | const shiki = require('shiki') 4 | 5 | shiki 6 | .getHighlighter({ 7 | theme: 'nord' 8 | }) 9 | .then(highlighter => { 10 | const md = markdown({ 11 | html: true, 12 | highlight: (code, lang) => { 13 | return highlighter.codeToHtml(code, lang) 14 | } 15 | }) 16 | 17 | const html = md.render(fs.readFileSync('index.md', 'utf-8')) 18 | const out = ` 19 | Shiki 20 | 21 | ${html} 22 | 23 | ` 24 | fs.writeFileSync('index.html', out) 25 | 26 | console.log('done: index.html') 27 | }) 28 | -------------------------------------------------------------------------------- /packages/site/gen-mono.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const markdown = require('markdown-it') 3 | const shiki = require('shiki') 4 | 5 | shiki 6 | .getHighlighter({ 7 | theme: JSON.parse(fs.readFileSync('./monochrome-dark-subtle.json', 'utf-8')) 8 | }) 9 | .then(highlighter => { 10 | const md = markdown({ 11 | highlight: (code, lang) => { 12 | return highlighter.codeToHtml(code, lang) 13 | } 14 | }) 15 | 16 | const result = md.render(fs.readFileSync('mono.md', 'utf-8')) 17 | fs.writeFileSync('mono.html', result) 18 | 19 | console.log('done: mono.html') 20 | }) 21 | -------------------------------------------------------------------------------- /packages/site/gen-palenight.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const markdown = require('markdown-it') 3 | const shiki = require('shiki') 4 | 5 | shiki 6 | .getHighlighter({ 7 | theme: 'material-palenight' 8 | }) 9 | .then(highlighter => { 10 | const md = markdown({ 11 | highlight: (code, lang) => { 12 | return highlighter.codeToHtml(code, lang) 13 | } 14 | }) 15 | 16 | const result = md.render(fs.readFileSync('palenight.md', 'utf-8')) 17 | fs.writeFileSync('palenight.html', result) 18 | 19 | console.log('done: palenight.html') 20 | }) 21 | -------------------------------------------------------------------------------- /packages/site/gen-svg-sample.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const shiki = require('shiki') 3 | const { getSVGRenderer } = require('shiki-renderer-svg') 4 | 5 | ;(async () => { 6 | const highlighter = await shiki.getHighlighter({ 7 | theme: 'nord' 8 | }) 9 | 10 | const svgRenderer = await getSVGRenderer({ 11 | bg: '#2E3440', 12 | fontFamily: { 13 | name: 'Inconsolata', 14 | cssURL: 'https://fonts.googleapis.com/css2?family=Inconsolata&display=swap' 15 | }, 16 | fontSize: 14 17 | }) 18 | 19 | const code = fs.readFileSync('gen-svg.js', 'utf-8') 20 | 21 | const tokens = highlighter.codeToThemedTokens(code, 'js') 22 | const out = svgRenderer.renderToSVG(tokens) 23 | 24 | fs.writeFileSync('svg.svg', out) 25 | 26 | console.log('done: svg.svg') 27 | })() 28 | -------------------------------------------------------------------------------- /packages/site/gen-svg.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const shiki = require('shiki') 3 | const { getSVGRenderer } = require('shiki-renderer-svg') 4 | 5 | ;(async () => { 6 | const highlighter = await shiki.getHighlighter({ 7 | theme: 'nord' 8 | }) 9 | 10 | const svgRenderer = await getSVGRenderer({ 11 | bg: '#2E3440', 12 | fontFamily: { 13 | name: 'IBM Plex Mono', 14 | cssURL: 15 | 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap' 16 | }, 17 | fontSize: 14 18 | }) 19 | 20 | const code = fs.readFileSync('gen-svg-sample.js', 'utf-8') 21 | 22 | const tokens = highlighter.codeToThemedTokens(code, 'js') 23 | const out = svgRenderer.renderToSVG(tokens) 24 | 25 | fs.writeFileSync('svg.svg', out) 26 | 27 | console.log('done: svg.svg') 28 | })() 29 | -------------------------------------------------------------------------------- /packages/site/gen-wenyan.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const shiki = require('shiki') 3 | 4 | ;(async () => { 5 | const highlighter = await shiki.getHighlighter({ 6 | theme: 'nord' 7 | }) 8 | 9 | const code = fs.readFileSync('beer.wy', 'utf-8') 10 | 11 | const html = highlighter.codeToHtml(code, '文言') 12 | 13 | fs.writeFileSync('文言.html', html) 14 | 15 | console.log('done: 文言') 16 | })() 17 | -------------------------------------------------------------------------------- /packages/site/index.js: -------------------------------------------------------------------------------- 1 | async function go() { 2 | const urlAndIds = [ 3 | ['/palenight', 'palenight'], 4 | ['/mono', 'mono'], 5 | ['/rockstar', 'rockstar'], 6 | ['/文言', '文言'], 7 | ['/svg.svg', 'svg'] 8 | ] 9 | 10 | for (let [url, id] of urlAndIds) { 11 | await getHtmlAndReplace(url, id) 12 | } 13 | } 14 | 15 | async function getHtmlAndReplace(url, elementId) { 16 | const targetHtml = await (await fetch(url)).text() 17 | document.getElementById(elementId).innerHTML = targetHtml 18 | } 19 | 20 | go() 21 | -------------------------------------------------------------------------------- /packages/site/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "checkJs": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/site/mono.html: -------------------------------------------------------------------------------- 1 |
const shiki = require('shiki')
2 | 
3 | shiki.getHighlighter({
4 |   theme: JSON.parse(fs.readFileSync('./monochrome-dark-subtle.json', 'utf-8'))
5 | })
6 | 
7 | -------------------------------------------------------------------------------- /packages/site/mono.md: -------------------------------------------------------------------------------- 1 | ```js 2 | const shiki = require('shiki') 3 | 4 | shiki.getHighlighter({ 5 | theme: JSON.parse(fs.readFileSync('./monochrome-dark-subtle.json', 'utf-8')) 6 | }) 7 | ``` 8 | -------------------------------------------------------------------------------- /packages/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shiki-site", 3 | "version": "0.9.5", 4 | "private": true, 5 | "devDependencies": { 6 | "@types/node": "^10.17.60", 7 | "markdown-it": "^8.4.2", 8 | "playwright": "^1.13.1", 9 | "shiki": "^0.9.5", 10 | "shiki-renderer-svg": "^0.9.5" 11 | }, 12 | "scripts": { 13 | "gen": "node gen-index.js && node gen-palenight.js && node gen-mono.js && node gen-custom-theme.js && node gen-svg.js && node gen-wenyan.js" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/site/palenight.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | import * as React from 'react'; 3 | import './App.css'; 4 | import Hello from './components/Hello'; 5 | 6 | const logo = require('./logo.svg'); 7 | 8 | function App() { 9 | return ( 10 |
11 |
12 | logo 13 |

Welcome to React

14 |
15 |

16 | To get started, edit src/App.tsx and save to reload. 17 |

18 | 19 |
20 | ); 21 | } 22 | 23 | export default App; 24 | ``` -------------------------------------------------------------------------------- /packages/site/rockstar.html: -------------------------------------------------------------------------------- 1 |
Midnight takes your heart and your soul
 2 | While your heart is as high as your soul
 3 | Put your heart without your soul into your heart
 4 | 
 5 | Give back your heart
 6 | 
 7 | 
 8 | Desire is a lovestruck ladykiller
 9 | My world is nothing 
10 | Fire is ice
11 | Hate is water
12 | Until my world is Desire,
13 | Build my world up
14 | If Midnight taking my world, Fire is nothing and Midnight taking my world, Hate is nothing
15 | Shout "FizzBuzz!"
16 | Take it to the top
17 | 
18 | If Midnight taking my world, Fire is nothing
19 | Shout "Fizz!"
20 | Take it to the top
21 | 
22 | If Midnight taking my world, Hate is nothing
23 | Say "Buzz!"
24 | Take it to the top
25 |   
26 | Whisper my world
27 | 
28 | -------------------------------------------------------------------------------- /packages/site/rockstar.md: -------------------------------------------------------------------------------- 1 | ```rockstar 2 | Midnight takes your heart and your soul 3 | While your heart is as high as your soul 4 | Put your heart without your soul into your heart 5 | 6 | Give back your heart 7 | 8 | 9 | Desire is a lovestruck ladykiller 10 | My world is nothing 11 | Fire is ice 12 | Hate is water 13 | Until my world is Desire, 14 | Build my world up 15 | If Midnight taking my world, Fire is nothing and Midnight taking my world, Hate is nothing 16 | Shout "FizzBuzz!" 17 | Take it to the top 18 | 19 | If Midnight taking my world, Fire is nothing 20 | Shout "Fizz!" 21 | Take it to the top 22 | 23 | If Midnight taking my world, Hate is nothing 24 | Say "Buzz!" 25 | Take it to the top 26 | 27 | Whisper my world 28 | ``` 29 | -------------------------------------------------------------------------------- /packages/site/rockstar.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "_source":"https://github.com/ra100/vscode-rockstar-language", 3 | "_license": "https://github.com/ra100/vscode-rockstar-language/blob/master/LICENSE", 4 | "scopeName": "source.rockstar", 5 | "name": "Rockstar", 6 | "fileTypes": [ 7 | "rock", 8 | "rockstar" 9 | ], 10 | "patterns": [{ 11 | "include": "#proper-variable" 12 | }, { 13 | "include": "#loop" 14 | }, { 15 | "include": "#conditional" 16 | }, { 17 | "include": "#method" 18 | }, { 19 | "include": "#comment" 20 | }, { 21 | "include": "#string" 22 | }, { 23 | "include": "#io" 24 | }, { 25 | "include": "#pronoun" 26 | }, { 27 | "include": "#number" 28 | }, { 29 | "include": "#boolean" 30 | }, { 31 | "include": "#common" 32 | }, { 33 | "include": "#equal" 34 | }, { 35 | "include": "#comparator" 36 | }, { 37 | "include": "#arithmetic" 38 | }, { 39 | "include": "#string-assignment" 40 | }, { 41 | "include": "#null" 42 | }], 43 | "repository": { 44 | "comment": { 45 | "patterns": [{ 46 | "begin": "\\(", 47 | "beginCaptures": { 48 | "0": { 49 | "name": "comment.block.rockstar" 50 | } 51 | }, 52 | "end": "\\)", 53 | "endCaptures": { 54 | "0": { 55 | "name": "comment.block.rockstar" 56 | } 57 | }, 58 | "name": "comment.block.rockstar" 59 | }] 60 | }, 61 | "boolean": { 62 | "patterns": [{ 63 | "match": "(\\b(is|was|were) )?\\b(true|false|right|yes|ok|wrong|no($| +)|lies)\\b", 64 | "name": "keyword.operator.rockstar", 65 | "captures": { 66 | "2": { 67 | "name": "constant.language.rockstar" 68 | }, 69 | "3": { 70 | "name": "constant.language.rockstar" 71 | } 72 | } 73 | }] 74 | }, 75 | "null": { 76 | "patterns": [{ 77 | "match": "(\\b(is|was|were) )?\\b(nothing|nowhere|nobody|null)\\b", 78 | "captures": { 79 | "2": { 80 | "name": "keyword.operator.rockstar" 81 | }, 82 | "3": { 83 | "name": "constant.language.rockstar" 84 | } 85 | } 86 | }] 87 | }, 88 | "pronoun": { 89 | "patterns": [{ 90 | "match": "\\b(it|he|she|him|her|they|them|ze|hir|zie|zir|xe|xem|ve|ver)\\b", 91 | "name": "storage.type.pronoun.rockstar" 92 | }] 93 | }, 94 | "number": { 95 | "patterns": [{ 96 | "match": "\\b(is|was|were) (?!and|as|nothing|nowhere|nobody|null|true|false|right|yes|ok|wrong|no|lies)(([a-z]+($|\\s))+)", 97 | "captures": { 98 | "1": { 99 | "name": "keyword.operator.rockstar" 100 | }, 101 | "2": { 102 | "name": "constant.numeric.rockstar" 103 | } 104 | } 105 | }] 106 | }, 107 | "string": { 108 | "patterns": [{ 109 | "begin": "\"", 110 | "beginCaptures": { 111 | "0": { 112 | "name": "string.double.rockstar" 113 | } 114 | }, 115 | "end": "\"", 116 | "endCaptures": { 117 | "0": { 118 | "name": "string.double.rockstar" 119 | } 120 | }, 121 | "name": "string.double.rockstar" 122 | }, 123 | { 124 | "match": "'\\w*'", 125 | "name": "string.double.rockstar" 126 | }, 127 | { 128 | "match": ",", 129 | "scope": "string.double.rockstar" 130 | } 131 | ] 132 | }, 133 | "equal": { 134 | "patterns": [{ 135 | "match": "\\b('s|is( not($| +))?|ain't|was|were)\\b", 136 | "name": "keyword.operator.rockstar" 137 | }] 138 | }, 139 | "comparator": { 140 | "patterns": [{ 141 | "match": "(higher|greater|bigger|stronger|lower|less|smaller|weaker) than|as (high|great|big|strong|low|little|small|weak) as", 142 | "name": "keyword.operator.rockstar" 143 | }] 144 | }, 145 | "loop": { 146 | "patterns": [{ 147 | "match": "(^| )(While|Until|Continue|Break it down|break|Take it to the top)($| )", 148 | "name": "keyword.control.rockstar" 149 | }] 150 | }, 151 | "conditional": { 152 | "patterns": [{ 153 | "match": "(^| )(If|if|Else|else)", 154 | "name": "keyword.control.conditional.rockstar" 155 | }] 156 | }, 157 | "method": { 158 | "patterns": [{ 159 | "match": "\\b(taking|takes|and|Give back)\\b", 160 | "name": "keyword.other.rockstar" 161 | }] 162 | }, 163 | "io": { 164 | "patterns": [{ 165 | "match": "(^| )(Say|Shout|Whisper|Scream|Listen( to)?)", 166 | "name": "support.function.builtin.rockstar" 167 | }] 168 | }, 169 | "assignment": { 170 | "patterns": [{ 171 | "match": "((^Put\\b)|\\b(into)\\b)", 172 | "name": "keyword.operator.rockstar" 173 | }] 174 | }, 175 | "arithmetic": { 176 | "patterns": [{ 177 | "match": "(Knock | down|Build | up|plus|without|minus|with|times|of|over|by)", 178 | "name": "keyword.operator.arithmetic.rockstar" 179 | }] 180 | }, 181 | "common": { 182 | "patterns": [{ 183 | "match": "(?吾有「「春日宴。」」書之 2 | 有數名之曰「酒數」 3 | 4 | 恆為是「酒數」等於者乃止也 5 | 6 | 吾有「「與君」」「酒數」 7 | 「「杯酒。可以窮歡宴。綠酒一杯歌一遍。」」書之 8 | 9 | 「酒數」昔之「酒數」今其是矣云云 10 | 11 | 吾有「「綠酒千杯腸已爛。」」書之 -------------------------------------------------------------------------------- /packages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "files": [], 4 | "references": [{ "path": "./shiki" }, { "path": "./renderer-svg" }] 5 | } 6 | -------------------------------------------------------------------------------- /packages/vuepress-plugin/README.md: -------------------------------------------------------------------------------- 1 | # vuepress-plugin-shiki 2 | 3 | ```bash 4 | yarn global add vuepress@next 5 | yarn add -D vuepress-plugin-shiki 6 | ``` 7 | 8 | `.vuepress/config.js` 9 | 10 | ```js 11 | module.exports = { 12 | plugins: { 13 | shiki: { theme: 'nord' } // theme: TTheme 14 | } 15 | } 16 | ``` 17 | 18 | [`TTheme` values](../themes/README.md#literal-values) 19 | 20 | ```ts 21 | export type TVSCode = 22 | | 'abyss' 23 | | 'dark_vs' 24 | | 'light_vs' 25 | | 'hc_black' 26 | | 'dark_plus' 27 | | 'light_plus' 28 | | 'kimbie_dark' 29 | | 'monokai' 30 | | 'monokai_dimmed' 31 | | 'quietlight' 32 | | 'red' 33 | | 'solarized_dark' 34 | | 'solarized_light' 35 | 36 | export type TMaterial = 37 | | 'Darker-High-Contrast' 38 | | 'Darker' 39 | | 'Default-High-Contrast' 40 | | 'Default' 41 | | 'Lighter-High-Contrast' 42 | | 'Lighter' 43 | | 'Ocean-High-Contrast' 44 | | 'Ocean' 45 | | 'Palenight-High-Contrast' 46 | | 'Palenight' 47 | 48 | export type TNice = 49 | | 'nord' 50 | | 'min-light' 51 | | 'min-dark' 52 | | 'white' 53 | | 'white-night' 54 | 55 | export type TTheme = TVSCode | TMaterial | TNice 56 | ``` -------------------------------------------------------------------------------- /packages/vuepress-plugin/index.js: -------------------------------------------------------------------------------- 1 | const shiki = require('shiki') 2 | 3 | let h 4 | 5 | module.exports = (options, ctx) => { 6 | return { 7 | async ready() { 8 | h = await shiki.getHighlighter({ 9 | theme: options.theme ? options.theme : 'nord', 10 | langs: options.langs ? options.langs : [] 11 | }) 12 | }, 13 | 14 | chainMarkdown(config) { 15 | config.options.highlight((code, lang) => { 16 | if (!lang) { 17 | return `
${escapeHtml(code)}
` 18 | } 19 | return h.codeToHtml(code, lang) 20 | }) 21 | } 22 | } 23 | } 24 | 25 | const htmlEscapes = { 26 | '&': '&', 27 | '<': '<', 28 | '>': '>', 29 | '"': '"', 30 | "'": ''' 31 | } 32 | 33 | function escapeHtml(html) { 34 | return html.replace(/[&<>"']/g, chr => htmlEscapes[chr]) 35 | } 36 | -------------------------------------------------------------------------------- /packages/vuepress-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuepress-plugin-shiki", 3 | "private": true, 4 | "version": "0.9.5", 5 | "description": "Vuepress plugin for Shiki", 6 | "keywords": [ 7 | "shiki", 8 | "vuepress", 9 | "vuepress-plugin", 10 | "syntax-highlighter", 11 | "highlighter" 12 | ], 13 | "author": "Pine Wu ", 14 | "homepage": "https://github.com/octref/shiki/tree/master/packages/vuepress-plugin", 15 | "license": "MIT", 16 | "main": "index.js", 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/octref/shiki.git" 20 | }, 21 | "dependencies": { 22 | "shiki": "^0.9.5" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/grammars/normalizeGrammarPaths.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | import { vscodeGrammarsToRemove, vscodeGrammarsToRename } from '../grammarSources' 4 | import chalk from 'chalk' 5 | import json5 from 'json5' 6 | 7 | const GRAMMAR_FOLDER_PATH = path.join(__dirname, '../..', 'tmp/grammars') 8 | 9 | /** 10 | * Remove unneeded grammars 11 | */ 12 | let files = fs.readdirSync(GRAMMAR_FOLDER_PATH) 13 | for (let f of files) { 14 | const fName = f.replace(/\.tmLanguage.json$/i, '') 15 | 16 | if (vscodeGrammarsToRemove.includes(fName)) { 17 | const fPath = path.resolve(GRAMMAR_FOLDER_PATH, f) 18 | fs.unlinkSync(fPath) 19 | console.log(`${chalk.red('removed')} ${chalk.blue(fPath)}`) 20 | } 21 | } 22 | 23 | /** 24 | * Rename some grammars 25 | */ 26 | files = fs.readdirSync(GRAMMAR_FOLDER_PATH) 27 | for (let f of files) { 28 | const fPath = path.resolve(GRAMMAR_FOLDER_PATH, f) 29 | const fName = f.replace(/\.tmLanguage.json$/i, '') 30 | if (vscodeGrammarsToRename[fName]) { 31 | const fNewPath = path.resolve( 32 | GRAMMAR_FOLDER_PATH, 33 | vscodeGrammarsToRename[fName] + '.tmLanguage.json' 34 | ) 35 | fs.renameSync(fPath, fNewPath) 36 | console.log( 37 | `${chalk.red('renamed')} ${chalk.blue(f)} to ${chalk.blue( 38 | vscodeGrammarsToRename[fName] + '.tmLanguage.json' 39 | )}` 40 | ) 41 | } 42 | } 43 | 44 | /** 45 | * - Make sure each grammar's file name matches its `name` key 46 | */ 47 | files = fs.readdirSync(GRAMMAR_FOLDER_PATH) 48 | for (let f of files) { 49 | normalizeGrammarFile(f) 50 | } 51 | 52 | export function normalizeGrammarFile(f: string) { 53 | const fPath = path.resolve(GRAMMAR_FOLDER_PATH, f) 54 | const fNameWithoutSuffix = f.replace(/\.tmLanguage.json$/i, '') 55 | const fName = fNameWithoutSuffix.toLowerCase() 56 | 57 | if (fs.existsSync(fPath)) { 58 | const parsedContent = json5.parse(fs.readFileSync(fPath, 'utf-8')) 59 | 60 | if (parsedContent.name !== fName) { 61 | parsedContent.name = fName 62 | fs.writeFileSync(fPath, JSON.stringify(parsedContent, null, 2)) 63 | console.log(`${chalk.red('normalized')} ${f}'s \`name\` to ${chalk.yellow(fName)}`) 64 | } 65 | if (fNameWithoutSuffix !== fNameWithoutSuffix.toLowerCase()) { 66 | const fNewPath = path.resolve( 67 | GRAMMAR_FOLDER_PATH, 68 | fNameWithoutSuffix.toLowerCase() + '.tmLanguage.json' 69 | ) 70 | fs.renameSync(fPath, fNewPath) 71 | console.log(`${chalk.red('renamed')} ${chalk.blue(f)} to ${chalk.blue(f.toLowerCase())}`) 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /scripts/grammars/pullGrammarsFromGitHub.ts: -------------------------------------------------------------------------------- 1 | import { parse as plistParse } from 'fast-plist' 2 | import fs from 'fs' 3 | import yaml from 'js-yaml' 4 | import kebabCase from 'lodash.kebabcase' 5 | import path from 'path' 6 | import { githubGrammarSources } from '../grammarSources' 7 | import { convertGHURLToDownloadURL, get } from '../util/download' 8 | import json5 from 'json5' 9 | import chalk from 'chalk' 10 | 11 | const GRAMMAR_FOLDER_PATH = path.join(__dirname, '../..', 'tmp/grammars') 12 | 13 | async function go() { 14 | for (let urlOrNameWithUrl of githubGrammarSources) { 15 | await downloadGrammarFromGH(urlOrNameWithUrl) 16 | } 17 | } 18 | 19 | go() 20 | 21 | async function downloadGrammarFromGH(urlOrNameWithUrl: string | [string, string]) { 22 | const ghUrl = typeof urlOrNameWithUrl === 'string' ? urlOrNameWithUrl : urlOrNameWithUrl[1] 23 | const targetUrl = convertGHURLToDownloadURL(ghUrl) 24 | 25 | let content 26 | try { 27 | content = await get(targetUrl) 28 | } catch (e) { 29 | throw Error(`Failed to download grammar from ${ghUrl}: ${e}`) 30 | } 31 | 32 | let contentObj 33 | if (ghUrl.endsWith('.json')) { 34 | contentObj = json5.parse(content) 35 | } else if (ghUrl.endsWith('.plist')) { 36 | contentObj = plistParse(content) 37 | } else if (ghUrl.endsWith('.yml') || ghUrl.endsWith('.yaml')) { 38 | contentObj = yaml.load(content) 39 | } else { 40 | if (content[0] === '{') { 41 | contentObj = json5.parse(content) 42 | } else if (content[0] === '<') { 43 | contentObj = plistParse(content) 44 | } else { 45 | contentObj = yaml.load(content) 46 | } 47 | } 48 | 49 | /** 50 | * Make sure downloaded grammar has correct `name` 51 | */ 52 | const specifiedLangId = typeof urlOrNameWithUrl === 'string' ? undefined : urlOrNameWithUrl[0] 53 | if (specifiedLangId) { 54 | contentObj['name'] = specifiedLangId 55 | } 56 | 57 | const newFileName = specifiedLangId 58 | ? specifiedLangId + '.tmLanguage.json' 59 | : kebabCase(contentObj['name'].toLowerCase()) + '.tmLanguage.json' 60 | 61 | /** 62 | * Write file 63 | */ 64 | fs.writeFileSync( 65 | path.resolve(GRAMMAR_FOLDER_PATH, newFileName), 66 | JSON.stringify(contentObj, null, 2) 67 | ) 68 | console.log(`Downloaded grammar: ${chalk.blue(newFileName)}`) 69 | } 70 | -------------------------------------------------------------------------------- /scripts/grammars/updateGrammarSourceFiles.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | import json5 from 'json5' 4 | import { embeddedLanguagesToExclude, languageAliases } from '../grammarSources' 5 | 6 | const langDir = path.resolve(__dirname, '../../packages/shiki/languages') 7 | const sampleDir = path.resolve(__dirname, '../../packages/shiki/samples') 8 | const langPath = path.resolve(__dirname, '../../packages/shiki/src/languages.ts') 9 | const readmePath = path.resolve(__dirname, '../../docs/languages.md') 10 | 11 | // Regex to quickly see if a grammar uses `include` keys to embed other languages 12 | const INCLUDE_REGEX = /"include": "([^#$].+)"/g 13 | 14 | const files = fs.readdirSync(langDir) 15 | const langIds = files.map(f => f.replace('.tmLanguage.json', '')) 16 | const scopeToIdMap = {} 17 | langIds 18 | .filter(id => !embeddedLanguagesToExclude.includes(id)) 19 | .forEach(id => { 20 | const grammarPath = path.resolve(langDir, `${id}.tmLanguage.json`) 21 | const grammarSrc = fs.readFileSync(grammarPath, 'utf-8') 22 | const grammar = json5.parse(grammarSrc) 23 | 24 | scopeToIdMap[grammar.scopeName] = id 25 | }) 26 | 27 | const langRegistrationContent = langIds 28 | .filter(id => !embeddedLanguagesToExclude.includes(id)) 29 | .map(id => { 30 | const grammarPath = path.resolve(langDir, `${id}.tmLanguage.json`) 31 | const grammarSrc = fs.readFileSync(grammarPath, 'utf-8') 32 | const grammar = json5.parse(grammarSrc) 33 | 34 | let regContent = ` { 35 | id: '${id}', 36 | scopeName: '${grammar.scopeName}', 37 | path: '${id}.tmLanguage.json'` 38 | 39 | if (fs.existsSync(path.resolve(sampleDir, `${id}.sample`))) { 40 | regContent += `, 41 | samplePath: '${id}.sample'` 42 | } 43 | 44 | if (languageAliases[id]) { 45 | const aliasStr = languageAliases[id].map(a => `'` + a + `'`).join(', ') 46 | regContent += `, 47 | aliases: [${aliasStr}]` 48 | } 49 | 50 | const embeddedLangs = new Set() 51 | ;[...grammarSrc.matchAll(INCLUDE_REGEX)].forEach(([full, captured]) => { 52 | const scope = captured.split('#')[0] 53 | if (!grammar.scopeName || (grammar.scopeName && scope !== grammar.scopeName)) { 54 | if (scopeToIdMap[scope]) { 55 | embeddedLangs.add(scopeToIdMap[scope]) 56 | } 57 | } 58 | }) 59 | if (embeddedLangs.size > 0) { 60 | regContent += `, 61 | embeddedLangs: [${[...embeddedLangs].map(id => `'` + id + `'`).join(', ')}]` 62 | } 63 | 64 | regContent += ` 65 | }` 66 | 67 | return regContent 68 | }) 69 | .join(',\n') 70 | 71 | const langContent = `import { ILanguageRegistration } from './types' 72 | 73 | export type Lang = 74 | ${langIds 75 | .filter(id => !embeddedLanguagesToExclude.includes(id)) 76 | .map(id => { 77 | if (!languageAliases[id]) { 78 | return ` | '${id}'` 79 | } 80 | 81 | const baseContent = ` | '${id}'` 82 | const aliasesContent = languageAliases[id].map(l => `'` + l + `'`).join(' | ') 83 | return `${baseContent} | ${aliasesContent}` 84 | }) 85 | .join('\n')} 86 | 87 | export const languages: ILanguageRegistration[] = [ 88 | ${langRegistrationContent} 89 | ] 90 | ` 91 | 92 | fs.writeFileSync(langPath, langContent) 93 | 94 | const readmeReplaceContent = `export type Lang = 95 | ${langIds 96 | .filter(id => !embeddedLanguagesToExclude.includes(id)) 97 | .map(id => { 98 | if (!languageAliases[id]) { 99 | return ` | '${id}'` 100 | } 101 | 102 | const baseContent = ` | '${id}'` 103 | const aliasesContent = languageAliases[id].map(l => `'` + l + `'`).join(' | ') 104 | return `${baseContent} | ${aliasesContent}` 105 | }) 106 | .join('\n')} 107 | ` 108 | 109 | const readmeSrc = fs.readFileSync(readmePath, 'utf-8') 110 | const newReadmeSrc = readmeSrc.replace(/## All Languages\n\n```ts([^`]+)```/, (_match, langs) => { 111 | return '## All Languages\n\n```ts\n' + readmeReplaceContent + '```' 112 | }) 113 | 114 | fs.writeFileSync(readmePath, newReadmeSrc) 115 | -------------------------------------------------------------------------------- /scripts/pullGrammars.sh: -------------------------------------------------------------------------------- 1 | # clean up 2 | rm -rf tmp/grammars 3 | mkdir -p tmp/grammars 4 | 5 | echo "> Getting VS Code grammars" 6 | if [ ! -d tmp/vscode ]; then 7 | git clone https://github.com/microsoft/vscode.git tmp/vscode --depth=1 8 | else 9 | (cd tmp/vscode && git checkout . && git pull) 10 | fi 11 | # Two html file will cause `cp` to fail 12 | mv tmp/vscode/extensions/php/syntaxes/html.tmLanguage.json tmp/vscode/extensions/php/syntaxes/php-html.tmLanguage.json 13 | cp tmp/vscode/extensions/**/syntaxes/*.json tmp/grammars 14 | echo "> Done getting VS Code grammars" 15 | 16 | echo "> Getting grammars from GitHub" 17 | npx esno scripts/grammars/pullGrammarsFromGitHub.ts 18 | echo "> Done getting grammars from GitHub" 19 | 20 | echo "> Normalizing grammars" 21 | npx esno scripts/grammars/normalizeGrammarPaths.ts 22 | echo "> Done normalizing grammars" 23 | 24 | echo "> Copying grammars" 25 | cp tmp/grammars/*.json packages/shiki/languages 26 | echo "> Done copying grammars" 27 | 28 | echo "> Updating source files" 29 | npx esno scripts/grammars/updateGrammarSourceFiles.ts 30 | echo "> Done updating source files" 31 | 32 | echo "> Formatting grammar files" 33 | npx prettier --write packages/shiki/languages/* 34 | echo "> Done formatting grammar files" 35 | 36 | echo "> All done" 37 | -------------------------------------------------------------------------------- /scripts/pullThemes.sh: -------------------------------------------------------------------------------- 1 | # clean up 2 | rm -rf tmp/themes 3 | mkdir -p tmp/themes 4 | 5 | echo "> Getting VS Code themes" 6 | if [ ! -d tmp/vscode ]; then 7 | git clone https://github.com/microsoft/vscode.git tmp/vscode --depth=1 8 | else 9 | (cd tmp/vscode && git checkout . && git pull) 10 | fi 11 | cp tmp/vscode/extensions/theme-*/themes/*.json tmp/themes 12 | npx esno scripts/themes/processVSCThemes.ts 13 | echo "> Done getting VS Code themes" 14 | 15 | echo "> Getting themes from GitHub" 16 | npx esno scripts/themes/pullThemesFromGitHub.ts 17 | echo "> Done getting themes from GitHub" 18 | 19 | echo "> Getting themes from VS Code marketplace" 20 | npx esno scripts/themes/pullThemesFromMarketplace.ts 21 | echo "> Done getting themes from VS Code marketplace" 22 | 23 | echo "> Normalizing themes" 24 | npx esno scripts/themes/normalizeThemePaths.ts 25 | echo "> Done normalizing themes" 26 | 27 | echo "> Copying themes" 28 | cp tmp/themes/*.json packages/shiki/themes 29 | echo "> Done copying themes" 30 | 31 | echo "> Updating source files" 32 | npx esno scripts/themes/updateThemeSrc.ts 33 | echo "> Done updating source files" 34 | 35 | echo "> Formatting theme files" 36 | npx prettier --write packages/shiki/themes/* 37 | echo "> Done formatting theme files" 38 | 39 | echo "> All done" 40 | -------------------------------------------------------------------------------- /scripts/themeSources.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * All themes in vscode are copied over, with some transformations 3 | */ 4 | 5 | /** 6 | * Remove these themes bundled in vscode 7 | */ 8 | export const vscodeThemesToRemove = [ 9 | // Included in dark_plus 10 | 'dark_vs', 11 | // Included in light_plus 12 | 'light_vs', 13 | 'Red-color-theme', 14 | 'dimmed-monokai-color-theme', 15 | 'kimbie-dark-color-theme', 16 | 'quietlight-color-theme', 17 | 'abyss-color-theme', 18 | 'hc_black', 19 | 'tomorrow-night-blue-color-theme' 20 | ] 21 | 22 | /** 23 | * Rename these themes bundled in vscode 24 | */ 25 | export const vscodeThemesToRename = { 26 | dark_plus: 'dark-plus', 27 | light_plus: 'light-plus', 28 | 'monokai-color-theme': 'monokai', 29 | 'solarized-dark-color-theme': 'solarized-dark', 30 | 'solarized-light-color-theme': 'solarized-light' 31 | } 32 | 33 | /** 34 | * All theme sources on github.com. 35 | * 36 | * To add one: 37 | * - Add the URL to the end 38 | * - Run `yarn update:themes`, examine the changes 39 | * 40 | * The theme id is normalized from the `name` key of the theme json file. 41 | * When the theme provides an undesirable name (or no `name` key), for example `Slack Theme Dark Mode` at 42 | * https://github.com/slack-theme/visual-studio-code/blob/f4c3c57d35b89874de3c96df551d6809a30a82d7/themes/dark-mode.json#L2 43 | * provide an array like `['slack-dark', '']` to name the theme `slack-dark` 44 | */ 45 | export const githubThemeSources: (string | [string, string])[] = [ 46 | [ 47 | 'nord', 48 | 'https://github.com/arcticicestudio/nord-visual-studio-code/blob/develop/themes/nord-color-theme.json' 49 | ], 50 | 'https://github.com/misolori/min-theme/blob/master/themes/min-light.json', 51 | 'https://github.com/misolori/min-theme/blob/master/themes/min-dark.json', 52 | [ 53 | 'slack-ochin', 54 | 'https://github.com/slack-theme/visual-studio-code/blob/master/themes/ochin.json' 55 | ], 56 | [ 57 | 'slack-dark', 58 | 'https://github.com/slack-theme/visual-studio-code/blob/master/themes/dark-mode.json' 59 | ], 60 | [ 61 | 'poimandres', 62 | 'https://github.com/drcmda/poimandres-theme/blob/main/themes/poimandres-color-theme.json' 63 | ] 64 | ] 65 | 66 | /** 67 | * Themes from VS Code marketplace 68 | * Some themes have compilation step and do not include the built theme on GitHub, 69 | * so pull from VS Code marketplace instead. 70 | * 71 | * Key is publisher + extId 72 | * Value is a list. Each item represents a file to extract from the downloaded VSIX. 73 | * If given a single path `extension/foo/bar.json`, extract `bar.json` to `tmp/themes/bar.json` 74 | * If given ['baz.json', `extension/foo/bar.json`], extract `bar.json` to `tmp/themes/baz.json` 75 | */ 76 | export const marketplaceThemeSources: { [extPublisherAndId: string]: (string | string[])[] } = { 77 | 'equinusocio.vsc-material-theme': [ 78 | ['material-darker.json', 'extension/build/themes/Material-Theme-Darker.json'], 79 | ['material-default.json', 'extension/build/themes/Material-Theme-Default.json'], 80 | ['material-lighter.json', 'extension/build/themes/Material-Theme-Lighter.json'], 81 | ['material-ocean.json', 'extension/build/themes/Material-Theme-Ocean.json'], 82 | ['material-palenight.json', 'extension/build/themes/Material-Theme-Palenight.json'] 83 | ], 84 | 'dracula-theme.theme-dracula': [ 85 | ['dracula.json', 'extension/theme/dracula.json'], 86 | ['dracula-soft.json', 'extension/theme/dracula-soft.json'] 87 | ], 88 | 'GitHub.github-vscode-theme': [ 89 | ['github-dark.json', 'extension/themes/dark.json'], 90 | ['github-light.json', 'extension/themes/light.json'] 91 | ], 92 | 'antfu.theme-vitesse': [ 93 | ['vitesse-dark.json', 'themes/vitesse-dark.json'], 94 | ['vitesse-light.json', 'themes/vitesse-light.json'] 95 | ] 96 | } 97 | -------------------------------------------------------------------------------- /scripts/themes/normalizeThemePaths.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | import json5 from 'json5' 4 | import { vscodeThemesToRename, vscodeThemesToRemove } from '../themeSources' 5 | import chalk from 'chalk' 6 | 7 | const THEME_FOLDER_PATH = path.join(__dirname, '../..', 'tmp/themes') 8 | 9 | /** 10 | * Remove unneeded themes 11 | */ 12 | let files = fs.readdirSync(THEME_FOLDER_PATH) 13 | for (let f of files) { 14 | const fName = f.replace(/\.json$/i, '') 15 | 16 | if (vscodeThemesToRemove.includes(fName)) { 17 | const fPath = path.resolve(THEME_FOLDER_PATH, f) 18 | fs.unlinkSync(fPath) 19 | console.log(`${chalk.red('removed')} ${chalk.blue(fPath)}`) 20 | } 21 | } 22 | 23 | /** 24 | * Rename some themes 25 | */ 26 | files = fs.readdirSync(THEME_FOLDER_PATH) 27 | for (let f of files) { 28 | const fPath = path.resolve(THEME_FOLDER_PATH, f) 29 | const fName = f.replace(/\.json$/i, '') 30 | if (vscodeThemesToRename[fName]) { 31 | const fNewPath = path.resolve(THEME_FOLDER_PATH, vscodeThemesToRename[fName] + '.json') 32 | fs.renameSync(fPath, fNewPath) 33 | console.log( 34 | `${chalk.red('renamed')} ${chalk.blue(f)} to ${chalk.blue( 35 | vscodeThemesToRename[fName] + '.json' 36 | )}` 37 | ) 38 | } 39 | } 40 | 41 | /** 42 | * - Make sure each theme's file name matches its `name` key 43 | */ 44 | files = fs.readdirSync(THEME_FOLDER_PATH) 45 | for (let f of files) { 46 | normalizeThemeFile(f) 47 | } 48 | 49 | /** 50 | * - Make sure each theme's file name matches its `name` key 51 | */ 52 | export function normalizeThemeFile(f: string) { 53 | const fPath = path.resolve(THEME_FOLDER_PATH, f) 54 | const fNameWithoutSuffix = f.replace(/\.json$/i, '') 55 | const fName = fNameWithoutSuffix.toLowerCase() 56 | 57 | if (fs.existsSync(fPath)) { 58 | const parsedContent = json5.parse(fs.readFileSync(fPath, 'utf-8')) 59 | 60 | if (!parsedContent.name || parsedContent.name !== fName) { 61 | parsedContent.name = fName 62 | fs.writeFileSync(fPath, JSON.stringify(parsedContent, null, 2)) 63 | console.log(`${chalk.red('normalized')} ${f}'s \`name\` to ${chalk.yellow(fName)}`) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /scripts/themes/processVSCThemes.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | import json5 from 'json5' 4 | 5 | const THEME_FOLDER_PATH = path.join(__dirname, '../..', 'tmp/themes') 6 | 7 | function readJson5(f) { 8 | const p = path.resolve(THEME_FOLDER_PATH, f) 9 | if (!fs.existsSync(p)) { 10 | return undefined 11 | } 12 | 13 | return json5.parse(fs.readFileSync(p, 'utf-8')) 14 | } 15 | 16 | /** 17 | * Handle dark/light plus 18 | * 19 | * - Merge dark_vs into dark_plus 20 | * - Merge light_vs into light_plus 21 | * - Unshift `editor.foreground` and `editor.background` to beginning of `tokenColors`. 22 | * - Remove dark_vs and light_vs 23 | */ 24 | const darkVSContent = readJson5('dark_vs.json') 25 | const darkPlusContent = readJson5('dark_plus.json') 26 | 27 | if (darkVSContent && darkPlusContent) { 28 | delete darkPlusContent['include'] 29 | const darkDefaultFgBgTokenColor = { 30 | settings: { 31 | foreground: darkVSContent['colors']['editor.foreground'] 32 | } 33 | } 34 | darkPlusContent.name = 'dark-plus' 35 | darkPlusContent.colors = { ...darkVSContent.colors } 36 | darkPlusContent.tokenColors = [ 37 | darkDefaultFgBgTokenColor, 38 | ...darkVSContent.tokenColors, 39 | ...darkPlusContent.tokenColors 40 | ] 41 | darkPlusContent.semanticTokenColors = { 42 | ...darkVSContent.semanticTokenColors, 43 | ...darkPlusContent.semanticTokenColors 44 | } 45 | 46 | fs.writeFileSync( 47 | path.resolve(THEME_FOLDER_PATH, 'dark_plus.json'), 48 | JSON.stringify(darkPlusContent, null, 2) 49 | ) 50 | } 51 | 52 | const lightVSContent = readJson5('light_vs.json') 53 | const lightPlusContent = readJson5('light_plus.json') 54 | 55 | if (lightVSContent && lightPlusContent) { 56 | delete lightPlusContent['include'] 57 | const lightDefaultFgBgTokenColor = { 58 | settings: { 59 | foreground: lightVSContent['colors']['editor.foreground'] 60 | } 61 | } 62 | lightPlusContent.name = 'light-plus' 63 | lightPlusContent.colors = { ...lightVSContent.colors } 64 | lightPlusContent.tokenColors = [ 65 | lightDefaultFgBgTokenColor, 66 | ...lightVSContent.tokenColors, 67 | ...lightPlusContent.tokenColors 68 | ] 69 | lightPlusContent.semanticTokenColors = { 70 | ...lightVSContent.semanticTokenColors, 71 | ...lightPlusContent.semanticTokenColors 72 | } 73 | 74 | fs.writeFileSync( 75 | path.resolve(THEME_FOLDER_PATH, 'light_plus.json'), 76 | JSON.stringify(lightPlusContent, null, 2) 77 | ) 78 | } 79 | -------------------------------------------------------------------------------- /scripts/themes/pullThemesFromGitHub.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import json5 from 'json5' 3 | import kebabCase from 'lodash.kebabcase' 4 | import path from 'path' 5 | import { githubThemeSources } from '../themeSources' 6 | import { convertGHURLToDownloadURL, get } from '../util/download' 7 | import chalk from 'chalk' 8 | 9 | const THEME_FOLDER_PATH = path.join(__dirname, '../..', 'tmp/themes') 10 | 11 | async function go() { 12 | for (let urlOrNameWithUrl of githubThemeSources) { 13 | await downloadThemeFromGH(urlOrNameWithUrl) 14 | } 15 | } 16 | 17 | go() 18 | 19 | async function downloadThemeFromGH(urlOrNameWithUrl: string | [string, string]) { 20 | const ghUrl = typeof urlOrNameWithUrl === 'string' ? urlOrNameWithUrl : urlOrNameWithUrl[1] 21 | const targetUrl = convertGHURLToDownloadURL(ghUrl) 22 | 23 | let content 24 | try { 25 | content = await get(targetUrl) 26 | } catch (e) { 27 | throw Error(`Failed to download grammar from ${ghUrl}: ${e}`) 28 | } 29 | 30 | const contentObj = json5.parse(content) 31 | 32 | /** 33 | * Make sure downloaded theme has correct `name` 34 | */ 35 | const specifiedLangId = typeof urlOrNameWithUrl === 'string' ? undefined : urlOrNameWithUrl[0] 36 | if (specifiedLangId) { 37 | contentObj['name'] = specifiedLangId 38 | } 39 | 40 | const newFileName = specifiedLangId 41 | ? specifiedLangId + '.json' 42 | : kebabCase(contentObj['name'].toLowerCase()) + '.json' 43 | 44 | /** 45 | * Write file 46 | */ 47 | fs.writeFileSync( 48 | path.resolve(THEME_FOLDER_PATH, newFileName), 49 | JSON.stringify(contentObj, null, 2) 50 | ) 51 | console.log(`Downloaded theme: ${chalk.blue(newFileName)}`) 52 | } 53 | -------------------------------------------------------------------------------- /scripts/themes/pullThemesFromMarketplace.ts: -------------------------------------------------------------------------------- 1 | import { get } from '../util/download' 2 | import fs from 'fs' 3 | import unzipper from 'unzipper' 4 | import { marketplaceThemeSources } from '../themeSources' 5 | import chalk from 'chalk' 6 | 7 | go() 8 | 9 | async function go() { 10 | for (let [extFullId, fPaths] of Object.entries(marketplaceThemeSources)) { 11 | const [_publisher, extId] = extFullId.split('.') 12 | let content 13 | try { 14 | content = await get(getMarketplaceLink(extFullId), 'binary') 15 | } catch (e) { 16 | console.log(e) 17 | throw Error(`Failed`) 18 | } 19 | 20 | const zipPath = `tmp/${extId}.zip` 21 | fs.writeFileSync(zipPath, content) 22 | 23 | const zip = fs.createReadStream(zipPath).pipe(unzipper.Parse({ forceStream: true })) 24 | 25 | for await (const entry of zip) { 26 | const match = fPaths.filter(pathOrNameWithPath => { 27 | if (typeof pathOrNameWithPath === 'string') { 28 | return entry.path === pathOrNameWithPath 29 | } else { 30 | return entry.path === pathOrNameWithPath[1] 31 | } 32 | }) 33 | 34 | if (match.length > 0) { 35 | const fName = typeof match[0] === 'string' ? entry.path.split('/').pop() : match[0][0] 36 | 37 | entry.pipe(fs.createWriteStream(`tmp/themes/${fName}`)) 38 | console.log( 39 | `${chalk.red('extracted')} ${chalk.blue(fName)} from ${chalk.yellow(extFullId)}` 40 | ) 41 | } else { 42 | entry.autodrain() 43 | } 44 | } 45 | } 46 | } 47 | 48 | function getMarketplaceLink(publisherDotExtId: string) { 49 | const [publisher, extId] = publisherDotExtId.split('.') 50 | 51 | return ( 52 | `https://${publisher}.gallery.vsassets.io` + 53 | `/_apis/public/gallery/publisher/${publisher}` + 54 | `/extension/${extId}/latest` + 55 | `/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage` 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /scripts/themes/updateThemeSrc.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | const themeDir = path.resolve(__dirname, '../../packages/shiki/themes') 5 | const themePath = path.resolve(__dirname, '../../packages/shiki/src/themes.ts') 6 | const readmePath = path.resolve(__dirname, '../../docs/themes.md') 7 | 8 | const files = fs.readdirSync(themeDir) 9 | const themeIds = files.map(f => f.replace('.json', '')) 10 | 11 | const themeContent = `export type Theme = 12 | ${themeIds.map(id => ` | '${id}'`).join('\n')} 13 | 14 | export const themes: Theme[] = [ 15 | ${themeIds.map(id => ` '${id}'`).join(',\n')} 16 | ] 17 | ` 18 | 19 | fs.writeFileSync(themePath, themeContent) 20 | 21 | const readmeReplaceContent = `export type Theme = 22 | ${themeIds.map(id => ` | '${id}'`).join('\n')} 23 | ` 24 | 25 | const readmeSrc = fs.readFileSync(readmePath, 'utf-8') 26 | const newReadmeSrc = readmeSrc.replace(/## All Themes\n\n```ts([^`]+)```/, (_match, langs) => { 27 | return '## All Themes\n\n```ts\n' + readmeReplaceContent + '```' 28 | }) 29 | 30 | fs.writeFileSync(readmePath, newReadmeSrc) 31 | -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "target": "es2017", 5 | "esModuleInterop": true, 6 | "moduleResolution": "node", 7 | "lib": ["esnext"], 8 | "sourceMap": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/util/download.ts: -------------------------------------------------------------------------------- 1 | import url from 'url' 2 | import https from 'https' 3 | 4 | export async function get(url: string, encoding: BufferEncoding = 'utf-8'): Promise { 5 | return new Promise((r, reject) => { 6 | https 7 | .get(url, res => { 8 | const { statusCode } = res 9 | if (statusCode !== 200) { 10 | reject('request failed') 11 | } 12 | 13 | res.setEncoding(encoding) 14 | if (encoding === 'utf-8') { 15 | let rawData = '' 16 | res.on('data', chunk => (rawData += chunk)) 17 | res.on('end', () => { 18 | try { 19 | r(rawData) 20 | } catch (e) { 21 | console.log(e) 22 | reject('get failed') 23 | } 24 | }) 25 | } else if (encoding === 'binary') { 26 | let data = [] 27 | res.on('data', chunk => data.push(Buffer.from(chunk, 'binary'))) 28 | res.on('end', function () { 29 | r(Buffer.concat(data)) 30 | }) 31 | res.on('error', function (err) { 32 | console.log(err) 33 | reject('get failed') 34 | }) 35 | } 36 | }) 37 | .on('error', e => { 38 | reject('get failed') 39 | }) 40 | }) 41 | } 42 | 43 | export function convertGHURLToDownloadURL(ghURL: string) { 44 | const oldPath = url.parse(ghURL).path 45 | return 'https://raw.githubusercontent.com' + oldPath.replace('/blob/', '/') 46 | } 47 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "moduleResolution": "node", 8 | "lib": ["es2015", "es2016.array.include", "DOM", "WebWorker"], 9 | "sourceMap": true 10 | }, 11 | "references": [{ "path": "packages/shiki" }, { "path": "packages/renderer-svg" }] 12 | } 13 | --------------------------------------------------------------------------------