def update_tree(self):
     cu.ed.set_prop(cu.PROP_CODETREE, False)
     cu.tree_proc(self.h_tree, cu.TREE_ITEM_DELETE, 0)
     lines = cu.ed.get_text_all().split("\n")
     last_levels = {0: 0}
     heads = list(gen_headers(lines))
     for index, (line_number, level, header) in enumerate(heads):
         for test_level in reversed(range(level)):
             parent = last_levels.get(test_level)
             if parent is None:
                 continue
             identity = cu.tree_proc(self.h_tree,
                                     cu.TREE_ITEM_ADD,
                                     parent,
                                     index=-1,
                                     text=header)
             # when adding level K, forget all levels > K
             last_levels = {
                 k: v
                 for k, v in last_levels.items() if k <= level
             }
             last_levels[level] = identity
             if index == len(heads) - 1:
                 end_y = len(lines) - 1
                 end_x = len(cu.ed.get_text_line(end_y))
             else:
                 end_y = heads[index + 1][0]  # line_index of next header
                 end_x = 0
             rng = (0, line_number, end_x, end_y)
             cu.tree_proc(self.h_tree,
                          cu.TREE_ITEM_SET_RANGE,
                          identity,
                          index=-1,
                          text=rng)
             break
예제 #2
0
    def update_tree(self, ed, lexer):
        getter = self.get_getter(lexer)
        if not getter: return

        filename = ed.get_filename()
        lines = ed.get_text_all().split("\n")
        heads = list(getter(filename, lines))

        ed.set_prop(app.PROP_CODETREE, False)
        app.tree_proc(self.h_tree, app.TREE_LOCK)
        app.tree_proc(self.h_tree, app.TREE_ITEM_DELETE, 0)
        last_levels = {0: 0}
        for index, data in enumerate(heads):
            pos = data[0]
            level = data[1]
            header = data[2]
            icon_index = data[3] if len(data) > 3 else -1

            for test_level in reversed(range(level)):
                parent = last_levels.get(test_level)
                if parent is None:
                    continue
                identity = app.tree_proc(self.h_tree,
                                         app.TREE_ITEM_ADD,
                                         parent,
                                         index=-1,
                                         text=header,
                                         image_index=icon_index)
                # when adding level K, forget all levels > K
                last_levels = {
                    k: v
                    for k, v in last_levels.items() if k <= level
                }
                last_levels[level] = identity

                if type(pos) == int:
                    if index == len(heads) - 1:
                        end_y = len(lines) - 1
                        s = ed.get_text_line(end_y)
                        if s is None:
                            end_x = 0
                        else:
                            end_x = len(s)
                    else:
                        end_y = heads[index +
                                      1][0]  # line_index of next header
                        end_x = 0
                    rng = (0, pos, end_x, end_y)
                else:
                    rng = pos

                app.tree_proc(self.h_tree,
                              app.TREE_ITEM_SET_RANGE,
                              identity,
                              index=-1,
                              text=rng)
                break

        app.tree_proc(self.h_tree, app.TREE_UNLOCK)
예제 #3
0
 def best_path(id_prnt, prnt_cap=''):
     rsp_l   = []
     kids    = app.tree_proc(ID_TREE, app.TREE_ITEM_ENUM, id_prnt)
     pass;                  #log('>>id_prnt, prnt_cap, kids={}',(id_prnt, prnt_cap, len(kids) if kids else 0))
     if kids is None:
         pass;              #log('<<no kids',())
         return [], INF
     row_bfr, kid_bfr, cap_bfr = -INF, NO_ID, ''
     row_aft, kid_aft, cap_aft = +INF, NO_ID, ''
     for kid, cap in kids:
         pass;              #log('kid, cap={}',(kid, cap))
         cMin, rMin, \
         cMax, rMax  = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_SYNTAX_RANGE , kid) \
                         if app.app_api_version() < '1.0.226' else \
                       app.tree_proc(ID_TREE, app.TREE_ITEM_GET_RANGE        , kid)
         pass;              #log('? kid,cap, rMin,rMax,row={}',(kid,cap, rMin,rMax,row))
         if False:pass
         elif rMin<=row<=rMax:   # Cover!
             sub_l, gap_sub  = best_path(kid, cap)
             pass;          #log('? sub_l, gap_sub={}',(sub_l, gap_sub))
             if gap_sub == 0:    # Sub-kid also covers
                 pass;      #log('+ sub_l={}',(sub_l))
                 rsp_l   = [(kid, cap)] + sub_l
             else:               # The kid is best
                 pass;      #log('0 ',())
                 rsp_l   = [(kid, cap)]
             pass;          #log('<<! rsp_l={}',(rsp_l))
             return rsp_l, 0
         elif row_bfr                  < rMax            < row:
             row_bfr, kid_bfr, cap_bfr = rMax, kid, cap
             pass;          #log('< row_bfr, kid_bfr, cap_bfr={}',(row_bfr, kid_bfr, cap_bfr))
         elif row_aft                  > rMin            > row:
             row_aft, kid_aft, cap_aft = rMin, kid, cap
             pass;          #log('> row_aft, kid_aft, cap_aft={}',(row_aft, kid_aft, cap_aft))
        #for kid
     pass;                  #log('? row_bfr, kid_bfr, cap_bfr={}',(row_bfr, kid_bfr, cap_bfr))
     pass;                  #log('? row_aft, kid_aft, cap_aft={}',(row_aft, kid_aft, cap_aft))
     pass;                  #log('? abs(row_bfr-row), abs(row_aft-row)={}',(abs(row_bfr-row), abs(row_aft-row)))
     kid_x, cap_x, gap_x = (kid_bfr, cap_bfr, row_bfr-row) \
                         if abs(row_bfr-row) <= abs(row_aft-row) else \
                           (kid_aft, cap_aft, row_aft-row)
     pass;                  #log('kid_x, cap_x, gap_x={}',(kid_x, cap_x, gap_x))
     sub_l, gap_sub  = best_path(kid_x, cap_x)
     pass;                  #log('? sub_l,gap_sub ?? gap_x={}',(sub_l, gap_sub, gap_x))
     if abs(gap_sub) <= abs(gap_x):  # Sub-kid better
         rsp_l  = [(kid_x, cap_x)] + sub_l
         pass;              #log('<<sub bt: rsp_l, gap_sub={}',(rsp_l, gap_sub))
         return rsp_l, gap_sub
     # The kid is best
     rsp_l   = [(kid_x, cap_x)]
     pass;                  #log('<<bst: rsp_l, gap_x={}',(rsp_l, gap_x))
     return rsp_l, gap_x
예제 #4
0
def tree_path_to_status():
    pass;                  #log('?',())
    path_l, gap = _get_best_tree_path(ed.get_carets()[0][1])
    if not path_l:  return
    ID_TREE = app.app_proc(app.PROC_SIDEPANEL_GET_CONTROL, 'Code tree')
    if not ID_TREE: return
    id_sel  = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_SELECTED)
    id_need = path_l[-1][0]
    if id_need != id_sel:
        app.tree_proc(ID_TREE, app.TREE_ITEM_SELECT, id_need)
    path    = '['+ '] / ['.join([cap.rstrip(':')[:40] for (nid,cap) in path_l]) + ']'
    return app.msg_status_alt(
        path if gap==0 else f('[{:+}] {}', -gap, path)
    , 10)
예제 #5
0
 def scan_tree(id_prnt, tree_nds, path_prnt):
     nonlocal tree_p
     kids            = app.tree_proc(ID_TREE, app.TREE_ITEM_ENUM, id_prnt)
     if kids is None:    return None
     for nid, cap in kids:
         path        = path_prnt + [cap]
         tree_p     += [(nid, cap, path)]
         sub         = scan_tree(nid, [], path)
     return tree_nds
