📄 filediff.py
字号:
alloc = area.get_allocation() (wtotal,htotal) = alloc.width, alloc.height window.begin_paint_rect( (0,0,wtotal,htotal) ) window.clear() context = window.cairo_create() context.rectangle(0, 0, wtotal, htotal) context.clip() context.set_line_width(0.5) if self.keymask & MASK_SHIFT: pix0 = self.pixbuf_delete pix1 = self.pixbuf_delete elif self.keymask & MASK_CTRL: pix0 = self.pixbuf_copy0 pix1 = self.pixbuf_copy1 else: # self.keymask == 0: pix0 = self.pixbuf_apply0 pix1 = self.pixbuf_apply1 draw_style = self.prefs.draw_style gc = area.meldgc.get_gc which = self.linkmap.index(area) pix_start = [None] * self.num_panes pix_start[which ] = self.textview[which ].get_visible_rect().y pix_start[which+1] = self.textview[which+1].get_visible_rect().y def bounds(idx): return [self._pixel_to_line(idx, pix_start[idx]), self._pixel_to_line(idx, pix_start[idx]+htotal)] visible = [None] + bounds(which) + bounds(which+1) for c in self.linediffer.pair_changes(which, which+1, self._get_texts()): if self.prefs.ignore_blank_lines: c1,c2 = self._consume_blank_lines( self._get_texts()[which ][c[1]:c[2]] ) c3,c4 = self._consume_blank_lines( self._get_texts()[which+1][c[3]:c[4]] ) c = c[0], c[1]+c1,c[2]-c2, c[3]+c3,c[4]-c4 if c[1]==c[2] and c[3]==c[4]: continue assert c[0] != "equal" if c[2] < visible[1] and c[4] < visible[3]: # find first visible chunk continue elif c[1] > visible[2] and c[3] > visible[4]: # we've gone past last visible break # f and t are short for "from" and "to" f0,f1 = [self._line_to_pixel(which, l) - pix_start[which ] for l in c[1:3] ] t0,t1 = [self._line_to_pixel(which+1, l) - pix_start[which+1] for l in c[3:5] ] if f0==f1: f0 -= 1; f1 += 1 if t0==t1: t0 -= 1; t1 += 1 if draw_style == 2: x_step = wtotal / 3.0 # bezier control point distance # thin antialiased lines in cairo look thicker than they are # this is a workaround (works like a charm) aa_adjustment = 0.2 context.move_to(0, f0 - aa_adjustment) context.curve_to(x_step, f0 - aa_adjustment, x_step * 2, t0 - aa_adjustment, wtotal + 1, t0 - aa_adjustment) context.line_to(wtotal + 1, t1 + aa_adjustment) context.curve_to(x_step * 2, t1 + aa_adjustment, x_step, f1 + aa_adjustment, 0, f1 + aa_adjustment) if c[0] in ("insert", "delete"): bg = gdk.color_parse(self.prefs.color_delete_bg) else: #replace bg = gdk.color_parse(self.prefs.color_replace_bg) context.set_source_rgb(bg.red / 65535.0, bg.green / 65535.0, bg.blue / 65535.0) context.fill_preserve() context.set_source_rgb(bg.red / 65535.0 * 0.8, bg.green / 65535.0 * 0.8, bg.blue / 65535.0 * 0.8) context.stroke() else: w = wtotal p = self.pixbuf_apply0.get_width() window.draw_polygon(gctext, 0, (( -1, f0), ( p, f0), ( p,f1), ( -1,f1)) ) window.draw_polygon(gctext, 0, ((w+1, t0), (w-p, t0), (w-p,t1), (w+1,t1)) ) window.draw_line( gctext, p, (f0+f1)/2, w-p, (t0+t1)/2 ) x = wtotal-self.pixbuf_apply0.get_width() if c[0]=="insert": window.draw_pixbuf( gctext, pix1, 0,0, x, t0, -1,-1, 0,0,0) elif c[0] == "delete": window.draw_pixbuf( gctext, pix0, 0,0, 0, f0, -1,-1, 0,0,0) else: #replace window.draw_pixbuf( gctext, pix1, 0,0, x, t0, -1,-1, 0,0,0) window.draw_pixbuf( gctext, pix0, 0,0, 0, f0, -1,-1, 0,0,0) # allow for scrollbar at end of textview mid = 0.5 * self.textview0.get_allocation().height window.draw_line(gctext, int(.25*wtotal), int(mid), int(.75*wtotal), int(mid) ) window.end_paint() def on_linkmap_scroll_event(self, area, event): self.next_diff(event.direction) def on_linkmap_button_press_event(self, area, event): if event.button == 1: self.focus_before_click = None for t in self.textview: if t.is_focus(): self.focus_before_click = t break area.grab_focus() self.mouse_chunk = None alloc = area.get_allocation() (wtotal,htotal) = alloc.width, alloc.height pix_width = self.pixbuf_apply0.get_width() pix_height = self.pixbuf_apply0.get_height() if self.keymask == MASK_CTRL: # hack pix_height *= 2 which = self.linkmap.index(area) # quick reject are we near the gutter? if event.x < pix_width: side = 0 rect_x = 0 elif event.x > wtotal - pix_width: side = 1 rect_x = wtotal - pix_width else: return 1 src = which + side dst = which + 1 - side adj = self.scrolledwindow[src].get_vadjustment() func = lambda c: self._line_to_pixel(src, c[1]) - adj.value for c in self.linediffer.pair_changes(src, dst, self._get_texts()): if self.prefs.ignore_blank_lines: c1,c2 = self._consume_blank_lines( self._get_texts()[src][c[1]:c[2]] ) c3,c4 = self._consume_blank_lines( self._get_texts()[dst][c[3]:c[4]] ) c = c[0], c[1]+c1,c[2]-c2, c[3]+c3,c[4]-c4 if c[1]==c[2] and c[3]==c[4]: continue if c[0] == "insert": continue h = func(c) if h < 0: # find first visible chunk continue elif h > htotal: # we've gone past last visible break elif h < event.y and event.y < h + pix_height: self.mouse_chunk = ( (src,dst), (rect_x, h, pix_width, pix_height), c) break #print self.mouse_chunk return 1 elif event.button == 2: self.linkmap_drag_coord = event.x return 0 def on_linkmap_motion_notify_event(self, area, event): return #dx = event.x - self.linkmap_drag_coord #self.linkmap_drag_coord = event.x #w,h = self.scrolledwindow0.size_request() #w,h = size[2] - size[0], size[3] - size[1] #self.scrolledwindow0.set_size_request(w+dx,h) #print w+dx #textview0.get_allocation( #print misc.all(event) def on_linkmap_button_release_event(self, area, event): if event.button == 1: if self.focus_before_click: self.focus_before_click.grab_focus() self.focus_before_click = None if self.mouse_chunk: (src,dst), rect, chunk = self.mouse_chunk # check we're still in button inrect = lambda p, r: ((r[0] < p.x) and (p.x < r[0]+r[2]) and (r[1] < p.y) and (p.y < r[1]+r[3])) if inrect(event, rect): # gtk tries to jump back to where the cursor was unless we move the cursor self.textview[src].place_cursor_onscreen() self.textview[dst].place_cursor_onscreen() chunk = chunk[1:] self.mouse_chunk = None if self.keymask & MASK_SHIFT: # delete b = self.textview[src].get_buffer() b.delete(b.get_iter_at_line(chunk[0]), b.get_iter_at_line(chunk[1])) elif self.keymask & MASK_CTRL: # copy up or down b0 = self.textview[src].get_buffer() t0 = b0.get_text( b0.get_iter_at_line(chunk[0]), b0.get_iter_at_line(chunk[1]), 0) b1 = self.textview[dst].get_buffer() if event.y - rect[1] < 0.5 * rect[3]: # copy up b1.insert_with_tags_by_name(b1.get_iter_at_line(chunk[2]), t0, "edited line") else: # copy down b1.insert_with_tags_by_name(b1.get_iter_at_line(chunk[3]), t0, "edited line") else: # replace b0 = self.textview[src].get_buffer() t0 = b0.get_text( b0.get_iter_at_line(chunk[0]), b0.get_iter_at_line(chunk[1]), 0) b1 = self.textview[dst].get_buffer() self.on_text_begin_user_action() b1.delete(b1.get_iter_at_line(chunk[2]), b1.get_iter_at_line(chunk[3])) b1.insert_with_tags_by_name(b1.get_iter_at_line(chunk[2]), t0, "edited line") self.on_text_end_user_action() return 1 return 0 def on_linkmap_drag_begin(self, *args): print argsif gobject.pygtk_version < (2,8,0): gobject.type_register(FileDiff)################################################################################## Local Functions#################################################################################class MeldBufferData(object): __slots__ = ("modified", "writable", "filename", "label", "encoding", "newlines") def __init__(self, filename=None): self.modified = 0 self.writable = 1 self.filename = filename self.label = filename self.encoding = None self.newlines = None################################################################################## BufferInsertionAction#################################################################################class BufferInsertionAction(object): """A helper to undo/redo text insertion into a text buffer""" def __init__(self, buffer, offset, text): self.buffer = buffer self.offset = offset self.text = text def undo(self): b = self.buffer b.delete( b.get_iter_at_offset( self.offset), b.get_iter_at_offset(self.offset + len(self.text)) ) def redo(self): b = self.buffer b.insert( b.get_iter_at_offset( self.offset), self.text)################################################################################## BufferDeletionAction#################################################################################class BufferDeletionAction(object): """A helper to undo/redo text deletion from a text buffer""" def __init__(self, buffer, offset, text): self.buffer = buffer self.offset = offset self.text = text def undo(self): b = self.buffer b.insert( b.get_iter_at_offset( self.offset), self.text) def redo(self): b = self.buffer b.delete( b.get_iter_at_offset( self.offset), b.get_iter_at_offset(self.offset + len(self.text)) )################################################################################## BufferModifiedAction#################################################################################class BufferModifiedAction(object): """A helper set modified flag on a text buffer""" def __init__(self, buffer, app): self.buffer, self.app = buffer, app self.app.set_buffer_modified(self.buffer, 1) def undo(self): self.app.set_buffer_modified(self.buffer, 0) def redo(self): self.app.set_buffer_modified(self.buffer, 1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -