tmuxinator 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/bin/tmuxinator +1 -1
  3. data/lib/tmuxinator.rb +6 -7
  4. data/lib/tmuxinator/assets/sample.yml +13 -1
  5. data/lib/tmuxinator/assets/template-stop.erb +11 -0
  6. data/lib/tmuxinator/assets/template.erb +15 -1
  7. data/lib/tmuxinator/cli.rb +85 -15
  8. data/lib/tmuxinator/config.rb +74 -30
  9. data/lib/tmuxinator/deprecations.rb +8 -0
  10. data/lib/tmuxinator/doctor.rb +17 -0
  11. data/lib/tmuxinator/hooks.rb +14 -0
  12. data/lib/tmuxinator/hooks/project.rb +42 -0
  13. data/lib/tmuxinator/pane.rb +26 -18
  14. data/lib/tmuxinator/project.rb +113 -48
  15. data/lib/tmuxinator/version.rb +1 -1
  16. data/lib/tmuxinator/wemux_support.rb +18 -9
  17. data/lib/tmuxinator/window.rb +42 -26
  18. data/spec/fixtures/TMUXINATOR_CONFIG/TMUXINATOR_CONFIG.yml +0 -0
  19. data/spec/fixtures/dot-tmuxinator/both.yml +0 -0
  20. data/spec/fixtures/dot-tmuxinator/dup/local-dup.yml +0 -0
  21. data/spec/fixtures/dot-tmuxinator/home.yml +0 -0
  22. data/spec/fixtures/dot-tmuxinator/local-dup.yml +0 -0
  23. data/spec/fixtures/sample.yml +0 -1
  24. data/spec/fixtures/xdg-tmuxinator/both.yml +0 -0
  25. data/spec/fixtures/xdg-tmuxinator/xdg.yml +0 -0
  26. data/spec/lib/tmuxinator/cli_spec.rb +87 -13
  27. data/spec/lib/tmuxinator/config_spec.rb +163 -91
  28. data/spec/lib/tmuxinator/doctor_spec.rb +69 -0
  29. data/spec/lib/tmuxinator/hooks/project_spec.rb +63 -0
  30. data/spec/lib/tmuxinator/hooks_spec.rb +31 -0
  31. data/spec/lib/tmuxinator/pane_spec.rb +24 -1
  32. data/spec/lib/tmuxinator/project_spec.rb +58 -23
  33. data/spec/lib/tmuxinator/window_spec.rb +8 -6
  34. data/spec/spec_helper.rb +2 -1
  35. metadata +177 -7
@@ -15,5 +15,13 @@ module Tmuxinator
15
15
  def cli_args?
16
16
  yaml["cli_args"]
17
17
  end
18
+
19
+ def pre?
20
+ yaml["pre"]
21
+ end
22
+
23
+ def post?
24
+ yaml["post"]
25
+ end
18
26
  end
19
27
  end
@@ -0,0 +1,17 @@
1
+ module Tmuxinator
2
+ class Doctor
3
+ class << self
4
+ def editor?
5
+ !ENV["EDITOR"].nil? && !ENV["EDITOR"].empty?
6
+ end
7
+
8
+ def installed?
9
+ Kernel.system("type tmux > /dev/null")
10
+ end
11
+
12
+ def shell?
13
+ !ENV["SHELL"].nil? && !ENV["SHELL"].empty?
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ module Tmuxinator
2
+ module Hooks
3
+ module_function
4
+
5
+ def commands_from(project, hook_name)
6
+ hook_config = project.yaml[hook_name]
7
+ if hook_config.is_a?(Array)
8
+ hook_config.join("; ")
9
+ else
10
+ hook_config
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,42 @@
1
+ module Tmuxinator
2
+ module Hooks
3
+ module Project
4
+ module_function
5
+
6
+ # Commands specified in this hook run when "tmuxinator start project"
7
+ # command is issued
8
+ def hook_on_project_start
9
+ # this method can only be used from inside Tmuxinator::Project
10
+ Tmuxinator::Hooks.commands_from self, "on_project_start"
11
+ end
12
+
13
+ # Commands specified in this hook run when "tmuxinator start project"
14
+ # command is issued and there is no tmux session available named "project"
15
+ def hook_on_project_first_start
16
+ # this method can only be used from inside Tmuxinator::Project
17
+ Tmuxinator::Hooks.commands_from self, "on_project_first_start"
18
+ end
19
+
20
+ # Commands specified in this hook run when "tmuxinator start project"
21
+ # command is issued and there is no tmux session available named "project"
22
+ def hook_on_project_restart
23
+ # this method can only be used from inside Tmuxinator::Project
24
+ Tmuxinator::Hooks.commands_from self, "on_project_restart"
25
+ end
26
+
27
+ # Commands specified in this hook run when you exit from a project ( aka
28
+ # detach from a tmux session )
29
+ def hook_on_project_exit
30
+ # this method can only be used from inside Tmuxinator::Project
31
+ Tmuxinator::Hooks.commands_from self, "on_project_exit"
32
+ end
33
+
34
+ # Command specified in this hook run when "tmuxinator stop project"
35
+ # command is issued
36
+ def hook_on_project_stop
37
+ # this method can only be used from inside Tmuxinator::Project
38
+ Tmuxinator::Hooks.commands_from self, "on_project_stop"
39
+ end
40
+ end # End Project
41
+ end # End Hooks
42
+ end # End Tmuxinator
@@ -10,39 +10,37 @@ module Tmuxinator
10
10
  end
