mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-20 06:01:24 +02:00
syntax highlighting (#3762)
* syntax highlighting * Delete package-lock.json * Update package.json * Update package.json * Delete syntax-highlighting.js * Update [example].js * Update [example].js * Update [example].js * added correct file * linting * Update site/examples/code-highlighting.js Co-authored-by: Tim Buckley <timothypbuckley@gmail.com> * Update site/examples/code-highlighting.js Co-authored-by: Tim Buckley <timothypbuckley@gmail.com> * Update site/examples/code-highlighting.js Co-authored-by: Tim Buckley <timothypbuckley@gmail.com> * updated pull request with some linting * moved getLength fcn Co-authored-by: Tim Buckley <timothypbuckley@gmail.com>
This commit is contained in:
237
site/examples/code-highlighting.js
Normal file
237
site/examples/code-highlighting.js
Normal file
@@ -0,0 +1,237 @@
|
||||
import Prism from 'prismjs'
|
||||
import 'prismjs/components/prism-python'
|
||||
import 'prismjs/components/prism-php'
|
||||
import 'prismjs/components/prism-sql'
|
||||
import 'prismjs/components/prism-java'
|
||||
import React, { useState, useCallback, useMemo } from 'react'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
import { Text, createEditor } from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { css } from 'emotion'
|
||||
|
||||
const CodeHighlightingExample = () => {
|
||||
const [value, setValue] = useState(initialValue)
|
||||
const [language, setLanguage] = useState('html')
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
|
||||
// decorate function depends on the language selected
|
||||
const decorate = useCallback(
|
||||
([node, path]) => {
|
||||
const ranges = []
|
||||
if (!Text.isText(node)) {
|
||||
return ranges
|
||||
}
|
||||
const tokens = Prism.tokenize(node.text, Prism.languages[language])
|
||||
let start = 0
|
||||
|
||||
for (const token of tokens) {
|
||||
const length = getLength(token)
|
||||
const end = start + length
|
||||
|
||||
if (typeof token !== 'string') {
|
||||
ranges.push({
|
||||
[token.type]: true,
|
||||
anchor: { path, offset: start },
|
||||
focus: { path, offset: end },
|
||||
})
|
||||
}
|
||||
|
||||
start = end
|
||||
}
|
||||
|
||||
return ranges
|
||||
},
|
||||
[language]
|
||||
)
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<div
|
||||
contentEditable={false}
|
||||
style={{ position: 'relative', top: '5px', right: '5px' }}
|
||||
>
|
||||
<h3>
|
||||
Select a language
|
||||
<select
|
||||
value={language}
|
||||
style={{ float: 'right' }}
|
||||
onChange={e => setLanguage(e.target.value)}
|
||||
>
|
||||
<option value="js">JavaScript</option>
|
||||
<option value="css">CSS</option>
|
||||
<option value="html">HTML</option>
|
||||
<option value="python">Python</option>
|
||||
<option value="sql">SQL</option>
|
||||
<option value="java">Java</option>
|
||||
<option value="php">PHP</option>
|
||||
</select>
|
||||
</h3>
|
||||
</div>
|
||||
<Editable
|
||||
decorate={decorate}
|
||||
renderLeaf={renderLeaf}
|
||||
placeholder="Write some code..."
|
||||
/>
|
||||
</Slate>
|
||||
)
|
||||
}
|
||||
|
||||
const getLength = token => {
|
||||
if (typeof token === 'string') {
|
||||
return token.length
|
||||
} else if (typeof token.content === 'string') {
|
||||
return token.content.length
|
||||
} else {
|
||||
return token.content.reduce((l, t) => l + getLength(t), 0)
|
||||
}
|
||||
}
|
||||
|
||||
// different token types, styles found on Prismjs website
|
||||
const Leaf = ({ attributes, children, leaf }) => {
|
||||
return (
|
||||
<span
|
||||
{...attributes}
|
||||
className={css`
|
||||
font-family: monospace;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
|
||||
${leaf.comment &&
|
||||
css`
|
||||
color: slategray;
|
||||
`}
|
||||
|
||||
${(leaf.operator || leaf.url) &&
|
||||
css`
|
||||
color: #9a6e3a;
|
||||
`}
|
||||
${leaf.keyword &&
|
||||
css`
|
||||
color: #07a;
|
||||
`}
|
||||
${(leaf.variable || leaf.regex) &&
|
||||
css`
|
||||
color: #e90;
|
||||
`}
|
||||
${(leaf.number ||
|
||||
leaf.boolean ||
|
||||
leaf.tag ||
|
||||
leaf.constant ||
|
||||
leaf.symbol ||
|
||||
leaf.attr - name ||
|
||||
leaf.selector) &&
|
||||
css`
|
||||
color: #905;
|
||||
`}
|
||||
${leaf.punctuation &&
|
||||
css`
|
||||
color: #999;
|
||||
`}
|
||||
${(leaf.string || leaf.char) &&
|
||||
css`
|
||||
color: #690;
|
||||
`}
|
||||
${(leaf.function || leaf.class - name) &&
|
||||
css`
|
||||
color: #dd4a68;
|
||||
`}
|
||||
`}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: '<h1>Hi!</h1>',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
// modifications and additions to prism library
|
||||
|
||||
Prism.languages.python = Prism.languages.extend('python', {})
|
||||
Prism.languages.insertBefore('python', 'prolog', {
|
||||
comment: { pattern: /##[^\n]*/, alias: 'comment' },
|
||||
})
|
||||
Prism.languages.javascript = Prism.languages.extend('javascript', {})
|
||||
Prism.languages.insertBefore('javascript', 'prolog', {
|
||||
comment: { pattern: /\/\/[^\n]*/, alias: 'comment' },
|
||||
})
|
||||
Prism.languages.html = Prism.languages.extend('html', {})
|
||||
Prism.languages.insertBefore('html', 'prolog', {
|
||||
comment: { pattern: /<!--[^\n]*-->/, alias: 'comment' },
|
||||
})
|
||||
Prism.languages.markdown = Prism.languages.extend('markup', {})
|
||||
Prism.languages.insertBefore('markdown', 'prolog', {
|
||||
blockquote: { pattern: /^>(?:[\t ]*>)*/m, alias: 'punctuation' },
|
||||
code: [
|
||||
{ pattern: /^(?: {4}|\t).+/m, alias: 'keyword' },
|
||||
{ pattern: /``.+?``|`[^`\n]+`/, alias: 'keyword' },
|
||||
],
|
||||
title: [
|
||||
{
|
||||
pattern: /\w+.*(?:\r?\n|\r)(?:==+|--+)/,
|
||||
alias: 'important',
|
||||
inside: { punctuation: /==+$|--+$/ },
|
||||
},
|
||||
{
|
||||
pattern: /(^\s*)#+.+/m,
|
||||
lookbehind: !0,
|
||||
alias: 'important',
|
||||
inside: { punctuation: /^#+|#+$/ },
|
||||
},
|
||||
],
|
||||
hr: {
|
||||
pattern: /(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,
|
||||
lookbehind: !0,
|
||||
alias: 'punctuation',
|
||||
},
|
||||
list: {
|
||||
pattern: /(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,
|
||||
lookbehind: !0,
|
||||
alias: 'punctuation',
|
||||
},
|
||||
'url-reference': {
|
||||
pattern: /!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,
|
||||
inside: {
|
||||
variable: { pattern: /^(!?\[)[^\]]+/, lookbehind: !0 },
|
||||
string: /(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,
|
||||
punctuation: /^[\[\]!:]|[<>]/,
|
||||
},
|
||||
alias: 'url',
|
||||
},
|
||||
bold: {
|
||||
pattern: /(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,
|
||||
lookbehind: !0,
|
||||
inside: { punctuation: /^\*\*|^__|\*\*$|__$/ },
|
||||
},
|
||||
italic: {
|
||||
pattern: /(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,
|
||||
lookbehind: !0,
|
||||
inside: { punctuation: /^[*_]|[*_]$/ },
|
||||
},
|
||||
url: {
|
||||
pattern: /!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,
|
||||
inside: {
|
||||
variable: { pattern: /(!?\[)[^\]]+(?=\]$)/, lookbehind: !0 },
|
||||
string: { pattern: /"(?:\\.|[^"\\])*"(?=\)$)/ },
|
||||
},
|
||||
},
|
||||
})
|
||||
Prism.languages.markdown.bold.inside.url = Prism.util.clone(
|
||||
Prism.languages.markdown.url
|
||||
)
|
||||
Prism.languages.markdown.italic.inside.url = Prism.util.clone(
|
||||
Prism.languages.markdown.url
|
||||
)
|
||||
Prism.languages.markdown.bold.inside.italic = Prism.util.clone(
|
||||
Prism.languages.markdown.italic
|
||||
)
|
||||
Prism.languages.markdown.italic.inside.bold = Prism.util.clone(Prism.languages.markdown.bold); // prettier-ignore
|
||||
|
||||
export default CodeHighlightingExample
|
@@ -24,6 +24,7 @@ import PlainText from '../../examples/plaintext'
|
||||
import ReadOnly from '../../examples/read-only'
|
||||
import RichText from '../../examples/richtext'
|
||||
import SearchHighlighting from '../../examples/search-highlighting'
|
||||
import CodeHighlighting from '../../examples/code-highlighting'
|
||||
import Tables from '../../examples/tables'
|
||||
|
||||
const EXAMPLES = [
|
||||
@@ -43,6 +44,7 @@ const EXAMPLES = [
|
||||
['Read-only', ReadOnly, 'read-only'],
|
||||
['Rich Text', RichText, 'richtext'],
|
||||
['Search Highlighting', SearchHighlighting, 'search-highlighting'],
|
||||
['Code Highlighting', CodeHighlighting, 'code-highlighting'],
|
||||
['Tables', Tables, 'tables'],
|
||||
]
|
||||
|
||||
|
Reference in New Issue
Block a user