heytmux 0.1.1 → 0.3.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 +5 -5
- data/Gemfile +2 -0
- data/README.md +3 -2
- data/Rakefile +2 -0
- data/exe/heytmux +4 -3
- data/heytmux.gemspec +7 -8
- data/lib/heytmux/core.rb +22 -10
- data/lib/heytmux/pane_action.rb +1 -1
- data/lib/heytmux/pane_actions/expect.rb +1 -0
- data/lib/heytmux/tmux.rb +1 -1
- data/lib/heytmux/validations.rb +27 -6
- data/lib/heytmux/version.rb +1 -1
- data/lib/heytmux.rb +6 -5
- metadata +15 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2416296679429973f3324dee4b41204cf0414cba0296028c2856215370dc2627
|
4
|
+
data.tar.gz: 6b5b41223076adf68875297d9e2c5fc8959b07250a37e9df71e435baa03bed6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 579bf7e26c4e2c91870303e608c6e5a9bfe9d9368b1d610550fa6d0e185e4cfc62aaf4c364f12ef5679e5a263548b5c44720074e8675e0759059701e0b587b7b
|
7
|
+
data.tar.gz: fcb6ae512001bb29b3af8c2aeb8f124dbb2fe66b018769ca6bd7af9804b3dbc82058dcbc96a4cf7951cff939ed635f7085dc7fed95ffdd33c9a4f3b3ec87e453
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Hey tmux!
|
2
2
|
=========
|
3
3
|
|
4
|
-
[](https://github.com/junegunn/heytmux/actions)
|
5
5
|
[](https://coveralls.io/github/junegunn/heytmux?branch=master)
|
6
6
|
[](https://rubygems.org/gems/heytmux)
|
7
7
|
|
@@ -221,7 +221,7 @@ expanded according to the list.
|
|
221
221
|
- pane {{item}}: sleep {{item}}
|
222
222
|
```
|
223
223
|
|
224
|
-
Note that you have to quote a pane title if it starts with `{{
|
224
|
+
Note that you have to quote a pane title if it starts with `{{`.
|
225
225
|
|
226
226
|
This is often useful when you have to work with a series of log files or with
|
227
227
|
a set of servers.
|
@@ -238,6 +238,7 @@ a set of servers.
|
|
238
238
|
- ssh user@{{item}} tail -f /var/log/server-{{item}}.log
|
239
239
|
```
|
240
240
|
|
241
|
+
Also note that `{{ item.index }}` expands to zero-based index of the item.
|
241
242
|
|
242
243
|
#### Referring to environment variables
|
243
244
|
|
data/Rakefile
CHANGED
data/exe/heytmux
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'heytmux'
|
4
5
|
|
@@ -17,13 +18,13 @@ if (unreadable = ARGV.find { |f| !File.readable?(f) })
|
|
17
18
|
end
|
18
19
|
|
19
20
|
require 'yaml'
|
20
|
-
strings = [$stdin.tty? ? nil : ['standard input', $stdin.read],
|
21
|
+
strings = [ARGV.any? || $stdin.tty? ? nil : ['standard input', $stdin.read],
|
21
22
|
*ARGV.map { |f| [f, File.read(f)] }].compact
|
22
23
|
specs = strings.map do |name, str|
|
23
24
|
begin
|
24
25
|
str = Heytmux.replace_env_vars(str)
|
25
|
-
YAML.
|
26
|
-
rescue => e
|
26
|
+
YAML.safe_load(str)
|
27
|
+
rescue StandardError => e
|
27
28
|
abort("Failed to parse #{name}: #{e}")
|
28
29
|
end
|
29
30
|
end
|
data/heytmux.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
lib = File.expand_path('
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'heytmux/version'
|
6
6
|
|
@@ -21,11 +21,10 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ['lib']
|
23
23
|
|
24
|
-
spec.required_ruby_version = '>= 2.
|
25
|
-
spec.add_development_dependency 'bundler', '
|
26
|
-
spec.add_development_dependency '
|
27
|
-
spec.add_development_dependency 'minitest'
|
24
|
+
spec.required_ruby_version = '>= 2.4'
|
25
|
+
spec.add_development_dependency 'bundler', '>= 2.2.15'
|
26
|
+
spec.add_development_dependency 'coveralls_reborn'
|
27
|
+
spec.add_development_dependency 'minitest'
|
28
28
|
spec.add_development_dependency 'pry'
|
29
|
-
spec.add_development_dependency '
|
30
|
-
spec.add_development_dependency 'coveralls'
|
29
|
+
spec.add_development_dependency 'rake'
|
31
30
|
end
|
data/lib/heytmux/core.rb
CHANGED
@@ -71,12 +71,17 @@ module Heytmux
|
|
71
71
|
|
72
72
|
# Finds appropriate PaneActions for the commands and processes them
|
73
73
|
def process_command!(window_index, pane)
|
74
|
-
pane_index, item, commands =
|
74
|
+
pane_index, item, item_index, commands =
|
75
|
+
pane.values_at(:index, :item, :item_index, :command)
|
75
76
|
[*commands].compact.each do |command|
|
76
77
|
label, body = command.is_a?(Hash) ? command.first : [:paste, command]
|
77
78
|
PaneAction.for(label).process(window_index, pane_index, body) do |source|
|
78
79
|
string = source.to_s
|
79
|
-
|
80
|
+
if item
|
81
|
+
string.gsub(ITEM_PAT, item).gsub(ITEM_INDEX_PAT, item_index.to_s)
|
82
|
+
else
|
83
|
+
string
|
84
|
+
end
|
80
85
|
end
|
81
86
|
end
|
82
87
|
end
|
@@ -84,9 +89,8 @@ module Heytmux
|
|
84
89
|
# Groups entities by the group key and extracts unique, sorted indexes and
|
85
90
|
# returns stateful indexer that issues index number for the given group key
|
86
91
|
def indexer(entities, group_key, index_key)
|
87
|
-
indexes =
|
88
|
-
|
89
|
-
.map { |g, es| [g, es.map { |e| e[index_key] }.sort.uniq] }]
|
92
|
+
indexes = entities.group_by { |e| e[group_key] }
|
93
|
+
.transform_values { |es| es.map { |e| e[index_key] }.sort.uniq }
|
90
94
|
->(group) { indexes.fetch(group, []).shift }
|
91
95
|
end
|
92
96
|
private_class_method :indexer
|
@@ -140,12 +144,20 @@ module Heytmux
|
|
140
144
|
end
|
141
145
|
|
142
146
|
def interpret_and_expand_pane_spec(pane, items, pane_indexer)
|
147
|
+
pane_items = pane[ITEMS_KEY]
|
148
|
+
if pane_items && pane.length > 1
|
149
|
+
pane = pane.except(ITEMS_KEY)
|
150
|
+
items = pane_items || items
|
151
|
+
end
|
152
|
+
|
143
153
|
title, command = pane.is_a?(Hash) ? pane.first : [pane.tr("\n", ' '), pane]
|
144
|
-
if title =~ ITEM_PAT
|
145
|
-
items.map do |item|
|
154
|
+
if title =~ ITEM_PAT || title =~ ITEM_INDEX_PAT
|
155
|
+
items.map.with_index do |item, item_idx|
|
146
156
|
title_sub = title.gsub(ITEM_PAT, item.to_s)
|
157
|
+
.gsub(ITEM_INDEX_PAT, item_idx.to_s)
|
147
158
|
{ title: title_sub, command: command,
|
148
|
-
item: item.to_s,
|
159
|
+
item: item.to_s, item_index: item_idx,
|
160
|
+
index: pane_indexer[title_sub] }
|
149
161
|
end
|
150
162
|
else
|
151
163
|
[{ title: title, command: command, index: pane_indexer[title] }]
|
@@ -154,9 +166,9 @@ module Heytmux
|
|
154
166
|
|
155
167
|
# Checks if there are entities without the required_field and creates them
|
156
168
|
# with the given block. Returns two arrays of found and created entities.
|
157
|
-
def create_if_missing(entities, required_field)
|
169
|
+
def create_if_missing(entities, required_field, &block)
|
158
170
|
found, missing = entities.partition { |e| e[required_field] }
|
159
|
-
[found, missing.map
|
171
|
+
[found, missing.map(&block)]
|
160
172
|
end
|
161
173
|
private_class_method :create_if_missing
|
162
174
|
|
data/lib/heytmux/pane_action.rb
CHANGED
data/lib/heytmux/tmux.rb
CHANGED
@@ -23,7 +23,7 @@ module Heytmux
|
|
23
23
|
list = tmux(%w[list-panes -s -F],
|
24
24
|
labels.map { |label| "\#{#{label}}" }.join(delimiter))
|
25
25
|
list.each_line.map do |line|
|
26
|
-
|
26
|
+
labels.zip(line.chomp.split(delimiter)).to_h.tap do |h|
|
27
27
|
h[:window_index] = h[:window_index].to_i
|
28
28
|
h[:pane_index] = h[:pane_index].to_i
|
29
29
|
end
|
data/lib/heytmux/validations.rb
CHANGED
@@ -12,15 +12,15 @@ module Heytmux
|
|
12
12
|
unless spec.key?(WINDOWS_KEY)
|
13
13
|
raise(ArgumentError, 'windows key is not found')
|
14
14
|
end
|
15
|
+
|
15
16
|
spec[WINDOWS_KEY]
|
16
17
|
when Array then spec
|
17
18
|
else
|
18
19
|
raise ArgumentError, "Not a valid spec: #{spec}"
|
19
20
|
end
|
20
21
|
|
21
|
-
unless windows.is_a?(Array)
|
22
|
-
|
23
|
-
end
|
22
|
+
raise ArgumentError, 'windows must be given as a list' unless windows.is_a?(Array)
|
23
|
+
|
24
24
|
windows.each { |window| validate_window(window) }
|
25
25
|
nil
|
26
26
|
end
|
@@ -33,9 +33,8 @@ module Heytmux
|
|
33
33
|
message = "Not a valid window spec: #{window_spec.inspect}"
|
34
34
|
case window_spec
|
35
35
|
when Hash
|
36
|
-
unless single_spec?(window_spec, Hash, Array)
|
37
|
-
|
38
|
-
end
|
36
|
+
raise ArgumentError, message unless single_spec?(window_spec, Hash, Array)
|
37
|
+
|
39
38
|
spec = window_spec.first.last
|
40
39
|
spec = { PANES_KEY => spec } if spec.is_a?(Array)
|
41
40
|
spec.fetch(PANES_KEY, []).each do |pane|
|
@@ -55,6 +54,17 @@ module Heytmux
|
|
55
54
|
message = "Not a valid pane spec: #{pane_spec.inspect}"
|
56
55
|
case pane_spec
|
57
56
|
when Hash
|
57
|
+
# Is 'items' present?
|
58
|
+
has_items = pane_spec.key?(ITEMS_KEY)
|
59
|
+
if has_items && pane_spec.except(ITEMS_KEY).any?
|
60
|
+
items = pane_spec[ITEMS_KEY]
|
61
|
+
if !items.is_a?(Array) || items.empty?
|
62
|
+
raise ArgumentError, "'items' must be a non-empty array"
|
63
|
+
end
|
64
|
+
|
65
|
+
pane_spec = pane_spec.except(ITEMS_KEY)
|
66
|
+
end
|
67
|
+
|
58
68
|
unless single_spec?(pane_spec)
|
59
69
|
if unquoted_pane_title?(pane_spec)
|
60
70
|
message = 'Invalid pane title. ' \
|
@@ -62,6 +72,15 @@ module Heytmux
|
|
62
72
|
end
|
63
73
|
raise ArgumentError, message
|
64
74
|
end
|
75
|
+
|
76
|
+
if has_items
|
77
|
+
title = pane_spec.first.first
|
78
|
+
unless title =~ ITEM_PAT || title =~ ITEM_INDEX_PAT
|
79
|
+
raise ArgumentError,
|
80
|
+
'Pane title must contain {{ item }} or {{ item.index }} ' \
|
81
|
+
"when 'items' is given"
|
82
|
+
end
|
83
|
+
end
|
65
84
|
validate_commands(pane_spec.first.last)
|
66
85
|
else
|
67
86
|
raise ArgumentError, message unless valid_name?(pane_spec)
|
@@ -77,6 +96,7 @@ module Heytmux
|
|
77
96
|
case command
|
78
97
|
when Hash
|
79
98
|
raise ArgumentError, message unless single_spec?(command)
|
99
|
+
|
80
100
|
label, body = command.first
|
81
101
|
validate_action(label, body)
|
82
102
|
else
|
@@ -90,6 +110,7 @@ module Heytmux
|
|
90
110
|
def validate_action(label, body)
|
91
111
|
action = PaneAction.for(label)
|
92
112
|
raise ArgumentError, "Unsupported action: #{label}" unless action
|
113
|
+
|
93
114
|
action.validate(body)
|
94
115
|
end
|
95
116
|
|
data/lib/heytmux/version.rb
CHANGED
data/lib/heytmux.rb
CHANGED
@@ -6,9 +6,9 @@ require 'set'
|
|
6
6
|
module Heytmux
|
7
7
|
DEFAULT_LAYOUT = ->(num_panes) { num_panes <= 3 ? 'even-vertical' : 'tiled' }
|
8
8
|
DEFAULT_OPTIONS = {
|
9
|
-
'automatic-rename'
|
10
|
-
'allow-rename'
|
11
|
-
'pane-base-index'
|
9
|
+
'automatic-rename' => 'off',
|
10
|
+
'allow-rename' => 'off',
|
11
|
+
'pane-base-index' => 0,
|
12
12
|
'pane-border-status' => 'bottom',
|
13
13
|
'pane-border-format' => '#{pane_title}'
|
14
14
|
}.freeze
|
@@ -17,8 +17,9 @@ module Heytmux
|
|
17
17
|
LAYOUT_KEY = 'layout'
|
18
18
|
PANES_KEY = 'panes'
|
19
19
|
ITEMS_KEY = 'items'
|
20
|
-
ITEM_PAT = /{{ *item *}}/i
|
21
|
-
|
20
|
+
ITEM_PAT = /{{ *item *}}/i.freeze
|
21
|
+
ITEM_INDEX_PAT = /{{ *item\.index *}}/i.freeze
|
22
|
+
ENV_PAT = /{{ *\$([a-z0-9_]+) *(?:\| *(.*?) *)?}}/i.freeze
|
22
23
|
|
23
24
|
EXPECT_SLEEP_INTERVAL = 0.5
|
24
25
|
EXPECT_TIMEOUT = 60
|
metadata
CHANGED
@@ -1,59 +1,44 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heytmux
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Junegunn Choi
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-05-20 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: bundler
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
|
-
- - "
|
16
|
+
- - ">="
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
18
|
+
version: 2.2.15
|
20
19
|
type: :development
|
21
20
|
prerelease: false
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
23
22
|
requirements:
|
24
|
-
- - "
|
23
|
+
- - ">="
|
25
24
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
25
|
+
version: 2.2.15
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
27
|
+
name: coveralls_reborn
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
30
29
|
requirements:
|
31
|
-
- - "
|
30
|
+
- - ">="
|
32
31
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
32
|
+
version: '0'
|
34
33
|
type: :development
|
35
34
|
prerelease: false
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
37
36
|
requirements:
|
38
|
-
- - "
|
37
|
+
- - ">="
|
39
38
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
39
|
+
version: '0'
|
41
40
|
- !ruby/object:Gem::Dependency
|
42
41
|
name: minitest
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '5.10'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '5.10'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: pry
|
57
42
|
requirement: !ruby/object:Gem::Requirement
|
58
43
|
requirements:
|
59
44
|
- - ">="
|
@@ -67,7 +52,7 @@ dependencies:
|
|
67
52
|
- !ruby/object:Gem::Version
|
68
53
|
version: '0'
|
69
54
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
55
|
+
name: pry
|
71
56
|
requirement: !ruby/object:Gem::Requirement
|
72
57
|
requirements:
|
73
58
|
- - ">="
|
@@ -81,7 +66,7 @@ dependencies:
|
|
81
66
|
- !ruby/object:Gem::Version
|
82
67
|
version: '0'
|
83
68
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
69
|
+
name: rake
|
85
70
|
requirement: !ruby/object:Gem::Requirement
|
86
71
|
requirements:
|
87
72
|
- - ">="
|
@@ -121,7 +106,6 @@ files:
|
|
121
106
|
homepage: https://github.com/junegunn/heytmux
|
122
107
|
licenses: []
|
123
108
|
metadata: {}
|
124
|
-
post_install_message:
|
125
109
|
rdoc_options: []
|
126
110
|
require_paths:
|
127
111
|
- lib
|
@@ -129,16 +113,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
113
|
requirements:
|
130
114
|
- - ">="
|
131
115
|
- !ruby/object:Gem::Version
|
132
|
-
version: '2.
|
116
|
+
version: '2.4'
|
133
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
118
|
requirements:
|
135
119
|
- - ">="
|
136
120
|
- !ruby/object:Gem::Version
|
137
121
|
version: '0'
|
138
122
|
requirements: []
|
139
|
-
|
140
|
-
rubygems_version: 2.6.8
|
141
|
-
signing_key:
|
123
|
+
rubygems_version: 3.6.2
|
142
124
|
specification_version: 4
|
143
125
|
summary: Hey tmux!
|
144
126
|
test_files: []
|