termup 2.0.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8702c31b85da161fafb1b949d630708e70502a61
4
+ data.tar.gz: 750ecb147eafa0f15e370dd9fb0116f0dcd3451d
5
+ SHA512:
6
+ metadata.gz: 95d9c08e02a3db81ecf7b6b220835b2a8271b889d501ff836b3f22181542547f554ad298f42fd6c2703779b0fb776728575b64e12d1a1b984b9437df19fdb87e
7
+ data.tar.gz: 06d58b6a0a0576dadde3cc187385bdf269a4ee48f191cc300279d32ef690c5e41711307a3deb5756a853d2b58a84f6e34017acb359d0a2821a233a8b615773cb
data/README.md CHANGED
@@ -5,11 +5,12 @@ Automate opening up terminal tabs (or split panes) with a set of routine command
5
5
 
6
6
  It's the easiest way to get started for your projects every day.
7
7
 
8
- Compatible with Terminal.app and iTerm 2 on Mac OS X 10.6 - 10.8 and Ruby 1.8.7 - 1.9.3.
8
+ Compatible with Terminal.app and iTerm2 v3 on OSX Yosemite or later.
9
9
 
10
10
  ![Split Panes](https://github.com/kenn/termup/raw/master/images/split_panes.png)
11
11
 
12
- **iTerm 1 users:** Termup 2.0 and up is not compatible with iTerm 1. Install 1.3.1 by `gem install termup -v=1.3.1`
12
+ **For iTerm2 v2 or earlier:** Termup 3.0 and up is not compatible with iTerm2 v2. Install Termup 2 by `gem install termup -v=2.0.3`
13
+ **For iTerm 1:** Termup 2.0 and up is not compatible with iTerm 1. Install 1.3.1 by `gem install termup -v=1.3.1`
13
14
 
14
15
  Installation
15
16
  ------------
@@ -20,6 +21,11 @@ $ gem install termup
20
21
 
21
22
  Note that you need to prepend `sudo` if you're using the OSX pre-installed Ruby.
22
23
 
24
+ Changelog
25
+ ---------
26
+
27
+ Termup v3.0 is a complete rewrite using the new JavaScript for Automation which was introduced with OSX Yosemite.
28
+
23
29
  Usage
24
30
  -----
25
31
 
@@ -20,6 +20,6 @@ tabs:
20
20
  commands:
21
21
  - echo pane4
22
22
  properties:
23
- foreground_color: yellow
24
- background_color: blue
23
+ foreground_color: [65535,0,0]
24
+ background_color: [0,0,65535]
25
25
  transparency: 0.1
@@ -1,5 +1,15 @@
1
+ require 'yaml'
2
+ require 'pathname'
3
+ require 'execjs/runtimes/jxa'
4
+
5
+ ExecJS.runtime = ExecJS::Runtimes::JXA
6
+
1
7
  module Termup
8
+ Dir = Pathname.new(ENV['HOME']).join('.config/termup')
9
+
2
10
  autoload :Base, 'termup/base'
3
11
  autoload :Cli, 'termup/cli'
4
- autoload :Handler, 'termup/handler'
12
+ autoload :Iterm, 'termup/iterm'
13
+ autoload :Process, 'termup/process'
14
+ autoload :Terminal, 'termup/terminal'
5
15
  end
@@ -1,90 +1,34 @@
1
- require 'yaml'
2
-
3
1
  module Termup
4
2
  class Base
5
- def initialize(project)
6
- @handler = Termup::Handler.new
7
-
8
- config = YAML.load(File.read("#{TERMUP_DIR}/#{project}.yml"))
9
- @tabs = config['tabs']
10
-
11
- # Config file compatibility checking
12
- if @tabs.is_a?(Array) and @tabs.first.is_a?(Hash)
13
- abort 'YAML syntax for config has been changed. See https://github.com/kenn/termup for details.'
14
- end
15
-
16
- @options = config['options'] || {}
17
- @iterm_options = @options['iterm']
18
-
19
- # Split panes for iTerm 2
20
- split_panes if @handler.iterm? and @iterm_options
21
-
22
- # Setting up tabs / panes
23
- @tabs.each_with_index do |(tabname, values), index|
24
- # Set tab title
25
- @handler.set_property(:name, tabname)
26
-
27
- # Run commands
28
- (advanced_iterm? ? values['commands'] : values).each do |command|
29
- @handler.run command
30
- end
31
-
32
- # Layout
33
- if advanced_iterm?
34
- values['properties'].each do |key, value|
35
- @handler.set_property(key, value)
36
- end if values['properties']
37
-
38
- values['layout'].each do |command|
39
- layout command
40
- end if values['layout']
41
- else
42
- # Move to next
43
- if @iterm_options
44
- layout :goto_next_pane
45
- else
46
- if index < @tabs.size - 1
47
- layout :new_tab
48
- sleep 0.01 # Allow some time to complete opening a new tab
49
- else
50
- layout :goto_next_tab # Back home
51
- end
52
- end
53
- end
54
- end
3
+ def initialize(project, process)
4
+ @config = YAML.load_file(Termup::Dir.join("#{project}.yml"))
5
+ @options = @config['options'] || {}
6
+ @tabs = @config['tabs'] || {}
7
+ @process = process
8
+ @lines = []
55
9
  end
56
10
 
57
- def split_panes
58
- width, height = @iterm_options['width'], @iterm_options['height']
59
- return unless width and height
60
-
61
- (width - 1).times do
62
- layout :split_vertically
63
- end
64
- layout :goto_next_pane # Back home
65
- width.times do
66
- (height - 1).times do
67
- layout :split_horizontally
68
- end
69
- layout :goto_next_pane # Move to next, or back home
70
- end
11
+ def start
12
+ script = <<-JS
13
+ var app = Application(#{@process.pid});
14
+ var se = Application('System Events');
15
+ app.activate();
16
+ #{@lines.join(';')}
17
+ JS
18
+ ExecJS.exec script
71
19
  end
72
20
 
73
- def advanced_iterm?
74
- unless defined?(@advanced_iterm)
75
- @advanced_iterm = case @tabs.values.first
76
- when Hash then true
77
- when Array then false
78
- else
79
- abort 'invalid YAML format'
80
- end
81
- abort 'advanced config only supported for iTerm' if @advanced_iterm and !@handler.iterm?
82
- end
83
- @advanced_iterm
84
- end
21
+ protected
85
22
 
86
- def layout(command)
87
- @handler.layout(command)
23
+ def hit(key, *using)
24
+ # activate
25
+ using = using.map{|i| i.to_s.gsub(/_/,' ') }
26
+ case key
27
+ when Integer
28
+ @lines << "se.keyCode(#{key}, { using: #{using} })"
29
+ when String
30
+ @lines << "se.keystroke('#{key}', { using: #{using} })"
31
+ end
88
32
  end
89
33
  end
90
34
  end
@@ -1,8 +1,6 @@
1
1
  require 'thor'
2
2
 
3
3
  module Termup
4
- TERMUP_DIR = File.join(ENV['HOME'],'.config','termup')
5
-
6
4
  class Cli < Thor
7
5
  include Thor::Actions
8
6
 
@@ -26,8 +24,8 @@ module Termup
26
24
 
27
25
  desc 'edit PROJECT', 'Edit termup project (Shortcut: e)'
28
26
  def edit(project)
29
- unless File.exists?(path(project))
30
- empty_directory TERMUP_DIR
27
+ unless path(project).exist?
28
+ empty_directory Termup::Dir
31
29
  if options['iterm_advanced']
32
30
  template 'templates/iterm_advanced.yml', path(project)
33
31
  elsif options['iterm_basic']
@@ -42,20 +40,25 @@ module Termup
42
40
 
43
41
  desc 'list', 'List termup projects (Shortcut: l)'
44
42
  def list
45
- projects = Dir["#{TERMUP_DIR}/*.yml"].map{|file| File.basename(file,'.yml') }
43
+ projects = Pathname.glob(Termup::Dir.join('*.yml')).map{|f| f.basename('.yml') }
46
44
  say "Your projects: #{projects.join(', ')}"
47
45
  end
48
46
 
49
47
  desc 'start PROJECT', 'Start termup project (Shortcut: s)'
50
48
  def start(project)
51
- say "project \"#{project}\" doesn't exist!" and return unless File.exists?(path(project))
52
- Termup::Base.new(project)
49
+ say "project \"#{project}\" doesn't exist!" and return unless path(project).exist?
50
+ process = Termup::Process.new
51
+ if process.iterm?
52
+ Termup::Iterm.new(project, process).start
53
+ else
54
+ Termup::Terminal.new(project, process).start
55
+ end
53
56
  end
54
57
 
55
58
  protected
56
59
 
57
60
  def path(project)
58
- "#{TERMUP_DIR}/#{project}.yml"
61
+ Termup::Dir.join("#{project}.yml")
59
62
  end
60
63
  end
61
64
  end
@@ -0,0 +1,96 @@
1
+ module Termup
2
+ class Iterm < Base
3
+ def start
4
+ split_panes if @options['iterm']
5
+
6
+ # Setting up tabs
7
+ @tabs.each.with_index do |(tabname, values), index|
8
+ set_property(:name, tabname) # Set tab title
9
+
10
+ if advanced_iterm?
11
+ values['commands'].each do |command|
12
+ run(command)
13
+ end
14
+
15
+ values['properties'].each do |key, value|
16
+ set_property(key, value)
17
+ end if values['properties']
18
+
19
+ values['layout'].each do |command|
20
+ layout command
21
+ end if values['layout']
22
+ else
23
+ values.each do |command|
24
+ run(command)
25
+ end
26
+
27
+ layout :goto_next_pane
28
+ end
29
+ end
30
+
31
+ super
32
+ end
33
+
34
+ private
35
+
36
+ def split_panes
37
+ width, height = @options['iterm']['width'], @options['iterm']['height']
38
+ return unless width && height
39
+
40
+ (width - 1).times do
41
+ layout :split_vertically
42
+ end
43
+ layout :goto_next_pane # Back home
44
+ width.times do
45
+ (height - 1).times do
46
+ layout :split_horizontally
47
+ end
48
+ layout :goto_next_pane # Move to next, or back home
49
+ end
50
+ end
51
+
52
+ def run(command)
53
+ @lines << "app.currentWindow().currentSession().write({'text':'#{command}'})"
54
+ end
55
+
56
+ def set_property(key, value)
57
+ value = value.inspect if value.is_a?(String)
58
+ @lines << "app.currentWindow().currentSession().#{camelize(key)}.set(#{value})"
59
+ end
60
+
61
+ def advanced_iterm?
62
+ unless defined?(@advanced_iterm)
63
+ @advanced_iterm = case @tabs.values.first
64
+ when Hash then true
65
+ when Array then false
66
+ else
67
+ abort 'invalid YAML format'
68
+ end
69
+ end
70
+ @advanced_iterm
71
+ end
72
+
73
+ def camelize(string)
74
+ string.to_s.split('_').map.with_index{|s,index| index.zero? ? s : s.slice(0).upcase + s.slice(1..-1) }.join
75
+ end
76
+
77
+ def layout(command)
78
+ case command.to_sym
79
+ when :new_tab then hit 't', :command_down
80
+ when :close_tab then hit 'w', :command_down
81
+ when :goto_previous_tab then hit '[', :command_down, :shift_down
82
+ when :goto_next_tab then hit ']', :command_down, :shift_down
83
+ when :goto_previous_pane then hit '[', :command_down
84
+ when :goto_next_pane then hit ']', :command_down
85
+ when :split_vertically then hit 'd', :command_down
86
+ when :split_horizontally then hit 'd', :command_down, :shift_down
87
+ when :go_left then hit 123, :command_down, :option_down
88
+ when :go_right then hit 124, :command_down, :option_down
89
+ when :go_down then hit 125, :command_down, :option_down
90
+ when :go_up then hit 126, :command_down, :option_down
91
+ else
92
+ abort "Unknown iTerm2.app command: #{command}"
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,40 @@
1
+ module Termup
2
+ class Process
3
+ attr_reader :pid
4
+
5
+ def initialize
6
+ lookup_pid
7
+ end
8
+
9
+ def terminal?
10
+ app_name == 'Terminal'
11
+ end
12
+
13
+ def iterm?
14
+ app_name == 'iTerm'
15
+ end
16
+
17
+ def app_name
18
+ @app_name ||= ExecJS.eval "Application(#{@pid}).name()"
19
+ end
20
+
21
+ def lookup_pid
22
+ pid = ::Process.ppid
23
+ pids = []
24
+
25
+ # Go up the process tree to find term-like process
26
+ while pid > 1 do
27
+ pids << pid if term_like_pids.include?(pid)
28
+ pid = `ps -p #{pid} -o ppid=`.strip.to_i
29
+ end
30
+
31
+ abort 'terminal pid not found!' if pids.empty?
32
+
33
+ @pid = pids.last
34
+ end
35
+
36
+ def term_like_pids
37
+ @term_like_pids ||= `ps x | grep Term`.split("\n").reject{|i| i =~ /grep/ }.map{|i| i.match(/\d+/).to_s.to_i }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ module Termup
2
+ class Terminal < Base
3
+ def start
4
+ # Setting up tabs / panes
5
+ @tabs.each.with_index do |(tabname, values), index|
6
+ values.each do |command|
7
+ @lines << "app.doScript('#{command}', { in: app.windows[0].tabs.last() })"
8
+ end
9
+
10
+ if index < @tabs.size - 1
11
+ layout :new_tab
12
+ sleep 0.01 # Allow some time to complete opening a new tab
13
+ else
14
+ layout :goto_next_tab # Back home
15
+ end
16
+ end
17
+
18
+ super
19
+ end
20
+
21
+ def layout(command)
22
+ case command.to_sym
23
+ when :new_tab then hit 't', :command_down
24
+ when :close_tab then hit 'w', :command_down
25
+ when :goto_previous_tab then hit '[', :command_down, :shift_down
26
+ when :goto_next_tab then hit ']', :command_down, :shift_down
27
+ else
28
+ abort "Unknown Terminal.app command: #{command}"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,3 @@
1
1
  module Termup
2
- VERSION = '2.0.3'
2
+ VERSION = '3.0.0'
3
3
  end
@@ -2,19 +2,19 @@
2
2
  require File.expand_path('../lib/termup/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
- gem.authors = ["Kenn Ejima"]
6
- gem.email = ["kenn.ejima@gmail.com"]
5
+ gem.authors = ['Kenn Ejima']
6
+ gem.email = ['kenn.ejima@gmail.com']
7
7
  gem.description = %q{Setup terminal tabs with preset commands for your projects}
8
8
  gem.summary = %q{Setup terminal tabs with preset commands for your projects}
9
- gem.homepage = "https://github.com/kenn/termup"
9
+ gem.homepage = 'https://github.com/kenn/termup'
10
10
 
11
11
  gem.files = `git ls-files`.split($\).reject{|f| f =~ /^images/ } # Exclude images
12
12
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
13
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
- gem.name = "termup"
15
- gem.require_paths = ["lib"]
14
+ gem.name = 'termup'
15
+ gem.require_paths = ['lib']
16
16
  gem.version = Termup::VERSION
17
17
 
18
- gem.add_runtime_dependency 'rb-appscript', '~> 0.6.1'
19
- gem.add_runtime_dependency 'thor', '~> 0.16.0'
18
+ gem.add_dependency 'execjs-runtimes-jxa', '~> 0.1'
19
+ gem.add_dependency 'thor', '~> 0.16'
20
20
  end
metadata CHANGED
@@ -1,48 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: termup
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
5
- prerelease:
4
+ version: 3.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Kenn Ejima
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-12-12 00:00:00.000000000 Z
11
+ date: 2016-06-13 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: rb-appscript
16
- prerelease: false
14
+ name: execjs-runtimes-jxa
17
15
  requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: 0.6.1
22
- none: false
19
+ version: '0.1'
23
20
  type: :runtime
21
+ prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
23
  requirements:
26
- - - ~>
24
+ - - "~>"
27
25
  - !ruby/object:Gem::Version
28
- version: 0.6.1
29
- none: false
26
+ version: '0.1'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: thor
32
- prerelease: false
33
29
  requirement: !ruby/object:Gem::Requirement
34
30
  requirements:
35
- - - ~>
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
- version: 0.16.0
38
- none: false
33
+ version: '0.16'
39
34
  type: :runtime
35
+ prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
37
  requirements:
42
- - - ~>
38
+ - - "~>"
43
39
  - !ruby/object:Gem::Version
44
- version: 0.16.0
45
- none: false
40
+ version: '0.16'
46
41
  description: Setup terminal tabs with preset commands for your projects
47
42
  email:
48
43
  - kenn.ejima@gmail.com
@@ -51,7 +46,7 @@ executables:
51
46
  extensions: []
52
47
  extra_rdoc_files: []
53
48
  files:
54
- - .gitignore
49
+ - ".gitignore"
55
50
  - Gemfile
56
51
  - LICENSE
57
52
  - README.md
@@ -63,32 +58,32 @@ files:
63
58
  - lib/termup.rb
64
59
  - lib/termup/base.rb
65
60
  - lib/termup/cli.rb
66
- - lib/termup/handler.rb
61
+ - lib/termup/iterm.rb
62
+ - lib/termup/process.rb
63
+ - lib/termup/terminal.rb
67
64
  - lib/termup/version.rb
68
65
  - termup.gemspec
69
66
  homepage: https://github.com/kenn/termup
70
67
  licenses: []
68
+ metadata: {}
71
69
  post_install_message:
72
70
  rdoc_options: []
73
71
  require_paths:
74
72
  - lib
75
73
  required_ruby_version: !ruby/object:Gem::Requirement
76
74
  requirements:
77
- - - ! '>='
75
+ - - ">="
78
76
  - !ruby/object:Gem::Version
79
77
  version: '0'
80
- none: false
81
78
  required_rubygems_version: !ruby/object:Gem::Requirement
82
79
  requirements:
83
- - - ! '>='
80
+ - - ">="
84
81
  - !ruby/object:Gem::Version
85
82
  version: '0'
86
- none: false
87
83
  requirements: []
88
84
  rubyforge_project:
89
- rubygems_version: 1.8.24
85
+ rubygems_version: 2.5.1
90
86
  signing_key:
91
- specification_version: 3
87
+ specification_version: 4
92
88
  summary: Setup terminal tabs with preset commands for your projects
93
89
  test_files: []
94
- has_rdoc:
@@ -1,111 +0,0 @@
1
- require 'appscript'
2
-
3
- module Termup
4
- class Handler
5
- def app(*args)
6
- Appscript.app(*args)
7
- end
8
-
9
- def run(command)
10
- if terminal?
11
- app_process.do_script(command, :in => app_process.windows[1].tabs.last.get)
12
- else
13
- app_process.current_terminal.current_session.write(:text => command)
14
- end
15
- end
16
-
17
- def set_property(key, value)
18
- if iterm?
19
- app_process.current_terminal.current_session.send(key).set(value)
20
- else
21
- # No-op for terminal for now
22
- end
23
- end
24
-
25
- def activate
26
- app_process.activate
27
- end
28
-
29
- def hit(key, *using)
30
- activate
31
- case key
32
- when Integer
33
- app('System Events').processes[app_name].key_code key, using && { :using => using }
34
- when String
35
- app('System Events').processes[app_name].keystroke key, using && { :using => using }
36
- end
37
- end
38
-
39
- def terminal?
40
- app_name == 'Terminal'
41
- end
42
-
43
- def iterm?
44
- app_name == 'iTerm'
45
- end
46
-
47
- def app_name
48
- @app_name ||= app_process.name.get
49
- end
50
-
51
- def app_process
52
- @app_process ||= app.by_pid(term_pid)
53
- end
54
-
55
- def term_pid
56
- return @term_pid if @term_pid
57
-
58
- pid = Process.ppid
59
-
60
- # Go up the process tree to find term-like process
61
- 100.times do
62
- ppid = `ps -p #{pid} -o ppid=`.strip.to_i
63
-
64
- abort 'terminal pid not found!' if ppid == 1
65
-
66
- if term_like_pids.include?(ppid)
67
- @term_pid = ppid
68
- break
69
- end
70
-
71
- pid = ppid
72
- end
73
-
74
- @term_pid
75
- end
76
-
77
- def term_like_pids
78
- @term_like_pids ||= `ps x | grep Term`.split("\n").reject{|i| i =~ /grep/ }.map{|i| i.match(/\d+/).to_s.to_i }
79
- end
80
-
81
- def layout(command)
82
- if iterm?
83
- case command.to_sym
84
- when :new_tab then hit 't', :command_down
85
- when :close_tab then hit 'w', :command_down
86
- when :goto_previous_tab then hit '[', :command_down, :shift_down
87
- when :goto_next_tab then hit ']', :command_down, :shift_down
88
- when :goto_previous_pane then hit '[', :command_down
89
- when :goto_next_pane then hit ']', :command_down
90
- when :split_vertically then hit 'd', :command_down
91
- when :split_horizontally then hit 'd', :command_down, :shift_down
92
- when :go_left then hit 123, :command_down, :option_down
93
- when :go_right then hit 124, :command_down, :option_down
94
- when :go_down then hit 125, :command_down, :option_down
95
- when :go_up then hit 126, :command_down, :option_down
96
- else
97
- abort "Unknown iTerm2.app command: #{command}"
98
- end
99
- else
100
- case command.to_sym
101
- when :new_tab then hit 't', :command_down
102
- when :close_tab then hit 'w', :command_down
103
- when :goto_previous_tab then hit '[', :command_down, :shift_down
104
- when :goto_next_tab then hit ']', :command_down, :shift_down
105
- else
106
- abort "Unknown Terminal.app command: #{command}"
107
- end
108
- end
109
- end
110
- end
111
- end