terminitor 0.4.1 → 0.5.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.
@@ -0,0 +1,83 @@
1
+ module Terminitor
2
+
3
+ class CurrentWindowsConsole
4
+ include Input
5
+ def send_command(cmd)
6
+ # puts "[current] #{cmd}"
7
+ type_in cmd
8
+ end
9
+ end
10
+
11
+
12
+
13
+ class WindowsConsole
14
+ include Windows::Process
15
+ include Windows::Handle
16
+ include Windows::Window
17
+ include Input
18
+
19
+ Windows::API.new('SetForegroundWindow', 'L', 'I', 'user32')
20
+
21
+ attr_accessor :name
22
+ attr_accessor :parameters
23
+ attr_accessor :title
24
+ attr_reader :pid
25
+ attr_reader :thread_id
26
+ attr_reader :hwnd
27
+
28
+ def initialize(options = {})
29
+ @name = options[:name] || name
30
+ @title = options[:title] || name
31
+ @parameters = options[:parameters]
32
+
33
+ start
34
+ end
35
+
36
+ def start
37
+ command_line = name
38
+ command_line = name + ' ' + parameters if parameters
39
+
40
+ # returns a struct, raises an error if fails
41
+ process_info = Process.create(
42
+ :command_line => command_line,
43
+ :close_handles => false,
44
+ :creation_flags => Process::CREATE_NEW_CONSOLE
45
+ )
46
+ @pid = process_info.process_id
47
+ @thread_id = process_info.thread_id
48
+ @process_handle = process_info.process_handle
49
+ @thread_handle = process_info.thread_handle
50
+
51
+ @pid
52
+ end
53
+
54
+ def kill!
55
+ CloseHandle(@process_handle)
56
+ CloseHandle(@thread_handle)
57
+
58
+ Process::kill(9, pid)
59
+ end
60
+
61
+ def find_window(process_id)
62
+ sleep 0.4 #todo - find a better way to wait for console to show up!!
63
+ child_after = 0
64
+ while (child_after = FindWindowEx(nil, child_after, nil, nil)) > 0 do
65
+ process_id = 0.chr * 4
66
+ GetWindowThreadProcessId(child_after, process_id)
67
+ process_id = process_id.unpack('L').first
68
+ return child_after if process_id == @pid
69
+ end
70
+
71
+
72
+ return nil
73
+ end
74
+
75
+ def send_command(cmd)
76
+ @hwnd ||= find_window(@thread_id)
77
+ SetForegroundWindow(@hwnd)
78
+ # puts "[#{@hwnd}] #{cmd}"
79
+ type_in(cmd)
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,117 @@
1
+ module Terminitor
2
+
3
+ # Terminator core for Terminitor.
4
+ #
5
+ # Since Terminator doesn't have a complete IPC interface,
6
+ # everything is done by using "xdotool" to simulate keypresses.
7
+ class TerminatorCore < AbstractCore
8
+ def initialize(path)
9
+ abort("xdotool required for Terminator support") if (@xdotool = `which xdotool`.chomp).empty?
10
+ super
11
+ end
12
+
13
+ def execute_command(cmd, options = {})
14
+ # add a cr to the end if missing
15
+ cmd += "\n" if (cmd =~ /\n\Z/).nil?
16
+ run_in_active_terminator cmd, options
17
+ true
18
+ end
19
+
20
+ def open_tab(options = nil)
21
+ send_keypress "ctrl+shift+t", options
22
+ end
23
+
24
+ def open_window(options = nil)
25
+ send_keypress "ctrl+shift+i", options
26
+ end
27
+
28
+ protected
29
+
30
+ # Run arbitrary command in active terminator window.
31
+ # abort()s if the active window is not a terminator window.
32
+ #
33
+ # @param cmd [String] command.
34
+ # @param options [Hash] options hash.
35
+ def run_in_active_terminator(cmd, options)
36
+ winid = window_id
37
+ type_in_window winid, cmd
38
+ end
39
+
40
+ # Send keypresses to active window.
41
+ #
42
+ # @param keys [String] keypresses in the form expected by xdotool.
43
+ # @param options [Hash] options hash from terminitor.
44
+ def send_keypress(keys, options)
45
+ winid = window_id
46
+ xdotool("key --window #{winid} #{keys}")
47
+ end
48
+
49
+ # Get the X11 window ID of the active terminator window.
50
+ #
51
+ # If the active window is not a terminator window, abort.
52
+ #
53
+ # @return [String] X11 window ID of active terminator window.
54
+ def window_id
55
+ active = get_active_window
56
+ if get_terminator_windows.include? active
57
+ return active
58
+ else
59
+ abort("not running in Terminator")
60
+ end
61
+ end
62
+
63
+ # Use xdotool to get the window id of the active window.
64
+ #
65
+ # @return [String] active X11 window ID.
66
+ def get_active_window
67
+ xdotool("getactivewindow").chomp
68
+ end
69
+
70
+ # Use xdotool to get the window IDs of all visible
71
+ # terminator windows.
72
+ #
73
+ # @return [Array] String array of terminator window IDs.
74
+ def get_terminator_windows
75
+ xdotool("search --onlyvisible --class terminator").split("\n")
76
+ end
77
+
78
+ # Focus window with given id.
79
+ #
80
+ # @param id [String] X11 window id.
81
+ def focus_window(id)
82
+ xdotool("windowfocus #{id}")
83
+ end
84
+
85
+ # Raise window with given id.
86
+ #
87
+ # @param id [String] X11 window id.
88
+ def raise_window(id)
89
+ xdotool("windowraise #{id}")
90
+ end
91
+
92
+ # Send arbitrary text to given window.
93
+ #
94
+ # @param winid [String] X11 window id.
95
+ # @param text [String] text to type.
96
+ def type_in_window(winid, text)
97
+ xdotool("type --window #{winid} \"#{text}\"")
98
+ end
99
+
100
+ # Run arbitrary xdotool commands.
101
+ #
102
+ # @param cmd [String] command as string.
103
+ # @return [String] result as string.
104
+ def xdotool(cmd)
105
+ execute("#{@xdotool} #{cmd}")
106
+ end
107
+
108
+ # Execute arbitrary command and return result string.
109
+ #
110
+ # @param cmd [String] command string.
111
+ # @return [String] result as string.
112
+ def execute(cmd)
113
+ IO.popen(cmd).read
114
+ end
115
+ end
116
+ end
117
+
@@ -2,6 +2,7 @@ module Terminitor
2
2
  # This class parses the Termfile to fit the new Ruby Dsl Syntax
