10 changed files with 226 additions and 15 deletions
@ -1,6 +1,6 @@ |
|||
[submodule "ucwmac"] |
|||
path = ucwmac |
|||
url = git://git.ucw.cz/ucwmac.git |
|||
[submodule "katex-server"] |
|||
path = katex-server |
|||
[submodule "src/formatitko/katex-server"] |
|||
path = src/formatitko/katex-server |
|||
url = https://gitea.ks.matfyz.cz/KSP/formatitko-katex-server.git |
|||
|
@ -0,0 +1 @@ |
|||
node_modules |
@ -0,0 +1 @@ |
|||
This was made by Standa Lukeš @exyi |
@ -0,0 +1 @@ |
|||
console.log(require('katex').renderToString('\\frac{2a}{b}')) |
@ -0,0 +1,131 @@ |
|||
// KaTeX rendering server
|
|||
// Listens on unix socket, path is provided as first argument
|
|||
// Expects JSON lines, each line is a query with the following schema:
|
|||
// {
|
|||
// formulas: [
|
|||
// {
|
|||
// tex: string,
|
|||
// options?: object
|
|||
// }
|
|||
// ],
|
|||
// options?: object
|
|||
// }
|
|||
|
|||
// see https://katex.org/docs/options.html for list of available options
|
|||
// If options formulas[].options field is used, the global options field is ignored.
|
|||
|
|||
// For each line, returns one JSON line with the following schema:
|
|||
// {
|
|||
// results: [
|
|||
// { html?: string } | { error?: string }
|
|||
// ]
|
|||
// } | { error?: string }
|
|||
|
|||
|
|||
// If one formula is invalid, the error in results is used
|
|||
// If the entire query is invalid (couldn't parse JSON, for example), the outer error field is used
|
|||
|
|||
|
|||
import katex from 'katex' |
|||
import net from 'net' |
|||
import * as readline from 'readline' |
|||
|
|||
const myArgs = process.argv.slice(2) |
|||
|
|||
const unixSocketPath = myArgs[0] |
|||
if (!unixSocketPath) { |
|||
console.error('you must specify socket path') |
|||
process.exit(1) |
|||
} |
|||
|
|||
// This server listens on a Unix socket at /var/run/mysocket
|
|||
var unixServer = net.createServer(handleClient); |
|||
unixServer.listen(unixSocketPath); |
|||
console.log("OK") |
|||
|
|||
function handleExit(signal) { |
|||
// unixServer.emit('close')
|
|||
unixServer.close(function () { |
|||
|
|||
}); |
|||
process.exit(0); // put this into the callback to avoid closing open connections
|
|||
} |
|||
process.on('SIGINT', handleExit); |
|||
process.on('SIGQUIT', handleExit); |
|||
process.on('SIGTERM', handleExit); |
|||
process.on('exit', handleExit); |
|||
|
|||
const defaultOptions = {} |
|||
|
|||
/** |
|||
* @param {net.Socket} socket |
|||
* @returns {Promise<void>} |
|||
* */ |
|||
function socketWrite(socket, data) { |
|||
return new Promise((resolve, reject) => { |
|||
socket.write(data, (err) => { |
|||
if (err) { |
|||
reject(err) |
|||
} else { |
|||
resolve() |
|||
} |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
/** |
|||
* @param {net.Socket} client |
|||
* */ |
|||
async function handleClient(client) { |
|||
const rl = readline.createInterface({ input: client }) |
|||
|
|||
/* Added by GS: A stack of katex's `macros` objects, each group inherits |
|||
* the one from the parent group and can add its own stuff without |
|||
* affecting the parent. |
|||
*/ |
|||
let macroStack = [{}] |
|||
for await (const line of rl) { |
|||
try { |
|||
// The custom commands for pushing and popping the macro stack.
|
|||
if (line === "begingroup") { |
|||
// Copy the current state of macros and push it onto the stack.
|
|||
macroStack.push({...macroStack.slice(-1)[0]}) |
|||
continue |
|||
} else if (line === "endgroup") { |
|||
macroStack.pop() |
|||
continue |
|||
} else if (line === "init") { |
|||
macroStack = [{}] |
|||
continue |
|||
} |
|||
const query = JSON.parse(line) |
|||
const results = [] |
|||
for (const input of query.formulas) { |
|||
const options = input.options ?? query.options ?? defaultOptions |
|||
// Add macros from the macros option
|
|||
if (options.macros) { |
|||
for (const macro of Object.keys(options.macros)) { |
|||
macroStack.slice(-1)[macro] = options.macros[macro] |
|||
} |
|||
} |
|||
options.macros = macroStack.slice(-1)[0] |
|||
// Enforce globalGroup option, katex then saves created macros
|
|||
// into the options.macros object.
|
|||
options.globalGroup = true |
|||
try { |
|||
const html = katex.renderToString(input.tex, options) |
|||
results.push({ html }) |
|||
} catch (e) { |
|||
results.push({ error: String(e) }) |
|||
} |
|||
} |
|||
await socketWrite(client, JSON.stringify({ results }, null, query.debug ? ' ' : undefined)) |
|||
await socketWrite(client, '\n') |
|||
} catch (e) { |
|||
console.error(e) |
|||
await socketWrite(client, JSON.stringify({ error: String(e) })) |
|||
await socketWrite(client, '\n') |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,42 @@ |
|||
{ |
|||
"name": "formatitko-katex-server", |
|||
"version": "1.0.0", |
|||
"lockfileVersion": 3, |
|||
"requires": true, |
|||
"packages": { |
|||
"": { |
|||
"name": "formatitko-katex-server", |
|||
"version": "1.0.0", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"katex": "^0.16.3" |
|||
}, |
|||
"bin": { |
|||
"formatitko-katex-server": "index.mjs" |
|||
} |
|||
}, |
|||
"node_modules/commander": { |
|||
"version": "8.3.0", |
|||
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", |
|||
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", |
|||
"engines": { |
|||
"node": ">= 12" |
|||
} |
|||
}, |
|||
"node_modules/katex": { |
|||
"version": "0.16.3", |
|||
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.3.tgz", |
|||
"integrity": "sha512-3EykQddareoRmbtNiNEDgl3IGjryyrp2eg/25fHDEnlHymIDi33bptkMv6K4EOC2LZCybLW/ZkEo6Le+EM9pmA==", |
|||
"funding": [ |
|||
"https://opencollective.com/katex", |
|||
"https://github.com/sponsors/katex" |
|||
], |
|||
"dependencies": { |
|||
"commander": "^8.0.0" |
|||
}, |
|||
"bin": { |
|||
"katex": "cli.js" |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
{ |
|||
"name": "formatitko-katex-server", |
|||
"version": "1.0.0", |
|||
"description": "", |
|||
"main": "index.mjs", |
|||
"bin": { |
|||
"formatitko-katex-server":"index.mjs" |
|||
}, |
|||
"scripts": { |
|||
"test": "echo \"Error: no test specified\" && exit 1" |
|||
}, |
|||
"author": "", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"katex": "^0.16.3" |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. |
|||
# yarn lockfile v1 |
|||
|
|||
|
|||
commander@^8.3.0: |
|||
version "8.3.0" |
|||
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" |
|||
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== |
|||
|
|||
katex@^0.16.3: |
|||
version "0.16.9" |
|||
resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.9.tgz#bc62d8f7abfea6e181250f85a56e4ef292dcb1fa" |
|||
integrity sha512-fsSYjWS0EEOwvy81j3vRA8TEAhQhKiqO+FQaKWp0m39qwOzHVBgAUBIXWj1pB+O2W3fIpNa6Y9KSKCVbfPhyAQ== |
|||
dependencies: |
|||
commander "^8.3.0" |
Loading…
Reference in new issue