def subcode_recolorize_main(self): # monkey patch update to avoid flickering of subcode markers _update = self.update try: self.update = lambda: None ColorDelegator.recolorize_main(self) finally: self.update = _update # must restore update function item = self.tag_nextrange("TODO", '1.0') if item: self.update() return # colorizer didn't finish labeling MAYBESUBCODE, abort # colorize the MAYBESUBCODE as SUBCODE if it is, else comment next = "1.0" while True: item = self.tag_nextrange("MAYBESUBCODE", next) if not item: break # remove MAYBESUBCODE and replace with COMMENT head, tail = item self.tag_remove("MAYBESUBCODE", head, tail) self.tag_add("COMMENT", head, tail) chars = self.get(head, tail) #print 'consider', repr(chars) # tag multiline comments then subcode markers m = self.subcodeprog.search(chars) while m: value = m.groupdict()['SUBCODE'] if value: a, b = m.span("SUBCODE") start = head + "+%dc" % a stop = head + "+%dc" % b if not chars[:a].strip( ): # fix subtle bug for ## ## lines self.tag_remove("COMMENT", start, stop) self.tag_add("SUBCODE", start, stop) m = self.subcodeprog.search(chars, m.end()) next = tail self.update()
def subcode_recolorize_main(self): # monkey patch update to avoid flickering of subcode markers _update = self.update try: self.update = lambda:None ColorDelegator.recolorize_main(self) finally: self.update = _update # must restore update function item = self.tag_nextrange("TODO", '1.0') if item: self.update() return # colorizer didn't finish labeling MAYBESUBCODE, abort # colorize the MAYBESUBCODE as SUBCODE if it is, else comment next = "1.0" while True: item = self.tag_nextrange("MAYBESUBCODE", next) if not item: break # remove MAYBESUBCODE and replace with COMMENT head, tail = item self.tag_remove("MAYBESUBCODE", head, tail) self.tag_add("COMMENT", head, tail) chars = self.get(head, tail) #print 'consider', repr(chars) # tag multiline comments then subcode markers m = self.subcodeprog.search(chars) while m: value = m.groupdict()['SUBCODE'] if value: a, b = m.span("SUBCODE") start = head + "+%dc" % a stop = head + "+%dc" % b if not chars[:a].strip(): # fix subtle bug for ## ## lines self.tag_remove("COMMENT",start, stop) self.tag_add("SUBCODE", start, stop) m = self.subcodeprog.search(chars, m.end()) next = tail self.update()
class CodeBrowser: menudefs = [ ('edit', [None, ('Toggle Code _Browser', '<<toggle-classdefbrowser>>'), ]),] def __init__(self, editwin): self.editwin = editwin self.text = self.editwin.text self.text.bind('<<toggle-classdefbrowser>>', self.toggle_classdef) self.text.bind('<<toggle-keywordbrowser>>', self.toggle_keyword) #self.text.bind('<Button-1>', self.button_click, '+') self.browser_text = [] self.init_status_bar() self.hidden = True self.after_id = None def close(self): if self.after_id is not None: self.text.after_cancel(self.after_id) def init_status_bar(self): sb = self.editwin.status_bar sb.set_label('ClassDefBrowser', text="Code Browser") L = sb.labels['ClassDefBrowser'] L.bind('<Button-1>', self.toggle_classdef) L.bind('<Button-3>', self.toggle_keyword) ToolTip(L, "Click to Show Classes and Definitions in buffer") def font_timer_event(self): if self.hidden: return # taken from CodeContext.py newtextfont = self.editwin.text["font"] if self.textln and newtextfont != self.textfont: self.textfont = newtextfont self.textln["font"] = self.textfont self.after_id = self.text.after(FONTUPDATEINTERVAL, self.font_timer_event) def toggle_classdef(self, ev=None): tag_filter = {'KEYWORD': ['def', 'class']} self.text.after(1, lambda: self.toggle(tag_filter)) def toggle_keyword(self, ev=None): tag_filter = {'KEYWORD': ['def', 'class'], 'COMMENT': True} #self.toggle(tag_filter) self.text.after(1, lambda: self.toggle(tag_filter)) def toggle(self, tag_filter=None): if self.hidden: self.show(tag_filter) else: self.hide() def button_click(self, ev=None): print('button_click') # TODO - goto defintion on Ctrl+Click def show(self, tag_filter=None): if self.hidden == False: self.hide() return self.hidden = False # add a text widget, left of code text widget self.text_frame = text_frame = Frame(self.editwin.text_frame) self.vbar = vbar = Scrollbar(text_frame, name='vbar') vbar.pack(side=RIGHT, fill=Y) theme = idleConf.GetOption('main','Theme','name') normal_colors = idleConf.GetHighlight(theme, 'normal') text_options = { 'padx': 5, 'wrap': 'none', 'cursor': 'arrow', 'wrap': 'none', 'foreground':normal_colors['foreground'], 'background':normal_colors['background'], } self.textln = textln = Text(text_frame, **text_options) textln.pack(side='left',fill=BOTH, expand=YES) vbar['command'] = textln.yview textln['yscrollcommand'] = vbar.set # adjust font textln.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'), idleConf.GetOption('main', 'EditorWindow', 'font-size'))) textln.bind("<ButtonRelease>", self.focus_in_event) textln.bind("<Return>", self.enter_callback) textln.bind("<Escape>", self.escape_callback) textln.bind('<FocusOut>', self.focus_out, '+') # pass through keybindings for classdefbrowser keydefs = idleConf.GetExtensionBindings('CodeBrowser') for event, keylist in list(keydefs.items()): for k in keylist: def passthru(event, evName=event, text=self.text): text.event_generate(evName) try: textln.bind(k, passthru) except TclError as err: print(err) pass # start the line numbers self.per = per = Percolator(textln) self.color = ColorDelegator() self.per.insertfilter(self.color) self.line_delegator = LineDelegator() per.insertfilter(self.line_delegator) textln._insert = self.line_delegator.delegate.insert textln._delete = self.line_delegator.delegate.delete self.update_display(tag_filter) self.textfont = "" self.font_timer_event() self.nearest() text_frame.place(x=0, rely=1, relheight=1, relwidth=1, anchor=SW) text_frame.lift() def nearest(self): """ Enter ClassDefBrowser """ # scroll textln to the nearest keyword found in text text = self.text textln = self.textln text_insert, text_col = sp(text.index(INSERT)) text_end, col = sp(text.index(END)) text_end -= 1 text_top = (text.yview()[0] * text_end) text_bot = (text.yview()[1] * text_end) if text_top <= text_insert <= text_bot: pass else: text_insert = round((text_bot + text_top) / 2.0) for i in reversed(self.taglines): if i[0] <= text_insert: text_insert = i[0] break n = 0 for n, i in enumerate(self.taglines): if i[0] > text_insert: target_line = n break else: target_line = n + 1 textln.tag_add("NEAREST", '%i.0' % target_line, '%i.0' % (target_line+1)) theme = idleConf.GetOption('main','Theme','name') hilite = idleConf.GetHighlight(theme, "hilite") textln.tag_configure("NEAREST", **hilite) textln.tag_raise('NEAREST') # place cursor at beginning of line text tline = min(target_line-1, len(self.taglines)-1) if self.taglines: origline, txt = self.taglines[tline] text_col = txt.find(txt.strip()) textln.mark_set(INSERT, '%i.%i' % (target_line, text_col)) offset = text_insert - round(text_top) - 1 textln.yview(target_line - offset) textln.focus_set() def focus_out(self, ev=None): self.hide() def hide(self, event=None): if self.color: self.per.removefilter(self.color) self.text_frame.destroy() self.browser_text = None self.hidden = True self.text.focus_set() def enter_callback(self, ev=None): self.focus_in_event() def escape_callback(self, ev=None): self.hide() def focus_in_event(self, event=None): """ Leaves ClassDefBrowser, returns to source code.""" if self.hidden: return # don't leave on scroll wheel events if event and event.state != 256: # FIXME return t = self.textln line, col = list(map(int, t.index(INSERT).split('.'))) ind = line - TEXTOFFSET if 0 <= ind < len(self.taglines): L = self.taglines[ind][0] self.text.mark_set(INSERT, '%i.%i' % (L, col)) self.editwin.set_line_and_column() line_end, col_end = sp(self.textln.index(END)) d = self.textln.yview()[0] * line_end offset = L - line + round(d//1) + 1 text_end, col_end = sp(self.text.index(END)) self.text.yview(offset) self.hide() def nextrange(self, taglist, marker): text = self.text L = [] for tag in taglist: n = text.tag_nextrange(tag, marker) if n: L.append((sp(n[0]), sp(n[1]), tag)) if L: # find nearest range L.sort() line, col, tag = L[0] return (jn(*line), jn(*col)), tag else: return None, None def update_display(self, tag_filter=None): if self.hidden: return if tag_filter is None: tag_filter = {'KEYWORD': ['def', 'class'], 'COMMENT': True} text = self.text marker = "1.0" taglines = [] lastline = 0 lasttag = None while True: c, tag = self.nextrange(list(tag_filter.keys()), marker) if not c: break line, col = sp(c[0]) if line == lastline: #if tag == lasttag: marker = c[1] continue lastline = line lasttag == tag tagtxt = text.get(c[0], c[1]) filt = tag_filter[tag] if filt == True or tagtxt in filt: txt = text.get('%i.0' % line, '%i.0 lineend' % (line)) taglines.append((line, txt)) marker = c[1] textln = self.textln VIEW = textln.yview() text = self.editwin.text code_items = [] for n, i in enumerate(taglines): line, t = i code_items.append('%4i %s' % i) code_items.extend(['']*5) code_text = '\n'.join(code_items) if not code_text.strip(): code_text = '\nCode Browser found no classes or definitions.\nPress Escape to return to editing.' if self.browser_text != code_text: # check if I need to update the display, avoid flickering textln._delete(1.0, END) textln._insert(END, code_text) self.color.recolorize_main() self.browser_text = code_text self.taglines = taglines self.nearest()
def recolorize_main(self): self.tag_remove("TODO", "1.0", "iomark") self.tag_add("SYNC", "1.0", "iomark") ColorDelegator.recolorize_main(self)
def recolorize_main(self): self.tag_remove('TODO', '1.0', 'iomark') self.tag_add('SYNC', '1.0', 'iomark') ColorDelegator.recolorize_main(self)
class CodeBrowser: menudefs = [ ('edit', [ None, ('Toggle Code _Browser', '<<toggle-classdefbrowser>>'), ]), ] def __init__(self, editwin): self.editwin = editwin self.text = self.editwin.text self.text.bind('<<toggle-classdefbrowser>>', self.toggle_classdef) self.text.bind('<<toggle-keywordbrowser>>', self.toggle_keyword) #self.text.bind('<Button-1>', self.button_click, '+') self.browser_text = [] self.init_status_bar() self.hidden = True self.after_id = None def close(self): if self.after_id is not None: self.text.after_cancel(self.after_id) def init_status_bar(self): sb = self.editwin.status_bar sb.set_label('ClassDefBrowser', text="Code Browser") L = sb.labels['ClassDefBrowser'] L.bind('<Button-1>', self.toggle_classdef) L.bind('<Button-3>', self.toggle_keyword) ToolTip(L, "Click to Show Classes and Definitions in buffer") def font_timer_event(self): if self.hidden: return # taken from CodeContext.py newtextfont = self.editwin.text["font"] if self.textln and newtextfont != self.textfont: self.textfont = newtextfont self.textln["font"] = self.textfont self.after_id = self.text.after(FONTUPDATEINTERVAL, self.font_timer_event) def toggle_classdef(self, ev=None): tag_filter = {'KEYWORD': ['def', 'class']} self.text.after(1, lambda: self.toggle(tag_filter)) def toggle_keyword(self, ev=None): tag_filter = {'KEYWORD': ['def', 'class'], 'COMMENT': True} #self.toggle(tag_filter) self.text.after(1, lambda: self.toggle(tag_filter)) def toggle(self, tag_filter=None): if self.hidden: self.show(tag_filter) else: self.hide() def button_click(self, ev=None): print('button_click') # TODO - goto defintion on Ctrl+Click def show(self, tag_filter=None): if self.hidden == False: self.hide() return self.hidden = False # add a text widget, left of code text widget self.text_frame = text_frame = Frame(self.editwin.text_frame) self.vbar = vbar = Scrollbar(text_frame, name='vbar') vbar.pack(side=RIGHT, fill=Y) theme = idleConf.GetOption('main', 'Theme', 'name') normal_colors = idleConf.GetHighlight(theme, 'normal') text_options = { 'padx': 5, 'wrap': 'none', 'cursor': 'arrow', 'wrap': 'none', 'foreground': normal_colors['foreground'], 'background': normal_colors['background'], } self.textln = textln = Text(text_frame, **text_options) textln.pack(side='left', fill=BOTH, expand=YES) vbar['command'] = textln.yview textln['yscrollcommand'] = vbar.set # adjust font textln.config( font=(idleConf.GetOption('main', 'EditorWindow', 'font'), idleConf.GetOption('main', 'EditorWindow', 'font-size'))) textln.bind("<ButtonRelease>", self.focus_in_event) textln.bind("<Return>", self.enter_callback) textln.bind("<Escape>", self.escape_callback) textln.bind('<FocusOut>', self.focus_out, '+') # pass through keybindings for classdefbrowser keydefs = idleConf.GetExtensionBindings('CodeBrowser') for event, keylist in list(keydefs.items()): for k in keylist: def passthru(event, evName=event, text=self.text): text.event_generate(evName) try: textln.bind(k, passthru) except TclError as err: print(err) pass # start the line numbers self.per = per = Percolator(textln) self.color = ColorDelegator() self.per.insertfilter(self.color) self.line_delegator = LineDelegator() per.insertfilter(self.line_delegator) textln._insert = self.line_delegator.delegate.insert textln._delete = self.line_delegator.delegate.delete self.update_display(tag_filter) self.textfont = "" self.font_timer_event() self.nearest() text_frame.place(x=0, rely=1, relheight=1, relwidth=1, anchor=SW) text_frame.lift() def nearest(self): """ Enter ClassDefBrowser """ # scroll textln to the nearest keyword found in text text = self.text textln = self.textln text_insert, text_col = sp(text.index(INSERT)) text_end, col = sp(text.index(END)) text_end -= 1 text_top = (text.yview()[0] * text_end) text_bot = (text.yview()[1] * text_end) if text_top <= text_insert <= text_bot: pass else: text_insert = round((text_bot + text_top) / 2.0) for i in reversed(self.taglines): if i[0] <= text_insert: text_insert = i[0] break n = 0 for n, i in enumerate(self.taglines): if i[0] > text_insert: target_line = n break else: target_line = n + 1 textln.tag_add("NEAREST", '%i.0' % target_line, '%i.0' % (target_line + 1)) theme = idleConf.GetOption('main', 'Theme', 'name') hilite = idleConf.GetHighlight(theme, "hilite") textln.tag_configure("NEAREST", **hilite) textln.tag_raise('NEAREST') # place cursor at beginning of line text tline = min(target_line - 1, len(self.taglines) - 1) if self.taglines: origline, txt = self.taglines[tline] text_col = txt.find(txt.strip()) textln.mark_set(INSERT, '%i.%i' % (target_line, text_col)) offset = text_insert - round(text_top) - 1 textln.yview(target_line - offset) textln.focus_set() def focus_out(self, ev=None): self.hide() def hide(self, event=None): if self.color: self.per.removefilter(self.color) self.text_frame.destroy() self.browser_text = None self.hidden = True self.text.focus_set() def enter_callback(self, ev=None): self.focus_in_event() def escape_callback(self, ev=None): self.hide() def focus_in_event(self, event=None): """ Leaves ClassDefBrowser, returns to source code.""" if self.hidden: return # don't leave on scroll wheel events if event and event.state != 256: # FIXME return t = self.textln line, col = list(map(int, t.index(INSERT).split('.'))) ind = line - TEXTOFFSET if 0 <= ind < len(self.taglines): L = self.taglines[ind][0] self.text.mark_set(INSERT, '%i.%i' % (L, col)) self.editwin.set_line_and_column() line_end, col_end = sp(self.textln.index(END)) d = self.textln.yview()[0] * line_end offset = L - line + round(d // 1) + 1 text_end, col_end = sp(self.text.index(END)) self.text.yview(offset) self.hide() def nextrange(self, taglist, marker): text = self.text L = [] for tag in taglist: n = text.tag_nextrange(tag, marker) if n: L.append((sp(n[0]), sp(n[1]), tag)) if L: # find nearest range L.sort() line, col, tag = L[0] return (jn(*line), jn(*col)), tag else: return None, None def update_display(self, tag_filter=None): if self.hidden: return if tag_filter is None: tag_filter = {'KEYWORD': ['def', 'class'], 'COMMENT': True} text = self.text marker = "1.0" taglines = [] lastline = 0 lasttag = None while True: c, tag = self.nextrange(list(tag_filter.keys()), marker) if not c: break line, col = sp(c[0]) if line == lastline: #if tag == lasttag: marker = c[1] continue lastline = line lasttag == tag tagtxt = text.get(c[0], c[1]) filt = tag_filter[tag] if filt == True or tagtxt in filt: txt = text.get('%i.0' % line, '%i.0 lineend' % (line)) taglines.append((line, txt)) marker = c[1] textln = self.textln VIEW = textln.yview() text = self.editwin.text code_items = [] for n, i in enumerate(taglines): line, t = i code_items.append('%4i %s' % i) code_items.extend([''] * 5) code_text = '\n'.join(code_items) if not code_text.strip(): code_text = '\nCode Browser found no classes or definitions.\nPress Escape to return to editing.' if self.browser_text != code_text: # check if I need to update the display, avoid flickering textln._delete(1.0, END) textln._insert(END, code_text) self.color.recolorize_main() self.browser_text = code_text self.taglines = taglines self.nearest()
def recolorize_main(self): if not self.subcode_enable: return ColorDelegator.recolorize_main(self) else: return self.subcode_recolorize_main()