How can I update content being piped to FZF?

338 Views Asked by At

I want to poll something and then pipe results to FZF, such that it gets updated there. Here is an example using CURL:

while true; do curl google.com -s; sleep 2; done | fzf

This stacks-up all the outputs like:

  </BODY></HTML>
  <A HREF="http://www.google.com/">here</A>.
  The document has moved
  <H1>301 Moved</H1>
  <TITLE>301 Moved</TITLE></HEAD><BODY>
  <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
  </BODY></HTML>
  <A HREF="http://www.google.com/">here</A>.
  The document has moved
  <H1>301 Moved</H1>
  <TITLE>301 Moved</TITLE></HEAD><BODY>
  <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
  </BODY></HTML>
  <A HREF="http://www.google.com/">here</A>.
  The document has moved
  <H1>301 Moved</H1>
  <TITLE>301 Moved</TITLE></HEAD><BODY>
  <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">

But I want it to just list one output

  </BODY></HTML>
  <A HREF="http://www.google.com/">here</A>.
  The document has moved
  <H1>301 Moved</H1>
  <TITLE>301 Moved</TITLE></HEAD><BODY>
> <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">

and update it if it changes.

1

There are 1 best solutions below

0
PeterM On BEST ANSWER

A simple way of dealing with this is with a key-press-reload command:

curl google.com | fzf --bind 'ctrl-r:reload(curl google.com)'

But that requires pressing CTRL-R to refresh. To make it automated... can wrap the desired command and FZF, and use FZF with fzf -f <query> to only get the results to display. Eg, with node create fzf-watch.js:

const { exec } = require("child_process");
const cmd = process.argv[2];
let query = "";
let timeout;
let commandRes = "";

if (!cmd) {
  console.log("A command must be provided as the second argument");
  process.exit(1);
}

function runCommand(cb) {
  exec(cmd, function (error, stdout, stderr) {
    if (stderr) {
      console.log("standard error", stderr);
    }
    commandRes = stdout;
    cb();
  });
}

function printOut(/** @type {string} */ str) {
  console.clear();
  console.log(str);
  process.stdout.write(`Query: ${query}`);
}

function runFzf() {
  if (!query) {
    printOut(commandRes);
    return;
  }
  exec(
    `echo '${commandRes}' | fzf -f "${query}"`,
    function (error, stdout, stderr) {
      if (!error) {
        printOut(stdout);
      } else {
        printOut("");
      }
    }
  );
}

function runQuery() {
  // Run fzf on existing result in the meantime
  runFzf();
  // Start running the command
  runCommand(runFzf);
  if (timeout) {
    clearTimeout(timeout);
  }
  timeout = setTimeout(runQuery, 5000);
}

const readline = require("readline");

readline.emitKeypressEvents(process.stdin);

process.stdin.setRawMode(true);

process.stdin.on("keypress", (k, key) => {
  if (key.name === "backspace") {
    query = query.substring(0, query.length - 1);
  }
  else if (key.sequence === "\u0003") {
    process.exit();
  } else {
    query = `${query}${k}`;
  }
  runQuery();
});

runQuery();

Call it like this to watch the results (called every 5 seconds):

node ./fzf-watch.js 'curl google.com'