BufPreWrite hook dependent on buffer content

Hi!

The Problem

I want markdown files to get autoformatted on safe.
For that, I want to use pandoc. Since I have markdown files with pandoc’s YAML markdown header and latex content, I need to consider that.
Since the workaround needed for this creates redundant newlines in the beginning of the file (see github isse), I want to adress this by either deleting theses newlines or by changing the formatcmd depending on file content.

Why not use prettier for formatting?

I would like to use --reference-links with pandoc, which creates references for all the links in the document at the bottom of the file.

The Question

Depending on which way I choose, I want to do one of the following:

  • (a) delete three newlines in the beginning of the file or after the YAML header
  • (b) check the file content for a specific line within the YAML header

The problem is that either way, I’m not sure how to approach this since the YAML header starts with --- but ends with either --- or ....
Also, it normally is at the beginning of the file but it doesn’t have to by definition.

So the only way I can come up with for matching this is some sort of complicated PCRE regex, wich wouldn’t be very portable at all.

Maybe soneone else has another idea?

Hi basbebe,
It’s not everything but it may get you started. The top one I got from @dmerejkowsky. The other one I just winged it. Have fun. Bye :wave:

# on every `:write` a hook like this can be done for every file type.
hook global BufWritePost .* %{
  nop %sh{ pandoc --flags "${kak_hook_param}" }
}
----
# or on a specific file type you can run something like `pandoc --flags`
hook global WinSetOption filetype=latex %{
  hook window BufWritePost .* %{ sh%{ pdflatex -halt-on-error -file-line-error -output-format=pdf -synctex=1 [...] } }
}

Hey basbebe, forgot I had this. You could swap it out for pandoc or yaml parser…

hook global WinSetOption filetype=kotlin %{
    # <https://discuss.kakoune.com/t/what-is-the-right-way-to-do-format-on-write/922/2>
    set-option window lintcmd 'ktlint --relative --verbose --editorconfig="$HOME/.editorconfig"'
    set-option window formatcmd 'ktlint --format--relative'
}

Bye buddy :wave:


Might actually have a solution for you basbebe that I came across today. Source adapted:
nficano 2019, permissions, dotfiles/bin/, viewed 05 March 2021, dotfiles/permissions at master · nficano/dotfiles · GitHub

#!/bin/sh
#/ Shows the permissions of a file or directory in octal form.
#/
#/ USAGE:
#/    permissions /path/to/file/or/dir
#/
#/ EXAMPLES:
#/    permissions /usr/bin    # drwxr-xr-x 755 /usr/bin

usage () {
  grep '^#/' < "$0" | cut -c4-
}

As the line begin is always known then the problem is only the line end. We can look for simple alternation pattern and pipe the result as above. Also consider the sed utility, a play ground can be found here https://sed.js.org/.

grep '^---.*(---|....)' | utility

Unix utilities are not one off my strengths, so it’s an idea not proof of concept.

If that was no help to you at all, see you tomorrow. Bye :wave:.

Hi duncan,

thanks for getting into this!

The last grep rule might go in the right direction.
I will have to somehow select everything except the YAML header and consider the case when it’s not at the beginning of the file.

I was kind of hoping there was another way of doing this in Kakoune (like how syntax highlighting and other highlighters select parts) but I guess this is the right approach.

Hey basbebe, just had this thought that we haven’t considered for the yaml file. Output to temp and do your thing, then save it, the way you like it:

# ref: https://github.com/mawww/config/blob/master/kakrc#L136
define-command -params .. fifo %{ evaluate-commands %sh{
   output=$(mktemp -d "${TMPDIR:-/tmp}"/kak-fifo.XXXXXXXX)/fifo
   mkfifo ${output}
   ( eval "$@" > ${output} 2>&1 & ) > /dev/null 2>&1 < /dev/null

   printf %s\\n "evaluate-commands -try-client '$kak_opt_toolsclient' %{
           edit! -fifo ${output} *fifo*
           hook -always -once buffer BufCloseFifo .* %{ nop %sh{ rm -r $(dirname ${output}) } }
       }"
}}

Copy and paste the bellow example into kakoune and give it a run manually to see the keys in action.

---
Then on the *fifo* buffer do this:

# multi line output from begin and all lines inclusive of ending. 
execute-keys %s^---.*(^---|^...)$<ret>

# to delete all the enclosed
execute-keys d

# Or if on the one line match it, grab it, 
execute-keys %s^---.*(---|...)$<ret>

# and everything above it. Then delete current selection.
# <a-;>Gkdd <-- an extra d key maybe needed to remove top blank line.
execute-keys <a-;>Gkd

# either evaluate-commands or execute-keys for this one, I'm not sure which.
execute-keys :write filename.yaml

...

:doc execeval

‘execute-keys runs keys as if they were pressed, whereas evaluate-commands evaluates its given parameters as if they were entered in the command prompt’.

Am I getting any better? All the best. Bye :wave: