/
__init__.py
298 lines (263 loc) · 9.77 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#VERSION 1.1.4
import gedit, gtk, gtk.glade
import gconf
import gnomevfs
import pygtk
pygtk.require('2.0')
import os, os.path, gobject, urllib
from gtk import gdk
# set this to true for gedit versions before 2.16
pre216_version = False
max_result = 50
ui_str="""<ui>
<menubar name="MenuBar">
<menu name="FileMenu" action="File">
<placeholder name="FileOps_2">
<menuitem name="SnapOpen" action="SnapOpenAction"/>
</placeholder>
</menu>
</menubar>
</ui>
"""
# essential interface
class SnapOpenPluginInstance:
def __init__( self, plugin, window ):
self._window = window
self._plugin = plugin
if pre216_version:
self._encoding = gedit.gedit_encoding_get_current()
else:
self._encoding = gedit.encoding_get_current()
self._rootdir = "file://" + os.getcwd()
self._show_hidden = False
self._liststore = None;
self._init_glade()
self._insert_menu()
def deactivate( self ):
self._remove_menu()
self._action_group = None
self._window = None
self._plugin = None
self._liststore = None;
def update_ui( self ):
return
# MENU STUFF
def _insert_menu( self ):
manager = self._window.get_ui_manager()
self._action_group = gtk.ActionGroup( "SnapOpenPluginActions" )
snapopen_action = gtk.Action( name="SnapOpenAction", label="Snap Open...\t",
tooltip="Snap open a file", stock_id=gtk.STOCK_OPEN )
snapopen_action.connect( "activate", lambda a: self.on_snapopen_action() )
self._action_group.add_action_with_accel( snapopen_action, "<Ctrl><Alt>o" )
manager.insert_action_group( self._action_group, 0 )
self._ui_id = manager.new_merge_id()
manager.add_ui_from_string( ui_str )
manager.ensure_update()
def _remove_menu( self ):
manager = self._window.get_ui_manager()
manager.remove_ui( self._ui_id )
manager.remove_action_group( self._action_group )
manager.ensure_update()
# UI DIALOGUES
def _init_glade( self ):
self._snapopen_glade = gtk.glade.XML( os.path.dirname( __file__ ) + "/snapopen.glade" )
#setup window
self._snapopen_window = self._snapopen_glade.get_widget( "SnapOpenWindow" )
self._snapopen_window.connect("key-release-event", self.on_window_key)
self._snapopen_window.set_transient_for(self._window)
#setup buttons
self._snapopen_glade.get_widget( "ok_button" ).connect( "clicked", self.open_selected_item )
self._snapopen_glade.get_widget( "cancel_button" ).connect( "clicked", lambda a: self._snapopen_window.hide())
#setup entry field
self._glade_entry_name = self._snapopen_glade.get_widget( "entry_name" )
self._glade_entry_name.connect("key-press-event", self.on_key_press)
self._glade_entry_name.connect("key-release-event", self.on_pattern_entry)
#setup list field
self._hit_list = self._snapopen_glade.get_widget( "hit_list" )
self._hit_list.connect("select-cursor-row", self.on_select_from_list)
self._hit_list.connect("button_press_event", self.on_list_mouse)
self._liststore = gtk.ListStore(str, str)
self._hit_list.set_model(self._liststore)
column = gtk.TreeViewColumn("Name" , gtk.CellRendererText(), text=0)
column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
column2 = gtk.TreeViewColumn("File", gtk.CellRendererText(), text=1)
column2.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
self._hit_list.append_column(column)
self._hit_list.append_column(column2)
self._hit_list.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
#mouse event on list
def on_list_mouse( self, widget, event ):
if event.type == gtk.gdk._2BUTTON_PRESS:
self.open_selected_item( event )
#key selects from list (passthrough 3 args)
def on_select_from_list(self, widget, event):
self.open_selected_item(event)
# Forward Up and Down key press events to the hit list.
def on_key_press( self, widget, event ):
if event.keyval in (gtk.keysyms.Up, gtk.keysyms.Down):
widget.stop_emission("key-press-event")
selection = self._hit_list.get_selection()
model, rows = selection.get_selected_rows()
if len(rows) > 0:
if event.keyval == gtk.keysyms.Up:
path = (rows[0][0] - 1, )
else:
path = (rows[0][0] + 1, )
try:
iter = model.get_iter(path)
except ValueError:
iter = None
if iter != None:
selection.unselect_all()
selection.select_iter(iter)
return True
#keyboard event on entry field
def on_pattern_entry( self, widget, event ):
oldtitle = self._snapopen_window.get_title().replace(" * too many hits", "")
if event.keyval in (gtk.keysyms.Up, gtk.keysyms.Down):
return
if event.keyval == gtk.keysyms.Return:
self.open_selected_item( event )
return
pattern = self._glade_entry_name.get_text()
pattern = pattern.replace(" ","*")
# modify lines below as needed, these defaults work pretty well
filefilter = " | grep -s -v \"/\.\" 2>/dev/null"
cmd = ""
if self._show_hidden:
filefilter = ""
if len(pattern) > 0:
cmd = ('cd "%(path)s"' +
' && find . -maxdepth 10 -depth -type f -iwholename "*%(pattern)s*"' +
' | grep -v -E "(/\.|~$)" 2>/dev/null' + # ignore hidden and backup files
' | head -n %(max_results)d' +
' | sort') % \
{ 'path' : self._shell_escape(self._rootdir),
'pattern' : self._shell_escape(pattern),
'max_results' : max_result + 1 }
self._snapopen_window.set_title("Searching ... ")
else:
self._snapopen_window.set_title("Enter pattern ... ")
#print cmd
self._liststore.clear()
maxcount = 0
hits = os.popen(cmd).readlines()
for file in hits:
file = file.rstrip().replace("./", "") #remove cwd prefix
name = os.path.basename(file)
self._liststore.append([name, file])
if maxcount > max_result:
break
maxcount = maxcount + 1
if maxcount > max_result:
oldtitle = oldtitle + " * too many hits"
self._snapopen_window.set_title(oldtitle)
selected = []
self._hit_list.get_selection().selected_foreach(self.foreach, selected)
if len(selected) == 0:
iter = self._liststore.get_iter_first()
if iter != None:
self._hit_list.get_selection().select_iter(iter)
#on menuitem activation (incl. shortcut)
def on_snapopen_action( self ):
fbroot = self.get_filebrowser_root()
if fbroot != "" and fbroot is not None:
self._rootdir = fbroot
self._snapopen_window.set_title("Snap open (Filebrowser integration)")
else:
eddtroot = self.get_eddt_root()
if eddtroot != "" and eddtroot is not None:
self._rootdir = eddtroot
self._snapopen_window.set_title("Snap open (EDDT integration)")
else:
self._snapopen_window.set_title("Snap open (cwd): " + self._rootdir)
self._snapopen_window.show()
self._glade_entry_name.select_region(0,-1)
self._glade_entry_name.grab_focus()
#on any keyboard event in main window
def on_window_key( self, widget, event ):
if event.keyval == gtk.keysyms.Escape:
self._snapopen_window.hide()
def foreach(self, model, path, iter, selected):
selected.append(model.get_value(iter, 1))
#open file in selection and hide window
def open_selected_item( self, event ):
selected = []
self._hit_list.get_selection().selected_foreach(self.foreach, selected)
for selected_file in selected:
self._open_file ( selected_file )
self._snapopen_window.hide()
#gedit < 2.16 version (get_tab_from_uri)
def old_get_tab_from_uri(self, window, uri):
docs = window.get_documents()
for doc in docs:
if doc.get_uri() == uri:
return gedit.tab_get_from_document(doc)
return None
#opens (or switches to) the given file
def _open_file( self, filename ):
uri = "file://" + self._rootdir + "/" + filename
if pre216_version:
tab = self.old_get_tab_from_uri(self._window, uri)
else:
tab = self._window.get_tab_from_uri(uri)
if tab == None:
tab = self._window.create_tab_from_uri( uri, self._encoding, 0, False, False )
self._window.set_active_tab( tab )
# Escapes the given string for so that the return value, when surrounded by quotes, can be
# passed to the shell as a single arugment. Example:
#
# >>> print self._shell_escape('hello "world$')
# hello \"world
def _shell_escape( self, string ):
return string.replace('"', '\\"').replace('$', '\\$')
# Convert a GNOME file URI, such as "file:///home/foo%20bar/hello.txt"
def _file_uri_to_filename( self, uri ):
return urllib.unquote_plus(uri.replace("file://", ""))
# EDDT integration
def get_eddt_root(self):
base = u'/apps/gedit-2/plugins/eddt'
client = gconf.client_get_default()
client.add_dir(base, gconf.CLIENT_PRELOAD_NONE)
path = os.path.join(base, u'repository')
val = client.get(path)
if val is not None:
return self._file_uri_to_filename(val.get_string())
# FILEBROWSER integration
def get_filebrowser_root(self):
base = u'/apps/gedit-2/plugins/filebrowser/on_load'
client = gconf.client_get_default()
client.add_dir(base, gconf.CLIENT_PRELOAD_NONE)
path = os.path.join(base, u'virtual_root')
val = client.get(path)
if val is not None:
# Also read hidden files setting
base = u'/apps/gedit-2/plugins/filebrowser'
client = gconf.client_get_default()
client.add_dir(base, gconf.CLIENT_PRELOAD_NONE)
path = os.path.join(base, u'filter_mode')
try:
fbfilter = client.get(path).get_string()
except AttributeError:
fbfilter = "hidden"
if fbfilter.find("hidden") == -1:
self._show_hidden = True
else:
self._show_hidden = False
return self._file_uri_to_filename(val.get_string())
# STANDARD PLUMMING
class SnapOpenPlugin( gedit.Plugin ):
DATA_TAG = "SnapOpenPluginInstance"
def __init__( self ):
gedit.Plugin.__init__( self )
def _get_instance( self, window ):
return window.get_data( self.DATA_TAG )
def _set_instance( self, window, instance ):
window.set_data( self.DATA_TAG, instance )
def activate( self, window ):
self._set_instance( window, SnapOpenPluginInstance( self, window ) )
def deactivate( self, window ):
self._get_instance( window ).deactivate()
self._set_instance( window, None )
def update_ui( self, window ):
self._get_instance( window ).update_ui()