Module: Runbook::Helpers::TmuxHelper

Included in:
Run::ClassMethods
Defined in:
lib/runbook/helpers/tmux_helper.rb

Constant Summary collapse

FILE_PERMISSIONS =
0600

Instance Method Summary collapse

Instance Method Details

#_all_panes_exist?(stored_layout) ⇒ Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/runbook/helpers/tmux_helper.rb', line 49

def _all_panes_exist?(stored_layout)
  (stored_layout.values - _session_panes).empty?
end

#_initialize_panes(panes_to_init, layout_panes) ⇒ Object



141
142
143
144
145
146
147
# File 'lib/runbook/helpers/tmux_helper.rb', line 141

def _initialize_panes(panes_to_init, layout_panes)
  panes_to_init.each do |pane|
    target = layout_panes[pane[:name]]
    _set_directory(pane[:directory], target) if pane[:directory]
    send_keys(pane[:command], target) if pane[:command]
  end
end

#_kill_pane(pane_id) ⇒ Object



37
38
39
# File 'lib/runbook/helpers/tmux_helper.rb', line 37

def _kill_pane(pane_id)
  `tmux kill-pane -t #{pane_id}`
end

#_layout_file(runbook_title) ⇒ Object



41
42
43
# File 'lib/runbook/helpers/tmux_helper.rb', line 41

def _layout_file(runbook_title)
  `tmux display-message -p -t $TMUX_PANE "#{Dir.tmpdir}/runbook_layout_\#{pid}_\#{session_name}_\#{pane_pid}_\#{pane_id}_#{runbook_title}.yml"`.strip
end

#_new_window(name) ⇒ Object



157
158
159
# File 'lib/runbook/helpers/tmux_helper.rb', line 157

def _new_window(name)
  `tmux new-window -n "#{name}" -P -F '#D' -d`.strip
end

#_pager_escape_sequenceObject



33
34
35
# File 'lib/runbook/helpers/tmux_helper.rb', line 33

def _pager_escape_sequence
  "q C-u"
end

#_remove_stale_layoutsObject



53
54
55
56
57
58
59
# File 'lib/runbook/helpers/tmux_helper.rb', line 53

def _remove_stale_layouts
  session_panes = _session_panes
  session_layout_files = _session_layout_files
  session_layout_files.each do |file|
    File.delete(file) unless session_panes.any? { |pane| /_#{pane}_/ =~ file }
  end
end

#_rename_window(name) ⇒ Object



153
154
155
# File 'lib/runbook/helpers/tmux_helper.rb', line 153

def _rename_window(name)
  `tmux rename-window "#{name}"`
end

#_runbook_paneObject



149
150
151
# File 'lib/runbook/helpers/tmux_helper.rb', line 149

def _runbook_pane
  @runbook_pane ||= `tmux display-message -p '#D'`.strip
end

#_session_layout_filesObject



65
66
67
68
# File 'lib/runbook/helpers/tmux_helper.rb', line 65

def _session_layout_files
  session_layout_glob = `tmux display-message -p "#{Dir.tmpdir}/runbook_layout_\#{pid}_\#{session_name}_*.yml"`.strip
  Dir[session_layout_glob]
end

#_session_panesObject



61
62
63
# File 'lib/runbook/helpers/tmux_helper.rb', line 61

def _session_panes
  `tmux list-panes -s -F '#D'`.split("\n")
end

#_set_directory(directory, target) ⇒ Object



172
173
174
# File 'lib/runbook/helpers/tmux_helper.rb', line 172

def _set_directory(directory, target)
  send_keys("cd #{directory}; clear", target)
end

#_setup_layout(structure) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/runbook/helpers/tmux_helper.rb', line 70

def _setup_layout(structure)
  current_pane = _runbook_pane
  panes_to_init = []
  {}.tap do |layout_panes|
    if structure.is_a?(Hash)
      first_window = true
      structure.each do |name, window|
        if first_window
          _rename_window(name)
          first_window = false
        else
          current_pane = _new_window(name)
        end
        _setup_panes(layout_panes, panes_to_init, current_pane, window)
      end
    else
      _setup_panes(layout_panes, panes_to_init, current_pane, structure)
    end
    _swap_runbook_pane(panes_to_init, layout_panes)
    _initialize_panes(panes_to_init, layout_panes)
  end
end

#_setup_panes(layout_panes, panes_to_init, current_pane, structure, depth = 0) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/runbook/helpers/tmux_helper.rb', line 93

def _setup_panes(layout_panes, panes_to_init, current_pane, structure, depth=0)
  return if structure.empty?
  case structure
  when Array
    case structure.size
    when 1
      _setup_panes(layout_panes, panes_to_init, current_pane, structure.shift, depth+1)
    else
      size = 100 - 100 / structure.size
      new_pane = _split(current_pane, depth, size)
      _setup_panes(layout_panes, panes_to_init, current_pane, structure.shift, depth+1)
      _setup_panes(layout_panes, panes_to_init, new_pane, structure, depth)
    end
  when Hash
    if structure.values.all? { |v| v.is_a?(Numeric) }
      total_size = structure.values.reduce(:+)
      case structure.size
      when 1
        _setup_panes(layout_panes, panes_to_init, current_pane, structure.keys[0], depth+1)
      else
        size = (total_size - structure.values[0]) * 100 / total_size
        new_pane = _split(current_pane, depth, size)
        first_struct = structure.keys[0]
        structure.delete(first_struct)
        _setup_panes(layout_panes, panes_to_init, current_pane, first_struct, depth+1)
        _setup_panes(layout_panes, panes_to_init, new_pane, structure, depth)
      end
    else
      layout_panes[structure[:name]] = current_pane
      panes_to_init << structure
    end
  when Symbol
    layout_panes[structure] = current_pane
  end
end

#_slug(title) ⇒ Object



45
46
47
# File 'lib/runbook/helpers/tmux_helper.rb', line 45

def _slug(title)
  title.titleize.gsub(/[\/\s]+/, "").underscore.dasherize
end

#_split(current_pane, depth, size) ⇒ Object



161
162
163
164
165
166
# File 'lib/runbook/helpers/tmux_helper.rb', line 161

def _split(current_pane, depth, size)
  direction = depth.even? ? "h" : "v"
  command = "tmux split-window"
  args = "-#{direction} -t #{current_pane} -p #{size} -P -F '#D' -d"
  `#{command} #{args}`.strip
end

#_swap_panes(target_pane, source_pane) ⇒ Object



168
169
170
# File 'lib/runbook/helpers/tmux_helper.rb', line 168

def _swap_panes(target_pane, source_pane)
  `tmux swap-pane -d -t #{target_pane} -s #{source_pane}`
end

#_swap_runbook_pane(panes_to_init, layout_panes) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
# File 'lib/runbook/helpers/tmux_helper.rb', line 129

def _swap_runbook_pane(panes_to_init, layout_panes)
  if (runbook_pane = panes_to_init.find { |pane| pane[:runbook_pane] })
    current_runbook_pane_name = layout_panes.keys.find do |k|
      layout_panes[k] == _runbook_pane
    end
    target_pane_id = layout_panes[runbook_pane[:name]]
    layout_panes[runbook_pane[:name]] = _runbook_pane
    layout_panes[current_runbook_pane_name] = target_pane_id
    _swap_panes(target_pane_id, _runbook_pane)
  end
end

#kill_all_panes(layout_panes) ⇒ Object



26
27
28
29
30
31
# File 'lib/runbook/helpers/tmux_helper.rb', line 26

def kill_all_panes(layout_panes)
  runbook_pane = _runbook_pane
  layout_panes.values.each do |pane_id|
    _kill_pane(pane_id) unless pane_id == runbook_pane
  end
end

#send_keys(command, target) ⇒ Object



22
23
24
# File 'lib/runbook/helpers/tmux_helper.rb', line 22

def send_keys(command, target)
  `tmux send-keys -t #{target} #{_pager_escape_sequence} '#{command}' C-m`
end

#setup_layout(structure, runbook_title:) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/runbook/helpers/tmux_helper.rb', line 5

def setup_layout(structure, runbook_title:)
  _remove_stale_layouts
  layout_file = _layout_file(_slug(runbook_title))
  if File.exists?(layout_file)
    stored_layout = ::YAML::load_file(layout_file)
    if _all_panes_exist?(stored_layout)
      return stored_layout
    end
  end

  _setup_layout(structure).tap do |layout_panes|
    File.open(layout_file, 'w', FILE_PERMISSIONS) do |f|
      f.write(layout_panes.to_yaml)
    end
  end
end