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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +1 -1
  4. data/.travis.yml +5 -0
  5. data/CHANGELOG.md +36 -0
  6. data/CONTRIBUTING.md +29 -0
  7. data/Gemfile +4 -7
  8. data/{LICENSE.txt → LICENSE} +1 -1
  9. data/README.md +128 -118
  10. data/Rakefile +1 -72
  11. data/bin/mux +8 -3
  12. data/bin/tmuxinator +8 -3
  13. data/completion/tmuxinator.bash +18 -0
  14. data/completion/tmuxinator.zsh +20 -0
  15. data/lib/tmuxinator.rb +13 -7
  16. data/lib/tmuxinator/assets/sample.yml +24 -11
  17. data/lib/tmuxinator/assets/template.erb +47 -0
  18. data/lib/tmuxinator/cli.rb +121 -145
  19. data/lib/tmuxinator/config.rb +92 -0
  20. data/lib/tmuxinator/deprecations.rb +19 -0
  21. data/lib/tmuxinator/pane.rb +36 -0
  22. data/lib/tmuxinator/project.rb +142 -0
  23. data/lib/tmuxinator/util.rb +14 -0
  24. data/lib/tmuxinator/version.rb +3 -0
  25. data/lib/tmuxinator/window.rb +76 -0
  26. data/spec/factories/projects.rb +17 -0
  27. data/spec/fixtures/sample.deprecations.yml +35 -0
  28. data/spec/fixtures/sample.yml +35 -0
  29. data/spec/lib/tmuxinator/cli_spec.rb +230 -0
  30. data/spec/lib/tmuxinator/config_spec.rb +121 -0
  31. data/spec/lib/tmuxinator/pane_spec.rb +7 -0
  32. data/spec/lib/tmuxinator/project_spec.rb +209 -0
  33. data/spec/lib/tmuxinator/util_spec.rb +4 -0
  34. data/spec/lib/tmuxinator/window_spec.rb +62 -0
  35. data/spec/spec_helper.rb +28 -8
  36. data/tmuxinator.gemspec +47 -65
  37. metadata +186 -62
  38. data/.document +0 -5
  39. data/Gemfile.lock +0 -28
  40. data/TODO +0 -4
  41. data/VERSION +0 -1
  42. data/bin/tmuxinator_completion +0 -29
  43. data/lib/tmuxinator/assets/tmux_config.tmux +0 -37
  44. data/lib/tmuxinator/config_writer.rb +0 -104
  45. data/lib/tmuxinator/helper.rb +0 -19
  46. 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,14 @@
1
+ module Tmuxinator
2
+ module Util
3
+ include Thor::Actions
4
+
5
+ def exit!(msg)
6
+ puts msg
7
+ Kernel.exit(1)
8
+ end
9
+
10
+ def yes_no(condition)
11
+ condition ? say("Yes", :green) : say("No", :red)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Tmuxinator
2
+ VERSION = "0.6.0"
3
+ 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