terminitor 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +105 -57
- data/lib/terminitor/abstract_core.rb +1 -1
- data/lib/terminitor/cores/iterm_core.rb +142 -35
- data/lib/terminitor/dsl.rb +45 -5
- data/lib/terminitor/version.rb +1 -1
- data/test/abstract_core_test.rb +2 -2
- data/test/cores/iterm_core_test.rb +11 -35
- data/test/dsl_test.rb +56 -1
- data/test/fixtures/iterm_panes.term +20 -0
- metadata +7 -16
data/README.md
CHANGED
@@ -86,22 +86,24 @@ YAML syntax.
|
|
86
86
|
|
87
87
|
#### Ruby DSL Syntax ####
|
88
88
|
|
89
|
-
|
89
|
+
````ruby
|
90
|
+
setup 'echo "setup"' # code to run during setup
|
90
91
|
|
91
|
-
|
92
|
-
|
92
|
+
# open a tab in current window with these commands
|
93
|
+
tab "echo 'default'", "echo 'default tab'"
|
93
94
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
window do
|
96
|
+
before { run 'cd /path' } # run this command before each command.
|
97
|
+
|
98
|
+
run 'padrino start' # run in new window
|
98
99
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
100
|
+
tab "echo 'first tab'", "echo 'of window'" # create a new tab in window and run it.
|
101
|
+
tab "named tab" do
|
102
|
+
run "echo 'named tab'"
|
103
|
+
run "ls"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
````
|
105
107
|
|
106
108
|
The newer Ruby DSL syntax allows for more complicated behavior such as window creation as well as setup blocks that can be executed prior loading a project.
|
107
109
|
|
@@ -109,51 +111,58 @@ The newer Ruby DSL syntax allows for more complicated behavior such as window cr
|
|
109
111
|
|
110
112
|
to create tabs, we can simply invoke the tab command with either the command arguments like:
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
+
````ruby
|
115
|
+
tab "echo 'hi'", "gitx"
|
116
|
+
````
|
117
|
+
|
114
118
|
or even pass it a block:
|
115
119
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
+
````ruby
|
121
|
+
tab do
|
122
|
+
run "echo 'hi'"
|
123
|
+
run "mate ."
|
124
|
+
end
|
125
|
+
````
|
120
126
|
|
121
127
|
##### Windows #####
|
122
128
|
|
123
129
|
to create windows, we can simply invoke the window command with a block containing additional commands like:
|
124
130
|
|
125
|
-
|
131
|
+
````ruby
|
132
|
+
window do
|
126
133
|
|
127
|
-
|
128
|
-
|
129
|
-
tab "echo 'hi'" # Creates another tab
|
130
|
-
tab "mate ." # And another
|
131
|
-
tab do # Last hoorah
|
132
|
-
run "open http://www.google.com"
|
133
|
-
end
|
134
|
-
end
|
134
|
+
run "whoami" # Runs the command in the current window.
|
135
135
|
|
136
|
+
tab "echo 'hi'" # Creates another tab
|
137
|
+
tab "mate ." # And another
|
138
|
+
tab do # Last hoorah
|
139
|
+
run "open http://www.google.com"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
````
|
136
143
|
|
137
144
|
##### Before #####
|
138
145
|
|
139
146
|
Sometimes you'll want to create a few commands that you want to run in each tab instance. You can do that with 'before':
|
140
147
|
|
141
|
-
|
142
|
-
|
143
|
-
|
148
|
+
````ruby
|
149
|
+
before { run "cd /path" } # execute this command before other commands in the default window
|
150
|
+
run "whoami"
|
151
|
+
tab 'uptime'
|
144
152
|
|
145
|
-
|
146
|
-
|
147
|
-
|
153
|
+
# In this instance, "cd /path" wil be executed in the default window before 'whoami'
|
154
|
+
# and also in the tab before 'uptime'.
|
155
|
+
# You can also use this inside a specific window context:
|
148
156
|
|
149
|
-
|
150
|
-
|
151
|
-
|
157
|
+
window do
|
158
|
+
before 'cd /tmp'
|
159
|
+
run 'watchr test.watchr' # "cd /tmp" first than run watchr
|
152
160
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
161
|
+
tab do
|
162
|
+
run 'padrino start' # "cd /tmp" is ran beforehand and then padrino start is executed
|
163
|
+
end
|
164
|
+
end
|
165
|
+
````
|
157
166
|
|
158
167
|
|
159
168
|
|
@@ -163,15 +172,19 @@ The setup block allows you to store commands that can be ran specifically before
|
|
163
172
|
|
164
173
|
the command arguments:
|
165
174
|
|
166
|
-
|
175
|
+
````ruby
|
176
|
+
setup "bundle install", "gitx"
|
177
|
+
````
|
167
178
|
|
168
179
|
or with a block:
|
169
180
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
181
|
+
````ruby
|
182
|
+
setup do
|
183
|
+
run "echo 'hi'"
|
184
|
+
run "bundle install"
|
185
|
+
run 'git remote add upstream git://github.com/achiu/terminitor.git'
|
186
|
+
end
|
187
|
+
````
|
175
188
|
|
176
189
|
|
177
190
|
Once defined, you can invoke your projects setup with:
|
@@ -185,19 +198,23 @@ You can also set settings on each of your tabs and windows. for example, this is
|
|
185
198
|
|
186
199
|
Open a tab with terminal settings "Grass"
|
187
200
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
201
|
+
````ruby
|
202
|
+
tab :name => "named tab", :settings => "Grass" do
|
203
|
+
run "echo 'named tab'"
|
204
|
+
run "ls"
|
205
|
+
end
|
206
|
+
````
|
192
207
|
|
193
208
|
This will create a tab with a title of 'named tab' using Terminals 'Grass' setting.
|
194
209
|
|
195
210
|
|
196
211
|
How about a window with a specific size:
|
197
212
|
|
198
|
-
|
213
|
+
````ruby
|
214
|
+
window :bounds => [10,20,300,200] do
|
199
215
|
|
200
|
-
|
216
|
+
end
|
217
|
+
````
|
201
218
|
|
202
219
|
Currently, the following options are available:
|
203
220
|
|
@@ -322,9 +339,39 @@ focus during execution of these commands. Obviously the long term goal is to sol
|
|
322
339
|
|
323
340
|
#### ITermCore ####
|
324
341
|
|
325
|
-
Currently the iTerm Core only provides basic functionality such as opening tabs, windows, and executing commands within them. The capture
|
342
|
+
Currently the iTerm Core only provides basic functionality such as opening tabs, windows, and executing commands within them. It is also possible to split tabs into panes. The capture
|
326
343
|
and settings functionality will be integrated soon.
|
327
344
|
|
345
|
+
Splitting tabs into panes works as follows:
|
346
|
+
|
347
|
+
tab do
|
348
|
+
pane "gitx" # first pane
|
349
|
+
pane do # second pane level => horizontal split
|
350
|
+
run "irb"
|
351
|
+
end
|
352
|
+
pane 'ls' # first pane level => vertical split
|
353
|
+
end
|
354
|
+
|
355
|
+
should result into something like this:
|
356
|
+
|
357
|
+
# ###########################
|
358
|
+
# # # #
|
359
|
+
# # # #
|
360
|
+
# # 'gitx' # #
|
361
|
+
# # # #
|
362
|
+
# # # #
|
363
|
+
# ############## 'ls' #
|
364
|
+
# # # #
|
365
|
+
# # # #
|
366
|
+
# # 'irb' # #
|
367
|
+
# # # #
|
368
|
+
# # # #
|
369
|
+
# ###########################
|
370
|
+
|
371
|
+
It is not possible to split the second level panes (the horizontal
|
372
|
+
ones). Nevertheless you should be able to split tabs into any kind of pane pattern you wish
|
373
|
+
with this syntax.
|
374
|
+
|
328
375
|
|
329
376
|
#### Fetching ####
|
330
377
|
|
@@ -365,14 +412,15 @@ Thanks to the following people for their contributions so far:
|
|
365
412
|
* Flavio Castelli ([flavio](https://github.com/flavio)) for contributing Konsole(KDE) core.
|
366
413
|
* Alexey Kuleshov ([kulesa](https://github.com/kulesa)) for contributing the terminal settings and terminal settings capture functionality
|
367
414
|
* Arthur Gunn ([gunn](https://github.com/gunn)) for contributing a path to support tab syntax and load path.
|
368
|
-
* Elliot Winkler ([mcmire](https://github.com/mcmire)) for adding 1.8.6 compatiblity and ensuring tabs open in order
|
415
|
+
* Elliot Winkler ([mcmire](https://github.com/mcmire)) for adding 1.8.6 compatiblity and ensuring tabs open in order and fixing named tabs
|
369
416
|
* Justin Hilemen ([bobthecow](https://github.com/bobthecow)) for fixing the list command to remove the term extensions.
|
370
417
|
* Dave Perrett ([recurser](https://github.com/recurser)) for adding basic iTerm support.
|
371
418
|
* Ilkka Laukkanen ([ilkka](https://github.com/achiu/terminitor/commits/master?author=ilkka)) for Terminator core and other fixes
|
372
419
|
* Elia Schito ([elia](https://github.com/achiu/terminitor/commits/master?author=elia)) for patch to allow usage of "&" for background operations
|
373
420
|
* Dotan J. Nahum ([jondot](https://github.com/jondot)) for adding windows(cmd.exe) support
|
374
|
-
* Kyriacos Souroullas ([kyriacos](https://github.com/kyriacos)
|
375
|
-
* Jerry Cheung ([jch](https://github.com/jch))
|
421
|
+
* Kyriacos Souroullas ([kyriacos](https://github.com/kyriacos) for removing params to support generic commands
|
422
|
+
* Jerry Cheung ([jch](https://github.com/jch)) for adding ignore for emac backups
|
423
|
+
* Michael Klein ([LevelbossMike](https://github.com/LevelbossMike)) for adding iTerm Pane support
|
376
424
|
|
377
425
|
Acknowledgements
|
378
426
|
-----------------
|
@@ -53,7 +53,7 @@ module Terminitor
|
|
53
53
|
# clean up prompt
|
54
54
|
tab_content[:commands].insert(0, 'clear') if tab_name || !@working_dir.to_s.empty?
|
55
55
|
# add title to tab
|
56
|
-
tab_content[:commands].insert(0, "PS1
|
56
|
+
tab_content[:commands].insert(0, "PS1=\"$PS1\\e]2;#{tab_name}\\a\"") if tab_name
|
57
57
|
tab_content[:commands].insert(0, "cd \"#{@working_dir}\"") unless @working_dir.to_s.empty?
|
58
58
|
tab_content[:commands].each { |cmd| execute_command(cmd, :in => tab) }
|
59
59
|
end
|
@@ -3,12 +3,12 @@ module Terminitor
|
|
3
3
|
# This Core manages all the interaction with Appscript and the Terminal
|
4
4
|
class ItermCore < AbstractCore
|
5
5
|
include Appscript
|
6
|
-
|
6
|
+
|
7
7
|
ALLOWED_OPTIONS = {
|
8
8
|
:window => [:bounds, :visible, :miniaturized],
|
9
9
|
:tab => [:settings, :selected]
|
10
10
|
}
|
11
|
-
|
11
|
+
|
12
12
|
# Initialize @terminal with Terminal.app, Load the Windows, store the Termfile
|
13
13
|
# Terminitor::MacCore.new('/path')
|
14
14
|
def initialize(path)
|
@@ -17,10 +17,10 @@ module Terminitor
|
|
17
17
|
@windows = @terminal.terminals
|
18
18
|
@delayed_options = []
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
# executes the given command via appscript
|
22
22
|
# execute_command 'cd /path/to', :in => #<tab>
|
23
|
-
def execute_command(cmd, options = {})
|
23
|
+
def execute_command(cmd, options = {})
|
24
24
|
if options[:in]
|
25
25
|
options[:in].write(:text => "#{cmd}")
|
26
26
|
else
|
@@ -28,48 +28,33 @@ module Terminitor
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
# Opens a new tab
|
31
|
+
# Opens a new tab, iterm sets focus on new tab
|
32
32
|
# TODO : handle options (?)
|
33
33
|
def open_tab(options = nil)
|
34
|
-
|
35
|
-
session.exec(:command => ENV['SHELL'])
|
36
|
-
session
|
34
|
+
current_terminal.launch_ :session => 'New session'
|
37
35
|
end
|
38
|
-
|
39
|
-
#
|
36
|
+
|
37
|
+
# Open new window, applies settings to the first tab. iterm sets focus on
|
38
|
+
# new tab
|
40
39
|
# TODO : handle options (?)
|
41
40
|
def open_window(options = nil)
|
42
41
|
window = terminal.make( :new => :terminal )
|
43
|
-
|
44
|
-
session.exec(:command => ENV['SHELL'])
|
45
|
-
session
|
46
|
-
end
|
47
|
-
|
48
|
-
# Returns the Terminal Process
|
49
|
-
# We need this method to workaround appscript so that we can instantiate new tabs and windows.
|
50
|
-
# otherwise it would have looked something like window.make(:new => :tab) but that doesn't work.
|
51
|
-
def terminal_process
|
52
|
-
app("System Events").application_processes["iTerm.app"]
|
53
|
-
end
|
54
|
-
|
55
|
-
# Returns the last instantiated tab from active window
|
56
|
-
def return_last_tab
|
57
|
-
current_terminal.sessions.last.get rescue false
|
42
|
+
window.launch_ :session => 'New session'
|
58
43
|
end
|
59
44
|
|
60
|
-
#
|
45
|
+
# Returns the active window i.e. the active terminal session in iTerm
|
61
46
|
def active_window
|
62
|
-
current_terminal.current_session
|
47
|
+
current_terminal.current_session
|
63
48
|
end
|
64
|
-
|
65
|
-
# Returns the current terminal
|
49
|
+
|
50
|
+
# Returns the current terminal i.e. the active iTerm window
|
66
51
|
def current_terminal
|
67
52
|
@terminal.current_terminal
|
68
53
|
end
|
69
54
|
|
70
55
|
# Sets options of the given object
|
71
56
|
def set_options(object, options = {})
|
72
|
-
options.each_pair do |option, value|
|
57
|
+
options.each_pair do |option, value|
|
73
58
|
case option
|
74
59
|
when :settings # works for windows and tabs, for example :settings => "Grass"
|
75
60
|
begin
|
@@ -97,7 +82,7 @@ module Terminitor
|
|
97
82
|
end
|
98
83
|
end
|
99
84
|
end
|
100
|
-
|
85
|
+
|
101
86
|
# Apply delayed options and remove them from the queue
|
102
87
|
def set_delayed_options
|
103
88
|
@delayed_options.length.times do
|
@@ -106,12 +91,134 @@ module Terminitor
|
|
106
91
|
end
|
107
92
|
end
|
108
93
|
|
94
|
+
# this command will run commands in the designated window
|
95
|
+
# run_in_window 'window1', {:tab1 => ['ls','ok']}
|
96
|
+
# @param [String] name of window
|
97
|
+
# @param [Hash] Hash of window's content extracted from Termfile
|
98
|
+
# @param [Hash] Hash of options
|
99
|
+
def run_in_window(window_name, window_content, options = {})
|
100
|
+
window_options = window_content[:options]
|
101
|
+
first_tab = true
|
102
|
+
window_content[:tabs].keys.sort.each do |tab_key|
|
103
|
+
tab_content = window_content[:tabs][tab_key]
|
104
|
+
# Open window on first 'tab' statement
|
105
|
+
# first tab is already opened in the new window, so first tab should be
|
106
|
+
# opened as a new tab in default window only
|
107
|
+
tab_options = tab_content[:options]
|
108
|
+
tab_name = tab_options[:name] if tab_options
|
109
|
+
if first_tab && !options[:default]
|
110
|
+
first_tab = false
|
111
|
+
combined_options = (window_options.to_a + tab_options.to_a).inject([]) {|arr, pair| arr += pair }
|
112
|
+
window_options = Hash[*combined_options] # safe merge
|
113
|
+
tab = window_options.empty? ? open_window(nil) : open_window(window_options)
|
114
|
+
else
|
115
|
+
# give us the current window if its default, else open a tab.
|
116
|
+
tab = ( tab_key == 'default' ? active_window : open_tab(tab_options) )
|
117
|
+
end
|
118
|
+
# append our before block commands.
|
119
|
+
tab_content[:commands].insert(0, window_content[:before]).flatten! if window_content[:before]
|
120
|
+
# clean up prompt
|
121
|
+
tab_content[:commands].insert(0, 'clear') if tab_name || !@working_dir.to_s.empty?
|
122
|
+
# add title to tab
|
123
|
+
tab_content[:commands].insert(0, "PS1=$PS1\"\\e]2;#{tab_name}\\a\"") if tab_name
|
124
|
+
tab_content[:commands].insert(0, "cd \"#{@working_dir}\"") unless @working_dir.to_s.empty?
|
125
|
+
# if tab_content hash has a key :panes we know this tab should be split
|
126
|
+
# we can execute tab commands if there is no key :panes
|
127
|
+
if tab_content.key?(:panes)
|
128
|
+
handle_panes(tab_content)
|
129
|
+
else
|
130
|
+
tab_content[:commands].each { |cmd| execute_command(cmd, :in => tab) }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
set_delayed_options
|
134
|
+
end
|
135
|
+
|
136
|
+
def handle_panes(tab_content)
|
137
|
+
panes = tab_content[:panes]
|
138
|
+
tab_commands = tab_content[:commands]
|
139
|
+
first_pane_level_split(panes, tab_commands)
|
140
|
+
second_pane_level_split(panes, tab_commands)
|
141
|
+
end
|
142
|
+
|
143
|
+
def first_pane_level_split(panes, tab_commands)
|
144
|
+
first_pane = true
|
145
|
+
split_v_counter = 0
|
146
|
+
panes.keys.sort.each do |pane_key|
|
147
|
+
pane_content = panes[pane_key]
|
148
|
+
unless first_pane
|
149
|
+
split_v
|
150
|
+
split_v_counter += 1
|
151
|
+
end
|
152
|
+
first_pane = false if first_pane
|
153
|
+
pane_commands = pane_content[:commands]
|
154
|
+
execute_pane_commands(pane_commands, tab_commands)
|
155
|
+
end
|
156
|
+
split_v_counter.times { select_pane 'Left' }
|
157
|
+
end
|
158
|
+
|
159
|
+
def second_pane_level_split(panes, tab_commands)
|
160
|
+
panes.keys.sort.each do |pane_key|
|
161
|
+
pane_content = panes[pane_key]
|
162
|
+
handle_subpanes(pane_content[:panes], tab_commands) if pane_content.has_key? :panes
|
163
|
+
# select next vertical pane
|
164
|
+
select_pane 'Right'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def handle_subpanes(subpanes, tab_commands)
|
169
|
+
subpanes.keys.sort.each do |subpane_key|
|
170
|
+
subpane_commands = subpanes[subpane_key][:commands]
|
171
|
+
split_h
|
172
|
+
execute_pane_commands(subpane_commands, tab_commands)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def execute_pane_commands(pane_commands, tab_commands)
|
177
|
+
pane_commands = tab_commands + pane_commands
|
178
|
+
pane_commands.each { |cmd| execute_command cmd}
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
# Methods for splitting panes (GUI_scripting)
|
183
|
+
#
|
184
|
+
def iterm_menu
|
185
|
+
terminal_process = Appscript.app("System Events").processes["iTerm"]
|
186
|
+
terminal_process.menu_bars.first
|
187
|
+
end
|
188
|
+
|
189
|
+
def call_ui_action(menu, submenu = nil, action)
|
190
|
+
menu = iterm_menu.menu_bar_items[menu].menus[menu]
|
191
|
+
if submenu
|
192
|
+
menu = menu.menu_items[submenu].menus[submenu]
|
193
|
+
end
|
194
|
+
menu.menu_items[action].click
|
195
|
+
end
|
196
|
+
|
197
|
+
def split_v
|
198
|
+
call_ui_action("Shell", nil, "Split vertically")
|
199
|
+
end
|
200
|
+
|
201
|
+
def split_h
|
202
|
+
call_ui_action("Shell", nil, "Split horizontally")
|
203
|
+
end
|
204
|
+
|
205
|
+
# to select panes; iTerm's Appscript select method does not work
|
206
|
+
# as expected, we have to select via menu instead
|
207
|
+
def select_pane(direction)
|
208
|
+
valid_directions = %w[Above Below Left Right]
|
209
|
+
if valid_directions.include?(direction)
|
210
|
+
call_ui_action("Window", "Select Split Pane", "Select Pane #{direction}")
|
211
|
+
else
|
212
|
+
puts "Error: #{direction} is not a valid direction to select a pane; Only Above/Below/Left/Right are valid directions"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
109
216
|
private
|
110
|
-
|
217
|
+
|
111
218
|
# These methods are here for reference so I can ponder later
|
112
219
|
# how I could possibly use them.
|
113
220
|
# And Currently aren't tested. =(
|
114
|
-
|
221
|
+
|
115
222
|
# returns a window by the id
|
116
223
|
def window_by_id(id)
|
117
224
|
@windows.ID(id)
|
@@ -127,12 +234,12 @@ module Terminitor
|
|
127
234
|
def set_window_title(window, title)
|
128
235
|
window.custom_title.set(title)
|
129
236
|
end
|
130
|
-
|
237
|
+
|
131
238
|
# selects options allowed for window or tab
|
132
239
|
def allowed_options(object_type, options)
|
133
240
|
Hash[ options.select {|option, value| ALLOWED_OPTIONS[object_type].include?(option) }]
|
134
241
|
end
|
135
|
-
|
242
|
+
|
136
243
|
# Add option to the list of delayed options
|
137
244
|
def delayed_option(option, value, object)
|
138
245
|
@delayed_options << {
|
data/lib/terminitor/dsl.rb
CHANGED
@@ -28,7 +28,7 @@ module Terminitor
|
|
28
28
|
|
29
29
|
# sets command context to be run inside a specific window
|
30
30
|
# @param [Hash] options hash.
|
31
|
-
# @param [Proc]
|
31
|
+
# @param [Proc]
|
32
32
|
# @example
|
33
33
|
# window(:name => 'new window', :size => [80,30], :position => [9, 100]) { tab('ls','gitx') }
|
34
34
|
# window { tab('ls', 'gitx') }
|
@@ -47,6 +47,8 @@ module Terminitor
|
|
47
47
|
# if we are in a window context, append commands to default tab.
|
48
48
|
if @_context.is_a?(Hash) && @_context[:tabs]
|
49
49
|
current = @_context[:tabs]['default'][:commands]
|
50
|
+
elsif @_context.is_a?(Hash)
|
51
|
+
current = @_context[:commands]
|
50
52
|
else
|
51
53
|
current = @_context
|
52
54
|
end
|
@@ -82,19 +84,50 @@ module Terminitor
|
|
82
84
|
tab_name = "tab#{tabs.keys.size}"
|
83
85
|
if block_given?
|
84
86
|
tab_contents = tabs[tab_name] = {:commands => []}
|
85
|
-
|
87
|
+
|
86
88
|
options = {}
|
87
89
|
options = args.pop if args.last.is_a? Hash
|
88
90
|
options[:name] = args.first if args.first.is_a?(String) || args.first.is_a?(Symbol)
|
89
|
-
|
91
|
+
|
90
92
|
tab_contents[:options] = options unless options.empty?
|
91
|
-
|
92
|
-
in_context tab_contents
|
93
|
+
|
94
|
+
in_context tab_contents, &block
|
95
|
+
clean_up_context
|
93
96
|
else
|
94
97
|
tabs[tab_name] = { :commands => args}
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
101
|
+
# Generates a pane in the terminal. These can be nested to
|
102
|
+
# create horizontal panes. Vertical panes are created with each top
|
103
|
+
# level nest.
|
104
|
+
# @param [Array<String>] Array of comamnds
|
105
|
+
# @param [Proc]
|
106
|
+
# @example
|
107
|
+
# pane "top"
|
108
|
+
# pane { pane "uptime" }
|
109
|
+
def pane(*args, &block)
|
110
|
+
@_context[:panes] = {} unless @_context.has_key? :panes
|
111
|
+
panes = @_context[:panes]
|
112
|
+
pane_name = "pane#{panes.keys.size}"
|
113
|
+
if block_given?
|
114
|
+
pane_contents = panes[pane_name] = {:commands => []}
|
115
|
+
if @_context.has_key? :is_first_lvl_pane
|
116
|
+
# after in_context we should be able to access
|
117
|
+
# @_context and @_old_context as before
|
118
|
+
context = @_context
|
119
|
+
old_context = @_old_context
|
120
|
+
in_context pane_contents[:commands], &block
|
121
|
+
clean_up_context(context, old_context)
|
122
|
+
else
|
123
|
+
pane_contents[:is_first_lvl_pane] = true
|
124
|
+
in_context pane_contents, &block
|
125
|
+
end
|
126
|
+
else
|
127
|
+
panes[pane_name] = { :commands => args }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
98
131
|
# Returns yaml file as Terminitor formmatted hash
|
99
132
|
# @return [Hash] Return hash format of Termfile
|
100
133
|
def to_hash
|
@@ -111,6 +144,13 @@ module Terminitor
|
|
111
144
|
@_context = @_old_context
|
112
145
|
end
|
113
146
|
|
147
|
+
def clean_up_context(context = last_open_window, old_context = nil)
|
148
|
+
@_context = context
|
149
|
+
@_old_context = old_context
|
150
|
+
end
|
114
151
|
|
152
|
+
def last_open_window
|
153
|
+
@windows[@windows.keys.last]
|
154
|
+
end
|
115
155
|
end
|
116
156
|
end
|
data/lib/terminitor/version.rb
CHANGED
data/test/abstract_core_test.rb
CHANGED
@@ -123,11 +123,11 @@ context "AbstractCore" do
|
|
123
123
|
mock(core).open_window(:bounds => [10,10], :settings => 'cool', :name => "first tab") { "first" }
|
124
124
|
mock(core).open_tab(:settings => 'grass', :name => 'second tab') { "second" }
|
125
125
|
mock(core).set_delayed_options { true }
|
126
|
-
mock(core).execute_command('PS1
|
126
|
+
mock(core).execute_command('PS1="$PS1\e]2;first tab\a"', :in => 'first')
|
127
127
|
mock(core).execute_command('clear', :in => 'first')
|
128
128
|
mock(core).execute_command('ls', :in => "first")
|
129
129
|
mock(core).execute_command('ok', :in => "first")
|
130
|
-
mock(core).execute_command('PS1
|
130
|
+
mock(core).execute_command('PS1="$PS1\e]2;second tab\a"', :in => 'second')
|
131
131
|
mock(core).execute_command('clear', :in => 'second')
|
132
132
|
mock(core).execute_command('ps', :in => "second")
|
133
133
|
core.process!
|
@@ -11,54 +11,30 @@ on_platform "darwin" do
|
|
11
11
|
@iterm_core = Terminitor::ItermCore.new('/path/to')
|
12
12
|
end
|
13
13
|
|
14
|
-
asserts "#terminal_process calls System Events" do
|
15
|
-
core = topic.dup
|
16
|
-
mock(core).app('System Events') { mock!.application_processes.returns("iTerm.app" => true) }
|
17
|
-
core.terminal_process
|
18
|
-
end
|
19
|
-
|
20
|
-
context "#open_tab" do
|
21
14
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
core.open_tab
|
28
|
-
end
|
15
|
+
asserts "#open_tab launches a new sessions" do
|
16
|
+
core = topic.dup
|
17
|
+
mock(core).current_terminal.stub!.launch_(:session => 'New session')
|
18
|
+
core.open_tab
|
19
|
+
end.nil
|
29
20
|
|
30
|
-
|
21
|
+
asserts "#open_window creates a new session" do
|
22
|
+
core = topic.dup
|
23
|
+
mock(core).terminal.stub!.make(:new => :terminal).stub!.launch_(:session => 'New session')
|
24
|
+
core.open_window
|
25
|
+
end.nil
|
31
26
|
|
32
|
-
context "#open_window" do
|
33
|
-
|
34
|
-
should "return the last tab" do
|
35
|
-
core = topic.dup
|
36
|
-
mock(core).terminal.stub!.make(:new=>:terminal).
|
37
|
-
stub!.sessions.stub!.end.stub!.make(:new=>:session).
|
38
|
-
stub!.exec(:command => ENV['SHELL'])
|
39
|
-
core.open_window
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
asserts "#return_last_tab returns the last tab" do
|
44
|
-
core = topic.dup
|
45
|
-
mock(core).current_terminal.stub!.sessions.stub!.
|
46
|
-
last.stub!.get.returns(true)
|
47
|
-
core.return_last_tab
|
48
|
-
end
|
49
|
-
|
50
27
|
asserts "#execute_command executes" do
|
51
28
|
core = topic.dup
|
52
29
|
mock(core).active_window.stub!.write(:text => "hasta").returns(true)
|
53
30
|
core.execute_command('hasta')
|
54
31
|
end
|
55
|
-
|
32
|
+
|
56
33
|
asserts "#active_window gives window" do
|
57
34
|
core = topic.dup
|
58
35
|
mock(core).current_terminal.stub!.current_session.stub!.get.returns(true)
|
59
36
|
core.active_window
|
60
37
|
end
|
61
|
-
|
62
38
|
end
|
63
39
|
end
|
64
40
|
|
data/test/dsl_test.rb
CHANGED
@@ -20,7 +20,7 @@ context "Dsl" do
|
|
20
20
|
|
21
21
|
context "with :tabs" do
|
22
22
|
setup { topic[:tabs] }
|
23
|
-
|
23
|
+
|
24
24
|
asserts(:[], 'tab2').equivalent_to({
|
25
25
|
:commands=>["echo 'named tab'", "ls"],
|
26
26
|
:options => {
|
@@ -87,3 +87,58 @@ context "Dsl" do
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
90
|
+
|
91
|
+
context "with panes" do
|
92
|
+
setup { Terminitor::Dsl.new File.expand_path('../fixtures/iterm_panes.term', __FILE__) }
|
93
|
+
asserts_topic.assigns :setup
|
94
|
+
asserts_topic.assigns :windows
|
95
|
+
asserts_topic.assigns :_context
|
96
|
+
|
97
|
+
context "creates correct hash" do
|
98
|
+
setup { topic.to_hash }
|
99
|
+
|
100
|
+
context "in windows" do
|
101
|
+
setup { topic[:windows] }
|
102
|
+
|
103
|
+
context "with default window" do
|
104
|
+
setup { topic['default'] }
|
105
|
+
|
106
|
+
context "tabs with panes " do
|
107
|
+
setup { topic[:tabs] }
|
108
|
+
|
109
|
+
context "tabs can hold panes" do
|
110
|
+
asserts(:[], 'tab1').equivalent_to({
|
111
|
+
:commands=>["ls"],
|
112
|
+
:panes => {
|
113
|
+
'pane0' => {
|
114
|
+
:commands => ["echo 'first level pane'"],
|
115
|
+
:is_first_lvl_pane => true,
|
116
|
+
:panes => {
|
117
|
+
'pane0' => {
|
118
|
+
:commands => ["echo 'first second level pane'"]
|
119
|
+
}
|
120
|
+
}
|
121
|
+
},
|
122
|
+
'pane1' => {
|
123
|
+
:commands => ["gitx"],
|
124
|
+
:is_first_lvl_pane => true,
|
125
|
+
:panes => {
|
126
|
+
'pane0' => {
|
127
|
+
:commands => ["ls"]
|
128
|
+
},
|
129
|
+
'pane1' => {
|
130
|
+
:commands => ["echo 'wohoo'", "echo '2nd cmd'"]
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
})
|
136
|
+
asserts(:[], 'tab2').equivalent_to({
|
137
|
+
:commands => ["echo 'second tab'"]
|
138
|
+
})
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
tab do
|
2
|
+
run 'ls'
|
3
|
+
pane do
|
4
|
+
run "echo 'first level pane'"
|
5
|
+
pane do
|
6
|
+
run "echo 'first second level pane'"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
pane do
|
10
|
+
run "gitx"
|
11
|
+
pane 'ls'
|
12
|
+
pane do
|
13
|
+
run "echo 'wohoo'"
|
14
|
+
run "echo '2nd cmd'"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
tab do
|
19
|
+
run "echo 'second tab'"
|
20
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terminitor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
4
|
+
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
7
|
+
- 6
|
8
|
+
- 0
|
9
|
+
version: 0.6.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Arthur Chiu
|
@@ -16,7 +15,7 @@ autorequire:
|
|
16
15
|
bindir: bin
|
17
16
|
cert_chain: []
|
18
17
|
|
19
|
-
date: 2011-
|
18
|
+
date: 2011-05-15 00:00:00 -07:00
|
20
19
|
default_executable:
|
21
20
|
dependencies:
|
22
21
|
- !ruby/object:Gem::Dependency
|
@@ -27,7 +26,6 @@ dependencies:
|
|
27
26
|
requirements:
|
28
27
|
- - ~>
|
29
28
|
- !ruby/object:Gem::Version
|
30
|
-
hash: 5
|
31
29
|
segments:
|
32
30
|
- 0
|
33
31
|
- 6
|
@@ -43,7 +41,6 @@ dependencies:
|
|
43
41
|
requirements:
|
44
42
|
- - ~>
|
45
43
|
- !ruby/object:Gem::Version
|
46
|
-
hash: 39
|
47
44
|
segments:
|
48
45
|
- 0
|
49
46
|
- 14
|
@@ -59,7 +56,6 @@ dependencies:
|
|
59
56
|
requirements:
|
60
57
|
- - ~>
|
61
58
|
- !ruby/object:Gem::Version
|
62
|
-
hash: 3
|
63
59
|
segments:
|
64
60
|
- 0
|
65
61
|
- 6
|
@@ -75,7 +71,6 @@ dependencies:
|
|
75
71
|
requirements:
|
76
72
|
- - ~>
|
77
73
|
- !ruby/object:Gem::Version
|
78
|
-
hash: 23
|
79
74
|
segments:
|
80
75
|
- 1
|
81
76
|
- 0
|
@@ -91,7 +86,6 @@ dependencies:
|
|
91
86
|
requirements:
|
92
87
|
- - ~>
|
93
88
|
- !ruby/object:Gem::Version
|
94
|
-
hash: 41
|
95
89
|
segments:
|
96
90
|
- 0
|
97
91
|
- 12
|
@@ -107,7 +101,6 @@ dependencies:
|
|
107
101
|
requirements:
|
108
102
|
- - ~>
|
109
103
|
- !ruby/object:Gem::Version
|
110
|
-
hash: 23
|
111
104
|
segments:
|
112
105
|
- 1
|
113
106
|
- 0
|
@@ -123,7 +116,6 @@ dependencies:
|
|
123
116
|
requirements:
|
124
117
|
- - ">="
|
125
118
|
- !ruby/object:Gem::Version
|
126
|
-
hash: 3
|
127
119
|
segments:
|
128
120
|
- 0
|
129
121
|
version: "0"
|
@@ -185,6 +177,7 @@ files:
|
|
185
177
|
- test/fixtures/bar.term
|
186
178
|
- test/fixtures/foo.term
|
187
179
|
- test/fixtures/foo.yml
|
180
|
+
- test/fixtures/iterm_panes.term
|
188
181
|
- test/runner_test.rb
|
189
182
|
- test/teststrap.rb
|
190
183
|
- test/yaml_test.rb
|
@@ -203,7 +196,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
203
196
|
requirements:
|
204
197
|
- - ">="
|
205
198
|
- !ruby/object:Gem::Version
|
206
|
-
hash: 3
|
207
199
|
segments:
|
208
200
|
- 0
|
209
201
|
version: "0"
|
@@ -212,7 +204,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
204
|
requirements:
|
213
205
|
- - ">="
|
214
206
|
- !ruby/object:Gem::Version
|
215
|
-
hash: 23
|
216
207
|
segments:
|
217
208
|
- 1
|
218
209
|
- 3
|
@@ -221,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
221
212
|
requirements: []
|
222
213
|
|
223
214
|
rubyforge_project: terminitor
|
224
|
-
rubygems_version: 1.
|
215
|
+
rubygems_version: 1.3.7
|
225
216
|
signing_key:
|
226
217
|
specification_version: 3
|
227
218
|
summary: Automate your development workflow
|