11
11
 
12
12
  def tmux_window_and_pane_target
13
- x = tab.index + project.base_index
14
- y = index + project.base_index
15
- "#{project.name}:#{x}.#{y}"
13
+ "#{project.name}:#{window_index}.#{pane_index}"
16
14
  end
17
15
 
18
16
  def tmux_pre_command
19
- return unless tab.pre
20
-
21
- t = tmux_window_and_pane_target
22
- e = tab.pre.shellescape
23
- "#{project.tmux} send-keys -t #{t} #{e} C-m"
17
+ _send_target(tab.pre.shellescape) if tab.pre
24
18
  end
25
19
 
26
20
  def tmux_pre_window_command
27
- return unless project.pre_window
28
-
29
- t = tmux_window_and_pane_target
30
- e = project.pre_window.shellescape
31
- "#{project.tmux} send-keys -t #{t} #{e} C-m"
21
+ _send_target(project.pre_window.shellescape) if project.pre_window
32
22
  end
33
23
 
34
24
  def tmux_main_command(command)
35
25
  if command
36
- x = tab.index + project.base_index
37
- y = index + tab.project.base_index
38
- e = command.shellescape
39
- n = project.name
40
- "#{project.tmux} send-keys -t #{n}:#{x}.#{y} #{e} C-m"
26
+ _send_target(command.shellescape)
41
27
  else
42
28
  ""
43
29
  end
44
30
  end
45
31
 
32
+ def name
33
+ project.name
34
+ end
35
+
36
+ def window_index
37
+ tab.index + project.base_index
38
+ end
39
+
40
+ def pane_index
41
+ index + tab.project.base_index
42
+ end
43
+
46
44
  def tmux_split_command
47
45
  path = if tab.root?
48
46
  "#{Tmuxinator::Config.default_path_option} #{tab.root}"
@@ -53,5 +51,15 @@ module Tmuxinator
53
51
  def last?
54
52
  index == tab.panes.length - 1
55
53
  end
54
+
55
+ private
56
+
57
+ def _send_target(e)
58
+ _send_keys(tmux_window_and_pane_target, e)
59
+ end
60
+
61
+ def _send_keys(t, e)
62
+ "#{project.tmux} send-keys -t #{t} #{e} C-m"
63
+ end
56
64
  end
57
65
  end
@@ -2,6 +2,7 @@ module Tmuxinator
2
2
  class Project
3
3
  include Tmuxinator::Util
4
4
  include Tmuxinator::Deprecations
5
+ include Tmuxinator::Hooks::Project
5
6
  include Tmuxinator::WemuxSupport
6
7
 
7
8
  RBENVRVM_DEP_MSG = <<-M
@@ -19,12 +20,20 @@ module Tmuxinator
19
20
  SYNC_DEP_MSG = <<-M
20
21
  DEPRECATION: The synchronize option's current default behaviour is to
21
22
  enable pane synchronization before running commands. In a future release,
22
- the default syncronization option will be `after`, i.e. synchronization of
23
+ the default synchronization option will be `after`, i.e. synchronization of
23
24
  panes will occur after the commands described in each of the panes
24
25
  have run. At that time, the current behavior will need to be explicitly
25
26
  enabled, using the `synchronize: before` option. To use this behaviour
26
27
  now, use the 'synchronize: after' option.
27
28
  M
29
+ PRE_DEP_MSG = <<-M
30
+ DEPRECATION: the pre option has been replaced by project hooks and will
31
+ not be supported anymore.
32
+ M
33
+ POST_DEP_MSG = <<-M
34
+ DEPRECATION: the post option has been replaced by project hooks and will
35
+ not be supported anymore.
36
+ M
28
37
 
29
38
  attr_reader :yaml
30
39
  attr_reader :force_attach
@@ -41,8 +50,8 @@ module Tmuxinator
41
50
 
42
51
  content = Erubis::Eruby.new(raw_content).result(binding)
