I am trying to write a rxvt-unicode perl extension to do what mrxvt PrintScreen does. I.e., the extension should pipe urxvt's contents to user-defined commands. The main purpose would be viewing urxvt's contents unwrapped in less -S.

Here are my first attempts. (The command is still hardcoded cat -n, and including color escape codes and joining of wrapped lines is still missing.)

#! perl -w
use strict;

sub on_user_command {
    my ($self, $cmd) = @_;
    open PIPE, "|cat -n" or die "urxvt-pipe: error opening pipe: $^E\n";
    for (my $i = $self->top_row; $i < $self->nrow; $i++) {
        print PIPE $self->ROW_t($i), "\n";
    close PIPE or warn "urxvt-pipe: error closing pipe: $^E\n";

Replacing the pipe with exec_async does not help:

#! perl -w
use strict;

sub on_user_command {
    my ($self, $cmd) = @_;
    open FH, ">/tmp/urxvt.txt" or die "urxvt-pipe: error opening file: $^E\n";

    for (my $i = $self->top_row; $i < $self->nrow; $i++) {
        print FH $self->ROW_t($i), "\n";

    close FH or warn "urxvt-pipe: error closing file: $^E\n";
    $self->exec_async("cat", "-n", "/tmp/urxvt.txt");

The problem with both is that the cat runs inside urxvt's parent (e.g. another urxvt or an emacs buffer if I call urxvt as the "compile" command during extension development). I would like it to run in the instance whose contents I'm piping, or a new tab thereof. Is that possible?

Obviously as a workaround, the exec_async could be modified to open a new window: $self->exec_async("urxvt", "-title", "less urxvt scrollback", "-e", "less", "-S", "/tmp/urxvt.txt"); But I'd prefer the same window, and also rather avoid creating a temporary file.


This does not answer the real question, but unfortunately it was rejected as too long for a comment.

I made the workaround less ugly, moving the new window part out of the extension:

  • The extension uses IPC::Run3::run3 to capture the subprocess's stdout and stderr, and writes that to the "right" urxvt using $term->special_encode and $term->cmd_parse. (Not that less had any usefull output, but just to make it a general purpose extension.)
  • The configured command (in a URxvt.keysym... line in ~/.Xdefaults) is: zsh -c 'stdin2fifo | read -r p && urxvt -e less -SNRfI -- "$p"'
  • Script stdin2fifo reads stdin and writes it to a temp named pipe. less -f displays the pipe. So there's hopefully no disk I/O for the real data, only for a file system entry.

Script stdin2fifo:

if [ $# -ne 0 ]; then
    cat <<EOF
Usage: $(basename "$0")
Reads stdin, writes it to a new named pipe (in the background), and prints the
pipe's pathname.
Can be used (in zsh, at least) to "send stdin to another terminal". For example:
... | $(basename "$0") | read -r p && urxvt -e less -f -- "\$p"
    exit 4

set -e
dir=$(mktemp -d "/tmp/$(basename "$0")_XXXXXX")
mkfifo "$pipe"
(cat > "$pipe")&
echo "$pipe"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.