mirror of
https://github.com/explosion/spaCy.git
synced 2025-01-12 10:16:27 +03:00
Fix Juniper component
This commit is contained in:
parent
0b50883a96
commit
2a5d9a0d01
874
website/package-lock.json
generated
874
website/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -12,6 +12,9 @@
|
||||||
"prettier": "prettier . --write"
|
"prettier": "prettier . --write"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/lang-python": "^6.1.0",
|
||||||
|
"@jupyterlab/services": "^3.2.1",
|
||||||
|
"@lezer/highlight": "^1.1.3",
|
||||||
"@mapbox/rehype-prism": "^0.8.0",
|
"@mapbox/rehype-prism": "^0.8.0",
|
||||||
"@mdx-js/loader": "^2.1.5",
|
"@mdx-js/loader": "^2.1.5",
|
||||||
"@mdx-js/react": "^2.1.5",
|
"@mdx-js/react": "^2.1.5",
|
||||||
|
@ -20,6 +23,8 @@
|
||||||
"@types/node": "18.11.9",
|
"@types/node": "18.11.9",
|
||||||
"@types/react": "18.0.25",
|
"@types/react": "18.0.25",
|
||||||
"@types/react-dom": "18.0.8",
|
"@types/react-dom": "18.0.8",
|
||||||
|
"@uiw/codemirror-themes": "^4.19.3",
|
||||||
|
"@uiw/react-codemirror": "^4.19.3",
|
||||||
"acorn": "^8.8.1",
|
"acorn": "^8.8.1",
|
||||||
"browser-monads": "^1.0.0",
|
"browser-monads": "^1.0.0",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
|
@ -32,6 +37,7 @@
|
||||||
"next-mdx-remote": "^4.2.0",
|
"next-mdx-remote": "^4.2.0",
|
||||||
"next-pwa": "^5.6.0",
|
"next-pwa": "^5.6.0",
|
||||||
"next-sitemap": "^3.1.32",
|
"next-sitemap": "^3.1.32",
|
||||||
|
"node-fetch": "^2.6.7",
|
||||||
"parse-numeric-range": "^1.3.0",
|
"parse-numeric-range": "^1.3.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"prismjs": "^1.29.0",
|
"prismjs": "^1.29.0",
|
||||||
|
@ -48,7 +54,8 @@
|
||||||
"remark-unwrap-images": "^3.0.1",
|
"remark-unwrap-images": "^3.0.1",
|
||||||
"sass": "^1.56.1",
|
"sass": "^1.56.1",
|
||||||
"typescript": "4.8.4",
|
"typescript": "4.8.4",
|
||||||
"unist-util-visit": "^4.1.1"
|
"unist-util-visit": "^4.1.1",
|
||||||
|
"ws": "^8.11.0"
|
||||||
},
|
},
|
||||||
"engine": 18
|
"engine": 18
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import CUSTOM_TYPES from '../../meta/type-annotations.json'
|
||||||
import { isString, htmlToReact } from './util'
|
import { isString, htmlToReact } from './util'
|
||||||
import Link, { OptionalLink } from './link'
|
import Link, { OptionalLink } from './link'
|
||||||
import GitHubCode from './github'
|
import GitHubCode from './github'
|
||||||
|
import Juniper from './juniper'
|
||||||
import classes from '../styles/code.module.sass'
|
import classes from '../styles/code.module.sass'
|
||||||
import siteMetadata from '../../meta/site.json'
|
import siteMetadata from '../../meta/site.json'
|
||||||
import { binderBranch } from '../../meta/dynamicMeta.mjs'
|
import { binderBranch } from '../../meta/dynamicMeta.mjs'
|
||||||
|
@ -305,8 +306,6 @@ export const CodeHighlighted = ({ children, highlight, lang }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Code extends React.Component {
|
export class Code extends React.Component {
|
||||||
state = { Juniper: null }
|
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
lang: 'none',
|
lang: 'none',
|
||||||
executable: null,
|
executable: null,
|
||||||
|
@ -323,20 +322,6 @@ export class Code extends React.Component {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
}
|
}
|
||||||
|
|
||||||
updateJuniper() {
|
|
||||||
if (this.state.Juniper == null && window.Juniper !== null) {
|
|
||||||
this.setState({ Juniper: window.Juniper })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.updateJuniper()
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
this.updateJuniper()
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { lang, title, executable, github, wrap, highlight, className, children } = this.props
|
const { lang, title, executable, github, wrap, highlight, className, children } = this.props
|
||||||
const codeClassNames = classNames(classes['code'], className, `language-${lang}`, {
|
const codeClassNames = classNames(classes['code'], className, `language-${lang}`, {
|
||||||
|
@ -344,14 +329,13 @@ export class Code extends React.Component {
|
||||||
[classes['cli']]: lang === 'cli',
|
[classes['cli']]: lang === 'cli',
|
||||||
})
|
})
|
||||||
const ghClassNames = classNames(codeClassNames, classes['max-height'])
|
const ghClassNames = classNames(codeClassNames, classes['max-height'])
|
||||||
const { Juniper } = this.state
|
|
||||||
|
|
||||||
if (github) {
|
if (github) {
|
||||||
return <GitHubCode url={github} className={ghClassNames} lang={lang} />
|
return <GitHubCode url={github} className={ghClassNames} lang={lang} />
|
||||||
}
|
}
|
||||||
if (!!executable && Juniper) {
|
if (!!executable) {
|
||||||
return (
|
return (
|
||||||
<JuniperWrapper Juniper={Juniper} title={title} lang={lang}>
|
<JuniperWrapper title={title} lang={lang}>
|
||||||
{children}
|
{children}
|
||||||
</JuniperWrapper>
|
</JuniperWrapper>
|
||||||
)
|
)
|
||||||
|
@ -370,7 +354,7 @@ export class Code extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const JuniperWrapper = ({ Juniper, title, lang, children }) => {
|
const JuniperWrapper = ({ title, lang, children }) => {
|
||||||
const { binderUrl, binderVersion } = siteMetadata
|
const { binderUrl, binderVersion } = siteMetadata
|
||||||
const juniperTitle = title || 'Editable Code'
|
const juniperTitle = title || 'Editable Code'
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,37 +1,44 @@
|
||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import CodeMirror from 'codemirror'
|
import CodeMirror from '@uiw/react-codemirror'
|
||||||
import python from 'codemirror/mode/python/python' // eslint-disable-line no-unused-vars
|
import { createTheme } from '@uiw/codemirror-themes'
|
||||||
import { Widget } from '@phosphor/widgets'
|
import { tags as t } from '@lezer/highlight'
|
||||||
|
import { python } from '@codemirror/lang-python'
|
||||||
import { Kernel, ServerConnection } from '@jupyterlab/services'
|
import { Kernel, ServerConnection } from '@jupyterlab/services'
|
||||||
import { OutputArea, OutputAreaModel } from '@jupyterlab/outputarea'
|
|
||||||
import { RenderMimeRegistry, standardRendererFactories } from '@jupyterlab/rendermime'
|
|
||||||
import { window } from 'browser-monads'
|
import { window } from 'browser-monads'
|
||||||
|
import classes from '../styles/code.module.sass'
|
||||||
|
|
||||||
|
const spacyTheme = createTheme({
|
||||||
|
theme: 'dark',
|
||||||
|
settings: {
|
||||||
|
background: 'var(--color-front)',
|
||||||
|
foreground: 'var(--color-subtle)',
|
||||||
|
caret: 'var(--color-theme-dark)',
|
||||||
|
selection: 'var(--color-theme)',
|
||||||
|
selectionMatch: 'var(--color-theme)',
|
||||||
|
gutterBackground: 'var(--color-front)',
|
||||||
|
gutterForeground: 'var(--color-subtle)',
|
||||||
|
fontFamily: 'var(--font-code)',
|
||||||
|
},
|
||||||
|
styles: [
|
||||||
|
{ tag: t.comment, color: 'var(--syntax-comment)' },
|
||||||
|
{ tag: t.variableName, color: 'var(--color-subtle)' },
|
||||||
|
{ tag: [t.string, t.special(t.brace)], color: '#fff' },
|
||||||
|
{ tag: t.number, color: 'var(--syntax-number)' },
|
||||||
|
{ tag: t.string, color: 'var(--syntax-selector)' },
|
||||||
|
{ tag: t.bool, color: 'var(--syntax-keyword)' },
|
||||||
|
{ tag: t.keyword, color: 'var(--syntax-keyword)' },
|
||||||
|
{ tag: t.operator, color: 'var(--syntax-operator)' },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
export default class Juniper extends React.Component {
|
export default class Juniper extends React.Component {
|
||||||
outputRef = null
|
state = {
|
||||||
inputRef = null
|
kernel: null,
|
||||||
state = { kernel: null, renderers: null, fromStorage: null }
|
renderers: null,
|
||||||
|
fromStorage: null,
|
||||||
componentDidMount() {
|
output: null,
|
||||||
const renderers = standardRendererFactories.filter((factory) =>
|
code: this.props.children,
|
||||||
factory.mimeTypes.includes('text/latex') ? window.MathJax : true
|
|
||||||
)
|
|
||||||
|
|
||||||
const outputArea = new OutputArea({
|
|
||||||
model: new OutputAreaModel({ trusted: true }),
|
|
||||||
rendermime: new RenderMimeRegistry({ initialFactories: renderers }),
|
|
||||||
})
|
|
||||||
|
|
||||||
const cm = new CodeMirror(this.inputRef, {
|
|
||||||
value: this.props.children.trim(),
|
|
||||||
mode: this.props.lang,
|
|
||||||
theme: this.props.theme,
|
|
||||||
})
|
|
||||||
const runCode = () => this.execute(outputArea, cm.getValue())
|
|
||||||
cm.setOption('extraKeys', { 'Shift-Enter': runCode })
|
|
||||||
Widget.attach(outputArea, this.outputRef)
|
|
||||||
this.setState({ runCode })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log(logFunction) {
|
log(logFunction) {
|
||||||
|
@ -127,14 +134,25 @@ export default class Juniper extends React.Component {
|
||||||
* @param {OutputArea} outputArea - The cell's output area.
|
* @param {OutputArea} outputArea - The cell's output area.
|
||||||
* @param {string} code - The code to execute.
|
* @param {string} code - The code to execute.
|
||||||
*/
|
*/
|
||||||
renderResponse(outputArea, code) {
|
async renderResponse(kernel) {
|
||||||
outputArea.future = this.state.kernel.requestExecute({ code })
|
if (this.state.code === null || this.state.code === '') {
|
||||||
outputArea.model.add({
|
this.state.output = 'No code entered'
|
||||||
output_type: 'stream',
|
return
|
||||||
name: 'loading',
|
}
|
||||||
text: this.props.msgLoading,
|
|
||||||
|
const response = kernel.requestExecute({
|
||||||
|
code: this.state.code,
|
||||||
})
|
})
|
||||||
outputArea.model.clear(true)
|
|
||||||
|
this.state.output = this.props.msgLoading
|
||||||
|
|
||||||
|
response.handleMsg = (message) => {
|
||||||
|
if (message.content && message.content.name === 'stdout') {
|
||||||
|
this.setState({
|
||||||
|
output: message.content.text,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,41 +160,31 @@ export default class Juniper extends React.Component {
|
||||||
* @param {OutputArea} - outputArea - The cell's output area.
|
* @param {OutputArea} - outputArea - The cell's output area.
|
||||||
* @param {string} code - The code to execute.
|
* @param {string} code - The code to execute.
|
||||||
*/
|
*/
|
||||||
execute(outputArea, code) {
|
runCode() {
|
||||||
this.log(() => console.info('executing'))
|
this.log(() => console.info('executing'))
|
||||||
if (this.state.kernel) {
|
if (this.state.kernel) {
|
||||||
if (this.props.isolateCells) {
|
if (this.props.isolateCells) {
|
||||||
this.state.kernel
|
this.state.kernel
|
||||||
.restart()
|
.restart()
|
||||||
.then(() => this.renderResponse(outputArea, code))
|
.then(() => this.renderResponse(this.state.kernel))
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.log(() => console.error('failed', err))
|
this.log(() => console.error('faileder', err))
|
||||||
this.setState({ kernel: null })
|
this.setState({ kernel: null })
|
||||||
outputArea.model.clear()
|
this.setState({ output: this.props.msgError })
|
||||||
outputArea.model.add({
|
|
||||||
output_type: 'stream',
|
|
||||||
name: 'failure',
|
|
||||||
text: this.props.msgError,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.renderResponse(outputArea, code)
|
this.renderResponse(this.state.kernel)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.log(() => console.info('requesting kernel'))
|
this.log(() => console.info('requesting kernel'))
|
||||||
const url = this.props.url.split('//')[1]
|
const url = this.props.url.split('//')[1]
|
||||||
const action = !this.state.fromStorage ? 'Launching' : 'Reconnecting to'
|
const action = !this.state.fromStorage ? 'Launching' : 'Reconnecting to'
|
||||||
outputArea.model.clear()
|
this.setState({ output: `${action} Docker container on ${url}...` })
|
||||||
outputArea.model.add({
|
this.getKernel()
|
||||||
output_type: 'stream',
|
|
||||||
name: 'stdout',
|
|
||||||
text: `${action} Docker container on ${url}...`,
|
|
||||||
})
|
|
||||||
new Promise((resolve, reject) => this.getKernel().then(resolve).catch(reject))
|
|
||||||
.then((kernel) => {
|
.then((kernel) => {
|
||||||
this.setState({ kernel })
|
this.setState({ kernel })
|
||||||
this.renderResponse(outputArea, code)
|
this.renderResponse(kernel)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.log(() => console.error('failed', err))
|
this.log(() => console.error('failed', err))
|
||||||
|
@ -185,33 +193,40 @@ export default class Juniper extends React.Component {
|
||||||
this.setState({ fromStorage: false })
|
this.setState({ fromStorage: false })
|
||||||
window.localStorage.removeItem(this.props.storageKey)
|
window.localStorage.removeItem(this.props.storageKey)
|
||||||
}
|
}
|
||||||
outputArea.model.clear()
|
this.setState({ output: this.props.msgError })
|
||||||
outputArea.model.add({
|
|
||||||
output_type: 'stream',
|
|
||||||
name: 'failure',
|
|
||||||
text: this.props.msgError,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={this.props.classNames.cell}>
|
<div className={this.props.classNames.cell}>
|
||||||
<div
|
{this.state.code && (
|
||||||
className={this.props.classNames.input}
|
<CodeMirror
|
||||||
ref={(x) => {
|
value={this.state.code}
|
||||||
this.inputRef = x
|
extensions={[python()]}
|
||||||
}}
|
theme={spacyTheme}
|
||||||
/>
|
basicSetup={{
|
||||||
<button className={this.props.classNames.button} onClick={this.state.runCode}>
|
lineNumbers: false,
|
||||||
|
foldGutter: false,
|
||||||
|
highlightActiveLine: false,
|
||||||
|
highlightSelectionMatches: false,
|
||||||
|
}}
|
||||||
|
className={classes['juniper-input']}
|
||||||
|
onChange={(value) => {
|
||||||
|
this.setState({ code: value })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<button className={this.props.classNames.button} onClick={() => this.runCode()}>
|
||||||
{this.props.msgButton}
|
{this.props.msgButton}
|
||||||
</button>
|
</button>
|
||||||
<div
|
{this.state.output !== null && (
|
||||||
ref={(x) => {
|
<pre
|
||||||
this.outputRef = x
|
className={`${this.props.classNames.output} ${classes['juniper-input']} ${classes.wrap}`}
|
||||||
}}
|
>
|
||||||
className={this.props.classNames.output}
|
{this.state.output}
|
||||||
/>
|
</pre>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Link from './components/link'
|
import Link from './components/link'
|
||||||
import Section, { Hr } from './components/section'
|
import Section, { Hr } from './components/section'
|
||||||
import { Table, Tr, Th, Tx, Td } from './components/table'
|
import { Table, Tr, Th, Tx, Td } from './components/table'
|
||||||
import { Pre, Code, InlineCode, TypeAnnotation } from './components/code'
|
import CodeBlock, { Pre, Code, InlineCode, TypeAnnotation } from './components/code'
|
||||||
import { Ol, Ul, Li } from './components/list'
|
import { Ol, Ul, Li } from './components/list'
|
||||||
import { H2, H3, H4, H5, P, Abbr, Help, Label } from './components/typography'
|
import { H2, H3, H4, H5, P, Abbr, Help, Label } from './components/typography'
|
||||||
import Accordion from './components/accordion'
|
import Accordion from './components/accordion'
|
||||||
|
@ -76,6 +76,7 @@ export const remarkComponents = {
|
||||||
Tag,
|
Tag,
|
||||||
Accordion,
|
Accordion,
|
||||||
Grid,
|
Grid,
|
||||||
|
CodeBlock,
|
||||||
InlineCode,
|
InlineCode,
|
||||||
Project,
|
Project,
|
||||||
Integration,
|
Integration,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user