tmuxinator 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/tmuxinator +1 -1
- data/lib/tmuxinator.rb +6 -7
- data/lib/tmuxinator/assets/sample.yml +13 -1
- data/lib/tmuxinator/assets/template-stop.erb +11 -0
- data/lib/tmuxinator/assets/template.erb +15 -1
- data/lib/tmuxinator/cli.rb +85 -15
- data/lib/tmuxinator/config.rb +74 -30
- data/lib/tmuxinator/deprecations.rb +8 -0
- data/lib/tmuxinator/doctor.rb +17 -0
- data/lib/tmuxinator/hooks.rb +14 -0
- data/lib/tmuxinator/hooks/project.rb +42 -0
- data/lib/tmuxinator/pane.rb +26 -18
- data/lib/tmuxinator/project.rb +113 -48
- data/lib/tmuxinator/version.rb +1 -1
- data/lib/tmuxinator/wemux_support.rb +18 -9
- data/lib/tmuxinator/window.rb +42 -26
- data/spec/fixtures/TMUXINATOR_CONFIG/TMUXINATOR_CONFIG.yml +0 -0
- data/spec/fixtures/dot-tmuxinator/both.yml +0 -0
- data/spec/fixtures/dot-tmuxinator/dup/local-dup.yml +0 -0
- data/spec/fixtures/dot-tmuxinator/home.yml +0 -0
- data/spec/fixtures/dot-tmuxinator/local-dup.yml +0 -0
- data/spec/fixtures/sample.yml +0 -1
- data/spec/fixtures/xdg-tmuxinator/both.yml +0 -0
- data/spec/fixtures/xdg-tmuxinator/xdg.yml +0 -0
- data/spec/lib/tmuxinator/cli_spec.rb +87 -13
- data/spec/lib/tmuxinator/config_spec.rb +163 -91
- data/spec/lib/tmuxinator/doctor_spec.rb +69 -0
- data/spec/lib/tmuxinator/hooks/project_spec.rb +63 -0
- data/spec/lib/tmuxinator/hooks_spec.rb +31 -0
- data/spec/lib/tmuxinator/pane_spec.rb +24 -1
- data/spec/lib/tmuxinator/project_spec.rb +58 -23
- data/spec/lib/tmuxinator/window_spec.rb +8 -6
- data/spec/spec_helper.rb +2 -1
- metadata +177 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b82c1fce5acc4afbea3917be671204b8ec18ce24
|
4
|
+
data.tar.gz: '06860d74aa9ccabd291d0f4e996fdfdf803600d9'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e240783bffcbabaa05f371944a7e6654117b9ca1840e7cb2cdf736171943e740973ce8d38506d67c8cd5a8b2ebab360727f3d67b84587c2241c4850e568118ef
|
7
|
+
data.tar.gz: ca0fc2c809ead67680c77cbb2fff2a43d917ffaa6a89c40ed9ef2c46eef2f517611814c2b385979c18401709158e4695d602bec448d599d70148a0789d916012
|
data/bin/tmuxinator
CHANGED
@@ -6,7 +6,7 @@ require "tmuxinator"
|
|
6
6
|
|
7
7
|
name = ARGV[0] || nil
|
8
8
|
|
9
|
-
if ARGV.
|
9
|
+
if ARGV.empty? && Tmuxinator::Config.local?
|
10
10
|
Tmuxinator::Cli.new.local
|
11
11
|
elsif name && !Tmuxinator::Cli::COMMANDS.keys.include?(name.to_sym) &&
|
12
12
|
Tmuxinator::Config.exists?(name)
|
data/lib/tmuxinator.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
|
-
require "yaml"
|
2
1
|
require "erubis"
|
2
|
+
require "fileutils"
|
3
3
|
require "shellwords"
|
4
4
|
require "thor"
|
5
5
|
require "thor/version"
|
6
|
+
require "xdg"
|
7
|
+
require "yaml"
|
6
8
|
|
7
9
|
require "tmuxinator/util"
|
8
10
|
require "tmuxinator/deprecations"
|
9
11
|
require "tmuxinator/wemux_support"
|
10
12
|
require "tmuxinator/cli"
|
11
13
|
require "tmuxinator/config"
|
14
|
+
require "tmuxinator/doctor"
|
15
|
+
require "tmuxinator/hooks"
|
16
|
+
require "tmuxinator/hooks/project"
|
12
17
|
require "tmuxinator/pane"
|
13
18
|
require "tmuxinator/project"
|
14
19
|
require "tmuxinator/window"
|
@@ -16,9 +21,3 @@ require "tmuxinator/version"
|
|
16
21
|
|
17
22
|
module Tmuxinator
|
18
23
|
end
|
19
|
-
|
20
|
-
class Object
|
21
|
-
def blank?
|
22
|
-
respond_to?(:empty?) ? !!empty? : !self
|
23
|
-
end
|
24
|
-
end
|
@@ -9,6 +9,18 @@ root: ~/
|
|
9
9
|
# Runs before everything. Use it to start daemons etc.
|
10
10
|
# pre: sudo /etc/rc.d/mysqld start
|
11
11
|
|
12
|
+
# Project hooks
|
13
|
+
# Runs on project start, always
|
14
|
+
# on_project_start: command
|
15
|
+
# Run on project start, the first time
|
16
|
+
# on_project_first_start: command
|
17
|
+
# Run on project start, after the first time
|
18
|
+
# on_project_restart: command
|
19
|
+
# Run on project exit ( detaching from tmux session )
|
20
|
+
# on_project_exit: command
|
21
|
+
# Run on project stop
|
22
|
+
# on_project_stop: command
|
23
|
+
|
12
24
|
# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions.
|
13
25
|
# pre_window: rbenv shell 2.0.0-p247
|
14
26
|
|
@@ -21,7 +33,7 @@ root: ~/
|
|
21
33
|
# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used.
|
22
34
|
# startup_window: editor
|
23
35
|
|
24
|
-
#
|
36
|
+
# Specifies (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used.
|
25
37
|
# startup_pane: 1
|
26
38
|
|
27
39
|
# Controls whether the tmux session should be attached to automatically. Defaults to true.
|
@@ -6,11 +6,18 @@ unset RBENV_DIR
|
|
6
6
|
|
7
7
|
<%= tmux %> start-server;
|
8
8
|
|
9
|
+
cd <%= root || "." %>
|
10
|
+
|
11
|
+
# Run on_project_start command.
|
12
|
+
<%= hook_on_project_start %>
|
13
|
+
|
9
14
|
<%- if !tmux_has_session? name -%>
|
10
|
-
cd <%= root || "." %>
|
11
15
|
|
12
16
|
# Run pre command.
|
13
17
|
<%= pre %>
|
18
|
+
|
19
|
+
# Run on_project_first_start command.
|
20
|
+
<%= hook_on_project_first_start %>
|
14
21
|
|
15
22
|
# Create the session and the first window. Manually switch to root
|
16
23
|
# directory if required to support tmux < 1.9
|
@@ -73,6 +80,9 @@ unset RBENV_DIR
|
|
73
80
|
|
74
81
|
<%= tmux %> select-window -t <%= startup_window %>
|
75
82
|
<%= tmux %> select-pane -t <%= startup_pane %>
|
83
|
+
<%- else -%>
|
84
|
+
# Run on_project_restart command.
|
85
|
+
<%= hook_on_project_restart %>
|
76
86
|
<%- end -%>
|
77
87
|
|
78
88
|
<%- if attach? -%>
|
@@ -84,3 +94,7 @@ unset RBENV_DIR
|
|
84
94
|
<%- end -%>
|
85
95
|
|
86
96
|
<%= post %>
|
97
|
+
<%- unless attach? -%>
|
98
|
+
# Run on_project_exit command.
|
99
|
+
<%= hook_on_project_exit %>
|
100
|
+
<%- end -%>
|
data/lib/tmuxinator/cli.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "open3"
|
2
|
+
|
1
3
|
module Tmuxinator
|
2
4
|
class Cli < Thor
|
3
5
|
# By default, Thor returns exit(0) when an error occurs.
|
@@ -30,7 +32,7 @@ module Tmuxinator
|
|
30
32
|
version: "Display installed tmuxinator version",
|
31
33
|
doctor: "Look for problems in your configuration",
|
32
34
|
list: "Lists all tmuxinator projects"
|
33
|
-
}
|
35
|
+
}.freeze
|
34
36
|
|
35
37
|
package_name "tmuxinator" \
|
36
38
|
unless Gem::Version.create(Thor::VERSION) < Gem::Version.create("0.18")
|
@@ -58,7 +60,7 @@ module Tmuxinator
|
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
61
|
-
desc "new [PROJECT]", COMMANDS[:new]
|
63
|
+
desc "new [PROJECT] [SESSION]", COMMANDS[:new]
|
62
64
|
map "open" => :new
|
63
65
|
map "edit" => :new
|
64
66
|
map "o" => :new
|
@@ -68,18 +70,76 @@ module Tmuxinator
|
|
68
70
|
aliases: ["-l"],
|
69
71
|
desc: "Create local project file at ./.tmuxinator.yml"
|
70
72
|
|
71
|
-
def new(name)
|
72
|
-
|
73
|
-
|
73
|
+
def new(name, session = nil)
|
74
|
+
if session
|
75
|
+
new_project_with_session(name, session)
|
76
|
+
else
|
77
|
+
new_project(name)
|
78
|
+
end
|
74
79
|
end
|
75
80
|
|
76
81
|
no_commands do
|
82
|
+
def new_project(name)
|
83
|
+
project_file = find_project_file(name, options[:local])
|
84
|
+
Kernel.system("$EDITOR #{project_file}") || doctor
|
85
|
+
end
|
86
|
+
|
87
|
+
def new_project_with_session(name, session)
|
88
|
+
if Tmuxinator::Config.version < 1.6
|
89
|
+
raise "Creating projects from sessions is unsupported\
|
90
|
+
for tmux version 1.5 or lower."
|
91
|
+
end
|
92
|
+
|
93
|
+
windows, _, s0 = Open3.capture3(<<-CMD)
|
94
|
+
tmux list-windows -t #{session}\
|
95
|
+
-F "#W \#{window_layout} \#{window_active} \#{pane_current_path}"
|
96
|
+
CMD
|
97
|
+
panes, _, s1 = Open3.capture3(<<-CMD)
|
98
|
+
tmux list-panes -s -t #{session} -F "#W \#{pane_current_path}"
|
99
|
+
CMD
|
100
|
+
tmux_options, _, s2 = Open3.capture3(<<-CMD)
|
101
|
+
tmux show-options -t #{session}
|
102
|
+
CMD
|
103
|
+
project_root = tmux_options[/^default-path "(.+)"$/, 1]
|
104
|
+
|
105
|
+
unless [s0, s1, s2].all?(&:success?)
|
106
|
+
raise "Session '#{session}' doesn't exist."
|
107
|
+
end
|
108
|
+
|
109
|
+
panes = panes.each_line.map(&:split).group_by(&:first)
|
110
|
+
windows = windows.each_line.map do |line|
|
111
|
+
window_name, layout, active, path = line.split(" ")
|
112
|
+
project_root ||= path if active.to_i == 1
|
113
|
+
[
|
114
|
+
window_name,
|
115
|
+
layout,
|
116
|
+
Array(panes[window_name]).map do |_, pane_path|
|
117
|
+
"cd #{pane_path}"
|
118
|
+
end
|
119
|
+
]
|
120
|
+
end
|
121
|
+
|
122
|
+
yaml = {
|
123
|
+
"name" => name,
|
124
|
+
"project_root" => project_root,
|
125
|
+
"windows" => windows.map do |window_name, layout, window_panes|
|
126
|
+
{
|
127
|
+
window_name => {
|
128
|
+
"layout" => layout,
|
129
|
+
"panes" => window_panes
|
130
|
+
}
|
131
|
+
}
|
132
|
+
end
|
133
|
+
}
|
134
|
+
|
135
|
+
path = config_path(name, options[:local])
|
136
|
+
File.open(path, "w") do |f|
|
137
|
+
f.write(YAML.dump(yaml))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
77
141
|
def find_project_file(name, local = false)
|
78
|
-
path =
|
79
|
-
Tmuxinator::Config::LOCAL_DEFAULT
|
80
|
-
else
|
81
|
-
Tmuxinator::Config.default_project(name)
|
82
|
-
end
|
142
|
+
path = config_path(name, local)
|
83
143
|
if File.exist?(path)
|
84
144
|
path
|
85
145
|
else
|
@@ -87,6 +147,14 @@ module Tmuxinator
|
|
87
147
|
end
|
88
148
|
end
|
89
149
|
|
150
|
+
def config_path(name, local = false)
|
151
|
+
if local
|
152
|
+
Tmuxinator::Config::LOCAL_DEFAULT
|
153
|
+
else
|
154
|
+
Tmuxinator::Config.default_project(name)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
90
158
|
def generate_project_file(name, path)
|
91
159
|
template = Tmuxinator::Config.default? ? :default : :sample
|
92
160
|
content = File.read(Tmuxinator::Config.send(template.to_sym))
|
@@ -127,7 +195,7 @@ module Tmuxinator
|
|
127
195
|
end
|
128
196
|
|
129
197
|
def kill_project(project)
|
130
|
-
Kernel.exec(project.
|
198
|
+
Kernel.exec(project.kill)
|
131
199
|
end
|
132
200
|
end
|
133
201
|
|
@@ -231,7 +299,9 @@ module Tmuxinator
|
|
231
299
|
|
232
300
|
def implode
|
233
301
|
if yes?("Are you sure you want to delete all tmuxinator configs?", :red)
|
234
|
-
|
302
|
+
Tmuxinator::Config.directories.each do |directory|
|
303
|
+
FileUtils.remove_dir(directory)
|
304
|
+
end
|
235
305
|
say "Deleted all tmuxinator projects."
|
236
306
|
end
|
237
307
|
end
|
@@ -257,13 +327,13 @@ module Tmuxinator
|
|
257
327
|
|
258
328
|
def doctor
|
259
329
|
say "Checking if tmux is installed ==> "
|
260
|
-
yes_no Tmuxinator::
|
330
|
+
yes_no Tmuxinator::Doctor.installed?
|
261
331
|
|
262
332
|
say "Checking if $EDITOR is set ==> "
|
263
|
-
yes_no Tmuxinator::
|
333
|
+
yes_no Tmuxinator::Doctor.editor?
|
264
334
|
|
265
335
|
say "Checking if $SHELL is set ==> "
|
266
|
-
yes_no Tmuxinator::
|
336
|
+
yes_no Tmuxinator::Doctor.shell?
|
267
337
|
end
|
268
338
|
end
|
269
339
|
end
|
data/lib/tmuxinator/config.rb
CHANGED
@@ -1,13 +1,35 @@
|
|
1
1
|
module Tmuxinator
|
2
2
|
class Config
|
3
3
|
LOCAL_DEFAULT = "./.tmuxinator.yml".freeze
|
4
|
-
NO_LOCAL_FILE_MSG =
|
4
|
+
NO_LOCAL_FILE_MSG =
|
5
|
+
"Project file at ./.tmuxinator.yml doesn't exist.".freeze
|
5
6
|
|
6
7
|
class << self
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
# The directory (created if needed) in which to store new projects
|
9
|
+
def directory
|
10
|
+
return environment if File.directory?(environment)
|
11
|
+
return xdg if File.directory?(xdg)
|
12
|
+
return home if File.directory?(home)
|
13
|
+
# No project directory specified or existant, default to XDG:
|
14
|
+
FileUtils::mkdir_p(xdg)
|
15
|
+
xdg
|
16
|
+
end
|
17
|
+
|
18
|
+
def home
|
19
|
+
ENV["HOME"] + "/.tmuxinator"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Is ~/.config/tmuxinator unless $XDG_CONFIG_DIR is set
|
23
|
+
def xdg
|
24
|
+
XDG["CONFIG"].to_s + "/tmuxinator"
|
25
|
+
end
|
26
|
+
|
27
|
+
# $TMUXINATOR_CONFIG (and create directory) or "".
|
28
|
+
def environment
|
29
|
+
environment = ENV["TMUXINATOR_CONFIG"]
|
30
|
+
return "" if environment.to_s.empty? # variable is unset (nil) or blank
|
31
|
+
FileUtils::mkdir_p(environment) unless File.directory?(environment)
|
32
|
+
environment
|
11
33
|
end
|
12
34
|
|
13
35
|
def sample
|
@@ -15,69 +37,78 @@ module Tmuxinator
|
|
15
37
|
end
|
16
38
|
|
17
39
|
def default
|
18
|
-
"#{
|
40
|
+
"#{directory}/default.yml"
|
19
41
|
end
|
20
42
|
|
21
43
|
def default?
|
22
44
|
exists?("default")
|
23
45
|
end
|
24
46
|
|
25
|
-
def installed?
|
26
|
-
Kernel.system("type tmux > /dev/null")
|
27
|
-
end
|
28
|
-
|
29
47
|
def version
|
30
|
-
`tmux -V`.split(" ")[1].to_f if installed?
|
48
|
+
`tmux -V`.split(" ")[1].to_f if Tmuxinator::Doctor.installed?
|
31
49
|
end
|
32
50
|
|
33
51
|
def default_path_option
|
34
52
|
version && version < 1.8 ? "default-path" : "-c"
|
35
53
|
end
|
36
54
|
|
37
|
-
def editor?
|
38
|
-
!ENV["EDITOR"].nil? && !ENV["EDITOR"].empty?
|
39
|
-
end
|
40
|
-
|
41
|
-
def shell?
|
42
|
-
!ENV["SHELL"].nil? && !ENV["SHELL"].empty?
|
43
|
-
end
|
44
|
-
|
45
55
|
def exists?(name)
|
46
56
|
File.exist?(project(name))
|
47
57
|
end
|
48
58
|
|
49
|
-
def
|
50
|
-
|
51
|
-
projects.detect { |project| File.basename(project, ".yml") == name }
|
59
|
+
def local?
|
60
|
+
local_project
|
52
61
|
end
|
53
62
|
|
54
|
-
|
55
|
-
|
63
|
+
# Pathname of given project searching only global directories
|
64
|
+
def global_project(name)
|
65
|
+
project_in(environment, name) ||
|
66
|
+
project_in(xdg, name) ||
|
67
|
+
project_in(home, name)
|
56
68
|
end
|
57
69
|
|
58
|
-
def
|
70
|
+
def local_project
|
59
71
|
[LOCAL_DEFAULT].detect { |f| File.exist?(f) }
|
60
72
|
end
|
61
73
|
|
62
74
|
def default_project(name)
|
63
|
-
"#{
|
75
|
+
"#{directory}/#{name}.yml"
|
64
76
|
end
|
65
77
|
|
78
|
+
# Pathname of the given project
|
66
79
|
def project(name)
|
67
|
-
|
80
|
+
global_project(name) || local_project || default_project(name)
|
68
81
|
end
|
69
82
|
|
70
83
|
def template
|
71
84
|
asset_path "template.erb"
|
72
85
|
end
|
73
86
|
|
87
|
+
def stop_template
|
88
|
+
asset_path "template-stop.erb"
|
89
|
+
end
|
90
|
+
|
74
91
|
def wemux_template
|
75
92
|
asset_path "wemux_template.erb"
|
76
93
|
end
|
77
94
|
|
95
|
+
# Sorted list of all .yml files, including duplicates
|
78
96
|
def configs
|
79
|
-
|
80
|
-
|
97
|
+
directories.map do |directory|
|
98
|
+
Dir["#{directory}/**/*.yml"].map do |path|
|
99
|
+
path.gsub("#{directory}/", "").gsub(".yml", "")
|
100
|
+
end
|
101
|
+
end.flatten.sort
|
102
|
+
end
|
103
|
+
|
104
|
+
# Existant directories which may contain project files
|
105
|
+
# Listed in search order
|
106
|
+
# Used by `implode` and `list` commands
|
107
|
+
def directories
|
108
|
+
if !environment.nil? && !environment.empty?
|
109
|
+
[environment]
|
110
|
+
else
|
111
|
+
[xdg, home].select { |d| File.directory? d }
|
81
112
|
end
|
82
113
|
end
|
83
114
|
|
@@ -89,7 +120,7 @@ module Tmuxinator
|
|
89
120
|
project_file = if name.nil?
|
90
121
|
raise NO_LOCAL_FILE_MSG \
|
91
122
|
unless Tmuxinator::Config.local?
|
92
|
-
|
123
|
+
local_project
|
93
124
|
else
|
94
125
|
raise "Project #{name} doesn't exist." \
|
95
126
|
unless Tmuxinator::Config.exists?(name)
|
@@ -98,11 +129,24 @@ module Tmuxinator
|
|
98
129
|
Tmuxinator::Project.load(project_file, options).validate!
|
99
130
|
end
|
100
131
|
|
132
|
+
# Deprecated methods: ignore the 1st, use the 2nd
|
133
|
+
alias :root :directory
|
134
|
+
alias :project_in_root :global_project
|
135
|
+
alias :project_in_local :local_project
|
136
|
+
|
101
137
|
private
|
102
138
|
|
103
139
|
def asset_path(asset)
|
104
140
|
"#{File.dirname(__FILE__)}/assets/#{asset}"
|
105
141
|
end
|
142
|
+
|
143
|
+
# The first pathname of the project named 'name' found while
|
144
|
+
# recursively searching 'directory'
|
145
|
+
def project_in(directory, name)
|
146
|
+
return nil if String(directory).empty?
|
147
|
+
projects = Dir.glob("#{directory}/**/*.yml").sort
|
148
|
+
projects.detect { |project| File.basename(project, ".yml") == name }
|
149
|
+
end
|
106
150
|
end
|
107
151
|
end
|
108
152
|
end
|