├── tabssh.go └── README.md /tabssh.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gliderlabs/ssh" 6 | "io" 7 | "io/ioutil" 8 | "log" 9 | ) 10 | 11 | var i int 12 | 13 | func eval(expr string) string { 14 | // FIXME: these need to be unique across runs 15 | // (or just fix the truncate bug, whatever it is) 16 | evalpath := fmt.Sprintf("/Users/osnr/t/tabs/last-focused/evals/eval%d.js", i) 17 | err := ioutil.WriteFile(evalpath, []byte(expr), 0755) 18 | i = i + 1 19 | if err != nil { 20 | fmt.Printf("Unable to write file: %v", err) 21 | } 22 | 23 | dat, err := ioutil.ReadFile(evalpath + ".result") 24 | fmt.Printf("[%s]", dat) 25 | return string(dat) 26 | } 27 | 28 | func url() string { 29 | url, err := ioutil.ReadFile("/Users/osnr/t/tabs/last-focused/url.txt") 30 | _ = err 31 | return string(url[:len(url)-1]) 32 | } 33 | 34 | func main() { 35 | ssh.Handle(func(s ssh.Session) { 36 | for { 37 | io.WriteString(s, "\u001b[32m") 38 | io.WriteString(s, url()) 39 | io.WriteString(s, "\u001b[0m> ") 40 | 41 | line := "" 42 | for { 43 | ch := make([]byte, 1, 1) 44 | s.Read(ch) 45 | 46 | line = line + string(ch) 47 | s.Write(ch) 48 | 49 | // fmt.Println(url.PathEscape(string(ch))) 50 | if ch[0] == byte('\r') { 51 | s.Write([]byte{'\n'}) 52 | break 53 | } 54 | // FIXME: this doesn't work 55 | if ch[0] == byte('\b') { 56 | line = line[:len(line)-1] 57 | } 58 | } 59 | fmt.Printf("Read") 60 | io.WriteString(s, string(eval(line))) 61 | } 62 | }) 63 | 64 | log.Fatal(ssh.ListenAndServe(":2222", nil)) 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tabssh 2 | 3 | [idk](https://twitter.com/rsnous/status/1365106287080472579) 4 | 5 | Uses [TabFS](https://github.com/osnr/TabFS) and 6 | [gilderlabs/ssh](https://twitter.com/jf/status/1352012743600062465). 7 | 8 | Set your TabFS mount path in `tabssh.go`. 9 | 10 | ``` 11 | $ go run tabssh.go 12 | ``` 13 | 14 | and 15 | 16 | ``` 17 | $ ssh -o StrictHostKeyChecking=no localhost -p 2222 18 | ``` 19 | 20 | (you can set a fun hostname in `~/.config/ssh`: 21 | ``` 22 | Host last-focused-tab.safari.localhost 23 | HostName localhost 24 | Port 2222 25 | LogLevel ERROR 26 | StrictHostKeyChecking no 27 | UserKnownHostsFile /dev/null 28 | ``` 29 | ) 30 | 31 | ## ideas 32 | 33 | a hack would be to make it dispatch to tab depending on provided username, like how 34 | [their Docker 35 | example](https://github.com/gliderlabs/ssh/tree/master/_examples/ssh-docker) 36 | dispatches to process (ssh `jq@localhost` runs `jq`) 37 | 38 | but really, the _right_ way to do it would be to make it so that 39 | `safari.localhost` is a hostname that actually lets you talk to 40 | Safari, and `last-focused-tab.safari.localhost` is a hostname that 41 | actually lets you talk to the last focused tab. 42 | 43 | could you make a virtual network or something to do that? (where each 44 | tab is a host on the virtual network) I mean, that feels 45 | philosophically right; [tabs are virtual 46 | computers](https://twitter.com/rsnous/status/1352014584731734016), so 47 | maybe they should be network-addressable like your real computer is 48 | (and maybe other things should be network-addressable that way too -- 49 | individual applications, documents, etc). 50 | 51 | like 'port numbers' feel kinda like they unnaturally promote one level 52 | of computer, the physical one on your desk that has a Wi-Fi chip, and 53 | hide the computers nested inside it (such as each of your browser 54 | tabs) 55 | --------------------------------------------------------------------------------