consular-gnome-terminal 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.
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +61 -0
- data/LICENSE.txt +674 -0
- data/README.rdoc +13 -0
- data/Rakefile +23 -0
- data/consular-gnome-terminal.gemspec +50 -0
- data/cucumber.yml +1 -0
- data/features/support/env.rb +18 -0
- data/lib/consular/gnome-terminal.rb +260 -0
- data/lib/consular/gnome-terminal/version.rb +16 -0
- data/spec/gnome-terminal_spec.rb +56 -0
- data/spec/spec_helper.rb +30 -0
- data/tests.watchr +151 -0
- metadata +210 -0
data/README.rdoc
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
= Terminator support for Consular
|
2
|
+
|
3
|
+
This gem is an add-on to Consular that implements support for the Terminator
|
4
|
+
terminal emulator on Linux.
|
5
|
+
|
6
|
+
Since Terminator does not have an API for controlling it, a commandline tool
|
7
|
+
called `xdotool` is used to send keyboard shortcuts to a running Terminator
|
8
|
+
in order to control it.
|
9
|
+
|
10
|
+
== Copyright
|
11
|
+
|
12
|
+
Copyright (c) 2011 Ilkka Laukkanen. See LICENSE.txt for further details.
|
13
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler::GemHelper.install_tasks
|
4
|
+
|
5
|
+
require 'rspec/core'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
8
|
+
t.pattern = 'spec/**/*_spec.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
RSpec::Core::RakeTask.new(:rcov) do |t|
|
12
|
+
t.pattern = 'spec/**/*_spec.rb'
|
13
|
+
t.rcov = true
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'cucumber/rake/task'
|
17
|
+
Cucumber::Rake::Task.new(:features)
|
18
|
+
|
19
|
+
require 'yard'
|
20
|
+
YARD::Rake::YardocTask.new
|
21
|
+
|
22
|
+
task :default => [:features, :spec]
|
23
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Gnome Terminal support for Consular
|
2
|
+
# Copyright (C) 2011 Jesse Cooke
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
$:.push File.expand_path("../lib", __FILE__)
|
18
|
+
require 'consular/gnome-terminal/version'
|
19
|
+
|
20
|
+
Gem::Specification.new do |s|
|
21
|
+
s.name = 'consular-gnome-terminal'
|
22
|
+
s.version = Consular::GnomeTerminal::VERSION
|
23
|
+
s.authors = ['Jesse Cooke']
|
24
|
+
s.email = [%q{jesse@jc00ke.com}]
|
25
|
+
s.homepage = %q{http://github.com/jc00ke/consular-gnome-terminal}
|
26
|
+
s.summary = %q{Gnome Terminal support for Consular}
|
27
|
+
s.licenses = ["GPLv3"]
|
28
|
+
s.description =
|
29
|
+
%q{Add support for automating the Gnome Terminal with Consular.}
|
30
|
+
|
31
|
+
s.files = `git ls-files`.split("\n")
|
32
|
+
s.test_files = `git ls-files -- test/* spec/* features/*`.split("\n")
|
33
|
+
|
34
|
+
s.extra_rdoc_files = [
|
35
|
+
'LICENSE.txt',
|
36
|
+
'README.rdoc'
|
37
|
+
]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
|
40
|
+
s.add_runtime_dependency('consular')
|
41
|
+
|
42
|
+
s.add_development_dependency('rake')
|
43
|
+
s.add_development_dependency('rspec')
|
44
|
+
s.add_development_dependency('yard')
|
45
|
+
s.add_development_dependency('cucumber')
|
46
|
+
s.add_development_dependency('spork')
|
47
|
+
s.add_development_dependency('watchr')
|
48
|
+
s.add_development_dependency('bundler')
|
49
|
+
s.add_development_dependency('mocha')
|
50
|
+
end
|
data/cucumber.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
default: --color --drb --port 8990
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spork'
|
2
|
+
|
3
|
+
Spork.prefork do
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rspec/expectations'
|
14
|
+
end
|
15
|
+
|
16
|
+
Spork.each_run do
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
require 'consular'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
module Consular
|
5
|
+
# Consular core for interacting with GnomeTerminal.
|
6
|
+
#
|
7
|
+
# Since we don't have any real API to work with and just send
|
8
|
+
# keypresses via XTEST, we don't have tab references either.
|
9
|
+
# Instead we just count tabs and return tab indexes.
|
10
|
+
#
|
11
|
+
# Adapted from http://github.com/ikka/consular-terminator
|
12
|
+
class GnomeTerminal < Core
|
13
|
+
|
14
|
+
Consular.add_core self
|
15
|
+
|
16
|
+
class << self
|
17
|
+
# Check to see if current system is valid for this core
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
def valid_system?
|
21
|
+
if (RbConfig::CONFIG['host_os'] =~ /linux/) != nil
|
22
|
+
if !(xdotool = `which xdotool`.chomp).empty?
|
23
|
+
begin
|
24
|
+
return File::Stat.new(xdotool).executable?
|
25
|
+
rescue
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
return false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Initialize
|
35
|
+
#
|
36
|
+
# @param [String] path
|
37
|
+
# path to Termfile.
|
38
|
+
#
|
39
|
+
# @api public
|
40
|
+
def initialize(path)
|
41
|
+
super
|
42
|
+
@tabidx = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Method called by runner to Execute Termfile setup.
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def setup!
|
49
|
+
@termfile[:setup].each { |cmd| execute_command(cmd, :in => active_window) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Method called by runner to execute Termfile.
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
def process!
|
56
|
+
windows = @termfile[:windows]
|
57
|
+
default = windows.delete('default')
|
58
|
+
execute_window(default, :default => true) unless default[:tabs].empty?
|
59
|
+
windows.each_pair { |_, cont| execute_window(cont) }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Executes the commands for each designated window.
|
63
|
+
# .run_windows will iterate through each of the tabs in
|
64
|
+
# sorted order to execute the tabs in the order they were set.
|
65
|
+
# The logic follows this:
|
66
|
+
#
|
67
|
+
# If the content is for the 'default' window,
|
68
|
+
# then use the current active window and generate the commands.
|
69
|
+
#
|
70
|
+
# If the content is for a new window,
|
71
|
+
# then generate a new window and activate the windows.
|
72
|
+
#
|
73
|
+
# Otherwise, open a new tab and execute the commands.
|
74
|
+
#
|
75
|
+
# @param [Hash] content
|
76
|
+
# The hash contents of the window from the Termfile.
|
77
|
+
# @param [Hash] options
|
78
|
+
# Addional options to pass. You can use:
|
79
|
+
# :default - Whether this is being run as the default window.
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# @core.execute_window contents, :default => true
|
83
|
+
# @core.execute_window contents, :default => true
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
def execute_window(content, options = {})
|
87
|
+
window_options = content[:options]
|
88
|
+
_contents = content[:tabs]
|
89
|
+
_first_run = true
|
90
|
+
|
91
|
+
_contents.keys.sort.each do |key|
|
92
|
+
_content = _contents[key]
|
93
|
+
_options = content[:options]
|
94
|
+
_name = options[:name]
|
95
|
+
|
96
|
+
_tab =
|
97
|
+
if _first_run && !options[:default]
|
98
|
+
open_window options.merge(window_options)
|
99
|
+
else
|
100
|
+
key == 'default' ? nil : open_tab(_options)
|
101
|
+
end
|
102
|
+
|
103
|
+
_first_run = false
|
104
|
+
commands = prepend_befores _content[:commands], _contents[:befores]
|
105
|
+
commands = set_title _name, commands
|
106
|
+
commands.each { |cmd| execute_command cmd, :in => _tab }
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
# Prepend a title setting command prior to the other commands.
|
112
|
+
#
|
113
|
+
# @param [String] title
|
114
|
+
# The title to set for the context of the commands.
|
115
|
+
# @param [Array<String>] commands
|
116
|
+
# The context of commands to preprend to.
|
117
|
+
#
|
118
|
+
# @api public
|
119
|
+
def set_title(title, commands)
|
120
|
+
cmd = "PS1=\"$PS1\\[\\e]2;#{title}\\a\\]\""
|
121
|
+
title ? commands.insert(0, cmd) : commands
|
122
|
+
end
|
123
|
+
|
124
|
+
# Prepends the :before commands to the current context's
|
125
|
+
# commands if it exists.
|
126
|
+
#
|
127
|
+
# @param [Array<String>] commands
|
128
|
+
# The current tab commands
|
129
|
+
# @param [Array<String>] befores
|
130
|
+
# The current window's :befores
|
131
|
+
#
|
132
|
+
# @return [Array<String>]
|
133
|
+
# The current context commands with the :before commands prepended
|
134
|
+
#
|
135
|
+
# @api public
|
136
|
+
def prepend_befores(commands, befores = nil)
|
137
|
+
unless befores.nil? || befores.empty?
|
138
|
+
commands.insert(0, befores).flatten!
|
139
|
+
else
|
140
|
+
commands
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Execute the given command in the context of the
|
145
|
+
# active window.
|
146
|
+
#
|
147
|
+
# @param [String] cmd
|
148
|
+
# The command to execute.
|
149
|
+
# @param [Hash] options
|
150
|
+
# Additional options to pass into appscript for the context.
|
151
|
+
#
|
152
|
+
# @example
|
153
|
+
# @osx.execute_command 'ps aux', :in => @tab_object
|
154
|
+
#
|
155
|
+
# @api public
|
156
|
+
def execute_command(cmd, options = {})
|
157
|
+
run_in_active_gnome_terminal cmd, options
|
158
|
+
end
|
159
|
+
|
160
|
+
# Opens a new tab and return the last instantiated tab(itself).
|
161
|
+
#
|
162
|
+
# @param [Hash] options
|
163
|
+
# Options to further customize the window. You can use:
|
164
|
+
# :settings -
|
165
|
+
# :selected -
|
166
|
+
#
|
167
|
+
# @return
|
168
|
+
# Returns a refernce to the last instantiated tab of the
|
169
|
+
# window.
|
170
|
+
#
|
171
|
+
# @api public
|
172
|
+
def open_tab(options = nil)
|
173
|
+
send_keypress(active_gnome_terminal_window, "ctrl+shift+t")
|
174
|
+
# FIXME: horribly hacky but can't come up with any way
|
175
|
+
# to truly make sure tab has opened.
|
176
|
+
sleep 1
|
177
|
+
end
|
178
|
+
|
179
|
+
# Opens a new window and returns its
|
180
|
+
# last instantiated tab.(The first 'tab' in the window).
|
181
|
+
#
|
182
|
+
# @param [Hash] options
|
183
|
+
# Options to further customize the window. You can use:
|
184
|
+
# :bound - Set the bounds of the windows
|
185
|
+
# :visible - Set whether or not the current window is visible
|
186
|
+
# :miniaturized - Set whether or not the window is minimized
|
187
|
+
#
|
188
|
+
# @return
|
189
|
+
# Returns a refernce to the last instantiated tab of the
|
190
|
+
# window.
|
191
|
+
#
|
192
|
+
# @api public
|
193
|
+
def open_window(options = nil)
|
194
|
+
windowid_before = active_gnome_terminal_window
|
195
|
+
send_keypress(active_gnome_terminal_window, "ctrl+shift+i")
|
196
|
+
# wait for the active window to change -> new window opened
|
197
|
+
while active_gnome_terminal_window == windowid_before
|
198
|
+
sleep 1
|
199
|
+
end
|
200
|
+
return (@tabidx = 0)
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
# Send keypresses to window winid
|
206
|
+
#
|
207
|
+
# @api private
|
208
|
+
def send_keypress(winid, keys)
|
209
|
+
xdotool("windowfocus #{winid}")
|
210
|
+
xdotool("key #{keys}")
|
211
|
+
end
|
212
|
+
|
213
|
+
# Run command with active gnome-terminal
|
214
|
+
#
|
215
|
+
# @api private
|
216
|
+
def run_in_active_gnome_terminal(cmd, options = {})
|
217
|
+
type_in_window(active_gnome_terminal_window, "#{cmd}\n")
|
218
|
+
end
|
219
|
+
|
220
|
+
# Get active gnome-terminal window winid.
|
221
|
+
# Gets the active window and returns it if it is
|
222
|
+
# a GnomeTerminal window. If it is not a gnome-terminal window,
|
223
|
+
# the method gets all gnome-terminal windows and returns the
|
224
|
+
# first one. If no gnome-terminal windows exist, aborts.
|
225
|
+
#
|
226
|
+
# @api private
|
227
|
+
def active_gnome_terminal_window
|
228
|
+
active = xdotool("getactivewindow").chomp
|
229
|
+
if not all_gnome_terminal_windows.include? active
|
230
|
+
active = all_gnome_terminal_windows.first
|
231
|
+
end
|
232
|
+
if not active
|
233
|
+
abort("No Gnome Terminal windows found")
|
234
|
+
end
|
235
|
+
return active
|
236
|
+
end
|
237
|
+
|
238
|
+
# Get window IDs of all gnome-terminal windows.
|
239
|
+
#
|
240
|
+
# @api private
|
241
|
+
def all_gnome_terminal_windows
|
242
|
+
xdotool("search --onlyvisible --class gnome-terminal").split("\n")
|
243
|
+
end
|
244
|
+
|
245
|
+
# Type text in window winid.
|
246
|
+
#
|
247
|
+
# @api private
|
248
|
+
def type_in_window(winid, text)
|
249
|
+
xdotool("windowfocus #{winid}")
|
250
|
+
xdotool("type \"#{text}\"")
|
251
|
+
end
|
252
|
+
|
253
|
+
# Execute xdotool with the given args and return output
|
254
|
+
#
|
255
|
+
# @api private
|
256
|
+
def xdotool(cmd)
|
257
|
+
IO.popen("xdotool #{cmd}").read
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'consular'
|
2
|
+
|
3
|
+
module Consular
|
4
|
+
class GnomeTerminal < Core
|
5
|
+
module Version
|
6
|
+
MAJOR = 0
|
7
|
+
MINOR = 1
|
8
|
+
PATCH = 0
|
9
|
+
BUILD = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
VERSION = [
|
13
|
+
Version::MAJOR, Version::MINOR, Version::PATCH, Version::BUILD
|
14
|
+
].compact.join('.')
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
describe Consular::GnomeTerminal do
|
5
|
+
it 'should be added as a core to Consular' do
|
6
|
+
Consular.cores.should include Consular::GnomeTerminal
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should treat linux as a valid system' do
|
10
|
+
RbConfig::CONFIG.expects(:[]).with('host_os').returns('x86-linux')
|
11
|
+
Consular::GnomeTerminal.expects(:`).with('which xdotool').returns('/usr/bin/xdotool')
|
12
|
+
stat = mock()
|
13
|
+
stat.expects(:executable?).returns(true)
|
14
|
+
File::Stat.expects(:new).returns(stat)
|
15
|
+
Consular::GnomeTerminal.valid_system?.should == true
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should treat non-linux as an invalid system' do
|
19
|
+
RbConfig::CONFIG.expects(:[]).with('host_os').returns('darwin')
|
20
|
+
Consular::GnomeTerminal.valid_system?.should == false
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should treat systems without "which" as invalid' do
|
24
|
+
RbConfig::CONFIG.expects(:[]).with('host_os').returns('x86-linux')
|
25
|
+
Consular::GnomeTerminal.expects(:`).with('which xdotool').returns('which: command not found')
|
26
|
+
File::Stat.expects(:new).throws('no such file')
|
27
|
+
Consular::GnomeTerminal.valid_system?.should == false
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should treat systems without "xdotool" as invalid' do
|
31
|
+
RbConfig::CONFIG.expects(:[]).with('host_os').returns('x86-linux')
|
32
|
+
Consular::GnomeTerminal.expects(:`).with('which xdotool').returns('')
|
33
|
+
File::Stat.expects(:new).throws('no such file')
|
34
|
+
Consular::GnomeTerminal.valid_system?.should == false
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should send ctrl+shift+i when creating new window' do
|
38
|
+
f = EmptyTermfile.new
|
39
|
+
core = Consular::GnomeTerminal.new f.path
|
40
|
+
core.expects(:active_gnome_terminal_window).once.returns(1)
|
41
|
+
core.expects(:active_gnome_terminal_window).once.returns(1)
|
42
|
+
core.expects(:xdotool).with("windowfocus 1")
|
43
|
+
core.expects(:xdotool).with("key ctrl+shift+i")
|
44
|
+
core.expects(:active_gnome_terminal_window).once.returns(2)
|
45
|
+
core.open_window
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should send ctrl+shift+t when creating new tab' do
|
49
|
+
f = EmptyTermfile.new
|
50
|
+
core = Consular::GnomeTerminal.new f.path
|
51
|
+
core.expects(:active_gnome_terminal_window).returns(1)
|
52
|
+
core.expects(:xdotool).with("windowfocus 1")
|
53
|
+
core.expects(:xdotool).with("key ctrl+shift+t")
|
54
|
+
core.open_tab
|
55
|
+
end
|
56
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spork'
|
2
|
+
|
3
|
+
Spork.prefork do
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
require 'rspec'
|
7
|
+
require 'mocha'
|
8
|
+
|
9
|
+
# Requires supporting files with custom matchers and macros, etc,
|
10
|
+
# in ./support/ and its subdirectories.
|
11
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'tempfile'
|
17
|
+
|
18
|
+
class EmptyTermfile < Tempfile
|
19
|
+
def initialize
|
20
|
+
super('consular')
|
21
|
+
write(%q(setup "echo 'setup'"))
|
22
|
+
rewind
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Spork.each_run do
|
28
|
+
require 'consular/gnome-terminal'
|
29
|
+
end
|
30
|
+
|