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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -4
  3. data/.rubocop.yml +48 -0
  4. data/.travis.yml +2 -2
  5. data/Gemfile +1 -1
  6. data/{LICENSE → LICENSE.md} +0 -0
  7. data/README.md +124 -166
  8. data/Rakefile +12 -27
  9. data/bin/teamocil +3 -4
  10. data/lib/teamocil.rb +51 -4
  11. data/lib/teamocil/cli.rb +23 -90
  12. data/lib/teamocil/command/new_window.rb +16 -0
  13. data/lib/teamocil/command/rename_session.rb +9 -0
  14. data/lib/teamocil/command/rename_window.rb +9 -0
  15. data/lib/teamocil/command/select_layout.rb +9 -0
  16. data/lib/teamocil/command/select_pane.rb +9 -0
  17. data/lib/teamocil/command/select_window.rb +9 -0
  18. data/lib/teamocil/command/send_keys.rb +9 -0
  19. data/lib/teamocil/command/send_keys_to_pane.rb +9 -0
  20. data/lib/teamocil/command/split_window.rb +15 -0
  21. data/lib/teamocil/layout.rb +58 -36
  22. data/lib/teamocil/tmux/pane.rb +15 -0
  23. data/lib/teamocil/tmux/session.rb +28 -0
  24. data/lib/teamocil/tmux/window.rb +47 -0
  25. data/lib/teamocil/utils/closed_struct.rb +16 -0
  26. data/lib/teamocil/utils/option_parser.rb +56 -0
  27. data/lib/teamocil/version.rb +1 -1
  28. data/teamocil.gemspec +15 -16
  29. metadata +27 -54
  30. data/examples/four-splits.yml +0 -8
  31. data/examples/one-and-three-splits.yml +0 -8
  32. data/examples/six-splits.yml +0 -10
  33. data/examples/two-horizontal-splits.yml +0 -6
  34. data/examples/two-vertical-splits.yml +0 -6
  35. data/lib/teamocil/error.rb +0 -6
  36. data/lib/teamocil/layout/pane.rb +0 -66
  37. data/lib/teamocil/layout/session.rb +0 -30
  38. data/lib/teamocil/layout/window.rb +0 -77
  39. data/spec/cli_spec.rb +0 -79
  40. data/spec/fixtures/.my-fancy-layouts-directory/sample-3.yml +0 -10
  41. data/spec/fixtures/.teamocil/sample-2.yml +0 -10
  42. data/spec/fixtures/.teamocil/sample.yml +0 -10
  43. data/spec/fixtures/layouts.yml +0 -76
  44. data/spec/layout_spec.rb +0 -229
  45. data/spec/mock/cli.rb +0 -35
  46. data/spec/mock/layout.rb +0 -16
  47. 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
@@ -1,3 +1,3 @@
1
1
  module Teamocil
2
- VERSION = "0.4.5"
2
+ VERSION = '1.0'
3
3
  end
data/teamocil.gemspec CHANGED
@@ -1,29 +1,28 @@
1
1
  # encoding: utf-8
2
2
 
3
- $:.push File.expand_path("../lib", __FILE__)
4
- require "teamocil/version"
3
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
4
+ require 'teamocil/version'
5
5
 
6
- spec = Gem::Specification.new do |s|
6
+ Gem::Specification.new do |s|
7
7
  # Metadata
8
- s.name = "teamocil"
8
+ s.name = 'teamocil'
9
9
  s.version = Teamocil::VERSION
10
10
  s.platform = Gem::Platform::RUBY
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."
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 = ["lib"]
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 "rake"
26
- s.add_development_dependency "rspec", '~> 2.13'
27
- s.add_development_dependency "yard"
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.5
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-18 00:00:00.000000000 Z
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: rspec
28
+ name: phare
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.13'
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: '2.13'
40
+ version: '0.6'
41
41
  - !ruby/object:Gem::Dependency
42
- name: yard
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/error.rb
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/layout/pane.rb
94
- - lib/teamocil/layout/session.rb
95
- - lib/teamocil/layout/window.rb
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: []
@@ -1,8 +0,0 @@
1
- windows:
2
- - name: simple-four-panes
3
- layout: tiled
4
- panes:
5
- - cmd: echo 'first pane'
6
- - cmd: echo 'second pane'
7
- - cmd: echo 'fourth pane'
8
- - cmd: echo 'third pane'
@@ -1,8 +0,0 @@
1
- windows:
2
- - name: simple-one-and-three-panes
3
- layout: main-vertical
4
- panes:
5
- - cmd: echo 'first pane'
6
- - cmd: echo 'second pane'
7
- - cmd: echo 'third pane'
8
- - cmd: echo 'fourth pane'
@@ -1,10 +0,0 @@
1
- windows:
2
- - name: simple-six-panes
3
- layout: tiled
4
- panes:
5
- - cmd: echo 'first pane'
6
- - cmd: echo 'second pane'
7
- - cmd: echo 'fourth pane'
8
- - cmd: echo 'third pane'
9
- - cmd: echo 'sixth pane'
10
- - cmd: echo 'fifth pane'
@@ -1,6 +0,0 @@
1
- windows:
2
- - name: simple-two-vertical-panes
3
- layout: even-horizontal
4
- panes:
5
- - cmd: echo 'first pane'
6
- - cmd: echo 'second pane'
@@ -1,6 +0,0 @@
1
- windows:
2
- - name: simple-two-horizontal-panes
3
- layout: even-vertical
4
- panes:
5
- - cmd: echo 'first pane'
6
- - cmd: echo 'second pane'
@@ -1,6 +0,0 @@
1
- module Teamocil
2
- module Error
3
- class StandardError < ::StandardError; end
4
- class LayoutError < StandardError; end
5
- end
6
- end
@@ -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