tmuxinator 0.8.1 → 0.9.0
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 +4 -4
- data/completion/mux.fish +1 -1
- data/completion/tmuxinator.bash +1 -0
- data/completion/tmuxinator.fish +2 -0
- data/completion/tmuxinator.zsh +1 -0
- data/lib/tmuxinator/assets/sample.yml +7 -1
- data/lib/tmuxinator/assets/template.erb +9 -5
- data/lib/tmuxinator/assets/wemux_template.erb +9 -5
- data/lib/tmuxinator/cli.rb +10 -11
- data/lib/tmuxinator/config.rb +5 -5
- data/lib/tmuxinator/pane.rb +0 -4
- data/lib/tmuxinator/project.rb +37 -2
- data/lib/tmuxinator/version.rb +1 -1
- data/lib/tmuxinator/window.rb +27 -10
- data/spec/factories/projects.rb +8 -0
- data/spec/fixtures/noroot.yml +5 -0
- data/spec/fixtures/sample.deprecations.yml +3 -0
- data/spec/lib/tmuxinator/cli_spec.rb +9 -8
- data/spec/lib/tmuxinator/config_spec.rb +10 -10
- data/spec/lib/tmuxinator/project_spec.rb +50 -15
- data/spec/lib/tmuxinator/window_spec.rb +157 -33
- data/spec/matchers/pane_matcher.rb +44 -0
- data/spec/spec_helper.rb +3 -0
- metadata +7 -5
- data/bin/mux +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4701d5ffcbc531c162e257f79c3f3399e106ec4
|
4
|
+
data.tar.gz: 94774dea4bbad7cfbc17f16d9428cd85061e2b5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fac94b03868d51bfac62e4205b91b4695a97d686d46759a09df7e33144e415b100b9b72984f7c0fd7d0146a27ac21c630d97729769e137047d0253ecf16afaa7
|
7
|
+
data.tar.gz: d9833164fd80716d76f19269f0eb07d424b57e788a2fe70f6c31c2a7f74130285a1a332e2b1401c2026a9a696afaa76cb76db7fa05e4934a7391912170e00e42
|
data/completion/mux.fish
CHANGED
@@ -1 +1 @@
|
|
1
|
-
tmuxinator.fish
|
1
|
+
completion/tmuxinator.fish
|
data/completion/tmuxinator.bash
CHANGED
data/completion/tmuxinator.fish
CHANGED
@@ -20,3 +20,5 @@ complete -f -c $__fish_tmuxinator_program_cmd -n '__fish_tmuxinator_using_comman
|
|
20
20
|
complete -f -c $__fish_tmuxinator_program_cmd -n '__fish_tmuxinator_using_command open' -a "(__fish_tmuxinator_program completions open)"
|
21
21
|
complete -f -c $__fish_tmuxinator_program_cmd -n '__fish_tmuxinator_using_command copy' -a "(__fish_tmuxinator_program completions copy)"
|
22
22
|
complete -f -c $__fish_tmuxinator_program_cmd -n '__fish_tmuxinator_using_command delete' -a "(__fish_tmuxinator_program completions delete)"
|
23
|
+
|
24
|
+
abbr --add mux "tmuxinator"
|
data/completion/tmuxinator.zsh
CHANGED
@@ -19,7 +19,10 @@ root: ~/
|
|
19
19
|
# tmux_command: byobu
|
20
20
|
|
21
21
|
# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used.
|
22
|
-
# startup_window:
|
22
|
+
# startup_window: editor
|
23
|
+
|
24
|
+
# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used.
|
25
|
+
# startup_pane: 1
|
23
26
|
|
24
27
|
# Controls whether the tmux session should be attached to automatically. Defaults to true.
|
25
28
|
# attach: false
|
@@ -30,6 +33,9 @@ root: ~/
|
|
30
33
|
windows:
|
31
34
|
- editor:
|
32
35
|
layout: main-vertical
|
36
|
+
# Synchronize all panes of this window, can be enabled before or after the pane commands run.
|
37
|
+
# 'before' represents legacy functionality and will be deprecated in a future release, in favour of 'after'
|
38
|
+
# synchronize: after
|
33
39
|
panes:
|
34
40
|
- vim
|
35
41
|
- guard
|
@@ -34,6 +34,9 @@ unset RBENV_DIR
|
|
34
34
|
<% windows.each do |window| %>
|
35
35
|
|
36
36
|
# Window "<%= window.name %>"
|
37
|
+
<% if window.synchronize_before? %>
|
38
|
+
<%= window.tmux_synchronize_panes %>
|
39
|
+
<% end %>
|
37
40
|
<% unless window.panes? %>
|
38
41
|
<% if window.project.pre_window %>
|
39
42
|
<%= window.tmux_pre_window_command %>
|
@@ -49,12 +52,8 @@ unset RBENV_DIR
|
|
49
52
|
<% if pane.tab.pre %>
|
50
53
|
<%= pane.tmux_pre_command %>
|
51
54
|
<% end %>
|
52
|
-
<%
|
53
|
-
<% pane.commands.each do |command| %>
|
55
|
+
<% pane.commands.each do |command| %>
|
54
56
|
<%= pane.tmux_main_command(command) %>
|
55
|
-
<% end %>
|
56
|
-
<% else %>
|
57
|
-
<%= pane.tmux_main_command(commands.first) %>
|
58
57
|
<% end %>
|
59
58
|
|
60
59
|
<% unless pane.last? %>
|
@@ -66,9 +65,14 @@ unset RBENV_DIR
|
|
66
65
|
<%= window.tmux_layout_command %>
|
67
66
|
<%= window.tmux_select_first_pane %>
|
68
67
|
<% end %>
|
68
|
+
|
69
|
+
<% if window.synchronize_after? %>
|
70
|
+
<%= window.tmux_synchronize_panes %>
|
71
|
+
<% end %>
|
69
72
|
<% end %>
|
70
73
|
|
71
74
|
<%= tmux %> select-window -t <%= startup_window %>
|
75
|
+
<%= tmux %> select-pane -t <%= startup_pane %>
|
72
76
|
<%- end -%>
|
73
77
|
|
74
78
|
<%- if attach? -%>
|
@@ -23,6 +23,9 @@ if [ "$?" -eq 127 ]; then
|
|
23
23
|
<%- windows.each do |window| -%>
|
24
24
|
|
25
25
|
# Window "<%= window.name %>"
|
26
|
+
<% if window.synchronize_before? %>
|
27
|
+
<%= window.tmux_synchronize_panes %>
|
28
|
+
<% end %>
|
26
29
|
<%- unless window.panes? -%>
|
27
30
|
<%= window.tmux_pre_window_command %>
|
28
31
|
<%- window.commands.each do |command| -%>
|
@@ -32,12 +35,8 @@ if [ "$?" -eq 127 ]; then
|
|
32
35
|
<%- window.panes.each do |pane| -%>
|
33
36
|
<%= pane.tmux_pre_window_command %>
|
34
37
|
<%= pane.tmux_pre_command %>
|
35
|
-
|
36
|
-
<%- pane.commands.each do |command| -%>
|
38
|
+
<%- pane.commands.each do |command| -%>
|
37
39
|
<%= pane.tmux_main_command(command) %>
|
38
|
-
<%- end -%>
|
39
|
-
<%- else -%>
|
40
|
-
<%= pane.tmux_main_command(commands.first) %>
|
41
40
|
<%- end -%>
|
42
41
|
|
43
42
|
<%- unless pane.last? -%>
|
@@ -48,9 +47,14 @@ if [ "$?" -eq 127 ]; then
|
|
48
47
|
|
49
48
|
<%= window.tmux_select_first_pane %>
|
50
49
|
<%- end -%>
|
50
|
+
|
51
|
+
<%- if window.synchronize_after? -%>
|
52
|
+
<%= window.tmux_synchronize_panes %>
|
53
|
+
<%- end %>
|
51
54
|
<%- end -%>
|
52
55
|
|
53
56
|
<%= tmux %> select-window -t <%= startup_window %>
|
57
|
+
<%= tmux %> select-pane -t <%= startup_pane %>
|
54
58
|
fi
|
55
59
|
|
56
60
|
wemux attach
|
data/lib/tmuxinator/cli.rb
CHANGED
@@ -12,20 +12,19 @@ module Tmuxinator
|
|
12
12
|
commands: "Lists commands available in tmuxinator",
|
13
13
|
completions: "Used for shell completion",
|
14
14
|
new: "Create a new project file and open it in your editor",
|
15
|
+
edit: "Alias of new",
|
15
16
|
open: "Alias of new",
|
16
|
-
start:
|
17
|
+
start: %w{
|
17
18
|
Start a tmux session using a project's tmuxinator config,
|
18
19
|
with an optional [ALIAS] for project reuse
|
19
|
-
|
20
|
-
stop:
|
21
|
-
Stop a tmux session using a project's tmuxinator config.
|
22
|
-
DESC
|
20
|
+
}.join(" "),
|
21
|
+
stop: "Stop a tmux session using a project's tmuxinator config",
|
23
22
|
local: "Start a tmux session using ./.tmuxinator.yml",
|
24
23
|
debug: "Output the shell commands that are generated by tmuxinator",
|
25
|
-
copy:
|
26
|
-
Copy an existing project to a new project and
|
27
|
-
your editor
|
28
|
-
|
24
|
+
copy: %w{
|
25
|
+
Copy an existing project to a new project and
|
26
|
+
open it in your editor
|
27
|
+
}.join(" "),
|
29
28
|
delete: "Deletes given project",
|
30
29
|
implode: "Deletes all tmuxinator projects",
|
31
30
|
version: "Display installed tmuxinator version",
|
@@ -53,7 +52,7 @@ module Tmuxinator
|
|
53
52
|
desc "completions [arg1 arg2]", COMMANDS[:completions]
|
54
53
|
|
55
54
|
def completions(arg)
|
56
|
-
if %w(start stop open copy delete).include?(arg)
|
55
|
+
if %w(start stop edit open copy delete).include?(arg)
|
57
56
|
configs = Tmuxinator::Config.configs
|
58
57
|
say configs.join("\n")
|
59
58
|
end
|
@@ -81,7 +80,7 @@ module Tmuxinator
|
|
81
80
|
else
|
82
81
|
Tmuxinator::Config.default_project(name)
|
83
82
|
end
|
84
|
-
if File.
|
83
|
+
if File.exist?(path)
|
85
84
|
path
|
86
85
|
else
|
87
86
|
generate_project_file(name, path)
|
data/lib/tmuxinator/config.rb
CHANGED
@@ -5,9 +5,9 @@ module Tmuxinator
|
|
5
5
|
|
6
6
|
class << self
|
7
7
|
def root
|
8
|
-
root_dir = File.expand_path("
|
9
|
-
Dir.mkdir(
|
10
|
-
|
8
|
+
root_dir = File.expand_path("#{ENV['HOME']}/.tmuxinator")
|
9
|
+
Dir.mkdir(root_dir) unless File.directory?(root_dir)
|
10
|
+
root_dir
|
11
11
|
end
|
12
12
|
|
13
13
|
def sample
|
@@ -43,7 +43,7 @@ module Tmuxinator
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def exists?(name)
|
46
|
-
File.
|
46
|
+
File.exist?(project(name))
|
47
47
|
end
|
48
48
|
|
49
49
|
def project_in_root(name)
|
@@ -56,7 +56,7 @@ module Tmuxinator
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def project_in_local
|
59
|
-
[LOCAL_DEFAULT].detect { |f| File.
|
59
|
+
[LOCAL_DEFAULT].detect { |f| File.exist?(f) }
|
60
60
|
end
|
61
61
|
|
62
62
|
def default_project(name)
|
data/lib/tmuxinator/pane.rb
CHANGED
data/lib/tmuxinator/project.rb
CHANGED
@@ -16,6 +16,15 @@ module Tmuxinator
|
|
16
16
|
DEPRECATION: The cli_args option has been replaced by the tmux_options
|
17
17
|
option and will not be supported in 0.8.0.
|
18
18
|
M
|
19
|
+
SYNC_DEP_MSG = <<-M
|
20
|
+
DEPRECATION: The synchronize option's current default behaviour is to
|
21
|
+
enable pane synchronization before running commands. In a future release,
|
22
|
+
the default syncronization option will be `after`, i.e. synchronization of
|
23
|
+
panes will occur after the commands described in each of the panes
|
24
|
+
have run. At that time, the current behavior will need to be explicitly
|
25
|
+
enabled, using the `synchronize: before` option. To use this behaviour
|
26
|
+
now, use the 'synchronize: after' option.
|
27
|
+
M
|
19
28
|
|
20
29
|
attr_reader :yaml
|
21
30
|
attr_reader :force_attach
|
@@ -148,8 +157,11 @@ module Tmuxinator
|
|
148
157
|
end
|
149
158
|
|
150
159
|
def tmux_has_session?(name)
|
151
|
-
|
152
|
-
|
160
|
+
# Redirect stderr to /dev/null in order to prevent "failed to connect
|
161
|
+
# to server: Connection refused" error message and non-zero exit status
|
162
|
+
# if no tmux sessions exist.
|
163
|
+
# Please see issues #402 and #414.
|
164
|
+
sessions = `#{tmux_command} ls 2> /dev/null`
|
153
165
|
!!sessions.match("^#{name}:")
|
154
166
|
end
|
155
167
|
|
@@ -183,10 +195,18 @@ module Tmuxinator
|
|
183
195
|
get_pane_base_index ? get_pane_base_index.to_i : get_base_index.to_i
|
184
196
|
end
|
185
197
|
|
198
|
+
def pane_base_index
|
199
|
+
get_pane_base_index.to_i
|
200
|
+
end
|
201
|
+
|
186
202
|
def startup_window
|
187
203
|
yaml["startup_window"] || base_index
|
188
204
|
end
|
189
205
|
|
206
|
+
def startup_pane
|
207
|
+
yaml["startup_pane"] || pane_base_index
|
208
|
+
end
|
209
|
+
|
190
210
|
def tmux_options?
|
191
211
|
yaml["tmux_options"]
|
192
212
|
end
|
@@ -228,6 +248,7 @@ module Tmuxinator
|
|
228
248
|
deprecations << RBENVRVM_DEP_MSG if yaml["rbenv"] || yaml["rvm"]
|
229
249
|
deprecations << TABS_DEP_MSG if yaml["tabs"]
|
230
250
|
deprecations << CLIARGS_DEP_MSG if yaml["cli_args"]
|
251
|
+
deprecations << SYNC_DEP_MSG if legacy_synchronize?
|
231
252
|
deprecations
|
232
253
|
end
|
233
254
|
|
@@ -271,5 +292,19 @@ module Tmuxinator
|
|
271
292
|
|
272
293
|
options_hash
|
273
294
|
end
|
295
|
+
|
296
|
+
def legacy_synchronize?
|
297
|
+
(synchronize_options & [true, "before"]).any?
|
298
|
+
end
|
299
|
+
|
300
|
+
def synchronize_options
|
301
|
+
window_options.map do |option|
|
302
|
+
option["synchronize"] if option.is_a?(Hash)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def window_options
|
307
|
+
yaml["windows"].map(&:values).flatten
|
308
|
+
end
|
274
309
|
end
|
275
310
|
end
|
data/lib/tmuxinator/version.rb
CHANGED
data/lib/tmuxinator/window.rb
CHANGED
@@ -2,7 +2,7 @@ module Tmuxinator
|
|
2
2
|
class Window
|
3
3
|
include Tmuxinator::Util
|
4
4
|
|
5
|
-
attr_reader :name, :root, :panes, :layout, :commands, :index, :project
|
5
|
+
attr_reader :name, :root, :panes, :layout, :commands, :index, :project, :synchronize
|
6
6
|
|
7
7
|
def initialize(window_yaml, index, project)
|
8
8
|
@name = if !window_yaml.keys.first.nil?
|
@@ -10,6 +10,7 @@ module Tmuxinator
|
|
10
10
|
end
|
11
11
|
@root = nil
|
12
12
|
@panes = []
|
13
|
+
@synchronize = false
|
13
14
|
@layout = nil
|
14
15
|
@pre = nil
|
15
16
|
@project = project
|
@@ -18,6 +19,7 @@ module Tmuxinator
|
|
18
19
|
value = window_yaml.values.first
|
19
20
|
|
20
21
|
if value.is_a?(Hash)
|
22
|
+
@synchronize = value["synchronize"] || false
|
21
23
|
@layout = value["layout"] ? value["layout"].shellescape : nil
|
22
24
|
@pre = value["pre"] if value["pre"]
|
23
25
|
@root = if value["root"]
|
@@ -27,20 +29,23 @@ module Tmuxinator
|
|
27
29
|
end
|
28
30
|
|
29
31
|
@panes = build_panes(value["panes"])
|
30
|
-
else
|
31
|
-
@commands = build_commands(tmux_window_command_prefix, value)
|
32
32
|
end
|
33
|
+
|
34
|
+
@commands = build_commands(tmux_window_command_prefix, value)
|
33
35
|
end
|
34
36
|
|
35
37
|
def build_panes(panes_yml)
|
36
38
|
Array(panes_yml).map.with_index do |pane_yml, index|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
commands = case pane_yml
|
40
|
+
when Hash
|
41
|
+
pane_yml.values.first
|
42
|
+
when Array
|
43
|
+
pane_yml
|
44
|
+
else
|
45
|
+
pane_yml
|
46
|
+
end
|
47
|
+
|
48
|
+
Tmuxinator::Pane.new(index, project, self, *commands)
|
44
49
|
end.flatten
|
45
50
|
end
|
46
51
|
|
@@ -99,6 +104,10 @@ module Tmuxinator
|
|
99
104
|
"#{project.tmux} select-layout -t #{tmux_window_target} tiled"
|
100
105
|
end
|
101
106
|
|
107
|
+
def tmux_synchronize_panes
|
108
|
+
"#{project.tmux} set-window-option -t #{tmux_window_target} synchronize-panes on"
|
109
|
+
end
|
110
|
+
|
102
111
|
def tmux_layout_command
|
103
112
|
"#{project.tmux} select-layout -t #{tmux_window_target} #{layout}"
|
104
113
|
end
|
@@ -106,5 +115,13 @@ module Tmuxinator
|
|
106
115
|
def tmux_select_first_pane
|
107
116
|
"#{project.tmux} select-pane -t #{tmux_window_target}.#{panes.first.index + project.base_index}"
|
108
117
|
end
|
118
|
+
|
119
|
+
def synchronize_before?
|
120
|
+
synchronize == true || synchronize == "before"
|
121
|
+
end
|
122
|
+
|
123
|
+
def synchronize_after?
|
124
|
+
synchronize == "after"
|
125
|
+
end
|
109
126
|
end
|
110
127
|
end
|
data/spec/factories/projects.rb
CHANGED
@@ -73,6 +73,14 @@ FactoryGirl.define do
|
|
73
73
|
initialize_with { Tmuxinator::Project.new(file) }
|
74
74
|
end
|
75
75
|
|
76
|
+
factory :noroot_project, class: Tmuxinator::Project do
|
77
|
+
transient do
|
78
|
+
file { yaml_load("spec/fixtures/noroot.yml") }
|
79
|
+
end
|
80
|
+
|
81
|
+
initialize_with { Tmuxinator::Project.new(file) }
|
82
|
+
end
|
83
|
+
|
76
84
|
factory :nowindows_project, class: Tmuxinator::Project do
|
77
85
|
transient do
|
78
86
|
file { yaml_load("spec/fixtures/nowindows.yml") }
|
@@ -40,6 +40,7 @@ describe Tmuxinator::Cli do
|
|
40
40
|
expected = %w(commands
|
41
41
|
completions
|
42
42
|
new
|
43
|
+
edit
|
43
44
|
open
|
44
45
|
start
|
45
46
|
stop
|
@@ -181,7 +182,7 @@ describe Tmuxinator::Cli do
|
|
181
182
|
|
182
183
|
before do
|
183
184
|
# make sure that no project file exists initially
|
184
|
-
FileUtils.remove_file(path) if File.
|
185
|
+
FileUtils.remove_file(path) if File.exist?(path)
|
185
186
|
expect(File).not_to exist(path)
|
186
187
|
|
187
188
|
# now generate a project file
|
@@ -221,7 +222,7 @@ describe Tmuxinator::Cli do
|
|
221
222
|
|
222
223
|
context "existing project doesn't exist" do
|
223
224
|
before do
|
224
|
-
expect(File).to receive_messages(
|
225
|
+
expect(File).to receive_messages(exist?: false)
|
225
226
|
end
|
226
227
|
|
227
228
|
it "creates a new tmuxinator project file" do
|
@@ -234,8 +235,8 @@ describe Tmuxinator::Cli do
|
|
234
235
|
let(:root_path) { "#{ENV['HOME']}\/\.tmuxinator\/#{name}\.yml" }
|
235
236
|
|
236
237
|
before do
|
237
|
-
allow(File).to receive(:
|
238
|
-
expect(File).to receive(:
|
238
|
+
allow(File).to receive(:exist?).with(anything).and_return(false)
|
239
|
+
expect(File).to receive(:exist?).with(root_path).and_return(true)
|
239
240
|
end
|
240
241
|
|
241
242
|
it "just opens the file" do
|
@@ -252,7 +253,7 @@ describe Tmuxinator::Cli do
|
|
252
253
|
|
253
254
|
context "existing project doesn't exist" do
|
254
255
|
before do
|
255
|
-
allow(File).to receive(:
|
256
|
+
allow(File).to receive(:exist?).at_least(:once) do
|
256
257
|
false
|
257
258
|
end
|
258
259
|
end
|
@@ -266,7 +267,7 @@ describe Tmuxinator::Cli do
|
|
266
267
|
context "files exists" do
|
267
268
|
let(:path) { Tmuxinator::Config::LOCAL_DEFAULT }
|
268
269
|
before do
|
269
|
-
expect(File).to receive(:
|
270
|
+
expect(File).to receive(:exist?).with(path) { true }
|
270
271
|
end
|
271
272
|
|
272
273
|
it "just opens the file" do
|
@@ -489,7 +490,7 @@ describe Tmuxinator::Cli do
|
|
489
490
|
let(:path) { Tmuxinator::Config.default_project(name) }
|
490
491
|
|
491
492
|
after(:each) do
|
492
|
-
FileUtils.remove_file(path) if File.
|
493
|
+
FileUtils.remove_file(path) if File.exist?(path)
|
493
494
|
end
|
494
495
|
|
495
496
|
context "when the project file does not already exist" do
|
@@ -537,7 +538,7 @@ describe Tmuxinator::Cli do
|
|
537
538
|
end
|
538
539
|
|
539
540
|
after(:each) do
|
540
|
-
FileUtils.remove_file(path) if File.
|
541
|
+
FileUtils.remove_file(path) if File.exist?(path)
|
541
542
|
end
|
542
543
|
|
543
544
|
it "should always generate a project file" do
|
@@ -48,8 +48,8 @@ describe Tmuxinator::Config do
|
|
48
48
|
|
49
49
|
context "when the file exists" do
|
50
50
|
before do
|
51
|
-
allow(File).to receive(:
|
52
|
-
allow(File).to receive(:
|
51
|
+
allow(File).to receive(:exist?).with(local_default) { false }
|
52
|
+
allow(File).to receive(:exist?).with(proj_default) { true }
|
53
53
|
end
|
54
54
|
|
55
55
|
it "returns true" do
|
@@ -59,8 +59,8 @@ describe Tmuxinator::Config do
|
|
59
59
|
|
60
60
|
context "when the file doesn't exist" do
|
61
61
|
before do
|
62
|
-
allow(File).to receive(:
|
63
|
-
allow(File).to receive(:
|
62
|
+
allow(File).to receive(:exist?).with(local_default) { false }
|
63
|
+
allow(File).to receive(:exist?).with(proj_default) { false }
|
64
64
|
end
|
65
65
|
|
66
66
|
it "returns true" do
|
@@ -147,7 +147,7 @@ describe Tmuxinator::Config do
|
|
147
147
|
|
148
148
|
describe "#exists?" do
|
149
149
|
before do
|
150
|
-
allow(File).to receive_messages(
|
150
|
+
allow(File).to receive_messages(exist?: true)
|
151
151
|
allow(Tmuxinator::Config).to receive_messages(project: "")
|
152
152
|
end
|
153
153
|
|
@@ -181,7 +181,7 @@ describe Tmuxinator::Config do
|
|
181
181
|
describe "#local?" do
|
182
182
|
it "checks if the given project exists" do
|
183
183
|
path = Tmuxinator::Config::LOCAL_DEFAULT
|
184
|
-
expect(File).to receive(:
|
184
|
+
expect(File).to receive(:exist?).with(path) { true }
|
185
185
|
expect(Tmuxinator::Config.local?).to be_truthy
|
186
186
|
end
|
187
187
|
end
|
@@ -191,7 +191,7 @@ describe Tmuxinator::Config do
|
|
191
191
|
|
192
192
|
context "with a project yml" do
|
193
193
|
it "gets the project as path to the yml file" do
|
194
|
-
expect(File).to receive(:
|
194
|
+
expect(File).to receive(:exist?).with(default) { true }
|
195
195
|
expect(Tmuxinator::Config.project_in_local).to eq default
|
196
196
|
end
|
197
197
|
end
|
@@ -220,7 +220,7 @@ describe Tmuxinator::Config do
|
|
220
220
|
|
221
221
|
context "with a local project, but no project in root" do
|
222
222
|
it "gets the project as path to the yml file" do
|
223
|
-
expect(File).to receive(:
|
223
|
+
expect(File).to receive(:exist?).with(default) { true }
|
224
224
|
expect(Tmuxinator::Config.project("sample")).to eq "./.tmuxinator.yml"
|
225
225
|
end
|
226
226
|
end
|
@@ -253,7 +253,7 @@ describe Tmuxinator::Config do
|
|
253
253
|
|
254
254
|
context "when no project name is provided" do
|
255
255
|
it "should raise if the local project file doesn't exist" do
|
256
|
-
expect(File).to receive(:
|
256
|
+
expect(File).to receive(:exist?).with(default) { false }
|
257
257
|
expect do
|
258
258
|
Tmuxinator::Config.validate
|
259
259
|
end.to raise_error RuntimeError, %r{Project.+doesn't.exist}
|
@@ -262,7 +262,7 @@ describe Tmuxinator::Config do
|
|
262
262
|
it "should load and validate the project" do
|
263
263
|
content = File.read(File.join(path, "sample.yml"))
|
264
264
|
|
265
|
-
expect(File).to receive(:
|
265
|
+
expect(File).to receive(:exist?).with(default).at_least(:once) { true }
|
266
266
|
expect(File).to receive(:read).with(default).and_return(content)
|
267
267
|
|
268
268
|
expect(Tmuxinator::Config.validate).to be_a Tmuxinator::Project
|
@@ -23,6 +23,7 @@ describe Tmuxinator::Project do
|
|
23
23
|
|
24
24
|
let(:wemux_project) { FactoryGirl.build(:wemux_project) }
|
25
25
|
let(:noname_project) { FactoryGirl.build(:noname_project) }
|
26
|
+
let(:noroot_project) { FactoryGirl.build(:noroot_project) }
|
26
27
|
let(:nameless_window_project) do
|
27
28
|
FactoryGirl.build(:nameless_window_project)
|
28
29
|
end
|
@@ -57,24 +58,40 @@ describe Tmuxinator::Project do
|
|
57
58
|
end
|
58
59
|
|
59
60
|
describe "#tmux_has_session?" do
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
call_tmux_ls = receive(:`).with(cmd).at_least(:once).and_return(resp)
|
61
|
+
context "no active sessions" do
|
62
|
+
before do
|
63
|
+
cmd = "#{project.tmux_command} ls 2> /dev/null"
|
64
|
+
resp = ""
|
65
|
+
call_tmux_ls = receive(:`).with(cmd).at_least(:once).and_return(resp)
|
66
66
|
|
67
|
-
|
68
|
-
|
67
|
+
expect(project).to call_tmux_ls
|
68
|
+
end
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
expect(project.tmux_has_session?("quux")).to be false
|
70
|
+
it "should return false if no sessions are found" do
|
71
|
+
expect(project.tmux_has_session?("no server running")).to be false
|
72
|
+
end
|
74
73
|
end
|
75
74
|
|
76
|
-
|
77
|
-
|
75
|
+
context "active sessions" do
|
76
|
+
before do
|
77
|
+
cmd = "#{project.tmux_command} ls 2> /dev/null"
|
78
|
+
resp = ""\
|
79
|
+
"foo: 1 window (created Sun May 25 10:12:00 1986) [0x0] (detached)\n"\
|
80
|
+
"bar: 1 window (created Sat Sept 01 00:00:00 1990) [0x0] (detached)"
|
81
|
+
call_tmux_ls = receive(:`).with(cmd).at_least(:once).and_return(resp)
|
82
|
+
|
83
|
+
expect(project).to call_tmux_ls
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should return true only when `tmux ls` has the named session" do
|
87
|
+
expect(project.tmux_has_session?("foo")).to be true
|
88
|
+
expect(project.tmux_has_session?("bar")).to be true
|
89
|
+
expect(project.tmux_has_session?("quux")).to be false
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should return false if a partial (prefix) match is found" do
|
93
|
+
expect(project.tmux_has_session?("foobar")).to be false
|
94
|
+
end
|
78
95
|
end
|
79
96
|
end
|
80
97
|
|
@@ -107,7 +124,7 @@ describe Tmuxinator::Project do
|
|
107
124
|
|
108
125
|
context "without root" do
|
109
126
|
it "doesn't throw an error" do
|
110
|
-
expect {
|
127
|
+
expect { noroot_project.root }.to_not raise_error
|
111
128
|
end
|
112
129
|
end
|
113
130
|
end
|
@@ -310,6 +327,24 @@ describe Tmuxinator::Project do
|
|
310
327
|
end
|
311
328
|
end
|
312
329
|
|
330
|
+
describe "#startup_pane" do
|
331
|
+
context "startup pane specified" do
|
332
|
+
it "get the startup pane index from project config" do
|
333
|
+
project.yaml["startup_pane"] = 1
|
334
|
+
|
335
|
+
expect(project.startup_pane).to eq(1)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
context "startup pane not specified" do
|
340
|
+
it "returns the base pane instead" do
|
341
|
+
allow(project).to receive_messages(pane_base_index: 4)
|
342
|
+
|
343
|
+
expect(project.startup_pane).to eq(4)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
313
348
|
describe "#window" do
|
314
349
|
it "gets the window and index for tmux" do
|
315
350
|
expect(project.window(1)).to eq "sample:1"
|
@@ -4,6 +4,7 @@ describe Tmuxinator::Window do
|
|
4
4
|
let(:project) { double }
|
5
5
|
let(:panes) { ["vim", nil, "top"] }
|
6
6
|
let(:window_name) { "editor" }
|
7
|
+
let(:synchronize) { false }
|
7
8
|
let(:yaml) do
|
8
9
|
{
|
9
10
|
window_name => {
|
@@ -11,6 +12,7 @@ describe Tmuxinator::Window do
|
|
11
12
|
"echo 'I get run in each pane. Before each pane command!'",
|
12
13
|
nil
|
13
14
|
],
|
15
|
+
"synchronize" => synchronize,
|
14
16
|
"layout" => "main-vertical",
|
15
17
|
"panes" => panes
|
16
18
|
}
|
@@ -34,6 +36,25 @@ describe Tmuxinator::Window do
|
|
34
36
|
let(:window) { Tmuxinator::Window.new(yaml, 0, project) }
|
35
37
|
let(:window_root) { Tmuxinator::Window.new(yaml_root, 0, project) }
|
36
38
|
|
39
|
+
shared_context "window command context" do
|
40
|
+
let(:project) { double(:project) }
|
41
|
+
let(:window) { Tmuxinator::Window.new(yaml, 0, project) }
|
42
|
+
let(:root?) { true }
|
43
|
+
let(:root) { "/project/tmuxinator" }
|
44
|
+
|
45
|
+
before do
|
46
|
+
allow(project).to receive_messages(
|
47
|
+
name: "test",
|
48
|
+
tmux: "tmux",
|
49
|
+
root: root,
|
50
|
+
root?: root?,
|
51
|
+
base_index: 1
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:tmux_part) { project.tmux }
|
56
|
+
end
|
57
|
+
|
37
58
|
before do
|
38
59
|
allow(project).to receive_messages(
|
39
60
|
tmux: "tmux",
|
@@ -65,14 +86,8 @@ describe Tmuxinator::Window do
|
|
65
86
|
end
|
66
87
|
|
67
88
|
describe "#panes" do
|
68
|
-
let(:pane) { double(:pane) }
|
69
|
-
|
70
|
-
before do
|
71
|
-
allow(Tmuxinator::Pane).to receive_messages new: pane
|
72
|
-
end
|
73
|
-
|
74
89
|
context "with a three element Array" do
|
75
|
-
let(:panes) { ["vim",
|
90
|
+
let(:panes) { ["vim", "ls", "top"] }
|
76
91
|
|
77
92
|
it "creates three panes" do
|
78
93
|
expect(Tmuxinator::Pane).to receive(:new).exactly(3).times
|
@@ -80,35 +95,63 @@ describe Tmuxinator::Window do
|
|
80
95
|
end
|
81
96
|
|
82
97
|
it "returns three panes" do
|
83
|
-
expect(window.panes).to
|
98
|
+
expect(window.panes).to all be_a_pane.with(
|
99
|
+
project: project, tab: window
|
100
|
+
)
|
101
|
+
|
102
|
+
expect(window.panes).to match([
|
103
|
+
a_pane.with(index: 0).and_commands("vim"),
|
104
|
+
a_pane.with(index: 1).and_commands("ls"),
|
105
|
+
a_pane.with(index: 2).and_commands("top")
|
106
|
+
])
|
84
107
|
end
|
85
108
|
end
|
86
109
|
|
87
110
|
context "with a String" do
|
88
111
|
let(:panes) { "vim" }
|
89
112
|
|
90
|
-
it "creates one pane" do
|
91
|
-
expect(Tmuxinator::Pane).to receive(:new).once
|
92
|
-
window.panes
|
93
|
-
end
|
94
|
-
|
95
113
|
it "returns one pane in an Array" do
|
96
|
-
expect(window.panes).to
|
114
|
+
expect(window.panes.first).to be_a_pane.
|
115
|
+
with(index: 0).and_commands("vim")
|
97
116
|
end
|
98
117
|
end
|
99
118
|
|
100
119
|
context "with nil" do
|
101
120
|
let(:panes) { nil }
|
102
121
|
|
103
|
-
it "doesn't create any panes" do
|
104
|
-
expect(Tmuxinator::Pane).to_not receive(:new)
|
105
|
-
window.panes
|
106
|
-
end
|
107
|
-
|
108
122
|
it "returns an empty Array" do
|
109
123
|
expect(window.panes).to be_empty
|
110
124
|
end
|
111
125
|
end
|
126
|
+
|
127
|
+
context "nested collections" do
|
128
|
+
let(:command1) { "cd /tmp/" }
|
129
|
+
let(:command2) { "ls" }
|
130
|
+
|
131
|
+
let(:panes) { ["vim", nested_collection] }
|
132
|
+
|
133
|
+
context "with nested hash" do
|
134
|
+
let(:nested_collection) { { pane2: [command1, command2] } }
|
135
|
+
|
136
|
+
it "returns two panes in an Array" do
|
137
|
+
expect(window.panes).to match [
|
138
|
+
a_pane.with(index: 0).and_commands("vim"),
|
139
|
+
a_pane.with(index: 1).and_commands(command1, command2)
|
140
|
+
]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "with nested array" do
|
145
|
+
let(:nested_collection) { [command1, command2] }
|
146
|
+
|
147
|
+
it "returns two panes in an Array" do
|
148
|
+
expect(window.panes).to match [
|
149
|
+
a_pane.with(index: 0).and_commands("vim"),
|
150
|
+
a_pane.with(index: 1).and_commands(command1, command2)
|
151
|
+
]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
112
155
|
end
|
113
156
|
|
114
157
|
describe "#pre" do
|
@@ -166,6 +209,16 @@ describe Tmuxinator::Window do
|
|
166
209
|
expect(window.commands).to be_empty
|
167
210
|
end
|
168
211
|
end
|
212
|
+
|
213
|
+
context "command is a hash" do
|
214
|
+
before do
|
215
|
+
yaml["editor"] = { "layout" => "main-horizontal", "panes" => [nil] }
|
216
|
+
end
|
217
|
+
|
218
|
+
it "returns an empty array" do
|
219
|
+
expect(window.commands).to be_empty
|
220
|
+
end
|
221
|
+
end
|
169
222
|
end
|
170
223
|
|
171
224
|
describe "#name_options" do
|
@@ -186,23 +239,94 @@ describe Tmuxinator::Window do
|
|
186
239
|
end
|
187
240
|
end
|
188
241
|
|
189
|
-
describe "#
|
190
|
-
|
191
|
-
let(:window) { Tmuxinator::Window.new(yaml, 0, project) }
|
192
|
-
let(:root?) { true }
|
193
|
-
let(:root) { "/project/tmuxinator" }
|
242
|
+
describe "#synchronize_before?" do
|
243
|
+
subject { window.synchronize_before? }
|
194
244
|
|
195
|
-
before do
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
root: root,
|
200
|
-
root?: root?,
|
201
|
-
base_index: 1
|
202
|
-
)
|
245
|
+
context "synchronize is 'before'" do
|
246
|
+
let(:synchronize) { "before" }
|
247
|
+
|
248
|
+
it { is_expected.to be true }
|
203
249
|
end
|
204
250
|
|
205
|
-
|
251
|
+
context "synchronize is true" do
|
252
|
+
let(:synchronize) { true }
|
253
|
+
|
254
|
+
it { is_expected.to be true }
|
255
|
+
end
|
256
|
+
|
257
|
+
context "synchronize is 'after'" do
|
258
|
+
let(:synchronize) { "after" }
|
259
|
+
|
260
|
+
it { is_expected.to be false }
|
261
|
+
end
|
262
|
+
|
263
|
+
context "synchronization disabled" do
|
264
|
+
let(:synchronize) { false }
|
265
|
+
|
266
|
+
it { is_expected.to be false }
|
267
|
+
end
|
268
|
+
|
269
|
+
context "synchronization not specified" do
|
270
|
+
it { is_expected.to be false }
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe "#synchronize_after?" do
|
275
|
+
subject { window.synchronize_after? }
|
276
|
+
|
277
|
+
context "synchronization is 'after'" do
|
278
|
+
let(:synchronize) { "after" }
|
279
|
+
|
280
|
+
it { is_expected.to be true }
|
281
|
+
end
|
282
|
+
|
283
|
+
context "synchronization is true" do
|
284
|
+
let(:synchronize) { true }
|
285
|
+
|
286
|
+
it { is_expected.to be false }
|
287
|
+
end
|
288
|
+
|
289
|
+
context "synchronization is 'before'" do
|
290
|
+
let(:synchronize) { "before" }
|
291
|
+
|
292
|
+
it { is_expected.to be false }
|
293
|
+
end
|
294
|
+
|
295
|
+
context "synchronization disabled" do
|
296
|
+
let(:synchronize) { false }
|
297
|
+
|
298
|
+
it { is_expected.to be false }
|
299
|
+
end
|
300
|
+
|
301
|
+
context "synchronization not specified" do
|
302
|
+
it { is_expected.to be false }
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
describe "#tmux_synchronize_panes" do
|
307
|
+
include_context "window command context"
|
308
|
+
|
309
|
+
let(:window_option_set_part) { "set-window-option" }
|
310
|
+
let(:target_part) { "-t #{window.tmux_window_target}" }
|
311
|
+
let(:synchronize_panes_part) { "synchronize-panes" }
|
312
|
+
|
313
|
+
context "synchronization enabled" do
|
314
|
+
let(:synchronize) { true }
|
315
|
+
let(:enabled) { "on" }
|
316
|
+
|
317
|
+
let(:full_command) do
|
318
|
+
"#{tmux_part} #{window_option_set_part} #{target_part} #{synchronize_panes_part} #{enabled}"
|
319
|
+
end
|
320
|
+
|
321
|
+
it "should set the synchronize-panes window option on" do
|
322
|
+
expect(window.tmux_synchronize_panes).to eq full_command
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
describe "#tmux_new_window_command" do
|
328
|
+
include_context "window command context"
|
329
|
+
|
206
330
|
let(:window_part) { "new-window" }
|
207
331
|
let(:name_part) { window.tmux_window_name_option }
|
208
332
|
let(:target_part) { "-t #{window.tmux_window_target}" }
|
@@ -0,0 +1,44 @@
|
|
1
|
+
RSpec::Matchers.alias_matcher :be_a_pane, :a_pane
|
2
|
+
RSpec::Matchers.define :a_pane do
|
3
|
+
attr_reader :commands
|
4
|
+
|
5
|
+
match do
|
6
|
+
result = is_pane
|
7
|
+
|
8
|
+
result && attributes_match if @expected_attrs
|
9
|
+
result &&= commands_match if commands
|
10
|
+
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
failure_message do |actual|
|
15
|
+
return "Expected #{actual} to be a Tmuxinator::Pane" unless is_pane
|
16
|
+
|
17
|
+
msg = "Actual pane does not match expected"
|
18
|
+
msg << "\n Expected #{@commands} but has #{actual.commands}" if @commands
|
19
|
+
msg << "\n Expected pane to have #{@expected_attrs}" if @expected_attrs
|
20
|
+
end
|
21
|
+
|
22
|
+
chain :with do |attrs|
|
23
|
+
@expected_attrs = attrs
|
24
|
+
end
|
25
|
+
|
26
|
+
chain :with_commands do |*expected|
|
27
|
+
@commands = expected
|
28
|
+
end
|
29
|
+
alias_method :and_commands, :with_commands
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def attributes_match
|
34
|
+
expect(@actual).to have_attributes(@expected_attrs)
|
35
|
+
end
|
36
|
+
|
37
|
+
def commands_match
|
38
|
+
@actual.commands == commands
|
39
|
+
end
|
40
|
+
|
41
|
+
def is_pane
|
42
|
+
@actual.is_a? Tmuxinator::Pane
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tmuxinator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Allen Bargi
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-10-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -64,12 +64,10 @@ email:
|
|
64
64
|
- allen.bargi@gmail.com
|
65
65
|
- chris@chowie.net
|
66
66
|
executables:
|
67
|
-
- mux
|
68
67
|
- tmuxinator
|
69
68
|
extensions: []
|
70
69
|
extra_rdoc_files: []
|
71
70
|
files:
|
72
|
-
- bin/mux
|
73
71
|
- bin/tmuxinator
|
74
72
|
- completion/mux.fish
|
75
73
|
- completion/tmuxinator.bash
|
@@ -92,6 +90,7 @@ files:
|
|
92
90
|
- spec/fixtures/detach.yml
|
93
91
|
- spec/fixtures/nameless_window.yml
|
94
92
|
- spec/fixtures/noname.yml
|
93
|
+
- spec/fixtures/noroot.yml
|
95
94
|
- spec/fixtures/nowindows.yml
|
96
95
|
- spec/fixtures/sample.deprecations.yml
|
97
96
|
- spec/fixtures/sample.yml
|
@@ -105,6 +104,7 @@ files:
|
|
105
104
|
- spec/lib/tmuxinator/util_spec.rb
|
106
105
|
- spec/lib/tmuxinator/wemux_support_spec.rb
|
107
106
|
- spec/lib/tmuxinator/window_spec.rb
|
107
|
+
- spec/matchers/pane_matcher.rb
|
108
108
|
- spec/spec_helper.rb
|
109
109
|
homepage: https://github.com/tmuxinator/tmuxinator
|
110
110
|
licenses:
|
@@ -131,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
131
|
version: 1.8.23
|
132
132
|
requirements: []
|
133
133
|
rubyforge_project:
|
134
|
-
rubygems_version: 2.
|
134
|
+
rubygems_version: 2.6.6
|
135
135
|
signing_key:
|
136
136
|
specification_version: 4
|
137
137
|
summary: Create and manage complex tmux sessions easily.
|
@@ -140,6 +140,7 @@ test_files:
|
|
140
140
|
- spec/fixtures/detach.yml
|
141
141
|
- spec/fixtures/nameless_window.yml
|
142
142
|
- spec/fixtures/noname.yml
|
143
|
+
- spec/fixtures/noroot.yml
|
143
144
|
- spec/fixtures/nowindows.yml
|
144
145
|
- spec/fixtures/sample.deprecations.yml
|
145
146
|
- spec/fixtures/sample.yml
|
@@ -153,4 +154,5 @@ test_files:
|
|
153
154
|
- spec/lib/tmuxinator/util_spec.rb
|
154
155
|
- spec/lib/tmuxinator/wemux_support_spec.rb
|
155
156
|
- spec/lib/tmuxinator/window_spec.rb
|
157
|
+
- spec/matchers/pane_matcher.rb
|
156
158
|
- spec/spec_helper.rb
|
data/bin/mux
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
tmuxinator
|