3
3
  class Dsl
4
4
 
5
+ # @param [String] path to termfile
5
6
  def initialize(path)
6
7
  file = File.read(path)
7
8
  @setup = []
@@ -12,8 +13,11 @@ module Terminitor
12
13
 
13
14
  # Contains all commands that will be run prior to the usual 'workflow'
14
15
  # e.g bundle install, setup forks, etc ...
15
- # setup "bundle install", "brew update"
16
- # setup { run('bundle install') }
16
+ # @param [Array<String>] array of commands
17
+ # @param [Proc]
18
+ # @example
19
+ # setup "bundle install", "brew update"
20
+ # setup { run('bundle install') }
17
21
  def setup(*commands, &block)
18
22
  if block_given?
19
23
  in_context @setup, &block
@@ -23,8 +27,11 @@ module Terminitor
23
27
  end
24
28
 
25
29
  # sets command context to be run inside a specific window
26
- # window(:name => 'new window', :size => [80,30], :position => [9, 100]) { tab('ls','gitx') }
27
- # window { tab('ls', 'gitx') }
30
+ # @param [Hash] options hash.
31
+ # @param [Proc]
32
+ # @example
33
+ # window(:name => 'new window', :size => [80,30], :position => [9, 100]) { tab('ls','gitx') }
34
+ # window { tab('ls', 'gitx') }
28
35
  def window(options = {}, &block)
29
36
  window_name = "window#{@windows.keys.size}"
30
37
  window_contents = @windows[window_name] = {:tabs => {'default' => {:commands =>[]}}}
@@ -33,20 +40,26 @@ module Terminitor
33
40
  end
34
41
 
35
42
  # stores command in context
36
- # run 'brew update'
43
+ # @param [Array<String>] Array of commands
44
+ # @example
45
+ # run 'brew update'
37
46
  def run(*commands)
38
- if @_context.is_a?(Hash) && @_context[:tabs] # if we are in a window context, append commands to default tab.
47
+ # if we are in a window context, append commands to default tab.
48
+ if @_context.is_a?(Hash) && @_context[:tabs]
39
49
  current = @_context[:tabs]['default'][:commands]
