def background_completion(project, completion_id, basic_comps, temp_file, orig_file, temp_path, 
        view, cache, current_input, complete_offset, run_compiler_completion):
    hide_delay, show_delay = hxsettings.get_completion_delays()

    commas = current_input[2]
    macro_completion = current_input[4]

    
    view_id = view.id()
    
    comps = list(basic_comps) # make copy

    only_delayed = hxsettings.only_delayed_completions()

    timer = time.time()

    def in_main (ret_, err_):
        
        hints, comps_, status_, errors = get_completion_output(temp_file, orig_file, err_, commas)

        
        comps_ = [(t[0], t[1]) for t in comps_]
                
        log("background completion time: " + str(time.time() - timer))
        project.completion_context.set_errors(errors)
        highlight_errors( errors, view )

        
        hxtemp.remove_path(temp_path)
        comps.extend(comps_)

        
        if completion_id == project.completion_context.current_id:
            cache["output"] = (ret_,comps_,status_, hints)
            cache["input"] = current_input
        else:
            log("ignored completion")
        
        # do we still need this completion, or is it old
        has_new_comps = len(comps) > len(basic_comps)
        has_hints = len(hints) > 0
        if completion_id == project.completion_context.current_id and (has_new_comps or hxsettings.only_delayed_completions() or has_hints):
            
            project.completion_context.delayed.insert(view_id, (comps, hints))
            if only_delayed:
                log("trigger_auto_complete")
                trigger_manual_completion(view,macro_completion)
                #view.run_command('auto_complete', {'disable_auto_insert': True})
            else:
                view.run_command('hide_auto_complete')
                sublime.set_timeout(lambda : trigger_manual_completion(view,macro_completion), show_delay)
                #sublime.set_timeout(lambda : view.run_command('auto_complete', {'disable_auto_insert': True}), show_delay)
        else:
            log("ignore background completion")
        
        project.completion_context.running.delete(completion_id)
    def on_result(ret_, err_):
        # replace current completion workaround
        # delays are customizable with project settings
        sublime.set_timeout(lambda : in_main(ret_, err_), hide_delay if not only_delayed else 20)

    project.completion_context.running.insert(completion_id, (complete_offset, view.id()))
    project.completion_context.current_id = completion_id

    run_compiler_completion(on_result, True)
    def in_main (ret_, err_):
        
        hints, comps_, status_, errors = get_completion_output(temp_file, orig_file, err_, commas)

        
        comps_ = [(t[0], t[1]) for t in comps_]
                
        log("background completion time: " + str(time.time() - timer))
        project.completion_context.set_errors(errors)
        highlight_errors( errors, view )

        
        hxtemp.remove_path(temp_path)
        comps.extend(comps_)

        
        if completion_id == project.completion_context.current_id:
            cache["output"] = (ret_,comps_,status_, hints)
            cache["input"] = current_input
        else:
            log("ignored completion")
        
        # do we still need this completion, or is it old
        has_new_comps = len(comps) > len(basic_comps)
        has_hints = len(hints) > 0
        if completion_id == project.completion_context.current_id and (has_new_comps or hxsettings.only_delayed_completions() or has_hints):
            
            project.completion_context.delayed.insert(view_id, (comps, hints))
            if only_delayed:
                log("trigger_auto_complete")
                trigger_manual_completion(view,macro_completion)
                #view.run_command('auto_complete', {'disable_auto_insert': True})
            else:
                view.run_command('hide_auto_complete')
                sublime.set_timeout(lambda : trigger_manual_completion(view,macro_completion), show_delay)
                #sublime.set_timeout(lambda : view.run_command('auto_complete', {'disable_auto_insert': True}), show_delay)
        else:
            log("ignore background completion")
        
        project.completion_context.running.delete(completion_id)
def hx_normal_auto_complete(project, view, offset, build, cache):
    
    completion_id = time.time()
    last_completion_id = project.completion_context.current_id

    trigger = project.completion_context.get_and_delete_trigger(view)
    

    manual_completion = trigger is not TRIGGER_SUBLIME

    macro_completion = trigger is TRIGGER_MANUAL_MACRO


    src = view_tools.get_content(view)
    orig_file = view.file_name()
    src_dir = os.path.dirname(orig_file)
    
    

    #find actual autocompletable char.
    prev = src[offset-1]
    
    commas, complete_offset, toplevel_complete, is_new = get_completion_info(view, offset, src, prev)
    
    # autocompletion is triggered, but its already 
    # running as a background process, starting it
    # again would result in multiple queries for
    # the same view and src position
    if project.completion_context.running.exists(last_completion_id):
        o1, id1 = project.completion_context.running.get_or_default(last_completion_id, None)
        if (o1 == complete_offset and id1 == view.id()):
            log("cancel completion, same is running")
            return cancel_completion(view, False)


    

    complete_char = src[complete_offset-1]

    in_control_struct = control_struct.search( src[0:complete_offset] ) is not None

    on_demand = hxsettings.top_level_completions_on_demand()

    toplevel_complete = (toplevel_complete or complete_char in ":(," or in_control_struct) and not on_demand

    if (hxsettings.no_fuzzy_completion() and not manual_completion and not toplevel_complete):
        log("trigger manual -> cancel completion")
        trigger_manual_completion(view, macro_completion)
        
        return cancel_completion(view)

    offset_char = src[offset]
    

    if (offset_char == "\n" and prev == "." and src[offset-2] == "." and src[offset-3] != "."):
        log("iterator completion")
        return [(".\tint iterator", "..")]

    

    comps = []
    log("toplevel_complete:" + str(toplevel_complete))
    if is_new or toplevel_complete :
        all_comps = get_toplevel_completion( project, src , build.copy(), macro_completion, is_new )

        comps = filter_top_level_completions(offset_char, all_comps)
    else:
        log("comps_from_not_top_level")
        comps = []
    
    

    if is_new or (toplevel_complete and (in_control_struct or complete_char not in "(,"))  :
        log("comps_from_top_level_and_control_struct")
        return comps


    

    delayed = hxsettings.is_delayed_completion()

    
    
    comps1 = []
    status = ""

    offset = complete_offset

    current_input = create_completion_input_key(orig_file, offset, commas, src, macro_completion, complete_char)

    

    last_input = cache["input"]

    log("DELAYED COMPLETION: " + str(delayed))

    use_cache = use_completion_cache(last_input, current_input)

    hints = []

    if use_cache :
        log("use completions from cache")
        ret, comps1, status, hints = cache["output"]
    else :
        log("not use cache")
        if supported_compiler_completion_char(complete_char): 
            log(build)
            temp_path, temp_file = hxtemp.create_temp_path_and_file(build, orig_file, src)

            if temp_path is None or temp_file is None:
                # this should never happen, todo proper error message
                log("completion error")
                return []

            build.add_classpath(temp_path)
            display = temp_file + "@" + str(offset)
            def run_compiler_completion (cb, async):
                return get_compiler_completion( project, build, view, display, temp_file, orig_file , async, cb, macro_completion )
            if delayed:
                log("run delayed compiler completion")
                background_completion(project, completion_id, list(comps), temp_file, orig_file,temp_path,
                    view, cache, current_input, complete_offset, run_compiler_completion)
                
                ret, comps1, status, hints = "", [], "", []
            else:
                log("run normal compiler completion")
                ret0 = []
                err0 = []
                def cb(out1, err1):
                    ret0.append(out1)
                    err0.append(err1)
                run_compiler_completion(cb, False)
                ret = ret0[0]
                err = err0[0]
                
                hxtemp.remove_path(temp_path)
                hints, comps1, status, errors = get_completion_output(temp_file, orig_file, err, commas)
                comps1 = [(t[0], t[1]) for t in comps1]
                highlight_errors( errors, view )
        else:
            log("not supported completion char")
            ret, comps1, status, hints = "",[], "", []

    comps.extend(comps1)

    log("hints1:" + str(hints))
    
    if not delayed:
        cache["output"] = (ret,comps1,status, hints)
        cache["input"] = current_input
    

    if status != "":
        if len(comps) > 0 or len(hints > 0):
            log(status)
        else:
            hxpanel.default_panel().writeln( status )


    
    if not use_cache and delayed and hxsettings.only_delayed_completions():
        log("delayed is running: completion cancelled")
        return cancel_completion(view, True)
    
    comps = combine_hints_and_comps(comps, hints)

    log("completion end")
    return comps