Here, the eipe2 script wraps around emacsclient to enable myself to intercept the traffic of a bash pipeline and edit it mid-command. It’s modelled after vipe.

But that is only half the trick. I then do the same for tcl/expect. On its own, expect can’t edit the stream, but by placing an eipe2 within the expect script I can complete the pipeline, automating emacs with expect.

But that is not the most awesome part. Although expect could fully automate emacs, I hand over control to the user before exiting expect, allowing the user to make some final adjustments to the data before continuing the pipeline.

### The final command and an explanation

This commands pipes the html through expect, which spawns emacs and runs a few automated key presses to prepare the user for editing.

Command is then given to the user to do some editing.

When the buffer is killed, the emacs frame is also killed and the contents of the killed buffer is piped into vim.

Sadly I can’t explain it all here as there are so many components at work, but the result makes semi-automated stream editing using an interactive TUI possible and very easy to use.

 1 2 3 4 5 6 7 8 9 10 11 12 13 curl -s "https://mullikine.github.io/css/magit.css" | x \ -sh "eipe2 -aft"  # run emacs with language detection  \ -e "When done with this frame"  # wait for this string to apper  \ -m s -s o -s "\\bbold\\b" -c m  # start occur mode. search for 'bold'  \ -m l -m 1  # make it the only window  \ -m n  # go to the first/next occurrence  \ -m l -m ';'  # go to the other window  \ -m i  # enter 'iedit' mode  \ -m r  # select the word under the cursor (bold)  \ -s normal  # replace 'bold' with 'normal'  \ -i  # hand over interaction to the user  | v

### The generated expect script

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #!/usr/bin/expect -f #trap sigwinch and pass it to the child we spawned trap { set rows [stty rows] set cols [stty columns] stty rows $rows columns$cols < $spawn_out(slave,name) } WINCH proc getctrl {char} { set ctrl [expr ("$char" & 01xF)] return $ctrl } set force_conservative 0 if {$force_conservative} { set send_slow {1 .1} proc send {ignore arg} { sleep .1 exp_send -s -- $arg } } # For send -h set send_human {.4 .4 .2 .5 100} set ::env(PATH) "/home/shane/scripts:/home/shane/var/smulliga/source/git/google-cloud-sdk/google-cloud-sdk/bin:/home/shane/.cargo/bin:/usr/local/toolchains/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04/bin:/usr/local/toolchains/clang/bin:/usr/local/toolchains/boost/bin:/home/shane/.nix-profile/bin:/home/shane/.cask/bin:/home/shane/.opam/system/bin:/home/shane/notes2018/ws/codelingo/scripts:/home/shane/scripts:scripts:/home/shane/.pyenv/bin:/opt/apache-maven-3.5.3/bin:/home/shane/bin:/usr/local/racket/bin:/home/shane/local/emacs26/bin:/home/shane/local/bin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin:/home/shane/source/git/fzf/bin/fzf:/home/shane/go/bin:/home/shane/go1.6.2/bin:/downloads/node-v9.9.0-linux-x64/bin:/home/shane/node_modules/.bin/:/home/shane/.cabal/bin:/home/shane/.local/bin:/home/shane/.config/composer/vendor/bin:/usr/local/go/bin:/home/shane/dump/downloads/node-v9.9.0-linux-x64/bin:/home/shane/.config/composer/vendor/bin/home/shane/source/git/fzf/bin/fzf/home/shane/source/git/fzf/bin/fzf/home/shane/source/git/fzf/bin/fzf:/usr/bin" # This is not what you want. # set ::env(TTY) "/dev/pts/508" # I must set the TTY to expect's TTY # set ::env(TTY) "/dev/pts/508" # puts "$::env(TTY)" unset ::env(TTY) set timeout -1 match_max 100000 set SHELL "zsh" spawn "/tmp/file_new_script_cx9Zkd_rand-30891_pid-20249.sh" expect -exact "When done with this frame" send -- \033s send -- "o" send -- "cloudflare.com" send -- \015 send -- \033l send -- \0331 send -- \033n send -- \033l send -- \033\; interact expect eof close

## How it works - script snippets

I’m just going to copy out some of the important parts of the following scripts.

Explaining it all will take too long.

### eipe2

 1 2 3 4 5 6 #!/bin/bash export TTY ( hs "$(basename "$0")" "$@" "#" "<==" "$(ps -o comm= $PPID)" 0/dev/null orspe "$@" +ooq "(buffer-string)"

#### Generated expect code

 1 unset ::env(TTY)

TTY must be unset so the spawned scripts can determine the TTY from the /dev/tty command.