Beispiel #1
0
def start_channel(source_name, modulename, serveraddr, start_type='channel'):

    # setup logging
    setup_logging(modulename)
    # setup logger for module
    logger = getLogger(modulename)

    logger = getLogger(__name__)

    logger.info("start_channel for %s", modulename)

    # change proccess title
    try:
        import setproctitle
        setproctitle.setproctitle('%s nvim-completion-manager' % modulename)
    except:
        pass

    try:

        # connect neovim and setup python environment
        nvim = setup_neovim(serveraddr)

        if start_type == 'core':

            import cm_core
            nvim.vars['_cm_channel_id'] = nvim.channel_id
            handler = cm_core.CoreHandler(nvim)
            logger.info('starting core, enter event loop')
            run_event_loop('core', logger, nvim, handler)

        elif start_type == 'channel':

            nvim.call('cm#_channel_started', source_name, nvim.channel_id)

            if sys.version_info.major == 2:
                # python2 doesn't support namespace package
                # use load_source as a workaround
                import imp
                file = modulename.replace('.', '/')
                exp = 'globpath(&rtp,"pythonx/%s.py",1)' % file
                path = nvim.eval(exp).strip()
                logger.info('python2 file path: %s, exp: %s', path, exp)
                m = imp.load_source(modulename, path)
            else:
                m = importlib.import_module(modulename)

            handler = m.Source(nvim)
            logger.info('handler created, entering event loop')
            run_event_loop('channel', logger, nvim, handler)

    except Exception as ex:
        logger.exception('Exception when running %s: %s', modulename, ex)
        exit(1)
    finally:
        # terminate here
        exit(0)
Beispiel #2
0
def start_and_run_channel(channel_type, serveraddr, source_name, modulename):

    # connect neovim and setup python environment
    nvim = setup_neovim(serveraddr)

    if channel_type == 'core':

        import cm_core
        handler = cm_core.CoreHandler(nvim)
        logger.info('starting core, enter event loop')

    elif channel_type == 'channel':

        if sys.version_info.major == 2:
            # python2 doesn't support namespace package
            # use load_source as a workaround
            import imp
            file = modulename.replace('.', '/')
            exp = 'globpath(&rtp,"pythonx/%s.py",1)' % file
            path = nvim.eval(exp).strip()
            logger.info('<%s> python2 file path: %s, exp: %s', source_name,
                        path, exp)
            m = imp.load_source(modulename, path)
            # the previous module load may be hacked before, by register_source
            if not hasattr(m, 'Source'):
                m = imp.reload(m)
        else:
            m = importlib.import_module(modulename)
            # the previous module load may be hacked before, by register_source
            if not hasattr(m, 'Source'):
                m = importlib.reload(m)

        handler = m.Source(nvim)
        nvim.call('cm#_channel_started',
                  source_name,
                  nvim.channel_id,
                  async=True)
        logger.info('<%s> handler created, entering event loop', source_name)

    handler.cm_running_ = False
    handler.cm_msgs_ = []

    def on_request(method, args):
        logger.error('method: %s not implemented, ignore this request', method)

    def on_notification(method, args):

        # A trick to get rid of the greenlet coroutine without using the
        # next_message API.
        handler.cm_msgs_.append((method, args))
        if handler.cm_running_:
            logger.info("delay notification handling, method[%s]", method)
            return

        handler.cm_running_ = True

        while handler.cm_msgs_:

            method, args = handler.cm_msgs_.pop(0)

            try:
                logger.debug('%s method: %s, args: %s', channel_type, method,
                             args)

                if channel_type == 'channel' and method == 'cm_refresh':
                    ctx = args[1]
                    # The refresh calculation may be heavy, and the notification queue
                    # may have outdated refresh events, it would be  meaningless to
                    # process these event
                    if nvim.call('cm#context_changed', ctx):
                        logger.info('context_changed, ignoring context: %s',
                                    ctx)
                        continue

                func = getattr(handler, method, None)
                if func is None:
                    logger.info(
                        'method: %s not implemented, ignore this message',
                        method)
                    continue

                func(*args)
                logger.debug('%s method %s completed', channel_type, method)
            except Exception as ex:
                logger.exception("Failed processing method: %s, args: %s",
                                 method, args)

        handler.cm_running_ = False

    def on_setup():
        on_notification('cm_setup', [])

    try:
        logger.info("<%s> entering event loop", source_name)
        # Use next_message is simpler, as a handler doesn't need to deal with
        # concurrent issue, but it has serious issue,
        # https://github.com/roxma/nvim-completion-manager/issues/35#issuecomment-284049103
        nvim.run_loop(on_request, on_notification, on_setup)
    except Exception as ex:
        logger.exception("nvim.run_loop failed, %s", ex)
    finally:
        # use at_exit to ensure the calling of cm_shutdown
        func = getattr(handler, 'cm_shutdown', None)
        if func:
            func()
        if channel_type == 'core':
            exit(0)