Instantly share code, notes, and snippets.
Created
April 29, 2011 21:13
-
Star
0
(0)
You must be signed in to star a gist -
Fork
1
(1)
You must be signed in to fork a gist
-
Save NeoCat/949054 to your computer and use it in GitHub Desktop.
Share input within multiple terminals
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
# share-input.rb: share input within multiple terminals | |
# Author: NeoCat | |
require 'socket' | |
require 'pty' | |
require "thread" | |
require "curses" | |
def server(sock, sock_name) | |
puts "relay server started." | |
$sock_name = sock_name | |
$clients = [] | |
def stop_client(client) | |
client.close | |
$mutex.synchronize { | |
$clients.delete client | |
#p $clients | |
quit if $clients.empty? | |
} | |
end | |
def quit | |
puts "relay server stopped." | |
File.unlink $sock_name | |
exit | |
end | |
Signal.trap(:CHLD, 'IGNORE') | |
Signal.trap(:HUP) { quit } | |
Signal.trap(:INT) { quit } | |
Signal.trap(:TERM) { quit } | |
$mutex = Mutex.new | |
while new_client = sock.accept | |
$mutex.synchronize { $clients << new_client } | |
#p $clients | |
Thread.new(new_client) do |client| | |
begin | |
while data = client.readpartial(4096) | |
$clients.each do |c| | |
begin | |
c.write data | |
rescue | |
#puts "error on write: #$!" | |
stop_client c | |
end | |
end | |
end | |
rescue | |
#puts "error on read: #$!" | |
stop_client client | |
end | |
end | |
end | |
end | |
def make_connection(sock_id) | |
sock_name = "/tmp/sock.pty-relay."+sock_id.to_s | |
# launch a server unless it already exists | |
sock = nil | |
begin | |
sock = UNIXServer.open(sock_name) | |
rescue | |
end | |
if sock | |
fork { server(sock, sock_name) } | |
end | |
# client mode | |
return UNIXSocket.open(sock_name) | |
end | |
def relay_pty(sock, cmd) | |
$child_pid = nil | |
def quit | |
Curses::noraw | |
exit | |
end | |
Signal.trap(:CHLD, 'IGNORE') | |
Signal.trap(:HUP) { quit } | |
Signal.trap(:INT) { quit } | |
Signal.trap(:TERM) { quit } | |
Curses::init_screen | |
Curses::raw | |
p = PTY.spawn "export PTY_RELAY=#$$; stty rows #{Curses::lines} columns #{Curses::cols}; " + (cmd || "exec $SHELL") | |
$child_pid = p[2] | |
$p = p | |
single_mode = false | |
until p[0].closed? || STDIN.closed? || sock.closed? | |
s = IO.select [p[0], STDIN, sock] | |
if s0 = s[0][0] | |
out = nil | |
if single_mode | |
out = s0 === sock ? p[1] : s0 === STDIN ? p[1] : STDOUT | |
else | |
out = s0 === sock ? p[1] : s0 === STDIN ? sock : STDOUT | |
end | |
begin | |
if s0 === STDIN | |
data = s0.readpartial(1) | |
if !single_mode and data == "\C-]" | |
single_mode = true | |
elsif single_mode and data == "\r" | |
single_mode = false | |
out.write data | |
else | |
out.write data | |
end | |
else | |
out.write s0.readpartial(4096) | |
out.flush | |
end | |
rescue | |
#puts "error on relay: #$!" | |
p[0].close | |
p[1].close | |
end | |
end | |
end | |
quit | |
end | |
if ARGV[0] == '-h' | |
puts <<-EOD | |
#$0: share input within multiple terminals | |
usage: #$0 [server-id] [command] | |
- Execute #$0 in multiple terminal to share the input. | |
- The login shell or the specified command is started. | |
- If you hit ^], the input is not shared until you hit Enter key | |
and only applied to current terminal. | |
EOD | |
exit | |
end | |
if ENV['PTY_RELAY'] | |
STDERR.puts "Cannot launch #$0 inside another #$0 !" | |
exit 1 | |
end | |
sock_id = 0 | |
if ARGV[0] =~ /^\d+$/ | |
sock_id = ARGV[0].to_i | |
ARGV.shift | |
end | |
if sock = make_connection(sock_id) | |
relay_pty(sock, ARGV[0] && ARGV * " ") | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment