Merge lp:~statik/terminator/terminator-test-discovery into lp:terminator/trunk

Proposed by Elliot Murphy
Status: Merged
Merge reported by: Chris Jones
Merged at revision: not available
Proposed branch: lp:~statik/terminator/terminator-test-discovery
Merge into: lp:terminator/trunk
Diff against target: 12198 lines (+10849/-815)
39 files modified
data/preferences.glade (+1958/-0)
debian/control (+8/-0)
doc/terminator_config.5 (+0/-4)
terminator (+53/-20)
terminatorlib/__init__.py (+2/-1)
terminatorlib/borg.py (+107/-0)
terminatorlib/config.py (+414/-407)
terminatorlib/configfile.py (+0/-233)
terminatorlib/configobj/configobj.py (+2455/-0)
terminatorlib/configobj/validate.py (+1465/-0)
terminatorlib/container.py (+189/-0)
terminatorlib/cwd.py (+43/-0)
terminatorlib/debugserver.py (+1/-1)
terminatorlib/editablelabel.py (+49/-34)
terminatorlib/encoding.py (+89/-87)
terminatorlib/factory.py (+81/-0)
terminatorlib/keybindings.py (+107/-10)
terminatorlib/newterminator.py (+219/-0)
terminatorlib/notebook.py (+339/-0)
terminatorlib/optionparse.py (+101/-0)
terminatorlib/paned.py (+194/-0)
terminatorlib/plugin.py (+114/-0)
terminatorlib/plugins/terminal_menu.py (+29/-0)
terminatorlib/plugins/testplugin.py (+11/-0)
terminatorlib/plugins/url_handlers.py (+63/-0)
terminatorlib/prefseditor.py (+441/-0)
terminatorlib/pylint.sh (+11/-0)
terminatorlib/searchbar.py (+195/-0)
terminatorlib/terminal.py (+1113/-0)
terminatorlib/terminal_popup_menu.py (+244/-0)
terminatorlib/terminator.py (+60/-4)
terminatorlib/terminatorterm.py (+12/-3)
terminatorlib/tests/test_doctests.py (+13/-0)
terminatorlib/titlebar.py (+153/-0)
terminatorlib/translation.py (+16/-10)
terminatorlib/util.py (+148/-0)
terminatorlib/version.py (+5/-1)
terminatorlib/window.py (+330/-0)
test.py (+17/-0)
To merge this branch: bzr merge lp:~statik/terminator/terminator-test-discovery
Reviewer Review Type Date Requested Status
Chris Jones (community) Approve
Review via email: mp+16831@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Elliot Murphy (statik) wrote :

Hooks up test discovery for doctest so that

    trial terminatorlib

will now run the doctests.

I tried to propose this for merging into lp:~cmsj/+junk/terminator-epic-refactor, but launchpad doesn't allow merge proposals to or from +junk branches. Maybe move the epic refactor out of +junk ;)

Revision history for this message
Chris Jones (cmsj) wrote :

A fair point about the branch being in +junk. It's now way too far advanced to live there, so I'll move that out shortly.

