{"id":13410562,"url":"https://github.com/frabjous/knap","last_synced_at":"2025-04-06T00:10:28.891Z","repository":{"id":37604505,"uuid":"485172392","full_name":"frabjous/knap","owner":"frabjous","description":"Neovim plugin for creating live-updating-as-you-type previews of LaTeX, markdown, and other files in the viewer of your choice.","archived":false,"fork":false,"pushed_at":"2024-06-13T13:00:08.000Z","size":350,"stargazers_count":331,"open_issues_count":9,"forks_count":9,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-07-31T20:43:08.188Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/frabjous.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-25T00:18:36.000Z","updated_at":"2024-07-25T13:15:09.000Z","dependencies_parsed_at":"2024-01-03T03:29:23.590Z","dependency_job_id":"c0d5cebf-0917-4f69-8365-bf5250d481c0","html_url":"https://github.com/frabjous/knap","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frabjous%2Fknap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frabjous%2Fknap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frabjous%2Fknap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frabjous%2Fknap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/frabjous","download_url":"https://codeload.github.com/frabjous/knap/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247415973,"owners_count":20935387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:01:07.694Z","updated_at":"2025-04-06T00:10:28.871Z","avatar_url":"https://github.com/frabjous.png","language":"Lua","funding_links":[],"categories":["Programming Languages Support","Lua"],"sub_categories":["Markdown and LaTeX"],"readme":"\n# KNAP: Kevin's Neovim Auto-Previewer\n\nKNAP is a lua plugin for the [neovim](https://neovim.io/) text editor (version 0.7.0+) that provides a user-configurable interface for launching an “auto-refreshing” or “self-updating” preview of the results of the file being edited in neovim as defined by an arbitrary processing command, and a suitable viewing application of your choice.\n\nIt was designed with markup-language documents like LaTeX or markdown (or even just HTML) in mind. KNAP allows you to use the PDF viewer or browser of your choice to see the results in real time. Here is a sample of its use with a LaTeX file and its PDF output (here viewed in [llpp](https://github.com/moosotc/llpp)):\n\n![](latex-llpp.gif)\n\nMoreover, in principle KNAP could be used for many different purposes, including seeing the results of a data calculation applied to a JSON, XML or CSV file, or the effects of editing a CSS file on a webpage. You just need to configure it to do so.\n\nFor LaTeX it also provides SyncTeX support, and could be extended for similar mechanisms for other formats, if and when they exist.\n\nSimilar tools exist. I created KNAP for myself and my own workflow, but perhaps others will find it useful, so I made it public.\n\nKNAP has mainly been tested on Linux. There have been changes made recently that may provide Windows support, but the default configuration makes use of some programs unavailable on Linux. See [issue #27](https://github.com/frabjous/knap/issues/27) for a set up that may work for Windows users. KNAP presupposes you have enough understanding of command line interfaces to configure it properly, though there are some sample configurations below.\n\nLive-preview of a markdown file, with the Falkon browser:\n\n![](md-falkon.gif)\n\n*Warning*: Unless you use the “[buffer as stdin](#user-content-using-buffer-as-stdin-rather-than-saving)” option, part of the way this works is that your file is constantly saved, with its usual filename. This may be dangerous for some people’s workflow, especially those who don’t make adequate backups. *Take care not to save over important work if you don't have a way to get it back (e.g., a previous git commit).*\n\n## Table of Contents\n\n* [Installation](#user-content-installation)\n* [Invocation and Usage](#user-content-invocation-and-usage)\n* [Configuring Routines](#user-content-configuring-routines)\n* [Settings for SyncTeX or other “Jumps”](#user-content-settings-for-synctex-or-other-jumps)\n* [Delay Setting / Speed Tuning](#user-content-delay-setting--speed-tuning)\n* [Errors During Processing](#user-content-errors-during-processing)\n* [Default Configuration](#user-content-default-configuration)\n* [Setting a Different Root Document](#user-content-setting-a-different-root-document)\n* [Buffer-Specific Settings / XeLaTeX Detection Example](#user-content-buffer-specific-settings--xelatex-detection-example)\n* [Using Buffer As Stdin Rather Than Saving](#user-content-using-buffer-as-stdin-rather-than-saving)\n* [Configuration Hints for PDF Viewers](#user-content-configuration-hints-for-pdf-viewers)\n    - [Sioyek (recommended viewer)](#user-content-sioyek-recommended-viewer)\n    - [llpp](#user-content-llpp)\n    - [MuPDF](#user-content-mupdf)\n    - [QpdfView](#user-content-qpdfview)\n    - [Zathura](#user-content-zathura)\n    - [Okular](#user-content-okular)\n    - [apvlv](#user-content-apvlv)\n    - [Evince (aka GNOME Document Viewer)](#user-content-evince-aka-gnome-document-viewer)\n* [Configuration Hints for HTML Output / Browsers](#user-content-configuration-hints-for-html-output--browsers)\n    - [Falkon](#user-content-falkon-recommended-browser)\n    - [QuteBrowser](#user-content-qutebrowser)\n    - [Firefox, Chrome, Chromium, etc.](#user-content-firefox-chrome-chromium-etc)\n    - [Using a Live Server (works with any browser)](#user-content-using-a-live-server-works-with-any-browser)\n* [Troubleshooting and Workarounds](#user-content-troubleshooting-and-workarounds)\n* [License](#user-content-license)\n\n## Installation\n\n#### Manual Installation\n\nUsing git, simply clone this repo into an appropriate spot in your neovim runtimepath, e.g.:\n\n```sh\n$ mkdir -p ~/.local/share/nvim/site/pack/plugins/start\n$ cd ~/.local/share/nvim/site/pack/plugins/start\n$ git clone --depth 1 https://github.com/frabjous/knap.git\n\n```\n\n#### With a Neovim Package Manager\n\nI believe knap can be installed with most neovim package managers. For example, with [paq](https://github.com/savq/paq-nvim) you can put:\n\n```lua\nrequire \"paq\" {\n    \"savq/paq-nvim\";\n    \"frabjous/knap\";\n}\n```\nDifferent package managers work a little differently, so be sure to check the documentation for yours.\n\n#### Other Requirements\n\nOf course, you will also need whatever programs are needed for processing and viewing your files. For the [default configuration](#user-content-default-configuration), you'll need [Sioyek](https://sioyek.info) for viewing PDF output, [Falkon browser](https://www.falkon.org/) for html output, [pandoc](https://pandoc.org/) for processing markdown files, a TeX distribution such as [TeXlive](https://www.tug.org/texlive/) for LaTeX files, and [rubber](https://gitlab.com/latex-rubber/rubber/) for reporting LaTeX errors. The default settings assume you are using Sioyek 2.0+. On Linux, check your package manager to see if these are available in your distro’s repos. You don’t necessarily need them if you want to use a custom configuration instead.\n\n## Invocation and Usage\n\nNeovim will “lazily” load the plugin only when it is first called with a lua `require` that exposes the functions defined by the plugin. Most likely, you will want to map keys to require and call these functions. There are four functions it makes sense to call directly.\n\nIf you use the traditional `~/.config/nvim/init.vim` start up script, put something like this in it:\n\n```vimscript\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\" KNAP functions \"\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\" F5 processes the document once, and refreshes the view \"\ninoremap \u003csilent\u003e \u003cF5\u003e \u003cC-o\u003e:lua require(\"knap\").process_once()\u003cCR\u003e\nvnoremap \u003csilent\u003e \u003cF5\u003e \u003cC-c\u003e:lua require(\"knap\").process_once()\u003cCR\u003e\nnnoremap \u003csilent\u003e \u003cF5\u003e :lua require(\"knap\").process_once()\u003cCR\u003e\n\n\" F6 closes the viewer application, and allows settings to be reset \"\ninoremap \u003csilent\u003e \u003cF6\u003e \u003cC-o\u003e:lua require(\"knap\").close_viewer()\u003cCR\u003e\nvnoremap \u003csilent\u003e \u003cF6\u003e \u003cC-c\u003e:lua require(\"knap\").close_viewer()\u003cCR\u003e\nnnoremap \u003csilent\u003e \u003cF6\u003e :lua require(\"knap\").close_viewer()\u003cCR\u003e\n\n\" F7 toggles the auto-processing on and off \"\ninoremap \u003csilent\u003e \u003cF7\u003e \u003cC-o\u003e:lua require(\"knap\").toggle_autopreviewing()\u003cCR\u003e\nvnoremap \u003csilent\u003e \u003cF7\u003e \u003cC-c\u003e:lua require(\"knap\").toggle_autopreviewing()\u003cCR\u003e\nnnoremap \u003csilent\u003e \u003cF7\u003e :lua require(\"knap\").toggle_autopreviewing()\u003cCR\u003e\n\n\" F8 invokes a SyncTeX forward search, or similar, where appropriate \"\ninoremap \u003csilent\u003e \u003cF8\u003e \u003cC-o\u003e:lua require(\"knap\").forward_jump()\u003cCR\u003e\nvnoremap \u003csilent\u003e \u003cF8\u003e \u003cC-c\u003e:lua require(\"knap\").forward_jump()\u003cCR\u003e\nnnoremap \u003csilent\u003e \u003cF8\u003e :lua require(\"knap\").forward_jump()\u003cCR\u003e\n```\n\nOr if you use a lua config file such as `~/.config/nvim/init.lua`, you can put:\n\n```lua\n-- set shorter name for keymap function\nlocal kmap = vim.keymap.set\n\n-- F5 processes the document once, and refreshes the view\nkmap({ 'n', 'v', 'i' },'\u003cF5\u003e', function() require(\"knap\").process_once() end)\n\n-- F6 closes the viewer application, and allows settings to be reset\nkmap({ 'n', 'v', 'i' },'\u003cF6\u003e', function() require(\"knap\").close_viewer() end)\n\n-- F7 toggles the auto-processing on and off\nkmap({ 'n', 'v', 'i' },'\u003cF7\u003e', function() require(\"knap\").toggle_autopreviewing() end)\n\n-- F8 invokes a SyncTeX forward search, or similar, where appropriate\nkmap({ 'n', 'v', 'i' },'\u003cF8\u003e', function() require(\"knap\").forward_jump() end)\n```\n\nOf course, feel free to choose other keys in place of \u003ckbd\u003eF5\u003c/kbd\u003e-\u003ckbd\u003eF8\u003c/kbd\u003e.\n\nHere, the important key is \u003ckbd\u003eF7\u003c/kbd\u003e. When first pressed, it will call the processing command (e.g., `pdflatex` or `pandoc`), and then open the viewer application. Then once changes are finished being made, after a very short delay, it will call the processing command again, and then send the command to “refresh” or “update” the preview.\n\nPress it again to turn it off. When off, \u003ckbd\u003eF5\u003c/kbd\u003e would manually process the file once and update the viewer, without this being a repeated cycle. \u003ckbd\u003eF6\u003c/kbd\u003e would not only turn off auto-updating, but close the viewer, which is useful if you wish to change settings and use a different viewer, etc. If configured, \u003ckbd\u003eF8\u003c/kbd\u003e would make the viewer application jump to the place in the output corresponding to the current cursor position in neovim, as with SyncTeX for LaTeX.\n\n## Configuring Routines\n\nUnless you are fully satisfied with the defaults (unlikely), you will need to configure knap. You may use either vimscript or lua for this. You must set one of two [dictionary](https://neovim.io/doc/user/eval.html#Dictionary) variables in neovim before knap is invoked, `g:knap_settings` (global setting; applied to all buffers) or `b:knap_settings` (buffer-specific). For most use cases, `g:knap_settings` is more appropriate. If you use `~/.config/nvim/init.vim`, you might put:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"texoutputext\": \"pdf\",\n    \\ \"textopdf\": \"pdflatex -synctex=1 -halt-on-error -interaction=batchmode %docroot%\",\n    \\ \"textopdfviewerlaunch\": \"mupdf %outputfile%\",\n    \\ \"textopdfviewerrefresh\": \"kill -HUP %pid%\"\n\\ }\n```\n\nIn lua you can assign `vim.b.knap_settings` or `vim.g.knap_settings` to an equivalent table. If you use `init.lua`, you can do:\n\n```lua\nlocal gknapsettings = {\n    texoutputext = \"pdf\",\n    textopdf = \"pdflatex -synctex=1 -halt-on-error -interaction=batchmode %docroot%\",\n    textopdfviewerlaunch = \"mupdf %outputfile%\",\n    textopdfviewerrefresh = \"kill -HUP %pid%\"\n}\nvim.g.knap_settings = gknapsettings\n```\n\nMost of the lines here are of the form `\"setting\": \"value\",`, or, in lua, `setting = \"value\",`. Together these define *routines*. Each routine is targeted at a file extension for a given type of input files; in the above example, the target extension is \"`tex`\", as the routine targets LaTeX (`.tex`) files.\n\nThe first setting (*outputext* or *output extension*) tells us that when `.tex` files are processed, the results are `.pdf` files, or that `.pdf` files are the files that need to be \"previewed\" when editing a `.tex` file. This determines what will be done with your file when knap is activated, depending on its extension. (If you are editing a file without an extension, the neovim `\u0026filetype` setting will be used instead.)\n\nThis also tells the plugin that the *routine* we are defining is “`textopdf`”; the name of this routine is used in the other settings. Each routine has a name of the form `[input-extension]to[output-extension]`.\n\nThe main setting for the routine, which has the same name as the routine, is the command that is used to process the input file. In the example above, `pdflatex` (with some sane options) needs to be called to produce PDFs from LaTeX files. Someone else might prefer to configure it to use `xelatex` or `latexmk` instead; knap lets the user configure things how they wish.\n\nSettings of the form `[routine]viewerlaunch` determine what command is used to initially launch the program used to view the output files. Once launched, the command in the setting of the form `[routine]viewerrefresh` is invoked whenever the input file is re-processed and the output file changes.\n\nWhen invoked, the appropriate substitutions are made for these variables:\n\n```text\n %srcfile%     the filename (full path) of the file being edited\n %docroot%     the base name of the root document that needs to be processed*\n %outputfile%  the base name of the output file**\n %pid%         the process id of the viewer program, after launch\n %line%        the line number of the cursor position in neovim\n %column%      the column number of the cursor position in neovim\n %servername%  the path to the RPC socket for the current neovim instance (v:servername)\n```\n\n\\* In most use cases, the input document is the same as the one being edited, but see [Setting a Different Root Document](#user-content-setting-a-different-root-document) below for discussion of exceptions.\n\n\\*\\* The output file is assumed to be the same as the root document with the output extension replacing the input extension of the routine.\n\nQuotation marks will be wrapped around the filename variables; do not put additional quotation marks around them. If you need to use quotation marks elsewhere in the commands, be sure to escape them as `\\\"` when setting them in your `init.vim`/`init.lua`.\n\nNote the commands are always invoked from within the directory of the root document, which may or may not be the same as the document being edited.\n\nKNAP sets no limitations on what routines are defined for what file extensions, or how many routines are set inside `g:knap_settings`. Use a single dictionary for all such settings. For example, to have a routine to create HTML files from Markdown `.md` files, create the settings “`mdoutputext`”, “`mdtohtml`”, “`mdtohtmlviewerlaunch`” and “`mdtohtmlviewerrefresh`”. See the [defaults](#user-content-default-configuration) for examples.\n\nUse the setting “none” in cases when no command needs to be issued to process a kind of file, or to refresh the viewer. (Some viewer applications are self-refreshing!) You can also define routines where the input extension and output extension are the same, e.g., `htmltohtml`, since nothing needs to be done to an html file to make it view-able in a browser.\n\nNote also that it is harmless to have settings for different routines for the same input extension in your dictionary. E.g., you might have both `textopdf` and `textodvi` settings; the `texoutputext` variable will determine which one is used by default; however, you could do:\n\n`:let b:knap_settings[\"texoutputext\"] = \"dvi\"`\n\nfrom the command line in neovim before invoking knap on a TeX file to use the `textodvi` routine to produce `.dvi` files instead of the default `textopdf` routine.\n\n## Settings for SyncTeX or other “Jumps”\n\nIf the kind of processing tools and viewer software you’re using allow for it, you can create a command that will instruct the viewer to move to the part of the output corresponding to the current location in the source file, or in reverse, to instruct neovim to move to the part of the source corresponding to a portion of the output. This is possible, for example, with SyncTeX for LaTeX files.\n\nFor “forward” (source → output) jumps, you need to define a setting `[routine]forwardjump`; this may use the same variables as the other settings for the routines, and is where `%line%` and `%column%` are most likely to be relevant. See the default setting for `\"textopdfforwardjump\"` as an example below.\n\nFor “reverse” or “inverse” (output → source) jumps, you would in most cases configure the viewer to invoke a headless instance of neovim which will send an appropriate signal to the active instance via RPC and then immediately quit.\n\nThe `knaphelper.lua` file, when required by a lua command executed by a headless instance of neovim, exposes a function to help with this. The function takes the form `relayjump(servername, filename, line, column)`, which will instruct the neovim instance at `servername` to move its cursor to the specified line and column if `filename` is the file being edited (and just echoes a message otherwise). The viewer or some intermediary must be capable of determining the filename, line and column using SyncTeX or something similar. You could call this function with a headless instance of neovim like this:\n\n```sh\nnvim --headless -es --cmd \"lua require('knaphelper').relayjump('%servername%','%{filename}%',%{line}%,%{column}%)\"\n```\n\nIf this command can be configured to be used by the viewer in a viewerlaunch or viewerrefresh action, `%servername%` may be passed as part of the command using the substitution method mentioned above; the values of `%{filename}%`, `%{line}%` and `%{column}%` must be provided by the viewer or a helper script. Note also that if one uses `'all'` for `servername`, it will relay the command to all instances of neovim whose RPC server socket it can find, which may be useful if there is no easy way to configure the viewer launching the headless instance to use a specific server.\n\n## Delay Setting / Speed Tuning\n\nSubsequent re-processing of the input file and refreshing the viewer is triggered by changes to the buffer being edited in neovim. Typically, one wishes to finish what one is typing before seeing the result, so there is a short delay between any given change and the start of the processing, and the delay timer is reset with each buffer change. This means that one must at least briefly pause editing before re-processing will start.\n\nThis delay is configured in milliseconds. Setting a shorter delay will speed up processing and make it more frequent. Setting this value appropriately involves a trade-off: a lower number is faster, but will make use of more computing resources (processor and memory usage, number of disk writes).\n\nThis delay is set to 250 milliseconds (a quarter second) by default. Depending on your hardware and the processing cost of the commands you're using, you may wish to lower or raise this. To do so, include a setting for “delay” in `g:knap_settings`; e.g., for 100 milliseconds, put this in `init.vim`:\n\n```vimscript\nlet g:knap_settings = {\n    \\ ...\n    \\ \"delay\": 100,\n    \\ ...\n}\n```\n\nOr in `init.lua`:\n\n```lua\nlocal gknapsettings = {\n    ...\n    delay = 100,\n    ...\n}\nvim.g.knap_settings = gknapsettings\n```\n\nOr it can be set on an individual basis for a given buffer (before starting the autopreview), in neovim:\n\n`:let b:knap_settings[\"delay\"] = 100`\n\n## Errors During Processing\n\nIf the processing command for the routine finishes with an error (non-zero exit status), an error message will be reported in neovim, and the command to refresh the viewer will not be sent until the command is run again successfully. Typically, the message will include the first line of the stderr stream for the process.\n\nYou can fine-tune this by adding a setting of the form `[routine]shorterror` which calls a command to return useful debugging info if one exists instead. The [default configuration](#user-content-default-configuration) uses `rubber-info` to collect information about the first error in the LaTeX logs when using the `textopdf` routine.\n\nHowever, knap is not primarily designed to provide debugging or error checking capabilities.\n\n## Default Configuration\n\nThe default settings are used only when neither `g:knap_settings` or `b:knap_settings` is set with the key in question when the plugin is invoked.\n\nThey determine only the following routines:\n\n```text\ntextopdf            uses pdflatex for processing and sioyek for viewing/refreshing\nmdtohtml (default)  uses pandoc for processing and falkon for viewing\nmdtopdf             uses pandoc for processing and sioyek for viewing\nhtmltohtml          \"none\" for processing; falkon for viewing\n```\n\nThe precise values are listed below, here using the lua syntax (though the syntax for vimscript is quite close). You are, however, expected and encouraged to create your own, but comparison with the precise default values may be of some use:\n\n```lua\n{\n    htmloutputext = \"html\",\n    htmltohtml = \"none\",\n    htmltohtmlviewerlaunch = \"falkon %outputfile%\",\n    htmltohtmlviewerrefresh = \"none\",\n    mdoutputext = \"html\",\n    mdtohtml = \"pandoc --standalone %docroot% -o %outputfile%\",\n    mdtohtmlviewerlaunch = \"falkon %outputfile%\",\n    mdtohtmlviewerrefresh = \"none\",\n    mdtopdf = \"pandoc %docroot% -o %outputfile%\",\n    mdtopdfviewerlaunch = \"sioyek %outputfile%\",\n    mdtopdfviewerrefresh = \"none\",\n    markdownoutputext = \"html\",\n    markdowntohtml = \"pandoc --standalone %docroot% -o %outputfile%\",\n    markdowntohtmlviewerlaunch = \"falkon %outputfile%\",\n    markdowntohtmlviewerrefresh = \"none\",\n    markdowntopdf = \"pandoc %docroot% -o %outputfile%\",\n    markdowntopdfviewerlaunch = \"sioyek %outputfile%\",\n    markdowntopdfviewerrefresh = \"none\",\n    texoutputext = \"pdf\",\n    textopdf = \"pdflatex -interaction=batchmode -halt-on-error -synctex=1 %docroot%\",\n    textopdfviewerlaunch = \"sioyek --inverse-search 'nvim --headless -es --cmd \\\"lua require('\\\"'\\\"'knaphelper'\\\"'\\\"').relayjump('\\\"'\\\"'%servername%'\\\"'\\\"','\\\"'\\\"'%1'\\\"'\\\"',%2,%3)\\\"' --new-window %outputfile%\",\n    textopdfviewerrefresh = \"none\",\n    textopdfforwardjump = \"sioyek --inverse-search 'nvim --headless -es --cmd \\\"lua require('\\\"'\\\"'knaphelper'\\\"'\\\"').relayjump('\\\"'\\\"'%servername%'\\\"'\\\"','\\\"'\\\"'%1'\\\"'\\\"',%2,%3)\\\"' --reuse-window --forward-search-file %srcfile% --forward-search-line %line% %outputfile%\",\n    textopdfshorterror = \"A=%outputfile% ; LOGFILE=\\\"${A%.pdf}.log\\\" ; rubber-info \\\"$LOGFILE\\\" 2\u003e\u00261 | head -n 1\",\n    delay = 250\n}\n```\n\nWe can see that the commands can look quite complicated. The complexity of the `texttopdf` routine commands for sioyek is explained [below](#user-content-sioyek-recommended-viewer).\n\n## Setting a Different Root Document\n\nSometimes the document that needs to be processed is not actually the one being edited. It might be a supplementary file. This would happen with included packages, or subdocuments inserted in LaTeX via `\\include` or `\\input`. In such cases, the main document is considered the “root document”.\n\nYou can tell knap to process a document different from the one being edited by inserting a comment including the string “root = ” (without the quotes) in the first five lines of the file. The rest of the line is considered the root document’s name. So if editing `chapter1.tex` which is included in `main.tex`, at the top of `chapter1.tex`, you may put:\n\n`% TeX root = main.tex`\n\nThen it is `main.tex` that will be compiled when knap is invoked on `chapter1.tex`, not `chapter1.tex` itself.\n\n(The “TeX” at the beginning is ignored by knap, but is useful for conformity with other editors and plug-ins that use a similar convention.)\n\nThis might be useful for other sorts of tricks as well. For example, you could set a CSS document’s “root” to be an HTML document that uses it, and thereby see the results of editing the CSS in an auto-preview; put:\n\n`/* HTML root = index.html */`\n\nNote that it is the *root* document’s extension that determines the routine used, so for the above CSS example, the routine is simply `htmltohtml`, and no separate `csstohtml` routine is required. The output file is also considered to have the same base name as the root document, not the edited document.\n\nHowever, in such a case, it might be better to use “`touch %outputfile%`” for the main processing command rather than simply “none” if the viewer relies on detecting changes to trigger an auto-refresh. Only the CSS file is being changed, so the touch command is needed to mark the HTML file as changed as well, so the refresh will be triggered.\n\n## Buffer-Specific Settings / XeLaTeX Detection Example\n\nIf you wish to use different settings for *some* but not all files with a given extension, this can be done in your neovim initialization file, by calling a function that places options in the `b:knap_settings` dictionary variable. (Note: use `b:` here rather than `g:` to avoid affecting all buffers in the neovim instance.)\n\nAs an example, here is a snippet you can place in `~/.config/nvim/init.vim` that will detect if a LaTeX file should be processed with `xelatex` rather than `pdflatex`. It does so if \"`xelatex`\" occurs in the first five lines (such as in a comment), or if the `mathspec`, `fontspec` or `unicode-math` package is loaded.\n\n```vimscript\nfunction XeLaTeXCheck()\n    let l:xelatex = 0\n    let l:xelatexcomment = search('xelatex','nw')\n    if (l:xelatexcomment \u003e 0) \u0026\u0026 (l:xelatexcomment \u003c 6)\n        let l:xelatex = 1\n    else\n        if (search('\\\\usepackage{[^}]*mathspec[^}]*}','nw')) ||\n            \\ (search('\\\\usepackage{[^}]*fontspec[^}]*}','nw'))\n            let l:xelatex = 1\n        endif\n    endif\n    if (l:xelatex == 1)\n        if !exists(\"b:knap_settings\")\n            let b:knap_settings = {}\n        endif\n        let b:knap_settings[\"textopdf\"] = \"xelatex -interaction=batchmode -halt-on-error -synctex=1 %docroot%\"\nendfunction\nautocmd BufRead *.tex call XeLaTeXCheck()\n```\n\n(Note with this alone, this check would only be done when the file is loaded, unless you bind the function to another autocommand or key.)\n\nA similar thing could be done in a lua init file to check the first 15 lines like so:\n\n```lua\n_G.xelatexcheck = function()\n    local isxelatex = false\n    local fifteenlines = vim.api.nvim_buf_get_lines(0,0,15,false)\n    for l,line in ipairs(fifteenlines) do\n        if (line:lower():match(\"xelatex\")) or\n           (line:match(\"\\\\usepackage[^}]*mathspec\")) or\n           (line:match(\"\\\\usepackage[^}]*fontspec\")) or\n           (line:match(\"\\\\usepackage[^}]*unicode-math\")) then\n           isxelatex = true\n           break\n       end\n    end\n    if (isxelatex) then\n        local knapsettings = vim.b.knap_settings or {}\n        knapsettings[\"textopdf\"] =\n            'xelatex -interaction=batchmode -halt-on-error -synctex=1 %docroot%'\n        vim.b.knap_settings = knapsettings\n    end\nend\nvim.api.nvim_create_autocmd({'BufRead'}, {pattern = {'*.tex'}, callback = xelatexcheck})\n```\n\nThese are just examples; there are other, possibly better ways of dealing with XeLaTeX detection outside of knap, e.g., by using a processing command that itself does this.\n\n## Using Buffer As Stdin Rather Than Saving\n\nA newly introduced feature allows you to avoid constantly saving over your file. Instead, you may set the routine to send the current contents of the buffer, as it changes, as stdin to the processing command. The file will not be saved each time the routine is called. You are then free to save your file as you normally would in neovim only when you wish to make changes permanent.\n\nTo use this option, add a key for `[routine]bufferasstdin` to the settings dictionary and set it to `v:true` in vimscript, or simply `true` in lua. For a “`textopdf`” routine, you might put:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"textopdf\" : \"pdflatex -jobname \\\"$(basename -s .pdf %outputfile%)\\\" -halt-on-error\",\n    \\ \"textopdfbufferasstdin\" : v:true\n\\ }\n\n```\n\nNotice you will also need to change the processing command for the routine so that it reads from stdin rather than passing it the input filename or document root filename. All the usual flavors of LaTeX (PDFLaTeX, XeLaTeX, LuaLaTeX, etc.) are happy to read from standard in, though as above, you will need to use the `-jobname` option to ensure you get the right output filename. Unfortunately, using this option will cause SyncTeX not to work. (SyncTeX uses the input filename, which is not available to it with this option, which is why it is not used by default.)\n\nFor processing markdown, pandoc is happy to read from stdin as well, but you will need to set its input format with `-f`. E.g., if using lua in your configuration:\n\n```lua\nlocal gknapsettings = {\n    mdtohtml = \"pandoc -f markdown --standalone -o %outputfile%\",\n    mdtohtmlbufferasstdin = true\n}\nvim.g.knap_settings = gknapsettings\n```\n\nYou may include redirections in your processing command if you need finer grained control of what is done with the buffer contents, such as writing to a temporary file.\n\n## Configuration Hints for PDF Viewers\n\nIf you have managed to configure knap for any other open source PDF viewers, please let me know so I can add to this list.\n\nThese are listed roughly in order of how well they work in my experience.\n\nDo not use Adobe Reader. Not just for this, but for anything or any reason.\n\n### Sioyek (recommended viewer)\n\n[sioyek project page](https://sioyek.info/)\n\nSioyek is fast, auto-refreshing PDF viewer with customizable vim-like keybinds and interesting features for viewing research papers and technical works. It supports SyncTeX well, and does not flicker much on reloads. In my experience, it overall provides the best experience with knap, and so is used as the default PDF viewer.\n\nSince it is default, you need not put these settings in your `init.vim` unless you wish to tweak them:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"textopdfviewerlaunch\": \"sioyek --inverse-search 'nvim --headless -es --cmd \\\"lua require('\\\"'\\\"'knaphelper'\\\"'\\\"').relayjump('\\\"'\\\"'%servername%'\\\"'\\\"','\\\"'\\\"'%1'\\\"'\\\"',%2,0)\\\"' --new-window %outputfile%\",\n    \\ \"textopdfviewerrefresh\": \"none\",\n    \\ \"textopdfforwardjump\": \"sioyek --inverse-search 'nvim --headless -es --cmd \\\"lua require('\\\"'\\\"'knaphelper'\\\"'\\\"').relayjump('\\\"'\\\"'%servername%'\\\"'\\\"','\\\"'\\\"'%1'\\\"'\\\"',%2,0)\\\"' --reuse-window --forward-search-file %srcfile% --forward-search-line %line% %outputfile%\"\n}\n```\n\nThese settings directly pass the correct configuration for inverse jumps to Sioyek when it is launched. Getting this right is difficult. Since this uses the regular vim syntax for forming strings, if a command contains a double quotation mark, it must be escaped as `\\\"`. This command for inverse searches must be passed as a single argument, so it must be in its own quotes for the shell to interpret it as such. Moreover the command itself involves quoted arguments for the headless neovim instance, which themselves involve quoted lua strings! Since single quotation marks in shell arguments must be inside double quotation marks, and vice versa, and the double quotation marks must be escaped for lua, one ends up with rather convoluted syntax such as `require('\\\"'\\\"'knaphelper'\\\"'\\\"')` which becomes simply `require('knaphelper')` when all the escaping and shell unquoting is done. (The same complications exist for setting them with lua, as can be seen in the default settings above.)\n\nWith the typical configuration, reverse searches in Sioyek are activated by enabling SyncTeX mode with \u003ckbd\u003eF4\u003c/kbd\u003e and then right clicking a spot in the PDF.\n\n*Note:* If you are using an older version of Sioyek (below version 2.0), you should change the settings to use `--new-instance` and `--reuse-instance` instead of `--new-window` and `--reuse-window`.\n\n### llpp\n\n[llpp github page](https://github.com/moosotc/llpp)\n\nllpp is another great choice; both fast and capable, and does not flicker much on refresh.\n\nTo allow for SyncTeX support, it must be started with the `-remote` option, to listen to commands sent to a named pipe. The suggested knap settings for llpp for the `textopdf` routine below look complicated, because they first check to see if such a pipe exists, and create one if not. The pipe can also be used to send the refresh command.\n\nSuggested settings:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"mdtopdfviewerlaunch\": \"llpp %outputfile%\",\n    \\ \"mdtopdfviewerrefresh\": \"kill -HUP %pid%\",\n    \\ \"markdowntopdfviewerlaunch\": \"llpp %outputfile%\",\n    \\ \"markdowntopdfviewerrefresh\": \"kill -HUP %pid%\",\n    \\ \"textopdfviewerlaunch\": \"PIPE=$XDG_RUNTIME_DIR/llpp-remote.pipe ; ([[ -p $PIPE ]] || mkfifo -m 600 $PIPE) \u0026\u0026 exec llpp -remote $PIPE %outputfile%\",\n    \\ \"textopdfviewerrefresh\": \"(echo reload \u003e $XDG_RUNTIME_DIR/llpp-remote.pipe)\",\n    \\ \"textopdfforwardjump\": \"synctex view -i %line%:%column%:%srcfile% -o %outputfile% -x \\\"echo goto %{page} %{h} %{v} \u003e $XDG_RUNTIME_DIR/llpp-remote.pipe\\\"\"\n\\ }\n```\n\nFor SyncTeX reverse jumps, one cannot set it up to call a headless instance of neovim directly, as it outputs its arguments to its synctex-command in an incompatible way. One must make use of a helper script. One is provided by the plugin in the form of a luajit script called `synctex-inverse.lua` in the `llpp` subdirectory of the git repository. (It is assumed as a neovim user you have a luajit executable installed.) You should either copy this into a directory in your [`$PATH`](https://astrobiomike.github.io/unix/modifying_your_path), or add the llpp directory of the plugin repo to your `$PATH`, or call it using its full path. You can make it executable with `chmod a+x synctex-inverse.lua` if need be.\n\nSet this lua script as your synctex-command in your `llpp.conf` file (typically at `~/.config/llpp.conf`), under “`\u003cdefaults`”. If it is in your `$PATH` and executable you can simply do:\n\n`synctex-command='synctex-inverse.lua'`\n\nIf not you can use the full path and call luajit explicitly:\n\n`synctex-command='luajit /home/\u003cusername\u003e/.local/share/nvim/site/pack/plugins/start/knap/llpp/synctex-inverse.lua'`\n\nSubstitute your actual username for `\u003cusername\u003e` and otherwise adjust the path if you installed knap elsewhere (e.g., substitute `paqs` for `plugins` if you used `paq`).\n\nShift-clicking in llpp will then activate this with the appropriate arguments, and it, in turn, will call SyncTeX and then run a headless instance of neovim to call the relayjump function to move the cursor to the appropriate spot.\n\n### MuPDF\n\n[mupdf project page](https://mupdf.com/)\n\nMuPDF is extremely fast—perhaps the fastest open source PDF viewer there is. It is also flicker-free. Its main disadvantage is that it does not support SyncTeX. Still, it can be used as a viewer with knap.\n\nIt can be refreshed by sending the HUP signal. Here are example settings for a `textopdf` routine:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"mdtopdfviewerlaunch\": \"mupdf %outputfile%\",\n    \\ \"mdtopdfviewerrefresh\": \"kill -HUP %pid%\",\n    \\ \"markdowntopdfviewerlaunch\": \"mupdf %outputfile%\",\n    \\ \"markdowntopdfviewerrefresh\": \"kill -HUP %pid%\",\n    \\ \"textopdfviewerlaunch\": \"mupdf %outputfile%\",\n    \\ \"textopdfviewerrefresh\": \"kill -HUP %pid%\",\n    \\ \"textopdfforwardjump\" : \"false\"\n\\ }\n```\n\nYou might be able to kludge up partial jump-support using something like [xdotool](https://github.com/jordansissel/xdotool), but I'd recommend just using one of the viewers above instead, which are both based on MuPDF.\n\n### QpdfView\n\n[qdpfview project page](https://launchpad.net/qpdfview)\n\nThis is the best of the poppler-based viewers for this purpose, and it has excellent SyncTeX support.\n\nUse the `--unique` option to allow refreshing the current document as opposed to opening a new one. Add the `#src` component for SyncTeX jumping and highlighting.\n\nIf you enable auto-refresh under Edit \u003e Settings \u003e Behavior in qpdfview, you can set the refresh command to “none”.\n\nExample settings in `init.vim` for a `textopdf` routine:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"textopdfviewerlaunch\": \"qpdfview --unique --instance neovim %outputfile%\",\n    \\ \"textopdfviewerrefresh\": \"none\",\n    \\ \"textopdfforwardjump\" : \"qpdfview --unique --instance neovim %outputfile%#src:%srcfile%:%line%:%column%\"\n\\ }\n```\n\nFor SyncTeX inverse jumps, under Edit \u003e Settings \u003e Source editor in qpdfview, you can use:\n\n`nvim --headless -es --cmd \"lua require('knaphelper').relayjump('all','%1',%2,%3)\"`\n\nYou can then invoke it with control-click in qpdfview.\n\nIf you don’t want to use auto-refresh, then use the same command as the launch command for refreshing; you will however probably need to set your window manager to prevent qpdfview from stealing focus while you’re typing. (How to do this and whether it can be done will depend on your window manager.)\n\n### Zathura\n\n[zathura project page](http://pwmt.org/projects/zathura)\n\nZathura is also a fast, auto-refreshing viewer with nice SyncTeX support, and keybindings (neo)vim users might like.\n\nIts main disadvantage is it flickers when reloading far more than Sioyek, mupdf or llpp do.\n\nSuggested settings for `textopdf`:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"textopdfviewerlaunch\": \"zathura --synctex-editor-command 'nvim --headless -es --cmd \\\"lua require('\\\"'\\\"'knaphelper'\\\"'\\\"').relayjump('\\\"'\\\"'%servername%'\\\"'\\\"','\\\"'\\\"'%{input}'\\\"'\\\"',%{line},0)\\\"' %outputfile%\",\n    \\ \"textopdfviewerrefresh\": \"none\",\n    \\ \"textopdfforwardjump\": \"zathura --synctex-forward=%line%:%column%:%srcfile% %outputfile%\"\n\\ }\n```\n\nThe above settings directly pass the correct configuration for inverse jumps to Zathura when it is launched, again using the kind of convoluted syntax discussed for Sioyek [above](#user-content-sioyek-recommended-viewer). Control-click in Zathura to start the jump.\n\n### Okular\n\n[okular project page](https://okular.kde.org/)\n\nThe capabilities and commands for Okular are quite similar to those for qpdfview. To auto-reload, be sure “Reload document on file change” is checked under Settings \u003e Configure Okular \u003e General. Then you can use “none” for the refresh command. Suggested settings for a `textopdf` routine:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"textopdfviewerlaunch\": \"okular --unique %outputfile%\",\n    \\ \"textopdfviewerrefresh\": \"none\",\n    \\ \"textopdfforwardjump\" : \"okular --unique %outputfile%'#src:%line% '%srcfile%\"\n\\ }\n```\n\nTo configure inverse searches, in Okular, go to Settings \u003e Configure Okular \u003e Editor, choose “Custom Text Editor”, and under Command, put:\n\n`nvim --headless -es --cmd \"lua require('knaphelper').relayjump('all','%f',%l,%c)\"`\n\nInverse searches are invoked by shift-clicking in Okular.\n\n### apvlv\n\n[apvlv github page](https://github.com/naihe2010/apvlv)\n\nCreate the file `~/.apvlv` with the line:\n\n`set autoreload = 1`\n\nYou can then use the settings such as these:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"textopdfviewerlaunch\": \"apvlv %outputfile%\",\n    \\ \"texttopdfviewerrefresh\": \"none\",\n    \\ \"textopdfforwardjump\" : \"false\"\n\\ }\n```\n\nThis works decently well for refreshing the view, but there is no SyncTeX support.\n\n### Evince (aka GNOME Document Viewer)\n\n[evince project page](https://wiki.gnome.org/Apps/Evince)\n\nEvince auto-refreshes so again “none” can be used for that, and always uses a single instance. You can also specify a page number, which provides a simple SyncTeX forward search.\n\nSample configuration:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"textopdfviewerlaunch\": \"evince %outputfile%\",\n    \\ \"textopdfviewerrefresh\": \"none\",\n    \\ \"textopdfforwardjump\" : \"synctex view -i %line%:%column%:%srcfile% -o %outputfile% -x 'evince -i %{page+1} %outputfile%'\",\n\\ }\n```\n\nTo get more precise forward searches, or any kind of inverse searches, you’ll have to fiddle with DBus or use a DBus wrapper script such as [this](https://github.com/Vinno97/evince-synctex) or [this](https://github.com/latex-lsp/evince-synctex). If someone comes up with precise instructions for this, let me know, and I will post them here. I have never tried this, as it doesn’t seem worth it given the better alternatives. (The fact that the GNOME developers don't just put an option in evince to set a custom command shows their increasing disregard for the Unix philosophy.)\n\n## Configuration Hints for HTML Output / Browsers\n\nAgain, if you have suggestions for other browsers or approaches, let me know.\n\n### Falkon (recommended browser)\n\n[Falkon project page](https://www.falkon.org/)\n\nThe KDE Falkon browser (formerly qupzilla) is my preferred solution, as it is a modern-standards browser that auto-reloads local pages (those served with the `file://` protocol). Since it reloads for you, you do not need a refresh command. For example, for a `mdtohtml` routine, the default configuration for the `mdtohtml` routine uses simply:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"mdtohtmlviewerlaunch\" : \"falkon %outputfile%\",\n    \\ \"mdtohtmlviewerrefresh\" : \"none\",\n\\ }\n```\n\n### QuteBrowser\n\n[QuteBrowser project page](https://qutebrowser.org/)\n\nQutebrowser is a highly configurable, keyboard-driven browser with a vim-inspired interface. Although it doesn’t auto-reload like Falkon does, it can be triggered to reload manually by means of its userscript ability. The knap package now comes with such a userscript. (Again, it is assumed as a neovim user you have a working luajit interpreter on your system.) To use it, locate the file `knap-userscript.lua` in the `qutebrowser/` subfolder of the knap plugin directory. Make it executable. Copy it into qutebrowser’s userscript directory, or create a symbolic link to it there. Depending on where knap was installed, and qutebrowser’s config files are located, the commands for this might be something like:\n\n```\nchmod a+x ~/.local/share/nvim/site/pack/plugins/start/knap/qutebrowser/knap-userscript.lua\nmkdir -p ~/.config/qutebrowser/userscripts\nln -s ~/.local/share/nvim/site/pack/plugins/start/knap/qutebrowser/knap-userscript.lua \\\n      ~/.config/qutebrowser/userscripts/knap-userscript.lua\n```\n\nYou can set qutebrowser to start this userscript as part of the viewer launch command. The script creates uniquely named temporary files (based on its first argument) that allow knap to locate the FIFO pipe it can use to send qutebrowser refresh commands. The recommended settings for this are the following:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"mdtohtmlviewerlaunch\" : \"SRC=%srcfile%; ID=\\\"${SRC//[^A-Za-z0-9]/_-_-}\\\"; qutebrowser --target window %outputfile% \\\":spawn --userscript knap-userscript.lua $ID\\\"\",\n    \\ \"mdtohtmlviewerrefresh\" : \"SRC=%srcfile%; ID=\\\"${SRC//[^A-Za-z0-9]/_-_-}\\\"; echo ':run-with-count '$(\u003c/tmp/knap-$ID-qute-tabindex)' reload -f' \u003e \\\"$(\u003c/tmp/knap-$ID-qute-fifo)\\\"\",\n    \\ \"htmltohtml\" : \"none\",\n    \\ \"htmltohtmlviewerlaunch\" : \"SRC=%srcfile%; ID=\\\"${SRC//[^A-Za-z0-9]/_-_-}\\\"; qutebrowser --target window %outputfile% \\\":spawn --userscript knap-userscript.lua $ID\\\"\",\n    \\ \"htmltohtmlviewerrefresh\" : \"SRC=%srcfile%; ID=\\\"${SRC//[^A-Za-z0-9]/_-_-}\\\"; echo ':run-with-count '$(\u003c/tmp/knap-$ID-qute-tabindex)' reload -f' \u003e \\\"$(\u003c/tmp/knap-$ID-qute-fifo)\\\"\",\n\\ }\n```\n\nThe first part of these commands creates a (most probably) unique identifier from the source file name to use as part of the temporary file names, and the same method is used later to locate these files to use their contents to arrange the refreshes.\n\nYou might also consider using the [live server method](#using-a-live-server-works-with-any-browser) described below.\n\n### Firefox, Chrome, Chromium, etc.\n\nThe mainstream browsers don’t provide an easy way for an external application to refresh the displayed page if it is read directly with the `file://` protocol, at least short of using a webdriver. There are lots of potential workarounds for this, of greater and lesser complexity.\n\nA simple but kludgy way around this is to add a tag of the form `\u003cmeta http-equiv=\"refresh\" content=\"1\" \u003e` inside the `\u003chead\u003e...\u003c/head\u003e` of the html to instruct the browser to reload the page every second.\n\nWith knap, if you wish to avoid adding this tag to your actual file, you can use a trick to create a separate dummy file with this added using `sed` and then point the browser to it instead. For example, for straight HTML and for markdown input files, use something like:\n\n```vimscript\nlet g:knap_settings = {\n    \\ \"htmltohtml\": \"A=%outputfile% ; B=\\\"${A%.html}-preview.html\\\" ; sed 's/\u003c\\\\/head\u003e/\u003cmeta http-equiv=\\\"refresh\\\" content=\\\"1\\\" \u003e\u003c\\\\/head\u003e/' \\\"$A\\\" \u003e \\\"$B\\\"\",\n    \\ \"htmltohtmlviewerlaunch\": \"A=%outputfile% ; B=\\\"${A%.html}-preview.html\\\" ; firefox \\\"$B\\\"\",\n    \\ \"htmltohtmlviewerrefresh\": \"none\",\n    \\ \"mdtohtml\": \"A=%outputfile% ; B=\\\"${A%.html}-preview.html\\\" ; pandoc --standalone %docroot% -o \\\"$A\\\" \u0026\u0026 sed 's/\u003c\\\\/head\u003e/\u003cmeta http-equiv=\\\"refresh\\\" content=\\\"1\\\" \u003e\u003c\\\\/head\u003e/' \\\"$A\\\" \u003e \\\"$B\\\" \",\n    \\ \"mdtohtmlviewerlaunch\": \"A=%outputfile% ; firefox \\\"${A%.html}-preview.html\\\"\",\n    \\ \"mdtohtmlviewerrefresh\": \"none\",\n\\ }\n```\nReplace `firefox` above with `chromium` or `google-chrome-stable`, etc., for other popular browsers.\n\nAnother good alternative is using a live server; see below.\n\n### Using a Live Server (works with any browser)\n\nIt is possible to set up a local webserver to serve the file you’re working on, and have it refresh the file when it changes. Unlike some plugins, knap does not come prebundled with one in order to stay minimal, but it can work in conjunction with such tools. For example, one may make use of the node-based [local-server](https://github.com/tapio/live-server) package by Tapio Vierros. (Follow the instructions in its README for installation.)\n\nOne could then utilize settings such as the following:\n\n```vimspcript\nlet g:knap_settings = {\n    \"htmltohtmlviewerlaunch\": \"live-server --quiet --browser=firefox --open=%outputfile% --watch=%outputfile% --wait=800\",\n    \"htmltohtmlviewerrefresh\": \"none\",\n    \"mdtohtmlviewerlaunch\": \"live-server --quiet --browser=firefox --open=%outputfile% --watch=%outputfile% --wait=800\",\n    \"mdtohtmlviewerrefresh\": \"none\",\n\\ }\n```\nYou can replace “`firefox`” with the executable name for whichever browser you would prefer to use. It is usually necessary to use the `--wait=` option for live-server to avoid it attempting to reload the output file before it is completely written, but you may need to tweak the precise value (in milliseconds) depending on the speed of your processing routine.\n\nNote that knap spawns its viewer in the background, detached from the neovim process. In order to avoid leaving the server running after you exit neovim, you may wish to add an autocommand to kill all live-server instances upon exit. For instance, in your `init.vim` you could put:\n\n```vimscript\nautocmd BufUnload * lua if (vim.b.knap_viewerpid) then os.execute(\"pkill -f live-server\") end\n```\n\n## Troubleshooting and Workarounds\n\nThe developers of PDF viewers/browsers, etc., likely did not foresee their use for this purpose, and because of this, problems can arise. One of the most common issues occurs when the next cycle of the processing begins rewriting an updated version of the output file before the viewer is done reading it from the previous cycle. At worst, this can cause the viewer to malfunction or crash. And even when this doesn’t happen, it can create annoyances such as the viewer “losing your place” in the document and, e.g., scrolling back to the start of the document while you were editing the middle or end.\n\nIf you encounter this kind of difficulty, one thing to consider is raising the processing delay setting to 500 ms or higher; see [the info on this above](#delay-setting--speed-tuning). This might give the viewer the time it needs.\n\nAnother method that often alleviates such problems involves setting the processing command to write to a temporary file and only moving it to the desired location when the processing is completed. For example, suppose your original processing command were something like this:\n\n```\n\"mdtohtml\" : \"pandoc --citeproc --bibliography=mybib.yaml %docroot% \u003e %outputfile%\",\n```\n\nConsider changing it to this:\n\n```\n\"mdtohtml\" : \"tempout=\\\"/tmp/$(basename %outputfile%)\\\" ; pandoc --citeproc --bibliography=mybib.yaml \u003e \\\"$tempout\\\" \u0026\u0026 mv \\\"$tempout\\\" %outputfile%\",\n\n```\n\nSince moving a file is a much quicker process than writing it to begin with, this makes it far less likely for there to be a conflict between the routine writing the file and the viewer reading it simultaneously.\n\n## License\n\n[GPLv3](https://www.gnu.org/licenses/gpl-3.0.html).\n\nKNAP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but *without any warranty*; without even the implied warranty of *merchantability* or *fitness for a particular purpose*. See the [GNU General Public License](https://www.gnu.org/licenses/gpl-3.0.html) for more details.\n\n© 2022 Kevin C. Klement. \u003cklement@umass.edu\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrabjous%2Fknap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrabjous%2Fknap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrabjous%2Fknap/lists"}