예제 #6
0
 def do_find(ag, aid, data=''):
     nonlocal opts, tree_p, prev_wt, ready_l, ready_p
     # What/how/where will search
     what        = ag.val('what')
     if prev_wt==what and ready_l:
         return do_next(ag, 'next')
     prev_wt  = what
     pass;                  #log('what={}',(what)) if iflog(log4fun,_log4mod) else 0
     if not what:
         ready_l, ready_p    = [], -1
         return d(fid='what')
     opts['hist']= add_to_hist(what, opts['hist'])
     opts.update(ag.vals(['reex','case','word','wrap']))
     pass;                  #log('opts={}',(opts)) if iflog(log4fun,_log4mod) else 0
     tree_sid    = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_SELECTED)    # cur
     nodes       = tree_p                                                # To find from top
     if tree_sid and opts['clos']:                                       # To find from cur
         # Trick: [..,i,sid]+[j,..]   switch to   [j,..] or [j,..]+[..,i]  to search first after cur
         nids    = [nid for nid, cap, path in tree_p]
         pos     = nids.index(tree_sid)
         nodes   = tree_p[pos+1:] + (tree_p[:pos] if opts['wrap'] else [])
     # Search
     ready_l = []
     tree_ndn= -1
     try:
         pttn_r  = compile_pttn(what, opts['reex'], opts['case'], opts['word'])
     except:
         ready_er()
         return d(ctrls=[('what',d(items=opts['hist']))]
                 ,fid='what')
     for ndn, (nid, cap, path) in enumerate(nodes):
         if not pttn_r.search(cap):  continue
         if opts['clos']:
             select_node(nid)
             return None         # Close dlg
         ready_l+= [(nid, ' / '.join(path) if opts['fpth'] else cap, ndn)]
         tree_ndn= ndn if ndn==tree_sid else tree_ndn
     pass;                  #log('ready_l={}',(ready_l)) if iflog(log4fun,_log4mod) else 0
     ready_p = -1    if not ready_l  else \
               0     if not tree_sid else \
               first_true(enumerate(ready_l), 0, (lambda n_nid_cap_ndn: n_nid_cap_ndn[1][2]>tree_ndn))[0]
     pass;                  #log('ready_p={}',(ready_p)) if iflog(log4fun,_log4mod) else 0
     # Show results
     if ready_p!=-1:
         select_node(ready_l[ready_p][0])
         if opts['clos']:
             return None         # Close dlg
         ready_st()
     else:
         nfnd_st()
     return d(ctrls=[('what',d(items=opts['hist']))]
             ,fid='what')
예제 #7
0
 def tree_items_to_list(props=None, id_node=0, prefix='', more_levels=1000):
     '''Get all tree nodes to "props" starting from id_node (e.g. 0)'''
     props = [] if props is None else props 
     nodes = app.tree_proc(h_tree, app.TREE_ITEM_ENUM, id_node)
     if not nodes:
         nodes = app.tree_proc(h_tree, app.TREE_ITEM_ENUM, id_node)
         if not nodes:
             return 
     for id_kid, cap in nodes:
         prop    = app.tree_proc(h_tree, app.TREE_ITEM_GET_PROPS, id_kid)
         rng     = app.tree_proc(h_tree, app.TREE_ITEM_GET_RANGE, id_kid)
         subs    = prop['sub_items']
         if rng[0]>=0:
             prop['rng'] = rng
             prop['_t']  = f('{}{}\t{}'
                             , prefix
                             , prop['text']
                             , f('{}:{}', 1+rng[1], 1+rng[3]))
             props.append(prop)
         if subs and more_levels:
             # need items with sub_items too
             tree_items_to_list(props, id_kid, prefix+' '*4, more_levels-1)
     return props
예제 #8
0
def set_nearest_tree_node():
    path_l, gap = _get_best_tree_path(ed.get_carets()[0][1])
    if not path_l:  return
    ID_TREE = app.app_proc(app.PROC_SIDEPANEL_GET_CONTROL, 'Code tree')
    if not ID_TREE: return
    app.tree_proc(ID_TREE, app.TREE_ITEM_SELECT, path_l[-1][0])
예제 #9
0
 def select_node(nid):
     app.tree_proc(ID_TREE, app.TREE_ITEM_SELECT, nid)
     c_min, r_min,   \
     c_max, r_max    = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_RANGE, nid)
     ed.set_caret(c_min, r_min)
예제 #10
0
def find_tree_node():
    pass;                       log4fun=-1==-1  # Order log in the function
    HELP_C  = _('''
Search starts on Enter.
• A found node after current one will be selected.
• All found nodes are remembered and dialog can jump over them by [Shift+]Enter or by menu commands.
• If option "O" (wrapped search) is tuned on:
    - Search continues from the start, when end of the tree is reached
    - Jumps to previous/next nodes are looped too
• Option ".*" (regular expression) allows to use Python reg.ex. See "docs.python.org/3/library/re.html".
• Option "w" (whole words) is ignored if entered string contains not a word.
• If option "Close on success" (in menu) is tuned on, dialog will close after successful search.
• Option "Show full tree path" (in menu) shows in the statusbar the path of the found node (names of all parents).
• Command "Restore initial selection" (in menu) restores only first of initial carets.
    ''').strip()
    ed_crts = ed.get_carets()           # Carets at start
    opts    = d(reex=False,case=False,word=False,wrap=False,hist=[],clos=False,fpth=False)
    opts.update(get_hist('tree.find_node', opts))
    # Scan Tree
    ID_TREE = app.app_proc(app.PROC_SIDEPANEL_GET_CONTROL, 'Code tree')
    if not ID_TREE: return app.msg_status(_('No CodeTree'))
    if not app.tree_proc(ID_TREE, app.TREE_ITEM_ENUM, 0):   # 0 is root
        ed.cmd(cmds.cmd_TreeUpdate)                         # Try to build tree
    tree_t  = []        # [{nid:ID, sub:[{nid:ID, sub:{}, cap:'smth', path:['rt','smth']},], cap:'rt', path:[]},]
    tree_p  = []        # [,(ID, 'smth',['rt','smth']),]
    def scan_tree(id_prnt, tree_nds, path_prnt):
        nonlocal tree_p
        kids            = app.tree_proc(ID_TREE, app.TREE_ITEM_ENUM, id_prnt)
        if kids is None:    return None
        for nid, cap in kids:
            path        = path_prnt + [cap]
            tree_p     += [(nid, cap, path)]
            sub         = scan_tree(nid, [], path)
        return tree_nds
       #def scan_tree
    scan_tree(0, tree_t, [])    # 0 is root
    pass;                      #log('tree_t={}',pfrm100(tree_t)) if iflog(log4fun,_log4mod) else 0
    pass;                      #log('tree_p={}',pfrm100(tree_p)) if iflog(log4fun,_log4mod) else 0
        
    # How to select node
    def select_node(nid):
        app.tree_proc(ID_TREE, app.TREE_ITEM_SELECT, nid)
        c_min, r_min,   \
        c_max, r_max    = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_RANGE, nid)
        ed.set_caret(c_min, r_min)
       #def select_node
        
    # Ask
    MAX_HIST= apx.get_opt('ui_max_history_edits', 20)
    stbr    = None
    status  = lambda msg:  app.statusbar_proc(stbr, app.STATUSBAR_SET_CELL_TEXT, tag=1, value=msg)
    def add_to_hist(val, lst):
        """ Add/Move val to list head. """
        if val in lst:
            if 0 == lst.index(val):   return lst
            lst.remove(val)
        lst.insert(0, val)
        if len(lst)>MAX_HIST:
            del lst[MAX_HIST:]
        return lst
       #def add_to_hist
    compile_pttn= lambda    pttn_s, reex, case, word: re.compile(
                            pttn_s          if reex else
                      r'\b'+pttn_s+r'\b'    if word and re.match('^\w+$', pttn_s) else
                  re.escape(pttn_s)
                        ,   0 if case else re.I)
        
    prev_wt = None          # Prev what
    ready_l = []            # [(nid,cap|path,ndn)]
    ready_p = -1            # pos in ready_l
    nfnd_st = lambda: status(_('No suitable nodes'))
    ready_st= lambda: status(f('{pos}/{all}:  {cap}', pos=1+ready_p, all=len(ready_l), cap=ready_l[ready_p][1]))
    ready_er= lambda: status(_('Error'))
        
    def do_attr(ag, aid, data=''):
        nonlocal prev_wt
        prev_wt = ''
        return d(fid='what')
    
    def do_menu(ag, aid, data=''):
        def wnen_menu(ag, tag):
            nonlocal opts, prev_wt
            if   tag in ('prev','next'):    return do_next(ag, tag)
            if   tag in ('fpth','clos'):    prev_wt = '';   opts[tag] = not opts[tag]
            elif tag=='help':               app.msg_box(HELP_C, app.MB_OK)
            elif tag=='rest':               ed.set_caret(*ed_crts[0]);      return None
            return []
           #def wnen_menu
        
        ag.show_menu(
            [ d(    tag='help'  ,cap=_('&Help...')
            ),d(                 cap='-'
            ),d(    tag='prev'  ,cap=_('Find &previous')                                ,key='Shift+Enter'
            ),d(    tag='next'  ,cap=_('F&ind next')                                    ,key='Enter'
            ),d(                 cap='-'
            ),d(                 cap=_('&Options')  ,sub=
                [ d(tag='fpth'  ,cap=_('Show full tree path')   ,ch=opts['fpth']
                ),d(tag='clos'  ,cap=_('Close on success')      ,ch=opts['clos']
            )]),d(               cap='-'
            ),d(    tag='rest'  ,cap=_('Restore initial selection and close dialog &=') ,key='Shift+Esc'
            )]
        ,   aid
        ,   cmd4all=wnen_menu                                   # Set cmd=wnen_menu for all nodes
        )
        return d(fid='what')
       #def do_menu
    
    def do_next(ag, aid, data=''):
        if not ready_l:         return d(fid='what')
        nonlocal ready_p
        ready_n = ready_p + (-1 if aid=='prev' else 1)
        ready_n = ready_n % len(ready_l) if opts['wrap'] else max(0, min(len(ready_l)-1, ready_n), 0)
        pass;                  #log('ready_n,ready_p={}',(ready_n,ready_p)) if iflog(log4fun,_log4mod) else 0
        if ready_p == ready_n:  return d(fid='what')
        ready_p = ready_n
        ready_st()
        select_node(ready_l[ready_p][0])
        return d(fid='what')
       #def do_next
    
    def do_find(ag, aid, data=''):
        nonlocal opts, tree_p, prev_wt, ready_l, ready_p
        # What/how/where will search
        what        = ag.val('what')
        if prev_wt==what and ready_l:
            return do_next(ag, 'next')
        prev_wt  = what
        pass;                  #log('what={}',(what)) if iflog(log4fun,_log4mod) else 0
        if not what:
            ready_l, ready_p    = [], -1
            return d(fid='what')
        opts['hist']= add_to_hist(what, opts['hist'])
        opts.update(ag.vals(['reex','case','word','wrap']))
        pass;                  #log('opts={}',(opts)) if iflog(log4fun,_log4mod) else 0
        tree_sid    = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_SELECTED)    # cur
        nodes       = tree_p                                                # To find from top
        if tree_sid and opts['clos']:                                       # To find from cur
            # Trick: [..,i,sid]+[j,..]   switch to   [j,..] or [j,..]+[..,i]  to search first after cur
            nids    = [nid for nid, cap, path in tree_p]
            pos     = nids.index(tree_sid)
            nodes   = tree_p[pos+1:] + (tree_p[:pos] if opts['wrap'] else [])
        # Search
        ready_l = []
        tree_ndn= -1
        try:
            pttn_r  = compile_pttn(what, opts['reex'], opts['case'], opts['word'])
        except:
            ready_er()
            return d(ctrls=[('what',d(items=opts['hist']))]
                    ,fid='what')
        for ndn, (nid, cap, path) in enumerate(nodes):
            if not pttn_r.search(cap):  continue
            if opts['clos']:
                select_node(nid)
                return None         # Close dlg
            ready_l+= [(nid, ' / '.join(path) if opts['fpth'] else cap, ndn)]
            tree_ndn= ndn if ndn==tree_sid else tree_ndn
        pass;                  #log('ready_l={}',(ready_l)) if iflog(log4fun,_log4mod) else 0
        ready_p = -1    if not ready_l  else \
                  0     if not tree_sid else \
                  first_true(enumerate(ready_l), 0, (lambda n_nid_cap_ndn: n_nid_cap_ndn[1][2]>tree_ndn))[0]
        pass;                  #log('ready_p={}',(ready_p)) if iflog(log4fun,_log4mod) else 0
        # Show results
        if ready_p!=-1:
            select_node(ready_l[ready_p][0])
            if opts['clos']:
                return None         # Close dlg
            ready_st()
        else:
            nfnd_st()
        return d(ctrls=[('what',d(items=opts['hist']))]
                ,fid='what')
       #def do_find
    
    def do_key_down(ag, key, data=''):
        scam    = data if data else app.app_proc(app.PROC_GET_KEYSTATE, '')
        pass;                  #log('key,data,scam={}',(key,data,scam)) if iflog(log4fun,_log4mod) else 0
        if 0:pass
        elif (scam,key)==('s',VK_ENTER):        # Shift+Enter
            ag.update(do_next(ag, 'prev'))
        elif (scam,key)==('s',VK_ESCAPE):       # Shift+Esc
            ed.set_caret(*ed_crts[0])
            return None
        else: return [] # Nothing
        return False    # Stop event
       #def do_key_down
    
    ag      = DlgAg(
        form    =dict(cap=_('Find tree node'), w=365, h=58, h_max=58
                     ,on_key_down=do_key_down
                     ,border=app.DBORDER_TOOLSIZE
#                    ,resize=True
                     )
    ,   ctrls   =[0
  ,('find',d(tp='bttn',y=0          ,x=-99      ,w=44   ,cap=''     ,sto=False  ,def_bt=T           ,on=do_find         ))  # Enter
  ,('reex',d(tp='chbt',tid='what'   ,x=5+38*0   ,w=39   ,cap='.&*'  ,hint=_('Regular expression')   ,on=do_attr         ))  # &*
  ,('case',d(tp='chbt',tid='what'   ,x=5+38*1   ,w=39   ,cap='&aA'  ,hint=_('Case sensitive')       ,on=do_attr         ))  # &a
  ,('word',d(tp='chbt',tid='what'   ,x=5+38*2   ,w=39   ,cap='"&w"' ,hint=_('Whole words')          ,on=do_attr         ))  # &w
  ,('wrap',d(tp='chbt',tid='what'   ,x=5+38*3   ,w=39   ,cap='&O'   ,hint=_('Wrapped search')       ,on=do_attr         ))  # &/
  ,('what',d(tp='cmbx',y  =5        ,x=5+38*4+5 ,w=155  ,items=opts['hist']                                     ,a='r>' ))  # 
  ,('menu',d(tp='bttn',tid='what'   ,x=320      ,w=40   ,cap='&='                                   ,on=do_menu ,a='>>' ))  # &=
  ,('stbr',d(tp='stbr'              ,x=0        ,r=365                                  ,ali=ALI_BT             ,a='r>' ))  # 
                ][1:]
    ,   fid     ='what'
    ,   vals    = {k:opts[k] for k in ('reex','case','word','wrap')}
                          #,options={'gen_repro_to_file':'repro_dlg_find_tree_node.py'}
    )
    stbr    = ag.chandle('stbr')
    app.statusbar_proc(stbr, app.STATUSBAR_ADD_CELL             , tag=1)
    app.statusbar_proc(stbr, app.STATUSBAR_SET_CELL_AUTOSTRETCH , tag=1, value=True)
    ag.show(lambda ag: set_hist('tree.find_node', upd_dict(opts, ag.vals(['reex','case','word','wrap']))))