📄 filediff.py
字号:
try_codecs = self.prefs.text_codecs.split() yield _("[%s] Opening files") % self.label_text panetext = ["\n"] * self.num_panes tasks = [] for i,f in enumerate(files): if f: try: task = misc.struct(filename = f, file = codecs.open(f, "rU", try_codecs[0]), buf = buffers[i], codec = try_codecs[:], text = [], pane = i) tasks.append(task) except (IOError, LookupError), e: buffers[i].set_text("\n") misc.run_dialog( "%s\n\n%s\n%s" % ( _("Could not read from '%s'") % f, _("The error was:"), str(e)), parent = self) else: panetext[i] = buffers[i].get_text( buffers[i].get_start_iter(), buffers[i].get_end_iter() ) yield _("[%s] Reading files") % self.label_text while len(tasks): for t in tasks[:]: try: nextbit = t.file.read(4096) if nextbit.find("\x00") != -1: misc.run_dialog( "%s\n\n%s" % ( _("Could not read from '%s'") % t.filename, _("It contains ascii nulls.\nPerhaps it is a binary file.") ), parent = self ) t.buf.delete( t.buf.get_start_iter(), t.buf.get_end_iter() ) tasks.remove(t) except ValueError, err: t.codec.pop(0) if len(t.codec): t.file = codecs.open(t.filename, "rU", t.codec[0]) t.buf.delete( t.buf.get_start_iter(), t.buf.get_end_iter() ) t.text = [] else: print "codec error fallback", err t.buf.delete( t.buf.get_start_iter(), t.buf.get_end_iter() ) misc.run_dialog( "%s\n\n%s" % ( _("Could not read from '%s'") % t.filename, _("I tried encodings %s.") % try_codecs ), parent = self) tasks.remove(t) except IOError, ioerr: misc.run_dialog( "%s\n\n%s\n%s" % ( _("Could not read from '%s'") % t.filename, _("The error was:"), str(ioerr)), parent = self) tasks.remove(t) else: if len(nextbit): t.buf.insert( t.buf.get_end_iter(), nextbit ) t.text.append(nextbit) else: self.set_buffer_writable(t.buf, os.access(t.filename, os.W_OK)) self.bufferdata[t.pane].encoding = t.codec[0] if hasattr(t.file, "newlines"): self.bufferdata[t.pane].newlines = t.file.newlines tasks.remove(t) panetext[t.pane] = "".join(t.text) if len(panetext[t.pane]) and \ panetext[t.pane][-1] != "\n" and \ self.prefs.supply_newline: t.buf.insert( t.buf.get_end_iter(), "\n") panetext[t.pane] += "\n" yield 1 self.undosequence.clear() yield _("[%s] Computing differences") % self.label_text panetext = [self._filter_text(p) for p in panetext] lines = map(lambda x: x.split("\n"), panetext) step = self.linediffer.set_sequences_iter(*lines) while step.next() == None: yield 1 self.queue_draw() lenseq = [len(d) for d in self.linediffer.diffs] self.scheduler.add_task( self._update_highlighting( (0,lenseq[0]), (0,lenseq[1]) ).next ) self._connect_buffer_handlers() if sourceview_available: for i in range(len(files)): if files[i]: set_highlighting_enabled( self.textview[i].get_buffer(), files[i], self.prefs.use_syntax_highlighting ) yield 0 def _update_highlighting(self, range0, range1): buffers = [t.get_buffer() for t in self.textview] for b in buffers: taglist = ["delete line", "conflict line", "replace line", "inline line"] table = b.get_tag_table() for tagname in taglist: tag = table.lookup(tagname) b.remove_tag(tag, b.get_start_iter(), b.get_end_iter() ) for chunk in self.linediffer.all_changes(self._get_texts()): for i,c in enumerate(chunk): if c and c[0] == "replace": bufs = buffers[1], buffers[i*2] #tags = [b.get_tag_table().lookup("replace line") for b in bufs] starts = [b.get_iter_at_line(l) for b,l in zip(bufs, (c[1],c[3])) ] text1 = "\n".join( self._get_texts(raw=1)[1 ][c[1]:c[2]] ).encode("utf16") text1 = struct.unpack("%iH"%(len(text1)/2), text1)[1:] textn = "\n".join( self._get_texts(raw=1)[i*2][c[3]:c[4]] ).encode("utf16") textn = struct.unpack("%iH"%(len(textn)/2), textn)[1:] matcher = difflib.SequenceMatcher(None, text1, textn) #print "<<<\n%s\n---\n%s\n>>>" % (text1, textn) tags = [b.get_tag_table().lookup("inline line") for b in bufs] back = (0,0) for o in matcher.get_opcodes(): if o[0] == "equal": if (o[2]-o[1] < 3) or (o[4]-o[3] < 3): back = o[4]-o[3], o[2]-o[1] continue for i in range(2): s,e = starts[i].copy(), starts[i].copy() s.forward_chars( o[1+2*i] - back[i] ) e.forward_chars( o[2+2*i] ) bufs[i].apply_tag(tags[i], s, e) back = (0,0) yield 1 def on_textview_expose_event(self, textview, event): if self.num_panes == 1: return if event.window != textview.get_window(gtk.TEXT_WINDOW_TEXT) \ and event.window != textview.get_window(gtk.TEXT_WINDOW_LEFT): return if not hasattr(textview, "meldgc"): self._setup_gcs(textview) visible = textview.get_visible_rect() pane = self.textview.index(textview) start_line = self._pixel_to_line(pane, visible.y) end_line = 1+self._pixel_to_line(pane, visible.y+visible.height) gc = lambda x : getattr(textview.meldgc, "gc_"+x) #gcdark = textview.get_style().black_gc gclight = textview.get_style().bg_gc[gtk.STATE_ACTIVE] #curline = textview.get_buffer().get_iter_at_mark( textview.get_buffer().get_insert() ).get_line() def draw_change(change): # draw background and thin lines ypos0 = self._line_to_pixel(pane, change[1]) - visible.y width = event.window.get_size()[0] #gcline = (gclight, gcdark)[change[1] <= curline and curline < change[2]] gcline = gclight event.window.draw_line(gcline, 0,ypos0-1, width,ypos0-1) if change[2] != change[1]: ypos1 = self._line_to_pixel(pane, change[2]) - visible.y event.window.draw_line(gcline, 0,ypos1, width,ypos1) event.window.draw_rectangle(gc(change[0]), 1, 0,ypos0, width,ypos1-ypos0) last_change = None for change in self.linediffer.single_changes(pane, self._get_texts()): if change[2] < start_line: continue if change[1] > end_line: break if last_change and change[1] <= last_change[2]: last_change = ("conflict", last_change[1], max(last_change[2],change[2])) else: if last_change: draw_change(last_change) last_change = change if last_change: draw_change(last_change) def _get_filename_for_saving(self, title ): dialog = gtk.FileChooserDialog(title, parent=self.widget.get_toplevel(), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK) ) dialog.set_default_response(gtk.RESPONSE_OK) response = dialog.run() filename = None if response == gtk.RESPONSE_OK: filename = dialog.get_filename() dialog.destroy() if filename: if os.path.exists(filename): response = misc.run_dialog( _('"%s" exists!\nOverwrite?') % os.path.basename(filename), parent = self, buttonstype = gtk.BUTTONS_YES_NO) if response == gtk.RESPONSE_NO: return None return filename return None def _save_text_to_filename(self, filename, text): try: open(filename, "w").write(text) except IOError, e: misc.run_dialog( _("Error writing to %s\n\n%s.") % (filename, e), self, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK) return False return True def save_file(self, pane, saveas=0): buf = self.textview[pane].get_buffer() bufdata = self.bufferdata[pane] if saveas or not bufdata.filename: filename = self._get_filename_for_saving( _("Choose a name for buffer %i.") % (pane+1) ) if filename: bufdata.filename = bufdata.label = os.path.abspath(filename) self.fileentry[pane].set_filename( bufdata.filename) else: return melddoc.RESULT_ERROR text = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0) if bufdata.newlines: if type(bufdata.newlines) == type(""): if(bufdata.newlines) != '\n': text = text.replace("\n", bufdata.newlines) elif type(bufdata.newlines) == type(()): buttons = {'\n':("UNIX (LF)",0), '\r\n':("DOS (CR-LF)", 1), '\r':("MAC (CR)",2) } newline = misc.run_dialog( _("This file '%s' contains a mixture of line endings.\n\nWhich format would you like to use?") % bufdata.label, self, gtk.MESSAGE_WARNING, buttonstype=gtk.BUTTONS_CANCEL, extrabuttons=[ buttons[b] for b in bufdata.newlines ] ) if newline < 0: return for k,v in buttons.items(): if v[1] == newline: bufdata.newlines = k if k != '\n': text = text.replace('\n', k) break if bufdata.encoding and self.prefs.save_encoding==0: try: text = text.encode(bufdata.encoding) except UnicodeEncodeError: if misc.run_dialog( _("'%s' contains characters not encodable with '%s'\nWould you like to save as UTF-8?") % (bufdata.label, bufdata.encoding), self, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO) != gtk.RESPONSE_YES: return melddoc.RESULT_ERROR if self._save_text_to_filename(bufdata.filename, text): self.emit("file-changed", bufdata.filename) self.undosequence.clear() self.set_buffer_modified(buf, 0) return melddoc.RESULT_OK else: return melddoc.RESULT_ERROR def make_patch(self, pane): fontdesc = pango.FontDescription(self.prefs.get_current_font()) override = {} if sourceview_available: override["GtkTextView"] = gsv.SourceView override["GtkTextBuffer"] = gsv.SourceBuffer dialog = gnomeglade.Component( paths.share_dir("glade2/filediff.glade"), "patchdialog", override) dialog.widget.set_transient_for( self.widget.get_toplevel() ) bufs = [t.get_buffer() for t in self.textview] texts = [b.get_text(*b.get_bounds()).split("\n") for b in bufs] texts[0] = [l+"\n" for l in texts[0]] texts[1] = [l+"\n" for l in texts[1]] names = [self._get_pane_label(i) for i in range(2)] prefix = os.path.commonprefix( names ) try: prefixslash = prefix.rindex("/") + 1 except ValueError: prefixslash = 0 names = [n[prefixslash:] for n in names] if sourceview_available: dialog.textview.set_buffer( gsv.SourceBuffer() ) dialog.textview.modify_font(fontdesc) buf = dialog.textview.get_buffer() lines = [] for line in difflib.unified_diff(texts[0], texts[1], names[0], names[1]): buf.insert( buf.get_end_iter(), line ) lines.append(line) if sourceview_available: man = gsv.SourceLanguagesManager() gsl = man.get_language_from_mime_type("text/x-diff") if gsl: buf.set_language(gsl) buf.set_highlight(True) result = dialog.widget.run() dialog.widget.destroy() if result >= 0: txt = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0) if result == 1: # copy clip = gtk.clipboard_get() clip.set_text(txt) clip.store() else:# save as filename = self._get_filename_for_saving( _("Save patch as...") ) if filename: self._save_text_to_filename(filename, txt)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -