teamocil 0.1.11 → 0.2
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.
- 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
|