43
52
  YAML.load(content)
44
- rescue SyntaxError, StandardError
45
- raise "Failed to parse config file. Please check your formatting."
53
+ rescue SyntaxError, StandardError => error
54
+ raise "Failed to parse config file: #{error.message}"
46
55
  end
47
56
 
48
57
  new(yaml, options)
@@ -62,9 +71,9 @@ module Tmuxinator
62
71
 
63
72
  def validate!
64
73
  raise "Your project file should include some windows." \
65
- unless self.windows?
74
+ unless windows?
66
75
  raise "Your project file didn't specify a 'project_name'" \
67
- unless self.name?
76
+ unless name?
68
77
  self
69
78
  end
70
79
 
@@ -86,8 +95,16 @@ module Tmuxinator
86
95
  end
87
96
 
88
97
  def render
89
- template = File.read(Tmuxinator::Config.template)
90
- Erubis::Eruby.new(template).result(binding)
98
+ self.class.render_template(Tmuxinator::Config.template, binding)
99
+ end
100
+
101
+ def kill
102
+ self.class.render_template(Tmuxinator::Config.stop_template, binding)
103
+ end
104
+
105
+ def self.render_template(template, bndg)
106
+ content = File.read(template)
107
+ Erubis::Eruby.new(content).result(bndg)
91
108
  end
92
109
 
93
110
  def windows
@@ -100,52 +117,45 @@ module Tmuxinator
100
117
 
101
118
  def root
102
119
  root = yaml["project_root"] || yaml["root"]
103
- root.blank? ? nil : File.expand_path(root).shellescape
120
+ blank?(root) ? nil : File.expand_path(root).shellescape
104
121
  end
105
122
 
106
123
  def name
107
124
  name = custom_name || yaml["project_name"] || yaml["name"]
108
- name.blank? ? nil : name.to_s.shellescape
125
+ blank?(name) ? nil : name.to_s.shellescape
109
126
  end
110
127
 
111
128
  def pre
112
129
  pre_config = yaml["pre"]
113
- if pre_config.is_a?(Array)
114
- pre_config.join("; ")
115
- else
116
- pre_config
117
- end
130
+ parsed_parameters(pre_config)
118
131
  end
119
132
 
120
133
  def attach?
121
- if yaml["attach"].nil?
122
- yaml_attach = true
123
- else
124
- yaml_attach = yaml["attach"]
125
- end
134
+ yaml_attach = if yaml["attach"].nil?
135
+ true
136
+ else
137
+ yaml["attach"]
138
+ end
126
139
  attach = force_attach || !force_detach && yaml_attach
127
140
  attach
128
141
  end
129
142
 
130
143
  def pre_window
131
- if rbenv?
132
- "rbenv shell #{yaml['rbenv']}"
133
- elsif rvm?
134
- "rvm use #{yaml['rvm']}"
135
- elsif pre_tab?
136
- yaml["pre_tab"]
137
- else
138
- yaml["pre_window"]
139
- end
144
+ params = if rbenv?
145
+ "rbenv shell #{yaml['rbenv']}"
146
+ elsif rvm?
147
+ "rvm use #{yaml['rvm']}"
148
+ elsif pre_tab?
149
+ yaml["pre_tab"]
150
+ else
151
+ yaml["pre_window"]
152
+ end
153
+ parsed_parameters(params)
140
154
  end
141
155
 
142
156
  def post
143
157
  post_config = yaml["post"]
144
- if post_config.is_a?(Array)
145
- post_config.join("; ")
146
- else
147
- post_config
148
- end
158
+ parsed_parameters(post_config)
149
159
  end
150
160
 
151
161
  def tmux
@@ -192,7 +202,7 @@ module Tmuxinator
192
202
  end
193
203
 
194
204
  def base_index
195
- get_pane_base_index ? get_pane_base_index.to_i : get_base_index.to_i
205
+ get_base_index.to_i
196
206
  end
197
207
 
198
208
  def pane_base_index
@@ -200,11 +210,11 @@ module Tmuxinator
200
210
  end
201
211
 
202
212
  def startup_window
203
- yaml["startup_window"] || base_index
213
+ "#{name}:#{yaml['startup_window'] || base_index}"
204
214
  end
205
215
 
206
216
  def startup_pane
207
- yaml["startup_pane"] || pane_base_index
217
+ "#{startup_window}.#{yaml['startup_pane'] || pane_base_index}"
208
218
  end
209
219
 
210
220
  def tmux_options?
@@ -228,11 +238,7 @@ module Tmuxinator
228
238
  end
229
239
 
230
240
  def send_pane_command(cmd, window_index, _pane_index)
