dev-pty-screen 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.ruby-version +1 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +22 -0
- data/README.markdown +119 -0
- data/Rakefile +1 -0
- data/bin/dev-pty-client +87 -0
- data/bin/dev-pty-server +7 -0
- data/dev-pty-screen.gemspec +31 -0
- data/dev-pty-screen.gif +0 -0
- data/doc/welcome.txt +16 -0
- data/lib/client/app.rb +8 -0
- data/lib/client/options.rb +15 -0
- data/lib/server/app.rb +8 -0
- data/lib/server/key_server.rb +46 -0
- data/lib/server/options.rb +17 -0
- data/lib/server/pty_server.rb +99 -0
- data/lib/server/screen_server.rb +50 -0
- data/lib/server/vim_interface.rb +20 -0
- data/lib/version.rb +3 -0
- data/outline.markdown +8 -0
- data/spec/server/key_server_spec.rb +27 -0
- data/spec/server/pty_server_spec.rb +4 -0
- data/spec/server/screen_server_spec.rb +30 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8413b6443bdf23c7d815c537cd2cc7f406bff86a
|
4
|
+
data.tar.gz: 59ae1732cd1bc370eb32ac029fc0f82c8702a24b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bbabc50f961876b31fd38b15d00f2031495e38abc6728c05f66cae10c0a0d8874b0bc59aceac25e2d44eb12125bd35c2b581f5e90a59c9cbf03fdcc0f1863e5d
|
7
|
+
data.tar.gz: 41d24a6784db21dbb14f6854a823cc7f6e49ec7fd3fb257fb492145a0ebc65ded1eeeda68943e9132a6b84f85d42e4cf64491a088dac4b53ac284cb9be276e4a
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
celluloid (0.15.2)
|
5
|
+
timers (~> 1.1.0)
|
6
|
+
diff-lcs (1.2.4)
|
7
|
+
rspec (2.14.1)
|
8
|
+
rspec-core (~> 2.14.0)
|
9
|
+
rspec-expectations (~> 2.14.0)
|
10
|
+
rspec-mocks (~> 2.14.0)
|
11
|
+
rspec-core (2.14.5)
|
12
|
+
rspec-expectations (2.14.3)
|
13
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
14
|
+
rspec-mocks (2.14.3)
|
15
|
+
timers (1.1.0)
|
16
|
+
|
17
|
+
PLATFORMS
|
18
|
+
ruby
|
19
|
+
|
20
|
+
DEPENDENCIES
|
21
|
+
celluloid
|
22
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Mark Lorenz
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# /dev/pty/screen
|
2
|
+
> VIM pair programming without raster graphics.
|
3
|
+
|
4
|
+
> Desktop sharing is for windows devs!
|
5
|
+
|
6
|
+
> Tmux!? Who wants to set that all up (not me).
|
7
|
+
|
8
|
+
> A sister project to [/dev/pty/vim](https://github.com/dapplebeforedawn/dev-pty-vim)
|
9
|
+
|
10
|
+
## Obligatory Recursive Joke:
|
11
|
+
> Yo dawg, anyone want to pair with me on my pair programming program?
|
12
|
+
|
13
|
+
## What's It Do:
|
14
|
+
- Only the server runs VIM (or even needs it installed for that matter).
|
15
|
+
- Everyone who wishes to be part of the paring session connects to the server.
|
16
|
+
- This is a very similar technique to what GNU Screen or TMux do.
|
17
|
+
- [Here's an animated demo](http://dapplebeforedawn.github.io/dev-pty-vim/)
|
18
|
+
|
19
|
+
## How's It Work:
|
20
|
+
- The server's VIM is loaded into a pseudoterminal that is controlled by the server
|
21
|
+
- Client keystrokes are sent to the server
|
22
|
+
- The server then passes those on to the captive VIM
|
23
|
+
- STDOUT from the pseudoterminal is forwarded to the server and the broadcast to cleints
|
24
|
+
- Clients have their display updated to match the forwareded STDOUT
|
25
|
+
|
26
|
+
## TL;DR - An Animated Gif
|
27
|
+

|
28
|
+
|
29
|
+
## Installation:
|
30
|
+
Requires Ruby 2.0.0 or better.
|
31
|
+
|
32
|
+
```bash
|
33
|
+
gem install dev-pty-screen
|
34
|
+
```
|
35
|
+
|
36
|
+
or:
|
37
|
+
|
38
|
+
```bash
|
39
|
+
# clone this repository
|
40
|
+
git clone https://github.com/dapplebeforedawn/dev-pty-screen
|
41
|
+
|
42
|
+
# build the gem
|
43
|
+
cd dev-pty-screen
|
44
|
+
rake build
|
45
|
+
|
46
|
+
# install the gem
|
47
|
+
rake install
|
48
|
+
```
|
49
|
+
|
50
|
+
## Getting Started:
|
51
|
+
- On the computer hosting the code to work on.
|
52
|
+
```bash
|
53
|
+
cd /a/directory/with/some/code
|
54
|
+
dev-pty-server
|
55
|
+
```
|
56
|
+
|
57
|
+
- On each client
|
58
|
+
```bash
|
59
|
+
dev-pty-server
|
60
|
+
|
61
|
+
#program will appear to hang
|
62
|
+
:tabnew <cr>
|
63
|
+
```
|
64
|
+
|
65
|
+
- Quitting: ^Z (ctrl+z) prompts your client to quit. All other keys are forwarded to the server.
|
66
|
+
|
67
|
+
## Considerations:
|
68
|
+
This approach has a few draw-backs compared to the run-your-own-VIM tact that /dev/pty/vim uses (and a few advantages)
|
69
|
+
|
70
|
+
### Positives
|
71
|
+
- Since there's only one copy of the files and one running VIM, it's impossible for the buffers or files on disk to be out of sync
|
72
|
+
- When a commit is made using a VIM plugin, like [fugitive](https://github.com/tpope/vim-fugitive), only the repository running the server, and it's user make the commit (as opposed to two users making the same commit in two repos)
|
73
|
+
- The clients can only interact with the server, but not each other. This means in an untrusted pairing session, you could run the server on a temporary ec2, and invite strangers to pair without giving them access to your private network.
|
74
|
+
- A hell of a lot less setup than /dev/pty/vim
|
75
|
+
|
76
|
+
### Negatives
|
77
|
+
- As with /dev/pty/vim all clients need to share a common .vimrc (and plugins). Here it's inforced by there only being on copy of VIM running, as opposed to a pre-connect .vimrc handshake.
|
78
|
+
- Since the clients are dumb terminals, and they may have different screen sizes, some clients may not get a full screen experience. Screen size is controlled by the server, and forced upon the clients.
|
79
|
+
|
80
|
+
## Work in Progress:
|
81
|
+
- When a client initially connects they need to press key to get STDOUT to re-paint. Telling VIM to create a new tab (`:tabnew`) is a simple work around for now.
|
82
|
+
- Notifications about who is typing
|
83
|
+
- Custom .vimrcs that are applied when a client is typing
|
84
|
+
- Replace all the `Thread.new` calls with a celluloid actor
|
85
|
+
- Seriously, why are arrow keys so hard to work with !?
|
86
|
+
|
87
|
+
## Application Structure
|
88
|
+
```
|
89
|
+
├── bin
|
90
|
+
│ ├── dev-pty-client # Run this to start a client
|
91
|
+
│ └── dev-pty-server # Run this to start a server
|
92
|
+
├── lib
|
93
|
+
│ ├── client
|
94
|
+
│ │ ├── app.rb
|
95
|
+
│ │ └── options.rb # Options parser for the client
|
96
|
+
│ └── server
|
97
|
+
│ ├── app.rb
|
98
|
+
│ ├── key_server.rb # Listens for keys strokes from clients
|
99
|
+
│ ├── options.rb # Options parser for the server
|
100
|
+
│ ├── pty_server.rb # Manages the screen/key servers and the vim_interface
|
101
|
+
│ ├── screen_server.rb # Pushes STDOUT updates to clients
|
102
|
+
│ └── vim_interface.rb # Sends keystrokes to the captive VIM
|
103
|
+
|
|
104
|
+
├── spec
|
105
|
+
├── client
|
106
|
+
└── server
|
107
|
+
├── key_server_spec.rb
|
108
|
+
├── pty_server_spec.rb
|
109
|
+
└── screen_server_spec.rb
|
110
|
+
```
|
111
|
+
|
112
|
+
## Running the Tests:
|
113
|
+
```bash
|
114
|
+
rspec
|
115
|
+
```
|
116
|
+
|
117
|
+
## Support:
|
118
|
+
- File a bug here
|
119
|
+
- Contact me on twitter/email : @soodesune/markjlorenz@gmail.com
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/dev-pty-client
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'io/console'
|
5
|
+
|
6
|
+
require_relative '../lib/client/app'
|
7
|
+
|
8
|
+
Thread.abort_on_exception = true
|
9
|
+
|
10
|
+
class DevPtyClient
|
11
|
+
READSIZE = 4096
|
12
|
+
CLEAR = "\e[H\e[2J"
|
13
|
+
SUSPEND = ?\C-z
|
14
|
+
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
startup_message
|
18
|
+
|
19
|
+
@key_sock = Socket.tcp(App.options.server_host, App.options.key_port)
|
20
|
+
@screen_sock = Socket.tcp(App.options.server_host, App.options.screen_port)
|
21
|
+
|
22
|
+
Thread.new &screen_loop
|
23
|
+
Thread.new &key_loop
|
24
|
+
end
|
25
|
+
|
26
|
+
def screen_loop
|
27
|
+
-> do
|
28
|
+
loop { STDOUT.write @screen_sock.readpartial( READSIZE ) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
private :screen_loop
|
32
|
+
|
33
|
+
def key_loop
|
34
|
+
-> do
|
35
|
+
loop {
|
36
|
+
key = STDIN.getch
|
37
|
+
prompt_exit(key) or @key_sock.write(key)
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
private :key_loop
|
42
|
+
|
43
|
+
def suspend?(key)
|
44
|
+
key == SUSPEND
|
45
|
+
end
|
46
|
+
private :suspend?
|
47
|
+
|
48
|
+
def prompt_exit(key)
|
49
|
+
return false unless suspend?(key)
|
50
|
+
clear_screen
|
51
|
+
print "Disconnect from dev-pty-screen?(y/n): "
|
52
|
+
will_exit if gets.match /y/i
|
53
|
+
wont_exit
|
54
|
+
end
|
55
|
+
private :prompt_exit
|
56
|
+
|
57
|
+
def will_exit
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
private :will_exit
|
61
|
+
|
62
|
+
def wont_exit
|
63
|
+
print "Run any vim command to re-draw the screen."
|
64
|
+
return true
|
65
|
+
end
|
66
|
+
private :wont_exit
|
67
|
+
|
68
|
+
def clear_screen
|
69
|
+
puts CLEAR
|
70
|
+
end
|
71
|
+
private :clear_screen
|
72
|
+
|
73
|
+
def startup_message
|
74
|
+
clear_screen
|
75
|
+
message_lines = File.readlines App.path.parent.join('doc', 'welcome.txt')
|
76
|
+
longest_line = message_lines.max_by(&:length).length
|
77
|
+
screen_width = STDOUT.winsize.last
|
78
|
+
offset = Array.new(screen_width/2 - longest_line/2, " ")
|
79
|
+
message_lines.each do |line|
|
80
|
+
print offset * '' + line
|
81
|
+
end
|
82
|
+
end
|
83
|
+
private :startup_message
|
84
|
+
end
|
85
|
+
|
86
|
+
at_exit { `reset` }
|
87
|
+
DevPtyClient.new and sleep
|
data/bin/dev-pty-server
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'dev-pty-screen'
|
8
|
+
s.version = '0.0.1'
|
9
|
+
s.version = DevPtyScreen::VERSION
|
10
|
+
s.date = '2013-10-13'
|
11
|
+
s.summary = 'VIM screen sharing as the neckbeards intended'
|
12
|
+
|
13
|
+
s.description =<<HEREDOC
|
14
|
+
One user runs the server from with the resposity that you want to work one.
|
15
|
+
Clients (including the one who started the server) connect, and can
|
16
|
+
interact with the VIM session.
|
17
|
+
HEREDOC
|
18
|
+
|
19
|
+
s.authors = [ 'Mark Lorenz' ]
|
20
|
+
s.email = 'markjlorenz@gmail.com'
|
21
|
+
s.homepage = 'http://github.com/dapplebeforedawn'
|
22
|
+
s.license = 'MIT'
|
23
|
+
s.files = `git ls-files`.split($/)
|
24
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
25
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
26
|
+
s.require_paths = %w[ lib lib/server lib/client ]
|
27
|
+
|
28
|
+
s.add_dependency 'celluloid', '0.15.2'
|
29
|
+
s.add_development_dependency 'bundler', '~> 1.3'
|
30
|
+
s.add_development_dependency 'rake'
|
31
|
+
end
|
data/dev-pty-screen.gif
ADDED
Binary file
|
data/doc/welcome.txt
ADDED
data/lib/client/app.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
module Options
|
3
|
+
def self.parse!
|
4
|
+
options = OpenStruct.new key_port: 2000, screen_port: 2001,
|
5
|
+
server_host: 'localhost'
|
6
|
+
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.on("-l", "--key_port=val", Integer) { |arg| options.key_port = arg }
|
9
|
+
opts.on("-d", "--screen_port=val", Integer) { |arg| options.screen_port = arg }
|
10
|
+
opts.on("-s", "--server_host=val", String) { |arg| options.server_host = arg }
|
11
|
+
opts.on("-h", "--help") { puts opts; exit }
|
12
|
+
end.parse!
|
13
|
+
options
|
14
|
+
end
|
15
|
+
end
|
data/lib/server/app.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'celluloid'
|
3
|
+
Thread.abort_on_exception = true
|
4
|
+
|
5
|
+
class KeyServer
|
6
|
+
READSIZE = 4096
|
7
|
+
include Celluloid
|
8
|
+
|
9
|
+
def initialize port, callback
|
10
|
+
@port = port
|
11
|
+
@callback = callback
|
12
|
+
end
|
13
|
+
|
14
|
+
# screen_server.listen
|
15
|
+
def listen
|
16
|
+
Thread.new do
|
17
|
+
Socket.tcp_server_loop @port, ®ister
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def register
|
22
|
+
->(socket, client_info) {
|
23
|
+
socket.sync = true
|
24
|
+
Thread.new do
|
25
|
+
loop {
|
26
|
+
key_data = read_key(socket) or break
|
27
|
+
@callback.( key_data )
|
28
|
+
}
|
29
|
+
end
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def read_key(socket)
|
34
|
+
return socket.readpartial( READSIZE )
|
35
|
+
rescue EOFError; disconnected(socket)
|
36
|
+
end
|
37
|
+
private :read_key
|
38
|
+
|
39
|
+
def disconnected(socket)
|
40
|
+
socket_info = Socket.unpack_sockaddr_in(socket.local_address)
|
41
|
+
puts "A key client disconnected: #{socket_info}"
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
module Options
|
3
|
+
def self.parse!
|
4
|
+
# default_key_file = File.join(__dir__, '../', 'tmp/keys')
|
5
|
+
options = OpenStruct.new key_port: 2000, screen_port: 2001,
|
6
|
+
rows: 35, columns: 100
|
7
|
+
|
8
|
+
OptionParser.new do |opts|
|
9
|
+
opts.on("-k", "--key_port=val", Integer) { |arg| options.key_port = arg }
|
10
|
+
opts.on("-s", "--screen_port=val", Integer) { |arg| options.screen_port = arg }
|
11
|
+
opts.on("-r", "--rows=val", Integer) { |arg| options.rows = arg }
|
12
|
+
opts.on("-c", "--columns=val", Integer) { |arg| options.columns = arg }
|
13
|
+
opts.on("-h", "--help") { puts opts; exit }
|
14
|
+
end.parse!
|
15
|
+
options
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'pty'
|
2
|
+
require 'io/console'
|
3
|
+
|
4
|
+
require_relative 'screen_server'
|
5
|
+
require_relative 'key_server'
|
6
|
+
require_relative 'vim_interface'
|
7
|
+
require_relative 'app'
|
8
|
+
|
9
|
+
Thread.abort_on_exception = true
|
10
|
+
|
11
|
+
class PtyServer
|
12
|
+
READSIZE = 4096
|
13
|
+
ENTER_KEY = ?\C-m
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@pty_m, @pty_s = PTY.open
|
17
|
+
@vim_interface = VimInterface.new @pty_m
|
18
|
+
@screen_server = ScreenServer.new App.options.screen_port
|
19
|
+
@key_server = KeyServer.new App.options.key_port, key_callback
|
20
|
+
@pty_s.winsize = [ App.options.rows, App.options.columns ]
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
spawn_vim
|
25
|
+
initialize_pty
|
26
|
+
@screen_server.listen
|
27
|
+
@key_server.listen
|
28
|
+
screen_loop
|
29
|
+
end
|
30
|
+
|
31
|
+
def key_callback
|
32
|
+
->(key){
|
33
|
+
print key
|
34
|
+
@vim_interface << key
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def screen_loop
|
39
|
+
Thread.new do
|
40
|
+
loop {
|
41
|
+
@screen_server.async.write @pty_m.readpartial( READSIZE )
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def spawn_vim
|
47
|
+
spawn("vim", in: @pty_s, out: @pty_s)
|
48
|
+
sleep 0.2 # give it a moment to boot
|
49
|
+
end
|
50
|
+
private :spawn_vim
|
51
|
+
|
52
|
+
# WTH? -- Let me 'splain:
|
53
|
+
# There a difference between the mode that PTY
|
54
|
+
# starts the terminal in, and the mode that terminal
|
55
|
+
# running the server is in.
|
56
|
+
#
|
57
|
+
# This means the cursor moves around the screen on the server
|
58
|
+
# when you press the arrow keys, but when they are transmitted
|
59
|
+
# through the PTY to vim, the escape encoding is different,
|
60
|
+
# this results in vim just honking at you and not moving the cursor.
|
61
|
+
#
|
62
|
+
# By running `tput rmkx` from vim we are setting the PTY to
|
63
|
+
# cursor mode, and ta-dah, the arrows work again.
|
64
|
+
#
|
65
|
+
# We have to go through vim, because there's no instance of the
|
66
|
+
# PTY to talk to (PTY has only class methods) and there's no
|
67
|
+
# running shell on the PTY to send commands to directly, so
|
68
|
+
# we have to use vim's `!` to run `tput`.
|
69
|
+
#
|
70
|
+
# Reference:
|
71
|
+
# http://homes.mpimf-heidelberg.mpg.de/~rohm/computing/mpimf/notes/terminal.html
|
72
|
+
# http://unix.stackexchange.com/questions/73669/what-are-the-characters-printed-when-altarrow-keys-are-pressed
|
73
|
+
#
|
74
|
+
# Also, just for fun, in your terminal, pressing "ctrl+v" followed by
|
75
|
+
# any key will print the key codes, instead of running them. Try it
|
76
|
+
# with the enter/return key, you'll see that it's equal to `^m`. Now type
|
77
|
+
# a command and instead of hitting `enter`, press "ctrl+m". Works just the same.
|
78
|
+
# That is just too cool.
|
79
|
+
#
|
80
|
+
def initialize_pty
|
81
|
+
@vim_interface << ENTER_KEY
|
82
|
+
@vim_interface << ":!tput rmkx"
|
83
|
+
@vim_interface << ENTER_KEY
|
84
|
+
end
|
85
|
+
private :initialize_pty
|
86
|
+
|
87
|
+
|
88
|
+
# def save_key key
|
89
|
+
# File.open(@key_file, 'a') { |f| f.putc key }
|
90
|
+
# end
|
91
|
+
# private :save_key
|
92
|
+
|
93
|
+
|
94
|
+
# def clear_key_file
|
95
|
+
# File.unlink(@key_file) if File.exists?(@key_file)
|
96
|
+
# end
|
97
|
+
# private :clear_key_file
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'celluloid'
|
3
|
+
Thread.abort_on_exception = true
|
4
|
+
|
5
|
+
class ScreenServer
|
6
|
+
include Celluloid
|
7
|
+
|
8
|
+
def initialize port
|
9
|
+
@port = port
|
10
|
+
@sockets = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def listen
|
14
|
+
Thread.new do
|
15
|
+
Socket.tcp_server_loop @port, ®ister
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def register
|
20
|
+
->(socket, client_info) {
|
21
|
+
socket.sync = true
|
22
|
+
@sockets << socket
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
# screen_server.async.write
|
27
|
+
def write update
|
28
|
+
@sockets.each { |s| safe_write(s, update) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def safe_write(socket, update)
|
32
|
+
socket.write update
|
33
|
+
rescue Errno::EPIPE; disconnect(socket)
|
34
|
+
end
|
35
|
+
private :safe_write
|
36
|
+
|
37
|
+
def disconnect(socket)
|
38
|
+
disconnect_message socket
|
39
|
+
@sockets.delete socket
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
private :disconnect
|
43
|
+
|
44
|
+
def disconnect_message(socket)
|
45
|
+
socket_info = Socket.unpack_sockaddr_in(socket.local_address)
|
46
|
+
puts "A screen client disconnected: #{socket_info}"
|
47
|
+
end
|
48
|
+
private :disconnect_message
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
class VimInterface
|
4
|
+
def initialize pty_m
|
5
|
+
@pty_m = pty_m
|
6
|
+
@queue = Queue.new
|
7
|
+
start_worker
|
8
|
+
end
|
9
|
+
|
10
|
+
def push key
|
11
|
+
@queue << key
|
12
|
+
end
|
13
|
+
alias :<< :push
|
14
|
+
|
15
|
+
def start_worker
|
16
|
+
Thread.new do
|
17
|
+
loop { @pty_m << @queue.pop }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/version.rb
ADDED
data/outline.markdown
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require_relative '../../lib/server/key_server.rb'
|
3
|
+
|
4
|
+
describe KeyServer do
|
5
|
+
before do
|
6
|
+
server.listen
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:server_port) { 2002 }
|
10
|
+
let(:client) { Socket.tcp('localhost', server_port) }
|
11
|
+
let(:callback) { ->(k){ @global = k } }
|
12
|
+
let(:server) do
|
13
|
+
KeyServer.new(server_port, callback)
|
14
|
+
end
|
15
|
+
|
16
|
+
context "Sending Screen Updates" do
|
17
|
+
let(:message) { "H" }
|
18
|
+
|
19
|
+
it "should receive the message" do
|
20
|
+
Timeout.timeout(3) do
|
21
|
+
client.write message
|
22
|
+
sleep 0.1
|
23
|
+
expect(@global).to eq(message)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require_relative '../../lib/server/screen_server.rb'
|
3
|
+
|
4
|
+
describe ScreenServer do
|
5
|
+
before do
|
6
|
+
server.listen
|
7
|
+
client
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:server_port) { 2001 }
|
11
|
+
let(:server) { ScreenServer.new(server_port) }
|
12
|
+
let(:client) { Socket.tcp('localhost', server_port) }
|
13
|
+
|
14
|
+
context "Sending Screen Updates" do
|
15
|
+
before do
|
16
|
+
server.async.write message
|
17
|
+
end
|
18
|
+
let(:message) { "H" }
|
19
|
+
|
20
|
+
it "should receive the message" do
|
21
|
+
Timeout.timeout(3) do
|
22
|
+
expect(client.getc).to eq(message)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
# subject { client }
|
26
|
+
# its(:getc) { should eq("H") }
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dev-pty-screen
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark Lorenz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: celluloid
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.15.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.15.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: |2
|
56
|
+
One user runs the server from with the resposity that you want to work one.
|
57
|
+
Clients (including the one who started the server) connect, and can
|
58
|
+
interact with the VIM session.
|
59
|
+
email: markjlorenz@gmail.com
|
60
|
+
executables:
|
61
|
+
- dev-pty-client
|
62
|
+
- dev-pty-server
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- .ruby-version
|
68
|
+
- Gemfile
|
69
|
+
- Gemfile.lock
|
70
|
+
- LICENSE.txt
|
71
|
+
- README.markdown
|
72
|
+
- Rakefile
|
73
|
+
- bin/dev-pty-client
|
74
|
+
- bin/dev-pty-server
|
75
|
+
- dev-pty-screen.gemspec
|
76
|
+
- dev-pty-screen.gif
|
77
|
+
- doc/welcome.txt
|
78
|
+
- lib/client/app.rb
|
79
|
+
- lib/client/options.rb
|
80
|
+
- lib/server/app.rb
|
81
|
+
- lib/server/key_server.rb
|
82
|
+
- lib/server/options.rb
|
83
|
+
- lib/server/pty_server.rb
|
84
|
+
- lib/server/screen_server.rb
|
85
|
+
- lib/server/vim_interface.rb
|
86
|
+
- lib/version.rb
|
87
|
+
- outline.markdown
|
88
|
+
- spec/server/key_server_spec.rb
|
89
|
+
- spec/server/pty_server_spec.rb
|
90
|
+
- spec/server/screen_server_spec.rb
|
91
|
+
homepage: http://github.com/dapplebeforedawn
|
92
|
+
licenses:
|
93
|
+
- MIT
|
94
|
+
metadata: {}
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
- lib/server
|
100
|
+
- lib/client
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.0.6
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: VIM screen sharing as the neckbeards intended
|
117
|
+
test_files:
|
118
|
+
- spec/server/key_server_spec.rb
|
119
|
+
- spec/server/pty_server_spec.rb
|
120
|
+
- spec/server/screen_server_spec.rb
|