heytmux 0.0.0 → 0.1.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 +4 -4
- data/README.md +23 -2
- data/lib/heytmux.rb +5 -2
- data/lib/heytmux/core.rb +6 -21
- data/lib/heytmux/pane_action.rb +44 -0
- data/lib/heytmux/pane_actions/expect.rb +36 -0
- data/lib/heytmux/pane_actions/keys.rb +23 -0
- data/lib/heytmux/pane_actions/paste.rb +21 -0
- data/lib/heytmux/pane_actions/sleep.rb +18 -0
- data/lib/heytmux/validations.rb +20 -19
- data/lib/heytmux/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53af5daf1e2193c29b0a85affdb4fc72b739b536
|
4
|
+
data.tar.gz: 76fe05372f8e0252556ae26cbcb98f40579dca4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80b1a5981d257825a5ac9478c2e0dc089f4898a2ad17e49eb78d189227f3e46348fefe196b1b79b061237a28f1ee6730a5ccb5c22f7bf536d7f22cd37d64a0e8
|
7
|
+
data.tar.gz: b19c74aa98d105879a6374e9d92639906338d0dca952055c07d1af8f974421a69894d4d82e97c46136a68b8a6c209e4b107fddb2c4715e28655e16b752147529
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
Hey tmux!
|
2
2
|
=========
|
3
3
|
|
4
|
+
[](https://travis-ci.org/junegunn/heytmux) [](https://coveralls.io/github/junegunn/heytmux?branch=master)
|
5
|
+
|
4
6
|
Tmux scripting made easy.
|
5
7
|
|
6
8
|
Installation
|
@@ -25,7 +27,9 @@ Plug 'junegunn/heytmux'
|
|
25
27
|
```
|
26
28
|
|
27
29
|
- Registers `:Heytmux` command
|
28
|
-
- No need to install Gem
|
30
|
+
- No need to install Gem if you only use Heytmux inside Vim
|
31
|
+
- But if you want it to be globally available,
|
32
|
+
`Plug 'junegunn/heytmux', { 'do': 'gem install heytmux' }`
|
29
33
|
|
30
34
|
Usage
|
31
35
|
-----
|
@@ -252,7 +256,7 @@ following example will not work as expected.
|
|
252
256
|
```
|
253
257
|
|
254
258
|
With `expect` construct, you can make Heytmux wait until a certain regular
|
255
|
-
expression pattern appears on the
|
259
|
+
expression pattern appears on the pane (a la [Expect][expect]).
|
256
260
|
|
257
261
|
[expect]: https://en.wikipedia.org/wiki/Expect
|
258
262
|
|
@@ -265,6 +269,23 @@ expression pattern appears on the the pane (a la [Expect][expect]).
|
|
265
269
|
- uptime
|
266
270
|
```
|
267
271
|
|
272
|
+
#### Special commands
|
273
|
+
|
274
|
+
In addition to `expect`, Heytmux also supports `sleep` and `keys` commands.
|
275
|
+
`sleep` suspends the execution for a given time period. It's useful when the
|
276
|
+
shell on the target pane is non-interactive so you can't send `sleep` command
|
277
|
+
to it. `keys` command is for sending special keys, such as `c-c` (CTRL-C)
|
278
|
+
using `tmux send-keys` command. To send multiple keys, specify the keys as
|
279
|
+
a YAML list (e.g. `[c-c, c-l]`).
|
280
|
+
|
281
|
+
```yaml
|
282
|
+
- servers:
|
283
|
+
- server 1:
|
284
|
+
- vmstat 2 | tee log
|
285
|
+
- sleep: 3
|
286
|
+
- keys: c-c
|
287
|
+
```
|
288
|
+
|
268
289
|
Vim plugin
|
269
290
|
----------
|
270
291
|
|
data/lib/heytmux.rb
CHANGED
@@ -13,8 +13,6 @@ module Heytmux
|
|
13
13
|
'pane-border-format' => '#{pane_title}'
|
14
14
|
}.freeze
|
15
15
|
|
16
|
-
SUPPORTED_ACTIONS = %w[expect].to_set.freeze
|
17
|
-
|
18
16
|
WINDOWS_KEY = 'windows'
|
19
17
|
LAYOUT_KEY = 'layout'
|
20
18
|
PANES_KEY = 'panes'
|
@@ -28,5 +26,10 @@ end
|
|
28
26
|
|
29
27
|
require 'heytmux/version'
|
30
28
|
require 'heytmux/validations'
|
29
|
+
require 'heytmux/pane_action'
|
30
|
+
require 'heytmux/pane_actions/paste'
|
31
|
+
require 'heytmux/pane_actions/expect'
|
32
|
+
require 'heytmux/pane_actions/sleep'
|
33
|
+
require 'heytmux/pane_actions/keys'
|
31
34
|
require 'heytmux/tmux'
|
32
35
|
require 'heytmux/core'
|
data/lib/heytmux/core.rb
CHANGED
@@ -69,33 +69,18 @@ module Heytmux
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
# Finds appropriate PaneActions for the commands and processes them
|
72
73
|
def process_command!(window_index, pane)
|
73
74
|
pane_index, item, commands = pane.values_at(:index, :item, :command)
|
74
|
-
[*commands].each do |command|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
wait_until do
|
80
|
-
content = Tmux.capture(window_index, pane_index)
|
81
|
-
content =~ regex
|
82
|
-
end
|
83
|
-
else
|
84
|
-
command = command.gsub(ITEM_PAT, item) if item
|
85
|
-
Tmux.paste(window_index, pane_index, command)
|
75
|
+
[*commands].compact.each do |command|
|
76
|
+
label, body = command.is_a?(Hash) ? command.first : [:paste, command]
|
77
|
+
PaneAction.for(label).process(window_index, pane_index, body) do |source|
|
78
|
+
string = source.to_s
|
79
|
+
item ? string.gsub(ITEM_PAT, item) : string
|
86
80
|
end
|
87
81
|
end
|
88
82
|
end
|
89
83
|
|
90
|
-
def wait_until
|
91
|
-
timeout = Time.now + EXPECT_TIMEOUT
|
92
|
-
loop do
|
93
|
-
sleep EXPECT_SLEEP_INTERVAL
|
94
|
-
return if yield
|
95
|
-
raise 'Timed out' if Time.now > timeout
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
84
|
# Groups entities by the group key and extracts unique, sorted indexes and
|
100
85
|
# returns stateful indexer that issues index number for the given group key
|
101
86
|
def indexer(entities, group_key, index_key)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Heytmux
|
4
|
+
# Base class for pane actions. To implement a new type of action that is
|
5
|
+
# applied to a designated pane, one should write a class that derives from
|
6
|
+
# this class. Use register class method to associate the class with one or
|
7
|
+
# more labels.
|
8
|
+
class PaneAction
|
9
|
+
# Validation method to be overridden. Throw ArgumentError if body is
|
10
|
+
# invalid.
|
11
|
+
def validate(_body)
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
# Defines the behavior of the action. Should be implemented by the
|
16
|
+
# subclasses. When the method is called, a block is passed that is for
|
17
|
+
# replacing {{ item }} in the body. One may or may not want to use it on
|
18
|
+
# body depending on the use case.
|
19
|
+
def process(_window_index, _pane_index, _body)
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
# Registers a PaneAction class with the label
|
25
|
+
def register(*labels, klass)
|
26
|
+
instance = klass.new
|
27
|
+
(@actions ||= {}).merge!(
|
28
|
+
Hash[labels.map { |label| [label, instance] }]
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Finds PaneAction class for the label
|
33
|
+
def for(label)
|
34
|
+
@actions[label.to_sym]
|
35
|
+
end
|
36
|
+
|
37
|
+
def inherited(klass)
|
38
|
+
def klass.register(*labels)
|
39
|
+
PaneAction.register(*labels, self)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
module Heytmux
|
6
|
+
module PaneActions
|
7
|
+
# Pastes the command onto the pane
|
8
|
+
class Expect < PaneAction
|
9
|
+
register :expect
|
10
|
+
|
11
|
+
def validate(body)
|
12
|
+
raise ArgumentError, 'Expect condition is empty' if body.to_s.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def process(window_index, pane_index, body)
|
16
|
+
regex = Regexp.compile(yield(body))
|
17
|
+
wait_until do
|
18
|
+
content = Tmux.capture(window_index, pane_index)
|
19
|
+
raise 'Failed to capture pane content' unless $CHILD_STATUS.success?
|
20
|
+
content =~ regex
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def wait_until
|
27
|
+
timeout = Time.now + EXPECT_TIMEOUT
|
28
|
+
loop do
|
29
|
+
sleep EXPECT_SLEEP_INTERVAL
|
30
|
+
return if yield
|
31
|
+
raise 'Timed out' if Time.now > timeout
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Heytmux
|
4
|
+
module PaneActions
|
5
|
+
# Send keys using tmux send-keys command
|
6
|
+
class Keys < PaneAction
|
7
|
+
register :keys, :key
|
8
|
+
|
9
|
+
def validate(body)
|
10
|
+
body = body.is_a?(Array) ? body : [body]
|
11
|
+
body.each do |key|
|
12
|
+
unless Validations.valid_string?(key)
|
13
|
+
raise ArgumentError, 'Keys must be given as a string or a list'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(window_index, pane_index, body)
|
19
|
+
Tmux.tmux('send-keys', Tmux.target(window_index, pane_index), body)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Heytmux
|
4
|
+
module PaneActions
|
5
|
+
# Waits for a certain regular expression pattern appears
|
6
|
+
class Paste < PaneAction
|
7
|
+
register :paste
|
8
|
+
|
9
|
+
def validate(body)
|
10
|
+
case body
|
11
|
+
when Hash, Array
|
12
|
+
raise ArgumentError, "Invalid command: #{body}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def process(window_index, pane_index, body)
|
17
|
+
Tmux.paste(window_index, pane_index, yield(body))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Heytmux
|
4
|
+
module PaneActions
|
5
|
+
# Sleeps for the given duration
|
6
|
+
class Sleep < PaneAction
|
7
|
+
register :sleep
|
8
|
+
|
9
|
+
def validate(body)
|
10
|
+
raise ArgumentError, 'Sleep expects positive number' if body.to_f <= 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(_window_index, _pane_index, body)
|
14
|
+
sleep(body.to_f)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/heytmux/validations.rb
CHANGED
@@ -65,29 +65,28 @@ module Heytmux
|
|
65
65
|
# - command_string
|
66
66
|
# - [command_strings_or_hashes...]
|
67
67
|
def validate_commands(commands)
|
68
|
-
return if commands.is_a?(String)
|
69
68
|
message = "Invalid command: #{commands.inspect}"
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
69
|
+
commands = commands.is_a?(Array) ? commands : [commands]
|
70
|
+
commands.each do |command|
|
71
|
+
case command
|
72
|
+
when Hash
|
74
73
|
raise ArgumentError, message unless single_spec?(command)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
raise ArgumentError, message unless valid_name?(condition)
|
80
|
-
Regexp.compile(condition.to_s)
|
74
|
+
label, body = command.first
|
75
|
+
validate_action(label, body)
|
76
|
+
else
|
77
|
+
raise ArgumentError, message unless valid_string?(command)
|
81
78
|
end
|
82
|
-
strings.each do |command|
|
83
|
-
raise ArgumentError, message unless valid_name?(command)
|
84
|
-
end
|
85
|
-
else
|
86
|
-
raise ArgumentError, message unless valid_name?(commands)
|
87
79
|
end
|
88
80
|
nil
|
89
81
|
end
|
90
82
|
|
83
|
+
# Checks if the action is currently supported
|
84
|
+
def validate_action(label, body)
|
85
|
+
action = PaneAction.for(label)
|
86
|
+
raise ArgumentError, "Unsupported action: #{label}" unless action
|
87
|
+
action.validate(body)
|
88
|
+
end
|
89
|
+
|
91
90
|
# Checks if the given hash only contains one mapping from a string to
|
92
91
|
# a hash
|
93
92
|
def single_spec?(spec, *klasses)
|
@@ -95,11 +94,13 @@ module Heytmux
|
|
95
94
|
second.nil? && !key.to_s.empty? &&
|
96
95
|
(klasses.empty? || klasses.any? { |k| value.is_a?(k) })
|
97
96
|
end
|
98
|
-
|
97
|
+
|
98
|
+
def valid_string?(value)
|
99
|
+
!(value.is_a?(Array) || value.is_a?(Hash))
|
100
|
+
end
|
99
101
|
|
100
102
|
def valid_name?(value)
|
101
|
-
|
103
|
+
valid_string?(value) && !value.to_s.empty?
|
102
104
|
end
|
103
|
-
private_class_method :valid_name?
|
104
105
|
end
|
105
106
|
end
|
data/lib/heytmux/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heytmux
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Junegunn Choi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-07-
|
11
|
+
date: 2017-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -110,6 +110,11 @@ files:
|
|
110
110
|
- heytmux.gemspec
|
111
111
|
- lib/heytmux.rb
|
112
112
|
- lib/heytmux/core.rb
|
113
|
+
- lib/heytmux/pane_action.rb
|
114
|
+
- lib/heytmux/pane_actions/expect.rb
|
115
|
+
- lib/heytmux/pane_actions/keys.rb
|
116
|
+
- lib/heytmux/pane_actions/paste.rb
|
117
|
+
- lib/heytmux/pane_actions/sleep.rb
|
113
118
|
- lib/heytmux/tmux.rb
|
114
119
|
- lib/heytmux/validations.rb
|
115
120
|
- lib/heytmux/version.rb
|
@@ -132,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
137
|
version: '0'
|
133
138
|
requirements: []
|
134
139
|
rubyforge_project:
|
135
|
-
rubygems_version: 2.6.
|
140
|
+
rubygems_version: 2.6.11
|
136
141
|
signing_key:
|
137
142
|
specification_version: 4
|
138
143
|
summary: Hey tmux!
|