terminitor 0.5.2 → 0.6.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/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
|