tmuxinator 0.9.0 → 0.10.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/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
|