DEV Community

Jon Staab
Jon Staab

Posted on

Opening Command Output in a New Buffer

Last time, we tweaked our kakoune query browser to open the selected query in an info window. As I mentioned at the bottom of that post, there are a few problems with this over-simplistic approach, one of which is the limitations of the info window.

Today I'll be tweaking the plugin by moving the query output into its own scratch buffer, which we'll open for the user when a query is run. As an added bonus, I'll be generalizing the plugin to work the same for any external command, not just databases.

To start with, let's review our plugin:

def eval-query \
  -override \
  -docstring "Evaluate current selection using given connection." \
  -params 1 \
  -shell-script-candidates %{
    cat .eval-query.json \
      | jq -r '.connections|keys|@sh' \
      | sed s/\'//g \
      | tr -s " " "\n"
  } \
%{
  info -title "Query output" %sh{
    psql `cat .eval-query.json | jq .connections.$1 | cut -d\" -f 2` \
      -c "${kak_selection}" 2>&1
  }
}
Enter fullscreen mode Exit fullscreen mode

The salient information here is that info command. Instead of popping up an info dialog, we're going to capture the output and put it in the | register using set-register. Below is the modified command body:

set-register | %sh{
  cmd=`cat .eval-query.json | jq .connections.$1 | cut -d\" -f 2`
  eval "$cmd "${kak_selection}" 2>&1"
}
Enter fullscreen mode Exit fullscreen mode

We used the | register, since :doc registers states that it should be used by commands that spawn a subshell. I'm not sure if this is 100% kosher, so leave a comment if you know better!

Next, we're going to open a new scratch buffer called eval-query-output and stick the contents of the register in there. This is pretty straightforward:

edit -scratch *eval-query-output*
exec 'geA<ret><esc>"|p;'
Enter fullscreen mode Exit fullscreen mode

The edit command is probably familiar; it just opens a new buffer. -scratch tells kakoune we don't care about linking it with a file. Finally, we use execute-keys (exec for short) to go to the end of the file, add a new line, and paste the contents of the | register.

And that's it! See it in action below:

Opening query results in a new buffer

Because the mechanism for running a query is so generic, this plugin can be used just as easily to open anything in a new buffer, not limited to query results. By simply renaming connections to commands and updating our config file (I also renamed the plugin to beval for "buffer eval"), the possibilities become endless!

Let's add a fancy ls command that lets us open a directory listing in a new buffer:

{
  "commands": {
    "ls": "ls -lah"
  }
}
Enter fullscreen mode Exit fullscreen mode

Opening a directory listing in a new buffer

Finally, we can cheat by adding an eval key to run any command we want:

{
  "commands": {
    "eval": "eval"
  }
}
Enter fullscreen mode Exit fullscreen mode

Evaluate an arbitrary command

What we basically have now is | on steroids (and less well-designed). Let's go ahead and refactor this to split out the "pipe to buffer" functionality as a standalone thing.

def eval-to-buffer \
  -override \
  -docstring "Evaluate current selection into scratch buffer." \
  -params 1..1000 \
%{
  set-register | %sh{ eval "$@ 2>&1" }

  # Open our output buffer
  edit -scratch *command-output*

  # Put output into the buffer
  exec '%"|pd'
}

def beval \
  -override \
  -docstring "Evaluate current selection using named command into scratch buffer." \
  -params 1 \
  -shell-script-candidates %{ cat .beval.json | jq -r '.commands|keys|@sh' | sed s/\'//g | tr -s " " "\n" } \
%{
  eval-to-buffer %sh{
    cmd=`cat .beval.json | jq .commands.$1 | cut -d\" -f 2`
    echo "$cmd \"${kak_selection}\""
  }
}
Enter fullscreen mode Exit fullscreen mode

Now our project-specific configuration is independent of our mechanism for piping output to a buffer, since both are useful in different circumstances.

Further refinement is of course out there, but for now, I'll leave this here. Thanks for reading!

Top comments (0)