tmuxinator 0.5.0 → 0.6.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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -1
- data/.travis.yml +5 -0
- data/CHANGELOG.md +36 -0
- data/CONTRIBUTING.md +29 -0
- data/Gemfile +4 -7
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +128 -118
- data/Rakefile +1 -72
- data/bin/mux +8 -3
- data/bin/tmuxinator +8 -3
- data/completion/tmuxinator.bash +18 -0
- data/completion/tmuxinator.zsh +20 -0
- data/lib/tmuxinator.rb +13 -7
- data/lib/tmuxinator/assets/sample.yml +24 -11
- data/lib/tmuxinator/assets/template.erb +47 -0
- data/lib/tmuxinator/cli.rb +121 -145
- data/lib/tmuxinator/config.rb +92 -0
- data/lib/tmuxinator/deprecations.rb +19 -0
- data/lib/tmuxinator/pane.rb +36 -0
- data/lib/tmuxinator/project.rb +142 -0
- data/lib/tmuxinator/util.rb +14 -0
- data/lib/tmuxinator/version.rb +3 -0
- data/lib/tmuxinator/window.rb +76 -0
- data/spec/factories/projects.rb +17 -0
- data/spec/fixtures/sample.deprecations.yml +35 -0
- data/spec/fixtures/sample.yml +35 -0
- data/spec/lib/tmuxinator/cli_spec.rb +230 -0
- data/spec/lib/tmuxinator/config_spec.rb +121 -0
- data/spec/lib/tmuxinator/pane_spec.rb +7 -0
- data/spec/lib/tmuxinator/project_spec.rb +209 -0
- data/spec/lib/tmuxinator/util_spec.rb +4 -0
- data/spec/lib/tmuxinator/window_spec.rb +62 -0
- data/spec/spec_helper.rb +28 -8
- data/tmuxinator.gemspec +47 -65
- metadata +186 -62
- data/.document +0 -5
- data/Gemfile.lock +0 -28
- data/TODO +0 -4
- data/VERSION +0 -1
- data/bin/tmuxinator_completion +0 -29
- data/lib/tmuxinator/assets/tmux_config.tmux +0 -37
- data/lib/tmuxinator/config_writer.rb +0 -104
- data/lib/tmuxinator/helper.rb +0 -19
- data/spec/tmuxinator_spec.rb +0 -54
@@ -0,0 +1,92 @@
|
|
1
|
+
require "pry"
|
2
|
+
module Tmuxinator
|
3
|
+
class Config
|
4
|
+
class << self
|
5
|
+
def root
|
6
|
+
Dir.mkdir("#{ENV["HOME"]}/.tmuxinator") unless File.directory?(File.expand_path("~/.tmuxinator"))
|
7
|
+
"#{ENV["HOME"]}/.tmuxinator"
|
8
|
+
end
|
9
|
+
|
10
|
+
def sample
|
11
|
+
"#{File.dirname(__FILE__)}/assets/sample.yml"
|
12
|
+
end
|
13
|
+
|
14
|
+
def default
|
15
|
+
"#{ENV["HOME"]}/.tmuxinator/default.yml"
|
16
|
+
end
|
17
|
+
|
18
|
+
def default?
|
19
|
+
exists?(default)
|
20
|
+
end
|
21
|
+
|
22
|
+
def installed?
|
23
|
+
Kernel.system("which tmux > /dev/null")
|
24
|
+
end
|
25
|
+
|
26
|
+
def editor?
|
27
|
+
!ENV["EDITOR"].nil? && !ENV["EDITOR"].empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
def shell?
|
31
|
+
!ENV["SHELL"].nil? && !ENV["SHELL"].empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def exists?(name)
|
35
|
+
unless project(name).nil?
|
36
|
+
File.exists?(project(name))
|
37
|
+
else
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def project(name)
|
43
|
+
projects = Dir.glob("#{root}/**/*.yml")
|
44
|
+
projects.select { |project| project =~ /#{name}.yml/ }.first
|
45
|
+
end
|
46
|
+
|
47
|
+
def template
|
48
|
+
"#{File.dirname(__FILE__)}/assets/template.erb"
|
49
|
+
end
|
50
|
+
|
51
|
+
def configs
|
52
|
+
Dir["#{Tmuxinator::Config.root}/*.yml"].sort.map do |path|
|
53
|
+
path.gsub("#{Tmuxinator::Config.root}/", "").gsub(".yml", "")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate(name)
|
58
|
+
unless Tmuxinator::Config.exists?(name)
|
59
|
+
puts "Project #{name} doesn't exist."
|
60
|
+
exit!
|
61
|
+
end
|
62
|
+
|
63
|
+
config_path = Tmuxinator::Config.project(name)
|
64
|
+
|
65
|
+
yaml = begin
|
66
|
+
YAML.load(File.read(config_path))
|
67
|
+
rescue SyntaxError, StandardError
|
68
|
+
puts "Failed to parse config file. Please check your formatting."
|
69
|
+
exit!
|
70
|
+
end
|
71
|
+
|
72
|
+
project = Tmuxinator::Project.new(yaml)
|
73
|
+
|
74
|
+
unless project.windows?
|
75
|
+
puts "Your project file should include some windows."
|
76
|
+
exit!
|
77
|
+
end
|
78
|
+
|
79
|
+
unless project.root?
|
80
|
+
puts "Your project file didn't specify a 'project_root'"
|
81
|
+
exit!
|
82
|
+
end
|
83
|
+
|
84
|
+
unless project.name?
|
85
|
+
puts "Your project file didn't specify a 'project_name'"
|
86
|
+
end
|
87
|
+
|
88
|
+
project
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Tmuxinator
|
2
|
+
module Deprecations
|
3
|
+
def rvm?
|
4
|
+
yaml["rvm"].present?
|
5
|
+
end
|
6
|
+
|
7
|
+
def rbenv?
|
8
|
+
yaml["rbenv"].present?
|
9
|
+
end
|
10
|
+
|
11
|
+
def pre_tab?
|
12
|
+
yaml["pre_tab"].present?
|
13
|
+
end
|
14
|
+
|
15
|
+
def cli_args?
|
16
|
+
yaml["cli_args"].present?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Tmuxinator
|
2
|
+
class Pane
|
3
|
+
attr_reader :command, :project, :index, :project, :tab
|
4
|
+
|
5
|
+
def initialize(command, index, project, tab)
|
6
|
+
@command = command
|
7
|
+
@index = index
|
8
|
+
@project = project
|
9
|
+
@tab = tab
|
10
|
+
end
|
11
|
+
|
12
|
+
def tmux_window_and_pane_target
|
13
|
+
"#{project.name}:#{tab.index + project.base_index}.#{index + project.base_index}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def tmux_pre_command
|
17
|
+
tab.pre.present? ? "#{project.tmux} send-keys -t #{tmux_window_and_pane_target} #{tab.pre.shellescape} C-m" : ""
|
18
|
+
end
|
19
|
+
|
20
|
+
def tmux_pre_window_command
|
21
|
+
project.pre_window.present? ? "#{project.tmux} send-keys -t #{tmux_window_and_pane_target} #{project.pre_window.shellescape} C-m" : ""
|
22
|
+
end
|
23
|
+
|
24
|
+
def tmux_main_command
|
25
|
+
command.present? ? "#{project.tmux} send-keys -t #{project.name}:#{tab.index + project.base_index}.#{index + tab.project.base_index} #{command.shellescape} C-m" : ""
|
26
|
+
end
|
27
|
+
|
28
|
+
def tmux_split_command
|
29
|
+
"#{project.tmux} splitw -t #{tab.tmux_window_target}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def last?
|
33
|
+
index == tab.panes.length - 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Tmuxinator
|
2
|
+
class Project
|
3
|
+
include Tmuxinator::Util
|
4
|
+
include Tmuxinator::Deprecations
|
5
|
+
|
6
|
+
attr_reader :yaml
|
7
|
+
|
8
|
+
def initialize(yaml)
|
9
|
+
@yaml = yaml
|
10
|
+
end
|
11
|
+
|
12
|
+
def render
|
13
|
+
template = File.read(Tmuxinator::Config.template)
|
14
|
+
Erubis::Eruby.new(template).result(binding)
|
15
|
+
end
|
16
|
+
|
17
|
+
def windows
|
18
|
+
windows_yml =
|
19
|
+
if yaml["tabs"].present?
|
20
|
+
yaml["tabs"]
|
21
|
+
else
|
22
|
+
yaml["windows"]
|
23
|
+
end
|
24
|
+
|
25
|
+
@windows ||= windows_yml.map.with_index do |window_yml, index|
|
26
|
+
Tmuxinator::Window.new(window_yml, index, self)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def root
|
31
|
+
if yaml["project_root"].present?
|
32
|
+
yaml["project_root"]
|
33
|
+
else
|
34
|
+
yaml["root"]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def name
|
39
|
+
if yaml["project_name"].present?
|
40
|
+
yaml["project_name"].shellescape
|
41
|
+
else
|
42
|
+
yaml["name"].shellescape
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def pre
|
47
|
+
yaml["pre"]
|
48
|
+
end
|
49
|
+
|
50
|
+
def pre_window
|
51
|
+
if rbenv?
|
52
|
+
"rbenv shell #{yaml["rbenv"]}"
|
53
|
+
elsif rvm?
|
54
|
+
"rvm use #{yaml["rvm"]}"
|
55
|
+
elsif pre_tab?
|
56
|
+
yaml["pre_tab"]
|
57
|
+
else
|
58
|
+
yaml["pre_window"]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def tmux
|
63
|
+
"tmux#{tmux_options}#{socket}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def socket
|
67
|
+
if socket_path.present?
|
68
|
+
" -S #{socket_path}"
|
69
|
+
elsif socket_name.present?
|
70
|
+
" -L #{socket_name}"
|
71
|
+
else
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def socket_name
|
77
|
+
yaml["socket_name"]
|
78
|
+
end
|
79
|
+
|
80
|
+
def socket_path
|
81
|
+
yaml["socket_path"]
|
82
|
+
end
|
83
|
+
|
84
|
+
def tmux_options
|
85
|
+
if cli_args?
|
86
|
+
" #{yaml["cli_args"].strip}"
|
87
|
+
elsif tmux_options?
|
88
|
+
" #{yaml["tmux_options"].strip}"
|
89
|
+
else
|
90
|
+
""
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def base_index
|
95
|
+
`tmux start-server\\\; show-window-options -g | grep pane-base-index`.split(/\s/).last.to_i
|
96
|
+
end
|
97
|
+
|
98
|
+
def tmux_options?
|
99
|
+
yaml["tmux_options"].present?
|
100
|
+
end
|
101
|
+
|
102
|
+
def windows?
|
103
|
+
windows.any?
|
104
|
+
end
|
105
|
+
|
106
|
+
def root?
|
107
|
+
root.present?
|
108
|
+
end
|
109
|
+
|
110
|
+
def name?
|
111
|
+
name.present?
|
112
|
+
end
|
113
|
+
|
114
|
+
def window(i)
|
115
|
+
"#{name}:#{i}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def send_pane_command(cmd, window_index, pane_index)
|
119
|
+
if cmd.blank?
|
120
|
+
""
|
121
|
+
else
|
122
|
+
"#{tmux} send-keys -t #{window(window_index)} #{cmd.shellescape} C-m"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def send_keys(cmd, window_index)
|
127
|
+
if cmd.blank?
|
128
|
+
""
|
129
|
+
else
|
130
|
+
"#{tmux} send-keys -t #{window(window_index)} #{cmd.shellescape} C-m"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def deprecations
|
135
|
+
deprecations = []
|
136
|
+
deprecations << "DEPRECATION: rbenv/rvm specific options have been replaced by the pre_tab option and will not be supported in 0.8.0." if yaml["rbenv"] || yaml["rvm"]
|
137
|
+
deprecations << "DEPRECATION: The tabs option has been replaced by the window option and will not be supported in 0.8.0." if yaml["tabs"].present?
|
138
|
+
deprecations << "DEPRECATION: The cli_args option has been replaced by the tmux_options option and will not be supported in 0.8.0." if yaml["cli_args"].present?
|
139
|
+
deprecations
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Tmuxinator
|
2
|
+
class Window
|
3
|
+
attr_reader :name, :panes, :layout, :command, :index, :project
|
4
|
+
|
5
|
+
def initialize(window_yaml, index, project)
|
6
|
+
@name = window_yaml.keys.first.present? ? window_yaml.keys.first.shellescape : nil
|
7
|
+
@panes = []
|
8
|
+
@layout = nil
|
9
|
+
@pre = nil
|
10
|
+
@command = nil
|
11
|
+
@project = project
|
12
|
+
@index = index
|
13
|
+
|
14
|
+
value = window_yaml.values.first
|
15
|
+
|
16
|
+
if value.is_a?(Hash)
|
17
|
+
@layout = value["layout"].present? ? value["layout"].shellescape : nil
|
18
|
+
@pre = value["pre"] if value["pre"].present?
|
19
|
+
|
20
|
+
@panes = build_panes(value["panes"])
|
21
|
+
else
|
22
|
+
@command = value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_panes(pane_yml)
|
27
|
+
if pane_yml.is_a?(Array)
|
28
|
+
pane_yml.map.with_index do |pane_cmd, index|
|
29
|
+
Tmuxinator::Pane.new(pane_cmd, index, project, self)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
Tmuxinator::Pane.new(pane_yml, index, project, self)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def pre
|
37
|
+
if @pre.present?
|
38
|
+
if @pre.is_a?(Array)
|
39
|
+
@pre.join(" && ")
|
40
|
+
elsif @pre.is_a?(String)
|
41
|
+
@pre
|
42
|
+
end
|
43
|
+
else
|
44
|
+
""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def panes?
|
49
|
+
panes.any?
|
50
|
+
end
|
51
|
+
|
52
|
+
def tmux_window_target
|
53
|
+
"#{project.name}:#{index + project.base_index}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def tmux_pre_window_command
|
57
|
+
project.pre_window.present? ? "#{project.tmux} send-keys -t #{tmux_window_target} #{project.pre_window.shellescape} C-m" : ""
|
58
|
+
end
|
59
|
+
|
60
|
+
def tmux_main_command
|
61
|
+
command.present? ? "#{project.tmux} send-keys -t #{project.name}:#{index + project.base_index} #{command.shellescape} C-m" : ""
|
62
|
+
end
|
63
|
+
|
64
|
+
def tmux_new_window_command
|
65
|
+
"#{project.tmux} new-window -t #{tmux_window_target} -n #{name}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def tmux_layout_command
|
69
|
+
"#{project.tmux} select-layout -t #{tmux_window_target} #{layout}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def tmux_select_first_pane
|
73
|
+
"#{project.tmux} select-pane -t #{tmux_window_target}.#{panes.first.index + project.base_index}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :project, :class => Tmuxinator::Project do
|
3
|
+
ignore do
|
4
|
+
file { YAML.load(File.read("#{File.expand_path("spec/fixtures/sample.yml")}")) }
|
5
|
+
end
|
6
|
+
|
7
|
+
initialize_with { Tmuxinator::Project.new(file) }
|
8
|
+
end
|
9
|
+
|
10
|
+
factory :project_with_deprecations, :class => Tmuxinator::Project do
|
11
|
+
ignore do
|
12
|
+
file { YAML.load(File.read("#{File.expand_path("spec/fixtures/sample.deprecations.yml")}")) }
|
13
|
+
end
|
14
|
+
|
15
|
+
initialize_with { Tmuxinator::Project.new(file) }
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# ~/.tmuxinator/sample.deprecations.yml
|
2
|
+
# you can make as many tabs as you wish...
|
3
|
+
|
4
|
+
project_name: sample
|
5
|
+
project_root: ~/test
|
6
|
+
socket_name: foo # Remove to use default socket
|
7
|
+
pre: sudo /etc/rc.d/mysqld start # Runs before everything
|
8
|
+
rbenv: 2.0.0-p247
|
9
|
+
cli_args: -v -2 # Pass arguments to tmux
|
10
|
+
tabs:
|
11
|
+
- editor:
|
12
|
+
pre:
|
13
|
+
- echo "I get run in each pane, before each pane command!"
|
14
|
+
-
|
15
|
+
layout: main-vertical
|
16
|
+
panes:
|
17
|
+
- vim
|
18
|
+
- #empty, will just run plain bash
|
19
|
+
- top
|
20
|
+
- shell: git pull
|
21
|
+
- guard:
|
22
|
+
layout: tiled
|
23
|
+
pre:
|
24
|
+
- echo "I get run in each pane."
|
25
|
+
- echo "Before each pane command!"
|
26
|
+
panes:
|
27
|
+
-
|
28
|
+
- #empty, will just run plain bash
|
29
|
+
-
|
30
|
+
- database: bundle exec rails db
|
31
|
+
- server: bundle exec rails s
|
32
|
+
- logs: tail -f log/development.log
|
33
|
+
- console: bundle exec rails c
|
34
|
+
- capistrano:
|
35
|
+
- server: ssh user@example.com
|