teamocil 0.1.11 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/lib/teamocil.rb +1 -1
- data/lib/teamocil/cli.rb +2 -1
- data/lib/teamocil/layout.rb +139 -66
- data/spec/fixtures/layouts.yml +22 -1
- data/spec/layout_spec.rb +52 -4
- metadata +4 -5
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/lib/teamocil.rb
CHANGED
data/lib/teamocil/cli.rb
CHANGED
@@ -26,7 +26,8 @@ module Teamocil
|
|
26
26
|
bail "There is no file \"#{file}\"" unless File.exists?(file)
|
27
27
|
parsed_layout = YAML.load_file(file)
|
28
28
|
layout = Teamocil::Layout.new(parsed_layout, @options)
|
29
|
-
layout.
|
29
|
+
layout.compile!
|
30
|
+
layout.execute_commands(layout.generate_commands)
|
30
31
|
end
|
31
32
|
end # }}}
|
32
33
|
|
data/lib/teamocil/layout.rb
CHANGED
@@ -1,7 +1,137 @@
|
|
1
1
|
module Teamocil
|
2
|
-
|
2
|
+
|
3
|
+
# This class act as a wrapper around a tmux YAML layout file
|
3
4
|
class Layout
|
4
5
|
|
6
|
+
# This class represents a session within tmux
|
7
|
+
class Session
|
8
|
+
attr_reader :options, :windows, :name
|
9
|
+
|
10
|
+
# Initialize a new tmux session
|
11
|
+
#
|
12
|
+
# @param options [Hash] the options, mostly passed by the CLI
|
13
|
+
# @param attrs [Hash] the session data from the layout file
|
14
|
+
def initialize(options, attrs={}) # {{{
|
15
|
+
@name = attrs["name"]
|
16
|
+
@windows = attrs["windows"].each_with_index.map { |window, index| Window.new(self, index, window) }
|
17
|
+
@options = options
|
18
|
+
end # }}}
|
19
|
+
|
20
|
+
# Generate commands to send to tmux
|
21
|
+
#
|
22
|
+
# @return [Array]
|
23
|
+
def generate_commands # {{{
|
24
|
+
commands = []
|
25
|
+
commands << "tmux rename-session \"#{@name}\"" unless @name.nil?
|
26
|
+
commands << @windows.map(&:generate_commands)
|
27
|
+
commands << "tmux select-pane -t 0"
|
28
|
+
commands
|
29
|
+
end # }}}
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
# This class represents a window within tmux
|
34
|
+
class Window
|
35
|
+
attr_reader :filters, :root, :splits, :options, :index, :name
|
36
|
+
|
37
|
+
# Initialize a new tmux window
|
38
|
+
#
|
39
|
+
# @param session [Session] the session where the window is initialized
|
40
|
+
# @param index [Fixnnum] the window index
|
41
|
+
# @param attrs [Hash] the window data from the layout file
|
42
|
+
def initialize(session, index, attrs={}) # {{{
|
43
|
+
@name = attrs["name"]
|
44
|
+
@root = attrs["root"]
|
45
|
+
@options = attrs["options"]
|
46
|
+
@filters = attrs["filters"]
|
47
|
+
@splits = attrs["splits"].each_with_index.map { |split, index| Split.new(self, index, split) }
|
48
|
+
@index = index
|
49
|
+
@session = session
|
50
|
+
|
51
|
+
@options ||= {}
|
52
|
+
@filters ||= {}
|
53
|
+
@filters["before"] ||= []
|
54
|
+
@filters["after"] ||= []
|
55
|
+
end # }}}
|
56
|
+
|
57
|
+
# Generate commands to send to tmux
|
58
|
+
#
|
59
|
+
# @return [Array]
|
60
|
+
def generate_commands # {{{
|
61
|
+
commands = []
|
62
|
+
|
63
|
+
if @session.options.include?(:here) and @index == 0
|
64
|
+
commands << "tmux rename-window \"#{@name}\""
|
65
|
+
else
|
66
|
+
commands << "tmux new-window -n \"#{@name}\""
|
67
|
+
end
|
68
|
+
|
69
|
+
commands << @splits.map(&:generate_commands)
|
70
|
+
|
71
|
+
@options.each_pair do |option, value|
|
72
|
+
value = "on" if value === true
|
73
|
+
value = "off" if value === false
|
74
|
+
commands << "tmux set-window-option #{option} #{value}"
|
75
|
+
end
|
76
|
+
|
77
|
+
commands
|
78
|
+
end # }}}
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
# This class represents a split within a tmux window
|
83
|
+
class Split
|
84
|
+
attr_reader :width, :height, :cmd, :index, :target
|
85
|
+
|
86
|
+
# Initialize a new tmux split
|
87
|
+
#
|
88
|
+
# @param session [Session] the window where the split is initialized
|
89
|
+
# @param index [Fixnnum] the split index
|
90
|
+
# @param attrs [Hash] the split data from the layout file
|
91
|
+
def initialize(window, index, attrs={}) # {{{
|
92
|
+
@height = attrs["height"]
|
93
|
+
@width = attrs["width"]
|
94
|
+
@cmd = attrs["cmd"]
|
95
|
+
@target = attrs["target"]
|
96
|
+
@window = window
|
97
|
+
@index = index
|
98
|
+
end # }}}
|
99
|
+
|
100
|
+
# Generate commands to send to tmux
|
101
|
+
#
|
102
|
+
# @return [Array]
|
103
|
+
def generate_commands # {{{
|
104
|
+
commands = []
|
105
|
+
|
106
|
+
# Is it a vertical or horizontal split?
|
107
|
+
unless @index == 0
|
108
|
+
if !@width.nil?
|
109
|
+
commands << "tmux split-window -h -p #{@width}"
|
110
|
+
elsif !@height.nil?
|
111
|
+
commands << "tmux split-window -p #{@height}"
|
112
|
+
else
|
113
|
+
commands << "tmux split-window"
|
114
|
+
end
|
115
|
+
commands << " -t #{@target}" unless @target.nil?
|
116
|
+
end
|
117
|
+
|
118
|
+
# Wrap all commands around filters
|
119
|
+
@cmd = [@window.filters["before"]] + [@cmd] + [@window.filters["after"]]
|
120
|
+
|
121
|
+
# If a `root` key exist, start each split in this directory
|
122
|
+
@cmd.unshift "cd \"#{@window.root}\"" unless @window.root.nil?
|
123
|
+
|
124
|
+
# Execute each split command
|
125
|
+
@cmd.flatten.compact.each do |command|
|
126
|
+
commands << "tmux send-keys -t #{@index} \"#{command}\""
|
127
|
+
commands << "tmux send-keys -t #{@index} Enter"
|
128
|
+
end
|
129
|
+
|
130
|
+
commands
|
131
|
+
end # }}}
|
132
|
+
|
133
|
+
end
|
134
|
+
|
5
135
|
# Initialize a new layout from a hash
|
6
136
|
#
|
7
137
|
# @param layout [Hash] the parsed layout
|
@@ -11,79 +141,22 @@ module Teamocil
|
|
11
141
|
@options = options
|
12
142
|
end # }}}
|
13
143
|
|
14
|
-
# Generate commands and sends them to tmux
|
15
|
-
def to_tmux # {{{
|
16
|
-
commands = generate_commands
|
17
|
-
execute_commands(commands)
|
18
|
-
end # }}}
|
19
|
-
|
20
144
|
# Generate tmux commands based on the data found in the layout file
|
21
145
|
#
|
22
146
|
# @return [Array] an array of shell commands to send
|
23
147
|
def generate_commands # {{{
|
24
|
-
|
148
|
+
@session.generate_commands
|
149
|
+
end # }}}
|
25
150
|
|
26
|
-
|
151
|
+
# Compile the layout into objects
|
152
|
+
#
|
153
|
+
# @return [Session]
|
154
|
+
def compile! # {{{
|
27
155
|
if @layout["session"].nil?
|
28
|
-
|
156
|
+
@session = Session.new @options, "windows" => @layout["windows"]
|
29
157
|
else
|
30
|
-
|
31
|
-
windows = @layout["session"]["windows"]
|
32
|
-
end
|
33
|
-
|
34
|
-
windows.each_with_index do |window, window_index|
|
35
|
-
|
36
|
-
# Create a new window unless we used the `--here` option
|
37
|
-
if @options.include?(:here) and window_index == 0
|
38
|
-
output << "tmux rename-window \"#{window["name"]}\""
|
39
|
-
else
|
40
|
-
output << "tmux new-window -n \"#{window["name"]}\""
|
41
|
-
end
|
42
|
-
|
43
|
-
# Make sure we have all the keys we need
|
44
|
-
window["options"] ||= {}
|
45
|
-
window["filters"] ||= {}
|
46
|
-
window["filters"]["before"] ||= []
|
47
|
-
window["filters"]["after"] ||= []
|
48
|
-
|
49
|
-
# Create splits
|
50
|
-
window["splits"].each_with_index do |split, split_index|
|
51
|
-
unless split_index == 0
|
52
|
-
if split.include?("width")
|
53
|
-
cmd = "tmux split-window -h -p #{split["width"]}"
|
54
|
-
elsif split.include?("height")
|
55
|
-
cmd = "tmux split-window -p #{split["height"]}"
|
56
|
-
else
|
57
|
-
cmd = "tmux split-window"
|
58
|
-
end
|
59
|
-
cmd << " -t #{split["target"]}" if split.include?("target")
|
60
|
-
output << cmd
|
61
|
-
end
|
62
|
-
|
63
|
-
# Wrap all commands around filters
|
64
|
-
split["cmd"] = [window["filters"]["before"]] + [split["cmd"]] + [window["filters"]["after"]]
|
65
|
-
|
66
|
-
# If a `root` key exist, start each split in this directory
|
67
|
-
split["cmd"].unshift "cd \"#{window["root"]}\"" if window.include?("root")
|
68
|
-
|
69
|
-
# Execute each split command
|
70
|
-
split["cmd"].flatten.compact.each do |command|
|
71
|
-
output << "tmux send-keys -t #{split_index} \"#{command}\""
|
72
|
-
output << "tmux send-keys -t #{split_index} Enter"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Set tmux options
|
77
|
-
window["options"].each_pair do |option, value|
|
78
|
-
value = "on" if value === true
|
79
|
-
value = "off" if value === false
|
80
|
-
output << "tmux set-window-option #{option} #{value}"
|
81
|
-
end
|
82
|
-
|
158
|
+
@session = Session.new @options, @layout["session"]
|
83
159
|
end
|
84
|
-
|
85
|
-
# Set the focus in the first split
|
86
|
-
output << "tmux select-pane -t 0"
|
87
160
|
end # }}}
|
88
161
|
|
89
162
|
# Execute each command in the shell
|
data/spec/fixtures/layouts.yml
CHANGED
@@ -2,12 +2,33 @@
|
|
2
2
|
two-windows:
|
3
3
|
windows:
|
4
4
|
- name: "foo"
|
5
|
+
root: "/foo"
|
5
6
|
splits:
|
6
7
|
- cmd: "echo 'foo'"
|
7
8
|
- cmd: "echo 'foo again'"
|
8
9
|
width: 50
|
9
10
|
- name: "bar"
|
11
|
+
root: "/bar"
|
10
12
|
splits:
|
11
|
-
- cmd:
|
13
|
+
- cmd:
|
14
|
+
- "echo 'bar'"
|
15
|
+
- "echo 'bar in an array'"
|
12
16
|
- cmd: "echo 'bar again'"
|
13
17
|
width: 50
|
18
|
+
|
19
|
+
# Simple two windows layout with filters
|
20
|
+
two-windows-with-filters:
|
21
|
+
windows:
|
22
|
+
- name: "foo"
|
23
|
+
root: "/foo"
|
24
|
+
filters:
|
25
|
+
before:
|
26
|
+
- "echo first before filter"
|
27
|
+
- "echo second before filter"
|
28
|
+
after:
|
29
|
+
- "echo first after filter"
|
30
|
+
- "echo second after filter"
|
31
|
+
splits:
|
32
|
+
- cmd: "echo 'foo'"
|
33
|
+
- cmd: "echo 'foo again'"
|
34
|
+
width: 50
|
data/spec/layout_spec.rb
CHANGED
@@ -1,12 +1,60 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "spec_helper.rb")
|
2
2
|
|
3
3
|
describe Teamocil::Layout do
|
4
|
+
|
4
5
|
context "initializing" do
|
6
|
+
end
|
7
|
+
|
8
|
+
context "compiling" do
|
9
|
+
|
10
|
+
before :each do # {{{
|
11
|
+
@layout = Teamocil::Layout.new(layouts["two-windows"], {})
|
12
|
+
end # }}}
|
13
|
+
|
14
|
+
it "creates windows with names" do # {{{
|
15
|
+
session = @layout.compile!
|
16
|
+
session.windows[0].name.should == "foo"
|
17
|
+
session.windows[1].name.should == "bar"
|
18
|
+
end # }}}
|
19
|
+
|
20
|
+
it "creates windows with root paths" do # {{{
|
21
|
+
session = @layout.compile!
|
22
|
+
session.windows[0].root.should == "/foo"
|
23
|
+
session.windows[1].root.should == "/bar"
|
24
|
+
end # }}}
|
25
|
+
|
26
|
+
it "creates splits with dimensions" do # {{{
|
27
|
+
session = @layout.compile!
|
28
|
+
session.windows.first.splits[0].width.should == nil
|
29
|
+
session.windows.first.splits[1].width.should == 50
|
30
|
+
end # }}}
|
31
|
+
|
32
|
+
it "creates splits with commands specified in strings" do # {{{
|
33
|
+
session = @layout.compile!
|
34
|
+
session.windows.first.splits[0].cmd.should == "echo 'foo'"
|
35
|
+
end # }}}
|
36
|
+
|
37
|
+
it "creates splits with commands specified in an array" do # {{{
|
38
|
+
session = @layout.compile!
|
39
|
+
session.windows.last.splits[0].cmd.length.should == 2
|
40
|
+
session.windows.last.splits[0].cmd.first.should == "echo 'bar'"
|
41
|
+
session.windows.last.splits[0].cmd.last.should == "echo 'bar in an array'"
|
42
|
+
end # }}}
|
43
|
+
|
44
|
+
it "creates windows with before filters" do # {{{
|
45
|
+
layout = Teamocil::Layout.new(layouts["two-windows-with-filters"], {})
|
46
|
+
session = layout.compile!
|
47
|
+
session.windows.first.filters["before"].length.should == 2
|
48
|
+
session.windows.first.filters["before"].first.should == "echo first before filter"
|
49
|
+
session.windows.first.filters["before"].last.should == "echo second before filter"
|
50
|
+
end # }}}
|
5
51
|
|
6
|
-
it "
|
7
|
-
layout = Teamocil::Layout.new(layouts["two-windows"], {})
|
8
|
-
|
9
|
-
|
52
|
+
it "creates windows with after filters" do # {{{
|
53
|
+
layout = Teamocil::Layout.new(layouts["two-windows-with-filters"], {})
|
54
|
+
session = layout.compile!
|
55
|
+
session.windows.first.filters["after"].length.should == 2
|
56
|
+
session.windows.first.filters["after"].first.should == "echo first after filter"
|
57
|
+
session.windows.first.filters["after"].last.should == "echo second after filter"
|
10
58
|
end # }}}
|
11
59
|
|
12
60
|
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: teamocil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
|
10
|
-
version: 0.1.11
|
8
|
+
- 2
|
9
|
+
version: "0.2"
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- "R\xC3\xA9mi Pr\xC3\xA9vost"
|
@@ -15,7 +14,7 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2011-10-
|
17
|
+
date: 2011-10-23 00:00:00 Z
|
19
18
|
dependencies:
|
20
19
|
- !ruby/object:Gem::Dependency
|
21
20
|
name: rake
|