40
50
  else
41
51
  current = @_context
42
52
  end
43
- current << commands.join(" && ")
53
+ current << commands.map { |c| "(#{c})" }.join(" && ")
44
54
  end
45
55
 
46
56
  # runs commands before each tab in window context
47
- # window do
48
- # before { run 'whoami' }
49
- # end
57
+ # @param [Array<String>] Array of commands
58
+ # @param [Proc]
59
+ # @example
60
+ # window do
61
+ # before { run 'whoami' }
62
+ # end
50
63
  def before(*commands, &block)
51
64
  @_context[:before] ||= []
52
65
  if block_given?
@@ -57,8 +70,11 @@ module Terminitor
57
70
  end
58
71
 
59
72
  # sets command context to be run inside specific tab
60
- # tab(:name => 'new tab', :settings => 'Grass') { run 'mate .' }
61
- # tab 'ls', 'gitx'
73
+ # @param [Array<String>] Array of commands
74
+ # @param [Proc]
75
+ # @example
76
+ # tab(:name => 'new tab', :settings => 'Grass') { run 'mate .' }
77
+ # tab 'ls', 'gitx'
62
78
  def tab(*args, &block)
63
79
  tabs = @_context[:tabs]
64
80
  tab_name = "tab#{tabs.keys.size}"
@@ -78,6 +94,7 @@ module Terminitor
78
94
  end
79
95
 
80
96
  # Returns yaml file as Terminitor formmatted hash
97
+ # @return [Hash] Return hash format of Termfile
81
98
  def to_hash
82
99
  { :setup => @setup, :windows => @windows }
83
100
  end
@@ -2,8 +2,13 @@ module Terminitor
2
2
  # This module contains all the helper methods for the Cli component.
3
3
  module Runner
4
4
 
5
+ # Terminitor Global Path
6
+ TERM_PATH = File.join(ENV['HOME'],'.config','terminitor')
7
+
5
8
  # Finds the appropriate platform core, else say you don't got it.
6
- # find_core RUBY_PLATFORM
9
+ # @param [String] the ruby platform
10
+ # @example
11
+ # find_core RUBY_PLATFORM
7
12
  def find_core(platform)
8
13
  core = case platform.downcase
9
14
  when %r{darwin} then
@@ -12,12 +17,20 @@ module Terminitor
12
17
  else
13
18
  Terminitor::MacCore
14
19
  end
15
- when %r{linux} then Terminitor::KonsoleCore # TODO check for gnome and others
20
+ when %r{linux} then
21
+ if not `which terminator`.chomp.empty?
22
+ Terminitor::TerminatorCore
23
+ else
24
+ Terminitor::KonsoleCore # TODO silly fallback, make better check
25
+ end
26
+ when %r{mswin|mingw} then
27
+ Terminitor::CmdCore
16
28
  else nil
17
29
  end
18
30
  end
19
31
 
20
32
  # Defines how to capture terminal settings on the specified platform
33
+ # @param [String] the ruby platform
21
34
  def capture_core(platform)
22
35
  core = case platform.downcase
23
36
  when %r{darwin} then
@@ -26,14 +39,22 @@ module Terminitor
26
39
  else
27
40
  Terminitor::MacCapture
28
41
  end
29
- when %r{linux} then Terminitor::KonsoleCapture # TODO check for gnome and others
42
+ when %r{linux} then
43
+ if not `which terminator`.chomp.empty?
44
+ Terminitor::TerminatorCapture
45
+ else
46
+ Terminitor::KonsoleCapture # TODO silly fallback, make better check
47
+ end
30
48
  else nil
31
49
  end
32
50
  end
33
51
 
34
52
  # Execute the core with the given method.
35
- # execute_core :process!, 'project'
36
- # execute_core :setup!, 'my_project'
53
+ # @param [Symbol] symbol of method
54
+ # @param [String] Termfile name
55
+ # @example
56
+ # execute_core :process!, 'project'
57
+ # execute_core :setup!, 'my_project'
37
58
  def execute_core(method, project)
38
59
  if path = resolve_path(project)
39
60
  core = find_core(RUBY_PLATFORM)
@@ -44,7 +65,10 @@ module Terminitor
44
65
  end
