prosemirror-highlight
v0.15.1
Published
A ProseMirror plugin to highlight code blocks
Downloads
816,246
Maintainers
Readme
prosemirror-highlight
Highlight your ProseMirror code blocks with any syntax highlighter you like!
Usage
With Shiki
import { createHighlightPlugin } from 'prosemirror-highlight'
import { createParser } from 'prosemirror-highlight/shiki'
import { getSingletonHighlighter } from 'shiki'
const highlighter = await getSingletonHighlighter({
themes: ['github-light'],
langs: ['javascript', 'typescript', 'python'],
})
const parser = createParser(highlighter)
export const shikiPlugin = createHighlightPlugin({ parser })import { createHighlightPlugin } from 'prosemirror-highlight'
import { createParser, type Parser } from 'prosemirror-highlight/shiki'
import type { Decoration } from 'prosemirror-view'
import {
createHighlighter,
type BuiltinLanguage,
type Highlighter,
} from 'shiki'
let highlighter: Highlighter | undefined
let highlighterPromise: Promise<void> | undefined
let parser: Parser | undefined
const loadedLanguages = new Set<string>()
function loadHighlighter(): Promise<void> {
if (!highlighterPromise) {
highlighterPromise = createHighlighter({
themes: ['github-light', 'github-dark', 'github-dark-dimmed'],
langs: [],
}).then((h) => {
highlighter = h
})
}
return highlighterPromise
}
async function loadLanguage(
highlighter: Highlighter,
language: string,
): Promise<void> {
try {
return await highlighter.loadLanguage(language as BuiltinLanguage)
} finally {
loadedLanguages.add(language)
}
}
/**
* Lazy load highlighter and highlighter languages.
*
* When the highlighter or the required language is not loaded, it returns a
* promise that resolves when the highlighter or the language is loaded.
* Otherwise, it returns an array of decorations.
*/
const lazyParser: Parser = (options): Promise<void> | Decoration[] => {
if (!highlighter) {
return loadHighlighter()
}
const language = options.language
if (language && !loadedLanguages.has(language)) {
return loadLanguage(highlighter, language)
}
if (!parser) {
parser = createParser(highlighter, {
themes: {
light: 'github-light',
dark: 'github-dark',
dim: 'github-dark-dimmed',
},
defaultColor: 'dim',
})
}
return parser(options)
}
export const shikiLazyPlugin = createHighlightPlugin({ parser: lazyParser })When using Shiki, two CSS variables are set automatically to the <pre> element:
--prosemirror-highlight: The text color of the code block--prosemirror-highlight-bg: The background color of the code block
You can use these variables to set the background color and text color of the code block.
.ProseMirror pre {
color: var(--prosemirror-highlight, inherit);
background-color: var(--prosemirror-highlight-bg, inherit);
}With lowlight (based on Highlight.js)
import 'highlight.js/styles/default.css'
import { common, createLowlight } from 'lowlight'
import { createHighlightPlugin } from 'prosemirror-highlight'
import { createParser } from 'prosemirror-highlight/lowlight'
const lowlight = createLowlight(common)
const parser = createParser(lowlight)
export const lowlightPlugin = createHighlightPlugin({ parser })With refractor (based on Prism)
import { createHighlightPlugin } from 'prosemirror-highlight'
import { createParser } from 'prosemirror-highlight/refractor'
import { refractor } from 'refractor/all'
const parser = createParser(refractor)
export const refractorPlugin = createHighlightPlugin({ parser })With Lezer
import type { Tree } from '@lezer/common'
import { parser as cssParser } from '@lezer/css'
import { classHighlighter } from '@lezer/highlight'
import { parser as javascriptParser } from '@lezer/javascript'
import { createHighlightPlugin } from 'prosemirror-highlight'
import { createParser, type ParserOptions } from 'prosemirror-highlight/lezer'
function parse({ content, language }: ParserOptions): Tree | undefined {
const lang = language?.toLowerCase() || ''
switch (lang) {
case 'js':
case 'javascript':
case 'ts':
case 'typescript':
case 'jsx':
case 'tsx':
return javascriptParser.parse(content)
case 'css':
case 'scss':
case 'sass':
return cssParser.parse(content)
default:
return undefined
}
}
const parser = createParser({ highlighter: classHighlighter, parse })
export const lezerPlugin = createHighlightPlugin({ parser })With Sugar high
import { createHighlightPlugin } from 'prosemirror-highlight'
import { createParser } from 'prosemirror-highlight/sugar-high'
const parser = createParser()
export const sugarHighPlugin = createHighlightPlugin({ parser }):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;
}Line Numbers
You can add line numbers to code blocks by wrapping any parser with withLineNumbers:
import { createHighlightPlugin, withLineNumbers } from 'prosemirror-highlight'
import { createParser } from 'prosemirror-highlight/shiki'
import { getSingletonHighlighter } from 'shiki'
const highlighter = await getSingletonHighlighter({
themes: ['github-light'],
langs: ['javascript', 'typescript', 'python'],
})
const parser = withLineNumbers(createParser(highlighter))
export const shikiPlugin = createHighlightPlugin({ parser })This inserts <span class="line-number"> elements with class name line-number at the start of each line.
Online demo
Credits
- prosemirror-highlightjs - Highlight.js syntax highlighting for ProseMirror
License
MIT
