tmuxinator 0.6.11 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38f09af10a658caa15c32d1abe77373cc9e2d960
4
- data.tar.gz: 8a17b9b5cf0de202edb22ead61cd148462e4a8fd
3
+ metadata.gz: 079c5def07857f7b54737cd711899a7c529fee96
4
+ data.tar.gz: 461725febed6618763f593eec2952cbce8866368
5
5
  SHA512:
6
- metadata.gz: 7fba40c695a6406361c67fc0275a2706577bce38b86e1b37d4a6311fac8957d9212aba70ca93c3b52150e7ec77a45cf52b2da030781f82fe2fa8c57dec694440
7
- data.tar.gz: 6e39fbf6bcb98e0e7deac36693b931c1f1ff0fc024e7a6f0425bdb0c5345e2b59965511923ed8b37a0b2530604803dfc76a690d0da8463ed26e1201dc26b5db5
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
- if ARGV.length == 1
8
- name = ARGV[0]
7
+ name = ARGV[0] || nil
9
8
 
10
- if Tmuxinator::Cli::COMMANDS.keys.include?(name.to_sym)
11
- Tmuxinator::Cli.start
12
- elsif Tmuxinator::Config.exists?(name)
13
- Tmuxinator::Cli.new.start(name)
14
- else
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
@@ -4,16 +4,13 @@ $: << File.expand_path("../../lib/", __FILE__)
4
4
  require "thor"
5
5
  require "tmuxinator"
6
6
 
7
- if ARGV.length == 1
8
- name = ARGV[0]
7
+ name = ARGV[0] || nil
9
8
 
10
- if Tmuxinator::Cli::COMMANDS.keys.include?(name.to_sym)
11
- Tmuxinator::Cli.start
12
- elsif Tmuxinator::Config.exists?(name)
13
- Tmuxinator::Cli.new.start(name)
14
- else
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= <%= tmux %> new-session -d -s <%= name %> -n <%= windows.first.name %>
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
- <%= tmux %> -u attach-session -t <%= name %>
76
- else
77
- <%= tmux %> -u switch-client -t <%= name %>
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 %>
@@ -8,7 +8,7 @@ if [ "$?" -eq 127 ]; then
8
8
  <%= pre %>
9
9
 
10
10
  # Create the session and the first window.
11
- TMUX= <%= tmux %> new-session -d -s <%= name %> -n <%= windows.first.name %>
11
+ TMUX= <%= tmux_new_session_command %>
12
12
 
13
13
  # Set the default path.
14
14
  <%- if root? -%>
@@ -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: "Start a tmux session using a project's tmuxinator config, with an optional [ALIAS] for project reuse",
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: "Copy an existing project to a new project and open it in your editor",
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" unless Gem::Version.create(Thor::VERSION) < Gem::Version.create("0.18")
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
- COMMANDS.map do |command, desc|
27
- "#{command}:#{desc}"
28
- end.join("\n")
29
- else
30
- COMMANDS.keys.join("\n")
31
- end
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
- config = Tmuxinator::Config.project(name)
54
-
55
- unless Tmuxinator::Config.exists?(name)
56
- template = Tmuxinator::Config.default? ? Tmuxinator::Config.default : Tmuxinator::Config.sample
57
- erb = Erubis::Eruby.new(File.read(template)).result(binding)
58
- File.open(config, "w") { |f| f.write(erb) }
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 #{config}") || doctor
82
+ Kernel.system("$EDITOR #{project_file}") || doctor
62
83
  end
63
84
 
64
- desc "start [PROJECT] [SESSION_NAME]", COMMANDS[:start]
65
- map "s" => :start
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
- def start(name, custom_name = nil)
68
- project = Tmuxinator::Config.validate(name, custom_name )
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
- if project.deprecations.any?
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
- Kernel.exec(project.render)
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 "debug [PROJECT]", COMMANDS[:debug]
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
- def debug(name, custom_name = nil)
83
- project = Tmuxinator::Config.validate(name, custom_name )
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!") unless Tmuxinator::Config.exists?(existing)
170
+ exit!("Project #{existing} doesn't exist!") \
171
+ unless Tmuxinator::Config.exists?(existing)
96
172
 
97
- if !Tmuxinator::Config.exists?(new) or yes?("#{new} already exists, would you like to overwrite it?", :red)
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 = "#{Tmuxinator::Config.root}/#{project}.yml"
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 Tmuxinator::Config.shell?
237
+ yes_no Tmuxinator::Config.shell?
160
238
  end
161
239
  end
162
240
  end
@@ -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
- Dir.mkdir("#{ENV["HOME"]}/.tmuxinator") unless File.directory?(File.expand_path("~/.tmuxinator"))
6
- "#{ENV["HOME"]}/.tmuxinator"
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
- "#{File.dirname(__FILE__)}/assets/sample.yml"
14
+ asset_path "sample.yml"
11
15
  end
12
16
 
13
17
  def default
14
- "#{ENV["HOME"]}/.tmuxinator/default.yml"
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 project(name)
49
+ def project_in_root(name)
46
50
  projects = Dir.glob("#{root}/**/*.yml")
47
- project_file = projects.detect { |project| File.basename(project, ".yml") == name }
48
- project_file || "#{root}/#{name}.yml"
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
- "#{File.dirname(__FILE__)}/assets/template.erb"
71
+ asset_path "template.erb"
53
72
  end
54
73
 
55
74
  def wemux_template
56
- "#{File.dirname(__FILE__)}/assets/wemux_template.erb"
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(name, custom_name = nil)
66
- unless Tmuxinator::Config.exists?(name)
67
- puts "Project #{name} doesn't exist."
68
- exit!
69
- end
70
-
71
- config_path = Tmuxinator::Config.project(name)
72
-
73
- yaml = begin
74
- YAML.load(Erubis::Eruby.new(File.read(config_path)).result(binding))
75
- rescue SyntaxError, StandardError
76
- puts "Failed to parse config file. Please check your formatting."
77
- exit!
78
- end
79
-
80
- project = Tmuxinator::Project.new(yaml, custom_name)
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
- unless project.name?
88
- puts "Your project file didn't specify a 'project_name'"
89
- exit!
90
- end
101
+ private
91
102
 
92
- project
103
+ def asset_path(asset)
104
+ "#{File.dirname(__FILE__)}/assets/#{asset}"
93
105
  end
94
106
  end
95
107
  end
@@ -10,27 +10,43 @@ module Tmuxinator
10
10
  end
11
11
 
12
12
  def tmux_window_and_pane_target
13
- "#{project.name}:#{tab.index + project.base_index}.#{index + project.base_index}"
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
- "#{project.tmux} send-keys -t #{tmux_window_and_pane_target} #{tab.pre.shellescape} C-m"
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
- "#{project.tmux} send-keys -t #{tmux_window_and_pane_target} #{project.pre_window.shellescape} C-m"
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
- command ? "#{project.tmux} send-keys -t #{project.name}:#{tab.index + project.base_index}.#{index + tab.project.base_index} #{command.shellescape} C-m" : ""
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? ? "#{Tmuxinator::Config.default_path_option} #{tab.root}" : nil
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