(I recoiled in horror when I saw the diff was 12k lines, but I see against epic-refactor it's deliciously small and I will absolutely accept and merge it, thanks very much!)

review: Approve
Revision history for this message
Chris Jones (cmsj) wrote :

Merged into the newly pushed lp:~cmsj/terminator/epic-refactor

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'data/preferences.glade'
2--- data/preferences.glade 1970-01-01 00:00:00 +0000
3+++ data/preferences.glade 2010-01-05 05:03:15 +0000
4@@ -0,0 +1,1958 @@
5+<?xml version="1.0"?>
6+<interface>
7+ <requires lib="gtk+" version="2.16"/>
8+ <!-- interface-naming-policy project-wide -->
9+ <object class="GtkListStore" id="ProfilesListStore">
10+ <columns>
11+ <!-- column-name Profile -->
12+ <column type="gchararray"/>
13+ </columns>
14+ <data>
15+ <row>
16+ <col id="0" translatable="yes">Default</col>
17+ </row>
18+ </data>
19+ </object>
20+ <object class="GtkListStore" id="KeybindingsListStore">
21+ <columns>
22+ <!-- column-name Name -->
23+ <column type="gchararray"/>
24+ <!-- column-name Action -->
25+ <column type="gchararray"/>
26+ <!-- column-name Keyboard -->
27+ <column type="GtkCellRendererAccelMode"/>
28+ </columns>
29+ </object>
30+ <object class="GtkDialog" id="prefswin">
31+ <property name="border_width">5</property>
32+ <property name="type_hint">normal</property>
33+ <property name="has_separator">False</property>
34+ <child internal-child="vbox">
35+ <object class="GtkVBox" id="dialog-vbox1">
36+ <property name="visible">True</property>
37+ <property name="orientation">vertical</property>
38+ <property name="spacing">2</property>
39+ <child>
40+ <object class="GtkNotebook" id="notebook1">
41+ <property name="visible">True</property>
42+ <property name="can_focus">True</property>
43+ <child>
44+ <object class="GtkTable" id="global_config_table">
45+ <property name="visible">True</property>
46+ <property name="n_rows">6</property>
47+ <property name="n_columns">2</property>
48+ <child>
49+ <object class="GtkComboBox" id="focuscombo">
50+ <property name="visible">True</property>
51+ </object>
52+ <packing>
53+ <property name="left_attach">1</property>
54+ <property name="right_attach">2</property>
55+ <property name="x_options"></property>
56+ <property name="y_options">GTK_EXPAND</property>
57+ </packing>
58+ </child>
59+ <child>
60+ <object class="GtkLabel" id="label6">
61+ <property name="visible">True</property>
62+ <property name="label" translatable="yes">Mouse focus</property>
63+ </object>
64+ <packing>
65+ <property name="x_options"></property>
66+ <property name="y_options"></property>
67+ </packing>
68+ </child>
69+ <child>
70+ <object class="GtkLabel" id="label7">
71+ <property name="visible">True</property>
72+ <property name="label" translatable="yes">Terminal separator size</property>
73+ </object>
74+ <packing>
75+ <property name="top_attach">1</property>
76+ <property name="bottom_attach">2</property>
77+ <property name="x_options"></property>
78+ <property name="y_options"></property>
79+ </packing>
80+ </child>
81+ <child>
82+ <object class="GtkHScale" id="handlesize">
83+ <property name="visible">True</property>
84+ <property name="can_focus">True</property>
85+ <property name="digits">0</property>
86+ <property name="value_pos">left</property>
87+ </object>
88+ <packing>
89+ <property name="left_attach">1</property>
90+ <property name="right_attach">2</property>
91+ <property name="top_attach">1</property>
92+ <property name="bottom_attach">2</property>
93+ <property name="y_options">GTK_EXPAND</property>
94+ <property name="x_padding">20</property>
95+ </packing>
96+ </child>
97+ <child>
98+ <object class="GtkLabel" id="label8">
99+ <property name="visible">True</property>
100+ <property name="label" translatable="yes">Window geometry hints</property>
101+ </object>
102+ <packing>
103+ <property name="top_attach">2</property>
104+ <property name="bottom_attach">3</property>
105+ <property name="x_options"></property>
106+ <property name="y_options"></property>
107+ </packing>
108+ </child>
109+ <child>
110+ <object class="GtkCheckButton" id="wingeomcheck">
111+ <property name="visible">True</property>
112+ <property name="can_focus">True</property>
113+ <property name="receives_default">False</property>
114+ <property name="active">True</property>
115+ <property name="draw_indicator">True</property>
116+ </object>
117+ <packing>
118+ <property name="left_attach">1</property>
119+ <property name="right_attach">2</property>
120+ <property name="top_attach">2</property>
121+ <property name="bottom_attach">3</property>
122+ <property name="x_options"></property>
123+ <property name="y_options">GTK_EXPAND</property>
124+ </packing>
125+ </child>
126+ <child>
127+ <object class="GtkLabel" id="label9">
128+ <property name="visible">True</property>
129+ <property name="label" translatable="yes">Window state</property>
130+ </object>
131+ <packing>
132+ <property name="top_attach">3</property>
133+ <property name="bottom_attach">4</property>
134+ <property name="x_options"></property>
135+ <property name="y_options"></property>
136+ </packing>
137+ </child>
138+ <child>
139+ <object class="GtkComboBox" id="winstatecombo">
140+ <property name="visible">True</property>
141+ </object>
142+ <packing>
143+ <property name="left_attach">1</property>
144+ <property name="right_attach">2</property>
145+ <property name="top_attach">3</property>
146+ <property name="bottom_attach">4</property>
147+ <property name="x_options"></property>
148+ <property name="y_options">GTK_EXPAND</property>
149+ </packing>
150+ </child>
151+ <child>
152+ <object class="GtkLabel" id="label10">
153+ <property name="visible">True</property>
154+ <property name="label" translatable="yes">Window borders</property>
155+ </object>
156+ <packing>
157+ <property name="top_attach">4</property>
158+ <property name="bottom_attach">5</property>
159+ <property name="x_options"></property>
160+ <property name="y_options"></property>
161+ </packing>
162+ </child>
163+ <child>
164+ <object class="GtkCheckButton" id="winbordercheck">
165+ <property name="visible">True</property>
166+ <property name="can_focus">True</property>
167+ <property name="receives_default">False</property>
168+ <property name="active">True</property>
169+ <property name="draw_indicator">True</property>
170+ </object>
171+ <packing>
172+ <property name="left_attach">1</property>
173+ <property name="right_attach">2</property>
174+ <property name="top_attach">4</property>
175+ <property name="bottom_attach">5</property>
176+ <property name="x_options"></property>
177+ <property name="y_options">GTK_EXPAND</property>
178+ </packing>
179+ </child>
180+ <child>
181+ <object class="GtkLabel" id="label11">
182+ <property name="visible">True</property>
183+ <property name="label" translatable="yes">Tab position</property>
184+ </object>
185+ <packing>
186+ <property name="top_attach">5</property>
187+ <property name="bottom_attach">6</property>
188+ <property name="x_options"></property>
189+ <property name="y_options"></property>
190+ </packing>
191+ </child>
192+ <child>
193+ <object class="GtkComboBox" id="tabposcombo">
194+ <property name="visible">True</property>
195+ </object>
196+ <packing>
197+ <property name="left_attach">1</property>
198+ <property name="right_attach">2</property>
199+ <property name="top_attach">5</property>
200+ <property name="bottom_attach">6</property>
201+ <property name="x_options"></property>
202+ <property name="y_options">GTK_EXPAND</property>
203+ </packing>
204+ </child>
205+ </object>
206+ </child>
207+ <child type="tab">
208+ <object class="GtkLabel" id="label1">
209+ <property name="visible">True</property>
210+ <property name="label" translatable="yes">Global</property>
211+ </object>
212+ <packing>
213+ <property name="tab_fill">False</property>
214+ </packing>
215+ </child>
216+ <child>
217+ <object class="GtkHBox" id="hbox1">
218+ <property name="visible">True</property>
219+ <child>
220+ <object class="GtkTreeView" id="treeview1">
221+ <property name="visible">True</property>
222+ <property name="can_focus">True</property>
223+ <property name="model">ProfilesListStore</property>
224+ </object>
225+ <packing>
226+ <property name="expand">False</property>
227+ <property name="position">0</property>
228+ </packing>
229+ </child>
230+ <child>
231+ <object class="GtkNotebook" id="profile-editor-notebook">
232+ <property name="visible">True</property>
233+ <property name="can_focus">True</property>
234+ <property name="border_width">5</property>
235+ <child>
236+ <object class="GtkVBox" id="vbox3">
237+ <property name="visible">True</property>
238+ <property name="border_width">12</property>
239+ <property name="orientation">vertical</property>
240+ <property name="spacing">6</property>
241+ <child>
242+ <object class="GtkHBox" id="hbox135">
243+ <property name="visible">True</property>
244+ <property name="spacing">12</property>
245+ <child>
246+ <object class="GtkLabel" id="profile-name-label">
247+ <property name="visible">True</property>
248+ <property name="xalign">0</property>
249+ <property name="xpad">4</property>
250+ <property name="label" translatable="yes">_Profile name:</property>
251+ <property name="use_underline">True</property>
252+ <property name="justify">center</property>
253+ <property name="mnemonic_widget">profile-name-entry</property>
254+ </object>
255+ <packing>
256+ <property name="expand">False</property>
257+ <property name="fill">False</property>
258+ <property name="position">0</property>
259+ </packing>
260+ </child>
261+ <child>
262+ <object class="GtkEntry" id="profile-name-entry">
263+ <property name="visible">True</property>
264+ <property name="can_focus">True</property>
265+ <property name="invisible_char">&#x2022;</property>
266+ </object>
267+ <packing>
268+ <property name="position">1</property>
269+ </packing>
270+ </child>
271+ </object>
272+ <packing>
273+ <property name="expand">False</property>
274+ <property name="fill">False</property>
275+ <property name="position">0</property>
276+ </packing>
277+ </child>
278+ <child>
279+ <object class="GtkCheckButton" id="system-font-checkbutton">
280+ <property name="label" translatable="yes">_Use the system fixed width font</property>
281+ <property name="visible">True</property>
282+ <property name="can_focus">True</property>
283+ <property name="receives_default">False</property>
284+ <property name="use_underline">True</property>
285+ <property name="draw_indicator">True</property>
286+ </object>
287+ <packing>
288+ <property name="expand">False</property>
289+ <property name="fill">False</property>
290+ <property name="position">1</property>
291+ </packing>
292+ </child>
293+ <child>
294+ <object class="GtkAlignment" id="alignment10109">
295+ <property name="visible">True</property>
296+ <property name="left_padding">12</property>
297+ <child>
298+ <object class="GtkHBox" id="font-hbox">
299+ <property name="visible">True</property>
300+ <property name="spacing">12</property>
301+ <child>
302+ <object class="GtkLabel" id="font-selector-label">
303+ <property name="visible">True</property>
304+ <property name="xalign">0</property>
305+ <property name="label" translatable="yes">_Font:</property>
306+ <property name="use_underline">True</property>
307+ <property name="mnemonic_widget">font-selector</property>
308+ </object>
309+ <packing>
310+ <property name="expand">False</property>
311+ <property name="fill">False</property>
312+ <property name="position">0</property>
313+ </packing>
314+ </child>
315+ <child>
316+ <object class="GtkFontButton" id="font-selector">
317+ <property name="visible">True</property>
318+ <property name="can_focus">True</property>
319+ <property name="receives_default">True</property>
320+ <property name="focus_on_click">False</property>
321+ <property name="title" translatable="yes">Choose A Terminal Font</property>
322+ <property name="use_font">True</property>
323+ <property name="use_size">True</property>
324+ </object>
325+ <packing>
326+ <property name="expand">False</property>
327+ <property name="fill">False</property>
328+ <property name="position">1</property>
329+ </packing>
330+ </child>
331+ </object>
332+ </child>
333+ </object>
334+ <packing>
335+ <property name="expand">False</property>
336+ <property name="fill">False</property>
337+ <property name="position">2</property>
338+ </packing>
339+ </child>
340+ <child>
341+ <object class="GtkCheckButton" id="allow-bold-checkbutton">
342+ <property name="label" translatable="yes">_Allow bold text</property>
343+ <property name="visible">True</property>
344+ <property name="can_focus">True</property>
345+ <property name="receives_default">False</property>
346+ <property name="use_underline">True</property>
347+ <property name="draw_indicator">True</property>
348+ </object>
349+ <packing>
350+ <property name="expand">False</property>
351+ <property name="fill">False</property>
352+ <property name="position">3</property>
353+ </packing>
354+ </child>
355+ <child>
356+ <object class="GtkCheckButton" id="show-menubar-checkbutton">
357+ <property name="label" translatable="yes">Show _menubar by default in new terminals</property>
358+ <property name="visible">True</property>
359+ <property name="can_focus">True</property>
360+ <property name="receives_default">False</property>
361+ <property name="use_underline">True</property>
362+ <property name="draw_indicator">True</property>
363+ </object>
364+ <packing>
365+ <property name="expand">False</property>
366+ <property name="fill">False</property>
367+ <property name="position">4</property>
368+ </packing>
369+ </child>
370+ <child>
371+ <object class="GtkCheckButton" id="bell-checkbutton">
372+ <property name="label" translatable="yes">Terminal _bell</property>
373+ <property name="visible">True</property>
374+ <property name="can_focus">True</property>
375+ <property name="receives_default">False</property>
376+ <property name="use_underline">True</property>
377+ <property name="draw_indicator">True</property>
378+ </object>
379+ <packing>
380+ <property name="expand">False</property>
381+ <property name="fill">False</property>
382+ <property name="position">5</property>
383+ </packing>
384+ </child>
385+ <child>
386+ <object class="GtkHBox" id="hbox140">
387+ <property name="visible">True</property>
388+ <property name="spacing">12</property>
389+ <child>
390+ <object class="GtkLabel" id="label480">
391+ <property name="visible">True</property>
392+ <property name="label" translatable="yes">Cursor _shape:</property>
393+ <property name="use_underline">True</property>
394+ <property name="mnemonic_widget">cursor-shape-combobox</property>
395+ </object>
396+ <packing>
397+ <property name="expand">False</property>
398+ <property name="fill">False</property>
399+ <property name="position">0</property>
400+ </packing>
401+ </child>
402+ <child>
403+ <object class="GtkComboBox" id="cursor-shape-combobox">
404+ <property name="visible">True</property>
405+ </object>
406+ <packing>
407+ <property name="expand">False</property>
408+ <property name="position">1</property>
409+ </packing>
410+ </child>
411+ </object>
412+ <packing>
413+ <property name="expand">False</property>
414+ <property name="position">6</property>
415+ </packing>
416+ </child>
417+ <child>
418+ <object class="GtkHBox" id="hbox136">
419+ <property name="visible">True</property>
420+ <property name="spacing">12</property>
421+ <child>
422+ <object class="GtkLabel" id="word-chars-entry-label">
423+ <property name="visible">True</property>
424+ <property name="xalign">0</property>
425+ <property name="label" translatable="yes">Select-by-_word characters:</property>
426+ <property name="use_underline">True</property>
427+ <property name="justify">center</property>
428+ <property name="mnemonic_widget">word-chars-entry</property>
429+ </object>
430+ <packing>
431+ <property name="expand">False</property>
432+ <property name="fill">False</property>
433+ <property name="position">0</property>
434+ </packing>
435+ </child>
436+ <child>
437+ <object class="GtkEntry" id="word-chars-entry">
438+ <property name="visible">True</property>
439+ <property name="can_focus">True</property>
440+ <property name="invisible_char">&#x2022;</property>
441+ </object>
442+ <packing>
443+ <property name="position">1</property>
444+ </packing>
445+ </child>
446+ </object>
447+ <packing>
448+ <property name="expand">False</property>
449+ <property name="position">7</property>
450+ </packing>
451+ </child>
452+ </object>
453+ </child>
454+ <child type="tab">
455+ <object class="GtkLabel" id="label32">
456+ <property name="visible">True</property>
457+ <property name="label" translatable="yes">General</property>
458+ <property name="use_underline">True</property>
459+ <property name="justify">center</property>
460+ </object>
461+ <packing>
462+ <property name="tab_fill">False</property>
463+ </packing>
464+ </child>
465+ <child>
466+ <object class="GtkVBox" id="vbox91">
467+ <property name="visible">True</property>
468+ <property name="border_width">12</property>
469+ <property name="orientation">vertical</property>
470+ <property name="spacing">18</property>
471+ <child>
472+ <object class="GtkVBox" id="vbox79">
473+ <property name="visible">True</property>
474+ <property name="orientation">vertical</property>
475+ <property name="spacing">6</property>
476+ <child>
477+ <object class="GtkLabel" id="label33">
478+ <property name="visible">True</property>
479+ <property name="xalign">0</property>
480+ <property name="label" translatable="yes">&lt;b&gt;Title&lt;/b&gt;</property>
481+ <property name="use_markup">True</property>
482+ </object>
483+ <packing>
484+ <property name="expand">False</property>
485+ <property name="fill">False</property>
486+ <property name="position">0</property>
487+ </packing>
488+ </child>
489+ <child>
490+ <object class="GtkAlignment" id="alignment10108">
491+ <property name="visible">True</property>
492+ <property name="left_padding">12</property>
493+ <child>
494+ <object class="GtkVBox" id="vbox93">
495+ <property name="visible">True</property>
496+ <property name="orientation">vertical</property>
497+ <property name="spacing">6</property>
498+ <child>
499+ <object class="GtkHBox" id="hbox137">
500+ <property name="visible">True</property>
501+ <property name="spacing">12</property>
502+ <child>
503+ <object class="GtkLabel" id="title-entry-label">
504+ <property name="visible">True</property>
505+ <property name="xalign">0</property>
506+ <property name="label" translatable="yes">Initial _title:</property>
507+ <property name="use_underline">True</property>
508+ <property name="justify">center</property>
509+ <property name="mnemonic_widget">title-entry</property>
510+ </object>
511+ <packing>
512+ <property name="expand">False</property>
513+ <property name="fill">False</property>
514+ <property name="position">0</property>
515+ </packing>
516+ </child>
517+ <child>
518+ <object class="GtkEntry" id="title-entry">
519+ <property name="visible">True</property>
520+ <property name="can_focus">True</property>
521+ <property name="invisible_char">&#x2022;</property>
522+ </object>
523+ <packing>
524+ <property name="position">1</property>
525+ </packing>
526+ </child>
527+ </object>
528+ <packing>
529+ <property name="position">0</property>
530+ </packing>
531+ </child>
532+ <child>
533+ <object class="GtkHBox" id="hbox138">
534+ <property name="visible">True</property>
535+ <property name="spacing">12</property>
536+ <child>
537+ <object class="GtkLabel" id="title-mode-combobox-label">
538+ <property name="visible">True</property>
539+ <property name="xalign">0</property>
540+ <property name="label" translatable="yes">When terminal commands set their o_wn titles:</property>
541+ <property name="use_underline">True</property>
542+ <property name="justify">center</property>
543+ <property name="mnemonic_widget">title-mode-combobox</property>
544+ </object>
545+ <packing>
546+ <property name="expand">False</property>
547+ <property name="fill">False</property>
548+ <property name="position">0</property>
549+ </packing>
550+ </child>
551+ <child>
552+ <object class="GtkComboBox" id="title-mode-combobox">
553+ <property name="visible">True</property>
554+ </object>
555+ <packing>
556+ <property name="position">1</property>
557+ </packing>
558+ </child>
559+ </object>
560+ <packing>
561+ <property name="position">1</property>
562+ </packing>
563+ </child>
564+ </object>
565+ </child>
566+ </object>
567+ <packing>
568+ <property name="expand">False</property>
569+ <property name="position">1</property>
570+ </packing>
571+ </child>
572+ </object>
573+ <packing>
574+ <property name="expand">False</property>
575+ <property name="position">0</property>
576+ </packing>
577+ </child>
578+ <child>
579+ <object class="GtkVBox" id="vbox80">
580+ <property name="visible">True</property>
581+ <property name="orientation">vertical</property>
582+ <property name="spacing">6</property>
583+ <child>
584+ <object class="GtkLabel" id="label36">
585+ <property name="visible">True</property>
586+ <property name="xalign">0</property>
587+ <property name="label" translatable="yes">&lt;b&gt;Command&lt;/b&gt;</property>
588+ <property name="use_markup">True</property>
589+ </object>
590+ <packing>
591+ <property name="expand">False</property>
592+ <property name="fill">False</property>
593+ <property name="position">0</property>
594+ </packing>
595+ </child>
596+ <child>
597+ <object class="GtkAlignment" id="alignment10107">
598+ <property name="visible">True</property>
599+ <property name="left_padding">12</property>
600+ <child>
601+ <object class="GtkVBox" id="vbox81">
602+ <property name="visible">True</property>
603+ <property name="orientation">vertical</property>
604+ <child>
605+ <object class="GtkVBox" id="vbox92">
606+ <property name="visible">True</property>
607+ <property name="orientation">vertical</property>
608+ <property name="spacing">6</property>
609+ <child>
610+ <object class="GtkCheckButton" id="login-shell-checkbutton">
611+ <property name="label" translatable="yes">_Run command as a login shell</property>
612+ <property name="visible">True</property>
613+ <property name="can_focus">True</property>
614+ <property name="receives_default">False</property>
615+ <property name="use_underline">True</property>
616+ <property name="draw_indicator">True</property>
617+ </object>
618+ <packing>
619+ <property name="expand">False</property>
620+ <property name="fill">False</property>
621+ <property name="position">0</property>
622+ </packing>
623+ </child>
624+ <child>
625+ <object class="GtkCheckButton" id="update-records-checkbutton">
626+ <property name="label" translatable="yes">_Update login records when command is launched</property>
627+ <property name="visible">True</property>
628+ <property name="can_focus">True</property>
629+ <property name="receives_default">False</property>
630+ <property name="use_underline">True</property>
631+ <property name="draw_indicator">True</property>
632+ </object>
633+ <packing>
634+ <property name="expand">False</property>
635+ <property name="fill">False</property>
636+ <property name="position">1</property>
637+ </packing>
638+ </child>
639+ <child>
640+ <object class="GtkCheckButton" id="use-custom-command-checkbutton">
641+ <property name="label" translatable="yes">Ru_n a custom command instead of my shell</property>
642+ <property name="visible">True</property>
643+ <property name="can_focus">True</property>
644+ <property name="receives_default">False</property>
645+ <property name="use_underline">True</property>
646+ <property name="draw_indicator">True</property>
647+ </object>
648+ <packing>
649+ <property name="expand">False</property>
650+ <property name="fill">False</property>
651+ <property name="position">2</property>
652+ </packing>
653+ </child>
654+ <child>
655+ <object class="GtkAlignment" id="custom-command-box">
656+ <property name="visible">True</property>
657+ <property name="left_padding">12</property>
658+ <child>
659+ <object class="GtkHBox" id="hbox134">
660+ <property name="visible">True</property>
661+ <property name="spacing">12</property>
662+ <child>
663+ <object class="GtkLabel" id="custom-command-entry-label">
664+ <property name="visible">True</property>
665+ <property name="xalign">0</property>
666+ <property name="label" translatable="yes">Custom co_mmand:</property>
667+ <property name="use_underline">True</property>
668+ <property name="justify">center</property>
669+ <property name="mnemonic_widget">custom-command-entry</property>
670+ </object>
671+ <packing>
672+ <property name="expand">False</property>
673+ <property name="fill">False</property>
674+ <property name="position">0</property>
675+ </packing>
676+ </child>
677+ <child>
678+ <object class="GtkEntry" id="custom-command-entry">
679+ <property name="visible">True</property>
680+ <property name="can_focus">True</property>
681+ <property name="invisible_char">&#x2022;</property>
682+ </object>
683+ <packing>
684+ <property name="position">1</property>
685+ </packing>
686+ </child>
687+ </object>
688+ </child>
689+ </object>
690+ <packing>
691+ <property name="expand">False</property>
692+ <property name="position">3</property>
693+ </packing>
694+ </child>
695+ <child>
696+ <object class="GtkHBox" id="hbox27">
697+ <property name="visible">True</property>
698+ <property name="spacing">12</property>
699+ <child>
700+ <object class="GtkLabel" id="exit-action-combobox-label">
701+ <property name="visible">True</property>
702+ <property name="xalign">0</property>
703+ <property name="label" translatable="yes">When command _exits:</property>
704+ <property name="use_underline">True</property>
705+ <property name="justify">center</property>
706+ <property name="mnemonic_widget">exit-action-combobox</property>
707+ </object>
708+ <packing>
709+ <property name="expand">False</property>
710+ <property name="fill">False</property>
711+ <property name="position">0</property>
712+ </packing>
713+ </child>
714+ <child>
715+ <object class="GtkComboBox" id="exit-action-combobox">
716+ <property name="visible">True</property>
717+ </object>
718+ <packing>
719+ <property name="position">1</property>
720+ </packing>
721+ </child>
722+ </object>
723+ <packing>
724+ <property name="position">4</property>
725+ </packing>
726+ </child>
727+ </object>
728+ <packing>
729+ <property name="expand">False</property>
730+ <property name="position">0</property>
731+ </packing>
732+ </child>
733+ </object>
734+ </child>
735+ </object>
736+ <packing>
737+ <property name="expand">False</property>
738+ <property name="position">1</property>
739+ </packing>
740+ </child>
741+ </object>
742+ <packing>
743+ <property name="expand">False</property>
744+ <property name="position">1</property>
745+ </packing>
746+ </child>
747+ </object>
748+ <packing>
749+ <property name="position">1</property>
750+ </packing>
751+ </child>
752+ <child type="tab">
753+ <object class="GtkLabel" id="label38">
754+ <property name="visible">True</property>
755+ <property name="label" translatable="yes">Title and Command</property>
756+ <property name="use_underline">True</property>
757+ <property name="justify">center</property>
758+ </object>
759+ <packing>
760+ <property name="position">1</property>
761+ <property name="tab_fill">False</property>
762+ </packing>
763+ </child>
764+ <child>
765+ <object class="GtkVBox" id="vbox90">
766+ <property name="visible">True</property>
767+ <property name="border_width">12</property>
768+ <property name="orientation">vertical</property>
769+ <property name="spacing">18</property>
770+ <child>
771+ <object class="GtkVBox" id="vbox82">
772+ <property name="visible">True</property>
773+ <property name="orientation">vertical</property>
774+ <property name="spacing">6</property>
775+ <child>
776+ <object class="GtkLabel" id="label39">
777+ <property name="visible">True</property>
778+ <property name="xalign">0</property>
779+ <property name="label" translatable="yes">&lt;b&gt;Foreground and Background&lt;/b&gt;</property>
780+ <property name="use_markup">True</property>
781+ </object>
782+ <packing>
783+ <property name="expand">False</property>
784+ <property name="fill">False</property>
785+ <property name="position">0</property>
786+ </packing>
787+ </child>
788+ <child>
789+ <object class="GtkAlignment" id="alignment10105">
790+ <property name="visible">True</property>
791+ <property name="left_padding">12</property>
792+ <child>
793+ <object class="GtkTable" id="table24">
794+ <property name="visible">True</property>
795+ <property name="n_rows">4</property>
796+ <property name="n_columns">2</property>
797+ <property name="column_spacing">12</property>
798+ <property name="row_spacing">6</property>
799+ <child>
800+ <object class="GtkLabel" id="foreground-colorpicker-label">
801+ <property name="visible">True</property>
802+ <property name="xalign">0</property>
803+ <property name="label" translatable="yes">_Text color:</property>
804+ <property name="use_underline">True</property>
805+ <property name="justify">center</property>
806+ <property name="mnemonic_widget">foreground-colorpicker</property>
807+ </object>
808+ <packing>
809+ <property name="top_attach">2</property>
810+ <property name="bottom_attach">3</property>
811+ <property name="x_options">GTK_FILL</property>
812+ <property name="y_options"></property>
813+ </packing>
814+ </child>
815+ <child>
816+ <object class="GtkCheckButton" id="use-theme-colors-checkbutton">
817+ <property name="label" translatable="yes">_Use colors from system theme</property>
818+ <property name="visible">True</property>
819+ <property name="can_focus">True</property>
820+ <property name="receives_default">False</property>
821+ <property name="use_underline">True</property>
822+ <property name="draw_indicator">True</property>
823+ </object>
824+ <packing>
825+ <property name="right_attach">2</property>
826+ <property name="x_options">GTK_FILL</property>
827+ <property name="y_options"></property>
828+ </packing>
829+ </child>
830+ <child>
831+ <object class="GtkLabel" id="background-colorpicker-label">
832+ <property name="visible">True</property>
833+ <property name="xalign">0</property>
834+ <property name="label" translatable="yes">_Background color:</property>
835+ <property name="use_underline">True</property>
836+ <property name="justify">center</property>
837+ <property name="mnemonic_widget">background-colorpicker</property>
838+ </object>
839+ <packing>
840+ <property name="top_attach">3</property>
841+ <property name="bottom_attach">4</property>
842+ <property name="x_options">GTK_FILL</property>
843+ <property name="y_options"></property>
844+ </packing>
845+ </child>
846+ <child>
847+ <object class="GtkLabel" id="color-scheme-combobox-label">
848+ <property name="visible">True</property>
849+ <property name="xalign">0</property>
850+ <property name="label" translatable="yes">Built-in sche_mes:</property>
851+ <property name="use_underline">True</property>
852+ <property name="justify">center</property>
853+ <property name="mnemonic_widget">color-scheme-combobox</property>
854+ </object>
855+ <packing>
856+ <property name="top_attach">1</property>
857+ <property name="bottom_attach">2</property>
858+ <property name="x_options">GTK_FILL</property>
859+ <property name="y_options"></property>
860+ </packing>
861+ </child>
862+ <child>
863+ <object class="GtkHBox" id="hbox18">
864+ <property name="visible">True</property>
865+ <child>
866+ <object class="GtkColorButton" id="foreground-colorpicker">
867+ <property name="visible">True</property>
868+ <property name="can_focus">True</property>
869+ <property name="receives_default">True</property>
870+ <property name="title" translatable="yes">Choose Terminal Text Color</property>
871+ <property name="color">#000000000000</property>
872+ </object>
873+ <packing>
874+ <property name="expand">False</property>
875+ <property name="fill">False</property>
876+ <property name="position">0</property>
877+ </packing>
878+ </child>
879+ <child>
880+ <placeholder/>
881+ </child>
882+ </object>
883+ <packing>
884+ <property name="left_attach">1</property>
885+ <property name="right_attach">2</property>
886+ <property name="top_attach">2</property>
887+ <property name="bottom_attach">3</property>
888+ <property name="x_options">GTK_FILL</property>
889+ <property name="y_options">GTK_FILL</property>
890+ </packing>
891+ </child>
892+ <child>
893+ <object class="GtkHBox" id="hbox19">
894+ <property name="visible">True</property>
895+ <child>
896+ <object class="GtkColorButton" id="background-colorpicker">
897+ <property name="visible">True</property>
898+ <property name="can_focus">True</property>
899+ <property name="receives_default">True</property>
900+ <property name="title" translatable="yes">Choose Terminal Background Color</property>
901+ <property name="color">#000000000000</property>
902+ </object>
903+ <packing>
904+ <property name="expand">False</property>
905+ <property name="fill">False</property>
906+ <property name="position">0</property>
907+ </packing>
908+ </child>
909+ <child>
910+ <placeholder/>
911+ </child>
912+ </object>
913+ <packing>
914+ <property name="left_attach">1</property>
915+ <property name="right_attach">2</property>
916+ <property name="top_attach">3</property>
917+ <property name="bottom_attach">4</property>
918+ <property name="x_options">GTK_FILL</property>
919+ <property name="y_options">GTK_FILL</property>
920+ </packing>
921+ </child>
922+ <child>
923+ <object class="GtkComboBox" id="color-scheme-combobox">
924+ <property name="visible">True</property>
925+ </object>
926+ <packing>
927+ <property name="left_attach">1</property>
928+ <property name="right_attach">2</property>
929+ <property name="top_attach">1</property>
930+ <property name="bottom_attach">2</property>
931+ <property name="y_options">GTK_FILL</property>
932+ </packing>
933+ </child>
934+ </object>
935+ </child>
936+ </object>
937+ <packing>
938+ <property name="expand">False</property>
939+ <property name="position">1</property>
940+ </packing>
941+ </child>
942+ </object>
943+ <packing>
944+ <property name="expand">False</property>
945+ <property name="position">0</property>
946+ </packing>
947+ </child>
948+ <child>
949+ <object class="GtkVBox" id="vbox83">
950+ <property name="visible">True</property>
951+ <property name="orientation">vertical</property>
952+ <property name="spacing">6</property>
953+ <child>
954+ <object class="GtkLabel" id="label42">
955+ <property name="visible">True</property>
956+ <property name="xalign">0</property>
957+ <property name="label" translatable="yes">&lt;b&gt;Palette&lt;/b&gt;</property>
958+ <property name="use_markup">True</property>
959+ </object>
960+ <packing>
961+ <property name="expand">False</property>
962+ <property name="fill">False</property>
963+ <property name="position">0</property>
964+ </packing>
965+ </child>
966+ <child>
967+ <object class="GtkAlignment" id="alignment10106">
968+ <property name="visible">True</property>
969+ <property name="left_padding">12</property>
970+ <child>
971+ <object class="GtkTable" id="table25">
972+ <property name="visible">True</property>
973+ <property name="n_rows">3</property>
974+ <property name="n_columns">2</property>
975+ <property name="column_spacing">12</property>
976+ <property name="row_spacing">6</property>
977+ <child>
978+ <object class="GtkLabel" id="palette-optionmenu-label">
979+ <property name="visible">True</property>
980+ <property name="xalign">0</property>
981+ <property name="label" translatable="yes">Built-in _schemes:</property>
982+ <property name="use_underline">True</property>
983+ <property name="justify">center</property>
984+ <property name="mnemonic_widget">palette-combobox</property>
985+ </object>
986+ <packing>
987+ <property name="top_attach">1</property>
988+ <property name="bottom_attach">2</property>
989+ <property name="x_options">GTK_FILL</property>
990+ <property name="y_options"></property>
991+ </packing>
992+ </child>
993+ <child>
994+ <object class="GtkTable" id="palette-table">
995+ <property name="visible">True</property>
996+ <property name="n_rows">2</property>
997+ <property name="n_columns">8</property>
998+ <property name="column_spacing">6</property>
999+ <property name="row_spacing">6</property>
1000+ <child>
1001+ <object class="GtkColorButton" id="palette-colorpicker-1">
1002+ <property name="visible">True</property>
1003+ <property name="can_focus">True</property>
1004+ <property name="receives_default">True</property>
1005+ <property name="color">#000000000000</property>
1006+ </object>
1007+ <packing>
1008+ <property name="x_options"></property>
1009+ <property name="y_options"></property>
1010+ </packing>
1011+ </child>
1012+ <child>
1013+ <object class="GtkColorButton" id="palette-colorpicker-2">
1014+ <property name="visible">True</property>
1015+ <property name="can_focus">True</property>
1016+ <property name="receives_default">True</property>
1017+ <property name="color">#000000000000</property>
1018+ </object>
1019+ <packing>
1020+ <property name="left_attach">1</property>
1021+ <property name="right_attach">2</property>
1022+ <property name="x_options"></property>
1023+ <property name="y_options"></property>
1024+ </packing>
1025+ </child>
1026+ <child>
1027+ <object class="GtkColorButton" id="palette-colorpicker-3">
1028+ <property name="visible">True</property>
1029+ <property name="can_focus">True</property>
1030+ <property name="receives_default">True</property>
1031+ <property name="color">#000000000000</property>
1032+ </object>
1033+ <packing>
1034+ <property name="left_attach">2</property>
1035+ <property name="right_attach">3</property>
1036+ <property name="x_options"></property>
1037+ <property name="y_options"></property>
1038+ </packing>
1039+ </child>
1040+ <child>
1041+ <object class="GtkColorButton" id="palette-colorpicker-4">
1042+ <property name="visible">True</property>
1043+ <property name="can_focus">True</property>
1044+ <property name="receives_default">True</property>
1045+ <property name="color">#000000000000</property>
1046+ </object>
1047+ <packing>
1048+ <property name="left_attach">3</property>
1049+ <property name="right_attach">4</property>
1050+ <property name="x_options"></property>
1051+ <property name="y_options"></property>
1052+ </packing>
1053+ </child>
1054+ <child>
1055+ <object class="GtkColorButton" id="palette-colorpicker-5">
1056+ <property name="visible">True</property>
1057+ <property name="can_focus">True</property>
1058+ <property name="receives_default">True</property>
1059+ <property name="color">#000000000000</property>
1060+ </object>
1061+ <packing>
1062+ <property name="left_attach">4</property>
1063+ <property name="right_attach">5</property>
1064+ <property name="x_options"></property>
1065+ <property name="y_options"></property>
1066+ </packing>
1067+ </child>
1068+ <child>
1069+ <object class="GtkColorButton" id="palette-colorpicker-6">
1070+ <property name="visible">True</property>
1071+ <property name="can_focus">True</property>
1072+ <property name="receives_default">True</property>
1073+ <property name="color">#000000000000</property>
1074+ </object>
1075+ <packing>
1076+ <property name="left_attach">5</property>
1077+ <property name="right_attach">6</property>
1078+ <property name="x_options"></property>
1079+ <property name="y_options"></property>
1080+ </packing>
1081+ </child>
1082+ <child>
1083+ <object class="GtkColorButton" id="palette-colorpicker-8">
1084+ <property name="visible">True</property>
1085+ <property name="can_focus">True</property>
1086+ <property name="receives_default">True</property>
1087+ <property name="color">#000000000000</property>
1088+ </object>
1089+ <packing>
1090+ <property name="left_attach">7</property>
1091+ <property name="right_attach">8</property>
1092+ <property name="x_options"></property>
1093+ <property name="y_options"></property>
1094+ </packing>
1095+ </child>
1096+ <child>
1097+ <object class="GtkColorButton" id="palette-colorpicker-9">
1098+ <property name="visible">True</property>
1099+ <property name="can_focus">True</property>
1100+ <property name="receives_default">True</property>
1101+ <property name="color">#000000000000</property>
1102+ </object>
1103+ <packing>
1104+ <property name="top_attach">1</property>
1105+ <property name="bottom_attach">2</property>
1106+ <property name="x_options"></property>
1107+ <property name="y_options"></property>
1108+ </packing>
1109+ </child>
1110+ <child>
1111+ <object class="GtkColorButton" id="palette-colorpicker-10">
1112+ <property name="visible">True</property>
1113+ <property name="can_focus">True</property>
1114+ <property name="receives_default">True</property>
1115+ <property name="color">#000000000000</property>
1116+ </object>
1117+ <packing>
1118+ <property name="left_attach">1</property>
1119+ <property name="right_attach">2</property>
1120+ <property name="top_attach">1</property>
1121+ <property name="bottom_attach">2</property>
1122+ <property name="x_options"></property>
1123+ <property name="y_options"></property>
1124+ </packing>
1125+ </child>
1126+ <child>
1127+ <object class="GtkColorButton" id="palette-colorpicker-12">
1128+ <property name="visible">True</property>
1129+ <property name="can_focus">True</property>
1130+ <property name="receives_default">True</property>
1131+ <property name="color">#000000000000</property>
1132+ </object>
1133+ <packing>
1134+ <property name="left_attach">3</property>
1135+ <property name="right_attach">4</property>
1136+ <property name="top_attach">1</property>
1137+ <property name="bottom_attach">2</property>
1138+ <property name="x_options"></property>
1139+ <property name="y_options"></property>
1140+ </packing>
1141+ </child>
1142+ <child>
1143+ <object class="GtkColorButton" id="palette-colorpicker-11">
1144+ <property name="visible">True</property>
1145+ <property name="can_focus">True</property>
1146+ <property name="receives_default">True</property>
1147+ <property name="color">#000000000000</property>
1148+ </object>
1149+ <packing>
1150+ <property name="left_attach">2</property>
1151+ <property name="right_attach">3</property>
1152+ <property name="top_attach">1</property>
1153+ <property name="bottom_attach">2</property>
1154+ <property name="x_options"></property>
1155+ <property name="y_options"></property>
1156+ </packing>
1157+ </child>
1158+ <child>
1159+ <object class="GtkColorButton" id="palette-colorpicker-13">
1160+ <property name="visible">True</property>
1161+ <property name="can_focus">True</property>
1162+ <property name="receives_default">True</property>
1163+ <property name="color">#000000000000</property>
1164+ </object>
1165+ <packing>
1166+ <property name="left_attach">4</property>
1167+ <property name="right_attach">5</property>
1168+ <property name="top_attach">1</property>
1169+ <property name="bottom_attach">2</property>
1170+ <property name="x_options"></property>
1171+ <property name="y_options"></property>
1172+ </packing>
1173+ </child>
1174+ <child>
1175+ <object class="GtkColorButton" id="palette-colorpicker-16">
1176+ <property name="visible">True</property>
1177+ <property name="can_focus">True</property>
1178+ <property name="receives_default">True</property>
1179+ <property name="color">#000000000000</property>
1180+ </object>
1181+ <packing>
1182+ <property name="left_attach">7</property>
1183+ <property name="right_attach">8</property>
1184+ <property name="top_attach">1</property>
1185+ <property name="bottom_attach">2</property>
1186+ <property name="x_options"></property>
1187+ <property name="y_options"></property>
1188+ </packing>
1189+ </child>
1190+ <child>
1191+ <object class="GtkColorButton" id="palette-colorpicker-14">
1192+ <property name="visible">True</property>
1193+ <property name="can_focus">True</property>
1194+ <property name="receives_default">True</property>
1195+ <property name="color">#000000000000</property>
1196+ </object>
1197+ <packing>
1198+ <property name="left_attach">5</property>
1199+ <property name="right_attach">6</property>
1200+ <property name="top_attach">1</property>
1201+ <property name="bottom_attach">2</property>
1202+ <property name="x_options">GTK_FILL</property>
1203+ <property name="y_options"></property>
1204+ </packing>
1205+ </child>
1206+ <child>
1207+ <object class="GtkColorButton" id="palette-colorpicker-7">
1208+ <property name="visible">True</property>
1209+ <property name="can_focus">True</property>
1210+ <property name="receives_default">True</property>
1211+ <property name="color">#000000000000</property>
1212+ </object>
1213+ <packing>
1214+ <property name="left_attach">6</property>
1215+ <property name="right_attach">7</property>
1216+ <property name="x_options"></property>
1217+ <property name="y_options"></property>
1218+ </packing>
1219+ </child>
1220+ <child>
1221+ <object class="GtkColorButton" id="palette-colorpicker-15">
1222+ <property name="visible">True</property>
1223+ <property name="can_focus">True</property>
1224+ <property name="receives_default">True</property>
1225+ <property name="color">#000000000000</property>
1226+ </object>
1227+ <packing>
1228+ <property name="left_attach">6</property>
1229+ <property name="right_attach">7</property>
1230+ <property name="top_attach">1</property>
1231+ <property name="bottom_attach">2</property>
1232+ <property name="x_options">GTK_FILL</property>
1233+ <property name="y_options"></property>
1234+ </packing>
1235+ </child>
1236+ </object>
1237+ <packing>
1238+ <property name="left_attach">1</property>
1239+ <property name="right_attach">2</property>
1240+ <property name="top_attach">2</property>
1241+ <property name="bottom_attach">3</property>
1242+ <property name="x_options">GTK_FILL</property>
1243+ <property name="y_options">GTK_FILL</property>
1244+ </packing>
1245+ </child>
1246+ <child>
1247+ <object class="GtkLabel" id="label44">
1248+ <property name="visible">True</property>
1249+ <property name="xalign">0</property>
1250+ <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;&lt;b&gt;Note:&lt;/b&gt; Terminal applications have these colors available to them.&lt;/i&gt;&lt;/small&gt;</property>
1251+ <property name="use_markup">True</property>
1252+ <property name="justify">center</property>
1253+ </object>
1254+ <packing>
1255+ <property name="right_attach">2</property>
1256+ <property name="x_options">GTK_FILL</property>
1257+ <property name="y_options"></property>
1258+ </packing>
1259+ </child>
1260+ <child>
1261+ <object class="GtkComboBox" id="palette-combobox">
1262+ <property name="visible">True</property>
1263+ </object>
1264+ <packing>
1265+ <property name="left_attach">1</property>
1266+ <property name="right_attach">2</property>
1267+ <property name="top_attach">1</property>
1268+ <property name="bottom_attach">2</property>
1269+ <property name="y_options">GTK_FILL</property>
1270+ </packing>
1271+ </child>
1272+ <child>
1273+ <object class="GtkLabel" id="label43">
1274+ <property name="visible">True</property>
1275+ <property name="xalign">0</property>
1276+ <property name="yalign">0</property>
1277+ <property name="label" translatable="yes">Color p_alette:</property>
1278+ <property name="use_underline">True</property>
1279+ <property name="justify">center</property>
1280+ <property name="mnemonic_widget">palette-colorpicker-1</property>
1281+ </object>
1282+ <packing>
1283+ <property name="top_attach">2</property>
1284+ <property name="bottom_attach">3</property>
1285+ <property name="x_options">GTK_FILL</property>
1286+ <property name="y_options">GTK_FILL</property>
1287+ </packing>
1288+ </child>
1289+ </object>
1290+ </child>
1291+ </object>
1292+ <packing>
1293+ <property name="expand">False</property>
1294+ <property name="position">1</property>
1295+ </packing>
1296+ </child>
1297+ </object>
1298+ <packing>
1299+ <property name="expand">False</property>
1300+ <property name="position">1</property>
1301+ </packing>
1302+ </child>
1303+ </object>
1304+ <packing>
1305+ <property name="position">2</property>
1306+ </packing>
1307+ </child>
1308+ <child type="tab">
1309+ <object class="GtkLabel" id="label45">
1310+ <property name="visible">True</property>
1311+ <property name="label" translatable="yes">Colors</property>
1312+ <property name="use_underline">True</property>
1313+ <property name="justify">center</property>
1314+ </object>
1315+ <packing>
1316+ <property name="position">2</property>
1317+ <property name="tab_fill">False</property>
1318+ </packing>
1319+ </child>
1320+ <child>
1321+ <object class="GtkVBox" id="vbox86">
1322+ <property name="visible">True</property>
1323+ <property name="border_width">12</property>
1324+ <property name="orientation">vertical</property>
1325+ <property name="spacing">6</property>
1326+ <child>
1327+ <object class="GtkRadioButton" id="solid-radiobutton">
1328+ <property name="label" translatable="yes">_Solid color</property>
1329+ <property name="visible">True</property>
1330+ <property name="can_focus">True</property>
1331+ <property name="receives_default">False</property>
1332+ <property name="use_underline">True</property>
1333+ <property name="active">True</property>
1334+ <property name="draw_indicator">True</property>
1335+ </object>
1336+ <packing>
1337+ <property name="expand">False</property>
1338+ <property name="fill">False</property>
1339+ <property name="position">0</property>
1340+ </packing>
1341+ </child>
1342+ <child>
1343+ <object class="GtkVBox" id="vbox87">
1344+ <property name="visible">True</property>
1345+ <property name="orientation">vertical</property>
1346+ <property name="spacing">6</property>
1347+ <child>
1348+ <object class="GtkRadioButton" id="image-radiobutton">
1349+ <property name="label" translatable="yes">_Background image</property>
1350+ <property name="visible">True</property>
1351+ <property name="can_focus">True</property>
1352+ <property name="receives_default">False</property>
1353+ <property name="use_underline">True</property>
1354+ <property name="draw_indicator">True</property>
1355+ <property name="group">solid-radiobutton</property>
1356+ </object>
1357+ <packing>
1358+ <property name="expand">False</property>
1359+ <property name="fill">False</property>
1360+ <property name="position">0</property>
1361+ </packing>
1362+ </child>
1363+ <child>
1364+ <object class="GtkAlignment" id="alignment10103">
1365+ <property name="visible">True</property>
1366+ <property name="left_padding">12</property>
1367+ <child>
1368+ <object class="GtkVBox" id="vbox89">
1369+ <property name="visible">True</property>
1370+ <property name="orientation">vertical</property>
1371+ <property name="spacing">6</property>
1372+ <child>
1373+ <object class="GtkHBox" id="hbox2">
1374+ <property name="visible">True</property>
1375+ <property name="spacing">12</property>
1376+ <child>
1377+ <object class="GtkLabel" id="background-image-filechooser-label">
1378+ <property name="visible">True</property>
1379+ <property name="xalign">0</property>
1380+ <property name="label" translatable="yes">Image _file:</property>
1381+ <property name="use_underline">True</property>
1382+ <property name="justify">center</property>
1383+ <property name="mnemonic_widget">background-image-filechooser</property>
1384+ </object>
1385+ <packing>
1386+ <property name="expand">False</property>
1387+ <property name="fill">False</property>
1388+ <property name="position">0</property>
1389+ </packing>
1390+ </child>
1391+ <child>
1392+ <object class="GtkFileChooserButton" id="background-image-filechooser">
1393+ <property name="visible">True</property>
1394+ <property name="can_focus">True</property>
1395+ <property name="create_folders">False</property>
1396+ <property name="title" translatable="yes">Select Background Image</property>
1397+ </object>
1398+ <packing>
1399+ <property name="position">1</property>
1400+ </packing>
1401+ </child>
1402+ </object>
1403+ <packing>
1404+ <property name="position">0</property>
1405+ </packing>
1406+ </child>
1407+ <child>
1408+ <object class="GtkCheckButton" id="scroll-background-checkbutton">
1409+ <property name="label" translatable="yes">Background image _scrolls</property>
1410+ <property name="visible">True</property>
1411+ <property name="can_focus">True</property>
1412+ <property name="receives_default">False</property>
1413+ <property name="use_underline">True</property>
1414+ <property name="draw_indicator">True</property>
1415+ </object>
1416+ <packing>
1417+ <property name="expand">False</property>
1418+ <property name="fill">False</property>
1419+ <property name="position">1</property>
1420+ </packing>
1421+ </child>
1422+ </object>
1423+ </child>
1424+ </object>
1425+ <packing>
1426+ <property name="expand">False</property>
1427+ <property name="position">1</property>
1428+ </packing>
1429+ </child>
1430+ </object>
1431+ <packing>
1432+ <property name="expand">False</property>
1433+ <property name="position">1</property>
1434+ </packing>
1435+ </child>
1436+ <child>
1437+ <object class="GtkRadioButton" id="transparent-radiobutton">
1438+ <property name="label" translatable="yes">_Transparent background</property>
1439+ <property name="visible">True</property>
1440+ <property name="can_focus">True</property>
1441+ <property name="receives_default">False</property>
1442+ <property name="use_underline">True</property>
1443+ <property name="draw_indicator">True</property>
1444+ <property name="group">solid-radiobutton</property>
1445+ </object>
1446+ <packing>
1447+ <property name="expand">False</property>
1448+ <property name="fill">False</property>
1449+ <property name="position">2</property>
1450+ </packing>
1451+ </child>
1452+ <child>
1453+ <object class="GtkVBox" id="darken-background-vbox">
1454+ <property name="visible">True</property>
1455+ <property name="orientation">vertical</property>
1456+ <property name="spacing">6</property>
1457+ <child>
1458+ <object class="GtkLabel" id="darken-background-scale-label">
1459+ <property name="visible">True</property>
1460+ <property name="xalign">0</property>
1461+ <property name="label" translatable="yes">S_hade transparent or image background:</property>
1462+ <property name="use_underline">True</property>
1463+ <property name="mnemonic_widget">darken-background-scale</property>
1464+ </object>
1465+ <packing>
1466+ <property name="expand">False</property>
1467+ <property name="fill">False</property>
1468+ <property name="padding">1</property>
1469+ <property name="position">0</property>
1470+ </packing>
1471+ </child>
1472+ <child>
1473+ <object class="GtkHBox" id="hbox6">
1474+ <property name="visible">True</property>
1475+ <child>
1476+ <object class="GtkLabel" id="label64">
1477+ <property name="visible">True</property>
1478+ <property name="xalign">0</property>
1479+ <property name="xpad">6</property>
1480+ <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;None&lt;/i&gt;&lt;/small&gt;</property>
1481+ <property name="use_markup">True</property>
1482+ </object>
1483+ <packing>
1484+ <property name="expand">False</property>
1485+ <property name="fill">False</property>
1486+ <property name="position">0</property>
1487+ </packing>
1488+ </child>
1489+ <child>
1490+ <object class="GtkHScale" id="darken-background-scale">
1491+ <property name="visible">True</property>
1492+ <property name="can_focus">True</property>
1493+ <property name="update_policy">delayed</property>
1494+ <property name="digits">2</property>
1495+ <property name="draw_value">False</property>
1496+ <property name="value_pos">bottom</property>
1497+ </object>
1498+ <packing>
1499+ <property name="position">1</property>
1500+ </packing>
1501+ </child>
1502+ <child>
1503+ <object class="GtkLabel" id="label63">
1504+ <property name="visible">True</property>
1505+ <property name="xalign">1</property>
1506+ <property name="xpad">6</property>
1507+ <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;Maximum&lt;/i&gt;&lt;/small&gt;</property>
1508+ <property name="use_markup">True</property>
1509+ </object>
1510+ <packing>
1511+ <property name="expand">False</property>
1512+ <property name="fill">False</property>
1513+ <property name="position">2</property>
1514+ </packing>
1515+ </child>
1516+ </object>
1517+ <packing>
1518+ <property name="expand">False</property>
1519+ <property name="fill">False</property>
1520+ <property name="padding">1</property>
1521+ <property name="position">1</property>
1522+ </packing>
1523+ </child>
1524+ </object>
1525+ <packing>
1526+ <property name="expand">False</property>
1527+ <property name="position">3</property>
1528+ </packing>
1529+ </child>
1530+ </object>
1531+ <packing>
1532+ <property name="position">3</property>
1533+ </packing>
1534+ </child>
1535+ <child type="tab">
1536+ <object class="GtkLabel" id="label479">
1537+ <property name="visible">True</property>
1538+ <property name="xalign">0</property>
1539+ <property name="label" translatable="yes">Background</property>
1540+ <property name="use_markup">True</property>
1541+ </object>
1542+ <packing>
1543+ <property name="position">3</property>
1544+ <property name="tab_fill">False</property>
1545+ </packing>
1546+ </child>
1547+ <child>
1548+ <object class="GtkTable" id="table27">
1549+ <property name="visible">True</property>
1550+ <property name="border_width">12</property>
1551+ <property name="n_rows">4</property>
1552+ <property name="n_columns">2</property>
1553+ <property name="column_spacing">12</property>
1554+ <property name="row_spacing">6</property>
1555+ <child>
1556+ <object class="GtkCheckButton" id="scroll-on-keystroke-checkbutton">
1557+ <property name="label" translatable="yes">Scroll on _keystroke</property>
1558+ <property name="visible">True</property>
1559+ <property name="can_focus">True</property>
1560+ <property name="receives_default">False</property>
1561+ <property name="use_underline">True</property>
1562+ <property name="draw_indicator">True</property>
1563+ </object>
1564+ <packing>
1565+ <property name="right_attach">2</property>
1566+ <property name="top_attach">3</property>
1567+ <property name="bottom_attach">4</property>
1568+ <property name="y_options"></property>
1569+ </packing>
1570+ </child>
1571+ <child>
1572+ <object class="GtkCheckButton" id="scroll-on-output-checkbutton">
1573+ <property name="label" translatable="yes">Scroll on _output</property>
1574+ <property name="visible">True</property>
1575+ <property name="can_focus">True</property>
1576+ <property name="receives_default">False</property>
1577+ <property name="use_underline">True</property>
1578+ <property name="draw_indicator">True</property>
1579+ </object>
1580+ <packing>
1581+ <property name="right_attach">2</property>
1582+ <property name="top_attach">2</property>
1583+ <property name="bottom_attach">3</property>
1584+ <property name="y_options"></property>
1585+ </packing>
1586+ </child>
1587+ <child>
1588+ <object class="GtkHBox" id="hbox139">
1589+ <property name="visible">True</property>
1590+ <child>
1591+ <object class="GtkComboBox" id="scrollbar-position-combobox">
1592+ <property name="visible">True</property>
1593+ </object>
1594+ <packing>
1595+ <property name="expand">False</property>
1596+ <property name="position">0</property>
1597+ </packing>
1598+ </child>
1599+ </object>
1600+ <packing>
1601+ <property name="left_attach">1</property>
1602+ <property name="right_attach">2</property>
1603+ <property name="y_options">GTK_FILL</property>
1604+ </packing>
1605+ </child>
1606+ <child>
1607+ <object class="GtkHBox" id="scrollback-box">
1608+ <property name="visible">True</property>
1609+ <property name="spacing">6</property>
1610+ <child>
1611+ <object class="GtkSpinButton" id="scrollback-lines-spinbutton">
1612+ <property name="visible">True</property>
1613+ <property name="can_focus">True</property>
1614+ <property name="invisible_char">&#x2022;</property>
1615+ <property name="climb_rate">1</property>
1616+ <property name="numeric">True</property>
1617+ </object>
1618+ <packing>
1619+ <property name="expand">False</property>
1620+ <property name="position">0</property>
1621+ </packing>
1622+ </child>
1623+ <child>
1624+ <object class="GtkLabel" id="scrollback-lines-spinbutton-label">
1625+ <property name="visible">True</property>
1626+ <property name="xalign">0</property>
1627+ <property name="label" translatable="yes">lines</property>
1628+ <property name="justify">center</property>
1629+ <property name="mnemonic_widget">scrollback-lines-spinbutton</property>
1630+ </object>
1631+ <packing>
1632+ <property name="expand">False</property>
1633+ <property name="fill">False</property>
1634+ <property name="position">1</property>
1635+ </packing>
1636+ </child>
1637+ <child>
1638+ <object class="GtkLabel" id="scrollback-kb-label">
1639+ <property name="visible">True</property>
1640+ <property name="label">(about 120kB)</property>
1641+ </object>
1642+ <packing>
1643+ <property name="expand">False</property>
1644+ <property name="fill">False</property>
1645+ <property name="position">2</property>
1646+ </packing>
1647+ </child>
1648+ </object>
1649+ <packing>
1650+ <property name="left_attach">1</property>
1651+ <property name="right_attach">2</property>
1652+ <property name="top_attach">1</property>
1653+ <property name="bottom_attach">2</property>
1654+ <property name="x_options">GTK_FILL</property>
1655+ <property name="y_options">GTK_FILL</property>
1656+ </packing>
1657+ </child>
1658+ <child>
1659+ <object class="GtkLabel" id="scrollbar-position-combobox-label">
1660+ <property name="visible">True</property>
1661+ <property name="xalign">0</property>
1662+ <property name="label" translatable="yes">_Scrollbar is:</property>
1663+ <property name="use_underline">True</property>
1664+ <property name="justify">center</property>
1665+ <property name="mnemonic_widget">scrollbar-position-combobox</property>
1666+ </object>
1667+ <packing>
1668+ <property name="x_options">GTK_FILL</property>
1669+ <property name="y_options">GTK_FILL</property>
1670+ </packing>
1671+ </child>
1672+ <child>
1673+ <object class="GtkLabel" id="scrollback-label">
1674+ <property name="visible">True</property>
1675+ <property name="xalign">0</property>
1676+ <property name="label" translatable="yes">Scroll_back:</property>
1677+ <property name="use_underline">True</property>
1678+ <property name="justify">center</property>
1679+ <property name="mnemonic_widget">scrollback-lines-spinbutton</property>
1680+ </object>
1681+ <packing>
1682+ <property name="top_attach">1</property>
1683+ <property name="bottom_attach">2</property>
1684+ <property name="x_options">GTK_FILL</property>
1685+ <property name="y_options">GTK_FILL</property>
1686+ </packing>
1687+ </child>
1688+ </object>
1689+ <packing>
1690+ <property name="position">4</property>
1691+ </packing>
1692+ </child>
1693+ <child type="tab">
1694+ <object class="GtkLabel" id="label60">
1695+ <property name="visible">True</property>
1696+ <property name="label" translatable="yes">Scrolling</property>
1697+ <property name="use_underline">True</property>
1698+ </object>
1699+ <packing>
1700+ <property name="position">4</property>
1701+ <property name="tab_fill">False</property>
1702+ </packing>
1703+ </child>
1704+ <child>
1705+ <object class="GtkVBox" id="vbox4">
1706+ <property name="visible">True</property>
1707+ <property name="border_width">12</property>
1708+ <property name="orientation">vertical</property>
1709+ <property name="spacing">12</property>
1710+ <child>
1711+ <object class="GtkLabel" id="label51">
1712+ <property name="visible">True</property>
1713+ <property name="xalign">0</property>
1714+ <property name="yalign">7.4505801528346183e-09</property>
1715+ <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;&lt;b&gt;Note:&lt;/b&gt; These options may cause some applications to behave incorrectly. They are only here to allow you to work around certain applications and operating systems that expect different terminal behavior.&lt;/i&gt;&lt;/small&gt;</property>
1716+ <property name="use_markup">True</property>
1717+ <property name="wrap">True</property>
1718+ </object>
1719+ <packing>
1720+ <property name="expand">False</property>
1721+ <property name="position">0</property>
1722+ </packing>
1723+ </child>
1724+ <child>
1725+ <object class="GtkTable" id="table30">
1726+ <property name="visible">True</property>
1727+ <property name="n_rows">2</property>
1728+ <property name="n_columns">3</property>
1729+ <property name="column_spacing">12</property>
1730+ <property name="row_spacing">6</property>
1731+ <child>
1732+ <object class="GtkLabel" id="delete-binding-combobox-label">
1733+ <property name="visible">True</property>
1734+ <property name="xalign">0</property>
1735+ <property name="label" translatable="yes">_Delete key generates:</property>
1736+ <property name="use_underline">True</property>
1737+ <property name="justify">center</property>
1738+ <property name="mnemonic_widget">delete-binding-combobox</property>
1739+ </object>
1740+ <packing>
1741+ <property name="top_attach">1</property>
1742+ <property name="bottom_attach">2</property>
1743+ <property name="x_options">GTK_FILL</property>
1744+ <property name="y_options"></property>
1745+ </packing>
1746+ </child>
1747+ <child>
1748+ <object class="GtkLabel" id="backspace-binding-combobox-label">
1749+ <property name="visible">True</property>
1750+ <property name="xalign">0</property>
1751+ <property name="label" translatable="yes">_Backspace key generates:</property>
1752+ <property name="use_underline">True</property>
1753+ <property name="justify">center</property>
1754+ <property name="mnemonic_widget">backspace-binding-combobox</property>
1755+ </object>
1756+ <packing>
1757+ <property name="x_options">GTK_FILL</property>
1758+ <property name="y_options"></property>
1759+ </packing>
1760+ </child>
1761+ <child>
1762+ <object class="GtkComboBox" id="backspace-binding-combobox">
1763+ <property name="visible">True</property>
1764+ </object>
1765+ <packing>
1766+ <property name="left_attach">1</property>
1767+ <property name="right_attach">3</property>
1768+ <property name="x_options">GTK_FILL</property>
1769+ <property name="y_options">GTK_FILL</property>
1770+ </packing>
1771+ </child>
1772+ <child>
1773+ <object class="GtkComboBox" id="delete-binding-combobox">
1774+ <property name="visible">True</property>
1775+ </object>
1776+ <packing>
1777+ <property name="left_attach">1</property>
1778+ <property name="right_attach">3</property>
1779+ <property name="top_attach">1</property>
1780+ <property name="bottom_attach">2</property>
1781+ <property name="x_options">GTK_FILL</property>
1782+ <property name="y_options">GTK_FILL</property>
1783+ </packing>
1784+ </child>
1785+ </object>
1786+ <packing>
1787+ <property name="expand">False</property>
1788+ <property name="position">1</property>
1789+ </packing>
1790+ </child>
1791+ <child>
1792+ <object class="GtkHButtonBox" id="hbuttonbox1">
1793+ <property name="visible">True</property>
1794+ <property name="layout_style">start</property>
1795+ <child>
1796+ <object class="GtkButton" id="reset-compat-defaults-button">
1797+ <property name="label" translatable="yes">_Reset Compatibility Options to Defaults</property>
1798+ <property name="visible">True</property>
1799+ <property name="can_focus">True</property>
1800+ <property name="receives_default">True</property>
1801+ <property name="use_underline">True</property>
1802+ </object>
1803+ <packing>
1804+ <property name="expand">False</property>
1805+ <property name="fill">False</property>
1806+ <property name="position">0</property>
1807+ </packing>
1808+ </child>
1809+ </object>
1810+ <packing>
1811+ <property name="expand">False</property>
1812+ <property name="fill">False</property>
1813+ <property name="position">2</property>
1814+ </packing>
1815+ </child>
1816+ </object>
1817+ <packing>
1818+ <property name="position">5</property>
1819+ </packing>
1820+ </child>
1821+ <child type="tab">
1822+ <object class="GtkLabel" id="label54">
1823+ <property name="visible">True</property>
1824+ <property name="label" translatable="yes">Compatibility</property>
1825+ <property name="use_underline">True</property>
1826+ <property name="justify">center</property>
1827+ </object>
1828+ <packing>
1829+ <property name="position">5</property>
1830+ <property name="tab_fill">False</property>
1831+ </packing>
1832+ </child>
1833+ </object>
1834+ <packing>
1835+ <property name="position">1</property>
1836+ </packing>
1837+ </child>
1838+ </object>
1839+ <packing>
1840+ <property name="position">1</property>
1841+ </packing>
1842+ </child>
1843+ <child type="tab">
1844+ <object class="GtkLabel" id="label2">
1845+ <property name="visible">True</property>
1846+ <property name="label" translatable="yes">Profiles</property>
1847+ </object>
1848+ <packing>
1849+ <property name="position">1</property>
1850+ <property name="tab_fill">False</property>
1851+ </packing>
1852+ </child>
1853+ <child>
1854+ <object class="GtkLabel" id="label12">
1855+ <property name="visible">True</property>
1856+ <property name="label" translatable="yes">Not yet implemented</property>
1857+ </object>
1858+ <packing>
1859+ <property name="position">2</property>
1860+ </packing>
1861+ </child>
1862+ <child type="tab">
1863+ <object class="GtkLabel" id="label3">
1864+ <property name="visible">True</property>
1865+ <property name="label" translatable="yes">Layouts</property>
1866+ </object>
1867+ <packing>
1868+ <property name="position">2</property>
1869+ <property name="tab_fill">False</property>
1870+ </packing>
1871+ </child>
1872+ <child>
1873+ <object class="GtkTreeView" id="treeview2">
1874+ <property name="visible">True</property>
1875+ <property name="can_focus">True</property>
1876+ <property name="model">KeybindingsListStore</property>
1877+ </object>
1878+ <packing>
1879+ <property name="position">3</property>
1880+ </packing>
1881+ </child>
1882+ <child type="tab">
1883+ <object class="GtkLabel" id="label4">
1884+ <property name="visible">True</property>
1885+ <property name="label" translatable="yes">Keybindings</property>
1886+ </object>
1887+ <packing>
1888+ <property name="position">3</property>
1889+ <property name="tab_fill">False</property>
1890+ </packing>
1891+ </child>
1892+ <child>
1893+ <object class="GtkLabel" id="label13">
1894+ <property name="visible">True</property>
1895+ <property name="label" translatable="yes">Not yet implemented</property>
1896+ </object>
1897+ <packing>
1898+ <property name="position">4</property>
1899+ </packing>
1900+ </child>
1901+ <child type="tab">
1902+ <object class="GtkLabel" id="label5">
1903+ <property name="visible">True</property>
1904+ <property name="label" translatable="yes">Plugins</property>
1905+ </object>
1906+ <packing>
1907+ <property name="position">4</property>
1908+ <property name="tab_fill">False</property>
1909+ </packing>
1910+ </child>
1911+ </object>
1912+ <packing>
1913+ <property name="position">1</property>
1914+ </packing>
1915+ </child>
1916+ <child internal-child="action_area">
1917+ <object class="GtkHButtonBox" id="dialog-action_area1">
1918+ <property name="visible">True</property>
1919+ <property name="layout_style">end</property>
1920+ <child>
1921+ <object class="GtkButton" id="button1">
1922+ <property name="label">gtk-cancel</property>
1923+ <property name="visible">True</property>
1924+ <property name="can_focus">True</property>
1925+ <property name="receives_default">True</property>
1926+ <property name="use_stock">True</property>
1927+ </object>
1928+ <packing>
1929+ <property name="expand">False</property>
1930+ <property name="fill">False</property>
1931+ <property name="position">0</property>
1932+ </packing>
1933+ </child>
1934+ <child>
1935+ <object class="GtkButton" id="button2">
1936+ <property name="label">gtk-ok</property>
1937+ <property name="visible">True</property>
1938+ <property name="can_focus">True</property>
1939+ <property name="receives_default">True</property>
1940+ <property name="use_stock">True</property>
1941+ </object>
1942+ <packing>
1943+ <property name="expand">False</property>
1944+ <property name="fill">False</property>
1945+ <property name="position">1</property>
1946+ </packing>
1947+ </child>
1948+ </object>
1949+ <packing>
1950+ <property name="expand">False</property>
1951+ <property name="pack_type">end</property>
1952+ <property name="position">0</property>
1953+ </packing>
1954+ </child>
1955+ </object>
1956+ </child>
1957+ <action-widgets>
1958+ <action-widget response="0">button1</action-widget>
1959+ <action-widget response="0">button2</action-widget>
1960+ </action-widgets>
1961+ </object>
1962+</interface>
1963
1964=== modified file 'debian/control'
1965--- debian/control 2009-12-22 22:38:22 +0000
1966+++ debian/control 2010-01-05 05:03:15 +0000
1967@@ -14,10 +14,18 @@
1968
1969 Package: terminator
1970 Architecture: all
1971+<<<<<<< TREE
1972 Depends: ${python:Depends}, ${misc:Depends}, python-vte, python-gobject, python-gtk2, gconf2, libgtk2.0-bin
1973+=======
1974+Depends: ${python:Depends}, ${misc:Depends}, python-vte, python-gobject, python-gtk2 (>= 2.14.0), gconf2, libgtk2.0-bin
1975+>>>>>>> MERGE-SOURCE
1976 XB-Python-Version: ${python:Versions}
1977 Provides: x-terminal-emulator
1978+<<<<<<< TREE
1979 Recommends: xdg-utils, python-xdg, python-gnome2, deskbar-applet
1980+=======
1981+Recommends: xdg-utils, python-xdg, python-gnome2
1982+>>>>>>> MERGE-SOURCE
1983 Description: multiple GNOME terminals in one window
1984 Terminator is a little project to produce an efficient way of
1985 filling a large area of screen space with terminals.
1986
1987=== modified file 'doc/terminator_config.5'
1988--- doc/terminator_config.5 2009-12-02 00:19:26 +0000
1989+++ doc/terminator_config.5 2010-01-05 05:03:15 +0000
1990@@ -119,10 +119,6 @@
1991 If true, a titlebar will be drawn on zoomed/maximised terminals which indicates how many are hidden.
1992 Default value: \fBTrue\fR
1993 .TP
1994-.B titletips
1995-If true, a tooltip will be available for each terminal which shows the current title of that terminal.
1996-Default value: \fBFalse\fR
1997-.TP
1998 .B title_tx_txt_color
1999 Sets the colour of the text shown in the titlebar of the active terminal.
2000 Default value: \fB#FFFFFF\fR
2001
2002=== modified file 'terminator'
2003--- terminator 2009-11-19 15:03:21 +0000
2004+++ terminator 2010-01-05 05:03:15 +0000
2005@@ -1,6 +1,6 @@
2006 #!/usr/bin/env python
2007 # Terminator - multiple gnome terminals in one window
2008-# Copyright (C) 2006-2008 cmsj@tenshu.net
2009+# Copyright (C) 2006-2010 cmsj@tenshu.net
2010 #
2011 # This program is free software; you can redistribute it and/or modify
2012 # it under the terms of the GNU General Public License as published by
2013@@ -18,30 +18,33 @@
2014
2015 """Terminator by Chris Jones <cmsj@tenshu.net>"""
2016
2017-# import standard python libs
2018-import os, sys
2019-origcwd = os.getcwd()
2020-from optparse import OptionParser, SUPPRESS_HELP
2021-
2022-import terminatorlib.translation
2023-from terminatorlib.version import APP_NAME, APP_VERSION
2024-
2025-from terminatorlib.config import dbg, err, debug
2026-import terminatorlib.config
2027-
2028+import sys
2029+
2030+# Check we have simple basics like Gtk+ and a valid $DISPLAY
2031 try:
2032- import pygtk
2033- pygtk.require ("2.0")
2034-
2035- import gobject, gtk, pango
2036+ import pygtk
2037+ pygtk.require ("2.0")
2038+ import gtk
2039+
2040+ if gtk.gdk.display_get_default() == None:
2041+ print('You need to run terminator in an X environment. ' \
2042+ 'Make sure $DISPLAY is properly set')
2043+ sys.exit(1)
2044+
2045 except ImportError:
2046- err (_("You need to install the python bindings for " \
2047- "gobject, gtk and pango to run Terminator."))
2048- sys.exit(1)
2049+ print('You need to install the python bindings for ' \
2050+ 'gobject, gtk and pango to run Terminator.')
2051+ sys.exit(1)
2052
2053-from terminatorlib.terminator import Terminator
2054+import terminatorlib.config
2055+import terminatorlib.optionparse
2056+from terminatorlib.newterminator import Terminator
2057+from terminatorlib.factory import Factory
2058+from terminatorlib.version import APP_NAME, APP_VERSION
2059+from terminatorlib.util import dbg
2060
2061 if __name__ == '__main__':
2062+<<<<<<< TREE
2063 def execute_cb (option, opt, value, lparser):
2064 """Callback for use in parsing Terminator command line options"""
2065 assert value is None
2066@@ -140,7 +143,32 @@
2067 try:
2068 open (os.path.expanduser ('~/.config/terminator/config'))
2069 except IOError:
2070+=======
2071+ dbg ("%s starting up, version %s" % (APP_NAME, APP_VERSION))
2072+
2073+ OPTIONS = terminatorlib.optionparse.parse_options()
2074+
2075+ MAKER = Factory()
2076+ TERMINATOR = Terminator()
2077+ WINDOW = MAKER.make('Window')
2078+ TERMINAL = MAKER.make('Terminal')
2079+
2080+ WINDOW.add(TERMINAL)
2081+ WINDOW.show()
2082+ TERMINAL.spawn_child()
2083+
2084+ if OPTIONS.debug > 1:
2085+ import terminatorlib.debugserver as debugserver
2086+ # pylint: disable-msg=W0611
2087+ import threading
2088+
2089+ gtk.gdk.threads_init()
2090+ (DEBUGTHREAD, DEBUGSVR) = debugserver.spawn(locals())
2091+ TERMINATOR.debugaddress = DEBUGSVR.server_address
2092+
2093+>>>>>>> MERGE-SOURCE
2094 try:
2095+<<<<<<< TREE
2096 open (os.path.expanduser ('~/.terminatorrc'))
2097 error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR,
2098 gtk.BUTTONS_OK, ('''You have a configuration file:
2099@@ -175,4 +203,9 @@
2100 term.debugaddress = debugsvr.server_address
2101
2102 gtk.main()
2103+=======
2104+ gtk.main()
2105+ except KeyboardInterrupt:
2106+ pass
2107+>>>>>>> MERGE-SOURCE
2108
2109
2110=== modified file 'terminatorlib/__init__.py'
2111--- terminatorlib/__init__.py 2009-05-07 00:44:42 +0000
2112+++ terminatorlib/__init__.py 2010-01-05 05:03:15 +0000
2113@@ -1,6 +1,6 @@
2114 #!/usr/bin/python
2115 # Terminator - multiple gnome terminals in one window
2116-# Copyright (C) 2006-2008 cmsj@tenshu.net
2117+# Copyright (C) 2006-2010 cmsj@tenshu.net
2118 #
2119 # This program is free software; you can redistribute it and/or modify
2120 # it under the terms of the GNU General Public License as published by
2121@@ -17,3 +17,4 @@
2122
2123 """Terminator by Chris Jones <cmsj@tenshu.net>"""
2124
2125+from version import APP_NAME, APP_VERSION
2126
2127=== added file 'terminatorlib/borg.py'
2128--- terminatorlib/borg.py 1970-01-01 00:00:00 +0000
2129+++ terminatorlib/borg.py 2010-01-05 05:03:15 +0000
2130@@ -0,0 +1,107 @@
2131+#!/usr/bin/python
2132+# Terminator by Chris Jones <cmsj@tenshu.net>
2133+# GPL v2 only
2134+"""borg.py - We are the borg. Resistance is futile.
2135+ http://code.activestate.com/recipes/66531/
2136+ ActiveState's policy appears to be that snippets
2137+ exist to encourage re-use, but I can not find any
2138+ specific licencing terms.
2139+
2140+>>> obj1 = TestBorg()
2141+>>> obj2 = TestBorg()
2142+>>> obj1.attribute
2143+0
2144+>>> obj2.attribute
2145+0
2146+>>> obj1.attribute = 12345
2147+>>> obj1.attribute
2148+12345
2149+>>> obj2.attribute
2150+12345
2151+>>> obj2.attribute = 54321
2152+>>> obj1.attribute
2153+54321
2154+>>> obj3 = TestBorg2()
2155+>>> obj3.attribute
2156+1
2157+>>> obj4 = TestBorg2()
2158+>>> obj3.attribute = 98765
2159+>>> obj4.attribute
2160+98765
2161+>>>
2162+
2163+"""
2164+
2165+from util import dbg
2166+
2167+# pylint: disable-msg=R0903
2168+# pylint: disable-msg=R0921
2169+class Borg:
2170+ """Definition of a class that can never be duplicated. Correct usage is
2171+ thus:
2172+
2173+ from borg import Borg
2174+ class foo(Borg):
2175+ # All attributes on a borg class *must* = None
2176+ attribute = None
2177+
2178+ def __init__(self):
2179+ Borg.__init__(self, self.__class__.__name__)
2180+
2181+ def prepare_attributes(self):
2182+ if not self.attribute:
2183+ self.attribute = []
2184+
2185+ bar = foo()
2186+ bar.prepare_attributes()
2187+
2188+ The important thing to note is that all attributes of borg classes *must* be
2189+ declared as being None. If you attempt to use static class attributes you
2190+ will get unpredicted behaviour. Instead, prepare_attributes() must be called
2191+ which will then see the attributes in the shared state, and initialise them
2192+ if necessary."""
2193+ __shared_state = {}
2194+
2195+ def __init__(self, borgtype=None):
2196+ """Class initialiser. Overwrite our class dictionary with the shared
2197+ state. This makes us identical to every other instance of this class
2198+ type."""
2199+ if borgtype is None:
2200+ raise TypeError('Borg::__init__: You must pass a borgtype')
2201+ if not self.__shared_state.has_key(borgtype):
2202+ dbg('Borg::__init__: Preparing borg state for %s' % borgtype)
2203+ self.__shared_state[borgtype] = {}
2204+ self.__dict__ = self.__shared_state[borgtype]
2205+
2206+ def prepare_attributes(self):
2207+ """This should be used to prepare any attributes of the borg class."""
2208+ raise NotImplementedError('prepare_attributes')
2209+
2210+if __name__ == '__main__':
2211+ class TestBorg(Borg):
2212+ attribute = None
2213+
2214+ def __init__(self):
2215+ Borg.__init__(self, self.__class__.__name__)
2216+ self.prepare_attributes()
2217+
2218+ def prepare_attributes(self):
2219+ if not self.attribute:
2220+ self.attribute = 0
2221+
2222+ class TestBorg2(Borg):
2223+ attribute = None
2224+
2225+ def __init__(self):
2226+ Borg.__init__(self, self.__class__.__name__)
2227+ self.prepare_attributes()
2228+
2229+ def prepare_attributes(self):
2230+ if not self.attribute:
2231+ self.attribute = 1
2232+
2233+ import sys
2234+ import doctest
2235+ (failed, attempted) = doctest.testmod()
2236+ print "%d/%d tests failed" % (failed, attempted)
2237+ sys.exit(failed)
2238
2239=== modified file 'terminatorlib/config.py'
2240--- terminatorlib/config.py 2009-12-02 00:19:26 +0000
2241+++ terminatorlib/config.py 2010-01-05 05:03:15 +0000
2242@@ -1,6 +1,6 @@
2243 #!/usr/bin/python
2244 # TerminatorConfig - layered config classes
2245-# Copyright (C) 2006-2008 cmsj@tenshu.net
2246+# Copyright (C) 2006-2010 cmsj@tenshu.net
2247 #
2248 # This program is free software; you can redistribute it and/or modify
2249 # it under the terms of the GNU General Public License as published by
2250@@ -15,53 +15,44 @@
2251 # along with this program; if not, write to the Free Software
2252 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2253
2254-"""TerminatorConfig by Chris Jones <cmsj@tenshu.net>
2255-
2256-The config scheme works in layers, with defaults at the base,
2257-and a simple/flexible class which can be placed over the top
2258-in multiple layers. This was written for Terminator, but
2259-could be used generically. Its original use is to guarantee
2260-default values for any config item, while allowing them to be
2261-overridden by at least two other stores of configuration values.
2262-Those being gconf and a plain config file.
2263-In addition to the value, the default layer must also provide
2264-the datatype (str, int, float and bool are currently supported).
2265-values are found as attributes of the TerminatorConfig object.
2266-Trying to read a value that doesn't exist will raise an
2267-AttributeError. This is by design. If you want to look something
2268-up, set a default for it first."""
2269-
2270+"""Terminator by Chris Jones <cmsj@tenshu.net>
2271+
2272+Classes relating to configuration
2273+
2274+>>> DEFAULTS['global_config']['focus']
2275+'click'
2276+>>> config = Config()
2277+>>> config['focus'] = 'sloppy'
2278+>>> config['focus']
2279+'sloppy'
2280+>>> DEFAULTS['global_config']['focus']
2281+'click'
2282+>>> config2 = Config()
2283+>>> config2['focus']
2284+'sloppy'
2285+>>> config2['focus'] = 'click'
2286+>>> config2['focus']
2287+'click'
2288+>>> config['focus']
2289+'click'
2290+>>> config['fullscreen'].__class__.__name__
2291+'bool'
2292+>>>
2293+
2294+"""
2295+
2296+import platform
2297 import os
2298-import platform
2299 import sys
2300-import re
2301-import pwd
2302-import gtk
2303-import pango
2304-
2305-try:
2306- import gconf
2307-except ImportError:
2308- gconf = None
2309-
2310-from terminatorlib import translation
2311-
2312-# set this to true to enable debugging output
2313-# These should be moved somewhere better.
2314-debug = False
2315-
2316-def dbg (log = ""):
2317- """Print a message if debugging is enabled"""
2318- if debug:
2319- print >> sys.stderr, log
2320-
2321-def err (log = ""):
2322- """Print an error message"""
2323- print >> sys.stderr, log
2324-
2325-from terminatorlib.configfile import ConfigFile, ParsedWithErrors
2326+from copy import copy
2327+from configobj.configobj import ConfigObj
2328+from configobj.validate import Validator
2329+from borg import Borg
2330+from factory import Factory
2331+from util import dbg, err, DEBUG, get_config_dir, dict_diff
2332
2333 DEFAULTS = {
2334+<<<<<<< TREE
2335 'gt_dir' : '/apps/gnome-terminal',
2336 'profile_dir' : '/apps/gnome-terminal/profiles',
2337 'titlebars' : True,
2338@@ -178,369 +169,385 @@
2339 'ungroup_tab' : '<Super><Shift>T',
2340 'new_window' : '<Ctrl><Shift>I',
2341 }
2342+=======
2343+ 'global_config': {
2344+ 'focus' : 'click',
2345+ 'enable_real_transparency' : True,
2346+ 'handle_size' : -1,
2347+ 'geometry_hinting' : True,
2348+ 'fullscreen' : False,
2349+ 'borderless' : False,
2350+ 'maximise' : False,
2351+ 'hidden' : False,
2352+ 'tab_position' : 'top',
2353+ 'close_button_on_tab' : True,
2354+ 'hide_tabbar' : False,
2355+ 'scroll_tabbar' : False,
2356+ 'try_posix_regexp' : platform.system() != 'Linux',
2357+ },
2358+ 'keybindings': {
2359+ 'zoom_in' : '<Ctrl>plus',
2360+ 'zoom_out' : '<Ctrl>minus',
2361+ 'zoom_normal' : '<Ctrl>0',
2362+ 'new_root_tab' : '<Ctrl><Shift><Alt>T',
2363+ 'new_tab' : '<Ctrl><Shift>T',
2364+ 'go_next' : ('<Ctrl><Shift>N','<Ctrl>Tab'),
2365+ 'go_prev' : ('<Ctrl><Shift>P','<Ctrl><Shift>Tab'),
2366+ 'go_up' : '<Alt>Up',
2367+ 'go_down' : '<Alt>Down',
2368+ 'go_left' : '<Alt>Left',
2369+ 'go_right' : '<Alt>Right',
2370+ 'split_horiz' : '<Ctrl><Shift>O',
2371+ 'split_vert' : '<Ctrl><Shift>E',
2372+ 'close_term' : '<Ctrl><Shift>W',
2373+ 'copy' : '<Ctrl><Shift>C',
2374+ 'paste' : '<Ctrl><Shift>V',
2375+ 'toggle_scrollbar' : '<Ctrl><Shift>S',
2376+ 'search' : '<Ctrl><Shift>F',
2377+ 'close_window' : '<Ctrl><Shift>Q',
2378+ 'resize_up' : '<Ctrl><Shift>Up',
2379+ 'resize_down' : '<Ctrl><Shift>Down',
2380+ 'resize_left' : '<Ctrl><Shift>Left',
2381+ 'resize_right' : '<Ctrl><Shift>Right',
2382+ 'move_tab_right' : '<Ctrl><Shift>Page_Down',
2383+ 'move_tab_left' : '<Ctrl><Shift>Page_Up',
2384+ 'toggle_zoom' : '<Ctrl><Shift>X',
2385+ 'scaled_zoom' : '<Ctrl><Shift>Z',
2386+ 'next_tab' : '<Ctrl>Page_Down',
2387+ 'prev_tab' : '<Ctrl>Page_Up',
2388+ 'switch_to_tab_1' : None,
2389+ 'switch_to_tab_2' : None,
2390+ 'switch_to_tab_3' : None,
2391+ 'switch_to_tab_4' : None,
2392+ 'switch_to_tab_5' : None,
2393+ 'switch_to_tab_6' : None,
2394+ 'switch_to_tab_7' : None,
2395+ 'switch_to_tab_8' : None,
2396+ 'switch_to_tab_9' : None,
2397+ 'switch_to_tab_10' : None,
2398+ 'full_screen' : 'F11',
2399+ 'reset' : '<Ctrl><Shift>R',
2400+ 'reset_clear' : '<Ctrl><Shift>G',
2401+ 'hide_window' : '<Ctrl><Shift><Alt>a',
2402+ 'group_all' : '<Super>g',
2403+ 'ungroup_all' : '<Super><Shift>g',
2404+ 'group_tab' : '<Super>t',
2405+ 'ungroup_tab' : '<Super><Shift>T',
2406+ 'new_window' : '<Ctrl><Shift>I',
2407+ },
2408+ 'profiles': {
2409+ 'default': {
2410+ 'titlebars' : True,
2411+ 'zoomedtitlebar' : True,
2412+ 'allow_bold' : True,
2413+ 'audible_bell' : False,
2414+ 'visible_bell' : True,
2415+ 'urgent_bell' : False,
2416+ 'background_color' : '#000000',
2417+ 'background_darkness' : 0.5,
2418+ 'background_type' : 'solid',
2419+ 'background_image' : '',
2420+ 'backspace_binding' : 'ascii-del',
2421+ 'delete_binding' : 'delete-sequence',
2422+ 'cursor_blink' : True,
2423+ 'cursor_shape' : 'block',
2424+ 'cursor_color' : '',
2425+ 'emulation' : 'xterm',
2426+ 'font' : 'Mono 10',
2427+ 'foreground_color' : '#AAAAAA',
2428+ 'scrollbar_position' : "right",
2429+ 'scroll_background' : True,
2430+ 'scroll_on_keystroke' : True,
2431+ 'scroll_on_output' : True,
2432+ 'scrollback_lines' : 500,
2433+ 'exit_action' : 'close',
2434+ 'palette' :'#000000000000:#CDCD00000000:#0000CDCD0000:\
2435+#CDCDCDCD0000:#30BF30BFA38E:#A53C212FA53C:\
2436+#0000CDCDCDCD:#FAFAEBEBD7D7:#404040404040:\
2437+#FFFF00000000:#0000FFFF0000:#FFFFFFFF0000:\
2438+#00000000FFFF:#FFFF0000FFFF:#0000FFFFFFFF:\
2439+#FFFFFFFFFFFF',
2440+ 'word_chars' : '-A-Za-z0-9,./?%&#:_',
2441+ 'mouse_autohide' : True,
2442+ 'update_records' : True,
2443+ 'login_shell' : False,
2444+ 'use_custom_command' : False,
2445+ 'custom_command' : '',
2446+ 'use_system_font' : True,
2447+ 'use_theme_colors' : False,
2448+ 'encoding' : 'UTF-8',
2449+ 'active_encodings' : ['UTF-8', 'ISO-8859-1'],
2450+ 'focus_on_close' : 'auto',
2451+ 'force_no_bell' : False,
2452+ 'cycle_term_tab' : True,
2453+ 'copy_on_selection' : False,
2454+ 'title_tx_txt_color' : '#FFFFFF',
2455+ 'title_tx_bg_color' : '#C80003',
2456+ 'title_rx_txt_color' : '#FFFFFF',
2457+ 'title_rx_bg_color' : '#0076C9',
2458+ 'title_ia_txt_color' : '#000000',
2459+ 'title_ia_bg_color' : '#C0BEBF',
2460+ 'alternate_screen_scroll': True,
2461+ 'split_to_group' : False,
2462+ 'autoclean_groups' : True,
2463+ 'http_proxy' : '',
2464+ 'ignore_hosts' : ['localhost','127.0.0.0/8','*.local'],
2465+ },
2466+ },
2467+ 'layouts': {
2468+ },
2469+ 'plugins': {
2470+ },
2471+>>>>>>> MERGE-SOURCE
2472 }
2473
2474-
2475-class TerminatorConfig(object):
2476- """This class is used as the base point of the config system"""
2477- callback = None
2478- sources = None
2479- _keys = None
2480-
2481- def __init__ (self, sources):
2482- self.sources = []
2483-
2484- for source in sources:
2485- if isinstance(source, TerminatorConfValuestore):
2486- self.sources.append (source)
2487-
2488- # We always add a default valuestore last so no valid config item ever
2489- # goes unset
2490- source = TerminatorConfValuestoreDefault ()
2491- self.sources.append (source)
2492-
2493- def _merge_keybindings(self):
2494- if self._keys:
2495- return self._keys
2496-
2497- self._keys = {}
2498- for source in reversed(self.sources):
2499- try:
2500- val = source['keybindings']
2501- self._keys.update(val)
2502- except:
2503- pass
2504- return self._keys
2505-
2506- keybindings = property(_merge_keybindings)
2507-
2508- def __getattr__ (self, keyname):
2509- for source in self.sources:
2510- dbg ("TConfig: Looking for: '%s' in '%s'"%(keyname, source.type))
2511- try:
2512- val = source[keyname]
2513- dbg (" TConfig: got: '%s' from a '%s'"%(val, source.type))
2514- return (val)
2515- except KeyError:
2516- pass
2517-
2518- dbg (" TConfig: Out of sources")
2519- raise (AttributeError)
2520-
2521-class TerminatorConfValuestore(object):
2522- type = "Base"
2523- values = None
2524- reconfigure_callback = None
2525-
2526- def __init__ (self):
2527- self.values = {}
2528-
2529- # Our settings
2530- def __getitem__ (self, keyname):
2531- if self.values.has_key (keyname):
2532- value = self.values[keyname]
2533- dbg ("Returning '%s':'%s'"%(keyname, value))
2534- return value
2535- else:
2536- dbg ("Failed to find '%s'"%keyname)
2537- raise (KeyError)
2538-
2539-class TerminatorConfValuestoreDefault (TerminatorConfValuestore):
2540- def __init__ (self):
2541- TerminatorConfValuestore.__init__ (self)
2542- self.type = "Default"
2543- self.values = DEFAULTS
2544-
2545-class TerminatorConfValuestoreRC (TerminatorConfValuestore):
2546- rcfilename = ""
2547- type = "RCFile"
2548- def __init__ (self):
2549- TerminatorConfValuestore.__init__ (self)
2550- try:
2551- directory = os.environ['XDG_CONFIG_HOME']
2552- except KeyError:
2553- dbg(" VS_RCFile: XDG_CONFIG_HOME not found. defaulting to ~/.config")
2554- directory = os.path.join (os.path.expanduser("~"), ".config")
2555- self.rcfilename = os.path.join(directory, "terminator/config")
2556- dbg(" VS_RCFile: config file located at %s" % self.rcfilename)
2557- self.call_parser(True)
2558-
2559- def set_reconfigure_callback (self, function):
2560- dbg (" VS_RCFile: setting callback to: %s"%function)
2561- self.reconfigure_callback = function
2562- return (True)
2563-
2564- def call_parser (self, is_init = False):
2565- dbg (" VS_RCFile: parsing config file")
2566- try:
2567- ini = ConfigFile(self.rcfilename, self._rc_set_callback())
2568- ini.parse()
2569- except IOError, ex:
2570- dbg (" VS_RCFile: unable to open %s (%r)" % (self.rcfilename, ex))
2571- except ParsedWithErrors, ex:
2572- # We don't really want to produce an error dialog every run
2573- if not is_init:
2574- pass
2575- msg = _("""<big><b>Configuration error</b></big>
2576-
2577-Errors were encountered while parsing terminator_config(5) file:
2578-
2579- <b>%s</b>
2580-
2581-%d line(s) have been ignored.""") % (self.rcfilename, len(ex.errors))
2582-
2583- dialog = gtk.Dialog(_("Configuration error"), None, gtk.DIALOG_MODAL,
2584- (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
2585- dialog.set_has_separator(False)
2586- dialog.set_resizable(False)
2587-
2588- image = gtk.image_new_from_stock(gtk.STOCK_DIALOG_WARNING,
2589- gtk.ICON_SIZE_DIALOG)
2590- image.set_alignment (0.5, 0)
2591- dmsg = gtk.Label(msg)
2592- dmsg.set_use_markup(True)
2593- dmsg.set_alignment(0, 0.5)
2594-
2595- textbuff = gtk.TextBuffer()
2596- textbuff.set_text("\n".join(map(lambda ex: str(ex), ex.errors)))
2597- textview = gtk.TextView(textbuff)
2598- textview.set_editable(False)
2599-
2600- textview.modify_font(pango.FontDescription(DEFAULTS['font']))
2601- textscroll = gtk.ScrolledWindow()
2602- textscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
2603- textscroll.add(textview)
2604- # This should be scaled with the size of the text and font
2605- textscroll.set_size_request(600, 200)
2606-
2607- root = gtk.VBox()
2608- root.pack_start(dmsg, padding = 6)
2609- root.pack_start(textscroll, padding = 6)
2610-
2611- box = gtk.HBox()
2612- box.pack_start (image, False, False, 6)
2613- box.pack_start (root, False, False, 6)
2614-
2615- vbox = dialog.get_content_area()
2616- vbox.pack_start (box, False, False, 12)
2617- dialog.show_all()
2618-
2619- dialog.run()
2620- dialog.destroy()
2621-
2622- dbg("ConfigFile settings are: %r" % self.values)
2623-
2624- def _rc_set_callback(self):
2625- def callback(sections, key, value):
2626- dbg("Setting: section=%r with %r => %r" % (sections, key, value))
2627- section = None
2628- if len(sections) > 0:
2629- section = sections[0]
2630- if section is None:
2631- # handle some deprecated configs
2632- if key == 'silent_bell':
2633- err ("silent_bell config option is deprecated, for the new bell related config options, see: man terminator_config")
2634- if value:
2635- self.values['audible_bell'] = False
2636- else:
2637- self.values['audible_bell'] = True
2638- key = 'visible_bell'
2639-
2640- if not DEFAULTS.has_key (key):
2641- raise ValueError("Unknown configuration option %r" % key)
2642- deftype = DEFAULTS[key].__class__.__name__
2643- if key.endswith('_color'):
2644- try:
2645- gtk.gdk.color_parse(value)
2646- self.values[key] = value
2647- except ValueError:
2648- raise ValueError(_("Setting %r value %r not a valid colour; ignoring") % (key, value))
2649- elif key == 'tab_position':
2650- if value.lower() in ('top', 'left', 'bottom', 'right'):
2651- self.values[key] = value.lower()
2652- else:
2653- raise ValueError(_("%s must be one of: top, left, right, bottom") % key)
2654- elif deftype == 'bool':
2655- if value.lower () in ('true', 'yes', 'on'):
2656- self.values[key] = True
2657- elif value.lower () in ('false', 'no', 'off'):
2658- self.values[key] = False
2659- else:
2660- raise ValueError(_("Boolean setting %s expecting one of: yes, no, true, false, on, off") % key)
2661- elif deftype == 'int':
2662- self.values[key] = int (value)
2663- elif deftype == 'float':
2664- self.values[key] = float (value)
2665- elif deftype == 'list':
2666- raise ValueError(_("Reading list values from terminator_config(5) is not currently supported"))
2667- elif deftype == 'dict':
2668- if type(value) != dict:
2669- raise ValueError(_("Setting %r should be a section name") % key)
2670- self.values[key] = value
2671- else:
2672- self.values[key] = value
2673-
2674- dbg (" VS_RCFile: Set value %r to %r" % (key, self.values[key]))
2675- elif section == 'keybindings':
2676- self.values.setdefault(section, {})
2677- if not DEFAULTS[section].has_key(key):
2678- raise ValueError("Keybinding name %r is unknown" % key)
2679- else:
2680- self.values[section][key] = value
2681- else:
2682- raise ValueError("Section name %r is unknown" % section)
2683- return callback
2684-
2685-class TerminatorConfValuestoreGConf (TerminatorConfValuestore):
2686- profile = ""
2687- client = None
2688- cache = None
2689- notifies = None
2690-
2691- def __init__ (self, profileName = None):
2692- TerminatorConfValuestore.__init__ (self)
2693- self.type = "GConf"
2694- self.inactive = False
2695- self.cache = {}
2696- self.notifies = {}
2697-
2698- import gconf
2699-
2700- self.client = gconf.client_get_default ()
2701-
2702- # Grab a couple of values from base class to avoid recursing with our __getattr__
2703- self._gt_dir = DEFAULTS['gt_dir']
2704- self._profile_dir = DEFAULTS['profile_dir']
2705-
2706- dbg ('VSGConf: Profile bet on is: "%s"'%profileName)
2707- profiles = self.client.get_list (self._gt_dir + '/global/profile_list','string')
2708- dbg ('VSGConf: Found profiles: "%s"'%profiles)
2709-
2710- dbg ('VSGConf: Profile requested is: "%s"'%profileName)
2711- if not profileName:
2712- profile = self.client.get_string (self._gt_dir + '/global/default_profile')
2713- else:
2714- profile = profileName
2715- # In newer gnome-terminal, the profile keys are named Profile0/1 etc.
2716- # We have to match using visible_name instead
2717- for p in profiles:
2718- profileName2 = self.client.get_string (
2719- self._profile_dir + '/' + p + '/visible_name')
2720- if profileName == profileName2:
2721- profile = p
2722-
2723- #need to handle the list of Gconf.value
2724- if profile in profiles:
2725- dbg (" VSGConf: Found profile '%s' in profile_list"%profile)
2726- self.profile = '%s/%s' % (self._profile_dir, profile)
2727- elif "Default" in profiles:
2728- dbg (" VSGConf: profile '%s' not found, but 'Default' exists" % profile)
2729- self.profile = '%s/%s'%(self._profile_dir, "Default")
2730- else:
2731- # We're a bit stuck, there is no profile in the list
2732- # FIXME: Find a better way to handle this than setting a non-profile
2733- dbg ("VSGConf: No profile found, marking inactive")
2734- self.inactive = True
2735- return
2736-
2737- #set up the active encoding list
2738- self.active_encodings = self.client.get_list (self._gt_dir + '/global/active_encodings', 'string')
2739+class Config(object):
2740+ """Class to provide a slightly richer config API above ConfigBase"""
2741+ base = None
2742+ profile = None
2743
2744- self.client.add_dir (self.profile, gconf.CLIENT_PRELOAD_RECURSIVE)
2745- if self.on_gconf_notify:
2746- self.client.notify_add (self.profile, self.on_gconf_notify)
2747-
2748- self.client.add_dir ('/apps/metacity/general', gconf.CLIENT_PRELOAD_RECURSIVE)
2749- self.client.notify_add ('/apps/metacity/general/focus_mode', self.on_gconf_notify)
2750- self.client.add_dir ('/desktop/gnome/interface', gconf.CLIENT_PRELOAD_RECURSIVE)
2751- self.client.notify_add ('/desktop/gnome/interface/monospace_font_name', self.on_gconf_notify)
2752- # FIXME: Do we need to watch more non-profile stuff here?
2753-
2754- def set_reconfigure_callback (self, function):
2755- dbg (" VSConf: setting callback to: %s"%function)
2756- self.reconfigure_callback = function
2757- return (True)
2758-
2759- def on_gconf_notify (self, client, cnxn_id, entry, what):
2760- dbg (" VSGConf: invalidating cache")
2761- self.cache = {}
2762- dbg (" VSGConf: gconf changed, may run a callback. %s, %s"%(entry.key, entry.value))
2763- if entry.key[-12:] == 'visible_name':
2764- dbg (" VSGConf: only a visible_name change, ignoring")
2765- return False
2766- if self.reconfigure_callback:
2767- dbg (" VSGConf: callback is: %s"%self.reconfigure_callback)
2768- self.reconfigure_callback ()
2769-
2770- def __getitem__ (self, key = ""):
2771- if self.inactive:
2772- raise KeyError
2773-
2774- if self.cache.has_key (key):
2775- dbg (" VSGConf: returning cached value: %s"%self.cache[key])
2776- return (self.cache[key])
2777-
2778- ret = None
2779- value = None
2780-
2781- dbg (' VSGConf: preparing: %s/%s'%(self.profile, key))
2782-
2783- # FIXME: Ugly special cases we should look to fix in some other way.
2784- if key == 'font' and self['use_system_font']:
2785- value = self.client.get ('/desktop/gnome/interface/monospace_font_name')
2786- elif key == 'focus':
2787- value = self.client.get ('/apps/metacity/general/focus_mode')
2788- elif key == 'http_proxy':
2789- if self.client.get_bool ('/system/http_proxy/use_http_proxy'):
2790- dbg ('HACK: Mangling http_proxy')
2791-
2792- if self.client.get_bool ('/system/http_proxy/use_authentication'):
2793- dbg ('HACK: Using proxy authentication')
2794- value = 'http://%s:%s@%s:%s/' % (
2795- self.client.get_string ('/system/http_proxy/authentication_user'),
2796- self.client.get_string ('/system/http_proxy/authentication_password'),
2797- self.client.get_string ('/system/http_proxy/host'),
2798- self.client.get_int ('/system/http_proxy/port'))
2799- else:
2800- dbg ('HACK: Not using proxy authentication')
2801- value = 'http://%s:%s/' % (
2802- self.client.get_string ('/system/http_proxy/host'),
2803- self.client.get_int ('/system/http_proxy/port'))
2804- elif key == 'cursor_blink':
2805- tmp = self.client.get_string('%s/cursor_blink_mode' % self.profile)
2806- if tmp in ['on', 'off'] and self.notifies.has_key ('cursor_blink'):
2807- self.client.notify_remove (self.notifies['cursor_blink'])
2808- del (self.notifies['cursor_blink'])
2809- if tmp == 'on':
2810- value = True
2811- elif tmp == 'off':
2812- value = False
2813- elif tmp == 'system':
2814- value = self.client.get_bool ('/desktop/gnome/interface/cursor_blink')
2815- self.notifies['cursor_blink'] = self.client.notify_add ('/desktop/gnome/interface/cursor_blink', self.on_gconf_notify)
2816- else:
2817- value = self.client.get ('%s/%s'%(self.profile, key))
2818- else:
2819- value = self.client.get ('%s/%s'%(self.profile, key))
2820-
2821- if value != None:
2822- from types import StringType, BooleanType
2823- if type(value) in [StringType, BooleanType]:
2824- ret = value
2825- else:
2826- funcname = "get_" + DEFAULTS[key].__class__.__name__
2827- dbg (' GConf: picked function: %s'%funcname)
2828- # Special case for str
2829- if funcname == "get_str":
2830- funcname = "get_string"
2831- # Special case for strlist
2832- if funcname == "get_strlist":
2833- funcname = "get_list"
2834- typefunc = getattr (value, funcname)
2835- ret = typefunc ()
2836-
2837- self.cache[key] = ret
2838- return (ret)
2839- else:
2840- raise (KeyError)
2841-
2842+ def __init__(self, profile='default'):
2843+ self.base = ConfigBase()
2844+ self.profile = profile
2845+
2846+ def __getitem__(self, key):
2847+ """Look up a configuration item"""
2848+ return(self.base.get_item(key, self.profile))
2849+
2850+ def __setitem__(self, key, value):
2851+ """Set a particular configuration item"""
2852+ return(self.base.set_item(key, value, self.profile))
2853+
2854+ def set_profile(self, profile):
2855+ """Set our profile (which usually means change it)"""
2856+ dbg('Config::set_profile: Changing profile to %s' % profile)
2857+ self.profile = profile
2858+ if not self.base.profiles.has_key(profile):
2859+ dbg('Config::set_profile: %s does not exist, creating' % profile)
2860+ self.base.profiles[profile] = copy(DEFAULTS['profiles']['default'])
2861+
2862+ def del_profile(self, profile):
2863+ """Delete a profile"""
2864+ if self.base.profiles.has_key(profile):
2865+ del(self.base.profiles[profile])
2866+
2867+ def list_profiles(self):
2868+ """List all configured profiles"""
2869+ return(self.base.profiles.keys())
2870+
2871+ def save(self):
2872+ """Cause ConfigBase to save our config to file"""
2873+ return(self.base.save())
2874+
2875+class ConfigBase(Borg):
2876+ """Class to provide access to our user configuration"""
2877+ loaded = None
2878+ sections = None
2879+ global_config = None
2880+ profiles = None
2881+ keybindings = None
2882+ plugins = None
2883+ layouts = None
2884+
2885+ def __init__(self):
2886+ """Class initialiser"""
2887+
2888+ Borg.__init__(self, self.__class__.__name__)
2889+
2890+ self.prepare_attributes()
2891+ self.load()
2892+
2893+ def prepare_attributes(self):
2894+ """Set up our borg environment"""
2895+ if self.loaded is None:
2896+ self.loaded = False
2897+ if self.sections is None:
2898+ self.sections = ['global_config', 'keybindings', 'profiles',
2899+ 'layouts', 'plugins']
2900+ if self.global_config is None:
2901+ self.global_config = copy(DEFAULTS['global_config'])
2902+ if self.profiles is None:
2903+ self.profiles = {}
2904+ self.profiles['default'] = copy(DEFAULTS['profiles']['default'])
2905+ if self.keybindings is None:
2906+ self.keybindings = copy(DEFAULTS['keybindings'])
2907+ if self.plugins is None:
2908+ self.plugins = {}
2909+ if self.layouts is None:
2910+ self.layouts = copy(DEFAULTS['layouts'])
2911+
2912+ def defaults_to_configspec(self):
2913+ """Convert our tree of default values into a ConfigObj validation
2914+ specification"""
2915+ configspecdata = {}
2916+
2917+ section = {}
2918+ for key in DEFAULTS['global_config']:
2919+ keytype = DEFAULTS['global_config'][key].__class__.__name__
2920+ value = DEFAULTS['global_config'][key]
2921+ if keytype == 'int':
2922+ keytype = 'integer'
2923+ elif keytype == 'str':
2924+ keytype = 'string'
2925+ elif keytype == 'bool':
2926+ keytype = 'boolean'
2927+ elif keytype == 'list':
2928+ value = 'list(%s)' % ','.join(value)
2929+
2930+ keytype = '%s(default=%s)' % (keytype, value)
2931+
2932+ section[key] = keytype
2933+ configspecdata['global_config'] = section
2934+
2935+ section = {}
2936+ for key in DEFAULTS['keybindings']:
2937+ value = DEFAULTS['keybindings'][key]
2938+ if value is None:
2939+ continue
2940+ elif isinstance(value, tuple):
2941+ value = value[0]
2942+ section[key] = 'string(default=%s)' % value
2943+ configspecdata['keybindings'] = section
2944+
2945+ section = {}
2946+ for key in DEFAULTS['profiles']['default']:
2947+ keytype = DEFAULTS['profiles']['default'][key].__class__.__name__
2948+ value = DEFAULTS['profiles']['default'][key]
2949+ if keytype == 'int':
2950+ keytype = 'integer'
2951+ elif keytype == 'bool':
2952+ keytype = 'boolean'
2953+ elif keytype == 'str':
2954+ keytype = 'string'
2955+ value = '"%s"' % value
2956+ elif keytype == 'list':
2957+ value = 'list(%s)' % ','.join(value)
2958+
2959+ keytype = '%s(default=%s)' % (keytype, value)
2960+
2961+ section[key] = keytype
2962+ configspecdata['profiles'] = {}
2963+ configspecdata['profiles']['__many__'] = section
2964+
2965+ configspec = ConfigObj(configspecdata)
2966+ if DEBUG == True:
2967+ configspec.write(open('/tmp/terminator_configspec_debug.txt', 'w'))
2968+ return(configspec)
2969+
2970+ def load(self):
2971+ """Load configuration data from our various sources"""
2972+ if self.loaded is True:
2973+ dbg('ConfigBase::load: config already loaded')
2974+ return
2975+
2976+ filename = os.path.join(get_config_dir(), 'epic-config')
2977+ try:
2978+ configfile = open(filename, 'r')
2979+ except Exception, ex:
2980+ dbg('ConfigBase::load: Unable to open %s (%s)' % (filename, ex))
2981+ return
2982+
2983+ configspec = self.defaults_to_configspec()
2984+ parser = ConfigObj(configfile, configspec=configspec)
2985+ validator = Validator()
2986+ result = parser.validate(validator, preserve_errors=True)
2987+
2988+ if result != True:
2989+ err('ConfigBase::load: config format is not valid')
2990+
2991+ for section_name in self.sections:
2992+ dbg('ConfigBase::load: Processing section: %s' % section_name)
2993+ section = getattr(self, section_name)
2994+ if section_name == 'profiles':
2995+ for profile in parser[section_name]:
2996+ dbg('ConfigBase::load: Processing profile: %s' % profile)
2997+ if not section.has_key(section_name):
2998+ section[profile] = copy(DEFAULTS['profiles']['default'])
2999+ section[profile].update(parser[section_name][profile])
3000+ elif section_name == ['layouts', 'plugins']:
3001+ for part in parser[section_name]:
3002+ dbg('ConfigBase::load: Processing %s: %s' % (section_name,
3003+ part))
3004+ section[part] = parser[section_name][part]
3005+ else:
3006+ try:
3007+ section.update(parser[section_name])
3008+ except KeyError, ex:
3009+ dbg('ConfigBase::load: skipping loading missing section %s' %
3010+ section_name)
3011+
3012+ self.loaded = True
3013+
3014+ def save(self):
3015+ """Save the config to a file"""
3016+ dbg('ConfigBase::save: saving config')
3017+ parser = ConfigObj()
3018+ parser.indent_type = ' '
3019+
3020+ for section_name in ['global_config', 'keybindings']:
3021+ dbg('ConfigBase::save: Processing section: %s' % section_name)
3022+ section = getattr(self, section_name)
3023+ parser[section_name] = dict_diff(DEFAULTS[section_name], section)
3024+
3025+ parser['profiles'] = {}
3026+ for profile in self.profiles:
3027+ dbg('ConfigBase::save: Processing profile: %s' % profile)
3028+ parser['profiles'][profile] = dict_diff(DEFAULTS['profiles']['default'],
3029+ self.profiles[profile])
3030+
3031+ parser['layouts'] = {}
3032+ for layout in self.layouts:
3033+ dbg('ConfigBase::save: Processing layout: %s' % layout)
3034+ parser['layouts'][layout] = self.layouts[layout]
3035+
3036+ parser['plugins'] = {}
3037+ for plugin in self.plugins:
3038+ dbg('ConfigBase::save: Processing plugin: %s' % plugin)
3039+ parser['plugins'][plugin] = self.plugins[plugin]
3040+
3041+ parser.write(open(os.path.join(get_config_dir(), 'epic-config'), 'w'))
3042+
3043+ def get_item(self, key, profile='default', plugin=None):
3044+ """Look up a configuration item"""
3045+ dbg('ConfigBase::get_item: %s:%s' % (profile, key))
3046+ if self.global_config.has_key(key):
3047+ dbg('ConfigBase::get_item: found in globals: %s' %
3048+ self.global_config[key])
3049+ return(self.global_config[key])
3050+ elif self.profiles[profile].has_key(key):
3051+ dbg('ConfigBase::get_item: found in profile %s (%s)' % (
3052+ profile, self.profiles[profile][key]))
3053+ return(self.profiles[profile][key])
3054+ elif key == 'keybindings':
3055+ return(self.keybindings)
3056+ elif plugin is not None and self.plugins[plugin].has_key(key):
3057+ dbg('ConfigBase::get_item: found in plugin %s (%s)' % (
3058+ plugin, self.plugins[plugin][key]))
3059+ return(self.plugins[plugin][key])
3060+ else:
3061+ raise KeyError('ConfigBase::get_item: unknown key %s' % key)
3062+
3063+ def set_item(self, key, value, profile='default', plugin=None):
3064+ """Set a configuration item"""
3065+ dbg('ConfigBase::set_item: Setting %s=%s (profile=%s, plugin=%s)' %
3066+ (key, value, profile, plugin))
3067+
3068+ if self.global_config.has_key(key):
3069+ self.global_config[key] = value
3070+ elif self.profiles[profile].has_key(key):
3071+ self.profiles[profile][key] = value
3072+ elif key == 'keybindings':
3073+ self.keybindings = value
3074+ elif plugin is not None and self.plugins[plugin].has_key(key):
3075+ self.plugins[plugin][key] = value
3076+ else:
3077+ raise KeyError('ConfigBase::set_item: unknown key %s' % key)
3078+
3079+ return(True)
3080+
3081+if __name__ == '__main__':
3082+ import sys
3083+ import doctest
3084+ (failed, attempted) = doctest.testmod()
3085+ print "%d/%d tests failed" % (failed, attempted)
3086+ sys.exit(failed)
3087
3088=== removed file 'terminatorlib/configfile.py'
3089--- terminatorlib/configfile.py 2009-05-07 00:44:42 +0000
3090+++ terminatorlib/configfile.py 1970-01-01 00:00:00 +0000
3091@@ -1,233 +0,0 @@
3092-#!/usr/bin/python
3093-
3094-import re
3095-from terminatorlib.config import dbg, debug
3096-from terminatorlib import translation
3097-
3098-def group(*choices): return '(' + '|'.join(choices) + ')'
3099-def any(*choices): return group(*choices) + '*'
3100-def maybe(*choices): return group(*choices) + '?'
3101-
3102-Newline = re.compile(r'[\r\n]+')
3103-Whitespace = r'[ \f\t]*'
3104-Comment = r'#[^\r\n]*'
3105-Ignore = re.compile(Whitespace + maybe(Comment) + maybe(r'[\r\n]+') + '$')
3106-
3107-WhitespaceRE = re.compile(Whitespace)
3108-CommentRE = re.compile(Comment)
3109-
3110-QuotedStrings = {"'": re.compile(r"'([^'\r\n]*)'"), '"': re.compile(r'"([^"\r\n]*)"')}
3111-
3112-Section = re.compile(r"\[([^\r\n\]]+)\][ \f\t]*")
3113-Setting = re.compile(r"(\w+)\s*=\s*")
3114-
3115-PaletteColours = '(?:#[0-9a-fA-F]{12}:){15}#[0-9a-fA-F]{12}'
3116-SingleColour = '#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}'
3117-
3118-Colourvalue = re.compile(group(PaletteColours, SingleColour))
3119-Barevalue = re.compile(r'((?:[^\r\n# \f\t]+|[^\r\n#]+(?!' + Ignore.pattern +'))+)')
3120-
3121-Tabsize = 8
3122-HandleIndents = False
3123-
3124-class ConfigSyntaxError(Exception):
3125- def __init__(self, message, cf):
3126- self.single_error = cf.errors_are_fatal
3127- self.message = message
3128- self.file = cf.filename
3129- self.lnum = cf._lnum
3130- self.pos = cf._pos
3131- self.line = cf._line
3132-
3133- def __str__(self):
3134- if self.single_error:
3135- fmt = "File %(file)s line %(lnum)d:\n %(line)s\n %(pad)s^\n%(message)s"
3136- else:
3137- fmt = " * %(message)s, line %(lnum)d:\n %(line)s\n %(pad)s^\n"
3138- return fmt % {'message': self.message, 'file': self.file, 'lnum': self.lnum,
3139- 'line': self.line.rstrip(), 'pad': '-' * self.pos}
3140-
3141-class ConfigIndentError(ConfigSyntaxError):
3142- pass
3143-
3144-class ParsedWithErrors(Exception):
3145- def __init__(self, filename, errors):
3146- self.file = filename
3147- self.errors = errors
3148-
3149- def __str__(self):
3150- return """Errors were encountered while parsing configuration file:
3151-
3152- %r
3153-
3154-Some lines have been ignored.
3155-
3156-%s
3157-""" % (self.file, "\n".join(map(lambda error: str(error), self.errors)))
3158-
3159-
3160-class ConfigFile:
3161- def __init__(self, filename = None, callback = None, errors_are_fatal = False):
3162- self.callback = callback
3163- self.errors_are_fatal = errors_are_fatal
3164- self.filename = filename
3165- self.errors = []
3166-
3167- def _call_if_match(self, re, callable, group = 0):
3168- if self._pos == self._max:
3169- return False
3170- mo = re.match(self._line, self._pos)
3171- if mo:
3172- if callable:
3173- callable(mo.group(group))
3174- self._pos = mo.end()
3175- return True
3176- else:
3177- return False
3178-
3179- def _call_if_quoted_string(self, callable):
3180- if self._pos == self._max:
3181- return False
3182- chr = self._line[self._pos]
3183- if chr in '"\'':
3184- string = ''
3185- while True:
3186- mo = QuotedStrings[chr].match(self._line, self._pos)
3187- if mo is None:
3188- raise ConfigSyntaxError(_("Unterminated quoted string"), self)
3189- self._pos = mo.end()
3190- if self._line[self._pos - 2] == '\\':
3191- string += mo.group(1)[0:-1] + chr
3192- self._pos -= 1
3193- else:
3194- string += mo.group(1)
3195- break
3196- callable(string)
3197- return True
3198- else:
3199- return False
3200-
3201- def parse(self):
3202- file = open(self.filename)
3203- rc = file.readlines()
3204- file.close()
3205-
3206- self._indents = [0]
3207- self._pos = 0
3208- self._max = 0
3209- self._lnum = 0
3210- self._line = ''
3211-
3212- self._sections = {}
3213- self._currsetting = None
3214- self._currvalue = None
3215- self.errors = []
3216-
3217- for self._line in rc:
3218- try:
3219- self._lnum += 1
3220- self._pos = 0
3221- self._max = len(self._line)
3222- dbg("Line %d: %r" % (self._lnum, self._line))
3223-
3224- if HandleIndents:
3225- self._find_indent()
3226- else:
3227- self._call_if_match(WhitespaceRE, None)
3228-
3229- # [Section]
3230- self._call_if_match(Section, self._section, 1)
3231- # setting =
3232- if self._call_if_match(Setting, self._setting, 1):
3233- # "quoted value"
3234- if not self._call_if_quoted_string(self._value):
3235- # #000000 # colour that would otherwise be a comment
3236- if not self._call_if_match(Colourvalue, self._value, 1):
3237- # bare value
3238- if not self._call_if_match(Barevalue, self._value, 1):
3239- raise ConfigSyntaxError(_("Setting without a value"), self)
3240-
3241- self._call_if_match(Ignore, lambda junk: dbg("Skipping: %r" % junk))
3242-
3243- if self._line[self._pos:] != '':
3244- raise ConfigSyntaxError(_("Unexpected token"), self)
3245- self._line_ok()
3246- except ConfigSyntaxError, e:
3247- self._line_error(e)
3248- except ConfigIndentError, e:
3249- self.errors.append(e)
3250- break
3251-
3252- if self.errors:
3253- raise ParsedWithErrors(self.filename, self.errors)
3254-
3255- def _find_indent(self):
3256- # Based on tokenizer.py in the base Python standard library
3257- column = 0
3258- while self._pos < self._max:
3259- chr = self._line[self._pos]
3260- if chr == ' ': column += 1
3261- elif chr == '\t': column = (column / Tabsize + 1) * Tabsize
3262- elif chr == '\f': column = 0
3263- else: break
3264- self._pos += 1
3265- if self._pos == self._max: return
3266-
3267- if column > self._indents[-1]:
3268- self._indents.append(column)
3269- self._indent() # self._line[:self._pos])
3270-
3271- while column < self._indents[-1]:
3272- if column not in self._indents:
3273- raise ConfigSyntaxError("Unindent does not match a previous indent, config parsing aborted", self)
3274- self._indents.pop()
3275- self._deindent()
3276-
3277- def _indent(self):
3278- dbg(" -> Indent %d" % len(self._indents))
3279-
3280- def _deindent(self):
3281- dbg(" -> Deindent %d" % len(self._indents))
3282-
3283- def _get_section(self):
3284- i = 1
3285- sections = []
3286- while i <= len(self._indents):
3287- sname = self._sections.get(i, None)
3288- if not sname:
3289- break
3290- sections.append(str(sname))
3291- i += 1
3292- return tuple(sections)
3293-
3294- def _section(self, section):
3295- dbg("Section %r" % section)
3296- self._sections[len(self._indents)] = section.lower()
3297-
3298- def _setting(self, setting):
3299- dbg("Setting %r" % setting)
3300- self._currsetting = setting.lower()
3301-
3302- def _value(self, value):
3303- dbg("Value %r" % value)
3304- self._currvalue = value
3305-
3306- def _line_ok(self):
3307- if self._currvalue is None: return
3308- else:
3309- try: # *glares at 2.4 users*
3310- try:
3311- self.callback(self._get_section(), self._currsetting, self._currvalue)
3312- except ValueError, e:
3313- raise ConfigSyntaxError(str(e), self)
3314- finally:
3315- self._currvalue = None
3316-
3317- def _line_error(self, e):
3318- self._currvalue = None
3319- if self.errors_are_fatal:
3320- raise e
3321- else:
3322- self.errors.append(e)
3323-
3324-
3325
3326=== added directory 'terminatorlib/configobj'
3327=== added file 'terminatorlib/configobj/__init__.py'
3328=== added file 'terminatorlib/configobj/configobj.py'
3329--- terminatorlib/configobj/configobj.py 1970-01-01 00:00:00 +0000
3330+++ terminatorlib/configobj/configobj.py 2010-01-05 05:03:16 +0000
3331@@ -0,0 +1,2455 @@
3332+# configobj.py
3333+# A config file reader/writer that supports nested sections in config files.
3334+# Copyright (C) 2005-2009 Michael Foord, Nicola Larosa
3335+# E-mail: fuzzyman AT voidspace DOT org DOT uk
3336+# nico AT tekNico DOT net
3337+
3338+# ConfigObj 4
3339+# http://www.voidspace.org.uk/python/configobj.html
3340+
3341+# Released subject to the BSD License
3342+# Please see http://www.voidspace.org.uk/python/license.shtml
3343+
3344+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
3345+# For information about bugfixes, updates and support, please join the
3346+# ConfigObj mailing list:
3347+# http://lists.sourceforge.net/lists/listinfo/configobj-develop
3348+# Comments, suggestions and bug reports welcome.
3349+
3350+
3351+from __future__ import generators
3352+
3353+import sys
3354+import os
3355+import re
3356+
3357+compiler = None
3358+try:
3359+ import compiler
3360+except ImportError:
3361+ # for IronPython
3362+ pass
3363+
3364+
3365+try:
3366+ from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
3367+except ImportError:
3368+ # Python 2.2 does not have these
3369+ # UTF-8
3370+ BOM_UTF8 = '\xef\xbb\xbf'
3371+ # UTF-16, little endian
3372+ BOM_UTF16_LE = '\xff\xfe'
3373+ # UTF-16, big endian
3374+ BOM_UTF16_BE = '\xfe\xff'
3375+ if sys.byteorder == 'little':
3376+ # UTF-16, native endianness
3377+ BOM_UTF16 = BOM_UTF16_LE
3378+ else:
3379+ # UTF-16, native endianness
3380+ BOM_UTF16 = BOM_UTF16_BE
3381+
3382+# A dictionary mapping BOM to
3383+# the encoding to decode with, and what to set the
3384+# encoding attribute to.
3385+BOMS = {
3386+ BOM_UTF8: ('utf_8', None),
3387+ BOM_UTF16_BE: ('utf16_be', 'utf_16'),
3388+ BOM_UTF16_LE: ('utf16_le', 'utf_16'),
3389+ BOM_UTF16: ('utf_16', 'utf_16'),
3390+ }
3391+# All legal variants of the BOM codecs.
3392+# TODO: the list of aliases is not meant to be exhaustive, is there a
3393+# better way ?
3394+BOM_LIST = {
3395+ 'utf_16': 'utf_16',
3396+ 'u16': 'utf_16',
3397+ 'utf16': 'utf_16',
3398+ 'utf-16': 'utf_16',
3399+ 'utf16_be': 'utf16_be',
3400+ 'utf_16_be': 'utf16_be',
3401+ 'utf-16be': 'utf16_be',
3402+ 'utf16_le': 'utf16_le',
3403+ 'utf_16_le': 'utf16_le',
3404+ 'utf-16le': 'utf16_le',
3405+ 'utf_8': 'utf_8',
3406+ 'u8': 'utf_8',
3407+ 'utf': 'utf_8',
3408+ 'utf8': 'utf_8',
3409+ 'utf-8': 'utf_8',
3410+ }
3411+
3412+# Map of encodings to the BOM to write.
3413+BOM_SET = {
3414+ 'utf_8': BOM_UTF8,
3415+ 'utf_16': BOM_UTF16,
3416+ 'utf16_be': BOM_UTF16_BE,
3417+ 'utf16_le': BOM_UTF16_LE,
3418+ None: BOM_UTF8
3419+ }
3420+
3421+
3422+def match_utf8(encoding):
3423+ return BOM_LIST.get(encoding.lower()) == 'utf_8'
3424+
3425+
3426+# Quote strings used for writing values
3427+squot = "'%s'"
3428+dquot = '"%s"'
3429+noquot = "%s"
3430+wspace_plus = ' \r\n\v\t\'"'
3431+tsquot = '"""%s"""'
3432+tdquot = "'''%s'''"
3433+
3434+try:
3435+ enumerate
3436+except NameError:
3437+ def enumerate(obj):
3438+ """enumerate for Python 2.2."""
3439+ i = -1
3440+ for item in obj:
3441+ i += 1
3442+ yield i, item
3443+
3444+# Sentinel for use in getattr calls to replace hasattr
3445+MISSING = object()
3446+
3447+__version__ = '4.6.0'
3448+
3449+__revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
3450+
3451+__docformat__ = "restructuredtext en"
3452+
3453+__all__ = (
3454+ '__version__',
3455+ 'DEFAULT_INDENT_TYPE',
3456+ 'DEFAULT_INTERPOLATION',
3457+ 'ConfigObjError',
3458+ 'NestingError',
3459+ 'ParseError',
3460+ 'DuplicateError',
3461+ 'ConfigspecError',
3462+ 'ConfigObj',
3463+ 'SimpleVal',
3464+ 'InterpolationError',
3465+ 'InterpolationLoopError',
3466+ 'MissingInterpolationOption',
3467+ 'RepeatSectionError',
3468+ 'ReloadError',
3469+ 'UnreprError',
3470+ 'UnknownType',
3471+ '__docformat__',
3472+ 'flatten_errors',
3473+)
3474+
3475+DEFAULT_INTERPOLATION = 'configparser'
3476+DEFAULT_INDENT_TYPE = ' '
3477+MAX_INTERPOL_DEPTH = 10
3478+
3479+OPTION_DEFAULTS = {
3480+ 'interpolation': True,
3481+ 'raise_errors': False,
3482+ 'list_values': True,
3483+ 'create_empty': False,
3484+ 'file_error': False,
3485+ 'configspec': None,
3486+ 'stringify': True,
3487+ # option may be set to one of ('', ' ', '\t')
3488+ 'indent_type': None,
3489+ 'encoding': None,
3490+ 'default_encoding': None,
3491+ 'unrepr': False,
3492+ 'write_empty_values': False,
3493+}
3494+
3495+
3496+
3497+def getObj(s):
3498+ s = "a=" + s
3499+ if compiler is None:
3500+ raise ImportError('compiler module not available')
3501+ p = compiler.parse(s)
3502+ return p.getChildren()[1].getChildren()[0].getChildren()[1]
3503+
3504+
3505+class UnknownType(Exception):
3506+ pass
3507+
3508+
3509+class Builder(object):
3510+
3511+ def build(self, o):
3512+ m = getattr(self, 'build_' + o.__class__.__name__, None)
3513+ if m is None:
3514+ raise UnknownType(o.__class__.__name__)
3515+ return m(o)
3516+
3517+ def build_List(self, o):
3518+ return map(self.build, o.getChildren())
3519+
3520+ def build_Const(self, o):
3521+ return o.value
3522+
3523+ def build_Dict(self, o):
3524+ d = {}
3525+ i = iter(map(self.build, o.getChildren()))
3526+ for el in i:
3527+ d[el] = i.next()
3528+ return d
3529+
3530+ def build_Tuple(self, o):
3531+ return tuple(self.build_List(o))
3532+
3533+ def build_Name(self, o):
3534+ if o.name == 'None':
3535+ return None
3536+ if o.name == 'True':
3537+ return True
3538+ if o.name == 'False':
3539+ return False
3540+
3541+ # An undefined Name
3542+ raise UnknownType('Undefined Name')
3543+
3544+ def build_Add(self, o):
3545+ real, imag = map(self.build_Const, o.getChildren())
3546+ try:
3547+ real = float(real)
3548+ except TypeError:
3549+ raise UnknownType('Add')
3550+ if not isinstance(imag, complex) or imag.real != 0.0:
3551+ raise UnknownType('Add')
3552+ return real+imag
3553+
3554+ def build_Getattr(self, o):
3555+ parent = self.build(o.expr)
3556+ return getattr(parent, o.attrname)
3557+
3558+ def build_UnarySub(self, o):
3559+ return -self.build_Const(o.getChildren()[0])
3560+
3561+ def build_UnaryAdd(self, o):
3562+ return self.build_Const(o.getChildren()[0])
3563+
3564+
3565+_builder = Builder()
3566+
3567+
3568+def unrepr(s):
3569+ if not s:
3570+ return s
3571+ return _builder.build(getObj(s))
3572+
3573+
3574+
3575+class ConfigObjError(SyntaxError):
3576+ """
3577+ This is the base class for all errors that ConfigObj raises.
3578+ It is a subclass of SyntaxError.
3579+ """
3580+ def __init__(self, message='', line_number=None, line=''):
3581+ self.line = line
3582+ self.line_number = line_number
3583+ SyntaxError.__init__(self, message)
3584+
3585+
3586+class NestingError(ConfigObjError):
3587+ """
3588+ This error indicates a level of nesting that doesn't match.
3589+ """
3590+
3591+
3592+class ParseError(ConfigObjError):
3593+ """
3594+ This error indicates that a line is badly written.
3595+ It is neither a valid ``key = value`` line,
3596+ nor a valid section marker line.
3597+ """
3598+
3599+
3600+class ReloadError(IOError):
3601+ """
3602+ A 'reload' operation failed.
3603+ This exception is a subclass of ``IOError``.
3604+ """
3605+ def __init__(self):
3606+ IOError.__init__(self, 'reload failed, filename is not set.')
3607+
3608+
3609+class DuplicateError(ConfigObjError):
3610+ """
3611+ The keyword or section specified already exists.
3612+ """
3613+
3614+
3615+class ConfigspecError(ConfigObjError):
3616+ """
3617+ An error occured whilst parsing a configspec.
3618+ """
3619+
3620+
3621+class InterpolationError(ConfigObjError):
3622+ """Base class for the two interpolation errors."""
3623+
3624+
3625+class InterpolationLoopError(InterpolationError):
3626+ """Maximum interpolation depth exceeded in string interpolation."""
3627+
3628+ def __init__(self, option):
3629+ InterpolationError.__init__(
3630+ self,
3631+ 'interpolation loop detected in value "%s".' % option)
3632+
3633+
3634+class RepeatSectionError(ConfigObjError):
3635+ """
3636+ This error indicates additional sections in a section with a
3637+ ``__many__`` (repeated) section.
3638+ """
3639+
3640+
3641+class MissingInterpolationOption(InterpolationError):
3642+ """A value specified for interpolation was missing."""
3643+
3644+ def __init__(self, option):
3645+ InterpolationError.__init__(
3646+ self,
3647+ 'missing option "%s" in interpolation.' % option)
3648+
3649+
3650+class UnreprError(ConfigObjError):
3651+ """An error parsing in unrepr mode."""
3652+
3653+
3654+
3655+class InterpolationEngine(object):
3656+ """
3657+ A helper class to help perform string interpolation.
3658+
3659+ This class is an abstract base class; its descendants perform
3660+ the actual work.
3661+ """
3662+
3663+ # compiled regexp to use in self.interpolate()
3664+ _KEYCRE = re.compile(r"%\(([^)]*)\)s")
3665+
3666+ def __init__(self, section):
3667+ # the Section instance that "owns" this engine
3668+ self.section = section
3669+
3670+
3671+ def interpolate(self, key, value):
3672+ def recursive_interpolate(key, value, section, backtrail):
3673+ """The function that does the actual work.
3674+
3675+ ``value``: the string we're trying to interpolate.
3676+ ``section``: the section in which that string was found
3677+ ``backtrail``: a dict to keep track of where we've been,
3678+ to detect and prevent infinite recursion loops
3679+
3680+ This is similar to a depth-first-search algorithm.
3681+ """
3682+ # Have we been here already?
3683+ if backtrail.has_key((key, section.name)):
3684+ # Yes - infinite loop detected
3685+ raise InterpolationLoopError(key)
3686+ # Place a marker on our backtrail so we won't come back here again
3687+ backtrail[(key, section.name)] = 1
3688+
3689+ # Now start the actual work
3690+ match = self._KEYCRE.search(value)
3691+ while match:
3692+ # The actual parsing of the match is implementation-dependent,
3693+ # so delegate to our helper function
3694+ k, v, s = self._parse_match(match)
3695+ if k is None:
3696+ # That's the signal that no further interpolation is needed
3697+ replacement = v
3698+ else:
3699+ # Further interpolation may be needed to obtain final value
3700+ replacement = recursive_interpolate(k, v, s, backtrail)
3701+ # Replace the matched string with its final value
3702+ start, end = match.span()
3703+ value = ''.join((value[:start], replacement, value[end:]))
3704+ new_search_start = start + len(replacement)
3705+ # Pick up the next interpolation key, if any, for next time
3706+ # through the while loop
3707+ match = self._KEYCRE.search(value, new_search_start)
3708+
3709+ # Now safe to come back here again; remove marker from backtrail
3710+ del backtrail[(key, section.name)]
3711+
3712+ return value
3713+
3714+ # Back in interpolate(), all we have to do is kick off the recursive
3715+ # function with appropriate starting values
3716+ value = recursive_interpolate(key, value, self.section, {})
3717+ return value
3718+
3719+
3720+ def _fetch(self, key):
3721+ """Helper function to fetch values from owning section.
3722+
3723+ Returns a 2-tuple: the value, and the section where it was found.
3724+ """
3725+ # switch off interpolation before we try and fetch anything !
3726+ save_interp = self.section.main.interpolation
3727+ self.section.main.interpolation = False
3728+
3729+ # Start at section that "owns" this InterpolationEngine
3730+ current_section = self.section
3731+ while True:
3732+ # try the current section first
3733+ val = current_section.get(key)
3734+ if val is not None:
3735+ break
3736+ # try "DEFAULT" next
3737+ val = current_section.get('DEFAULT', {}).get(key)
3738+ if val is not None:
3739+ break
3740+ # move up to parent and try again
3741+ # top-level's parent is itself
3742+ if current_section.parent is current_section:
3743+ # reached top level, time to give up
3744+ break
3745+ current_section = current_section.parent
3746+
3747+ # restore interpolation to previous value before returning
3748+ self.section.main.interpolation = save_interp
3749+ if val is None:
3750+ raise MissingInterpolationOption(key)
3751+ return val, current_section
3752+
3753+
3754+ def _parse_match(self, match):
3755+ """Implementation-dependent helper function.
3756+
3757+ Will be passed a match object corresponding to the interpolation
3758+ key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
3759+ key in the appropriate config file section (using the ``_fetch()``
3760+ helper function) and return a 3-tuple: (key, value, section)
3761+
3762+ ``key`` is the name of the key we're looking for
3763+ ``value`` is the value found for that key
3764+ ``section`` is a reference to the section where it was found
3765+
3766+ ``key`` and ``section`` should be None if no further
3767+ interpolation should be performed on the resulting value
3768+ (e.g., if we interpolated "$$" and returned "$").
3769+ """
3770+ raise NotImplementedError()
3771+
3772+
3773+
3774+class ConfigParserInterpolation(InterpolationEngine):
3775+ """Behaves like ConfigParser."""
3776+ _KEYCRE = re.compile(r"%\(([^)]*)\)s")
3777+
3778+ def _parse_match(self, match):
3779+ key = match.group(1)
3780+ value, section = self._fetch(key)
3781+ return key, value, section
3782+
3783+
3784+
3785+class TemplateInterpolation(InterpolationEngine):
3786+ """Behaves like string.Template."""
3787+ _delimiter = '$'
3788+ _KEYCRE = re.compile(r"""
3789+ \$(?:
3790+ (?P<escaped>\$) | # Two $ signs
3791+ (?P<named>[_a-z][_a-z0-9]*) | # $name format
3792+ {(?P<braced>[^}]*)} # ${name} format
3793+ )
3794+ """, re.IGNORECASE | re.VERBOSE)
3795+
3796+ def _parse_match(self, match):
3797+ # Valid name (in or out of braces): fetch value from section
3798+ key = match.group('named') or match.group('braced')
3799+ if key is not None:
3800+ value, section = self._fetch(key)
3801+ return key, value, section
3802+ # Escaped delimiter (e.g., $$): return single delimiter
3803+ if match.group('escaped') is not None:
3804+ # Return None for key and section to indicate it's time to stop
3805+ return None, self._delimiter, None
3806+ # Anything else: ignore completely, just return it unchanged
3807+ return None, match.group(), None
3808+
3809+
3810+interpolation_engines = {
3811+ 'configparser': ConfigParserInterpolation,
3812+ 'template': TemplateInterpolation,
3813+}
3814+
3815+
3816+def __newobj__(cls, *args):
3817+ # Hack for pickle
3818+ return cls.__new__(cls, *args)
3819+
3820+class Section(dict):
3821+ """
3822+ A dictionary-like object that represents a section in a config file.
3823+
3824+ It does string interpolation if the 'interpolation' attribute
3825+ of the 'main' object is set to True.
3826+
3827+ Interpolation is tried first from this object, then from the 'DEFAULT'
3828+ section of this object, next from the parent and its 'DEFAULT' section,
3829+ and so on until the main object is reached.
3830+
3831+ A Section will behave like an ordered dictionary - following the
3832+ order of the ``scalars`` and ``sections`` attributes.
3833+ You can use this to change the order of members.
3834+
3835+ Iteration follows the order: scalars, then sections.
3836+ """
3837+
3838+
3839+ def __setstate__(self, state):
3840+ dict.update(self, state[0])
3841+ self.__dict__.update(state[1])
3842+
3843+ def __reduce__(self):
3844+ state = (dict(self), self.__dict__)
3845+ return (__newobj__, (self.__class__,), state)
3846+
3847+
3848+ def __init__(self, parent, depth, main, indict=None, name=None):
3849+ """
3850+ * parent is the section above
3851+ * depth is the depth level of this section
3852+ * main is the main ConfigObj
3853+ * indict is a dictionary to initialise the section with
3854+ """
3855+ if indict is None:
3856+ indict = {}
3857+ dict.__init__(self)
3858+ # used for nesting level *and* interpolation
3859+ self.parent = parent
3860+ # used for the interpolation attribute
3861+ self.main = main
3862+ # level of nesting depth of this Section
3863+ self.depth = depth
3864+ # purely for information
3865+ self.name = name
3866+ #
3867+ self._initialise()
3868+ # we do this explicitly so that __setitem__ is used properly
3869+ # (rather than just passing to ``dict.__init__``)
3870+ for entry, value in indict.iteritems():
3871+ self[entry] = value
3872+
3873+
3874+ def _initialise(self):
3875+ # the sequence of scalar values in this Section
3876+ self.scalars = []
3877+ # the sequence of sections in this Section
3878+ self.sections = []
3879+ # for comments :-)
3880+ self.comments = {}
3881+ self.inline_comments = {}
3882+ # the configspec
3883+ self.configspec = None
3884+ # for defaults
3885+ self.defaults = []
3886+ self.default_values = {}
3887+
3888+
3889+ def _interpolate(self, key, value):
3890+ try:
3891+ # do we already have an interpolation engine?
3892+ engine = self._interpolation_engine
3893+ except AttributeError:
3894+ # not yet: first time running _interpolate(), so pick the engine
3895+ name = self.main.interpolation
3896+ if name == True: # note that "if name:" would be incorrect here
3897+ # backwards-compatibility: interpolation=True means use default
3898+ name = DEFAULT_INTERPOLATION
3899+ name = name.lower() # so that "Template", "template", etc. all work
3900+ class_ = interpolation_engines.get(name, None)
3901+ if class_ is None:
3902+ # invalid value for self.main.interpolation
3903+ self.main.interpolation = False
3904+ return value
3905+ else:
3906+ # save reference to engine so we don't have to do this again
3907+ engine = self._interpolation_engine = class_(self)
3908+ # let the engine do the actual work
3909+ return engine.interpolate(key, value)
3910+
3911+
3912+ def __getitem__(self, key):
3913+ """Fetch the item and do string interpolation."""
3914+ val = dict.__getitem__(self, key)
3915+ if self.main.interpolation and isinstance(val, basestring):
3916+ return self._interpolate(key, val)
3917+ return val
3918+
3919+
3920+ def __setitem__(self, key, value, unrepr=False):
3921+ """
3922+ Correctly set a value.
3923+
3924+ Making dictionary values Section instances.
3925+ (We have to special case 'Section' instances - which are also dicts)
3926+
3927+ Keys must be strings.
3928+ Values need only be strings (or lists of strings) if
3929+ ``main.stringify`` is set.
3930+
3931+ ``unrepr`` must be set when setting a value to a dictionary, without
3932+ creating a new sub-section.
3933+ """
3934+ if not isinstance(key, basestring):
3935+ raise ValueError('The key "%s" is not a string.' % key)
3936+
3937+ # add the comment
3938+ if not self.comments.has_key(key):
3939+ self.comments[key] = []
3940+ self.inline_comments[key] = ''
3941+ # remove the entry from defaults
3942+ if key in self.defaults:
3943+ self.defaults.remove(key)
3944+ #
3945+ if isinstance(value, Section):
3946+ if not self.has_key(key):
3947+ self.sections.append(key)
3948+ dict.__setitem__(self, key, value)
3949+ elif isinstance(value, dict) and not unrepr:
3950+ # First create the new depth level,
3951+ # then create the section
3952+ if not self.has_key(key):
3953+ self.sections.append(key)
3954+ new_depth = self.depth + 1
3955+ dict.__setitem__(
3956+ self,
3957+ key,
3958+ Section(
3959+ self,
3960+ new_depth,
3961+ self.main,
3962+ indict=value,
3963+ name=key))
3964+ else:
3965+ if not self.has_key(key):
3966+ self.scalars.append(key)
3967+ if not self.main.stringify:
3968+ if isinstance(value, basestring):
3969+ pass
3970+ elif isinstance(value, (list, tuple)):
3971+ for entry in value:
3972+ if not isinstance(entry, basestring):
3973+ raise TypeError('Value is not a string "%s".' % entry)
3974+ else:
3975+ raise TypeError('Value is not a string "%s".' % value)
3976+ dict.__setitem__(self, key, value)
3977+
3978+
3979+ def __delitem__(self, key):
3980+ """Remove items from the sequence when deleting."""
3981+ dict. __delitem__(self, key)
3982+ if key in self.scalars:
3983+ self.scalars.remove(key)
3984+ else:
3985+ self.sections.remove(key)
3986+ del self.comments[key]
3987+ del self.inline_comments[key]
3988+
3989+
3990+ def get(self, key, default=None):
3991+ """A version of ``get`` that doesn't bypass string interpolation."""
3992+ try:
3993+ return self[key]
3994+ except KeyError:
3995+ return default
3996+
3997+
3998+ def update(self, indict):
3999+ """
4000+ A version of update that uses our ``__setitem__``.
4001+ """
4002+ for entry in indict:
4003+ self[entry] = indict[entry]
4004+
4005+
4006+ def pop(self, key, *args):
4007+ """
4008+ 'D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
4009+ If key is not found, d is returned if given, otherwise KeyError is raised'
4010+ """
4011+ val = dict.pop(self, key, *args)
4012+ if key in self.scalars:
4013+ del self.comments[key]
4014+ del self.inline_comments[key]
4015+ self.scalars.remove(key)
4016+ elif key in self.sections:
4017+ del self.comments[key]
4018+ del self.inline_comments[key]
4019+ self.sections.remove(key)
4020+ if self.main.interpolation and isinstance(val, basestring):
4021+ return self._interpolate(key, val)
4022+ return val
4023+
4024+
4025+ def popitem(self):
4026+ """Pops the first (key,val)"""
4027+ sequence = (self.scalars + self.sections)
4028+ if not sequence:
4029+ raise KeyError(": 'popitem(): dictionary is empty'")
4030+ key = sequence[0]
4031+ val = self[key]
4032+ del self[key]
4033+ return key, val
4034+
4035+
4036+ def clear(self):
4037+ """
4038+ A version of clear that also affects scalars/sections
4039+ Also clears comments and configspec.
4040+
4041+ Leaves other attributes alone :
4042+ depth/main/parent are not affected
4043+ """
4044+ dict.clear(self)
4045+ self.scalars = []
4046+ self.sections = []
4047+ self.comments = {}
4048+ self.inline_comments = {}
4049+ self.configspec = None
4050+
4051+
4052+ def setdefault(self, key, default=None):
4053+ """A version of setdefault that sets sequence if appropriate."""
4054+ try:
4055+ return self[key]
4056+ except KeyError:
4057+ self[key] = default
4058+ return self[key]
4059+
4060+
4061+ def items(self):
4062+ """D.items() -> list of D's (key, value) pairs, as 2-tuples"""
4063+ return zip((self.scalars + self.sections), self.values())
4064+
4065+
4066+ def keys(self):
4067+ """D.keys() -> list of D's keys"""
4068+ return (self.scalars + self.sections)
4069+
4070+
4071+ def values(self):
4072+ """D.values() -> list of D's values"""
4073+ return [self[key] for key in (self.scalars + self.sections)]
4074+
4075+
4076+ def iteritems(self):
4077+ """D.iteritems() -> an iterator over the (key, value) items of D"""
4078+ return iter(self.items())
4079+
4080+
4081+ def iterkeys(self):
4082+ """D.iterkeys() -> an iterator over the keys of D"""
4083+ return iter((self.scalars + self.sections))
4084+
4085+ __iter__ = iterkeys
4086+
4087+
4088+ def itervalues(self):
4089+ """D.itervalues() -> an iterator over the values of D"""
4090+ return iter(self.values())
4091+
4092+
4093+ def __repr__(self):
4094+ """x.__repr__() <==> repr(x)"""
4095+ return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
4096+ for key in (self.scalars + self.sections)])
4097+
4098+ __str__ = __repr__
4099+ __str__.__doc__ = "x.__str__() <==> str(x)"
4100+
4101+
4102+ # Extra methods - not in a normal dictionary
4103+
4104+ def dict(self):
4105+ """
4106+ Return a deepcopy of self as a dictionary.
4107+
4108+ All members that are ``Section`` instances are recursively turned to
4109+ ordinary dictionaries - by calling their ``dict`` method.
4110+
4111+ >>> n = a.dict()
4112+ >>> n == a
4113+ 1
4114+ >>> n is a
4115+ 0
4116+ """
4117+ newdict = {}
4118+ for entry in self:
4119+ this_entry = self[entry]
4120+ if isinstance(this_entry, Section):
4121+ this_entry = this_entry.dict()
4122+ elif isinstance(this_entry, list):
4123+ # create a copy rather than a reference
4124+ this_entry = list(this_entry)
4125+ elif isinstance(this_entry, tuple):
4126+ # create a copy rather than a reference
4127+ this_entry = tuple(this_entry)
4128+ newdict[entry] = this_entry
4129+ return newdict
4130+
4131+
4132+ def merge(self, indict):
4133+ """
4134+ A recursive update - useful for merging config files.
4135+
4136+ >>> a = '''[section1]
4137+ ... option1 = True
4138+ ... [[subsection]]
4139+ ... more_options = False
4140+ ... # end of file'''.splitlines()
4141+ >>> b = '''# File is user.ini
4142+ ... [section1]
4143+ ... option1 = False
4144+ ... # end of file'''.splitlines()
4145+ >>> c1 = ConfigObj(b)
4146+ >>> c2 = ConfigObj(a)
4147+ >>> c2.merge(c1)
4148+ >>> c2
4149+ ConfigObj({'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}})
4150+ """
4151+ for key, val in indict.items():
4152+ if (key in self and isinstance(self[key], dict) and
4153+ isinstance(val, dict)):
4154+ self[key].merge(val)
4155+ else:
4156+ self[key] = val
4157+
4158+
4159+ def rename(self, oldkey, newkey):
4160+ """
4161+ Change a keyname to another, without changing position in sequence.
4162+
4163+ Implemented so that transformations can be made on keys,
4164+ as well as on values. (used by encode and decode)
4165+
4166+ Also renames comments.
4167+ """
4168+ if oldkey in self.scalars:
4169+ the_list = self.scalars
4170+ elif oldkey in self.sections:
4171+ the_list = self.sections
4172+ else:
4173+ raise KeyError('Key "%s" not found.' % oldkey)
4174+ pos = the_list.index(oldkey)
4175+ #
4176+ val = self[oldkey]
4177+ dict.__delitem__(self, oldkey)
4178+ dict.__setitem__(self, newkey, val)
4179+ the_list.remove(oldkey)
4180+ the_list.insert(pos, newkey)
4181+ comm = self.comments[oldkey]
4182+ inline_comment = self.inline_comments[oldkey]
4183+ del self.comments[oldkey]
4184+ del self.inline_comments[oldkey]
4185+ self.comments[newkey] = comm
4186+ self.inline_comments[newkey] = inline_comment
4187+
4188+
4189+ def walk(self, function, raise_errors=True,
4190+ call_on_sections=False, **keywargs):
4191+ """
4192+ Walk every member and call a function on the keyword and value.
4193+
4194+ Return a dictionary of the return values
4195+
4196+ If the function raises an exception, raise the errror
4197+ unless ``raise_errors=False``, in which case set the return value to
4198+ ``False``.
4199+
4200+ Any unrecognised keyword arguments you pass to walk, will be pased on
4201+ to the function you pass in.
4202+
4203+ Note: if ``call_on_sections`` is ``True`` then - on encountering a
4204+ subsection, *first* the function is called for the *whole* subsection,
4205+ and then recurses into it's members. This means your function must be
4206+ able to handle strings, dictionaries and lists. This allows you
4207+ to change the key of subsections as well as for ordinary members. The
4208+ return value when called on the whole subsection has to be discarded.
4209+
4210+ See the encode and decode methods for examples, including functions.
4211+
4212+ .. admonition:: caution
4213+
4214+ You can use ``walk`` to transform the names of members of a section
4215+ but you mustn't add or delete members.
4216+
4217+ >>> config = '''[XXXXsection]
4218+ ... XXXXkey = XXXXvalue'''.splitlines()
4219+ >>> cfg = ConfigObj(config)
4220+ >>> cfg
4221+ ConfigObj({'XXXXsection': {'XXXXkey': 'XXXXvalue'}})
4222+ >>> def transform(section, key):
4223+ ... val = section[key]
4224+ ... newkey = key.replace('XXXX', 'CLIENT1')
4225+ ... section.rename(key, newkey)
4226+ ... if isinstance(val, (tuple, list, dict)):
4227+ ... pass
4228+ ... else:
4229+ ... val = val.replace('XXXX', 'CLIENT1')
4230+ ... section[newkey] = val
4231+ >>> cfg.walk(transform, call_on_sections=True)
4232+ {'CLIENT1section': {'CLIENT1key': None}}
4233+ >>> cfg
4234+ ConfigObj({'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}})
4235+ """
4236+ out = {}
4237+ # scalars first
4238+ for i in range(len(self.scalars)):
4239+ entry = self.scalars[i]
4240+ try:
4241+ val = function(self, entry, **keywargs)
4242+ # bound again in case name has changed
4243+ entry = self.scalars[i]
4244+ out[entry] = val
4245+ except Exception:
4246+ if raise_errors:
4247+ raise
4248+ else:
4249+ entry = self.scalars[i]
4250+ out[entry] = False
4251+ # then sections
4252+ for i in range(len(self.sections)):
4253+ entry = self.sections[i]
4254+ if call_on_sections:
4255+ try:
4256+ function(self, entry, **keywargs)
4257+ except Exception:
4258+ if raise_errors:
4259+ raise
4260+ else:
4261+ entry = self.sections[i]
4262+ out[entry] = False
4263+ # bound again in case name has changed
4264+ entry = self.sections[i]
4265+ # previous result is discarded
4266+ out[entry] = self[entry].walk(
4267+ function,
4268+ raise_errors=raise_errors,
4269+ call_on_sections=call_on_sections,
4270+ **keywargs)
4271+ return out
4272+
4273+
4274+ def as_bool(self, key):
4275+ """
4276+ Accepts a key as input. The corresponding value must be a string or
4277+ the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
4278+ retain compatibility with Python 2.2.
4279+
4280+ If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
4281+ ``True``.
4282+
4283+ If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
4284+ ``False``.
4285+
4286+ ``as_bool`` is not case sensitive.
4287+
4288+ Any other input will raise a ``ValueError``.
4289+
4290+ >>> a = ConfigObj()
4291+ >>> a['a'] = 'fish'
4292+ >>> a.as_bool('a')
4293+ Traceback (most recent call last):
4294+ ValueError: Value "fish" is neither True nor False
4295+ >>> a['b'] = 'True'
4296+ >>> a.as_bool('b')
4297+ 1
4298+ >>> a['b'] = 'off'
4299+ >>> a.as_bool('b')
4300+ 0
4301+ """
4302+ val = self[key]
4303+ if val == True:
4304+ return True
4305+ elif val == False:
4306+ return False
4307+ else:
4308+ try:
4309+ if not isinstance(val, basestring):
4310+ # TODO: Why do we raise a KeyError here?
4311+ raise KeyError()
4312+ else:
4313+ return self.main._bools[val.lower()]
4314+ except KeyError:
4315+ raise ValueError('Value "%s" is neither True nor False' % val)
4316+
4317+
4318+ def as_int(self, key):
4319+ """
4320+ A convenience method which coerces the specified value to an integer.
4321+
4322+ If the value is an invalid literal for ``int``, a ``ValueError`` will
4323+ be raised.
4324+
4325+ >>> a = ConfigObj()
4326+ >>> a['a'] = 'fish'
4327+ >>> a.as_int('a')
4328+ Traceback (most recent call last):
4329+ ValueError: invalid literal for int() with base 10: 'fish'
4330+ >>> a['b'] = '1'
4331+ >>> a.as_int('b')
4332+ 1
4333+ >>> a['b'] = '3.2'
4334+ >>> a.as_int('b')
4335+ Traceback (most recent call last):
4336+ ValueError: invalid literal for int() with base 10: '3.2'
4337+ """
4338+ return int(self[key])
4339+
4340+
4341+ def as_float(self, key):
4342+ """
4343+ A convenience method which coerces the specified value to a float.
4344+
4345+ If the value is an invalid literal for ``float``, a ``ValueError`` will
4346+ be raised.
4347+
4348+ >>> a = ConfigObj()
4349+ >>> a['a'] = 'fish'
4350+ >>> a.as_float('a')
4351+ Traceback (most recent call last):
4352+ ValueError: invalid literal for float(): fish
4353+ >>> a['b'] = '1'
4354+ >>> a.as_float('b')
4355+ 1.0
4356+ >>> a['b'] = '3.2'
4357+ >>> a.as_float('b')
4358+ 3.2000000000000002
4359+ """
4360+ return float(self[key])
4361+
4362+
4363+ def as_list(self, key):
4364+ """
4365+ A convenience method which fetches the specified value, guaranteeing
4366+ that it is a list.
4367+
4368+ >>> a = ConfigObj()
4369+ >>> a['a'] = 1
4370+ >>> a.as_list('a')
4371+ [1]
4372+ >>> a['a'] = (1,)
4373+ >>> a.as_list('a')
4374+ [1]
4375+ >>> a['a'] = [1]
4376+ >>> a.as_list('a')
4377+ [1]
4378+ """
4379+ result = self[key]
4380+ if isinstance(result, (tuple, list)):
4381+ return list(result)
4382+ return [result]
4383+
4384+
4385+ def restore_default(self, key):
4386+ """
4387+ Restore (and return) default value for the specified key.
4388+
4389+ This method will only work for a ConfigObj that was created
4390+ with a configspec and has been validated.
4391+
4392+ If there is no default value for this key, ``KeyError`` is raised.
4393+ """
4394+ default = self.default_values[key]
4395+ dict.__setitem__(self, key, default)
4396+ if key not in self.defaults:
4397+ self.defaults.append(key)
4398+ return default
4399+
4400+
4401+ def restore_defaults(self):
4402+ """
4403+ Recursively restore default values to all members
4404+ that have them.
4405+
4406+ This method will only work for a ConfigObj that was created
4407+ with a configspec and has been validated.
4408+
4409+ It doesn't delete or modify entries without default values.
4410+ """
4411+ for key in self.default_values:
4412+ self.restore_default(key)
4413+
4414+ for section in self.sections:
4415+ self[section].restore_defaults()
4416+
4417+
4418+class ConfigObj(Section):
4419+ """An object to read, create, and write config files."""
4420+
4421+ _keyword = re.compile(r'''^ # line start
4422+ (\s*) # indentation
4423+ ( # keyword
4424+ (?:".*?")| # double quotes
4425+ (?:'.*?')| # single quotes
4426+ (?:[^'"=].*?) # no quotes
4427+ )
4428+ \s*=\s* # divider
4429+ (.*) # value (including list values and comments)
4430+ $ # line end
4431+ ''',
4432+ re.VERBOSE)
4433+
4434+ _sectionmarker = re.compile(r'''^
4435+ (\s*) # 1: indentation
4436+ ((?:\[\s*)+) # 2: section marker open
4437+ ( # 3: section name open
4438+ (?:"\s*\S.*?\s*")| # at least one non-space with double quotes
4439+ (?:'\s*\S.*?\s*')| # at least one non-space with single quotes
4440+ (?:[^'"\s].*?) # at least one non-space unquoted
4441+ ) # section name close
4442+ ((?:\s*\])+) # 4: section marker close
4443+ \s*(\#.*)? # 5: optional comment
4444+ $''',
4445+ re.VERBOSE)
4446+
4447+ # this regexp pulls list values out as a single string
4448+ # or single values and comments
4449+ # FIXME: this regex adds a '' to the end of comma terminated lists
4450+ # workaround in ``_handle_value``
4451+ _valueexp = re.compile(r'''^
4452+ (?:
4453+ (?:
4454+ (
4455+ (?:
4456+ (?:
4457+ (?:".*?")| # double quotes
4458+ (?:'.*?')| # single quotes
4459+ (?:[^'",\#][^,\#]*?) # unquoted
4460+ )
4461+ \s*,\s* # comma
4462+ )* # match all list items ending in a comma (if any)
4463+ )
4464+ (
4465+ (?:".*?")| # double quotes
4466+ (?:'.*?')| # single quotes
4467+ (?:[^'",\#\s][^,]*?)| # unquoted
4468+ (?:(?<!,)) # Empty value
4469+ )? # last item in a list - or string value
4470+ )|
4471+ (,) # alternatively a single comma - empty list
4472+ )
4473+ \s*(\#.*)? # optional comment
4474+ $''',
4475+ re.VERBOSE)
4476+
4477+ # use findall to get the members of a list value
4478+ _listvalueexp = re.compile(r'''
4479+ (
4480+ (?:".*?")| # double quotes
4481+ (?:'.*?')| # single quotes
4482+ (?:[^'",\#].*?) # unquoted
4483+ )
4484+ \s*,\s* # comma
4485+ ''',
4486+ re.VERBOSE)
4487+
4488+ # this regexp is used for the value
4489+ # when lists are switched off
4490+ _nolistvalue = re.compile(r'''^
4491+ (
4492+ (?:".*?")| # double quotes
4493+ (?:'.*?')| # single quotes
4494+ (?:[^'"\#].*?)| # unquoted
4495+ (?:) # Empty value
4496+ )
4497+ \s*(\#.*)? # optional comment
4498+ $''',
4499+ re.VERBOSE)
4500+
4501+ # regexes for finding triple quoted values on one line
4502+ _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
4503+ _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
4504+ _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
4505+ _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
4506+
4507+ _triple_quote = {
4508+ "'''": (_single_line_single, _multi_line_single),
4509+ '"""': (_single_line_double, _multi_line_double),
4510+ }
4511+
4512+ # Used by the ``istrue`` Section method
4513+ _bools = {
4514+ 'yes': True, 'no': False,
4515+ 'on': True, 'off': False,
4516+ '1': True, '0': False,
4517+ 'true': True, 'false': False,
4518+ }
4519+
4520+
4521+ def __init__(self, infile=None, options=None, _inspec=False, **kwargs):
4522+ """
4523+ Parse a config file or create a config file object.
4524+
4525+ ``ConfigObj(infile=None, options=None, **kwargs)``
4526+ """
4527+ self._inspec = _inspec
4528+ # init the superclass
4529+ Section.__init__(self, self, 0, self)
4530+
4531+ infile = infile or []
4532+ options = dict(options or {})
4533+
4534+ # keyword arguments take precedence over an options dictionary
4535+ options.update(kwargs)
4536+ if _inspec:
4537+ options['list_values'] = False
4538+
4539+ defaults = OPTION_DEFAULTS.copy()
4540+ # TODO: check the values too.
4541+ for entry in options:
4542+ if entry not in defaults:
4543+ raise TypeError('Unrecognised option "%s".' % entry)
4544+
4545+ # Add any explicit options to the defaults
4546+ defaults.update(options)
4547+ self._initialise(defaults)
4548+ configspec = defaults['configspec']
4549+ self._original_configspec = configspec
4550+ self._load(infile, configspec)
4551+
4552+
4553+ def _load(self, infile, configspec):
4554+ if isinstance(infile, basestring):
4555+ self.filename = infile
4556+ if os.path.isfile(infile):
4557+ h = open(infile, 'rb')
4558+ infile = h.read() or []
4559+ h.close()
4560+ elif self.file_error:
4561+ # raise an error if the file doesn't exist
4562+ raise IOError('Config file not found: "%s".' % self.filename)
4563+ else:
4564+ # file doesn't already exist
4565+ if self.create_empty:
4566+ # this is a good test that the filename specified
4567+ # isn't impossible - like on a non-existent device
4568+ h = open(infile, 'w')
4569+ h.write('')
4570+ h.close()
4571+ infile = []
4572+
4573+ elif isinstance(infile, (list, tuple)):
4574+ infile = list(infile)
4575+
4576+ elif isinstance(infile, dict):
4577+ # initialise self
4578+ # the Section class handles creating subsections
4579+ if isinstance(infile, ConfigObj):
4580+ # get a copy of our ConfigObj
4581+ infile = infile.dict()
4582+
4583+ for entry in infile:
4584+ self[entry] = infile[entry]
4585+ del self._errors
4586+
4587+ if configspec is not None:
4588+ self._handle_configspec(configspec)
4589+ else:
4590+ self.configspec = None
4591+ return
4592+
4593+ elif getattr(infile, 'read', MISSING) is not MISSING:
4594+ # This supports file like objects
4595+ infile = infile.read() or []
4596+ # needs splitting into lines - but needs doing *after* decoding
4597+ # in case it's not an 8 bit encoding
4598+ else:
4599+ raise TypeError('infile must be a filename, file like object, or list of lines.')
4600+
4601+ if infile:
4602+ # don't do it for the empty ConfigObj
4603+ infile = self._handle_bom(infile)
4604+ # infile is now *always* a list
4605+ #
4606+ # Set the newlines attribute (first line ending it finds)
4607+ # and strip trailing '\n' or '\r' from lines
4608+ for line in infile:
4609+ if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
4610+ continue
4611+ for end in ('\r\n', '\n', '\r'):
4612+ if line.endswith(end):
4613+ self.newlines = end
4614+ break
4615+ break
4616+
4617+ infile = [line.rstrip('\r\n') for line in infile]
4618+
4619+ self._parse(infile)
4620+ # if we had any errors, now is the time to raise them
4621+ if self._errors:
4622+ info = "at line %s." % self._errors[0].line_number
4623+ if len(self._errors) > 1:
4624+ msg = "Parsing failed with several errors.\nFirst error %s" % info
4625+ error = ConfigObjError(msg)
4626+ else:
4627+ error = self._errors[0]
4628+ # set the errors attribute; it's a list of tuples:
4629+ # (error_type, message, line_number)
4630+ error.errors = self._errors
4631+ # set the config attribute
4632+ error.config = self
4633+ raise error
4634+ # delete private attributes
4635+ del self._errors
4636+
4637+ if configspec is None:
4638+ self.configspec = None
4639+ else:
4640+ self._handle_configspec(configspec)
4641+
4642+
4643+ def _initialise(self, options=None):
4644+ if options is None:
4645+ options = OPTION_DEFAULTS
4646+
4647+ # initialise a few variables
4648+ self.filename = None
4649+ self._errors = []
4650+ self.raise_errors = options['raise_errors']
4651+ self.interpolation = options['interpolation']
4652+ self.list_values = options['list_values']
4653+ self.create_empty = options['create_empty']
4654+ self.file_error = options['file_error']
4655+ self.stringify = options['stringify']
4656+ self.indent_type = options['indent_type']
4657+ self.encoding = options['encoding']
4658+ self.default_encoding = options['default_encoding']
4659+ self.BOM = False
4660+ self.newlines = None
4661+ self.write_empty_values = options['write_empty_values']
4662+ self.unrepr = options['unrepr']
4663+
4664+ self.initial_comment = []
4665+ self.final_comment = []
4666+ self.configspec = None
4667+
4668+ if self._inspec:
4669+ self.list_values = False
4670+
4671+ # Clear section attributes as well
4672+ Section._initialise(self)
4673+
4674+
4675+ def __repr__(self):
4676+ return ('ConfigObj({%s})' %
4677+ ', '.join([('%s: %s' % (repr(key), repr(self[key])))
4678+ for key in (self.scalars + self.sections)]))
4679+
4680+
4681+ def _handle_bom(self, infile):
4682+ """
4683+ Handle any BOM, and decode if necessary.
4684+
4685+ If an encoding is specified, that *must* be used - but the BOM should
4686+ still be removed (and the BOM attribute set).
4687+
4688+ (If the encoding is wrongly specified, then a BOM for an alternative
4689+ encoding won't be discovered or removed.)
4690+
4691+ If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
4692+ removed. The BOM attribute will be set. UTF16 will be decoded to
4693+ unicode.
4694+
4695+ NOTE: This method must not be called with an empty ``infile``.
4696+
4697+ Specifying the *wrong* encoding is likely to cause a
4698+ ``UnicodeDecodeError``.
4699+
4700+ ``infile`` must always be returned as a list of lines, but may be
4701+ passed in as a single string.
4702+ """
4703+ if ((self.encoding is not None) and
4704+ (self.encoding.lower() not in BOM_LIST)):
4705+ # No need to check for a BOM
4706+ # the encoding specified doesn't have one
4707+ # just decode
4708+ return self._decode(infile, self.encoding)
4709+
4710+ if isinstance(infile, (list, tuple)):
4711+ line = infile[0]
4712+ else:
4713+ line = infile
4714+ if self.encoding is not None:
4715+ # encoding explicitly supplied
4716+ # And it could have an associated BOM
4717+ # TODO: if encoding is just UTF16 - we ought to check for both
4718+ # TODO: big endian and little endian versions.
4719+ enc = BOM_LIST[self.encoding.lower()]
4720+ if enc == 'utf_16':
4721+ # For UTF16 we try big endian and little endian
4722+ for BOM, (encoding, final_encoding) in BOMS.items():
4723+ if not final_encoding:
4724+ # skip UTF8
4725+ continue
4726+ if infile.startswith(BOM):
4727+ ### BOM discovered
4728+ ##self.BOM = True
4729+ # Don't need to remove BOM
4730+ return self._decode(infile, encoding)
4731+
4732+ # If we get this far, will *probably* raise a DecodeError
4733+ # As it doesn't appear to start with a BOM
4734+ return self._decode(infile, self.encoding)
4735+
4736+ # Must be UTF8
4737+ BOM = BOM_SET[enc]
4738+ if not line.startswith(BOM):
4739+ return self._decode(infile, self.encoding)
4740+
4741+ newline = line[len(BOM):]
4742+
4743+ # BOM removed
4744+ if isinstance(infile, (list, tuple)):
4745+ infile[0] = newline
4746+ else:
4747+ infile = newline
4748+ self.BOM = True
4749+ return self._decode(infile, self.encoding)
4750+
4751+ # No encoding specified - so we need to check for UTF8/UTF16
4752+ for BOM, (encoding, final_encoding) in BOMS.items():
4753+ if not line.startswith(BOM):
4754+ continue
4755+ else:
4756+ # BOM discovered
4757+ self.encoding = final_encoding
4758+ if not final_encoding:
4759+ self.BOM = True
4760+ # UTF8
4761+ # remove BOM
4762+ newline = line[len(BOM):]
4763+ if isinstance(infile, (list, tuple)):
4764+ infile[0] = newline
4765+ else:
4766+ infile = newline
4767+ # UTF8 - don't decode
4768+ if isinstance(infile, basestring):
4769+ return infile.splitlines(True)
4770+ else:
4771+ return infile
4772+ # UTF16 - have to decode
4773+ return self._decode(infile, encoding)
4774+
4775+ # No BOM discovered and no encoding specified, just return
4776+ if isinstance(infile, basestring):
4777+ # infile read from a file will be a single string
4778+ return infile.splitlines(True)
4779+ return infile
4780+
4781+
4782+ def _a_to_u(self, aString):
4783+ """Decode ASCII strings to unicode if a self.encoding is specified."""
4784+ if self.encoding:
4785+ return aString.decode('ascii')
4786+ else:
4787+ return aString
4788+
4789+
4790+ def _decode(self, infile, encoding):
4791+ """
4792+ Decode infile to unicode. Using the specified encoding.
4793+
4794+ if is a string, it also needs converting to a list.
4795+ """
4796+ if isinstance(infile, basestring):
4797+ # can't be unicode
4798+ # NOTE: Could raise a ``UnicodeDecodeError``
4799+ return infile.decode(encoding).splitlines(True)
4800+ for i, line in enumerate(infile):
4801+ if not isinstance(line, unicode):
4802+ # NOTE: The isinstance test here handles mixed lists of unicode/string
4803+ # NOTE: But the decode will break on any non-string values
4804+ # NOTE: Or could raise a ``UnicodeDecodeError``
4805+ infile[i] = line.decode(encoding)
4806+ return infile
4807+
4808+
4809+ def _decode_element(self, line):
4810+ """Decode element to unicode if necessary."""
4811+ if not self.encoding:
4812+ return line
4813+ if isinstance(line, str) and self.default_encoding:
4814+ return line.decode(self.default_encoding)
4815+ return line
4816+
4817+
4818+ def _str(self, value):
4819+ """
4820+ Used by ``stringify`` within validate, to turn non-string values
4821+ into strings.
4822+ """
4823+ if not isinstance(value, basestring):
4824+ return str(value)
4825+ else:
4826+ return value
4827+
4828+
4829+ def _parse(self, infile):
4830+ """Actually parse the config file."""
4831+ temp_list_values = self.list_values
4832+ if self.unrepr:
4833+ self.list_values = False
4834+
4835+ comment_list = []
4836+ done_start = False
4837+ this_section = self
4838+ maxline = len(infile) - 1
4839+ cur_index = -1
4840+ reset_comment = False
4841+
4842+ while cur_index < maxline:
4843+ if reset_comment:
4844+ comment_list = []
4845+ cur_index += 1
4846+ line = infile[cur_index]
4847+ sline = line.strip()
4848+ # do we have anything on the line ?
4849+ if not sline or sline.startswith('#'):
4850+ reset_comment = False
4851+ comment_list.append(line)
4852+ continue
4853+
4854+ if not done_start:
4855+ # preserve initial comment
4856+ self.initial_comment = comment_list
4857+ comment_list = []
4858+ done_start = True
4859+
4860+ reset_comment = True
4861+ # first we check if it's a section marker
4862+ mat = self._sectionmarker.match(line)
4863+ if mat is not None:
4864+ # is a section line
4865+ (indent, sect_open, sect_name, sect_close, comment) = mat.groups()
4866+ if indent and (self.indent_type is None):
4867+ self.indent_type = indent
4868+ cur_depth = sect_open.count('[')
4869+ if cur_depth != sect_close.count(']'):
4870+ self._handle_error("Cannot compute the section depth at line %s.",
4871+ NestingError, infile, cur_index)
4872+ continue
4873+
4874+ if cur_depth < this_section.depth:
4875+ # the new section is dropping back to a previous level
4876+ try:
4877+ parent = self._match_depth(this_section,
4878+ cur_depth).parent
4879+ except SyntaxError:
4880+ self._handle_error("Cannot compute nesting level at line %s.",
4881+ NestingError, infile, cur_index)
4882+ continue
4883+ elif cur_depth == this_section.depth:
4884+ # the new section is a sibling of the current section
4885+ parent = this_section.parent
4886+ elif cur_depth == this_section.depth + 1:
4887+ # the new section is a child the current section
4888+ parent = this_section
4889+ else:
4890+ self._handle_error("Section too nested at line %s.",
4891+ NestingError, infile, cur_index)
4892+
4893+ sect_name = self._unquote(sect_name)
4894+ if parent.has_key(sect_name):
4895+ self._handle_error('Duplicate section name at line %s.',
4896+ DuplicateError, infile, cur_index)
4897+ continue
4898+
4899+ # create the new section
4900+ this_section = Section(
4901+ parent,
4902+ cur_depth,
4903+ self,
4904+ name=sect_name)
4905+ parent[sect_name] = this_section
4906+ parent.inline_comments[sect_name] = comment
4907+ parent.comments[sect_name] = comment_list
4908+ continue
4909+ #
4910+ # it's not a section marker,
4911+ # so it should be a valid ``key = value`` line
4912+ mat = self._keyword.match(line)
4913+ if mat is None:
4914+ # it neither matched as a keyword
4915+ # or a section marker
4916+ self._handle_error(
4917+ 'Invalid line at line "%s".',
4918+ ParseError, infile, cur_index)
4919+ else:
4920+ # is a keyword value
4921+ # value will include any inline comment
4922+ (indent, key, value) = mat.groups()
4923+ if indent and (self.indent_type is None):
4924+ self.indent_type = indent
4925+ # check for a multiline value
4926+ if value[:3] in ['"""', "'''"]:
4927+ try:
4928+ (value, comment, cur_index) = self._multiline(
4929+ value, infile, cur_index, maxline)
4930+ except SyntaxError:
4931+ self._handle_error(
4932+ 'Parse error in value at line %s.',
4933+ ParseError, infile, cur_index)
4934+ continue
4935+ else:
4936+ if self.unrepr:
4937+ comment = ''
4938+ try:
4939+ value = unrepr(value)
4940+ except Exception, e:
4941+ if type(e) == UnknownType:
4942+ msg = 'Unknown name or type in value at line %s.'
4943+ else:
4944+ msg = 'Parse error in value at line %s.'
4945+ self._handle_error(msg, UnreprError, infile,
4946+ cur_index)
4947+ continue
4948+ else:
4949+ if self.unrepr:
4950+ comment = ''
4951+ try:
4952+ value = unrepr(value)
4953+ except Exception, e:
4954+ if isinstance(e, UnknownType):
4955+ msg = 'Unknown name or type in value at line %s.'
4956+ else:
4957+ msg = 'Parse error in value at line %s.'
4958+ self._handle_error(msg, UnreprError, infile,
4959+ cur_index)
4960+ continue
4961+ else:
4962+ # extract comment and lists
4963+ try:
4964+ (value, comment) = self._handle_value(value)
4965+ except SyntaxError:
4966+ self._handle_error(
4967+ 'Parse error in value at line %s.',
4968+ ParseError, infile, cur_index)
4969+ continue
4970+ #
4971+ key = self._unquote(key)
4972+ if this_section.has_key(key):
4973+ self._handle_error(
4974+ 'Duplicate keyword name at line %s.',
4975+ DuplicateError, infile, cur_index)
4976+ continue
4977+ # add the key.
4978+ # we set unrepr because if we have got this far we will never
4979+ # be creating a new section
4980+ this_section.__setitem__(key, value, unrepr=True)
4981+ this_section.inline_comments[key] = comment
4982+ this_section.comments[key] = comment_list
4983+ continue
4984+ #
4985+ if self.indent_type is None:
4986+ # no indentation used, set the type accordingly
4987+ self.indent_type = ''
4988+
4989+ # preserve the final comment
4990+ if not self and not self.initial_comment:
4991+ self.initial_comment = comment_list
4992+ elif not reset_comment:
4993+ self.final_comment = comment_list
4994+ self.list_values = temp_list_values
4995+
4996+
4997+ def _match_depth(self, sect, depth):
4998+ """
4999+ Given a section and a depth level, walk back through the sections
5000+ parents to see if the depth level matches a previous section.
The diff has been truncated for viewing.