consular-iterm 1.0.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 +4 -0
- data/Gemfile +4 -0
- data/README.md +81 -0
- data/Rakefile +9 -0
- data/consular-iterm.gemspec +27 -0
- data/lib/consular/iterm.rb +333 -0
- data/lib/consular/iterm_dsl.rb +40 -0
- data/spec.watchr +67 -0
- data/spec/fixtures/bar.term +27 -0
- data/spec/iterm_dsl_spec.rb +58 -0
- data/spec/iterm_spec.rb +31 -0
- data/spec/spec_helper.rb +33 -0
- metadata +83 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Consular - iTerm Core
|
2
|
+
|
3
|
+
Automate your iTerm Terminal with Consular
|
4
|
+
|
5
|
+
|
6
|
+
# Setup && Installation
|
7
|
+
|
8
|
+
If you haven't already, install Consular:
|
9
|
+
|
10
|
+
gem install consular
|
11
|
+
|
12
|
+
then install consular-iterm:
|
13
|
+
|
14
|
+
gem install consular-iterm
|
15
|
+
|
16
|
+
|
17
|
+
next, run `init`:
|
18
|
+
|
19
|
+
consular init
|
20
|
+
|
21
|
+
This will generate a global directory and also a `.consularc` in your home
|
22
|
+
directory. On the top of your `.consularc`, just require this core like
|
23
|
+
so:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# You can require your additional core gems here.
|
27
|
+
require 'consular/osx'
|
28
|
+
|
29
|
+
# You can set specific Consular configurations
|
30
|
+
# here.
|
31
|
+
Consular.configure do |c|
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
|
36
|
+
## Additional Features
|
37
|
+
|
38
|
+
With `consular-iterm`, you can also genrate `panes` likes so:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
pane do
|
42
|
+
run "top"
|
43
|
+
pane "ps"
|
44
|
+
end
|
45
|
+
|
46
|
+
window do
|
47
|
+
pane "gitx"
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
Splitting tabs into panes works as follows:
|
52
|
+
|
53
|
+
tab do
|
54
|
+
pane "gitx" # first pane
|
55
|
+
pane do # second pane level => horizontal split
|
56
|
+
run "irb"
|
57
|
+
end
|
58
|
+
pane 'ls' # first pane level => vertical split
|
59
|
+
end
|
60
|
+
|
61
|
+
should result into something like this:
|
62
|
+
|
63
|
+
# ###########################
|
64
|
+
# # # #
|
65
|
+
# # # #
|
66
|
+
# # 'gitx' # #
|
67
|
+
# # # #
|
68
|
+
# # # #
|
69
|
+
# ############## 'ls' #
|
70
|
+
# # # #
|
71
|
+
# # # #
|
72
|
+
# # 'irb' # #
|
73
|
+
# # # #
|
74
|
+
# # # #
|
75
|
+
# ###########################
|
76
|
+
|
77
|
+
It is not possible to split the second level panes (the horizontal ones).
|
78
|
+
Nevertheless you should be able to split tabs into any kind of pane pattern you wish
|
79
|
+
with this syntax.
|
80
|
+
|
81
|
+
Now you can use iTerm Terminal to run your Consular scripts!
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "consular-iterm"
|
6
|
+
s.version = "1.0.0"
|
7
|
+
s.authors = ["Arthur Chiu"]
|
8
|
+
s.email = ["mr.arthur.chiu@gmail.com"]
|
9
|
+
s.homepage = "http://www.github.com/achiu/consular-iterm"
|
10
|
+
s.summary = %q{Automate your ITerm with Consular}
|
11
|
+
s.description = %q{Terminal Automation for ITerm via Consular}
|
12
|
+
|
13
|
+
s.rubyforge_project = "consular-iterm"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency 'consular'
|
21
|
+
|
22
|
+
s.add_development_dependency 'minitest'
|
23
|
+
|
24
|
+
# specify any dependencies here; for example:
|
25
|
+
# s.add_development_dependency "rspec"
|
26
|
+
# s.add_runtime_dependency "rest-client"
|
27
|
+
end
|
@@ -0,0 +1,333 @@
|
|
1
|
+
require 'consular'
|
2
|
+
require 'appscript'
|
3
|
+
require File.expand_path('../iterm_dsl', __FILE__)
|
4
|
+
|
5
|
+
module Consular
|
6
|
+
|
7
|
+
# Consular Core to interact with iTerm2 for Mac OS X
|
8
|
+
#
|
9
|
+
class ITerm < Core
|
10
|
+
include Appscript
|
11
|
+
|
12
|
+
Consular.add_core self
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
# Checks to see if the current system is darwin and
|
17
|
+
# if $TERM_PROGRAM is iTerm.app
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
def valid_system?
|
21
|
+
(RUBY_PLATFORM.downcase =~ /darwin/) && ENV['TERM_PROGRAM'] == 'iTerm.app'
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the name of Core. Used in CLI core selection.
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
def to_s
|
28
|
+
"Consular::ITerm Mac OSX iTerm2"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
# Initializes a reference to the iTerm.app via appscript
|
34
|
+
#
|
35
|
+
# @param [String] path
|
36
|
+
# Path to Termfile
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def initialize(path)
|
40
|
+
super
|
41
|
+
@terminal = app('iTerm')
|
42
|
+
end
|
43
|
+
|
44
|
+
# Method called by runner to Execute Termfile setup.
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def setup!
|
48
|
+
@termfile[:setup].each { |cmd| execute_command(cmd) }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Method called by runner to execute Termfile.
|
52
|
+
#
|
53
|
+
# @api public
|
54
|
+
def process!
|
55
|
+
windows = @termfile[:windows]
|
56
|
+
default = windows.delete('default')
|
57
|
+
execute_window(default, :default => true) unless default[:tabs].empty?
|
58
|
+
windows.each_pair { |_, cont| execute_window(cont) }
|
59
|
+
end
|
60
|
+
|
61
|
+
# Prepends the :before commands to the current context's
|
62
|
+
# commands if it exists.
|
63
|
+
#
|
64
|
+
# @param [Array<String>] commands
|
65
|
+
# The current tab commands
|
66
|
+
# @param [Array<String>] befores
|
67
|
+
# The current window's :befores
|
68
|
+
#
|
69
|
+
# @return [Array<String>]
|
70
|
+
# The current context commands with the :before commands prepended
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def prepend_befores(commands, befores = nil)
|
74
|
+
unless befores.nil? || befores.empty?
|
75
|
+
commands.insert(0, befores).flatten!
|
76
|
+
else
|
77
|
+
commands
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Prepend a title setting command prior to the other commands.
|
82
|
+
#
|
83
|
+
# @param [String] title
|
84
|
+
# The title to set for the context of the commands.
|
85
|
+
# @param [Array<String>] commands
|
86
|
+
# The context of commands to preprend to.
|
87
|
+
#
|
88
|
+
# @api public
|
89
|
+
def set_title(title, commands)
|
90
|
+
cmd = "PS1=\"$PS1\\[\\e]2;#{title}\\a\\]\""
|
91
|
+
title ? commands.insert(0, cmd) : commands
|
92
|
+
end
|
93
|
+
|
94
|
+
# Executes the commands for each designated window.
|
95
|
+
# .run_windows will iterate through each of the tabs in
|
96
|
+
# sorted order to execute the tabs in the order they were set.
|
97
|
+
# The logic follows this:
|
98
|
+
#
|
99
|
+
# If the content is for the 'default' window,
|
100
|
+
# then use the current active window and generate the commands.
|
101
|
+
#
|
102
|
+
# If the content is for a new window,
|
103
|
+
# then generate a new window and activate the windows.
|
104
|
+
#
|
105
|
+
# Otherwise, open a new tab and execute the commands.
|
106
|
+
#
|
107
|
+
# @param [Hash] content
|
108
|
+
# The hash contents of the window from the Termfile.
|
109
|
+
# @param [Hash] options
|
110
|
+
# Addional options to pass. You can use:
|
111
|
+
# :default - Whether this is being run as the default window.
|
112
|
+
#
|
113
|
+
# @example
|
114
|
+
# @core.execute_window contents, :default => true
|
115
|
+
# @core.execute_window contents, :default => true
|
116
|
+
#
|
117
|
+
# @api public
|
118
|
+
def execute_window(content, options = {})
|
119
|
+
window_options = content[:options]
|
120
|
+
_contents = content[:tabs]
|
121
|
+
_first_run = true
|
122
|
+
|
123
|
+
_contents.keys.sort.each do |key|
|
124
|
+
_content = _contents[key]
|
125
|
+
_options = content[:options]
|
126
|
+
_name = options[:name]
|
127
|
+
|
128
|
+
_tab =
|
129
|
+
if _first_run && !options[:default]
|
130
|
+
open_window options.merge(window_options)
|
131
|
+
else
|
132
|
+
key == 'default' ? active_tab : open_tab(_options) && active_tab
|
133
|
+
end
|
134
|
+
|
135
|
+
_first_run = false
|
136
|
+
commands = prepend_befores _content[:commands], content[:before]
|
137
|
+
commands = set_title _name, commands
|
138
|
+
|
139
|
+
if content.key? :panes
|
140
|
+
commands.each { |cmd| execute_command cmd, :in => _tab }
|
141
|
+
execute_panes content
|
142
|
+
content.delete :panes
|
143
|
+
else
|
144
|
+
commands.each { |cmd| execute_command cmd, :in => _tab }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Execute the tab and associated panes with the designated content
|
150
|
+
#
|
151
|
+
# @param [Hash] content
|
152
|
+
# The Context containing panes.
|
153
|
+
#
|
154
|
+
# @api public
|
155
|
+
def execute_panes(content)
|
156
|
+
panes = content[:panes]
|
157
|
+
commands = content[:tabs][:commands]
|
158
|
+
top_level_pane_split panes, commands
|
159
|
+
end
|
160
|
+
|
161
|
+
# Execute commands in the context of a top level pane
|
162
|
+
#
|
163
|
+
# @param [Hash] panes
|
164
|
+
# Pane contexts.
|
165
|
+
# @param [Array] commands
|
166
|
+
# Current context tab commands.
|
167
|
+
#
|
168
|
+
# @api public
|
169
|
+
def top_level_pane_split(panes, commands)
|
170
|
+
first_pane = true
|
171
|
+
|
172
|
+
panes.keys.sort.each do |pane_key|
|
173
|
+
pane_content = panes[pane_key]
|
174
|
+
pane_commands = pane_content[:commands]
|
175
|
+
|
176
|
+
vertical_split if first_pane
|
177
|
+
execute_pane_commands(pane_commands,commands)
|
178
|
+
|
179
|
+
if pane_content.key?(:panes)
|
180
|
+
select_pane('Left') if first_pane
|
181
|
+
execute_subpanes pane_content[:panes], commands
|
182
|
+
pane_content.delete :panes
|
183
|
+
end
|
184
|
+
|
185
|
+
first_pane = false if first_pane
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
# Execute commands in the context of sub panes
|
191
|
+
#
|
192
|
+
# @param [Array] subpanes
|
193
|
+
# Sub panes for the top level pane
|
194
|
+
# @param [Array] tabcommands
|
195
|
+
# Tab commands
|
196
|
+
#
|
197
|
+
# @api public
|
198
|
+
def execute_subpanes(subpanes, tab_commands)
|
199
|
+
subpanes.keys.sort.each do |subpane_key|
|
200
|
+
subpane_commands = subpanes[subpane_key][:commands]
|
201
|
+
horizontal_split
|
202
|
+
execute_pane_commands(subpane_commands, tab_commands)
|
203
|
+
select_pane 'Right'
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Execute the commands within a pane
|
208
|
+
#
|
209
|
+
# @param [Array] pane_commands
|
210
|
+
# Commands for the designated pane.
|
211
|
+
# @param [Array] tab_commands
|
212
|
+
# Commands for the designated tabs.
|
213
|
+
#
|
214
|
+
# @api public
|
215
|
+
def execute_pane_commands(pane_commands, tab_commands)
|
216
|
+
pane_commands = (tab_commands || []) + (pane_commands || [])
|
217
|
+
pane_commands.each { |cmd| execute_command cmd }
|
218
|
+
end
|
219
|
+
|
220
|
+
# Split the active tab with vertical panes
|
221
|
+
#
|
222
|
+
# @api public
|
223
|
+
def vertical_split
|
224
|
+
call_ui_action "Shell", nil, "Split Vertically with Current Profile"
|
225
|
+
end
|
226
|
+
|
227
|
+
# Split the active tab with horizontal panes
|
228
|
+
#
|
229
|
+
# @api public
|
230
|
+
def horizontal_split
|
231
|
+
call_ui_action "Shell", nil, "Split Horizontally with Current Profile"
|
232
|
+
end
|
233
|
+
|
234
|
+
# to select panes; iTerm's Appscript select method does not work
|
235
|
+
# as expected, we have to select via menu instead
|
236
|
+
#
|
237
|
+
# @param [String] direction
|
238
|
+
# Direction to split the pane. The valid directions are:
|
239
|
+
# 'Above', 'Below', 'Left', 'Right'
|
240
|
+
#
|
241
|
+
# @api public
|
242
|
+
def select_pane(direction)
|
243
|
+
valid_directions = %w[Above Below Left Right]
|
244
|
+
if valid_directions.include?(direction)
|
245
|
+
call_ui_action("Window", "Select Split Pane", "Select Pane #{direction}")
|
246
|
+
else
|
247
|
+
puts "Error: #{direction} is not a valid direction to select a pane; Only Above/Below/Left/Right are valid directions"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
# Opens a new tab and focuses on it.
|
253
|
+
#
|
254
|
+
# @param [Hash] options
|
255
|
+
# Additional options to further customize the tab.
|
256
|
+
#
|
257
|
+
# @api public
|
258
|
+
def open_tab(options = nil)
|
259
|
+
active_window.launch_ :session => 'New session'
|
260
|
+
end
|
261
|
+
|
262
|
+
# Opens a new window and focuses
|
263
|
+
# on the new tab.
|
264
|
+
#
|
265
|
+
# @param [Hash] options
|
266
|
+
# Additional options to further customize the window.
|
267
|
+
#
|
268
|
+
# @api public
|
269
|
+
def open_window(options = nil)
|
270
|
+
window = @terminal.make :new => :terminal
|
271
|
+
window.launch_ :session => 'New session'
|
272
|
+
end
|
273
|
+
|
274
|
+
# Execute the given command in the context of the active window.
|
275
|
+
#
|
276
|
+
# @param [String] cmd
|
277
|
+
# The command to execute.
|
278
|
+
# @param [Hash] options
|
279
|
+
# Additional options to pass into appscript for the context.
|
280
|
+
#
|
281
|
+
# @example
|
282
|
+
# @osx.execute_command 'ps aux', :in => @tab_object
|
283
|
+
#
|
284
|
+
# @api public
|
285
|
+
def execute_command(cmd, options = {})
|
286
|
+
context = options[:in] || active_tab
|
287
|
+
context.write :text => cmd
|
288
|
+
end
|
289
|
+
|
290
|
+
# Returns the active tab e.g the active terminal session.
|
291
|
+
#
|
292
|
+
# @api public
|
293
|
+
def active_tab
|
294
|
+
active_window.current_session
|
295
|
+
end
|
296
|
+
|
297
|
+
# Returns the active window/tab e.g the active terminal window.
|
298
|
+
#
|
299
|
+
# @api public
|
300
|
+
def active_window
|
301
|
+
@terminal.current_terminal
|
302
|
+
end
|
303
|
+
|
304
|
+
# Returns a reference to the iTerm menu bar.
|
305
|
+
#
|
306
|
+
# @api public
|
307
|
+
def iterm_menu
|
308
|
+
_process = app("System Events").processes["iTerm"]
|
309
|
+
_process.menu_bars.first
|
310
|
+
end
|
311
|
+
|
312
|
+
# Execute the menu action via UI.
|
313
|
+
#
|
314
|
+
# @param [String] menu
|
315
|
+
# Top level menu name
|
316
|
+
# @param [String] submenu
|
317
|
+
# Sub level menu name
|
318
|
+
# @param [String] action
|
319
|
+
# Action name/description.
|
320
|
+
#
|
321
|
+
# @example
|
322
|
+
# @core.call_ui_action 'Edit', 'Find', 'Find Next'
|
323
|
+
# @core.call_ui_action 'Shell', nil, 'Split Vertically With Same Profile'
|
324
|
+
#
|
325
|
+
# @api public
|
326
|
+
def call_ui_action(menu, submenu, action)
|
327
|
+
menu = iterm_menu.menu_bar_items[menu].menus[menu]
|
328
|
+
menu = menu.menu_items[submenu].menus[submenu] if submenu
|
329
|
+
menu.menu_items[action].click
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Consular
|
2
|
+
module ITermDSL
|
3
|
+
|
4
|
+
# Generates a pane in the terminal. These can be nested to
|
5
|
+
# create horizontal panes. Vertical panes are created with each top
|
6
|
+
# level nest.
|
7
|
+
#
|
8
|
+
# @param [Array<String>] args
|
9
|
+
# Array of comamnds
|
10
|
+
# @param [Proc] block
|
11
|
+
# Block of code to execute in pane context.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# pane "top"
|
16
|
+
# pane { pane "uptime" }
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
def pane(*args, &block)
|
20
|
+
@_context[:panes] = {} unless @_context.has_key? :panes
|
21
|
+
panes = @_context[:panes]
|
22
|
+
pane_name = "pane#{panes.keys.size}"
|
23
|
+
|
24
|
+
if block_given?
|
25
|
+
pane_contents = panes[pane_name] = {:commands => []}
|
26
|
+
if @_context.has_key? :is_top_pane
|
27
|
+
run_context pane_contents[:commands], &block
|
28
|
+
else
|
29
|
+
pane_contents[:is_top_pane] = true
|
30
|
+
run_context pane_contents, &block
|
31
|
+
end
|
32
|
+
else
|
33
|
+
panes[pane_name] = { :commands => args }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Consular::DSL.class_eval { include Consular::ITermDSL }
|
data/spec.watchr
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
ENV["WATCHR"] = "1"
|
2
|
+
system 'clear'
|
3
|
+
|
4
|
+
def growl(message)
|
5
|
+
growlnotify = `which growlnotify`.chomp
|
6
|
+
if not growlnotify.empty?
|
7
|
+
title = "Watchr Test Results"
|
8
|
+
image = message.include?('0 failures, 0 errors') ? "~/.watchr_images/passed.png" : "~/.watchr_images/failed.png"
|
9
|
+
options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
|
10
|
+
system %(#{growlnotify} #{options} &)
|
11
|
+
else
|
12
|
+
puts message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def run(cmd)
|
17
|
+
puts(cmd)
|
18
|
+
`#{cmd}`
|
19
|
+
end
|
20
|
+
|
21
|
+
def run_test_file(file)
|
22
|
+
system('clear')
|
23
|
+
result = run(%Q(ruby -I"lib:test" -rubygems #{file}))
|
24
|
+
growl result.split("\n").last rescue nil
|
25
|
+
puts result
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_all_tests
|
29
|
+
system('clear')
|
30
|
+
result = run "rake spec"
|
31
|
+
growl result.split("\n").last rescue nil
|
32
|
+
puts result
|
33
|
+
end
|
34
|
+
|
35
|
+
def related_test_files(path)
|
36
|
+
Dir['spec/**/*.rb'].select { |file| file =~ /#{File.basename(path).split(".").first}_spec.rb/ }
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_suite
|
40
|
+
run_all_tests
|
41
|
+
end
|
42
|
+
|
43
|
+
watch('spec/spec_helper\.rb') { run_all_tests }
|
44
|
+
watch('spec/(.*).*_spec\.rb') { |m| run_test_file(m[0]) }
|
45
|
+
watch('lib/.*/.*\.rb') { |m| related_test_files(m[0]).map {|tf| run_test_file(tf) } }
|
46
|
+
|
47
|
+
# Ctrl-\
|
48
|
+
Signal.trap 'QUIT' do
|
49
|
+
puts " --- Running all tests ---\n\n"
|
50
|
+
run_all_tests
|
51
|
+
end
|
52
|
+
|
53
|
+
@interrupted = false
|
54
|
+
|
55
|
+
# Ctrl-C
|
56
|
+
Signal.trap 'INT' do
|
57
|
+
if @interrupted then
|
58
|
+
@wants_to_quit = true
|
59
|
+
abort("\n")
|
60
|
+
else
|
61
|
+
puts "Interrupt a second time to quit"
|
62
|
+
@interrupted = true
|
63
|
+
Kernel.sleep 1.5
|
64
|
+
# raise Interrupt, nil # let the run loop catch it
|
65
|
+
run_suite
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
pane "top"
|
2
|
+
|
3
|
+
window do
|
4
|
+
pane do
|
5
|
+
run "ls"
|
6
|
+
pane "uptime"
|
7
|
+
end
|
8
|
+
|
9
|
+
pane "ps"
|
10
|
+
run "default"
|
11
|
+
tab "echo"
|
12
|
+
|
13
|
+
pane "test"
|
14
|
+
end
|
15
|
+
|
16
|
+
window do
|
17
|
+
run 'tab1'
|
18
|
+
|
19
|
+
pane "second window"
|
20
|
+
|
21
|
+
pane do
|
22
|
+
run "second pane"
|
23
|
+
pane "third pane"
|
24
|
+
end
|
25
|
+
|
26
|
+
tab "tab2"
|
27
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Consular::ITermDSL do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@dsl = Consular::DSL.new File.expand_path('../fixtures/bar.term', __FILE__)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "includes itself into Consular::DSL" do
|
10
|
+
assert_includes Consular::DSL.included_modules, Consular::ITermDSL
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".to_hash" do
|
14
|
+
before do
|
15
|
+
@result = @dsl.to_hash
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns the default window pane" do
|
19
|
+
assert_equal ['top'], @result[:windows]['default'][:panes]['pane0'][:commands]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns the first window first panes" do
|
23
|
+
@window1 = @result[:windows]['window1']
|
24
|
+
|
25
|
+
assert @window1[:panes]['pane0'][:is_top_pane], "that this is marked as top most pane"
|
26
|
+
assert_equal ['ls'], @window1[:panes]['pane0'][:commands]
|
27
|
+
assert_equal ['uptime'], @window1[:panes]['pane0'][:panes]['pane0'][:commands]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns the first window's second pane" do
|
31
|
+
@window1 = @result[:windows]['window1']
|
32
|
+
assert_equal ['ps'], @window1[:panes]['pane1'][:commands]
|
33
|
+
assert_equal ['test'], @window1[:panes]['pane2'][:commands]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "still returns tabs correctly" do
|
37
|
+
@window1 = @result[:windows]['window1']
|
38
|
+
|
39
|
+
assert_equal ['echo'], @window1[:tabs]['tab1'][:commands]
|
40
|
+
assert_equal ['default'], @window1[:tabs]['default'][:commands]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "still returns multiple windows" do
|
44
|
+
@window2 = @result[:windows]['window2']
|
45
|
+
|
46
|
+
assert @window2[:panes]['pane1'][:is_top_pane], "that this is marked as top most pane"
|
47
|
+
|
48
|
+
assert_equal ['second window'], @window2[:panes]['pane0'][:commands]
|
49
|
+
assert_equal ['second pane'], @window2[:panes]['pane1'][:commands]
|
50
|
+
assert_equal ['third pane'], @window2[:panes]['pane1'][:panes]['pane0'][:commands]
|
51
|
+
|
52
|
+
assert_equal ['tab1'], @window2[:tabs]['default'][:commands]
|
53
|
+
assert_equal ['tab2'], @window2[:tabs]['tab1'][:commands]
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/spec/iterm_spec.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Consular::ITerm do
|
4
|
+
before do
|
5
|
+
@core = Consular::ITerm.new File.expand_path('../fixtures/bar.term', __FILE__)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should return name of core with #to_s" do
|
9
|
+
assert_equal "Consular::ITerm Mac OSX iTerm2", Consular::ITerm.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should add itself to Consular cores" do
|
13
|
+
assert_includes Consular.cores, Consular::ITerm
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should set ivars on .initialize" do
|
17
|
+
refute_nil @core.instance_variable_get(:@termfile)
|
18
|
+
refute_nil @core.instance_variable_get(:@terminal)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should prepend commands with .prepend_befores" do
|
22
|
+
assert_equal ['ps', 'ls'], @core.prepend_befores(['ls'], ['ps'])
|
23
|
+
assert_equal ['ls'], @core.prepend_befores(['ls'])
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should set .set_title" do
|
27
|
+
assert_equal ["PS1=\"$PS1\\[\\e]2;hey\\a\\]\"",'ls'], @core.set_title('hey', ['ls'])
|
28
|
+
assert_equal ['ls'], @core.set_title(nil, ['ls'])
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'minitest'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require File.expand_path('../../lib/consular/iterm', __FILE__)
|
5
|
+
|
6
|
+
|
7
|
+
class ColoredIO
|
8
|
+
ESC = "\e["
|
9
|
+
NND = "#{ESC}0m"
|
10
|
+
|
11
|
+
def initialize(io)
|
12
|
+
@io = io
|
13
|
+
end
|
14
|
+
|
15
|
+
def print(o)
|
16
|
+
case o
|
17
|
+
when "."
|
18
|
+
@io.send(:print, "#{ESC}32m#{o}#{NND}")
|
19
|
+
when "E"
|
20
|
+
@io.send(:print, "#{ESC}33m#{o}#{NND}")
|
21
|
+
when "F"
|
22
|
+
@io.send(:print, "#{ESC}31m#{o}#{NND}")
|
23
|
+
else
|
24
|
+
@io.send(:print, o)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def puts(*o)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
MiniTest::Unit.output = ColoredIO.new(MiniTest::Unit.output)
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: consular-iterm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Arthur Chiu
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-02 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: consular
|
16
|
+
requirement: &2161515360 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2161515360
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: minitest
|
27
|
+
requirement: &2161514880 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2161514880
|
36
|
+
description: Terminal Automation for ITerm via Consular
|
37
|
+
email:
|
38
|
+
- mr.arthur.chiu@gmail.com
|
39
|
+
executables: []
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- .gitignore
|
44
|
+
- Gemfile
|
45
|
+
- README.md
|
46
|
+
- Rakefile
|
47
|
+
- consular-iterm.gemspec
|
48
|
+
- lib/consular/iterm.rb
|
49
|
+
- lib/consular/iterm_dsl.rb
|
50
|
+
- spec.watchr
|
51
|
+
- spec/fixtures/bar.term
|
52
|
+
- spec/iterm_dsl_spec.rb
|
53
|
+
- spec/iterm_spec.rb
|
54
|
+
- spec/spec_helper.rb
|
55
|
+
homepage: http://www.github.com/achiu/consular-iterm
|
56
|
+
licenses: []
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project: consular-iterm
|
75
|
+
rubygems_version: 1.8.10
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Automate your ITerm with Consular
|
79
|
+
test_files:
|
80
|
+
- spec/fixtures/bar.term
|
81
|
+
- spec/iterm_dsl_spec.rb
|
82
|
+
- spec/iterm_spec.rb
|
83
|
+
- spec/spec_helper.rb
|