45
66
 
46
67
  # opens doc in system designated editor
47
- # open_in_editor '/path/to', 'nano'
68
+ # @param [String] path to termfile
69
+ # @param [String] editor
70
+ # @example
71
+ # open_in_editor '/path/to', 'nano'
48
72
  def open_in_editor(path, editor=nil)
49
73
  editor = editor || ENV['TERM_EDITOR'] || ENV['EDITOR']
50
74
  say "please set $EDITOR or $TERM_EDITOR in your .bash_profile." unless editor
@@ -52,7 +76,8 @@ module Terminitor
52
76
  end
53
77
 
54
78
  # returns path to file
55
- # resolve_path 'my_project'
79
+ # @param [String] Termfile name
80
+ # @example resolve_path 'my_project'
56
81
  def resolve_path(project)
57
82
  unless project.empty?
58
83
  path = config_path(project, :yml) # Give old yml path
@@ -68,26 +93,29 @@ module Terminitor
68
93
  end
69
94
 
70
95
  # returns first line of file
71
- # grab_comment_for_file '/path/to'
96
+ # @param [String] Termfile path
97
+ # @example grab_comment_for_file '/path/to'
72
98
  def grab_comment_for_file(file)
73
99
  first_line = File.readlines(file).first
74
100
  first_line =~ /^\s*?#/ ? ("-" + first_line.gsub("#","")) : "\n"
75
101
  end
76
102
 
77
103
  # Return file in config_path
78
- # config_path '/path/to', :term
104
+ # @param [String] Termfile path
105
+ # @param [Symbol] Type of file
106
+ # @example config_path '/path/to', :term
79
107
  def config_path(file, type = :yml)
80
108
  return File.join(options[:root],"Termfile") if file.empty?
81
- dir = File.join(ENV['HOME'],'.terminitor')
82
109
  if type == :yml
83
- File.join(dir, "#{file.sub(/\.yml$/, '')}.yml")
110
+ File.join(TERM_PATH, "#{file.sub(/\.yml$/, '')}.yml")
84
111
  else
85
- File.join(dir, "#{file.sub(/\.term$/, '')}.term")
112
+ File.join(TERM_PATH, "#{file.sub(/\.term$/, '')}.term")
86
113
  end
87
114
  end
88
115
 
89
116
  # Returns error message depending if project is specified
90
- # return_error_message 'hi
117
+ # @param [String] Termfile name
118
+ # @example return_error_message 'hi
91
119
  def return_error_message(project)
92
120
  unless project.empty?
93
121
  say "'#{project}' doesn't exist! Please run 'terminitor open #{project.gsub(/\..*/,'')}'"
@@ -99,6 +127,9 @@ module Terminitor
99
127
  # This will clone a repo in the current directory.
100
128
  # It will first try to clone via ssh(read/write),
101
129
  # if not fall back to git-read only, else, fail.
130
+ # @param [String] Github username
131
+ # @param [String] Github project name
132
+ # @example github_clone 'achiu', 'terminitor'
102
133
  def github_clone(username, project)
103
134
  github = `which github`
104
135
  return false if github.empty?
@@ -107,7 +138,10 @@ module Terminitor
107
138
  end
108
139
 
109
140
  # Fetch the git repo and run the setup block
110
- # fetch_repo 'achiu', 'terminitor', :setup => true
141
+ # @param [String] Github username
142
+ # @param [String] Github project
143
+ # @param [Hash] options hash
144
+ # @example fetch_repo 'achiu', 'terminitor', :setup => true
111
145
  def github_repo(username, project, options ={})
112
146
  if github_clone(username, project)
113
147
  path = File.join(Dir.pwd, project)
@@ -1,3 +1,3 @@
1
1
  module Terminitor
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -6,11 +6,13 @@ module Terminitor
6
6
  attr_accessor :file
7
7
 
8
8
  # Load in the Yaml file...
9
+ # @param [String] Path to termfile
9
10
  def initialize(path)
10
11
  @file = YAML.load File.read(path)
11
12
  end
12
13
 
13
14
  # Returns yaml file as Terminitor formmatted hash
15
+ # @return [Hash] Hash format of termfile
14
16
  def to_hash
15
17
  combined = @file.inject({}) do |base, item|
16
18
  item = {item.keys.first => {:commands => item.values.first, :options => {}}}