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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 079c5def07857f7b54737cd711899a7c529fee96
|
4
|
+
data.tar.gz: 461725febed6618763f593eec2952cbce8866368
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4860c8924f4feb57ae84f2d122a78b9680ff08b83e3e446c70c6464ced07b4e81be1e80e347a20e660d1c386f33d3a393caa585813a1d3eb78648c94c4173ec
|
7
|
+
data.tar.gz: 6b05f2ad6143fd9cd4aa15318dd8e9e9dc816a7e080cb414e468977d7a0bf7d3583f58fd36fd7e981d6ebb103f7c3690b130062980beadbc37bf6728e0bfe946
|
data/bin/mux
CHANGED
@@ -4,16 +4,13 @@ $: << File.expand_path("../../lib/", __FILE__)
|
|
4
4
|
require "thor"
|
5
5
|
require "tmuxinator"
|
6
6
|
|
7
|
-
|
8
|
-
name = ARGV[0]
|
7
|
+
name = ARGV[0] || nil
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
Tmuxinator::Cli.start
|
16
|
-
end
|
9
|
+
if ARGV.length == 0 && Tmuxinator::Config.local?
|
10
|
+
Tmuxinator::Cli.new.local
|
11
|
+
elsif name && !Tmuxinator::Cli::COMMANDS.keys.include?(name.to_sym) &&
|
12
|
+
Tmuxinator::Config.exists?(name)
|
13
|
+
Tmuxinator::Cli.new.start(name, *ARGV.drop(1))
|
17
14
|
else
|
18
15
|
Tmuxinator::Cli.start
|
19
16
|
end
|
data/bin/tmuxinator
CHANGED
@@ -4,16 +4,13 @@ $: << File.expand_path("../../lib/", __FILE__)
|
|
4
4
|
require "thor"
|
5
5
|
require "tmuxinator"
|
6
6
|
|
7
|
-
|
8
|
-
name = ARGV[0]
|
7
|
+
name = ARGV[0] || nil
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
Tmuxinator::Cli.start
|
16
|
-
end
|
9
|
+
if ARGV.length == 0 && Tmuxinator::Config.local?
|
10
|
+
Tmuxinator::Cli.new.local
|
11
|
+
elsif name && !Tmuxinator::Cli::COMMANDS.keys.include?(name.to_sym) &&
|
12
|
+
Tmuxinator::Config.exists?(name)
|
13
|
+
Tmuxinator::Cli.new.start(name, *ARGV.drop(1))
|
17
14
|
else
|
18
15
|
Tmuxinator::Cli.start
|
19
16
|
end
|
@@ -14,7 +14,7 @@ if [ "$?" -eq 1 ]; then
|
|
14
14
|
|
15
15
|
# Create the session and the first window. Manually switch to root
|
16
16
|
# directory if required to support tmux < 1.9
|
17
|
-
TMUX= <%=
|
17
|
+
TMUX= <%= tmux_new_session_command %>
|
18
18
|
<% if windows.first.root? %>
|
19
19
|
<%= windows.first.tmux_window_command_prefix %> <%= "cd #{windows.first.root}".shellescape %> C-m
|
20
20
|
<% end %>
|
@@ -71,11 +71,11 @@ if [ "$?" -eq 1 ]; then
|
|
71
71
|
fi
|
72
72
|
|
73
73
|
<%- if attach? -%>
|
74
|
-
if [ -z "$TMUX" ]; then
|
75
|
-
|
76
|
-
else
|
77
|
-
|
78
|
-
fi
|
74
|
+
if [ -z "$TMUX" ]; then
|
75
|
+
<%= tmux %> -u attach-session -t <%= name %>
|
76
|
+
else
|
77
|
+
<%= tmux %> -u switch-client -t <%= name %>
|
78
|
+
fi
|
79
79
|
<%- end -%>
|
80
80
|
|
81
81
|
<%= post %>
|
data/lib/tmuxinator/cli.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
module Tmuxinator
|
2
2
|
class Cli < Thor
|
3
|
+
# By default, Thor returns exit(0) when an error occurs.
|
4
|
+
# Please see: https://github.com/tmuxinator/tmuxinator/issues/192
|
5
|
+
def self.exit_on_failure?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
3
9
|
include Tmuxinator::Util
|
4
10
|
|
5
11
|
COMMANDS = {
|
@@ -7,9 +13,16 @@ module Tmuxinator
|
|
7
13
|
completions: "Used for shell completion",
|
8
14
|
new: "Create a new project file and open it in your editor",
|
9
15
|
open: "Alias of new",
|
10
|
-
start:
|
16
|
+
start: <<-DESC,
|
17
|
+
Start a tmux session using a project's tmuxinator config,
|
18
|
+
with an optional [ALIAS] for project reuse
|
19
|
+
DESC
|
20
|
+
local: "Start a tmux session using ./.tmuxinator.yml",
|
11
21
|
debug: "Output the shell commands that are generated by tmuxinator",
|
12
|
-
copy:
|
22
|
+
copy: <<-DESC,
|
23
|
+
Copy an existing project to a new project and open it in
|
24
|
+
your editor
|
25
|
+
DESC
|
13
26
|
delete: "Deletes given project",
|
14
27
|
implode: "Deletes all tmuxinator projects",
|
15
28
|
version: "Display installed tmuxinator version",
|
@@ -17,18 +30,19 @@ module Tmuxinator
|
|
17
30
|
list: "Lists all tmuxinator projects"
|
18
31
|
}
|
19
32
|
|
20
|
-
package_name "tmuxinator"
|
33
|
+
package_name "tmuxinator" \
|
34
|
+
unless Gem::Version.create(Thor::VERSION) < Gem::Version.create("0.18")
|
21
35
|
|
22
36
|
desc "commands", COMMANDS[:commands]
|
23
37
|
|
24
38
|
def commands(shell = nil)
|
25
39
|
out = if shell == "zsh"
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
40
|
+
COMMANDS.map do |command, desc|
|
41
|
+
"#{command}:#{desc}"
|
42
|
+
end.join("\n")
|
43
|
+
else
|
44
|
+
COMMANDS.keys.join("\n")
|
45
|
+
end
|
32
46
|
|
33
47
|
puts out
|
34
48
|
end
|
@@ -48,39 +62,100 @@ module Tmuxinator
|
|
48
62
|
map "o" => :new
|
49
63
|
map "e" => :new
|
50
64
|
map "n" => :new
|
65
|
+
method_option :local, type: :boolean,
|
66
|
+
aliases: ["-l"],
|
67
|
+
desc: "Create local project file at ./.tmuxinator.yml"
|
51
68
|
|
52
69
|
def new(name)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
70
|
+
project_file = if options[:local]
|
71
|
+
Tmuxinator::Config::LOCAL_DEFAULT
|
72
|
+
else
|
73
|
+
Tmuxinator::Config.default_project(name)
|
74
|
+
end
|
75
|
+
unless Tmuxinator::Config.exists?(project_file)
|
76
|
+
template = Tmuxinator::Config.default? ? :default : :sample
|
77
|
+
content = File.read(Tmuxinator::Config.send(template.to_sym))
|
78
|
+
erb = Erubis::Eruby.new(content).result(binding)
|
79
|
+
File.open(project_file, "w") { |f| f.write(erb) }
|
59
80
|
end
|
60
81
|
|
61
|
-
Kernel.system("$EDITOR #{
|
82
|
+
Kernel.system("$EDITOR #{project_file}") || doctor
|
62
83
|
end
|
63
84
|
|
64
|
-
|
65
|
-
|
85
|
+
no_commands do
|
86
|
+
def create_project(project_options = {})
|
87
|
+
attach_opt = project_options[:attach]
|
88
|
+
attach = !attach_opt.nil? && attach_opt ? true : false
|
89
|
+
detach = !attach_opt.nil? && !attach_opt ? true : false
|
90
|
+
|
91
|
+
options = {
|
92
|
+
force_attach: attach,
|
93
|
+
force_detach: detach,
|
94
|
+
name: project_options[:name],
|
95
|
+
custom_name: project_options[:custom_name],
|
96
|
+
args: project_options[:args]
|
97
|
+
}
|
98
|
+
|
99
|
+
begin
|
100
|
+
Tmuxinator::Config.validate(options)
|
101
|
+
rescue => e
|
102
|
+
exit! e.message
|
103
|
+
end
|
104
|
+
end
|
66
105
|
|
67
|
-
|
68
|
-
|
106
|
+
def render_project(project)
|
107
|
+
if project.deprecations.any?
|
108
|
+
project.deprecations.each { |deprecation| say deprecation, :red }
|
109
|
+
puts
|
110
|
+
print "Press ENTER to continue."
|
111
|
+
STDIN.getc
|
112
|
+
end
|
69
113
|
|
70
|
-
|
71
|
-
project.deprecations.each { |deprecation| say deprecation, :red }
|
72
|
-
puts
|
73
|
-
print "Press ENTER to continue."
|
74
|
-
STDIN.getc
|
114
|
+
Kernel.exec(project.render)
|
75
115
|
end
|
116
|
+
end
|
76
117
|
|
77
|
-
|
118
|
+
desc "start [PROJECT] [ARGS]", COMMANDS[:start]
|
119
|
+
map "s" => :start
|
120
|
+
method_option :attach, type: :boolean,
|
121
|
+
aliases: "-a",
|
122
|
+
desc: "Attach to tmux session after creation."
|
123
|
+
method_option :name, aliases: "-n",
|
124
|
+
desc: "Give the session a different name"
|
125
|
+
|
126
|
+
def start(name, *args)
|
127
|
+
params = {
|
128
|
+
name: name,
|
129
|
+
custom_name: options[:name],
|
130
|
+
attach: options[:attach],
|
131
|
+
args: args
|
132
|
+
}
|
133
|
+
project = create_project(params)
|
134
|
+
render_project(project)
|
78
135
|
end
|
79
136
|
|
80
|
-
desc "
|
137
|
+
desc "local", COMMANDS[:local]
|
138
|
+
map "." => :local
|
139
|
+
|
140
|
+
def local
|
141
|
+
render_project(create_project(attach: options[:attach]))
|
142
|
+
end
|
81
143
|
|
82
|
-
|
83
|
-
|
144
|
+
method_option :attach, type: :boolean,
|
145
|
+
aliases: "-a",
|
146
|
+
desc: "Attach to tmux session after creation."
|
147
|
+
method_option :name, aliases: "-n",
|
148
|
+
desc: "Give the session a different name"
|
149
|
+
desc "debug [PROJECT] [ARGS]", COMMANDS[:debug]
|
150
|
+
|
151
|
+
def debug(name, *args)
|
152
|
+
params = {
|
153
|
+
name: name,
|
154
|
+
custom_name: options[:name],
|
155
|
+
attach: options[:attach],
|
156
|
+
args: args
|
157
|
+
}
|
158
|
+
project = create_project(params)
|
84
159
|
puts project.render
|
85
160
|
end
|
86
161
|
|
@@ -92,9 +167,12 @@ module Tmuxinator
|
|
92
167
|
existing_config_path = Tmuxinator::Config.project(existing)
|
93
168
|
new_config_path = Tmuxinator::Config.project(new)
|
94
169
|
|
95
|
-
exit!("Project #{existing} doesn't exist!")
|
170
|
+
exit!("Project #{existing} doesn't exist!") \
|
171
|
+
unless Tmuxinator::Config.exists?(existing)
|
96
172
|
|
97
|
-
|
173
|
+
new_exists = Tmuxinator::Config.exists?(new)
|
174
|
+
question = "#{new} already exists, would you like to overwrite it?"
|
175
|
+
if !new_exists || yes?(question, :red)
|
98
176
|
say "Overwriting #{new}" if Tmuxinator::Config.exists?(new)
|
99
177
|
FileUtils.copy_file(existing_config_path, new_config_path)
|
100
178
|
end
|
@@ -108,7 +186,7 @@ module Tmuxinator
|
|
108
186
|
|
109
187
|
def delete(project)
|
110
188
|
if Tmuxinator::Config.exists?(project)
|
111
|
-
config =
|
189
|
+
config = "#{Tmuxinator::Config.root}/#{project}.yml"
|
112
190
|
|
113
191
|
if yes?("Are you sure you want to delete #{project}?(y/n)", :red)
|
114
192
|
FileUtils.rm(config)
|
@@ -156,7 +234,7 @@ module Tmuxinator
|
|
156
234
|
yes_no Tmuxinator::Config.editor?
|
157
235
|
|
158
236
|
say "Checking if $SHELL is set ==> "
|
159
|
-
yes_no
|
237
|
+
yes_no Tmuxinator::Config.shell?
|
160
238
|
end
|
161
239
|
end
|
162
240
|
end
|
data/lib/tmuxinator/config.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
module Tmuxinator
|
2
2
|
class Config
|
3
|
+
LOCAL_DEFAULT = "./.tmuxinator.yml".freeze
|
4
|
+
NO_LOCAL_FILE_MSG = "Project file at ./.tmuxinator.yml doesn't exist."
|
5
|
+
|
3
6
|
class << self
|
4
7
|
def root
|
5
|
-
|
6
|
-
"#{ENV[
|
8
|
+
root_dir = File.expand_path("~/.tmuxinator")
|
9
|
+
Dir.mkdir("#{ENV['HOME']}/.tmuxinator") unless File.directory?(root_dir)
|
10
|
+
"#{ENV['HOME']}/.tmuxinator"
|
7
11
|
end
|
8
12
|
|
9
13
|
def sample
|
10
|
-
"
|
14
|
+
asset_path "sample.yml"
|
11
15
|
end
|
12
16
|
|
13
17
|
def default
|
14
|
-
"#{ENV[
|
18
|
+
"#{ENV['HOME']}/.tmuxinator/default.yml"
|
15
19
|
end
|
16
20
|
|
17
21
|
def default?
|
@@ -42,18 +46,33 @@ module Tmuxinator
|
|
42
46
|
File.exists?(project(name))
|
43
47
|
end
|
44
48
|
|
45
|
-
def
|
49
|
+
def project_in_root(name)
|
46
50
|
projects = Dir.glob("#{root}/**/*.yml")
|
47
|
-
|
48
|
-
|
51
|
+
projects.detect { |project| File.basename(project, ".yml") == name }
|
52
|
+
end
|
53
|
+
|
54
|
+
def local?
|
55
|
+
project_in_local
|
56
|
+
end
|
57
|
+
|
58
|
+
def project_in_local
|
59
|
+
[LOCAL_DEFAULT].detect { |f| File.exists?(f) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_project(name)
|
63
|
+
"#{root}/#{name}.yml"
|
64
|
+
end
|
65
|
+
|
66
|
+
def project(name)
|
67
|
+
project_in_root(name) || project_in_local || default_project(name)
|
49
68
|
end
|
50
69
|
|
51
70
|
def template
|
52
|
-
"
|
71
|
+
asset_path "template.erb"
|
53
72
|
end
|
54
73
|
|
55
74
|
def wemux_template
|
56
|
-
"
|
75
|
+
asset_path "wemux_template.erb"
|
57
76
|
end
|
58
77
|
|
59
78
|
def configs
|
@@ -62,34 +81,27 @@ module Tmuxinator
|
|
62
81
|
end
|
63
82
|
end
|
64
83
|
|
65
|
-
def validate(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
unless project.windows?
|
83
|
-
puts "Your project file should include some windows."
|
84
|
-
exit!
|
85
|
-
end
|
84
|
+
def validate(options = {})
|
85
|
+
name = options[:name]
|
86
|
+
options[:force_attach] ||= false
|
87
|
+
options[:force_detach] ||= false
|
88
|
+
|
89
|
+
project_file = if name.nil?
|
90
|
+
raise NO_LOCAL_FILE_MSG \
|
91
|
+
unless Tmuxinator::Config.local?
|
92
|
+
project_in_local
|
93
|
+
else
|
94
|
+
raise "Project #{name} doesn't exist." \
|
95
|
+
unless Tmuxinator::Config.exists?(name)
|
96
|
+
Tmuxinator::Config.project(name)
|
97
|
+
end
|
98
|
+
Tmuxinator::Project.load(project_file, options).validate!
|
99
|
+
end
|
86
100
|
|
87
|
-
|
88
|
-
puts "Your project file didn't specify a 'project_name'"
|
89
|
-
exit!
|
90
|
-
end
|
101
|
+
private
|
91
102
|
|
92
|
-
|
103
|
+
def asset_path(asset)
|
104
|
+
"#{File.dirname(__FILE__)}/assets/#{asset}"
|
93
105
|
end
|
94
106
|
end
|
95
107
|
end
|
data/lib/tmuxinator/pane.rb
CHANGED
@@ -10,27 +10,43 @@ module Tmuxinator
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def tmux_window_and_pane_target
|
13
|
-
|
13
|
+
x = tab.index + project.base_index
|
14
|
+
y = index + project.base_index
|
15
|
+
"#{project.name}:#{x}.#{y}"
|
14
16
|
end
|
15
17
|
|
16
18
|
def tmux_pre_command
|
17
19
|
return unless tab.pre
|
18
20
|
|
19
|
-
|
21
|
+
t = tmux_window_and_pane_target
|
22
|
+
e = tab.pre.shellescape
|
23
|
+
"#{project.tmux} send-keys -t #{t} #{e} C-m"
|
20
24
|
end
|
21
25
|
|
22
26
|
def tmux_pre_window_command
|
23
27
|
return unless project.pre_window
|
24
28
|
|
25
|
-
|
29
|
+
t = tmux_window_and_pane_target
|
30
|
+
e = project.pre_window.shellescape
|
31
|
+
"#{project.tmux} send-keys -t #{t} #{e} C-m"
|
26
32
|
end
|
27
33
|
|
28
34
|
def tmux_main_command(command)
|
29
|
-
|
35
|
+
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"
|
41
|
+
else
|
42
|
+
""
|
43
|
+
end
|
30
44
|
end
|
31
45
|
|
32
46
|
def tmux_split_command
|
33
|
-
path = tab.root?
|
47
|
+
path = if tab.root?
|
48
|
+
"#{Tmuxinator::Config.default_path_option} #{tab.root}"
|
49
|
+
end
|
34
50
|
"#{project.tmux} splitw #{path} -t #{tab.tmux_window_target}"
|
35
51
|
end
|
36
52
|
|