teamocil 0.3.7 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +8 -3
- data/examples/simple-four-splits.yml +1 -0
- data/lib/teamocil.rb +2 -1
- data/lib/teamocil/cli.rb +6 -1
- data/lib/teamocil/error.rb +6 -0
- data/lib/teamocil/layout/session.rb +2 -3
- data/lib/teamocil/layout/split.rb +4 -2
- data/lib/teamocil/layout/window.rb +7 -3
- data/spec/fixtures/layouts.yml +8 -0
- data/spec/layout_spec.rb +43 -1
- metadata +5 -4
data/README.md
CHANGED
@@ -51,6 +51,7 @@ If you are not using a top-level `session` key, then the first key of your layou
|
|
51
51
|
* `name` (the name that will appear in `tmux` statusbar)
|
52
52
|
* `root` (the directory in which every split will be created)
|
53
53
|
* `filters` (a hash of `before` and `after` commands to run for each split)
|
54
|
+
* `clear` (whether or not to prepend a `clear` command before the `before` filters list)
|
54
55
|
* `splits` (an array of split items)
|
55
56
|
* `options` (a hash of tmux options, see `man tmux` for a list)
|
56
57
|
|
@@ -59,6 +60,7 @@ If you are not using a top-level `session` key, then the first key of your layou
|
|
59
60
|
```yaml
|
60
61
|
windows:
|
61
62
|
- name: "my-first-window"
|
63
|
+
clear: true
|
62
64
|
options:
|
63
65
|
synchronize-panes: true
|
64
66
|
root: "~/Projects/foo-www"
|
@@ -87,7 +89,8 @@ Every window must define an array of splits that will be created within it. A ve
|
|
87
89
|
* `cmd` (the commands to initially execute in the split)
|
88
90
|
* `width` (the split width, in percentage)
|
89
91
|
* `height` (the split width, in percentage)
|
90
|
-
* `target` (the split to set focus on
|
92
|
+
* `target` (the split to set focus on before creating the current one)
|
93
|
+
* `focus` (the split to set focus on after initializing all the splits for a window)
|
91
94
|
|
92
95
|
#### Example
|
93
96
|
|
@@ -101,6 +104,7 @@ windows:
|
|
101
104
|
splits:
|
102
105
|
- cmd: "git status"
|
103
106
|
- cmd: "bundle exec rails server --port 4000"
|
107
|
+
focus: true
|
104
108
|
width: 50
|
105
109
|
- cmd:
|
106
110
|
- "sudo service memcached start"
|
@@ -185,9 +189,9 @@ To get autocompletion when typing `teamocil <Tab>` in a zsh session, add this li
|
|
185
189
|
compctl -g '~/.teamocil/*(:t:r)' teamocil
|
186
190
|
```
|
187
191
|
|
188
|
-
### ERB
|
192
|
+
### ERB support
|
189
193
|
|
190
|
-
You can use ERB in your
|
194
|
+
You can use ERB in your layouts. For example, you can use an environment variable in a layout like so:
|
191
195
|
|
192
196
|
```yaml
|
193
197
|
windows:
|
@@ -208,6 +212,7 @@ Feel free to contribute and submit issues/pull requests [on GitHub](https://gith
|
|
208
212
|
|
209
213
|
* Samuel Garneau ([garno](https://github.com/garno))
|
210
214
|
* Jimmy Bourassa ([jbourassa](https://github.com/jbourassa))
|
215
|
+
* Brandon Dimcheff ([bdimcheff](https://github.com/bdimcheff))
|
211
216
|
|
212
217
|
Take a look at the `spec` folder before you do, and make sure `bundle exec rake spec` passes after your modifications :)
|
213
218
|
|
data/lib/teamocil.rb
CHANGED
data/lib/teamocil/cli.rb
CHANGED
@@ -36,7 +36,12 @@ module Teamocil
|
|
36
36
|
yaml = ERB.new(File.read(file)).result
|
37
37
|
|
38
38
|
@layout = Teamocil::Layout.new(YAML.load(yaml), @options)
|
39
|
-
|
39
|
+
|
40
|
+
begin
|
41
|
+
@layout.compile!
|
42
|
+
rescue Teamocil::Error::LayoutError => e
|
43
|
+
bail e.message
|
44
|
+
end
|
40
45
|
@layout.execute_commands(@layout.generate_commands)
|
41
46
|
end
|
42
47
|
end # }}}
|
@@ -10,7 +10,8 @@ module Teamocil
|
|
10
10
|
# @param options [Hash] the options, mostly passed by the CLI
|
11
11
|
# @param attrs [Hash] the session data from the layout file
|
12
12
|
def initialize(options, attrs={}) # {{{
|
13
|
-
|
13
|
+
raise Teamocil::Error::LayoutError.new("You must specify a `windows` or `session` key for your layout.") unless attrs["windows"]
|
14
|
+
@name = attrs["name"] || "teamocil-session"
|
14
15
|
@windows = attrs["windows"].each_with_index.map { |window, window_index| Window.new(self, window_index, window) }
|
15
16
|
@options = options
|
16
17
|
end # }}}
|
@@ -22,8 +23,6 @@ module Teamocil
|
|
22
23
|
commands = []
|
23
24
|
commands << "tmux rename-session \"#{@name}\"" unless @name.nil?
|
24
25
|
commands << @windows.map(&:generate_commands)
|
25
|
-
commands << "tmux select-pane -t 0"
|
26
|
-
commands
|
27
26
|
end # }}}
|
28
27
|
|
29
28
|
end
|
@@ -3,7 +3,7 @@ module Teamocil
|
|
3
3
|
|
4
4
|
# This class represents a split within a tmux window
|
5
5
|
class Split
|
6
|
-
attr_reader :width, :height, :cmd, :index, :target
|
6
|
+
attr_reader :width, :height, :cmd, :index, :target, :focus
|
7
7
|
|
8
8
|
# Initialize a new tmux split
|
9
9
|
#
|
@@ -11,10 +11,12 @@ module Teamocil
|
|
11
11
|
# @param index [Fixnnum] the split index
|
12
12
|
# @param attrs [Hash] the split data from the layout file
|
13
13
|
def initialize(window, index, attrs={}) # {{{
|
14
|
+
raise Teamocil::Error::LayoutError.new("You cannot have empty splits") if attrs.nil?
|
14
15
|
@height = attrs["height"]
|
15
16
|
@width = attrs["width"]
|
16
17
|
@cmd = attrs["cmd"]
|
17
18
|
@target = attrs["target"]
|
19
|
+
@focus = attrs["focus"] || false
|
18
20
|
|
19
21
|
@window = window
|
20
22
|
@index = index
|
@@ -41,7 +43,7 @@ module Teamocil
|
|
41
43
|
end
|
42
44
|
|
43
45
|
# Wrap all commands around filters
|
44
|
-
@cmd = [@window.filters["before"]] + [@cmd] + [@window.filters["after"]]
|
46
|
+
@cmd = [@window.filters["before"]] + [@window.clear] + [@cmd] + [@window.filters["after"]]
|
45
47
|
|
46
48
|
# If a `root` key exist, start each split in this directory
|
47
49
|
@cmd.unshift "cd \"#{@window.root}\"" unless @window.root.nil?
|
@@ -3,7 +3,7 @@ module Teamocil
|
|
3
3
|
|
4
4
|
# This class represents a window within tmux
|
5
5
|
class Window
|
6
|
-
attr_reader :filters, :root, :splits, :options, :index, :name
|
6
|
+
attr_reader :filters, :root, :splits, :options, :index, :name, :clear
|
7
7
|
|
8
8
|
# Initialize a new tmux window
|
9
9
|
#
|
@@ -11,11 +11,13 @@ module Teamocil
|
|
11
11
|
# @param index [Fixnnum] the window index
|
12
12
|
# @param attrs [Hash] the window data from the layout file
|
13
13
|
def initialize(session, index, attrs={}) # {{{
|
14
|
-
@name = attrs["name"]
|
15
|
-
@root = attrs["root"]
|
14
|
+
@name = attrs["name"] || "teamocil-window-#{index+1}"
|
15
|
+
@root = attrs["root"] || "."
|
16
|
+
@clear = attrs["clear"] == true ? "clear" : nil
|
16
17
|
@options = attrs["options"] || {}
|
17
18
|
|
18
19
|
@splits = attrs["splits"] || []
|
20
|
+
raise Teamocil::Error::LayoutError.new("You must specify a `splits` key for every window.") if @splits.empty?
|
19
21
|
@splits = @splits.each_with_index.map { |split, split_index| Split.new(self, split_index, split) }
|
20
22
|
|
21
23
|
@filters = attrs["filters"] || {}
|
@@ -46,6 +48,8 @@ module Teamocil
|
|
46
48
|
commands << "tmux set-window-option #{option} #{value}"
|
47
49
|
end
|
48
50
|
|
51
|
+
commands << "tmux select-pane -t #{@splits.map(&:focus).index(true) || 0}"
|
52
|
+
|
49
53
|
commands
|
50
54
|
end # }}}
|
51
55
|
|
data/spec/fixtures/layouts.yml
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
two-windows:
|
3
3
|
windows:
|
4
4
|
- name: "foo"
|
5
|
+
clear: true
|
5
6
|
root: "/foo"
|
6
7
|
splits:
|
7
8
|
- cmd: "echo 'foo'"
|
@@ -15,6 +16,7 @@ two-windows:
|
|
15
16
|
- "echo 'bar in an array'"
|
16
17
|
target: bottom-right
|
17
18
|
- cmd: "echo 'bar again'"
|
19
|
+
focus: true
|
18
20
|
width: 50
|
19
21
|
|
20
22
|
# Simple two windows layout with filters
|
@@ -39,5 +41,11 @@ three-windows-within-a-session:
|
|
39
41
|
name: "my awesome session"
|
40
42
|
windows:
|
41
43
|
- name: "first window"
|
44
|
+
splits:
|
45
|
+
- cmd: "echo 'foo'"
|
42
46
|
- name: "second window"
|
47
|
+
splits:
|
48
|
+
- cmd: "echo 'foo'"
|
43
49
|
- name: "third window"
|
50
|
+
splits:
|
51
|
+
- cmd: "echo 'foo'"
|
data/spec/layout_spec.rb
CHANGED
@@ -8,6 +8,23 @@ describe Teamocil::Layout do
|
|
8
8
|
@layout = Teamocil::Layout.new(layouts["two-windows"], {})
|
9
9
|
end # }}}
|
10
10
|
|
11
|
+
describe "handles bad layouts" do # {{{
|
12
|
+
it "does not compile without windows" do # {{{
|
13
|
+
@layout = Teamocil::Layout.new({ "name" => "foo" }, {})
|
14
|
+
lambda { @layout.compile! }.should raise_error Teamocil::Error::LayoutError
|
15
|
+
end # }}}
|
16
|
+
|
17
|
+
it "does not compile without splits" do # {{{
|
18
|
+
@layout = Teamocil::Layout.new({ "windows" => [{ "name" => "foo" }] }, {})
|
19
|
+
lambda { @layout.compile! }.should raise_error Teamocil::Error::LayoutError
|
20
|
+
end # }}}
|
21
|
+
|
22
|
+
it "does not compile with empty splits" do # {{{
|
23
|
+
@layout = Teamocil::Layout.new({ "windows" => [{ "name" => "foo", "splits" => [nil, nil] }] }, {})
|
24
|
+
lambda { @layout.compile! }.should raise_error Teamocil::Error::LayoutError
|
25
|
+
end # }}}
|
26
|
+
end # }}}
|
27
|
+
|
11
28
|
describe "windows" do # {{{
|
12
29
|
it "creates windows" do # {{{
|
13
30
|
session = @layout.compile!
|
@@ -27,6 +44,12 @@ describe Teamocil::Layout do
|
|
27
44
|
session.windows[0].root.should == "/foo"
|
28
45
|
session.windows[1].root.should == "/bar"
|
29
46
|
end # }}}
|
47
|
+
|
48
|
+
it "creates windows with clear option" do # {{{
|
49
|
+
session = @layout.compile!
|
50
|
+
session.windows[0].clear.should == "clear"
|
51
|
+
session.windows[1].clear.should be_nil
|
52
|
+
end # }}}
|
30
53
|
end # }}}
|
31
54
|
|
32
55
|
describe "splits" do # {{{
|
@@ -54,6 +77,12 @@ describe Teamocil::Layout do
|
|
54
77
|
session.windows.last.splits[0].cmd.first.should == "echo 'bar'"
|
55
78
|
session.windows.last.splits[0].cmd.last.should == "echo 'bar in an array'"
|
56
79
|
end # }}}
|
80
|
+
|
81
|
+
it "handles focused splits" do # {{{
|
82
|
+
session = @layout.compile!
|
83
|
+
session.windows.last.splits[1].focus.should be_true
|
84
|
+
session.windows.last.splits[0].focus.should be_false
|
85
|
+
end # }}}
|
57
86
|
end # }}}
|
58
87
|
|
59
88
|
describe "filters" do # {{{
|
@@ -109,12 +138,25 @@ describe Teamocil::Layout do
|
|
109
138
|
@layout = Teamocil::Layout.new(layouts["two-windows"], {})
|
110
139
|
end # }}}
|
111
140
|
|
112
|
-
it "should generate commands" do #{{{
|
141
|
+
it "should generate split commands" do #{{{
|
113
142
|
session = @layout.compile!
|
114
143
|
commands = session.windows.last.splits[0].generate_commands
|
115
144
|
commands.length.should == 2
|
116
145
|
commands.first.should == "tmux send-keys -t 0 \"export TEAMOCIL=1 && cd \"/bar\" && echo 'bar' && echo 'bar in an array'\""
|
117
146
|
commands.last.should == "tmux send-keys -t 0 Enter"
|
147
|
+
|
148
|
+
session = @layout.compile!
|
149
|
+
commands = session.windows.first.splits[0].generate_commands
|
150
|
+
commands.length.should == 2
|
151
|
+
commands.first.should == "tmux send-keys -t 0 \"export TEAMOCIL=1 && cd \"/foo\" && clear && echo 'foo'\""
|
152
|
+
commands.last.should == "tmux send-keys -t 0 Enter"
|
153
|
+
end # }}}
|
154
|
+
|
155
|
+
it "should generate window commands" do #{{{
|
156
|
+
session = @layout.compile!
|
157
|
+
commands = session.windows.last.generate_commands
|
158
|
+
commands.first.should == "tmux new-window -n \"bar\""
|
159
|
+
commands.last.should == "tmux select-pane -t 1"
|
118
160
|
end # }}}
|
119
161
|
end
|
120
162
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: teamocil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-27 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- examples/simple-two-vertical-splits.yml
|
98
98
|
- lib/teamocil.rb
|
99
99
|
- lib/teamocil/cli.rb
|
100
|
+
- lib/teamocil/error.rb
|
100
101
|
- lib/teamocil/layout.rb
|
101
102
|
- lib/teamocil/layout/session.rb
|
102
103
|
- lib/teamocil/layout/split.rb
|
@@ -126,7 +127,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
127
|
version: '0'
|
127
128
|
segments:
|
128
129
|
- 0
|
129
|
-
hash:
|
130
|
+
hash: -4311130867002785670
|
130
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
132
|
none: false
|
132
133
|
requirements:
|
@@ -135,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
136
|
version: '0'
|
136
137
|
segments:
|
137
138
|
- 0
|
138
|
-
hash:
|
139
|
+
hash: -4311130867002785670
|
139
140
|
requirements: []
|
140
141
|
rubyforge_project:
|
141
142
|
rubygems_version: 1.8.18
|