diff --git a/README.md b/README.md index b9ddbb39..418a61f3 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,7 @@ Vivify brings your (Markdown) files to life in the browser! support](#editor-support)) - Vivify server starts lazily and automatically shuts down when no more viewers are connected -- customize KaTeX to your needs by providing available [KaTeX - options](#KaTeX-options) +- various [config options](#config) If you need any additional features, feel free to [open an issue](https://github.com/jannis-baum/vivify/issues/new/choose) or @@ -31,19 +30,40 @@ issue](https://github.com/jannis-baum/vivify/issues/new/choose) or - syntax highlighting for code - graphviz/dot graphs -### KaTeX options - -Customize KaTeX to your needs by providing an optional -`~/.vivify/katex_config.json` config file with [available KaTeX -options](https://katex.org/docs/options.html). For example: -``` -{ - "errorColor": "#cc0000", - "macros": { - "\\RR": "\\mathbb{R}" - } -} -``` +### Config + +Vivify will look for a config file at `~/.vivify/config.json` and +`~/.vivify.json`. This file should contain a JSON object that can have the +following optional keys: + +- **`"styles"`**\ + a path to a custom style sheet, see [the default + styles](./static/) for examples +- **`"port"`**\ + the port Vivify's server should run on; this will be overwritten by + the environment variable `VIV_PORT` (default is 31622) +- **`"timeout"`**\ + how long the server should wait in ms before shutting down after + the last client disconnected; this will be overwritten by the environment + variable `VIV_TIMEOUT` (default is 10000) +- **`"openCmd"`**\ + the command `viv` uses to open your browser at a given URL; this + will be overwritten by the environment variable `VIV_OPEN` (default will try + `open` and fall back to `xdg-open`) +- **`"katexOptions"`**\ + [available KaTeX options](https://katex.org/docs/options.html), such as + ```json + { + "errorColor": "#cc0000", + "macros": { + "\\RR": "\\mathbb{R}" + } + } + ``` +- **`"pageTitle"`**\ + JavaScript code that will be evaluated to determine the + viewer's page title based on the variable `path` for the given file (default + is `join(basename(dirname(path)), basename(path))`, e.g. `my_dir/my_file`) ## Usage @@ -76,7 +96,7 @@ I have been using [iamcco/markdown-preview.nvim](https://github.com/iamcco/markdown-preview.nvim) for the longest time and started this project because -1. I wanted a Markdown viewer that works without Vim and +1. I wanted a Markdown viewer that works with and without Vim and 2. I wanted a Markdown viewer that supports file links like in GitHub. Looking at diff --git a/src/parser/config.ts b/src/parser/config.ts new file mode 100644 index 00000000..f8989cfc --- /dev/null +++ b/src/parser/config.ts @@ -0,0 +1,32 @@ +import fs from 'fs'; +import { homedir } from 'os'; +import path from 'path'; + +type Config = { + styles?: string; + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + katexOptions?: any; + pageTitle?: string; +}; +let config: Config = {}; + +const configPaths = [ + path.join(homedir(), '.vivify', 'config.json'), + path.join(homedir(), '.vivify.json'), +]; + +for (const cp of configPaths) { + if (!fs.existsSync(cp)) continue; + try { + config = JSON.parse(fs.readFileSync(cp, 'utf8')); + break; + } catch {} +} + +if (config.styles && config.styles.length > 0) { + const stylePath = + config.styles[0] === '~' ? path.join(homedir(), config.styles.slice(1)) : config.styles; + config.styles = fs.existsSync(stylePath) ? fs.readFileSync(stylePath, 'utf8') : ''; +} + +export default config; diff --git a/src/parser/parser.ts b/src/parser/parser.ts index a36e9a43..adfbefa1 100644 --- a/src/parser/parser.ts +++ b/src/parser/parser.ts @@ -1,16 +1,10 @@ import { homedir } from 'os'; -import fs from 'fs'; import MarkdownIt from 'markdown-it'; import anchor from 'markdown-it-anchor'; import highlight from './highlight'; import graphviz from './dot'; - -const katexConfigPath = `${homedir()}/.vivify/katex_config.json`; -let katexConfig = {}; -if (fs.existsSync(katexConfigPath)) { - katexConfig = JSON.parse(fs.readFileSync(katexConfigPath, 'utf8')); -} +import config from './config'; const mdit = new MarkdownIt({ html: true, @@ -27,9 +21,9 @@ mdit.use(require('markdown-it-emoji')); mdit.use(require('markdown-it-task-lists')); mdit.use(require('markdown-it-inject-linenumbers')); mdit.use(require('markdown-it-texmath'), { - engine: require('katex'), - delimiters: 'dollars', - katexOptions: katexConfig + engine: require('katex'), + delimiters: 'dollars', + katexOptions: config.katexOptions, }); /* eslint-enable @typescript-eslint/no-var-requires */ mdit.use(graphviz); diff --git a/src/routes/viewer.ts b/src/routes/viewer.ts index e515a981..9b181266 100644 --- a/src/routes/viewer.ts +++ b/src/routes/viewer.ts @@ -6,6 +6,7 @@ import { Request, Response, Router } from 'express'; import { messageClientsAt } from '../app'; import parse, { pathHeading } from '../parser/parser'; +import config from '../parser/config'; export const router = Router(); @@ -14,6 +15,11 @@ const liveContent = new Map(); const getMimeFromPath = (path: string) => execSync(`file --mime-type -b '${path}'`).toString().trim(); +const pageTitle = (path: string) => { + if (config.pageTitle) return eval(`const path = "${path}"; ${config.pageTitle}`); + else return join(basename(dirname(path)), basename(path)); +}; + router.get(/.*/, async (req: Request, res: Response) => { const path = res.locals.filepath; @@ -46,10 +52,13 @@ router.get(/.*/, async (req: Request, res: Response) => { - ${join(basename(dirname(path)), basename(path))} + ${pageTitle(path)} +
diff --git a/viv b/viv index 4f518cb9..f4fb7b84 100755 --- a/viv +++ b/viv @@ -16,12 +16,23 @@ if ! [ -f "$1" ]; then fi FILE=`realpath "$1"` +if which jq 1>/dev/null 2>/dev/null; then + test -f ~/.vivify.json && VIV_CONFIG=~/.vivify.json + test -f ~/.vivify/config.json && VIV_CONFIG=~/.vivify/config.json + + if [ -n "$VIV_CONFIG" ]; then + [ -z "$VIV_PORT" ] && export VIV_PORT="`jq -r '.port' "$VIV_CONFIG" | sed 's/^null$//'`" + [ -z "$VIV_TIMEOUT" ] && export VIV_TIMEOUT="`jq -r '.timeout' "$VIV_CONFIG" | sed 's/^null$//'`" + [ -z "$VIV_OPEN" ] && export VIV_OPEN="`jq -r '.openCmd' "$VIV_CONFIG" | sed 's/^null$//'`" + fi +fi + if [ -z "$VIV_OPEN" ]; then which open 1>/dev/null 2>/dev/null && VIV_OPEN="open" which xdg-open 1>/dev/null 2>/dev/null && VIV_OPEN="xdg-open" if [ -z "$VIV_OPEN" ]; then - echo 'Please specify an "open" command in $VIV_OPEN' + echo 'Please specify an "open" command in ~/.vivify/config.json, ~/.vivify.json, or $VIV_OPEN' exit 1 fi fi