1
# -*- coding: utf-8 -*-
2
# Copyright Fernando San Martín Woerner <fsmw@gnome.org>
3
# $Id: edit.py 475 2005-07-29 17:29:32Z snmartin $
4
#Permission is hereby granted, free of charge, to any person obtaining a copy
5
#of this software and associated documentation files (the "Software"), to deal
6
#in the Software without restriction, including without limitation the rights
7
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
#copies of the Software, and to permit persons to whom the Software is
9
#furnished to do so, subject to the following conditions:
11
#The above copyright notice and this permission notice shall be included in
12
#all copies or substantial portions of the Software.
14
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
# This file is part of Culebra project.
35
special_chars = (".",)
39
RESPONSE_REPLACE_ALL = 3
44
class CulebraBuffer(gtksourceview.SourceBuffer):
46
def __init__(self, filename=None):
47
gtksourceview.SourceBuffer.__init__(self)
48
self.filename=filename
51
class CulebraView(gtksourceview.SourceView):
53
def __init__(self, buff=CulebraBuffer()):
55
gtksourceview.SourceView.__init__(self)
57
gtksourceview.SourceView.__init__(self, buff)
59
class EditWindow(gtk.EventBox):
61
def __init__(self, plugin=None, quit_cb=None):
62
gtk.EventBox.__init__(self)
63
self.search_string = None
64
self.last_search_iter = None
65
self.completion_win = None
66
self.insert_string = None
67
self.cursor_iter = None
70
self.current_word = ""
73
self.set_size_request(470, 300)
74
self.connect("delete_event", self.file_exit)
75
self.quit_cb = quit_cb
76
self.vbox = gtk.VBox()
79
self.menubar, self.toolbar = self.create_menu()
80
hdlbox = gtk.HandleBox()
81
self.vbox.pack_start(hdlbox, expand=False)
83
hdlbox.add(self.menubar)
85
hdlbox = gtk.HandleBox()
86
self.vbox.pack_start(hdlbox, expand=False)
88
hdlbox.add(self.toolbar)
90
self.vpaned = gtk.VPaned()
91
self.vbox.pack_start(self.vpaned, expand=True, fill = True)
93
self.vbox1 = gtk.VBox()
94
self.vpaned.add1(self.vbox1)
97
self.hpaned = gtk.HPaned()
98
self.vbox1.pack_start(self.hpaned, True, True)
99
self.hpaned.set_border_width(5)
102
lm = gtksourceview.SourceLanguagesManager()
103
buff = CulebraBuffer()
105
buff.set_data('languages-manager', lm)
106
# self.editor = gtksourceview.SourceView(buff)
107
self.editor = CulebraView(buff)
108
self.plugin.pida.mainwindow.connect('delete-event', self.file_exit)
109
font_desc = pango.FontDescription('monospace 10')
111
self.editor.modify_font(font_desc)
113
buff.connect('insert-text', self.insert_at_cursor_cb)
114
buff.set_data("save", False)
115
manager = buff.get_data('languages-manager')
116
language = manager.get_language_from_mime_type("text/x-python")
117
buff.set_highlight(True)
118
buff.set_language(language)
119
scrolledwin2 = gtk.ScrolledWindow()
120
scrolledwin2.add(self.editor)
121
self.editor.set_auto_indent(True)
122
self.editor.set_show_line_numbers(True)
123
self.editor.set_show_line_markers(True)
124
self.editor.set_tabs_width(4)
125
self.editor.connect('key-press-event', self.text_key_press_event_cb)
126
self.editor.connect('move-cursor', self.move_cursor)
127
self.editor.set_margin(80)
128
self.editor.set_show_margin(True)
129
self.editor.set_smart_home_end(True)
130
self.editor.set_highlight_current_line(True)
133
self.editor.grab_focus()
134
buff.set_data('filename', "untitled.py")
135
self.wins.append([buff, "untitled.py"])
136
self.current_buffer = 0
137
self.hpaned.add2(scrolledwin2)
138
self.hpaned.set_position(200)
140
self.clipboard = gtk.Clipboard(selection='CLIPBOARD')
146
def create_menu(self):
149
<menu name='FileMenu' action='FileMenu'>
150
<menuitem action='FileNew'/>
151
<menuitem action='FileOpen'/>
152
<menuitem action='FileSave'/>
153
<menuitem action='FileSaveAs'/>
154
<menuitem action='Close'/>
156
<menuitem action='FileExit'/>
158
<menu name='EditMenu' action='EditMenu'>
159
<menuitem action='EditUndo'/>
160
<menuitem action='EditRedo'/>
162
<menuitem action='EditCut'/>
163
<menuitem action='EditCopy'/>
164
<menuitem action='EditPaste'/>
165
<menuitem action='EditClear'/>
167
<menuitem action='DuplicateLine'/>
168
<menuitem action='DeleteLine'/>
169
<menuitem action='CommentBlock'/>
170
<menuitem action='UncommentBlock'/>
171
<menuitem action='UpperSelection'/>
172
<menuitem action='LowerSelection'/>
174
<menuitem action='Configuration' />
176
<menu name='FindMenu' action='FindMenu'>
177
<menuitem action='EditFind'/>
178
<menuitem action='EditFindNext'/>
179
<menuitem action='EditReplace'/>
181
<menuitem action='GotoLine'/>
183
<menu name='RunMenu' action='RunMenu'>
184
<menuitem action='RunScript'/>
185
<menuitem action='StopScript'/>
186
<menuitem action='DebugScript'/>
187
<menuitem action='DebugStep'/>
188
<menuitem action='DebugNext'/>
189
<menuitem action='DebugContinue'/>
191
<menu name='BufferMenu' action='BufferMenu'>
192
<menuitem action='PrevBuffer'/>
193
<menuitem action='NextBuffer'/>
197
<toolitem action='FileNew'/>
198
<toolitem action='FileOpen'/>
199
<toolitem action='FileSave'/>
200
<toolitem action='FileSaveAs'/>
201
<toolitem action='Close'/>
203
<toolitem action='EditUndo'/>
204
<toolitem action='EditRedo'/>
206
<toolitem action='EditCut'/>
207
<toolitem action='EditCopy'/>
208
<toolitem action='EditPaste'/>
210
<toolitem action='EditFind'/>
211
<toolitem action='EditReplace'/>
213
<toolitem action='RunScript'/>
214
<toolitem action='StopScript'/>
216
<toolitem action='PrevBuffer'/>
217
<toolitem action='NextBuffer'/>
222
('FileMenu', None, '_File'),
223
('FileNew', gtk.STOCK_NEW, None, None, None, self.file_new),
224
('FileOpen', gtk.STOCK_OPEN, None, None, None, self.file_open),
225
('FileSave', gtk.STOCK_SAVE, None, None, None, self.file_save),
226
('FileSaveAs', gtk.STOCK_SAVE_AS, None, None, None,
228
('Close', gtk.STOCK_CLOSE, None, None, None, self.file_close),
229
('FileExit', gtk.STOCK_QUIT, None, None, None, self.file_exit),
230
('EditMenu', None, '_Edit'),
231
('EditUndo', gtk.STOCK_UNDO, None, "<control>z", None, self.edit_undo),
232
('EditRedo', gtk.STOCK_REDO, None, "<control><shift>z", None, self.edit_redo),
233
('EditCut', gtk.STOCK_CUT, None, None, None, self.edit_cut),
234
('EditCopy', gtk.STOCK_COPY, None, None, None, self.edit_copy),
235
('EditPaste', gtk.STOCK_PASTE, None, None, None, self.edit_paste),
236
('EditClear', gtk.STOCK_REMOVE, 'C_lear', None, None,
238
('Configuration', None, 'Configur_e', None, None,
239
lambda action: self.plugin.do_action('showconfig', 'culebra')),
241
('DuplicateLine', None, 'Duplicate Line', '<control>d',
242
None, self.duplicate_line),
243
('DeleteLine', None, 'Delete Line', '<control>y',
244
None, self.delete_line),
245
('CommentBlock', None, 'Comment Selection', '<control>k',
246
None, self.comment_block),
247
('UncommentBlock', None, 'Uncomment Selection', '<control><shift>k',
248
None, self.uncomment_block),
249
('UpperSelection', None, 'Upper Selection', '<control>u',
250
None, self.upper_selection),
251
('LowerSelection', None, 'Lower Selection', '<control><shift>u',
252
None, self.lower_selection),
253
('FindMenu', None, '_Find'),
254
('EditFind', gtk.STOCK_FIND, None, None, None, self.edit_find),
255
('EditFindNext', None, 'Find _Next', None, None, self.edit_find_next),
256
('EditReplace', gtk.STOCK_FIND_AND_REPLACE, None, '<control>h',
257
None, self.edit_replace),
258
('GotoLine', None, 'Goto Line', '<control>g',
259
None, self.goto_line),
260
('RunMenu', None, '_Run'),
261
('RunScript', gtk.STOCK_EXECUTE, None, "F5",None, self.run_script),
262
('StopScript', gtk.STOCK_STOP, None, "<ctrl>F5",None, self.stop_script),
263
('DebugScript', None, "Debug Script", "F7",None, self.debug_script),
264
('DebugStep', None, "Step", "F8",None, self.step_script),
265
('DebugNext', None, "Next", "<shift>F7",None, self.next_script),
266
('DebugContinue', None, "Continue", "<control>F7", None, self.continue_script),
267
('BufferMenu', None, '_Buffers'),
268
('PrevBuffer', gtk.STOCK_GO_UP, None, "<shift>F6",None, self.prev_buffer),
269
('NextBuffer', gtk.STOCK_GO_DOWN, None, "F6",None, self.next_buffer),
271
self.ag = gtk.ActionGroup('edit')
272
self.ag.add_actions(actions)
273
self.ui = gtk.UIManager()
274
self.ui.insert_action_group(self.ag, 0)
275
self.ui.add_ui_from_string(ui_string)
276
self.get_parent_window().add_accel_group(self.ui.get_accel_group())
277
return (self.ui.get_widget('/menubar'), self.ui.get_widget('/toolbar'))
279
def set_title(self, title):
280
self.plugin.pida.mainwindow.set_title(title)
282
def move_cursor(self, tv, step, count, extend_selection):
285
def get_parent_window(self):
286
return self.plugin.pida.mainwindow
288
def get_current(self, page = None):
289
if len(self.wins) > 0:
291
return self.wins[self.current_buffer]
294
def _new_tab(self, f, buff = None):
295
l = [n for n in self.wins if n[1]==f]
297
lm = gtksourceview.SourceLanguagesManager()
299
buff = CulebraBuffer()
301
buff.set_data('languages-manager', lm)
302
font_desc = pango.FontDescription('monospace 10')
304
self.editor.modify_font(font_desc)
305
buff.connect('insert-text', self.insert_at_cursor_cb)
306
buff.set_data("save", False)
307
self.editor.set_buffer(buff)
308
self.editor.grab_focus()
309
buff.set_data('filename', f)
310
self.wins.append([buff, f])
311
self.current_buffer = len(self.wins) - 1
313
def insert_at_cursor_cb(self, buff, iter, text, length):
315
buff, fn = self.get_current()
316
iter2 = buff.get_iter_at_mark(buff.get_insert())
317
s, e = buff.get_bounds()
318
text_code = buff.get_text(s, e)
320
if self.ac_w is not None:
324
complete = self.get_context(buff, iter2, True)
325
if "\n" in complete or complete.isdigit():
328
complete = complete + text
330
c = compile(text_code, '<string>', 'exec')
331
lst_ = [a for a in c.co_names if a.startswith(complete)]
332
con = map(str, c.co_consts)
333
con = [a for a in con if a.startswith(complete) and a not in lst_]
335
lst_ += keyword.kwlist
336
lst_ = [a for a in lst_ if a.startswith(complete)]
339
lst_ += keyword.kwlist
340
lst_ = [a for a in lst_ if a.startswith(complete)]
344
complete = self.get_context(buff, iter2)
345
if complete.isdigit():
347
if len(complete.strip()) > 0:
349
lst_ = [str(a[0]) for a in importsTipper.GenerateTip(complete, os.path.dirname(fn)) if a is not None]
352
c = compile(text_code, '<string>', 'exec')
353
lst_ = [a for a in c.co_names if a.startswith(complete)]
354
con = map(str, c.co_consts)
355
con = [a for a in con if a.startswith(complete) and a not in lst_]
357
lst_ += keyword.kwlist
358
lst_ = [a for a in lst_ if a.startswith(complete)]
362
lst_ += keyword.kwlist
363
lst_ = [a for a in lst_ if a.startswith(complete)]
369
if self.ac_w is None:
370
self.ac_w = AutoCompletionWindow(self.editor, iter2, complete,
372
self.plugin.pida.mainwindow,
376
self.ac_w.set_list(self.editor, iter2, complete,
378
self.plugin.pida.mainwindow,
383
def get_context(self, buff, it, sp=False):
386
it.backward_word_start()
388
it.backward_word_starts(1)
390
iter3.backward_chars(1)
391
prev = iter3.get_text(it)
392
complete = it.get_text(iter2)
393
self.context_bounds = (buff.create_mark('cstart',it), buff.create_mark('cend',iter2))
394
if prev in (".", "_"):
395
t = self.get_context(buff, it)
401
def text_key_press_event_cb(self, widget, event):
402
#print event.state, event.keyval
403
keyname = gtk.gdk.keyval_name(event.keyval)
404
buf = widget.get_buffer()
405
bound = buf.get_selection_bounds()
406
tabs = widget.get_tabs_width()
407
space = " ".center(tabs)
409
if event.state & gtk.gdk.SHIFT_MASK and keyname == "ISO_Left_Tab":
411
it = buf.get_iter_at_mark(buf.get_insert())
412
start = buf.get_iter_at_line(it.get_line())
413
end = buf.get_iter_at_line(it.get_line())
415
while end.get_char() == " " and count < tabs:
418
buf.delete(start, end)
421
start_line = start.get_line()
422
end_line = end.get_line()
423
while start_line <= end_line:
424
insert_iter = buf.get_iter_at_line(start_line)
425
if not insert_iter.ends_line():
426
s_it = buf.get_iter_at_line(start_line)
427
e_it = buf.get_iter_at_line(start_line)
429
while e_it.get_char() == " " and count < tabs:
432
buf.delete(s_it, e_it)
436
elif event.keyval == gtk.keysyms.Tab:
438
buf.insert_at_cursor(space)
441
start_line = start.get_line()
442
end_line = end.get_line()
443
while start_line <= end_line:
444
insert_iter = buf.get_iter_at_line(start_line)
445
if not insert_iter.ends_line():
446
buf.insert(insert_iter, space)
450
def load_file(self, fname):
454
buff, fn = self.wins[self.current_buffer]
456
buff.set_data('filename', fname)
457
buff.set_text(fd.read())
459
self.editor.set_buffer(buff)
460
self.editor.queue_draw()
461
self.set_title(os.path.basename(fname))
462
self.dirname = os.path.dirname(fname)
463
buff.set_modified(False)
465
self.check_mime(self.current_buffer)
466
buff.place_cursor(buff.get_start_iter())
468
dlg = gtk.MessageDialog(self.get_parent_window(),
469
gtk.DIALOG_DESTROY_WITH_PARENT,
470
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
471
"Can't open " + fname)
472
print sys.exc_info()[1]
476
self.check_mime(self.current_buffer)
477
self.plugin.do_edit('getbufferlist')
478
self.plugin.do_edit('getcurrentbuffer')
479
for i, (buff, fn) in enumerate(self.wins):
481
self.plugin.do_edit('changebuffer', i)
483
self.editor.grab_focus()
485
def check_mime(self, buffer_number):
486
buff, fname = self.wins[buffer_number]
487
manager = buff.get_data('languages-manager')
488
if os.path.isabs(fname):
491
path = os.path.abspath(fname)
492
uri = gnomevfs.URI(path)
493
mime_type = gnomevfs.get_mime_type(path) # needs ASCII filename, not URI
495
language = manager.get_language_from_mime_type(mime_type)
497
buff.set_highlight(True)
498
buff.set_language(language)
500
dlg = gtk.MessageDialog(self.get_parent_window(),
501
gtk.DIALOG_DESTROY_WITH_PARENT,
502
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
503
'No language found for mime type "%s"' % mime_type)
504
buff.set_highlight(False)
506
dlg = gtk.MessageDialog(self.get_parent_window(),
507
gtk.DIALOG_DESTROY_WITH_PARENT,
508
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
509
'Couldn\'t get mime type for file "%s"' % fname)
510
buff.set_highlight(False)
511
buff.set_data("save", False)
514
buff, fname = self.get_current()
517
if buff.get_modified():
518
dlg = gtk.Dialog('Unsaved File', self.get_parent_window(),
519
gtk.DIALOG_DESTROY_WITH_PARENT,
520
(gtk.STOCK_YES, gtk.RESPONSE_YES,
521
gtk.STOCK_NO, gtk.RESPONSE_NO,
522
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
523
lbl = gtk.Label((fname or "Untitled")+
524
" has not been saved\n" +
525
"Do you want to save it?")
527
dlg.vbox.pack_start(lbl)
530
if ret == gtk.RESPONSE_NO:
532
if ret == gtk.RESPONSE_YES:
538
def file_new(self, mi=None):
539
if self.chk_save(): return
540
self._new_tab("untitled%s.py" % len(self.wins))
541
buff, fname = self.get_current()
543
buff.set_data('filename', fname)
544
buff.set_modified(False)
546
manager = buff.get_data('languages-manager')
547
language = manager.get_language_from_mime_type("text/x-python")
548
buff.set_highlight(True)
549
buff.set_language(language)
550
self.plugin.do_edit('getbufferlist')
551
self.plugin.do_edit('getcurrentbuffer')
552
self.plugin.do_edit('changebuffer', len(self.wins) - 1)
556
def file_open(self, mi=None):
557
fn = self.get_current()[1]
558
dirn =os.path.dirname(fn)
559
fname = dialogs.OpenFile('Open File', self.get_parent_window(),
564
buff = self.get_current()[0]
565
if not buff.get_modified():
566
del self.wins[self.current_buffer]
567
self.load_file(fname)
568
self.plugin.pida.mainwindow.set_title(os.path.split(fname)[1])
571
def file_save(self, mi=None, fname=None):
573
return self.file_saveas()
574
buff = self.editor.get_buffer()
575
curr_mark = buff.get_iter_at_mark(buff.get_insert())
576
f = buff.get_data('filename')
581
start, end = buff.get_bounds()
582
blockend = start.copy()
583
fd = open(fname, "w")
584
while blockend.forward_chars(BLOCK_SIZE):
585
buf = buff.get_text(start, blockend)
587
start = blockend.copy()
588
buf = buff.get_text(start, blockend)
591
buff.set_modified(False)
592
buff.set_data("save", True)
593
buff.set_data('filename', fname)
594
self.plugin.pida.mainwindow.set_title(os.path.split(fname)[1])
596
self.wins[self.current_buffer] = [buff, fname]
598
dlg = gtk.MessageDialog(self.get_parent_window(),
599
gtk.DIALOG_DESTROY_WITH_PARENT,
600
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
601
"Error saving file " + fname)
602
print sys.exc_info()[1]
606
self.check_mime(self.current_buffer)
607
self.plugin.do_edit('getbufferlist')
608
self.plugin.do_edit('getcurrentbuffer')
609
# self.plugin.do_edit('changebuffer', len(self.wins) - 1)
610
buff.place_cursor(curr_mark)
611
self.editor.grab_focus()
614
def file_saveas(self, mi=None):
615
buff, f = self.get_current()
616
f = dialogs.SaveFile('Save File As',
617
self.get_parent_window(),
620
if not f: return False
622
self.dirname = os.path.dirname(f)
623
self.plugin.pida.mainwindow.set_title(os.path.basename(f))
625
return self.file_save(fname=f)
627
def file_close(self, mi=None, event=None):
628
del self.wins[self.current_buffer]
629
if len(self.wins) == 0:
630
self._new_tab('untitled.py')
632
self.current_buffer = len(self.wins) - 1
633
self.editor.set_buffer(self.wins[self.current_buffer][0])
634
self.plugin.do_edit('getbufferlist')
635
self.plugin.do_edit('getcurrentbuffer')
638
def file_exit(self, mi=None, event=None):
639
if self.chk_save(): return True
642
if self.quit_cb: self.quit_cb(self)
643
self.plugin.do_action('quit')
646
def edit_cut(self, mi):
647
buff = self.get_current()[0]
648
buff.cut_clipboard(self.clipboard, True)
651
def edit_copy(self, mi):
652
buff = self.get_current()[0]
653
buff.copy_clipboard(self.clipboard)
656
def edit_paste(self, mi):
657
buff = self.get_current()[0]
658
buff.paste_clipboard(self.clipboard, None, True)
661
def edit_clear(self, mi):
662
buff = self.get_current()[0]
663
buff.delete_selection(True, True)
666
def edit_undo(self, mi):
667
buff = self.get_current()[0]
670
def edit_redo(self, mi):
671
buff = self.get_current()[0]
674
def edit_find(self, mi):
675
def dialog_response_callback(dialog, response_id):
676
if response_id == gtk.RESPONSE_CLOSE:
679
self._search(search_text.get_text(), self.last_search_iter)
680
buff = self.get_current()[0]
681
search_text = gtk.Entry()
682
s = buff.get_selection_bounds()
684
search_text.set_text(buff.get_slice(s[0], s[1]))
685
dialog = gtk.Dialog("Search", self.get_parent_window(),
686
gtk.DIALOG_DESTROY_WITH_PARENT,
687
(gtk.STOCK_FIND, RESPONSE_FORWARD,
688
gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
689
dialog.vbox.pack_end(search_text, True, True, 0)
690
dialog.connect("response", dialog_response_callback)
691
dialog.set_default_response(RESPONSE_FORWARD)
692
search_text.set_activates_default(True)
694
search_text.grab_focus()
696
response_id = dialog.run()
698
def edit_replace(self, mi):
699
def dialog_response_callback(dialog, response_id):
700
if response_id == gtk.RESPONSE_CLOSE:
703
if response_id == RESPONSE_FORWARD:
704
self._search(search_text.get_text(), self.last_search_iter)
706
if response_id == RESPONSE_REPLACE:
707
if not self._search(search_text.get_text(), self.last_search_iter):
709
start, end = buff.get_selection_bounds()
710
buff.delete(start, end)
711
buff.insert(start, replace_text.get_text())
712
self.last_search_iter = buff.get_iter_at_mark(buff.get_insert())
713
start = buff.get_iter_at_mark(buff.get_insert())
714
start.backward_chars(len(replace_text.get_text()))
715
buff.select_range(start, self.last_search_iter)
716
if response_id == RESPONSE_REPLACE_ALL:
717
current_iter = buff.get_iter_at_mark(buff.get_insert())
718
while self._search(search_text.get_text(), self.last_search_iter, False):
719
start, end = buff.get_selection_bounds()
720
buff.delete(start, end)
721
buff.insert(start, replace_text.get_text())
722
self.last_search_iter = buff.get_iter_at_mark(buff.get_insert())
723
start = buff.get_iter_at_mark(buff.get_insert())
724
start.backward_chars(len(replace_text.get_text()))
725
buff.select_range(start, self.last_search_iter)
726
buff.place_cursor(current_iter)
727
buff = self.get_current()[0]
728
search_text = gtk.Entry()
729
replace_text = gtk.Entry()
730
s = buff.get_selection_bounds()
732
search_text.set_text(buff.get_slice(s[0], s[1]))
733
dialog = gtk.Dialog("Search", self.get_parent_window(),
734
gtk.DIALOG_DESTROY_WITH_PARENT,
735
(gtk.STOCK_FIND, RESPONSE_FORWARD,
736
"Replace", RESPONSE_REPLACE,
737
"Replace All", RESPONSE_REPLACE_ALL,
738
gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
739
lbl = gtk.Label("Find what:")
740
dialog.vbox.pack_start(lbl, True, True, 0)
741
dialog.vbox.pack_start(search_text, True, True, 0)
742
lbl = gtk.Label("Replace with:")
743
dialog.vbox.pack_start(lbl, True, True, 0)
744
dialog.vbox.pack_start(replace_text, True, True, 0)
745
dialog.connect("response", dialog_response_callback)
746
dialog.set_default_response(RESPONSE_FORWARD)
747
search_text.set_activates_default(True)
748
replace_text.set_activates_default(True)
751
search_text.grab_focus()
753
response_id = dialog.run()
755
def _search(self, search_string, iter = None, scroll=True):
756
buff, fname = self.get_current()
758
start = buff.get_start_iter()
763
self.search_string = search_string
764
res = start.forward_search(search_string, gtk.TEXT_SEARCH_TEXT_ONLY)
766
match_start, match_end = res
767
buff.place_cursor(match_start)
768
buff.select_range(match_start, match_end)
770
self.editor.scroll_to_iter(match_start, 0.25)
771
self.last_search_iter = match_end
774
self.search_string = None
775
self.last_search_iter = buff.get_iter_at_mark(buff.get_insert())
778
def edit_find_next(self, mi):
779
self._search(self.search_string, self.last_search_iter)
781
def goto_line(self, mi=None):
782
def dialog_response_callback(dialog, response_id):
783
if response_id == gtk.RESPONSE_CLOSE:
786
line = line_text.get_text()
788
buff, f = self.get_current()
789
titer = buff.get_iter_at_line(int(line)-1)
790
self.editor.scroll_to_iter(titer, 0.25)
791
buff.place_cursor(titer)
792
self.editor.grab_focus()
795
line_text = gtk.Entry()
796
dialog = gtk.Dialog("Goto Line", self.get_parent_window(),
797
gtk.DIALOG_DESTROY_WITH_PARENT,
798
(gtk.STOCK_GO_FORWARD, RESPONSE_FORWARD,
799
gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
800
dialog.vbox.pack_end(line_text, True, True, 0)
801
dialog.connect("response", dialog_response_callback)
802
dialog.set_default_response(RESPONSE_FORWARD)
803
line_text.set_activates_default(True)
805
line_text.grab_focus()
807
response_id = dialog.run()
809
def comment_block(self, mi=None):
811
buf = self.get_current()[0]
812
bound = buf.get_selection_bounds()
814
it = buf.get_iter_at_mark(buf.get_insert())
816
insert_iter = buf.get_iter_at_line(line)
817
buf.insert(insert_iter, comment)
820
start_line = start.get_line()
821
end_line = end.get_line()
822
while start_line <= end_line:
823
insert_iter = buf.get_iter_at_line(start_line)
824
if not insert_iter.ends_line():
825
buf.insert(insert_iter, comment)
828
def uncomment_block(self, mi=None):
829
buf = self.get_current()[0]
830
bound = buf.get_selection_bounds()
832
it = buf.get_iter_at_mark(buf.get_insert())
833
start = buf.get_iter_at_line(it.get_line())
834
end = buf.get_iter_at_line(it.get_line())
836
while end.get_char() == "#":
839
buf.delete(start, end)
842
start_line = start.get_line()
843
end_line = end.get_line()
844
while start_line <= end_line:
845
insert_iter = buf.get_iter_at_line(start_line)
846
if not insert_iter.ends_line():
847
s_it = buf.get_iter_at_line(start_line)
848
e_it = buf.get_iter_at_line(start_line)
850
while e_it.get_char() == "#":
853
buf.delete(s_it, e_it)
856
def delete_line(self, mi):
857
buf = self.get_current()[0]
858
it = buf.get_iter_at_mark(buf.get_insert())
860
start = buf.get_iter_at_line(line)
861
end = buf.get_iter_at_line(line+1)
862
if start.get_line() == end.get_line():
864
buf.delete(start, end)
866
def duplicate_line(self, mi):
867
buf = self.get_current()[0]
868
it = buf.get_iter_at_mark(buf.get_insert())
870
start = buf.get_iter_at_line(line)
871
end = buf.get_iter_at_line(line+1)
873
if start.get_line() == end.get_line():
876
text = buf.get_text(start, end)
877
buf.insert(end, ret+text)
879
def upper_selection(self, mi):
880
buf = self.get_current()[0]
881
bound = buf.get_selection_bounds()
882
if not len(bound) == 0:
884
text = buf.get_text(start, end)
885
buf.delete(start, end)
886
buf.insert(start, text.upper())
888
def lower_selection(self, mi):
889
buf = self.get_current()[0]
890
bound = buf.get_selection_bounds()
891
if not len(bound) == 0:
893
text = buf.get_text(start, end)
894
buf.delete(start, end)
895
buf.insert(start, text.lower())
897
def run_script(self, mi):
899
self.plugin.do_evt("bufferexecute")
901
def stop_script(self, mi):
902
self.plugin.do_evt('killterminal')
904
def debug_script(self, mi):
905
self.plugin.do_evt('debuggerload')
906
buff = self.get_current()[0]
907
titer = buff.get_iter_at_line(0)
908
self.editor.scroll_to_iter(titer, 0.25)
909
buff.place_cursor(titer)
911
def step_script(self, mi):
912
self.plugin.do_evt('step')
914
def next_script(self, mi):
915
self.plugin.do_evt('next')
917
def continue_script(self, mi):
918
self.plugin.do_evt('continue')
920
def next_buffer(self, mi):
921
i = self.current_buffer + 1
922
if i >= len(self.wins):
924
self.plugin.do_edit('changebuffer', i)
926
def prev_buffer(self, mi):
927
i = self.current_buffer - 1
929
i = len(self.wins) - 1
930
self.plugin.do_edit('changebuffer', i)
933
class AutoCompletionWindow(gtk.Window):
935
def __init__(self, source_view, trig_iter, text, lst, parent, mod, cbound):
937
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
939
self.set_decorated(False)
940
self.store = gtk.ListStore(str, str, str)
941
self.source = source_view
944
self.cbounds = cbound
950
self.store.append((gtk.STOCK_CONVERT, i, ""))
951
self.tree = gtk.TreeView(self.store)
953
render = gtk.CellRendererPixbuf()
954
column = gtk.TreeViewColumn('', render, stock_id=0)
955
self.tree.append_column(column)
956
col = gtk.TreeViewColumn()
957
render = gtk.CellRendererText()
958
column = gtk.TreeViewColumn('', render, text=1)
959
self.tree.append_column(column)
960
col = gtk.TreeViewColumn()
961
render = gtk.CellRendererText()
962
column = gtk.TreeViewColumn('', render, text=2)
963
self.tree.append_column(column)
964
rect = source_view.get_iter_location(trig_iter)
965
wx, wy = source_view.buffer_to_window_coords(gtk.TEXT_WINDOW_WIDGET,
966
rect.x, rect.y + rect.height)
968
tx, ty = source_view.get_window(gtk.TEXT_WINDOW_WIDGET).get_origin()
969
wth, hht = parent.get_size()
970
width = wth - (tx+wx)
971
height = hht - (ty+wy)
972
if width > 200: width = 200
973
if height > 200: height = 200
974
self.move(wx+tx, wy+ty)
977
self.tree.set_size_request(width, height)
978
self.tree.connect('row-activated', self.row_activated_cb)
979
self.tree.connect('focus-out-event', self.focus_out_event_cb)
980
self.tree.connect('key-press-event', self.key_press_event_cb)
981
self.tree.set_search_column(1)
982
self.tree.set_search_equal_func(self.search_func)
983
self.tree.set_headers_visible(False)
984
self.set_transient_for(parent)
986
self.tree.set_cursor((0,))
987
self.tree.grab_focus()
989
def set_list(self, source_view, trig_iter, text, lst, parent, mod, cbound):
991
self.cbounds = cbound
992
self.store = gtk.ListStore(str, str, str)
993
self.source = source_view
998
self.store.append((gtk.STOCK_CONVERT, i, ""))
999
self.tree.set_model(self.store)
1000
self.tree.set_search_column(1)
1001
self.tree.set_search_equal_func(self.search_func)
1002
rect = source_view.get_iter_location(trig_iter)
1003
wx, wy = source_view.buffer_to_window_coords(gtk.TEXT_WINDOW_WIDGET,
1004
rect.x, rect.y + rect.height)
1005
tx, ty = source_view.get_window(gtk.TEXT_WINDOW_WIDGET).get_origin()
1006
wth, hht = parent.get_size()
1009
width = wth - (wx+tx)
1010
height = hht - (wy+ty)
1011
if width > 200: width = 200
1012
if height > 200: height = 200
1013
self.move(wx+tx, wy+ty)
1014
self.tree.set_size_request(width, height)
1016
self.tree.set_cursor((0,))
1017
self.tree.grab_focus()
1019
def row_activated_cb(self, tree, path, view_column, data = None):
1020
self.complete = self.store[path][1] + self.store[path][2]
1021
self.insert_complete()
1023
def insert_complete(self):
1024
buff = self.source.get_buffer()
1028
buff.select_range(buff.get_iter_at_mark(s), buff.get_iter_at_mark(e))
1029
start, end = buff.get_selection_bounds()
1030
buff.delete(start, end)
1031
buff.insert(start, self.complete)
1033
buff.insert_at_cursor(self.complete)
1035
buff.insert_at_cursor(self.complete[len(self.text):])
1038
def focus_out_event_cb(self, widget, event):
1041
def key_press_event_cb(self, widget, event):
1042
if event.keyval == gtk.keysyms.Escape:
1044
elif event.keyval == gtk.keysyms.BackSpace:
1047
def search_func(self, model, column, key, it):
1051
cp_text = self.text + key
1052
self.complete = cp_text
1053
if model.get_path(model.get_iter_first()) == model.get_path(it):
1055
if model.get_value(it, column).startswith(cp_text):
1057
if model.iter_next(it) is None and not self.found:
1059
self.complete = model.get_value(it, 1)
1062
self.insert_complete()
1064
return not model.get_value(it, column).startswith(cp_text)
1068
self.mainwindow = None
1070
def edit(fname, mainwin=False):
1071
quit_cb = lambda w: gtk.main_quit()
1074
w.connect('delete-event', gtk.main_quit)
1076
e = EditWindow(cb, quit_cb=quit_cb)
1079
w.set_title("Culebra")
1083
w.set_size_request(0,0)
1085
w.dirname = os.getcwd()
1087
if mainwin: gtk.main()
1090
if __name__ == '__main__':
1093
if len(sys.argv) > 1:
1094
fname = sys.argv[-1]
1097
edit(fname, mainwin=True)