def test_as_populated_list_throws_error_if_clearing_start(): r = RunLengthList([(0, "foo"), (3, "bar")]) try: r.blank_between(0, 2) except ValueError: pass else: assert False
def __init__(self, gui): DisplayView.__init__(self) #the identity of the return value of get_buffer() doesn't seem to be #stable. before, we used a property, but now we just get it once and #leave it at that because GTK complains about the non-identicality #of them. self.gui = gui self.paused = False self.end_mark = self.buffer.create_mark('end_mark', self.buffer.get_end_iter(), False) self.timestamps = RunLengthList({}) self.connect('focus-in-event', self.got_focus_cb) self.set_property("has-tooltip", True) self.connect("query-tooltip", self.display_tooltip_cb)
def taggedml(line, default_fg=WHITE, default_bg=BLACK): pattern=r'(<(?:\w|\*)+(?::\w+){0,1}>)' matches=re.findall(pattern, line) new_line="" tag_length=0 index=0 fg=RunLengthList([(0,fg_code(default_fg,False))]) bg=RunLengthList([(0,bg_code(default_bg))]) for m in matches: color_tag=m[1:-1].split(':') fg_color_str=color_tag[0] if '*' in fg_color_str: bold=True fg_color_str=fg_color_str.replace('*','') else: bold=False if len(color_tag)==2: bg_color_str=color_tag[1] else: bg_color_str=None if not hasattr(colours, fg_color_str.upper()): continue if bg_color_str!=None and not hasattr(colours, bg_color_str.upper()): continue m_idx=line.find(m,index) new_line=new_line+line[index:m_idx] try: fg_color=getattr(colours, fg_color_str.upper()) if bg_color_str!=None: bg_color=getattr(colours, bg_color_str.upper()) else: bg_color=default_bg except TypeError: return line fg.add_change(m_idx-tag_length, fg_code(fg_color,bold)) if bg_color!=None: bg.add_change(m_idx-tag_length, bg_code(bg_color)) index=line.find(m,index)+len(m) tag_length+=len(m) new_line=new_line+line[index:] return Metaline(new_line, fg,bg)
def test_blank_between_second_argument_None_blanks_to_end(): rl = RunLengthList([(0, "foo"), (2, "bar"), (4, "baz")]) rl.blank_between(1, None) assert rl.items() == [(0, "foo")]
def test_change_between_changes_to_end_if_second_argument_None(): rl = RunLengthList([(0, "foo"), (2, "bar"), (4, "baz")]) rl.change_between(1, None, "qux") assert rl.items() == [(0, "foo"), (1, "qux")]
def test_RunLengthList_add_change(): c = RunLengthList([(0, 1), (3, 2)]) c.add_change(1, 3) assert c.items() == [(0, 1), (1, 3), (3, 2)]
def test_RunLengthList_index_adjust(): c = RunLengthList([(0, 1), (3, 2), (6, 3)]) c.index_adjust(2, 2) assert c.items() == [(0, 1), (5, 2), (8, 3)], c.items()
def test_Metaline_insert_fg_bg_on_too_long(): fores, backs = RunLengthList([(0, "foo")]), RunLengthList([(0, "bar")]) m = Metaline("foo", fores.copy(), backs.copy()) m.insert(2, "bar") assert m.fores == fores, m.backs == backs
def index_adjust(self, index, adjustment): RunLengthList.index_adjust(self, index, adjustment) self.adjustments.append((index, adjustment))
def test_RunLengthList_insertion(): r1 = RunLengthList([(0, "foo"), (2, "qux")]) r2 = RunLengthList([(0, "bar"), (2, "baz")]) r1.insert_list_at(1, 3, r2) assert r1.items() == [(0, "foo"), (1, "bar"), (3, "baz"), (4, "foo"), (5, "qux")], r1.items()
def test_get_at_works_right_before_colour_change(): rll = RunLengthList({0: "foo", 2: "bar"}) assert rll.get_at(1) == "foo"
def test_RunLengthList_add_change_normalises_afterwards(): r = RunLengthList([(0, "foo")]) r.add_change(2, "foo") r.add_change(1, "bar") assert r.items() == [(0, "foo"), (1, "bar")]
def test_copy_returns_different_lists(): r = RunLengthList([(0, "foo")]) assert r.items() is not r.copy().items()
def test_RunLengthList_blank_between(): c = RunLengthList([(0, "FOO"), (2, "BAR"), (3, "BAZ"), (4, "QUX")]) c.blank_between(2, 3) assert c.items() == [(0, "FOO"), (3, "BAZ"), (4, "QUX")], c.items()
def test_RunlengthList_index_adjust_negative_adjustment_normalises(): c = RunLengthList([(0, "f"), (2, "o"), (3, "b")]) c.index_adjust(1, -2) assert c.items() == [(0, "f"), (1, "b")]
def test_RunLengthList_index_adjust_index_collision(): c = RunLengthList([(0, 1), (3, 2)]) c.index_adjust(3, 2) assert c.items() == [(0, 1), (5, 2)], c.items()
def test_get_at_works_for_index_0(): rll = RunLengthList({0: "foo", 1: "bar"}) assert rll.get_at(0) == "foo"
def test_RunLengthList_insertion_normalisation(): r1 = RunLengthList([(0, "foo"), (1, "bar")]) r2 = RunLengthList([(0, "foo"), (1, "bar")]) r1.insert_list_at(1, 2, r2) assert r1.items() == [(0, "foo"), (2, "bar")], r1.items()
def test_get_at_works_after_last_index(): rll = RunLengthList({0: "foo", 2: "bar"}) assert rll.get_at(10) == "bar"
def test_inserted_list_gets_chopped_if_not_enough_length(): r1 = RunLengthList([(0, "foo"), (1, "bar")]) r2 = RunLengthList([(0, "baz"), (2, "qux")]) r1.insert_list_at(1, 1, r2) assert r1.items() == [(0, "foo"), (1, "baz"), (2, "bar")]
def test_get_at_works_on_colour_change(): rll = RunLengthList({0: "foo", 2: "bar"}) assert rll.get_at(2) == "bar"
def test_RunLengthList_copy_copies_non_empty(): r = RunLengthList([(0, "foo")]) assert r == r.copy() assert not r.items() is r.copy().items()
def __init__(self, *args): self.adjustments = [] RunLengthList.__init__(self, *args)
def metaLine(self): line = "Shield|Aura|Barrier" fg = RunLengthList([(0, fg_code(YELLOW, True))]) bg = RunLengthList([(0, bg_code(GREEN))]) if self.shield: bg.add_change(0, bg_code(RED)) else: bg.add_change(0, bg_code(GREEN)) first_separator = line.find('|') if self.aura: bg.add_change(first_separator + 1, RED) else: bg.add_change(first_separator + 1, GREEN) second_separator = line.find('|', first_separator + 1) if self.barrier: bg.add_change(second_separator + 1, RED) else: bg.add_change(second_separator + 1, GREEN) ml = Metaline(line, fg, bg) return ml
class OutputView(DisplayView): """The display for all the text received from the MUD.""" def __init__(self, gui): DisplayView.__init__(self) #the identity of the return value of get_buffer() doesn't seem to be #stable. before, we used a property, but now we just get it once and #leave it at that because GTK complains about the non-identicality #of them. self.gui = gui self.paused = False self.end_mark = self.buffer.create_mark('end_mark', self.buffer.get_end_iter(), False) self.timestamps = RunLengthList({}) self.connect('focus-in-event', self.got_focus_cb) self.set_property("has-tooltip", True) self.connect("query-tooltip", self.display_tooltip_cb) def got_focus_cb(self, widget, event): """We never want focus; the command line automatically lets us have all incoming keypresses that we're interested in. """ self.gui.command_line.grab_focus() def display_tooltip_cb(self, widget, wx, wy, keyboard_mode, tooltip): """Display a timestamp for the line the user hovers over.""" #XXX: I'm not sure this is converting between coordinates right, I #need to double-check the GTK docs. bx, by = self.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx, wy) textiter = self.get_iter_at_location(bx, by) #GTK is very keen for the above code to succeed, but really it's only #useful for us if there's a tooltip above a bit of text, as opposed #to the ENTIRE FREAKING WIDGET. So test to see if bx and by can #roundtrip in the character's pixel rectangle rect = self.get_iter_location(textiter) if not 0 <= bx - rect.x <= rect.width or \ not 0 <= by - rect.y <= rect.height: return False received_at = self.timestamps.get_at(textiter.get_offset()) tooltip.set_text(received_at.strftime("Received at: %H:%M:%S")) return True def pause(self): """Stop autoscrolling to new data.""" if not self.paused: self.paused = True self.gui.paused_label.set_markup("PAUSED") def unpause(self): """Restart autoscrolling to new data. This does not automatically scroll to the buffer's end. """ if self.paused: self.paused = False self.gui.paused_label.set_markup("") #scroll to the end of output self.scroll_mark_onscreen(self.end_mark) def show_metaline(self, metaline): """Write a span of text to the window using the colours defined in the other channels. This will autoscroll to the end if we are not paused. """ #bytes = metaline.line.encode('utf-8') #end_iter = self.buffer.get_end_iter() #offset = end_iter.get_offset() #self.buffer.insert(end_iter, bytes) #self.apply_colours(metaline.fores, offset, len(metaline.line)) #self.apply_colours(metaline.backs, offset, len(metaline.line)) offset=DisplayView.show_metaline(self, metaline) if not self.paused: self.scroll_mark_onscreen(self.end_mark) else: self.gui.paused_label.set_markup("<span foreground='#FFFFFF' " "background='#000000'>" "MORE - PAUSED</span>") #this is a bit naughty, we're bypassing the RLL's safety thingies #anyway, we need to store the offset that -begins- the chunk of text self.timestamps[offset] = datetime.now()
def test_add_change_works_on_top_of_existing_colour_definition(): rl = RunLengthList([(0, "foo"), (2, +20)]) rl.add_change(2, -20) # deliberately try and get it to the left assert rl.items() == [(0, "foo"), (2, -20)]
def metaLine(self): line="Shield|Aura|Barrier" fg=RunLengthList([(0, fg_code(YELLOW,True))]) bg=RunLengthList([(0, bg_code(GREEN))]) if self.shield: bg.add_change(0, bg_code(RED)) else: bg.add_change(0, bg_code(GREEN)) first_separator=line.find('|') if self.aura: bg.add_change(first_separator+1, RED) else: bg.add_change(first_separator+1, GREEN) second_separator=line.find('|',first_separator+1) if self.barrier: bg.add_change(second_separator+1, RED) else: bg.add_change(second_separator+1, GREEN) ml=Metaline(line, fg, bg) return ml
def test_RunLengthList_add_change_already_got_index(): c = RunLengthList([(0, "foo"), (3, "bar")]) c.add_change(3, "baz") assert c.items() == [(0, "foo"), (3, "baz")]