class Tmuxinator::Cli

Constants

COMMANDS
RESERVED_COMMANDS
THOR_COMMANDS

For future reference: due to how tmuxinator currently consumes command-line arguments (see ::bootstrap, below), invocations of Thor's base commands (i.e. 'help', etc) can be instead routed to start (rather than to ::start). In order to prevent this, the THOR_COMMANDS and RESERVED_COMMANDS constants have been introduced. The former enumerates any/all Thor commands we want to insure get passed through to Thor.start. The latter is the superset of the Thor commands and any tmuxinator commands, defined in COMMANDS, above.

Public Class Methods

bootstrap(args = []) click to toggle source

This method was defined as something of a workaround… Previously the conditional contained within was in the executable (i.e. bin/tmuxinator). It has been moved here so as to be testable. A couple of notes:

  • ::start (defined in Thor::Base) expects the first argument to be an

array or ARGV, not a varargs. Perhaps ::bootstrap should as well?

  • ::start has a different purpose from start and hence a different

signature

# File lib/tmuxinator/cli.rb, line 422
def self.bootstrap(args = [])
  name = args[0] || nil
  if args.empty? && Tmuxinator::Config.local?
    Tmuxinator::Cli.new.local
  elsif name && !Tmuxinator::Cli::RESERVED_COMMANDS.include?(name) &&
        Tmuxinator::Config.exists?(name: name)
    Tmuxinator::Cli.new.start(name, *args.drop(1))
  else
    Tmuxinator::Cli.start(args)
  end
end
exit_on_failure?() click to toggle source

By default, Thor returns exit(0) when an error occurs. Please see: github.com/tmuxinator/tmuxinator/issues/192

# File lib/tmuxinator/cli.rb, line 7
def self.exit_on_failure?
  true
end

Public Instance Methods

commands(shell = nil) click to toggle source
# File lib/tmuxinator/cli.rb, line 53
def commands(shell = nil)
  out = if shell == "zsh"
          COMMANDS.map do |command, desc|
            "#{command}:#{desc}"
          end.join("\n")
        else
          COMMANDS.keys.join("\n")
        end

  say out
end
completions(arg) click to toggle source
# File lib/tmuxinator/cli.rb, line 67
def completions(arg)
  if %w(start stop edit open copy delete).include?(arg)
    configs = Tmuxinator::Config.configs
    say configs.join("\n")
  end
end
config_path(name, local = false) click to toggle source
# File lib/tmuxinator/cli.rb, line 161
def config_path(name, local = false)
  if local
    Tmuxinator::Config::LOCAL_DEFAULTS[0]
  else
    Tmuxinator::Config.default_project(name)
  end
end
copy(existing, new) click to toggle source
# File lib/tmuxinator/cli.rb, line 330
def copy(existing, new)
  existing_config_path = Tmuxinator::Config.project(existing)
  new_config_path = Tmuxinator::Config.project(new)

  exit!("Project #{existing} doesn't exist!") \
    unless Tmuxinator::Config.exists?(name: existing)

  new_exists = Tmuxinator::Config.exists?(name: new)
  question = "#{new} already exists, would you like to overwrite it?"
  if !new_exists || yes?(question, :red)
    say "Overwriting #{new}" if Tmuxinator::Config.exists?(name: new)
    FileUtils.copy_file(existing_config_path, new_config_path)
  end

  Kernel.system("$EDITOR #{new_config_path}")
end
create_project(project_options = {}) click to toggle source
# File lib/tmuxinator/cli.rb, line 177
def create_project(project_options = {})
  # Strings provided to --attach are coerced into booleans by Thor.
  # "f" and "false" will result in `:attach` being `false` and any other
  # string or the empty flag will result in `:attach` being `true`.
  # If the flag is not present, `:attach` will be `nil`.
  attach = detach = false
  attach = true if project_options[:attach] == true
  detach = true if project_options[:attach] == false

  options = {
    args: project_options[:args],
    custom_name: project_options[:custom_name],
    force_attach: attach,
    force_detach: detach,
    name: project_options[:name],
    project_config: project_options[:project_config]
  }

  begin
    Tmuxinator::Config.validate(options)
  rescue => e
    exit! e.message
  end
end
debug(name = nil, *args) click to toggle source
# File lib/tmuxinator/cli.rb, line 306
def debug(name = nil, *args)
  # project-config takes precedence over a named project in the case that
  # both are provided.
  if options["project-config"]
    args.unshift name if name
    name = nil
  end

  params = {
    args: args,
    attach: options[:attach],
    custom_name: options[:name],
    name: name,
    project_config: options["project-config"]
  }

  project = create_project(params)
  say project.render
end
delete(*projects) click to toggle source
# File lib/tmuxinator/cli.rb, line 351
def delete(*projects)
  projects.each do |project|
    if Tmuxinator::Config.exists?(name: project)
      config = Tmuxinator::Config.project(project)

      if yes?("Are you sure you want to delete #{project}?(y/n)", :red)
        FileUtils.rm(config)
        say "Deleted #{project}"
      end
    else
      say "#{project} does not exist!"
    end
  end
end
doctor() click to toggle source
# File lib/tmuxinator/cli.rb, line 403
def doctor
  say "Checking if tmux is installed ==> "
  yes_no Tmuxinator::Doctor.installed?

  say "Checking if $EDITOR is set ==> "
  yes_no Tmuxinator::Doctor.editor?

  say "Checking if $SHELL is set ==> "
  yes_no Tmuxinator::Doctor.shell?
