From 6d367fe350fdf0b9a0e342276a7caa8fcede9f61 Mon Sep 17 00:00:00 2001 From: ocavue Date: Tue, 21 May 2024 11:04:38 +1000 Subject: [PATCH] feat: support sugar-high (#29) --- README.md | 30 +++++++++++++ package.json | 14 +++++- playground/index.html | 25 +++++++---- playground/main.ts | 9 ++++ playground/sugar-high.ts | 5 +++ pnpm-lock.yaml | 7 +++ src/sugar-high.ts | 48 ++++++++++++++++++++ test/plugin.spec.ts | 96 ++++++++++++++++++++++++++++++++++++++++ tsup.config.ts | 1 + 9 files changed, 225 insertions(+), 10 deletions(-) create mode 100644 playground/sugar-high.ts create mode 100644 src/sugar-high.ts diff --git a/README.md b/README.md index e6a5753..78d34b1 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,35 @@ export const refractorPlugin = createHighlightPlugin({ parser }) +### With [Sugar high] + +
+Highlight with CSS + +```ts +import { createHighlightPlugin } from 'prosemirror-highlight' +import { createParser } from 'prosemirror-highlight/sugar-high' + +const parser = createParser() +export const sugarHighPlugin = createHighlightPlugin({ parser }) +``` + +```css +:root { + --sh-class: #2d5e9d; + --sh-identifier: #354150; + --sh-sign: #8996a3; + --sh-property: #0550ae; + --sh-entity: #249a97; + --sh-jsxliterals: #6266d1; + --sh-string: #00a99a; + --sh-keyword: #f47067; + --sh-comment: #a19595; +} +``` + +
+ ## Online demo [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/ocavue/prosemirror-highlight?file=playground%2Fmain.ts) @@ -215,3 +244,4 @@ MIT [Shikiji]: https://github.com/antfu/shikiji [refractor]: https://github.com/wooorm/refractor [Prism]: https://github.com/PrismJS/prism +[Sugar high]: https://github.com/huozhi/sugar-high diff --git a/package.json b/package.json index acd798e..f09edc6 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,9 @@ }, "./shikiji": { "default": "./src/shikiji.ts" + }, + "./sugar-high": { + "default": "./src/sugar-high.ts" } }, "files": [ @@ -67,7 +70,8 @@ "prosemirror-view": "^1.32.4", "refractor": "^4.8.1", "shiki": "^1.0.0", - "shikiji": "^0.8.0 || ^0.9.0 || ^0.10.0" + "shikiji": "^0.8.0 || ^0.9.0 || ^0.10.0", + "sugar-high": "^0.6.1" }, "peerDependenciesMeta": { "@types/hast": { @@ -99,6 +103,9 @@ }, "shikiji": { "optional": true + }, + "sugar-high": { + "optional": true } }, "devDependencies": { @@ -120,6 +127,7 @@ "refractor": "^4.8.1", "shiki": "^1.0.0", "shikiji": "^0.10.2", + "sugar-high": "^0.6.1", "tsup": "^8.0.1", "typescript": "^5.3.3", "vite": "^5.0.10", @@ -149,6 +157,10 @@ "./shikiji": { "types": "./dist/shikiji.d.ts", "default": "./dist/shikiji.js" + }, + "./sugar-high": { + "types": "./dist/sugar-high.d.ts", + "default": "./dist/sugar-high.js" } }, "typesVersions": { diff --git a/playground/index.html b/playground/index.html index e393cc3..7d189b1 100644 --- a/playground/index.html +++ b/playground/index.html @@ -17,19 +17,26 @@ border-radius: 6px; } - .editor { - margin: 8px; + body { + column-count: auto; + column-gap: 20px; + column-width: 500px; } - body { - display: grid; - grid-template-columns: repeat(1, minmax(0, 1fr)); + body > * { + break-inside: avoid; } - @media (min-width: 1200px) { - body { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } + :root { + --sh-class: #2d5e9d; + --sh-identifier: #354150; + --sh-sign: #8996a3; + --sh-property: #0550ae; + --sh-entity: #249a97; + --sh-jsxliterals: #6266d1; + --sh-string: #00a99a; + --sh-keyword: #f47067; + --sh-comment: #a19595; } diff --git a/playground/main.ts b/playground/main.ts index 8a8e1cf..5de726e 100644 --- a/playground/main.ts +++ b/playground/main.ts @@ -11,6 +11,8 @@ import { shikijiPlugin } from './shikiji' import { shikijiLazyPlugin } from './shikiji-lazy' import shikijiLazyCode from './shikiji-lazy?raw' import shikijiCode from './shikiji?raw' +import { sugarHighPlugin } from './sugar-high' +import sugarHighCode from './sugar-high?raw' function getOrCreateElement(id: string): HTMLElement { let element = document.getElementById(id) @@ -53,6 +55,13 @@ function main() { code: refractorCode, }) + setupView({ + mount: getOrCreateElement('editor-sugar-high'), + plugin: sugarHighPlugin, + title: 'Sugar High Example', + code: sugarHighCode, + }) + setupView({ mount: getOrCreateElement('editor-shiki-lazy'), plugin: shikiLazyPlugin, diff --git a/playground/sugar-high.ts b/playground/sugar-high.ts new file mode 100644 index 0000000..58d40af --- /dev/null +++ b/playground/sugar-high.ts @@ -0,0 +1,5 @@ +import { createHighlightPlugin } from 'prosemirror-highlight' +import { createParser } from 'prosemirror-highlight/sugar-high' + +const parser = createParser() +export const sugarHighPlugin = createHighlightPlugin({ parser }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47fcba6..9926716 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ devDependencies: shikiji: specifier: ^0.10.2 version: 0.10.2 + sugar-high: + specifier: ^0.6.1 + version: 0.6.1 tsup: specifier: ^8.0.1 version: 8.0.1(typescript@5.3.3) @@ -3585,6 +3588,10 @@ packages: ts-interface-checker: 0.1.13 dev: true + /sugar-high@0.6.1: + resolution: {integrity: sha512-kg1qMW7WwJcueXIlHkChL/p2EWY3gf8rQmP6n5nUq2TWVqatqDTMLvViS9WgAjgyTKH5/3/b8sRwWPOOAo1zMA==} + dev: true + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} diff --git a/src/sugar-high.ts b/src/sugar-high.ts new file mode 100644 index 0000000..954b641 --- /dev/null +++ b/src/sugar-high.ts @@ -0,0 +1,48 @@ +import { Decoration } from 'prosemirror-view' +import { tokenize } from 'sugar-high' + +import type { Parser } from './types' + +export type { Parser } + +/** + * Copied from https://github.com/huozhi/sugar-high/blob/v0.6.1/lib/index.js#L80-L107 + */ +const types = [ + 'identifier', + 'keyword', + 'string', + 'class', + 'property', + 'entity', + 'jsxliterals', + 'sign', + 'comment', + 'break', + 'space', +] as const + +export function createParser(): Parser { + return function parser({ content, pos }) { + const decorations: Decoration[] = [] + + const tokens = tokenize(content) + + let from = pos + 1 + + for (const [type, content] of tokens) { + const to = from + content.length + + const decoration = Decoration.inline(from, to, { + class: `sh__token--${types[type]}`, + style: `color: var(--sh-${types[type]})`, + }) + + decorations.push(decoration) + + from = to + } + + return decorations + } +} diff --git a/test/plugin.spec.ts b/test/plugin.spec.ts index 998268a..021c72e 100644 --- a/test/plugin.spec.ts +++ b/test/plugin.spec.ts @@ -149,4 +149,100 @@ describe('createHighlightPlugin', () => { `, ) }) + + it('can highlight code blocks with sugar-high', async () => { + const { createParser } = await import('../src/sugar-high') + + const parser = createParser() + const plugin = createHighlightPlugin({ parser }) + + const state = EditorState.create({ doc, plugins: [plugin] }) + const view = new EditorView(document.createElement('div'), { state }) + + const html = await formatHtml(view.dom.outerHTML) + expect(html).toMatchInlineSnapshot( + ` + "
+
+          
+            
+              console
+            
+            
+              .
+            
+            
+              log
+            
+            
+              (
+            
+            
+              123
+            
+            
+              +
+            
+            
+              "
+            
+            
+              456
+            
+            
+              "
+            
+            
+              )
+            
+            
+              ;
+            
+          
+        
+
+          
+            
+              print
+            
+            
+              (
+            
+            
+              "
+            
+            
+              1+1
+            
+            
+              "
+            
+            
+              ,
+            
+            
+              "
+            
+            
+              =
+            
+            
+              "
+            
+            
+              ,
+            
+            
+              2
+            
+            
+              )
+            
+          
+        
+
; + " + `, + ) + }) }) diff --git a/tsup.config.ts b/tsup.config.ts index 1adc4c5..70eb454 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -7,6 +7,7 @@ export default defineConfig({ 'src/refractor.ts', 'src/shiki.ts', 'src/shikiji.ts', + 'src/sugar-high.ts', ], format: ['esm'], clean: true,