teamocil 0.4.5 → 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/.gitignore +14 -4
- data/.rubocop.yml +48 -0
- data/.travis.yml +2 -2
- data/Gemfile +1 -1
- data/{LICENSE → LICENSE.md} +0 -0
- data/README.md +124 -166
- data/Rakefile +12 -27
- data/bin/teamocil +3 -4
- data/lib/teamocil.rb +51 -4
- data/lib/teamocil/cli.rb +23 -90
- data/lib/teamocil/command/new_window.rb +16 -0
- data/lib/teamocil/command/rename_session.rb +9 -0
- data/lib/teamocil/command/rename_window.rb +9 -0
- data/lib/teamocil/command/select_layout.rb +9 -0
- data/lib/teamocil/command/select_pane.rb +9 -0
- data/lib/teamocil/command/select_window.rb +9 -0
- data/lib/teamocil/command/send_keys.rb +9 -0
- data/lib/teamocil/command/send_keys_to_pane.rb +9 -0
- data/lib/teamocil/command/split_window.rb +15 -0
- data/lib/teamocil/layout.rb +58 -36
- data/lib/teamocil/tmux/pane.rb +15 -0
- data/lib/teamocil/tmux/session.rb +28 -0
- data/lib/teamocil/tmux/window.rb +47 -0
- data/lib/teamocil/utils/closed_struct.rb +16 -0
- data/lib/teamocil/utils/option_parser.rb +56 -0
- data/lib/teamocil/version.rb +1 -1
- data/teamocil.gemspec +15 -16
- metadata +27 -54
- data/examples/four-splits.yml +0 -8
- data/examples/one-and-three-splits.yml +0 -8
- data/examples/six-splits.yml +0 -10
- data/examples/two-horizontal-splits.yml +0 -6
- data/examples/two-vertical-splits.yml +0 -6
- data/lib/teamocil/error.rb +0 -6
- data/lib/teamocil/layout/pane.rb +0 -66
- data/lib/teamocil/layout/session.rb +0 -30
- data/lib/teamocil/layout/window.rb +0 -77
- data/spec/cli_spec.rb +0 -79
- data/spec/fixtures/.my-fancy-layouts-directory/sample-3.yml +0 -10
- data/spec/fixtures/.teamocil/sample-2.yml +0 -10
- data/spec/fixtures/.teamocil/sample.yml +0 -10
- data/spec/fixtures/layouts.yml +0 -76
- data/spec/layout_spec.rb +0 -229
- data/spec/mock/cli.rb +0 -35
- data/spec/mock/layout.rb +0 -16
- data/spec/spec_helper.rb +0 -17
@@ -0,0 +1,15 @@
|
|
1
|
+
module Teamocil
|
2
|
+
class Pane < ClosedStruct.new(:index, :root, :commands, :focus)
|
3
|
+
def as_tmux
|
4
|
+
[].tap do |tmux|
|
5
|
+
tmux << Command::SplitWindow.new(root: root) unless first?
|
6
|
+
tmux << Command::SendKeysToPane.new(index: index, keys: commands.join('; '))
|
7
|
+
tmux << Command::SendKeysToPane.new(index: index, keys: 'Enter')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def first?
|
12
|
+
index == 1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Teamocil
|
2
|
+
class Session < ClosedStruct.new(:name, :windows)
|
3
|
+
def initialize(object)
|
4
|
+
super
|
5
|
+
|
6
|
+
# Sessions need a name
|
7
|
+
self.name = "teamocil-session-#{rand(1_000_000)}" unless name
|
8
|
+
|
9
|
+
self.windows = windows.each_with_index.map do |window, index|
|
10
|
+
# Windows need to know their position
|
11
|
+
window.merge! index: index + 1
|
12
|
+
|
13
|
+
Window.new(window)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_tmux
|
18
|
+
[].tap do |tmux|
|
19
|
+
tmux << Command::RenameSession.new(name: name)
|
20
|
+
tmux << windows.map(&:as_tmux)
|
21
|
+
|
22
|
+
# Set the focus on the right window or do nothing
|
23
|
+
focused_window = windows.find(&:focus)
|
24
|
+
tmux << Command::SelectWindow.new(index: focused_window.index) if focused_window
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Teamocil
|
2
|
+
class Window < ClosedStruct.new(:index, :root, :focus, :layout, :name, :panes)
|
3
|
+
def initialize(object)
|
4
|
+
super
|
5
|
+
|
6
|
+
self.panes ||= splits
|
7
|
+
self.panes = panes.each_with_index.map do |pane, index|
|
8
|
+
# Support single command instead of `commands` key in Hash
|
9
|
+
pane = { commands: [pane] } if pane.is_a?(String)
|
10
|
+
|
11
|
+
# Panes need to know their position
|
12
|
+
pane.merge! index: index + 1
|
13
|
+
|
14
|
+
# Panes need know the window root directory
|
15
|
+
pane.merge! root: root
|
16
|
+
|
17
|
+
Pane.new(pane)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def first?
|
22
|
+
index == 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def as_tmux
|
26
|
+
[].tap do |tmux|
|
27
|
+
# Rename the current window or create a new one
|
28
|
+
if Teamocil.options[:here] && first?
|
29
|
+
tmux << Command::RenameWindow.new(name: name)
|
30
|
+
else
|
31
|
+
tmux << Command::NewWindow.new(name: name, root: root)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Execute all panes commands
|
35
|
+
tmux << panes.map(&:as_tmux)
|
36
|
+
|
37
|
+
# Select the window layout
|
38
|
+
tmux << Command::SelectLayout.new(layout: layout)
|
39
|
+
|
40
|
+
# Set the focus on the right pane or the first one
|
41
|
+
focused_pane = panes.find(&:focus)
|
42
|
+
focused_index = focused_pane ? focused_pane.index : 0
|
43
|
+
tmux << Command::SelectPane.new(index: focused_index)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Teamocil
|
2
|
+
class ClosedStruct < Struct
|
3
|
+
def initialize(*args)
|
4
|
+
args = [{}] unless args.any?
|
5
|
+
|
6
|
+
args.first.each_pair do |key, value|
|
7
|
+
# Make sure we only set values to defined arguments
|
8
|
+
if members.map { |x| x.intern }.include?(key.to_sym)
|
9
|
+
send "#{key}=", value
|
10
|
+
else
|
11
|
+
raise ArgumentError, "#{self.class.name} doesn’t support the `#{key}` keyword, only #{members.join(', ')}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Teamocil
|
2
|
+
class OptionParser
|
3
|
+
def initialize(arguments:)
|
4
|
+
@arguments = arguments
|
5
|
+
@parsed_options = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def parsed_options
|
9
|
+
@parsed_options.tap do
|
10
|
+
parser.parse!(@arguments)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# rubocop:disable MethodLength
|
15
|
+
def parser
|
16
|
+
::OptionParser.new do |parser|
|
17
|
+
parser.banner = 'Usage: teamocil [options] <layout>'
|
18
|
+
parser.separator ''
|
19
|
+
parser.separator 'Specific options:'
|
20
|
+
|
21
|
+
# Global options
|
22
|
+
parser.on('--list', 'List all available layouts in `~/.teamocil/`') do
|
23
|
+
@parsed_options[:list] = true
|
24
|
+
end
|
25
|
+
|
26
|
+
# Single layout options
|
27
|
+
parser.on('--here', 'Set up the first layout window in the current tmux window') do
|
28
|
+
@parsed_options[:here] = true
|
29
|
+
end
|
30
|
+
|
31
|
+
parser.on('--layout [layout]', 'Use a specific layout file, instead of `~/.teamocil/<layout>.yml`') do |layout|
|
32
|
+
@parsed_options[:layout] = layout
|
33
|
+
end
|
34
|
+
|
35
|
+
parser.on('--edit', 'Edit the YAML layout file instead of using it') do
|
36
|
+
@parsed_options[:edit] = true
|
37
|
+
end
|
38
|
+
|
39
|
+
parser.on('--show', 'Show the content of the layout file instead of executing it') do
|
40
|
+
@parsed_options[:show] = true
|
41
|
+
end
|
42
|
+
|
43
|
+
# Debug options
|
44
|
+
parser.on('--debug', 'Show the commands Teamocil will execute instead of actually executing them') do
|
45
|
+
@parsed_options[:debug] = true
|
46
|
+
end
|
47
|
+
|
48
|
+
parser.on('--version', '-v', 'Show Teamocil’s version number') do
|
49
|
+
Teamocil.puts(VERSION)
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
# rubocop:enable all
|
55
|
+
end
|
56
|
+
end
|
data/lib/teamocil/version.rb
CHANGED
data/teamocil.gemspec
CHANGED
@@ -1,29 +1,28 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
require
|
3
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
4
|
+
require 'teamocil/version'
|
5
5
|
|
6
|
-
|
6
|
+
Gem::Specification.new do |s|
|
7
7
|
# Metadata
|
8
|
-
s.name =
|
8
|
+
s.name = 'teamocil'
|
9
9
|
s.version = Teamocil::VERSION
|
10
10
|
s.platform = Gem::Platform::RUBY
|
11
|
-
s.authors =
|
12
|
-
s.email =
|
13
|
-
s.homepage =
|
14
|
-
s.license =
|
15
|
-
s.summary =
|
16
|
-
s.description =
|
11
|
+
s.authors = 'Rémi Prévost'
|
12
|
+
s.email = 'remi@exomel.com'
|
13
|
+
s.homepage = 'http://remiprev.github.com/teamocil'
|
14
|
+
s.license = 'MIT'
|
15
|
+
s.summary = 'Easy session, window and pane layouts for tmux'
|
16
|
+
s.description = 'Teamocil helps you set up window and pane layouts for tmux using YAML configuration files.'
|
17
17
|
|
18
18
|
# Manifest
|
19
19
|
s.files = `git ls-files`.split("\n")
|
20
20
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
-
s.require_paths = [
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
22
|
+
s.require_paths = ['lib']
|
23
23
|
|
24
24
|
# Dependencies
|
25
|
-
s.add_development_dependency
|
26
|
-
s.add_development_dependency
|
27
|
-
s.add_development_dependency
|
28
|
-
s.add_development_dependency "maruku"
|
25
|
+
s.add_development_dependency 'rake'
|
26
|
+
s.add_development_dependency 'phare', '~> 0.6'
|
27
|
+
s.add_development_dependency 'rubocop', '~> 0.24'
|
29
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: teamocil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0
|
4
|
+
version: '1.0'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rémi Prévost
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06
|
11
|
+
date: 2014-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -25,47 +25,33 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: phare
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0.6'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0.6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rubocop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: maruku
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
45
|
+
- - "~>"
|
60
46
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
47
|
+
version: '0.24'
|
62
48
|
type: :development
|
63
49
|
prerelease: false
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
65
51
|
requirements:
|
66
|
-
- - "
|
52
|
+
- - "~>"
|
67
53
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
54
|
+
version: '0.24'
|
69
55
|
description: Teamocil helps you set up window and pane layouts for tmux using YAML
|
70
56
|
configuration files.
|
71
57
|
email: remi@exomel.com
|
@@ -75,34 +61,31 @@ extensions: []
|
|
75
61
|
extra_rdoc_files: []
|
76
62
|
files:
|
77
63
|
- ".gitignore"
|
64
|
+
- ".rubocop.yml"
|
78
65
|
- ".travis.yml"
|
79
66
|
- Gemfile
|
80
|
-
- LICENSE
|
67
|
+
- LICENSE.md
|
81
68
|
- README.md
|
82
69
|
- Rakefile
|
83
70
|
- bin/teamocil
|
84
|
-
- examples/four-splits.yml
|
85
|
-
- examples/one-and-three-splits.yml
|
86
|
-
- examples/six-splits.yml
|
87
|
-
- examples/two-horizontal-splits.yml
|
88
|
-
- examples/two-vertical-splits.yml
|
89
71
|
- lib/teamocil.rb
|
90
72
|
- lib/teamocil/cli.rb
|
91
|
-
- lib/teamocil/
|
73
|
+
- lib/teamocil/command/new_window.rb
|
74
|
+
- lib/teamocil/command/rename_session.rb
|
75
|
+
- lib/teamocil/command/rename_window.rb
|
76
|
+
- lib/teamocil/command/select_layout.rb
|
77
|
+
- lib/teamocil/command/select_pane.rb
|
78
|
+
- lib/teamocil/command/select_window.rb
|
79
|
+
- lib/teamocil/command/send_keys.rb
|
80
|
+
- lib/teamocil/command/send_keys_to_pane.rb
|
81
|
+
- lib/teamocil/command/split_window.rb
|
92
82
|
- lib/teamocil/layout.rb
|
93
|
-
- lib/teamocil/
|
94
|
-
- lib/teamocil/
|
95
|
-
- lib/teamocil/
|
83
|
+
- lib/teamocil/tmux/pane.rb
|
84
|
+
- lib/teamocil/tmux/session.rb
|
85
|
+
- lib/teamocil/tmux/window.rb
|
86
|
+
- lib/teamocil/utils/closed_struct.rb
|
87
|
+
- lib/teamocil/utils/option_parser.rb
|
96
88
|
- lib/teamocil/version.rb
|
97
|
-
- spec/cli_spec.rb
|
98
|
-
- spec/fixtures/.my-fancy-layouts-directory/sample-3.yml
|
99
|
-
- spec/fixtures/.teamocil/sample-2.yml
|
100
|
-
- spec/fixtures/.teamocil/sample.yml
|
101
|
-
- spec/fixtures/layouts.yml
|
102
|
-
- spec/layout_spec.rb
|
103
|
-
- spec/mock/cli.rb
|
104
|
-
- spec/mock/layout.rb
|
105
|
-
- spec/spec_helper.rb
|
106
89
|
- teamocil.gemspec
|
107
90
|
homepage: http://remiprev.github.com/teamocil
|
108
91
|
licenses:
|
@@ -128,14 +111,4 @@ rubygems_version: 2.2.2
|
|
128
111
|
signing_key:
|
129
112
|
specification_version: 4
|
130
113
|
summary: Easy session, window and pane layouts for tmux
|
131
|
-
test_files:
|
132
|
-
- spec/cli_spec.rb
|
133
|
-
- spec/fixtures/.my-fancy-layouts-directory/sample-3.yml
|
134
|
-
- spec/fixtures/.teamocil/sample-2.yml
|
135
|
-
- spec/fixtures/.teamocil/sample.yml
|
136
|
-
- spec/fixtures/layouts.yml
|
137
|
-
- spec/layout_spec.rb
|
138
|
-
- spec/mock/cli.rb
|
139
|
-
- spec/mock/layout.rb
|
140
|
-
- spec/spec_helper.rb
|
141
|
-
has_rdoc:
|
114
|
+
test_files: []
|
data/examples/four-splits.yml
DELETED
data/examples/six-splits.yml
DELETED
data/lib/teamocil/error.rb
DELETED
data/lib/teamocil/layout/pane.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
module Teamocil
|
2
|
-
class Layout
|
3
|
-
# This class represents a pane within a tmux window
|
4
|
-
class Pane
|
5
|
-
attr_reader :width, :height, :cmd, :index, :target, :focus
|
6
|
-
|
7
|
-
# Initialize a new tmux pane
|
8
|
-
#
|
9
|
-
# @param session [Session] the window where the pane is initialized
|
10
|
-
# @param index [Fixnnum] the pane index
|
11
|
-
# @param attrs [Hash] the pane data from the layout file
|
12
|
-
def initialize(window, index, attrs={})
|
13
|
-
raise Teamocil::Error::LayoutError.new("You cannot have empty panes") if attrs.nil?
|
14
|
-
@height = attrs["height"]
|
15
|
-
@width = attrs["width"]
|
16
|
-
@cmd = attrs["cmd"]
|
17
|
-
@target = attrs["target"]
|
18
|
-
@focus = attrs["focus"] || false
|
19
|
-
|
20
|
-
@window = window
|
21
|
-
@index = index
|
22
|
-
end
|
23
|
-
|
24
|
-
# Generate commands to send to tmux
|
25
|
-
#
|
26
|
-
# @return [Array]
|
27
|
-
def generate_commands
|
28
|
-
commands = []
|
29
|
-
|
30
|
-
# Is it a vertical or horizontal pane
|
31
|
-
init_command = ""
|
32
|
-
unless @index == @window.pane_base_index
|
33
|
-
if !@width.nil?
|
34
|
-
init_command = "tmux split-window -h -p #{@width}"
|
35
|
-
elsif !@height.nil?
|
36
|
-
init_command = "tmux split-window -p #{@height}"
|
37
|
-
else
|
38
|
-
init_command = "tmux split-window"
|
39
|
-
end
|
40
|
-
init_command << " -t #{@target}" unless @target.nil?
|
41
|
-
commands << init_command
|
42
|
-
end
|
43
|
-
|
44
|
-
# Wrap all commands around filters
|
45
|
-
@cmd = [@window.filters["before"]] + [@window.clear] + [@cmd] + [@window.filters["after"]]
|
46
|
-
|
47
|
-
# If a `root` key exist, start each pane in this directory
|
48
|
-
@cmd.unshift "cd \"#{@window.root}\"" unless @window.root.nil?
|
49
|
-
|
50
|
-
# Set the TEAMOCIL environment variable
|
51
|
-
# depending on the shell set in ENV
|
52
|
-
if ENV['SHELL'].scan(/fish/).empty?
|
53
|
-
@cmd.unshift "export TEAMOCIL=1" if @window.with_env_var
|
54
|
-
else
|
55
|
-
@cmd.unshift "set -gx TEAMOCIL 1"
|
56
|
-
end
|
57
|
-
|
58
|
-
# Execute each pane command
|
59
|
-
commands << "tmux send-keys -t #{@index} \"#{@cmd.flatten.compact.join(@window.cmd_separator)}\""
|
60
|
-
commands << "tmux send-keys -t #{@index} Enter"
|
61
|
-
|
62
|
-
commands
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|