231
- if cmd.empty?
232
- ""
233
- else
234
- "#{tmux} send-keys -t #{window(window_index)} #{cmd.shellescape} C-m"
235
- end
241
+ send_keys(cmd, window_index)
236
242
  end
237
243
 
238
244
  def send_keys(cmd, window_index)
@@ -244,12 +250,61 @@ module Tmuxinator
244
250
  end
245
251
 
246
252
  def deprecations
247
- deprecations = []
248
- deprecations << RBENVRVM_DEP_MSG if yaml["rbenv"] || yaml["rvm"]
249
- deprecations << TABS_DEP_MSG if yaml["tabs"]
250
- deprecations << CLIARGS_DEP_MSG if yaml["cli_args"]
251
- deprecations << SYNC_DEP_MSG if legacy_synchronize?
252
- deprecations
253
+ deprecation_checks.zip(deprecation_messages).
254
+ inject([]) do |deps, (chk, msg)|
255
+ deps << msg if chk
256
+ deps
257
+ end
258
+ end
259
+
260
+ def deprecation_checks
261
+ [
262
+ rvm_or_rbenv?,
263
+ tabs?,
264
+ cli_args?,
265
+ legacy_synchronize?,
266
+ pre?,
267
+ post?
268
+ ]
269
+ end
270
+
271
+ def deprecation_messages
272
+ [
273
+ RBENVRVM_DEP_MSG,
274
+ TABS_DEP_MSG,
275
+ CLIARGS_DEP_MSG,
276
+ SYNC_DEP_MSG,
277
+ PRE_DEP_MSG,
278
+ POST_DEP_MSG
279
+ ]
280
+ end
281
+
282
+ def rbenv?
283
+ yaml["rbenv"]
284
+ end
285
+
286
+ def rvm?
287
+ yaml["rvm"]
288
+ end
289
+
290
+ def rvm_or_rbenv?
291
+ rvm? || rbenv?
292
+ end
293
+
294
+ def tabs?
295
+ yaml["tabs"]
296
+ end
297
+
298
+ def cli_args?
299
+ yaml["cli_args"]
300
+ end
301
+
302
+ def pre?
303
+ yaml["pre"]
304
+ end
305
+
306
+ def post?
307
+ yaml["post"]
253
308
  end
254
309
 
255
310
  def get_pane_base_index
@@ -261,7 +316,9 @@ module Tmuxinator
261
316
  end
262
317
 
263
318
  def show_tmux_options
264
- "#{tmux} start-server\\; show-option -g"
319
+ "#{tmux} start-server\\; " \
320
+ "show-option -g base-index\\; " \
321
+ "show-window-option -g pane-base-index\\;"
265
322
  end
266
323
 
267
324
  def tmux_new_session_command
@@ -275,6 +332,10 @@ module Tmuxinator
275
332
 
276
333
  private
277
334
 
335
+ def blank?(object)
336
+ (object.respond_to?(:empty?) && object.empty?) || !object
337
+ end
338
+
278
339
  def tmux_config
279
340
  @tmux_config ||= extract_tmux_config
280
341
  end
@@ -306,5 +367,9 @@ module Tmuxinator
306
367
  def window_options
307
368
  yaml["windows"].map(&:values).flatten
308
369
  end
370
+
371
+ def parsed_parameters(parameters)
372
+ parameters.is_a?(Array) ? parameters.join("; ") : parameters
373
+ end
309
374
  end
310
375
  end
@@ -1,3 +1,3 @@
1
1
  module Tmuxinator
2
- VERSION = "0.9.0"
2
+ VERSION = "0.10.0".freeze
3
3
  end
@@ -1,22 +1,31 @@
1
1
  module Tmuxinator
2
2
  module WemuxSupport
3
+ COMMAND = "wemux".freeze
4
+
3
5
  def wemux?
4
- yaml["tmux_command"] == "wemux"
6
+ yaml["tmux_command"] == COMMAND
5
7
  end
6
8
 
7
9
  def load_wemux_overrides
10
+ override_render!
11
+ override_commands!
12
+ end
13
+
14
+ def override_render!
8
15
  class_eval do
9
16
  define_method :render do
10
- template = File.read(Tmuxinator::Config.wemux_template)
11
- Erubis::Eruby.new(template).result(binding)
12
- end
13
-
14
- define_method :name do
15
- "wemux"
17
+ Tmuxinator::Project.render_template(
18
+ Tmuxinator::Config.wemux_template,
19
+ binding
20
+ )
16
21
  end
22
+ end
23
+ end
17
24
 
18
- define_method :tmux do
19
- "wemux"
25
+ def override_commands!
26
+ class_eval do
27
+ %i[name tmux].each do |m|
28
+ define_method(m) { COMMAND }
20
29
  end
21
30
  end
22
31
  end