oleg-shilo / sublime-codemap

CodeMap - is a ST3 plugin for showing the code tree representing the code structure of the active view/document
MIT License
41 stars 4 forks source link

Update code_map.py - Added Logic Fix, Corrected 2 Rubberbanding problems, and removed un-needed lambda function and extra timed function call - with sync_map function named as synch_map #30

Closed Acecool closed 6 years ago

Acecool commented 6 years ago

Changelog:

Note: I could probably change the length of additional logic by simply comparing the VIEW_ID... VIEW_ID should be unique, even between windows ( but it may not - and since I'm not sure whether or not they change or reset between windows, I've opted for the other approach but depending how things go further along it may be something to look into because it'll enable us to remove the file-name comparison and the window check and simply change v == None to v != current_view ... We could actually get rid of the v == None check because if v is None then it'll be different from current_view anyway... so is streamlines the logic quite a bit )...

##
## Updated to include bug fix ( where ( v == None ) wasn't checked when go was called because ΔT has passed and the user could've closed the file. ). Prevented rubberbanding by making sure the same window was used ( so old window isn't refocused ) and make sure the same file is still being looked at ( to make sure the previous file isn't re-opened when the user switched from it - I could simply compare VIEW ID and then I don't need to look at window, etc.. so I may change from that ) - Acecool
##
def synch_map(v, give_back_focus=True):

    ## Grabs the active view from the active window and reads the filename from it...
    ## Note: We can do it this way, or use the view passed to the function - but we need to do it the former for the go function because v may have changed... For now we'll use v to grab the current file...
    ## last_current_file =  = sublime.active_window( ).active_view( ).file_name( )
    last_current_file = v.file_name( )
    last_window = sublime.active_window( )

    ## Allow go to be called - but cancel it if the file switched...
    def go():
        ## Since T time has passed - we relearn data that may have changed.. This includes looking at variables passed through our scope - v is the VIEW / file we're mapping... v could be None now so if it is, then there's no point in proceeding..
        if ( v == None ):
            return

        ## Grab the active window - again T time has passed so we need to relearn data that may have changed...
        current_window = sublime.active_window( )

        ## If the active window has changed, prevent the previous window from refocusing... No need to proceed if the window has changed...
        if ( current_window != last_window ):
            return

        ## Set the current file ( after the timeout ) for a comparison.. We don't use v because this is a function called after T time has passed and v will still be the same... We need to grab the active window, the active view within it, and the file-name of that view... If they have changed, we don't resync it..
        current_file = current_window.active_view( ).file_name( )

        ## If the current file isn't what the sync_map function was called with, then we do not allow sync_map to continue otherwise it'll cause rubberbanding back to a file we've lost interest in...
        if ( current_file != last_current_file ):
            return

        map_view = get_code_map_view()

        if map_view and map_view.size() > 0:
            code_view_line, _ = v.rowcol(v.sel()[0].a)
            prev_map_line = None

            lines = map_view.lines(Region(0, map_view.size()))

            entries = []
            index = 0
            for line in lines:
                link = map_view.substr(line).split(':')[-1]

                try:
                    entries.append((int(link), line))
                except:
                    continue

            entries.sort(key=lambda tup: tup[0])

            for member_line_num, line in entries:
                # added +1 so that it works for the first line of the function
                if member_line_num > code_view_line + 1:
                    break
                else:
                    prev_map_line = line

            map_view.sel().clear()
            if prev_map_line:
                map_view.sel().add(prev_map_line)
                map_view.show(prev_map_line.a)
                map_view.window().focus_view(map_view)

        ## Make the give back focus a part of go because it uses timeout anyway...
        if give_back_focus:
            win().focus_view(v)

    # apply a timeout to the whole function, add an additional timeout if it's
    # necessary to focus back to the original view - Acecool: But only if we haven't switched to a different file...
    sublime.set_timeout(go, 10)