Merge lp:~ipv64ever/terminator/custom_commands_plugin_complex_cmd into lp:terminator/gtk3
- custom_commands_plugin_complex_cmd
- Merge into gtk3
Status: | Needs review |
---|---|
Proposed branch: | lp:~ipv64ever/terminator/custom_commands_plugin_complex_cmd |
Merge into: | lp:terminator/gtk3 |
Diff against target: |
355 lines (+144/-26) 2 files modified
terminatorlib/plugins/custom_commands.py (+113/-26) tests/test_custom_command_parser.py (+31/-0) |
To merge this branch: | bzr merge lp:~ipv64ever/terminator/custom_commands_plugin_complex_cmd |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Terminator | Pending | ||
Review via email: mp+358771@code.launchpad.net |
Commit message
Custom Commands Plugin: Added complex option.
This option enables parsing of special characters in command:
\n - send new line
\p - add 1 sec delay
This new option doesn't conflict with old Custom Command config.
By default all existing commands get this option disabled
Added unit tests of command parsing command.
Description of the change
At this moment Custom commands plugin allow to send only one string with ending '\n' character.
I suggest to add ability to create complex command. Each part of command is sent one by one.
For example command "command1\
'command1\n'
'command2\n'
'command3\n'
There's also an ability to add delays between commands using "\p" chars.
Example 'command1\
'command1\n'
1 sec delay
'command2\n'
2 sec delay
'command3\n'
Command parsing affects only on these two "\n" and "\p" characters in command
I use terminator in my work and i often have to login on embedded boards remotely through serial port.
Each time i type login, then send password using custom command, then sudo su and finally root password again. It's anoying especially when i have to do it a lot.
Unmerged revisions
- 1811. By Igor Korotin <email address hidden>
-
Custom Commands Plugin: Added complex option.
This option enables parsing of special characters in command:
\n - send new line
\p - add 1 sec delayThis new option doesn't conflict with old Custom Command config.
By default all existing commands get this option disabledAdded unit tests of command parsing command.
Preview Diff
1 | === modified file 'terminatorlib/plugins/custom_commands.py' | |||
2 | --- terminatorlib/plugins/custom_commands.py 2017-02-06 11:09:36 +0000 | |||
3 | +++ terminatorlib/plugins/custom_commands.py 2018-11-14 13:07:15 +0000 | |||
4 | @@ -4,11 +4,16 @@ | |||
5 | 4 | """custom_commands.py - Terminator Plugin to add custom command menu entries""" | 4 | """custom_commands.py - Terminator Plugin to add custom command menu entries""" |
6 | 5 | import sys | 5 | import sys |
7 | 6 | import os | 6 | import os |
8 | 7 | import re | ||
9 | 8 | import threading | ||
10 | 7 | 9 | ||
11 | 8 | # Fix imports when testing this file directly | 10 | # Fix imports when testing this file directly |
12 | 9 | if __name__ == '__main__': | 11 | if __name__ == '__main__': |
13 | 12 | print os.path.dirname(__file__) | ||
14 | 10 | sys.path.append( os.path.join(os.path.dirname(__file__), "../..")) | 13 | sys.path.append( os.path.join(os.path.dirname(__file__), "../..")) |
15 | 11 | 14 | ||
16 | 15 | import gi | ||
17 | 16 | gi.require_version('Gtk', '3.0') | ||
18 | 12 | from gi.repository import Gtk | 17 | from gi.repository import Gtk |
19 | 13 | from gi.repository import GObject | 18 | from gi.repository import GObject |
20 | 14 | import terminatorlib.plugin as plugin | 19 | import terminatorlib.plugin as plugin |
21 | @@ -16,7 +21,7 @@ | |||
22 | 16 | from terminatorlib.translation import _ | 21 | from terminatorlib.translation import _ |
23 | 17 | from terminatorlib.util import get_config_dir, err, dbg, gerr | 22 | from terminatorlib.util import get_config_dir, err, dbg, gerr |
24 | 18 | 23 | ||
26 | 19 | (CC_COL_ENABLED, CC_COL_NAME, CC_COL_COMMAND) = range(0,3) | 24 | (CC_COL_ENABLED, CC_COL_NAME, CC_COL_COMMAND,CC_COL_COMPLEX) = range(0,4) |
27 | 20 | 25 | ||
28 | 21 | # Every plugin you want Terminator to load *must* be listed in 'AVAILABLE' | 26 | # Every plugin you want Terminator to load *must* be listed in 'AVAILABLE' |
29 | 22 | AVAILABLE = ['CustomCommandsMenu'] | 27 | AVAILABLE = ['CustomCommandsMenu'] |
30 | @@ -30,6 +35,7 @@ | |||
31 | 30 | def __init__( self): | 35 | def __init__( self): |
32 | 31 | config = Config() | 36 | config = Config() |
33 | 32 | sections = config.plugin_get_config(self.__class__.__name__) | 37 | sections = config.plugin_get_config(self.__class__.__name__) |
34 | 38 | |||
35 | 33 | if not isinstance(sections, dict): | 39 | if not isinstance(sections, dict): |
36 | 34 | return | 40 | return |
37 | 35 | noord_cmds = [] | 41 | noord_cmds = [] |
38 | @@ -41,16 +47,22 @@ | |||
39 | 41 | name = s["name"] | 47 | name = s["name"] |
40 | 42 | command = s["command"] | 48 | command = s["command"] |
41 | 43 | enabled = s["enabled"] and s["enabled"] or False | 49 | enabled = s["enabled"] and s["enabled"] or False |
42 | 50 | if not (s.has_key("complex")): | ||
43 | 51 | cmplx = False | ||
44 | 52 | else: | ||
45 | 53 | cmplx = s["complex"] and s["complex"] or False | ||
46 | 44 | if s.has_key("position"): | 54 | if s.has_key("position"): |
47 | 45 | self.cmd_list[int(s["position"])] = {'enabled' : enabled, | 55 | self.cmd_list[int(s["position"])] = {'enabled' : enabled, |
48 | 46 | 'name' : name, | 56 | 'name' : name, |
50 | 47 | 'command' : command | 57 | 'command' : command, |
51 | 58 | 'complex' : cmplx | ||
52 | 48 | } | 59 | } |
53 | 49 | else: | 60 | else: |
54 | 50 | noord_cmds.append( | 61 | noord_cmds.append( |
55 | 51 | {'enabled' : enabled, | 62 | {'enabled' : enabled, |
56 | 52 | 'name' : name, | 63 | 'name' : name, |
58 | 53 | 'command' : command | 64 | 'command' : command, |
59 | 65 | 'complex' : cmplx | ||
60 | 54 | } | 66 | } |
61 | 55 | ) | 67 | ) |
62 | 56 | for cmd in noord_cmds: | 68 | for cmd in noord_cmds: |
63 | @@ -100,7 +112,7 @@ | |||
64 | 100 | else: | 112 | else: |
65 | 101 | menuitem = Gtk.MenuItem(leaf_name) | 113 | menuitem = Gtk.MenuItem(leaf_name) |
66 | 102 | terminals = terminal.terminator.get_target_terms(terminal) | 114 | terminals = terminal.terminator.get_target_terms(terminal) |
68 | 103 | menuitem.connect("activate", self._execute, {'terminals' : terminals, 'command' : command['command'] }) | 115 | menuitem.connect("activate", self._execute, {'terminals' : terminals, 'command' : command['command'], 'complex' : command['complex'] }) |
69 | 104 | target_submenu.append(menuitem) | 116 | target_submenu.append(menuitem) |
70 | 105 | 117 | ||
71 | 106 | def _save_config(self): | 118 | def _save_config(self): |
72 | @@ -109,6 +121,7 @@ | |||
73 | 109 | i = 0 | 121 | i = 0 |
74 | 110 | for command in [ self.cmd_list[key] for key in sorted(self.cmd_list.keys()) ] : | 122 | for command in [ self.cmd_list[key] for key in sorted(self.cmd_list.keys()) ] : |
75 | 111 | enabled = command['enabled'] | 123 | enabled = command['enabled'] |
76 | 124 | cmplx = command['complex'] | ||
77 | 112 | name = command['name'] | 125 | name = command['name'] |
78 | 113 | command = command['command'] | 126 | command = command['command'] |
79 | 114 | 127 | ||
80 | @@ -116,18 +129,60 @@ | |||
81 | 116 | item['enabled'] = enabled | 129 | item['enabled'] = enabled |
82 | 117 | item['name'] = name | 130 | item['name'] = name |
83 | 118 | item['command'] = command | 131 | item['command'] = command |
84 | 132 | item['complex'] = cmplx | ||
85 | 119 | item['position'] = i | 133 | item['position'] = i |
86 | 120 | 134 | ||
87 | 121 | config.plugin_set(self.__class__.__name__, name, item) | 135 | config.plugin_set(self.__class__.__name__, name, item) |
88 | 122 | i = i + 1 | 136 | i = i + 1 |
89 | 123 | config.save() | 137 | config.save() |
90 | 124 | 138 | ||
91 | 139 | def _parse(self, command_str): | ||
92 | 140 | ret_command_list = [] | ||
93 | 141 | command_list = command_str.split("\\n") | ||
94 | 142 | delay=0 | ||
95 | 143 | |||
96 | 144 | for idx, line in enumerate(command_list): | ||
97 | 145 | if line == '': | ||
98 | 146 | line = '\n' | ||
99 | 147 | ret_command_list.append({'command': line, 'delay': delay}) | ||
100 | 148 | else: | ||
101 | 149 | if line[-1] != '\n': | ||
102 | 150 | line = line + '\n' | ||
103 | 151 | # We've got separete command but it might have some other special characters | ||
104 | 152 | # So first of all - check whether line contains them. | ||
105 | 153 | obj = re.search(r"(?:\\p)", line) | ||
106 | 154 | if obj: | ||
107 | 155 | # Using 0x00 char to parse string. | ||
108 | 156 | _list = list(filter(None, re.sub(r"(?:\\p)", '\0\\p\0', line).split('\0'))) | ||
109 | 157 | for part in _list: | ||
110 | 158 | if part == '\\p': | ||
111 | 159 | delay += 1; | ||
112 | 160 | else: | ||
113 | 161 | ret_command_list.append({'command': part, 'delay': delay}) | ||
114 | 162 | delay = 0; | ||
115 | 163 | else: | ||
116 | 164 | ret_command_list.append({'command': line, 'delay': delay}) | ||
117 | 165 | return ret_command_list | ||
118 | 166 | |||
119 | 167 | def deferred_execute(self, terminal, command, rest_command_list): | ||
120 | 168 | terminal.vte.feed_child(command, len(command)) | ||
121 | 169 | if rest_command_list: | ||
122 | 170 | threading.Timer(rest_command_list[0]['delay'], self.deferred_execute, [terminal, rest_command_list[0]['command'], rest_command_list[1:]]).start() | ||
123 | 171 | |||
124 | 125 | def _execute(self, widget, data): | 172 | def _execute(self, widget, data): |
130 | 126 | command = data['command'] | 173 | cmplx = data['complex'] |
131 | 127 | if command[-1] != '\n': | 174 | |
132 | 128 | command = command + '\n' | 175 | if cmplx: |
133 | 129 | for terminal in data['terminals']: | 176 | command_list = self._parse(data['command']) |
134 | 130 | terminal.vte.feed_child(command, len(command)) | 177 | for terminal in data['terminals']: |
135 | 178 | threading.Timer(command_list[0]['delay'], self.deferred_execute, [terminal, command_list[0]['command'], command_list[1:]]).start() | ||
136 | 179 | |||
137 | 180 | else: | ||
138 | 181 | command = data['command'] | ||
139 | 182 | if command[-1] != '\n': | ||
140 | 183 | command = command + '\n' | ||
141 | 184 | for terminal in data['terminals']: | ||
142 | 185 | terminal.vte.feed_child(command, len(command)) | ||
143 | 131 | 186 | ||
144 | 132 | def configure(self, widget, data = None): | 187 | def configure(self, widget, data = None): |
145 | 133 | ui = {} | 188 | ui = {} |
146 | @@ -150,10 +205,10 @@ | |||
147 | 150 | icon = dbox.render_icon(Gtk.STOCK_DIALOG_INFO, Gtk.IconSize.BUTTON) | 205 | icon = dbox.render_icon(Gtk.STOCK_DIALOG_INFO, Gtk.IconSize.BUTTON) |
148 | 151 | dbox.set_icon(icon) | 206 | dbox.set_icon(icon) |
149 | 152 | 207 | ||
151 | 153 | store = Gtk.ListStore(bool, str, str) | 208 | store = Gtk.ListStore(bool, str, str, bool) |
152 | 154 | 209 | ||
153 | 155 | for command in [ self.cmd_list[key] for key in sorted(self.cmd_list.keys()) ]: | 210 | for command in [ self.cmd_list[key] for key in sorted(self.cmd_list.keys()) ]: |
155 | 156 | store.append([command['enabled'], command['name'], command['command']]) | 211 | store.append([command['enabled'], command['name'], command['command'], command['complex']]) |
156 | 157 | 212 | ||
157 | 158 | treeview = Gtk.TreeView(store) | 213 | treeview = Gtk.TreeView(store) |
158 | 159 | #treeview.connect("cursor-changed", self.on_cursor_changed, ui) | 214 | #treeview.connect("cursor-changed", self.on_cursor_changed, ui) |
159 | @@ -163,7 +218,7 @@ | |||
160 | 163 | ui['treeview'] = treeview | 218 | ui['treeview'] = treeview |
161 | 164 | 219 | ||
162 | 165 | renderer = Gtk.CellRendererToggle() | 220 | renderer = Gtk.CellRendererToggle() |
164 | 166 | renderer.connect('toggled', self.on_toggled, ui) | 221 | renderer.connect('toggled', self.on_toggled_enabled, ui) |
165 | 167 | column = Gtk.TreeViewColumn(_("Enabled"), renderer, active=CC_COL_ENABLED) | 222 | column = Gtk.TreeViewColumn(_("Enabled"), renderer, active=CC_COL_ENABLED) |
166 | 168 | treeview.append_column(column) | 223 | treeview.append_column(column) |
167 | 169 | 224 | ||
168 | @@ -175,6 +230,11 @@ | |||
169 | 175 | column = Gtk.TreeViewColumn(_("Command"), renderer, text=CC_COL_COMMAND) | 230 | column = Gtk.TreeViewColumn(_("Command"), renderer, text=CC_COL_COMMAND) |
170 | 176 | treeview.append_column(column) | 231 | treeview.append_column(column) |
171 | 177 | 232 | ||
172 | 233 | renderer = Gtk.CellRendererToggle() | ||
173 | 234 | renderer.connect('toggled', self.on_toggled_complex, ui) | ||
174 | 235 | column = Gtk.TreeViewColumn(_("Complex"), renderer, active=CC_COL_COMPLEX) | ||
175 | 236 | treeview.append_column(column) | ||
176 | 237 | |||
177 | 178 | scroll_window = Gtk.ScrolledWindow() | 238 | scroll_window = Gtk.ScrolledWindow() |
178 | 179 | scroll_window.set_size_request(500, 250) | 239 | scroll_window.set_size_request(500, 250) |
179 | 180 | scroll_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) | 240 | scroll_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) |
180 | @@ -246,28 +306,43 @@ | |||
181 | 246 | self.cmd_list = {} | 306 | self.cmd_list = {} |
182 | 247 | i=0 | 307 | i=0 |
183 | 248 | while iter: | 308 | while iter: |
185 | 249 | (enabled, name, command) = store.get(iter, | 309 | (enabled, name, command, cmplx) = store.get(iter, |
186 | 250 | CC_COL_ENABLED, | 310 | CC_COL_ENABLED, |
187 | 251 | CC_COL_NAME, | 311 | CC_COL_NAME, |
189 | 252 | CC_COL_COMMAND) | 312 | CC_COL_COMMAND, |
190 | 313 | CC_COL_COMPLEX) | ||
191 | 253 | self.cmd_list[i] = {'enabled' : enabled, | 314 | self.cmd_list[i] = {'enabled' : enabled, |
192 | 254 | 'name': name, | 315 | 'name': name, |
194 | 255 | 'command' : command} | 316 | 'command' : command, |
195 | 317 | 'complex' : cmplx} | ||
196 | 256 | iter = store.iter_next(iter) | 318 | iter = store.iter_next(iter) |
197 | 257 | i = i + 1 | 319 | i = i + 1 |
198 | 258 | 320 | ||
199 | 259 | 321 | ||
201 | 260 | def on_toggled(self, widget, path, data): | 322 | def on_toggled_enabled(self, widget, path, data): |
202 | 261 | treeview = data['treeview'] | 323 | treeview = data['treeview'] |
203 | 262 | store = treeview.get_model() | 324 | store = treeview.get_model() |
204 | 263 | iter = store.get_iter(path) | 325 | iter = store.get_iter(path) |
206 | 264 | (enabled, name, command) = store.get(iter, | 326 | (enabled, name, command, cmplx) = store.get(iter, |
207 | 265 | CC_COL_ENABLED, | 327 | CC_COL_ENABLED, |
208 | 266 | CC_COL_NAME, | 328 | CC_COL_NAME, |
210 | 267 | CC_COL_COMMAND | 329 | CC_COL_COMMAND, |
211 | 330 | CC_COL_COMPLEX | ||
212 | 268 | ) | 331 | ) |
213 | 269 | store.set_value(iter, CC_COL_ENABLED, not enabled) | 332 | store.set_value(iter, CC_COL_ENABLED, not enabled) |
214 | 270 | 333 | ||
215 | 334 | def on_toggled_complex(self, widget, path, data): | ||
216 | 335 | treeview = data['treeview'] | ||
217 | 336 | store = treeview.get_model() | ||
218 | 337 | iter = store.get_iter(path) | ||
219 | 338 | (enabled, name, command, cmplx) = store.get(iter, | ||
220 | 339 | CC_COL_ENABLED, | ||
221 | 340 | CC_COL_NAME, | ||
222 | 341 | CC_COL_COMMAND, | ||
223 | 342 | CC_COL_COMPLEX | ||
224 | 343 | ) | ||
225 | 344 | store.set_value(iter, CC_COL_COMPLEX, not cmplx) | ||
226 | 345 | |||
227 | 271 | 346 | ||
228 | 272 | def on_selection_changed(self,selection, data=None): | 347 | def on_selection_changed(self,selection, data=None): |
229 | 273 | treeview = selection.get_tree_view() | 348 | treeview = selection.get_tree_view() |
230 | @@ -279,7 +354,7 @@ | |||
231 | 279 | data['button_edit'].set_sensitive(iter is not None) | 354 | data['button_edit'].set_sensitive(iter is not None) |
232 | 280 | data['button_delete'].set_sensitive(iter is not None) | 355 | data['button_delete'].set_sensitive(iter is not None) |
233 | 281 | 356 | ||
235 | 282 | def _create_command_dialog(self, enabled_var = False, name_var = "", command_var = ""): | 357 | def _create_command_dialog(self, enabled_var = False, name_var = "", command_var = "",cmplx_var = False): |
236 | 283 | dialog = Gtk.Dialog( | 358 | dialog = Gtk.Dialog( |
237 | 284 | _("New Command"), | 359 | _("New Command"), |
238 | 285 | None, | 360 | None, |
239 | @@ -290,7 +365,7 @@ | |||
240 | 290 | ) | 365 | ) |
241 | 291 | ) | 366 | ) |
242 | 292 | dialog.set_transient_for(self.dbox) | 367 | dialog.set_transient_for(self.dbox) |
244 | 293 | table = Gtk.Table(3, 2) | 368 | table = Gtk.Table(6, 2) |
245 | 294 | 369 | ||
246 | 295 | label = Gtk.Label(label=_("Enabled:")) | 370 | label = Gtk.Label(label=_("Enabled:")) |
247 | 296 | table.attach(label, 0, 1, 0, 1) | 371 | table.attach(label, 0, 1, 0, 1) |
248 | @@ -309,19 +384,28 @@ | |||
249 | 309 | command = Gtk.Entry() | 384 | command = Gtk.Entry() |
250 | 310 | command.set_text(command_var) | 385 | command.set_text(command_var) |
251 | 311 | table.attach(command, 1, 2, 2, 3) | 386 | table.attach(command, 1, 2, 2, 3) |
252 | 387 | |||
253 | 388 | label = Gtk.Label(label=_("Complex:")) | ||
254 | 389 | table.attach(label, 0, 1, 3, 4) | ||
255 | 390 | cmplx = Gtk.CheckButton() | ||
256 | 391 | cmplx.set_active(cmplx_var) | ||
257 | 392 | table.attach(cmplx, 1, 2, 3, 4) | ||
258 | 393 | label = Gtk.Label(label=_('Complex Help: \n \\n - send end of line\n \\p - add 1 second delay')) | ||
259 | 394 | table.attach(label, 0, 2, 4, 6) | ||
260 | 312 | 395 | ||
261 | 313 | dialog.vbox.pack_start(table, True, True, 0) | 396 | dialog.vbox.pack_start(table, True, True, 0) |
262 | 314 | dialog.show_all() | 397 | dialog.show_all() |
264 | 315 | return (dialog,enabled,name,command) | 398 | return (dialog,enabled,name,command,cmplx) |
265 | 316 | 399 | ||
266 | 317 | def on_new(self, button, data): | 400 | def on_new(self, button, data): |
268 | 318 | (dialog,enabled,name,command) = self._create_command_dialog() | 401 | (dialog,enabled,name,command,cmplx) = self._create_command_dialog() |
269 | 319 | res = dialog.run() | 402 | res = dialog.run() |
270 | 320 | item = {} | 403 | item = {} |
271 | 321 | if res == Gtk.ResponseType.ACCEPT: | 404 | if res == Gtk.ResponseType.ACCEPT: |
272 | 322 | item['enabled'] = enabled.get_active() | 405 | item['enabled'] = enabled.get_active() |
273 | 323 | item['name'] = name.get_text() | 406 | item['name'] = name.get_text() |
274 | 324 | item['command'] = command.get_text() | 407 | item['command'] = command.get_text() |
275 | 408 | item['complex'] = cmplx.get_active() | ||
276 | 325 | if item['name'] == '' or item['command'] == '': | 409 | if item['name'] == '' or item['command'] == '': |
277 | 326 | err = Gtk.MessageDialog(dialog, | 410 | err = Gtk.MessageDialog(dialog, |
278 | 327 | Gtk.DialogFlags.MODAL, | 411 | Gtk.DialogFlags.MODAL, |
279 | @@ -342,7 +426,7 @@ | |||
280 | 342 | break | 426 | break |
281 | 343 | iter = store.iter_next(iter) | 427 | iter = store.iter_next(iter) |
282 | 344 | if not name_exist: | 428 | if not name_exist: |
284 | 345 | store.append((item['enabled'], item['name'], item['command'])) | 429 | store.append((item['enabled'], item['name'], item['command'], item['complex'])) |
285 | 346 | else: | 430 | else: |
286 | 347 | gerr(_("Name *%s* already exist") % item['name']) | 431 | gerr(_("Name *%s* already exist") % item['name']) |
287 | 348 | dialog.destroy() | 432 | dialog.destroy() |
288 | @@ -421,10 +505,11 @@ | |||
289 | 421 | if not iter: | 505 | if not iter: |
290 | 422 | return | 506 | return |
291 | 423 | 507 | ||
293 | 424 | (dialog,enabled,name,command) = self._create_command_dialog( | 508 | (dialog,enabled,name,command,cmplx) = self._create_command_dialog( |
294 | 425 | enabled_var = store.get_value(iter, CC_COL_ENABLED), | 509 | enabled_var = store.get_value(iter, CC_COL_ENABLED), |
295 | 426 | name_var = store.get_value(iter, CC_COL_NAME), | 510 | name_var = store.get_value(iter, CC_COL_NAME), |
297 | 427 | command_var = store.get_value(iter, CC_COL_COMMAND) | 511 | command_var = store.get_value(iter, CC_COL_COMMAND), |
298 | 512 | cmplx_var = store.get_value(iter, CC_COL_COMPLEX) | ||
299 | 428 | ) | 513 | ) |
300 | 429 | res = dialog.run() | 514 | res = dialog.run() |
301 | 430 | item = {} | 515 | item = {} |
302 | @@ -432,6 +517,7 @@ | |||
303 | 432 | item['enabled'] = enabled.get_active() | 517 | item['enabled'] = enabled.get_active() |
304 | 433 | item['name'] = name.get_text() | 518 | item['name'] = name.get_text() |
305 | 434 | item['command'] = command.get_text() | 519 | item['command'] = command.get_text() |
306 | 520 | item['complex'] = cmplx.get_active() | ||
307 | 435 | if item['name'] == '' or item['command'] == '': | 521 | if item['name'] == '' or item['command'] == '': |
308 | 436 | err = Gtk.MessageDialog(dialog, | 522 | err = Gtk.MessageDialog(dialog, |
309 | 437 | Gtk.DialogFlags.MODAL, | 523 | Gtk.DialogFlags.MODAL, |
310 | @@ -453,7 +539,8 @@ | |||
311 | 453 | store.set(iter, | 539 | store.set(iter, |
312 | 454 | CC_COL_ENABLED,item['enabled'], | 540 | CC_COL_ENABLED,item['enabled'], |
313 | 455 | CC_COL_NAME, item['name'], | 541 | CC_COL_NAME, item['name'], |
315 | 456 | CC_COL_COMMAND, item['command'] | 542 | CC_COL_COMMAND, item['command'], |
316 | 543 | CC_COL_COMPLEX, item['complex'] | ||
317 | 457 | ) | 544 | ) |
318 | 458 | else: | 545 | else: |
319 | 459 | gerr(_("Name *%s* already exist") % item['name']) | 546 | gerr(_("Name *%s* already exist") % item['name']) |
320 | 460 | 547 | ||
321 | === added file 'tests/test_custom_command_parser.py' | |||
322 | --- tests/test_custom_command_parser.py 1970-01-01 00:00:00 +0000 | |||
323 | +++ tests/test_custom_command_parser.py 2018-11-14 13:07:15 +0000 | |||
324 | @@ -0,0 +1,31 @@ | |||
325 | 1 | #!/usr/bin/env python2 | ||
326 | 2 | # Terminator by Chris Jones <cmsj@tenshu.net> | ||
327 | 3 | # GPL v2 only | ||
328 | 4 | # File created by Igor Korotin <Korotin.Igor.87@gmail.com> | ||
329 | 5 | |||
330 | 6 | import unittest | ||
331 | 7 | import re | ||
332 | 8 | import os | ||
333 | 9 | import sys, os.path | ||
334 | 10 | sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), ".."))) | ||
335 | 11 | |||
336 | 12 | from terminatorlib.plugins.custom_commands import CustomCommandsMenu | ||
337 | 13 | |||
338 | 14 | class TestCustomCommandParser(unittest.TestCase): | ||
339 | 15 | def test_parse(self): | ||
340 | 16 | menu = CustomCommandsMenu() | ||
341 | 17 | self.assertEqual(menu._parse( "word"), [{ 'command': 'word\n' , 'delay': 0}]) | ||
342 | 18 | self.assertEqual(menu._parse( "\\nword"), [{ 'command': '\n' , 'delay': 0}, { 'command': 'word\n', 'delay': 0}]) | ||
343 | 19 | self.assertEqual(menu._parse( "\\nword\\n\\n"), [{ 'command': '\n' , 'delay': 0}, { 'command': 'word\n', 'delay': 0}, {'command': '\n', 'delay': 0}, {'command': '\n', 'delay': 0}]) | ||
344 | 20 | self.assertEqual(menu._parse( "\\pword"), [{ 'command': 'word\n' , 'delay': 1}]) | ||
345 | 21 | self.assertEqual(menu._parse("\\p\\pword"), [{ 'command': 'word\n' , 'delay': 2}]) | ||
346 | 22 | self.assertEqual(menu._parse(" \\\\pword"), [{ 'command': ' \\' , 'delay': 0}, { 'command': 'word\n', 'delay': 1}]) | ||
347 | 23 | self.assertEqual(menu._parse( " word"), [{ 'command': ' word\n' , 'delay': 0}]) | ||
348 | 24 | self.assertEqual(menu._parse( "\\p word"), [{ 'command': ' word\n' , 'delay': 1}]) | ||
349 | 25 | self.assertEqual(menu._parse( "word\\p"), [{ 'command': 'word' , 'delay': 0}, { 'command': '\n' , 'delay': 1}]) | ||
350 | 26 | self.assertEqual(menu._parse("\\pword\\pword"), [{ 'command': 'word' , 'delay': 1}, { 'command': 'word\n', 'delay': 1}]) | ||
351 | 27 | self.assertEqual(menu._parse("\\pword\\word"), [{ 'command': 'word\\word\n', 'delay': 1}]) | ||
352 | 28 | self.assertEqual(menu._parse("\\p\\nword\\n\\p"), [{ 'command': '\n' , 'delay': 1}, { 'command': 'word\n', 'delay': 0}, {'command': '\n', 'delay': 1}]) | ||
353 | 29 | |||
354 | 30 | if __name__ == '__main__': | ||
355 | 31 | unittest.main() |