📄 vcview.py
字号:
else: path = self.model.value_path(it, 0) self.run_diff( [path] ) def run_diff_iter(self, paths, empty_patch_ok): yield _("[%s] Fetching differences") % self.label_text difffunc = self._command_iter(self.vc.diff_command(), paths, 0).next diff = None while type(diff) != type(()): diff = difffunc() yield 1 prefix, patch = diff[0], diff[1] yield _("[%s] Applying patch") % self.label_text if patch: self.show_patch(prefix, patch) elif empty_patch_ok: misc.run_dialog( _("No differences found."), parent=self, messagetype=gtk.MESSAGE_INFO) else: for path in paths: self.emit("create-diff", [path]) def run_diff(self, paths, empty_patch_ok=0): self.scheduler.add_task( self.run_diff_iter(paths, empty_patch_ok).next, atfront=1 ) def on_button_press_event(self, text, event): if event.button==3: VcMenu(self, event) return len(self._get_selected_treepaths()) != 1 return 0 def on_button_flatten_toggled(self, button): self.treeview_column_location.set_visible( self.button_flatten.get_active() ) self.refresh() def on_button_filter_toggled(self, button): self.refresh() def _get_selected_treepaths(self): sel = [] def gather(model, path, it): sel.append( model.get_path(it) ) s = self.treeview.get_selection() s.selected_foreach(gather) return sel def _get_selected_files(self): sel = [] def gather(model, path, it): sel.append( model.value_path(it,0) ) s = self.treeview.get_selection() s.selected_foreach(gather) # remove empty entries and remove trailing slashes return [ x[-1]!="/" and x or x[:-1] for x in sel if x != None ] def _command_iter(self, command, files, refresh): """Run 'command' on 'files'. Return a tuple of the directory the command was executed in and the output of the command. """ msg = misc.shelljoin(command) yield "[%s] %s" % (self.label_text, msg.replace("\n", u"\u21b2") ) def relpath(pbase, p): assert p.startswith(pbase) kill = len(pbase) and (len(pbase)+1) or 0 return p[kill:] or "." if len(files) == 1 and os.path.isdir(files[0]): workdir = self.vc.get_working_directory(files[0]) else: workdir = self.vc.get_working_directory( _commonprefix(files) ) files = [ relpath(workdir, f) for f in files ] r = None self.consolestream.write( misc.shelljoin(command+files) + " (in %s)\n" % workdir) readfunc = misc.read_pipe_iter(command + files, self.consolestream, workdir=workdir).next try: while r == None: r = readfunc() self.consolestream.write(r) yield 1 except IOError, e: misc.run_dialog("Error running command.\n'%s'\n\nThe error was:\n%s" % ( misc.shelljoin(command), e), parent=self, messagetype=gtk.MESSAGE_ERROR) if refresh: self.refresh_partial(workdir) yield workdir, r def _command(self, command, files, refresh=1): """Run 'command' on 'files'. """ self.scheduler.add_task( self._command_iter(command, files, refresh).next ) def _command_on_selected(self, command, refresh=1): files = self._get_selected_files() if len(files): self._command(command, files, refresh) else: misc.run_dialog( _("Select some files first."), parent=self, messagetype=gtk.MESSAGE_INFO) def on_button_update_clicked(self, object): self._command_on_selected( self.vc.update_command() ) def on_button_commit_clicked(self, object): dialog = CommitDialog( self ) dialog.run() def on_button_add_clicked(self, object): self._command_on_selected(self.vc.add_command() ) def on_button_add_binary_clicked(self, object): self._command_on_selected(self.vc.add_command(binary=1)) def on_button_remove_clicked(self, object): self._command_on_selected(self.vc.remove_command()) def on_button_revert_clicked(self, object): self._command_on_selected(self.vc.revert_command()) def on_button_delete_clicked(self, object): files = self._get_selected_files() for name in files: try: if os.path.isfile(name): os.remove(name) elif os.path.isdir(name): if misc.run_dialog(_("'%s' is a directory.\nRemove recusively?") % os.path.basename(name), parent = self, buttonstype=gtk.BUTTONS_OK_CANCEL) == gtk.RESPONSE_OK: shutil.rmtree(name) except OSError, e: misc.run_dialog(_("Error removing %s\n\n%s.") % (name,e), parent = self) workdir = _commonprefix(files) self.refresh_partial(workdir) def on_button_diff_clicked(self, object): files = self._get_selected_files() if len(files): self.run_diff(files, empty_patch_ok=1) def show_patch(self, prefix, patch): if not patch: return tmpdir = tempfile.mkdtemp("-meld") self.tempdirs.append(tmpdir) regex = re.compile(self.vc.PATCH_INDEX_RE, re.M) files = [f.split()[-1] for f in regex.findall(patch)] diffs = [] for fname in files: destfile = os.path.join(tmpdir,fname) destdir = os.path.dirname( destfile ) if not os.path.exists(destdir): os.makedirs(destdir) pathtofile = os.path.join(prefix, fname) try: shutil.copyfile( pathtofile, destfile) except IOError: # it is missing, create empty file open(destfile,"w").close() diffs.append( (destfile, pathtofile) ) patchcmd = self.vc.patch_command( tmpdir ) misc.write_pipe(patchcmd, patch) for d in diffs: self.emit("create-diff", d) def refresh(self): self.set_location( self.model.value_path( self.model.get_iter_root(), 0 ) ) def refresh_partial(self, where): if not self.button_flatten.get_active(): it = self.find_iter_by_name( where ) if it: newiter = self.model.insert_after( None, it) self.model.set_value(newiter, self.model.column_index( tree.COL_PATH, 0), where) self.model.set_state(newiter, 0, tree.STATE_NORMAL, isdir=1) self.model.remove(it) self.scheduler.add_task( self._search_recursively_iter(newiter).next ) else: # XXX fixme self.refresh() def on_button_jump_press_event(self, button, event): class MyMenu(gtk.Menu): def __init__(self, parent, where, showup=1): gtk.Menu.__init__(self) self.vcview = parent self.map_id = self.connect("map", lambda item: self.on_map(item,where,showup) ) def add_item(self, name, submenu, showup): item = gtk.MenuItem(name) if submenu: item.set_submenu( MyMenu(self.vcview, submenu, showup ) ) self.append( item ) def on_map(self, item, where, showup): if showup: self.add_item("..", os.path.dirname(where), 1 ) self.populate( where, self.listdir(where) ) self.show_all() self.disconnect(self.map_id) del self.map_id def listdir(self, d): try: return [p for p in os.listdir(d) if os.path.isdir( os.path.join(d,p))] except OSError: return [] def populate(self, where, children): for child in children: cc = self.listdir( os.path.join(where, child) ) self.add_item( child, len(cc) and os.path.join(where,child), 0 ) menu = MyMenu( self, os.path.abspath(self.location) ) menu.popup(None, None, None, event.button, event.time) def _update_item_state(self, it, vcentry, location): e = vcentry self.model.set_state( it, 0, e.state, e.isdir ) def set(col, val): self.model.set_value( it, self.model.column_index(col,0), val) set( COL_LOCATION, location ) set( COL_STATUS, e.get_status()) set( COL_REVISION, e.rev) set( COL_TAG, e.tag) set( COL_OPTIONS, e.options) def on_file_changed(self, filename): it = self.find_iter_by_name(filename) if it: path = self.model.value_path(it, 0) dirs, files = self.vc.lookup_files( [], [ (os.path.basename(path), path)] ) for e in files: if e.path == path: prefixlen = 1 + len( self.model.value_path( self.model.get_iter_root(), 0 ) ) self._update_item_state( it, e, e.parent[prefixlen:]) return def find_iter_by_name(self, name): it = self.model.get_iter_root() path = self.model.value_path(it, 0) while it: if name == path: return it elif name.startswith(path): child = self.model.iter_children( it ) while child: path = self.model.value_path(child, 0) if name == path: return child elif name.startswith(path): break else: child = self.model.iter_next( child ) it = child else: break return None def on_console_view_toggle(self, box, event=None): if box == self.console_hide_box: self.prefs.vc_console_visible = 0 self.console_hbox.hide() self.console_show_box.show() else: self.prefs.vc_console_visible = 1 self.console_hbox.show() self.console_show_box.hide() def on_consoleview_populate_popup(self, text, menu): item = gtk.ImageMenuItem(gtk.STOCK_CLEAR) def activate(*args): buf = text.get_buffer() buf.delete( buf.get_start_iter(), buf.get_end_iter() ) item.connect("activate", activate) item.show() menu.insert( item, 0 ) item = gtk.SeparatorMenuItem() item.show() menu.insert( item, 1 ) def next_diff(self, direction): start_iter = self.model.get_iter( (self._get_selected_treepaths() or [(0,)])[-1] ) def goto_iter(it): curpath = self.model.get_path(it) for i in range(len(curpath)-1): self.treeview.expand_row( curpath[:i+1], 0) self.treeview.set_cursor(curpath) search = {gtk.gdk.SCROLL_UP : self.model.inorder_search_up}.get(direction, self.model.inorder_search_down) for it in search( start_iter ): state = int(self.model.get_state( it, 0)) if state not in (tree.STATE_NORMAL, tree.STATE_EMPTY): goto_iter(it) return def on_reload_activate(self, *extra): self.on_fileentry_activate(self.fileentry)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -