Mini-tips: using scripts (and LLMs) to help you directly in vim

On Tue, 11 Feb 2025, by @lucasdicioccio, 460 words, 2 code snippets, 2 links, 3images.

I find LLMs exciting. That said, I’m not gonna generate whole articles on this blog. If I were to do so, I’d give you the prompt directly instead. However, LLMs come handy to fix my broken English and spot some typos (much better than my aspell scripts used to) or for roasting my articles.

I’ve watched a multitude of YouTube videos where individuals are seen copying and pasting from OpenAI or similar AI web-apps into their editors. How cutting-edge can they really be?

Well, being a dinosaur, I use #vim on Linux. And Linux, in 2025, still makes copy-pasting difficult across applications. Indeed, applications have different pasting buffers. Thus, the technology of copy-pasting is too advanced for me - how about just using vim?

You can do it in vim

Although vim has plugins, I’ve always ended up trashing them because plugin installations were causing troubles. Thus, as a dinosaur, I use dinosaur tools: the features inside vim, directly.

You can select lines in visual mode (Shift+V), then after pressing : you can issue a command on the selection !<command>. Selected lines are passed to a program as stdin, and stdout will be written back.

For instance, using the jq command, you can reformat some JSON directly from within vim. See the screenshots below: selecting the rows to format and after formatting them. The trick works also with other selectors like % for the whole file.

Selecting the lines and calling jq:

before: cramped json

The result is an expanded content, and I can notice the typo about codding (alright, the British pun is lame).

after: expanded json

other uses, and about LLMs

This feature is also useful for processing data files quickly; for example, you can use sort or any other bash command you prefer.

In the context of blogging, you can also utilize a script if you call an #LLM. I’ve created my own script that can be invoked in various contexts (e.g., calling a prompt directly, writing a prompt, calling vim and pasting the content of the edited file, using stdin as a source of the prompt).

The script I use is below:

#!/bin/bash

ollamaurl="https://example.com/endpoint-to-ollama-api/generate"
template="{\"model\":\"llama3.2\",\"stream\":false,\"options\":{\"num_gpu\":1}}"

case $1 in
	vim)
		tmpfile="$(mktemp)"
		vim "${tmpfile}"
		payload="$(echo "${template}" | jq --rawfile prompt ${tmpfile} ".prompt |= \$prompt")"
		rm $tmpfile
		curl --no-progress-meter "${ollamaurl}" -XPOST --data-binary "${payload}" | jq -r .response
		;;
	file)
		inputfile="$2"
		payload="$(echo "${template}" | jq --rawfile prompt ${inputfile} ".prompt |= \$prompt")"
		curl --no-progress-meter "${ollamaurl}" -XPOST --data-binary "${payload}" | jq -r .response
		;;
	task-file)
		inputtask=$2
		inputfile=$3
		tmpfile="$(mktemp)"
		echo "${inputtask}" >> $tmpfile
		echo "-----------" >> $tmpfile
		cat "${inputfile}" >> $tmpfile
		payload="$(echo "${template}" | jq --rawfile prompt "${tmpfile}" ".prompt |= \$prompt")"
		curl --no-progress-meter "${ollamaurl}" -XPOST --data-binary "${payload}" | jq -r .response
		;;
	task-stdin)
		inputtask=$2
		inputfile="/dev/stdin"
		tmpfile="$(mktemp)"
		echo "${inputtask}" >> $tmpfile
		echo "-----------" >> $tmpfile
		cat "${inputfile}" >> $tmpfile
		payload="$(echo "${template}" | jq --rawfile prompt "${tmpfile}" ".prompt |= \$prompt")"
		curl --no-progress-meter "${ollamaurl}" -XPOST --data-binary "${payload}" | jq -r .response
		;;
	task-stdin-echo)
		inputtask=$2
		inputfile="/dev/stdin"
		tmpfile="$(mktemp)"
		tmpfile2="$(mktemp)"
		echo "${inputtask}" >> $tmpfile
		echo "-----------" >> $tmpfile
		cat "${inputfile}" > $tmpfile2
		cat "${tmpfile2}" >> $tmpfile
		payload="$(echo "${template}" | jq --rawfile prompt "${tmpfile}" ".prompt |= \$prompt")"
		curl --no-progress-meter "${ollamaurl}" -XPOST --data-binary "${payload}" | jq -r .response
		cat "${tmpfile2}"
		;;
	*)
		inputstring=$1
		payload="$(echo "${template}" | jq --arg prompt "${inputstring}" ".prompt |= \$prompt")"
		curl --no-progress-meter "${ollamaurl}" -XPOST --data-binary "${payload}" | jq -r .response
		;;
esac

This code relies on the Ollama-API and requires jq and curl to be installed. The only tricks are: (a) use jq to update a template config from data read in temporary files or from arguments; and (b) use stream=false because we only want the output. The rest is fairly standard; I’ve hardcoded the models and number of GPUs. Of course to make it work, you need to adjust ollamaurl to point at somewhere else, like your locally-running instance.

I select some piece of writing with Shift+V, then call !/opt/bin/ollama.sh task-stdin <some prompt> on the picked lines.

A prompt I use is:

rewrite the following paragraph, only fix the english, keep the same style, just 

output the modified text

Finally, I recommend to !git commit -m 'snapshot' % the source file right before, so that you can then (still within vim) !git diff --word-diff % to spot the changes.

example diff text