end
find_project_file(name, local = false) click to toggle source
# File lib/tmuxinator/cli.rb, line 152
def find_project_file(name, local = false)
  path = config_path(name, local)
  if File.exist?(path)
    path
  else
    generate_project_file(name, path)
  end
end
generate_project_file(name, path) click to toggle source
# File lib/tmuxinator/cli.rb, line 169
def generate_project_file(name, path)
  template = Tmuxinator::Config.default? ? :default : :sample
  content = File.read(Tmuxinator::Config.send(template.to_sym))
  erb = Erubis::Eruby.new(content).result(binding)
  File.open(path, "w") { |f| f.write(erb) }
  path
end
implode() click to toggle source
# File lib/tmuxinator/cli.rb, line 369
def implode
  if yes?("Are you sure you want to delete all tmuxinator configs?", :red)
    Tmuxinator::Config.directories.each do |directory|
      FileUtils.remove_dir(directory)
    end
    say "Deleted all tmuxinator projects."
  end
end
kill_project(project) click to toggle source
# File lib/tmuxinator/cli.rb, line 226
def kill_project(project)
  Kernel.exec(project.kill)
end
list() click to toggle source
# File lib/tmuxinator/cli.rb, line 385
def list
  say "tmuxinator projects:"
  if options[:newline]
    say Tmuxinator::Config.configs.join("\n")
  else
    print_in_columns Tmuxinator::Config.configs
  end
end
local() click to toggle source
# File lib/tmuxinator/cli.rb, line 289
def local
  show_version_warning if version_warning?(
    options["suppress-tmux-version-warning"]
  )

  render_project(create_project(attach: options[:attach]))
end
new(name, session = nil) click to toggle source
# File lib/tmuxinator/cli.rb, line 84
def new(name, session = nil)
  if session
    new_project_with_session(name, session)
  else
    new_project(name)
  end
end
new_project(name) click to toggle source
# File lib/tmuxinator/cli.rb, line 93
def new_project(name)
  project_file = find_project_file(name, options[:local])
  Kernel.system("$EDITOR #{project_file}") || doctor
end
new_project_with_session(name, session) click to toggle source
# File lib/tmuxinator/cli.rb, line 98
      def new_project_with_session(name, session)
        if Tmuxinator::Config.version < 1.6
          raise "Creating projects from sessions is unsupported\
            for tmux version 1.5 or lower."
        end

        windows, _, s0 = Open3.capture3(<<-CMD)
          tmux list-windows -t #{session}\
          -F "#W \#{window_layout} \#{window_active} \#{pane_current_path}"
        CMD
        panes, _, s1 = Open3.capture3(<<-CMD)
          tmux list-panes -s -t #{session} -F "#W \#{pane_current_path}"
        CMD
        tmux_options, _, s2 = Open3.capture3(<<-CMD)
          tmux show-options -t #{session}
        CMD
        project_root = tmux_options[/^default-path "(.+)"$/, 1]

        unless [s0, s1, s2].all?(&:success?)
          raise "Session '#{session}' doesn't exist."
        end

        panes = panes.each_line.map(&:split).group_by(&:first)
        windows = windows.each_line.map do |line|
          window_name, layout, active, path = line.split(" ")
          project_root ||= path if active.to_i == 1
          [
            window_name,
            layout,
            Array(panes[window_name]).map do |_, pane_path|
              "cd #{pane_path}"
            end
          ]
        end

        yaml = {
          "name" => name,
          "project_root" => project_root,
          "windows" => windows.map do |window_name, layout, window_panes|
            {
              window_name => {
                "layout" => layout,
                "panes" => window_panes
              }
            }
          end
        }

        path = config_path(name, options[:local])
        File.open(path, "w") do |f|
          f.write(YAML.dump(yaml))
        end
      end
render_project(project) click to toggle source
# File lib/tmuxinator/cli.rb, line 202
def render_project(project)
  if project.deprecations.any?
    project.deprecations.each { |deprecation| say deprecation, :red }
    show_continuation_prompt
  end

  Kernel.exec(project.render)
end
show_continuation_prompt() click to toggle source
# File lib/tmuxinator/cli.rb, line 220
def show_continuation_prompt
  say
  print "Press ENTER to continue."
  STDIN.getc
end
show_version_warning() click to toggle source
# File lib/tmuxinator/cli.rb, line 215
def show_version_warning
  say Tmuxinator::TmuxVersion::UNSUPPORTED_VERSION_MSG, :red
  show_continuation_prompt
end
start(name = nil, *args) click to toggle source
# File lib/tmuxinator/cli.rb, line 243
def start(name = nil, *args)
  # project-config takes precedence over a named project in the case that
  # both are provided.
  if options["project-config"]
    args.unshift name if name
    name = nil
  end

  params = {
    args: args,
    attach: options[:attach],
    custom_name: options[:name],
    name: name,
    project_config: options["project-config"]
  }

  show_version_warning if version_warning?(
    options["suppress-tmux-version-warning"]
  )

  project = create_project(params)
  render_project(project)
end
stop(name) click to toggle source
# File lib/tmuxinator/cli.rb, line 272
def stop(name)
  params = {
    name: name
  }
  show_version_warning if version_warning?(
    options["suppress-tmux-version-warning"]
  )

  project = create_project(params)
  kill_project(project)
end
version() click to toggle source
# File lib/tmuxinator/cli.rb, line 397
def version
  say "tmuxinator #{Tmuxinator::VERSION}"
end
version_warning?(suppress_flag) click to toggle source
# File lib/tmuxinator/cli.rb, line 211
def version_warning?(suppress_flag)
  !Tmuxinator::TmuxVersion.supported? && !suppress_flag
end