|
@@ -1,8 +1,23 @@
|
|
|
import { EditorState } from '@codemirror/state'
|
|
import { EditorState } from '@codemirror/state'
|
|
|
import { SyntaxNode } from '@lezer/common'
|
|
import { SyntaxNode } from '@lezer/common'
|
|
|
-import { isUnknownCommandWithName } from '../../../utils/tree-query'
|
|
|
|
|
import { LineBreakCtrlSym } from '../../../lezer-latex/latex.terms.mjs'
|
|
import { LineBreakCtrlSym } from '../../../lezer-latex/latex.terms.mjs'
|
|
|
|
|
|
|
|
|
|
+const isUnknownCommandWithName = (
|
|
|
|
|
+ node: SyntaxNode,
|
|
|
|
|
+ command: string,
|
|
|
|
|
+ getText: (from: number, to: number) => string
|
|
|
|
|
+): boolean => {
|
|
|
|
|
+ if (!node.type.is('UnknownCommand')) {
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ const commandNameNode = node.getChild('CtrlSeq')
|
|
|
|
|
+ if (!commandNameNode) {
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ const commandName = getText(commandNameNode.from, commandNameNode.to)
|
|
|
|
|
+ return commandName === command
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Does a small amount of typesetting of LaTeX content into a DOM element.
|
|
* Does a small amount of typesetting of LaTeX content into a DOM element.
|
|
|
* Does **not** typeset math, you **must manually** invoke MathJax after this
|
|
* Does **not** typeset math, you **must manually** invoke MathJax after this
|
|
@@ -14,8 +29,14 @@ import { LineBreakCtrlSym } from '../../../lezer-latex/latex.terms.mjs'
|
|
|
export function typesetNodeIntoElement(
|
|
export function typesetNodeIntoElement(
|
|
|
node: SyntaxNode,
|
|
node: SyntaxNode,
|
|
|
element: HTMLElement,
|
|
element: HTMLElement,
|
|
|
- state: EditorState
|
|
|
|
|
|
|
+ state: EditorState | ((from: number, to: number) => string)
|
|
|
) {
|
|
) {
|
|
|
|
|
+ let getText: (from: number, to: number) => string
|
|
|
|
|
+ if (typeof state === 'function') {
|
|
|
|
|
+ getText = state
|
|
|
|
|
+ } else {
|
|
|
|
|
+ getText = state!.sliceDoc.bind(state!)
|
|
|
|
|
+ }
|
|
|
// If we're a TextArgument node, we should skip the braces
|
|
// If we're a TextArgument node, we should skip the braces
|
|
|
const argument = node.getChild('LongArg')
|
|
const argument = node.getChild('LongArg')
|
|
|
if (argument) {
|
|
if (argument) {
|
|
@@ -34,39 +55,39 @@ export function typesetNodeIntoElement(
|
|
|
const childNode = childNodeRef.node
|
|
const childNode = childNodeRef.node
|
|
|
if (from < childNode.from) {
|
|
if (from < childNode.from) {
|
|
|
ancestor().append(
|
|
ancestor().append(
|
|
|
- document.createTextNode(state.sliceDoc(from, childNode.from))
|
|
|
|
|
|
|
+ document.createTextNode(getText(from, childNode.from))
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
from = childNode.from
|
|
from = childNode.from
|
|
|
}
|
|
}
|
|
|
- if (isUnknownCommandWithName(childNode, '\\textit', state)) {
|
|
|
|
|
|
|
+ if (isUnknownCommandWithName(childNode, '\\textit', getText)) {
|
|
|
pushAncestor(document.createElement('i'))
|
|
pushAncestor(document.createElement('i'))
|
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
|
- } else if (isUnknownCommandWithName(childNode, '\\textbf', state)) {
|
|
|
|
|
|
|
+ } else if (isUnknownCommandWithName(childNode, '\\textbf', getText)) {
|
|
|
pushAncestor(document.createElement('b'))
|
|
pushAncestor(document.createElement('b'))
|
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
|
- } else if (isUnknownCommandWithName(childNode, '\\emph', state)) {
|
|
|
|
|
|
|
+ } else if (isUnknownCommandWithName(childNode, '\\emph', getText)) {
|
|
|
pushAncestor(document.createElement('em'))
|
|
pushAncestor(document.createElement('em'))
|
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
|
- } else if (isUnknownCommandWithName(childNode, '\\texttt', state)) {
|
|
|
|
|
|
|
+ } else if (isUnknownCommandWithName(childNode, '\\texttt', getText)) {
|
|
|
const spanElement = document.createElement('span')
|
|
const spanElement = document.createElement('span')
|
|
|
spanElement.classList.add('ol-cm-command-texttt')
|
|
spanElement.classList.add('ol-cm-command-texttt')
|
|
|
pushAncestor(spanElement)
|
|
pushAncestor(spanElement)
|
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
|
- } else if (isUnknownCommandWithName(childNode, '\\and', state)) {
|
|
|
|
|
|
|
+ } else if (isUnknownCommandWithName(childNode, '\\and', getText)) {
|
|
|
const spanElement = document.createElement('span')
|
|
const spanElement = document.createElement('span')
|
|
|
spanElement.classList.add('ol-cm-command-and')
|
|
spanElement.classList.add('ol-cm-command-and')
|
|
|
pushAncestor(spanElement)
|
|
pushAncestor(spanElement)
|
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
const textArgument = childNode.getChild('TextArgument')
|
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
|
|
|
} else if (
|
|
} else if (
|
|
|
- isUnknownCommandWithName(childNode, '\\corref', state) ||
|
|
|
|
|
- isUnknownCommandWithName(childNode, '\\fnref', state) ||
|
|
|
|
|
- isUnknownCommandWithName(childNode, '\\thanks', state)
|
|
|
|
|
|
|
+ isUnknownCommandWithName(childNode, '\\corref', getText) ||
|
|
|
|
|
+ isUnknownCommandWithName(childNode, '\\fnref', getText) ||
|
|
|
|
|
+ isUnknownCommandWithName(childNode, '\\thanks', getText)
|
|
|
) {
|
|
) {
|
|
|
// ignoring these commands
|
|
// ignoring these commands
|
|
|
from = childNode.to
|
|
from = childNode.to
|
|
@@ -79,11 +100,11 @@ export function typesetNodeIntoElement(
|
|
|
function leave(childNodeRef) {
|
|
function leave(childNodeRef) {
|
|
|
const childNode = childNodeRef.node
|
|
const childNode = childNodeRef.node
|
|
|
if (
|
|
if (
|
|
|
- isUnknownCommandWithName(childNode, '\\and', state) ||
|
|
|
|
|
- isUnknownCommandWithName(childNode, '\\textit', state) ||
|
|
|
|
|
- isUnknownCommandWithName(childNode, '\\textbf', state) ||
|
|
|
|
|
- isUnknownCommandWithName(childNode, '\\emph', state) ||
|
|
|
|
|
- isUnknownCommandWithName(childNode, '\\texttt', state)
|
|
|
|
|
|
|
+ isUnknownCommandWithName(childNode, '\\and', getText) ||
|
|
|
|
|
+ isUnknownCommandWithName(childNode, '\\textit', getText) ||
|
|
|
|
|
+ isUnknownCommandWithName(childNode, '\\textbf', getText) ||
|
|
|
|
|
+ isUnknownCommandWithName(childNode, '\\emph', getText) ||
|
|
|
|
|
+ isUnknownCommandWithName(childNode, '\\texttt', getText)
|
|
|
) {
|
|
) {
|
|
|
const typeSetElement = popAncestor()
|
|
const typeSetElement = popAncestor()
|
|
|
ancestor().appendChild(typeSetElement)
|
|
ancestor().appendChild(typeSetElement)
|
|
@@ -96,7 +117,7 @@ export function typesetNodeIntoElement(
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
if (from < node.to) {
|
|
if (from < node.to) {
|
|
|
- ancestor().append(document.createTextNode(state.sliceDoc(from, node.to)))
|
|
|
|
|
|
|
+ ancestor().append(document.createTextNode(getText(from, node.to)))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return element
|
|
return element
|