tmuxinator 0.6.11 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/mux +6 -9
- data/bin/tmuxinator +6 -9
- data/lib/tmuxinator/assets/template.erb +6 -6
- data/lib/tmuxinator/assets/wemux_template.erb +1 -1
- data/lib/tmuxinator/cli.rb +111 -33
- data/lib/tmuxinator/config.rb +47 -35
- data/lib/tmuxinator/pane.rb +21 -5
- data/lib/tmuxinator/project.rb +94 -29
- data/lib/tmuxinator/version.rb +1 -1
- data/lib/tmuxinator/wemux_support.rb +4 -4
- data/lib/tmuxinator/window.rb +15 -5
- data/spec/factories/projects.rb +53 -11
- data/spec/fixtures/detach.yml +41 -0
- data/spec/fixtures/nameless_window.yml +5 -0
- data/spec/fixtures/nowindows.yml +3 -0
- data/spec/fixtures/sample.yml +1 -0
- data/spec/fixtures/sample_number_as_name.yml +5 -0
- data/spec/lib/tmuxinator/cli_spec.rb +191 -30
- data/spec/lib/tmuxinator/config_spec.rb +105 -8
- data/spec/lib/tmuxinator/project_spec.rb +172 -28
- data/spec/lib/tmuxinator/util_spec.rb +0 -1
- data/spec/lib/tmuxinator/wemux_support_spec.rb +47 -0
- data/spec/lib/tmuxinator/window_spec.rb +82 -21
- data/spec/spec_helper.rb +16 -15
- metadata +13 -3
data/lib/tmuxinator/project.rb
CHANGED
@@ -4,11 +4,75 @@ module Tmuxinator
|
|
4
4
|
include Tmuxinator::Deprecations
|
5
5
|
include Tmuxinator::WemuxSupport
|
6
6
|
|
7
|
-
|
7
|
+
RBENVRVM_DEP_MSG = <<-M
|
8
|
+
DEPRECATION: rbenv/rvm-specific options have been replaced by the
|
9
|
+
pre_tab option and will not be supported in 0.8.0.
|
10
|
+
M
|
11
|
+
TABS_DEP_MSG = <<-M
|
12
|
+
DEPRECATION: The tabs option has been replaced by the windows option
|
13
|
+
and will not be supported in 0.8.0.
|
14
|
+
M
|
15
|
+
CLIARGS_DEP_MSG = <<-M
|
16
|
+
DEPRECATION: The cli_args option has been replaced by the tmux_options
|
17
|
+
option and will not be supported in 0.8.0.
|
18
|
+
M
|
19
|
+
|
20
|
+
attr_reader :yaml
|
21
|
+
attr_reader :force_attach
|
22
|
+
attr_reader :force_detach
|
23
|
+
attr_reader :custom_name
|
24
|
+
|
25
|
+
def self.load(path, options = {})
|
26
|
+
yaml = begin
|
27
|
+
raw_content = File.read(path)
|
28
|
+
|
29
|
+
args = options[:args] || []
|
30
|
+
@settings = parse_settings(args)
|
31
|
+
@args = args
|
32
|
+
|
33
|
+
content = Erubis::Eruby.new(raw_content).result(binding)
|
34
|
+
YAML.load(content)
|
35
|
+
rescue SyntaxError, StandardError
|
36
|
+
raise "Failed to parse config file. Please check your formatting."
|
37
|
+
end
|
38
|
+
|
39
|
+
new(yaml, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.parse_settings(args)
|
43
|
+
settings = args.select { |x| x.match(/.*=.*/) }
|
44
|
+
args.reject! { |x| x.match(/.*=.*/) }
|
45
|
+
|
46
|
+
settings.map! do |setting|
|
47
|
+
parts = setting.split("=")
|
48
|
+
[parts[0], parts[1]]
|
49
|
+
end
|
50
|
+
|
51
|
+
Hash[settings]
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate!
|
55
|
+
raise "Your project file should include some windows." \
|
56
|
+
unless self.windows?
|
57
|
+
raise "Your project file didn't specify a 'project_name'" \
|
58
|
+
unless self.name?
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize(yaml, options = {})
|
63
|
+
options[:force_attach] = false if options[:force_attach].nil?
|
64
|
+
options[:force_detach] = false if options[:force_detach].nil?
|
8
65
|
|
9
|
-
def initialize(yaml, custom_name = nil)
|
10
66
|
@yaml = yaml
|
11
|
-
|
67
|
+
|
68
|
+
@custom_name = options[:custom_name]
|
69
|
+
|
70
|
+
@force_attach = options[:force_attach]
|
71
|
+
@force_detach = options[:force_detach]
|
72
|
+
|
73
|
+
raise "Cannot force_attach and force_detach at the same time" \
|
74
|
+
if @force_attach && @force_detach
|
75
|
+
|
12
76
|
load_wemux_overrides if wemux?
|
13
77
|
end
|
14
78
|
|
@@ -20,7 +84,7 @@ module Tmuxinator
|
|
20
84
|
def windows
|
21
85
|
windows_yml = yaml["tabs"] || yaml["windows"]
|
22
86
|
|
23
|
-
@windows ||= windows_yml.map.with_index do |window_yml, index|
|
87
|
+
@windows ||= (windows_yml || {}).map.with_index do |window_yml, index|
|
24
88
|
Tmuxinator::Window.new(window_yml, index, self)
|
25
89
|
end
|
26
90
|
end
|
@@ -32,7 +96,7 @@ module Tmuxinator
|
|
32
96
|
|
33
97
|
def name
|
34
98
|
name = custom_name || yaml["project_name"] || yaml["name"]
|
35
|
-
name.blank? ? nil : name.shellescape
|
99
|
+
name.blank? ? nil : name.to_s.shellescape
|
36
100
|
end
|
37
101
|
|
38
102
|
def pre
|
@@ -44,11 +108,21 @@ module Tmuxinator
|
|
44
108
|
end
|
45
109
|
end
|
46
110
|
|
111
|
+
def attach?
|
112
|
+
if yaml["attach"].nil?
|
113
|
+
yaml_attach = true
|
114
|
+
else
|
115
|
+
yaml_attach = yaml["attach"]
|
116
|
+
end
|
117
|
+
attach = force_attach || !force_detach && yaml_attach
|
118
|
+
attach
|
119
|
+
end
|
120
|
+
|
47
121
|
def pre_window
|
48
122
|
if rbenv?
|
49
|
-
"rbenv shell #{yaml[
|
123
|
+
"rbenv shell #{yaml['rbenv']}"
|
50
124
|
elsif rvm?
|
51
|
-
"rvm use #{yaml[
|
125
|
+
"rvm use #{yaml['rvm']}"
|
52
126
|
elsif pre_tab?
|
53
127
|
yaml["pre_tab"]
|
54
128
|
else
|
@@ -56,14 +130,6 @@ module Tmuxinator
|
|
56
130
|
end
|
57
131
|
end
|
58
132
|
|
59
|
-
def attach
|
60
|
-
attach = true
|
61
|
-
if !yaml["attach"].nil?
|
62
|
-
attach = yaml["attach"]
|
63
|
-
end
|
64
|
-
attach
|
65
|
-
end
|
66
|
-
|
67
133
|
def post
|
68
134
|
post_config = yaml["post"]
|
69
135
|
if post_config.is_a?(Array)
|
@@ -86,8 +152,6 @@ module Tmuxinator
|
|
86
152
|
" -S #{socket_path}"
|
87
153
|
elsif socket_name
|
88
154
|
" -L #{socket_name}"
|
89
|
-
else
|
90
|
-
nil
|
91
155
|
end
|
92
156
|
end
|
93
157
|
|
@@ -101,9 +165,9 @@ module Tmuxinator
|
|
101
165
|
|
102
166
|
def tmux_options
|
103
167
|
if cli_args?
|
104
|
-
" #{yaml[
|
168
|
+
" #{yaml['cli_args'].to_s.strip}"
|
105
169
|
elsif tmux_options?
|
106
|
-
" #{yaml[
|
170
|
+
" #{yaml['tmux_options'].to_s.strip}"
|
107
171
|
else
|
108
172
|
""
|
109
173
|
end
|
@@ -133,15 +197,11 @@ module Tmuxinator
|
|
133
197
|
!name.nil?
|
134
198
|
end
|
135
199
|
|
136
|
-
def attach?
|
137
|
-
!!attach
|
138
|
-
end
|
139
|
-
|
140
200
|
def window(i)
|
141
201
|
"#{name}:#{i}"
|
142
202
|
end
|
143
203
|
|
144
|
-
def send_pane_command(cmd, window_index,
|
204
|
+
def send_pane_command(cmd, window_index, _pane_index)
|
145
205
|
if cmd.empty?
|
146
206
|
""
|
147
207
|
else
|
@@ -151,7 +211,7 @@ module Tmuxinator
|
|
151
211
|
|
152
212
|
def send_keys(cmd, window_index)
|
153
213
|
if cmd.empty?
|
154
|
-
|
214
|
+
""
|
155
215
|
else
|
156
216
|
"#{tmux} send-keys -t #{window(window_index)} #{cmd.shellescape} C-m"
|
157
217
|
end
|
@@ -159,9 +219,9 @@ module Tmuxinator
|
|
159
219
|
|
160
220
|
def deprecations
|
161
221
|
deprecations = []
|
162
|
-
deprecations <<
|
163
|
-
deprecations <<
|
164
|
-
deprecations <<
|
222
|
+
deprecations << RBENVRVM_DEP_MSG if yaml["rbenv"] || yaml["rvm"]
|
223
|
+
deprecations << TABS_DEP_MSG if yaml["tabs"]
|
224
|
+
deprecations << CLIARGS_DEP_MSG if yaml["cli_args"]
|
165
225
|
deprecations
|
166
226
|
end
|
167
227
|
|
@@ -177,6 +237,11 @@ module Tmuxinator
|
|
177
237
|
"#{tmux} start-server\\; show-option -g"
|
178
238
|
end
|
179
239
|
|
240
|
+
def tmux_new_session_command
|
241
|
+
window = windows.first.tmux_window_name_option
|
242
|
+
"#{tmux} new-session -d -s #{name} #{window}"
|
243
|
+
end
|
244
|
+
|
180
245
|
private
|
181
246
|
|
182
247
|
def tmux_config
|
@@ -187,7 +252,7 @@ module Tmuxinator
|
|
187
252
|
options_hash = {}
|
188
253
|
|
189
254
|
options_string = `#{show_tmux_options}`
|
190
|
-
options_string.encode!("UTF-8", :
|
255
|
+
options_string.encode!("UTF-8", invalid: :replace)
|
191
256
|
options_string.split("\n").map do |entry|
|
192
257
|
key, value = entry.split("\s")
|
193
258
|
options_hash[key] = value
|
data/lib/tmuxinator/version.rb
CHANGED
@@ -5,17 +5,17 @@ module Tmuxinator
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def load_wemux_overrides
|
8
|
-
|
9
|
-
|
8
|
+
class_eval do
|
9
|
+
define_method :render do
|
10
10
|
template = File.read(Tmuxinator::Config.wemux_template)
|
11
11
|
Erubis::Eruby.new(template).result(binding)
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
define_method :name do
|
15
15
|
"wemux"
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
define_method :tmux do
|
19
19
|
"wemux"
|
20
20
|
end
|
21
21
|
end
|
data/lib/tmuxinator/window.rb
CHANGED
@@ -5,7 +5,9 @@ module Tmuxinator
|
|
5
5
|
attr_reader :name, :root, :panes, :layout, :commands, :index, :project
|
6
6
|
|
7
7
|
def initialize(window_yaml, index, project)
|
8
|
-
@name = !window_yaml.keys.first.nil?
|
8
|
+
@name = if !window_yaml.keys.first.nil?
|
9
|
+
window_yaml.keys.first.shellescape
|
10
|
+
end
|
9
11
|
@root = nil
|
10
12
|
@panes = []
|
11
13
|
@layout = nil
|
@@ -18,7 +20,11 @@ module Tmuxinator
|
|
18
20
|
if value.is_a?(Hash)
|
19
21
|
@layout = value["layout"] ? value["layout"].shellescape : nil
|
20
22
|
@pre = value["pre"] if value["pre"]
|
21
|
-
@root =
|
23
|
+
@root = if value["root"]
|
24
|
+
File.expand_path(value["root"]).shellescape
|
25
|
+
elsif project.root?
|
26
|
+
project.root
|
27
|
+
end
|
22
28
|
|
23
29
|
@panes = build_panes(value["panes"])
|
24
30
|
else
|
@@ -29,7 +35,7 @@ module Tmuxinator
|
|
29
35
|
def build_panes(panes_yml)
|
30
36
|
Array(panes_yml).map.with_index do |pane_yml, index|
|
31
37
|
if pane_yml.is_a?(Hash)
|
32
|
-
pane_yml.map do |
|
38
|
+
pane_yml.map do |_name, commands|
|
33
39
|
Tmuxinator::Pane.new(index, project, self, *commands)
|
34
40
|
end
|
35
41
|
else
|
@@ -38,7 +44,7 @@ module Tmuxinator
|
|
38
44
|
end.flatten
|
39
45
|
end
|
40
46
|
|
41
|
-
def build_commands(
|
47
|
+
def build_commands(_prefix, command_yml)
|
42
48
|
if command_yml.is_a?(Array)
|
43
49
|
command_yml.map do |command|
|
44
50
|
"#{tmux_window_command_prefix} #{command.shellescape} C-m" if command
|
@@ -80,9 +86,13 @@ module Tmuxinator
|
|
80
86
|
"#{project.tmux} send-keys -t #{project.name}:#{index + project.base_index}"
|
81
87
|
end
|
82
88
|
|
89
|
+
def tmux_window_name_option
|
90
|
+
name ? "-n #{name}" : ""
|
91
|
+
end
|
92
|
+
|
83
93
|
def tmux_new_window_command
|
84
94
|
path = root? ? "#{Tmuxinator::Config.default_path_option} #{root}" : nil
|
85
|
-
"#{project.tmux} new-window #{path} -t #{tmux_window_target}
|
95
|
+
"#{project.tmux} new-window #{path} -t #{tmux_window_target} #{tmux_window_name_option}"
|
86
96
|
end
|
87
97
|
|
88
98
|
def tmux_layout_command
|
data/spec/factories/projects.rb
CHANGED
@@ -1,39 +1,81 @@
|
|
1
|
+
def yaml_load(file)
|
2
|
+
YAML.load(File.read(File.expand_path(file)))
|
3
|
+
end
|
1
4
|
FactoryGirl.define do
|
2
|
-
factory :project, :
|
5
|
+
factory :project, class: Tmuxinator::Project do
|
6
|
+
transient do
|
7
|
+
file { yaml_load("spec/fixtures/sample.yml") }
|
8
|
+
end
|
9
|
+
|
10
|
+
initialize_with { Tmuxinator::Project.new(file) }
|
11
|
+
end
|
12
|
+
|
13
|
+
factory :project_with_force_attach, class: Tmuxinator::Project do
|
14
|
+
transient do
|
15
|
+
file { yaml_load("spec/fixtures/detach.yml") }
|
16
|
+
end
|
17
|
+
|
18
|
+
initialize_with { Tmuxinator::Project.new(file, force_attach: true) }
|
19
|
+
end
|
20
|
+
|
21
|
+
factory :project_with_force_detach, class: Tmuxinator::Project do
|
22
|
+
transient do
|
23
|
+
file { yaml_load("spec/fixtures/detach.yml") }
|
24
|
+
end
|
25
|
+
initialize_with { Tmuxinator::Project.new(file, force_detach: true) }
|
26
|
+
end
|
27
|
+
|
28
|
+
factory :project_with_custom_name, class: Tmuxinator::Project do
|
29
|
+
transient do
|
30
|
+
file { yaml_load("spec/fixtures/sample.yml") }
|
31
|
+
end
|
32
|
+
|
33
|
+
initialize_with { Tmuxinator::Project.new(file, custom_name: "custom") }
|
34
|
+
end
|
35
|
+
|
36
|
+
factory :project_with_number_as_name, class: Tmuxinator::Project do
|
3
37
|
transient do
|
4
|
-
file {
|
38
|
+
file { yaml_load("spec/fixtures/sample_number_as_name.yml") }
|
5
39
|
end
|
6
40
|
|
7
41
|
initialize_with { Tmuxinator::Project.new(file) }
|
8
42
|
end
|
9
43
|
|
10
|
-
factory :
|
44
|
+
factory :project_with_deprecations, class: Tmuxinator::Project do
|
11
45
|
transient do
|
12
|
-
file {
|
46
|
+
file { yaml_load("spec/fixtures/sample.deprecations.yml") }
|
13
47
|
end
|
14
48
|
|
15
|
-
initialize_with { Tmuxinator::Project.new(file
|
49
|
+
initialize_with { Tmuxinator::Project.new(file) }
|
50
|
+
end
|
51
|
+
|
52
|
+
factory :wemux_project, class: Tmuxinator::Project do
|
53
|
+
transient do
|
54
|
+
file { yaml_load("spec/fixtures/sample_wemux.yml") }
|
55
|
+
end
|
56
|
+
|
57
|
+
initialize_with { Tmuxinator::Project.new(file) }
|
16
58
|
end
|
17
59
|
|
18
|
-
factory :
|
60
|
+
factory :noname_project, class: Tmuxinator::Project do
|
19
61
|
transient do
|
20
|
-
file {
|
62
|
+
file { yaml_load("spec/fixtures/noname.yml") }
|
21
63
|
end
|
22
64
|
|
23
65
|
initialize_with { Tmuxinator::Project.new(file) }
|
24
66
|
end
|
25
67
|
|
26
|
-
factory :
|
68
|
+
factory :nowindows_project, class: Tmuxinator::Project do
|
27
69
|
transient do
|
28
|
-
file {
|
70
|
+
file { yaml_load("spec/fixtures/nowindows.yml") }
|
29
71
|
end
|
30
72
|
|
31
73
|
initialize_with { Tmuxinator::Project.new(file) }
|
32
74
|
end
|
33
75
|
|
34
|
-
factory :
|
76
|
+
factory :nameless_window_project, class: Tmuxinator::Project do
|
35
77
|
transient do
|
36
|
-
file {
|
78
|
+
file { yaml_load("spec/fixtures/nameless_window.yml") }
|
37
79
|
end
|
38
80
|
|
39
81
|
initialize_with { Tmuxinator::Project.new(file) }
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# ~/.tmuxinator/sample.yml
|
2
|
+
# you can make as many tabs as you wish...
|
3
|
+
|
4
|
+
name: sample
|
5
|
+
root: ~/test
|
6
|
+
socket_name: foo # Remove to use default socket
|
7
|
+
pre: sudo /etc/rc.d/mysqld start # Runs before everything
|
8
|
+
pre_window: rbenv shell 2.0.0-p247 # Runs in each tab and pane
|
9
|
+
tmux_options: -f ~/.tmux.mac.conf # Pass arguments to tmux
|
10
|
+
attach: false
|
11
|
+
windows:
|
12
|
+
- editor:
|
13
|
+
pre:
|
14
|
+
- echo "I get run in each pane, before each pane command!"
|
15
|
+
-
|
16
|
+
layout: main-vertical
|
17
|
+
panes:
|
18
|
+
- vim
|
19
|
+
- #empty, will just run plain bash
|
20
|
+
- top
|
21
|
+
- pane_with_multiple_commands:
|
22
|
+
- ssh server
|
23
|
+
- echo "Hello"
|
24
|
+
- shell:
|
25
|
+
- git pull
|
26
|
+
- git merge
|
27
|
+
- guard:
|
28
|
+
layout: tiled
|
29
|
+
pre:
|
30
|
+
- echo "I get run in each pane."
|
31
|
+
- echo "Before each pane command!"
|
32
|
+
panes:
|
33
|
+
-
|
34
|
+
- #empty, will just run plain bash
|
35
|
+
-
|
36
|
+
- database: bundle exec rails db
|
37
|
+
- server: bundle exec rails s
|
38
|
+
- logs: tail -f log/development.log
|
39
|
+
- console: bundle exec rails c
|
40
|
+
- capistrano:
|
41
|
+
- server: ssh user@example.com
|
data/spec/fixtures/sample.yml
CHANGED
@@ -7,6 +7,7 @@ socket_name: foo # Remove to use default socket
|
|
7
7
|
pre: sudo /etc/rc.d/mysqld start # Runs before everything
|
8
8
|
pre_window: rbenv shell 2.0.0-p247 # Runs in each tab and pane
|
9
9
|
tmux_options: -f ~/.tmux.mac.conf # Pass arguments to tmux
|
10
|
+
tmux_detached: false
|
10
11
|
windows:
|
11
12
|
- editor:
|
12
13
|
pre:
|