Ejemplo n.º 1
0
def main(args=None, locals_=None, banner=None, welcome_message=None):
    """
    banner is displayed directly after the version information.
    welcome_message is passed on to Repl and displayed in the statusbar.
    """
    translations.init()

    config, options, exec_args = bpargs.parse(args, (
        'curtsies options', None, [
            Option('--log', '-L', action='count',
                   help=_("log debug messages to bpython.log")),
            Option('--paste', '-p', action='store_true',
                   help=_("start by pasting lines of a file into session")),
            ]))
    if options.log is None:
        options.log = 0
    logging_levels = [logging.ERROR, logging.INFO, logging.DEBUG]
    level = logging_levels[min(len(logging_levels) - 1, options.log)]
    logging.getLogger('curtsies').setLevel(level)
    logging.getLogger('bpython').setLevel(level)
    if options.log:
        handler = logging.FileHandler(filename='bpython.log')
        logging.getLogger('curtsies').addHandler(handler)
        logging.getLogger('curtsies').propagate = False
        logging.getLogger('bpython').addHandler(handler)
        logging.getLogger('bpython').propagate = False

    interp = None
    paste = None
    if exec_args:
        if not options:
            raise ValueError("don't pass in exec_args without options")
        exit_value = ()
        if options.paste:
            paste = curtsies.events.PasteEvent()
            encoding = inspection.get_encoding_file(exec_args[0])
            with io.open(exec_args[0], encoding=encoding) as f:
                sourcecode = f.read()
            paste.events.extend(sourcecode)
        else:
            try:
                interp = Interp(locals=locals_)
                bpargs.exec_code(interp, exec_args)
            except SystemExit as e:
                exit_value = e.args
            if not options.interactive:
                return extract_exit_value(exit_value)
    else:
        # expected for interactive sessions (vanilla python does it)
        sys.path.insert(0, '')

    if not options.quiet:
        print(bpargs.version_banner())
    if banner is not None:
        print(banner)
    global repl
    repl = FullCurtsiesRepl(config, locals_, welcome_message, interp, paste)
    try:
        with repl.input_generator:
            with repl.window as win:
                with repl:
                    repl.height, repl.width = win.t.height, win.t.width
                    exit_value = repl.mainloop()
    except (SystemExitFromCodeGreenlet, SystemExit) as e:
        exit_value = e.args
    return extract_exit_value(exit_value)
def main(args=None, locals_=None, banner=None):
    translations.init()

    # TODO: maybe support displays other than raw_display?
    config, options, exec_args = bpargs.parse(args, (
            'Urwid options', None, [
                Option('--twisted', '-T', action='store_true',
                       help=_('Run twisted reactor.')),
                Option('--reactor', '-r',
                       help=_('Select specific reactor (see --help-reactors). '
                       'Implies --twisted.')),
                Option('--help-reactors', action='store_true',
                       help=_('List available reactors for -r.')),
                Option('--plugin', '-p',
                       help=_('twistd plugin to run (use twistd for a list). '
                       'Use "--" to pass further options to the plugin.')),
                Option('--server', '-s', type='int',
                       help=_('Port to run an eval server on (forces Twisted).')),
                ]))

    if options.help_reactors:
        try:
            from twisted.application import reactors
            # Stolen from twisted.application.app (twistd).
            for r in reactors.getReactorTypes():
                print('    %-4s\t%s' % (r.shortName, r.description))
        except ImportError:
            sys.stderr.write('No reactors are available. Please install '
                'twisted for reactor support.\n')
        return

    palette = [
        (name, COLORMAP[color.lower()], 'default',
         'bold' if color.isupper() else 'default')
        for name, color in iteritems(config.color_scheme)]
    palette.extend([
            ('bold ' + name, color + ',bold', background, monochrome)
            for name, color, background, monochrome in palette])

    if options.server or options.plugin:
        options.twisted = True

    if options.reactor:
        try:
            from twisted.application import reactors
        except ImportError:
            sys.stderr.write('No reactors are available. Please install '
                'twisted for reactor support.\n')
            return
        try:
            # XXX why does this not just return the reactor it installed?
            reactor = reactors.installReactor(options.reactor)
            if reactor is None:
                from twisted.internet import reactor
        except reactors.NoSuchReactor:
            sys.stderr.write('Reactor %s does not exist\n' % (
                    options.reactor,))
            return
        event_loop = TwistedEventLoop(reactor)
    elif options.twisted:
        try:
            from twisted.internet import reactor
        except ImportError:
            sys.stderr.write('No reactors are available. Please install '
                'twisted for reactor support.\n')
            return
        event_loop = TwistedEventLoop(reactor)
    else:
        # None, not urwid.SelectEventLoop(), to work with
        # screens that do not support external event loops.
        event_loop = None
    # TODO: there is also a glib event loop. Do we want that one?

    # __main__ construction from bpython.cli
    if locals_ is None:
        main_mod = sys.modules['__main__'] = ModuleType('__main__')
        locals_ = main_mod.__dict__

    if options.plugin:
        try:
            from twisted import plugin
            from twisted.application import service
        except ImportError:
            sys.stderr.write('No twisted plugins are available. Please install '
                'twisted for twisted plugin support.\n')
            return

        for plug in plugin.getPlugins(service.IServiceMaker):
            if plug.tapname == options.plugin:
                break
        else:
            sys.stderr.write('Plugin %s does not exist\n' % (options.plugin,))
            return
        plugopts = plug.options()
        plugopts.parseOptions(exec_args)
        serv = plug.makeService(plugopts)
        locals_['service'] = serv
        reactor.callWhenRunning(serv.startService)
        exec_args = []
    interpreter = repl.Interpreter(locals_, locale.getpreferredencoding())

    # This nabs sys.stdin/out via urwid.MainLoop
    myrepl = URWIDRepl(event_loop, palette, interpreter, config)

    if options.server:
        factory = EvalFactory(myrepl)
        reactor.listenTCP(options.server, factory, interface='127.0.0.1')

    if options.reactor:
        # Twisted sets a sigInt handler that stops the reactor unless
        # it sees a different custom signal handler.
        def sigint(*args):
            reactor.callFromThread(myrepl.keyboard_interrupt)
        signal.signal(signal.SIGINT, sigint)

    # Save stdin, stdout and stderr for later restoration
    orig_stdin = sys.stdin
    orig_stdout = sys.stdout
    orig_stderr = sys.stderr
    # urwid's screen start() and stop() calls currently hit sys.stdin
    # directly (via RealTerminal.tty_signal_keys), so start the screen
    # before swapping sys.std*, and swap them back before restoring
    # the screen. This also avoids crashes if our redirected sys.std*
    # are called before we get around to starting the mainloop
    # (urwid raises an exception if we try to draw to the screen
    # before starting it).
    def run_with_screen_before_mainloop():
        try:
            # Currently we just set this to None because I do not
            # expect code hitting stdin to work. For example: exit()
            # (not sys.exit, site.py's exit) tries to close sys.stdin,
            # which breaks urwid's shutdown. bpython.cli sets this to
            # a fake object that reads input through curses and
            # returns it. When using twisted I do not think we can do
            # that because sys.stdin.read and friends block, and we
            # cannot re-enter the reactor. If using urwid's own
            # mainloop we *might* be able to do something similar and
            # re-enter its mainloop.
            sys.stdin = None #FakeStdin(myrepl)
            sys.stdout = myrepl
            sys.stderr = myrepl

            myrepl.main_loop.set_alarm_in(0, start)

            while True:
                try:
                    myrepl.main_loop.run()
                except KeyboardInterrupt:
                    # HACK: if we run under a twisted mainloop this should
                    # never happen: we have a SIGINT handler set.
                    # If we use the urwid select-based loop we just restart
                    # that loop if interrupted, instead of trying to cook
                    # up an equivalent to reactor.callFromThread (which
                    # is what our Twisted sigint handler does)
                    myrepl.main_loop.set_alarm_in(
                        0, lambda *args: myrepl.keyboard_interrupt())
                    continue
                break

        finally:
            sys.stdin = orig_stdin
            sys.stderr = orig_stderr
            sys.stdout = orig_stdout

    # This needs more thought. What needs to happen inside the mainloop?
    def start(main_loop, user_data):
        if exec_args:
            bpargs.exec_code(interpreter, exec_args)
            if not options.interactive:
                raise urwid.ExitMainLoop()
        if not exec_args:
            sys.path.insert(0, '')
            # this is CLIRepl.startup inlined.
            filename = os.environ.get('PYTHONSTARTUP')
            if filename and os.path.isfile(filename):
                with open(filename, 'r') as f:
                    if py3:
                        interpreter.runsource(f.read(), filename, 'exec')
                    else:
                        interpreter.runsource(f.read(), filename, 'exec',
                                              encode=False)

        if banner is not None:
            myrepl.write(banner)
            myrepl.write('\n')
        myrepl.start()

        # This bypasses main_loop.set_alarm_in because we must *not*
        # hit the draw_screen call (it's unnecessary and slow).
        def run_find_coroutine():
            if find_coroutine():
                main_loop.event_loop.alarm(0, run_find_coroutine)

        run_find_coroutine()

    myrepl.main_loop.screen.run_wrapper(run_with_screen_before_mainloop)

    if config.flush_output and not options.quiet:
        sys.stdout.write(myrepl.getstdout())
    if hasattr(sys.stdout, "flush"):
        sys.stdout.flush()
    return repl.extract_exit_value(myrepl.exit_value)
Ejemplo n.º 3
0
def main(args=None):
    translations.init()

    gtk_options = (_('gtk-specific options'),
                   _("Options specific to bpython's Gtk+ front end"), [
                       optparse.Option('--socket-id',
                                       dest='socket_id',
                                       type='int',
                                       help=_('Embed bpython'))
                   ])
    config, options, exec_args = bpython.args.parse(args, gtk_options, True)

    interpreter = repl.Interpreter(None, getpreferredencoding())
    repl_widget = ReplWidget(interpreter, config)
    repl_widget.connect('exit-event', gtk.main_quit)

    gobject.idle_add(init_import_completion)

    if not exec_args:
        sys.path.insert(0, '')
        gobject.idle_add(repl_widget.startup)
    else:
        if options.interactive:
            gobject.idle_add(bpython.args.exec_code, interpreter, exec_args)
        else:
            bpython.args.exec_code(interpreter, exec_args)
            return 0

    sys.stderr = repl_widget
    sys.stdout = repl_widget

    if not options.socket_id:
        parent = gtk.Window()
        parent.connect('delete-event', lambda widget, event: gtk.main_quit())

        # branding
        # fix icon to be distributed and loaded from the correct path
        icon = gtk.gdk.pixbuf_new_from_file(
            os.path.join(os.path.dirname(__file__), 'logo.png'))

        parent.set_title('bpython')
        parent.set_icon(icon)
        parent.resize(600, 300)
    else:
        parent = gtk.Plug(options.socket_id)
        parent.connect('destroy', gtk.main_quit)

    container = gtk.VBox()
    parent.add(container)

    mb = gtk.MenuBar()
    filemenu = gtk.Menu()

    filem = gtk.MenuItem("File")
    filem.set_submenu(filemenu)

    save = gtk.ImageMenuItem(gtk.STOCK_SAVE)
    save.connect("activate", repl_widget.do_write2file)
    filemenu.append(save)

    pastebin = gtk.MenuItem("Pastebin")
    pastebin.connect("activate", repl_widget.do_paste)
    filemenu.append(pastebin)

    pastebin_partial = gtk.MenuItem(_("Pastebin selection"))
    pastebin_partial.connect("activate", repl_widget.do_partial_paste)
    filemenu.append(pastebin_partial)

    exit = gtk.ImageMenuItem(gtk.STOCK_QUIT)
    exit.connect("activate", gtk.main_quit)
    filemenu.append(exit)

    mb.append(filem)
    vbox = gtk.VBox(False, 2)
    vbox.pack_start(mb, False, False, 0)

    container.pack_start(vbox, expand=False)

    # read from config
    sw = gtk.ScrolledWindow()
    sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
    sw.add(repl_widget)
    container.add(sw)

    sb = repl_widget.interact.statusbar
    container.pack_end(sb, expand=False)

    parent.set_focus(repl_widget)
    parent.show_all()
    parent.connect('delete-event', lambda widget, event: gtk.main_quit())

    try:
        gtk.main()
    except KeyboardInterrupt:
        pass

    return repl.extract_exit_value(repl_widget.exit_value)
Ejemplo n.º 4
0
def main(args=None, locals_=None, banner=None, welcome_message=None):
    """
    banner is displayed directly after the version information.
    welcome_message is passed on to Repl and displayed in the statusbar.
    """
    translations.init()

    config, options, exec_args = bpargs.parse(
        args, ('curtsies options', None, [
            Option('--log',
                   '-L',
                   action='count',
                   help=_("log debug messages to bpython.log")),
            Option('--paste',
                   '-p',
                   action='store_true',
                   help=_("start by pasting lines of a file into session")),
        ]))
    if options.log is None:
        options.log = 0
    logging_levels = [logging.ERROR, logging.INFO, logging.DEBUG]
    level = logging_levels[min(len(logging_levels) - 1, options.log)]
    logging.getLogger('curtsies').setLevel(level)
    logging.getLogger('bpython').setLevel(level)
    if options.log:
        handler = logging.FileHandler(filename='bpython.log')
        logging.getLogger('curtsies').addHandler(handler)
        logging.getLogger('curtsies').propagate = False
        logging.getLogger('bpython').addHandler(handler)
        logging.getLogger('bpython').propagate = False

    interp = None
    paste = None
    if exec_args:
        if not options:
            raise ValueError("don't pass in exec_args without options")
        exit_value = ()
        if options.paste:
            paste = curtsies.events.PasteEvent()
            encoding = inspection.get_encoding_file(exec_args[0])
            with io.open(exec_args[0], encoding=encoding) as f:
                sourcecode = f.read()
            paste.events.extend(sourcecode)
        else:
            try:
                interp = Interp(locals=locals_)
                bpargs.exec_code(interp, exec_args)
            except SystemExit as e:
                exit_value = e.args
            if not options.interactive:
                return extract_exit_value(exit_value)
    else:
        # expected for interactive sessions (vanilla python does it)
        sys.path.insert(0, '')

    if not options.quiet:
        print(bpargs.version_banner())
    if banner is not None:
        print(banner)
    global repl
    repl = FullCurtsiesRepl(config, locals_, welcome_message, interp, paste)
    try:
        with repl.input_generator:
            with repl.window as win:
                with repl:
                    repl.height, repl.width = win.t.height, win.t.width
                    exit_value = repl.mainloop()
    except (SystemExitFromCodeGreenlet, SystemExit) as e:
        exit_value = e.args
    return extract_exit_value(exit_value)
Ejemplo n.º 5
0
def main(args=None, locals_=None, banner=None):
    translations.init()

    # TODO: maybe support displays other than raw_display?
    config, options, exec_args = bpargs.parse(args, ('Urwid options', None, [
        Option('--twisted',
               '-T',
               action='store_true',
               help=_('Run twisted reactor.')),
        Option('--reactor',
               '-r',
               help=_('Select specific reactor (see --help-reactors). '
                      'Implies --twisted.')),
        Option('--help-reactors',
               action='store_true',
               help=_('List available reactors for -r.')),
        Option('--plugin',
               '-p',
               help=_('twistd plugin to run (use twistd for a list). '
                      'Use "--" to pass further options to the plugin.')),
        Option('--server',
               '-s',
               type='int',
               help=_('Port to run an eval server on (forces Twisted).')),
    ]))

    if options.help_reactors:
        try:
            from twisted.application import reactors
            # Stolen from twisted.application.app (twistd).
            for r in reactors.getReactorTypes():
                print('    %-4s\t%s' % (r.shortName, r.description))
        except ImportError:
            sys.stderr.write('No reactors are available. Please install '
                             'twisted for reactor support.\n')
        return

    palette = [(name, COLORMAP[color.lower()], 'default',
                'bold' if color.isupper() else 'default')
               for name, color in config.color_scheme.items()]
    palette.extend([('bold ' + name, color + ',bold', background, monochrome)
                    for name, color, background, monochrome in palette])

    if options.server or options.plugin:
        options.twisted = True

    if options.reactor:
        try:
            from twisted.application import reactors
        except ImportError:
            sys.stderr.write('No reactors are available. Please install '
                             'twisted for reactor support.\n')
            return
        try:
            # XXX why does this not just return the reactor it installed?
            reactor = reactors.installReactor(options.reactor)
            if reactor is None:
                from twisted.internet import reactor
        except reactors.NoSuchReactor:
            sys.stderr.write('Reactor %s does not exist\n' %
                             (options.reactor, ))
            return
        event_loop = TwistedEventLoop(reactor)
    elif options.twisted:
        try:
            from twisted.internet import reactor
        except ImportError:
            sys.stderr.write('No reactors are available. Please install '
                             'twisted for reactor support.\n')
            return
        event_loop = TwistedEventLoop(reactor)
    else:
        # None, not urwid.SelectEventLoop(), to work with
        # screens that do not support external event loops.
        event_loop = None
    # TODO: there is also a glib event loop. Do we want that one?

    # __main__ construction from bpython.cli
    if locals_ is None:
        main_mod = sys.modules['__main__'] = ModuleType('__main__')
        locals_ = main_mod.__dict__

    if options.plugin:
        try:
            from twisted import plugin
            from twisted.application import service
        except ImportError:
            sys.stderr.write(
                'No twisted plugins are available. Please install '
                'twisted for twisted plugin support.\n')
            return

        for plug in plugin.getPlugins(service.IServiceMaker):
            if plug.tapname == options.plugin:
                break
        else:
            sys.stderr.write('Plugin %s does not exist\n' % (options.plugin, ))
            return
        plugopts = plug.options()
        plugopts.parseOptions(exec_args)
        serv = plug.makeService(plugopts)
        locals_['service'] = serv
        reactor.callWhenRunning(serv.startService)
        exec_args = []
    interpreter = repl.Interpreter(locals_, locale.getpreferredencoding())

    # This nabs sys.stdin/out via urwid.MainLoop
    myrepl = URWIDRepl(event_loop, palette, interpreter, config)

    if options.server:
        factory = EvalFactory(myrepl)
        reactor.listenTCP(options.server, factory, interface='127.0.0.1')

    if options.reactor:
        # Twisted sets a sigInt handler that stops the reactor unless
        # it sees a different custom signal handler.
        def sigint(*args):
            reactor.callFromThread(myrepl.keyboard_interrupt)

        signal.signal(signal.SIGINT, sigint)

    # Save stdin, stdout and stderr for later restoration
    orig_stdin = sys.stdin
    orig_stdout = sys.stdout
    orig_stderr = sys.stderr

    # urwid's screen start() and stop() calls currently hit sys.stdin
    # directly (via RealTerminal.tty_signal_keys), so start the screen
    # before swapping sys.std*, and swap them back before restoring
    # the screen. This also avoids crashes if our redirected sys.std*
    # are called before we get around to starting the mainloop
    # (urwid raises an exception if we try to draw to the screen
    # before starting it).
    def run_with_screen_before_mainloop():
        try:
            # Currently we just set this to None because I do not
            # expect code hitting stdin to work. For example: exit()
            # (not sys.exit, site.py's exit) tries to close sys.stdin,
            # which breaks urwid's shutdown. bpython.cli sets this to
            # a fake object that reads input through curses and
            # returns it. When using twisted I do not think we can do
            # that because sys.stdin.read and friends block, and we
            # cannot re-enter the reactor. If using urwid's own
            # mainloop we *might* be able to do something similar and
            # re-enter its mainloop.
            sys.stdin = None  #FakeStdin(myrepl)
            sys.stdout = myrepl
            sys.stderr = myrepl

            myrepl.main_loop.set_alarm_in(0, start)

            while True:
                try:
                    myrepl.main_loop.run()
                except KeyboardInterrupt:
                    # HACK: if we run under a twisted mainloop this should
                    # never happen: we have a SIGINT handler set.
                    # If we use the urwid select-based loop we just restart
                    # that loop if interrupted, instead of trying to cook
                    # up an equivalent to reactor.callFromThread (which
                    # is what our Twisted sigint handler does)
                    myrepl.main_loop.set_alarm_in(
                        0, lambda *args: myrepl.keyboard_interrupt())
                    continue
                break

        finally:
            sys.stdin = orig_stdin
            sys.stderr = orig_stderr
            sys.stdout = orig_stdout

    # This needs more thought. What needs to happen inside the mainloop?
    def start(main_loop, user_data):
        if exec_args:
            bpargs.exec_code(interpreter, exec_args)
            if not options.interactive:
                raise urwid.ExitMainLoop()
        if not exec_args:
            sys.path.insert(0, '')
            # this is CLIRepl.startup inlined.
            filename = os.environ.get('PYTHONSTARTUP')
            if filename and os.path.isfile(filename):
                with open(filename, 'r') as f:
                    if py3:
                        interpreter.runsource(f.read(), filename, 'exec')
                    else:
                        interpreter.runsource(f.read(),
                                              filename,
                                              'exec',
                                              encode=False)

        if banner is not None:
            repl.write(banner)
            repl.write('\n')
        myrepl.start()

        # This bypasses main_loop.set_alarm_in because we must *not*
        # hit the draw_screen call (it's unnecessary and slow).
        def run_find_coroutine():
            if find_coroutine():
                main_loop.event_loop.alarm(0, run_find_coroutine)

        run_find_coroutine()

    myrepl.main_loop.screen.run_wrapper(run_with_screen_before_mainloop)

    if config.flush_output and not options.quiet:
        sys.stdout.write(myrepl.getstdout())
    if hasattr(sys.stdout, "flush"):
        sys.stdout.flush()
    return repl.extract_exit_value(myrepl.exit_value)
Ejemplo n.º 6
0
#Input
edit = CommandEdit('> ')

#Master container
fill = urwid.Frame(myrepl.frame, menu)
myrepl.main_loop = PandaMainLoop(
    fill, palette, unhandled_input=myrepl.handle_input,
    event_loop=PandaEventLoop()
)

if config.flush_output and not options.quiet:
    sys.stdout.write(myrepl.getstdout())
if hasattr(sys.stdout, "flush"):
    sys.stdout.flush()
repl.extract_exit_value(myrepl.exit_value)


def run_with_screen_before_mainloop():
    sys.stdin = None  # FakeStdin(myrepl)
    sys.stdout = myrepl
    sys.stderr = myrepl

    myrepl.main_loop.set_alarm_in(0, start)
    '''try:
        # Currently we just set this to None because I do not
        # expect code hitting stdin to work. For example: exit()
        # (not sys.exit, site.py's exit) tries to close sys.stdin,
        # which breaks urwid's shutdown. bpython.cli sets this to
        # a fake object that reads input through curses and
        # returns it. When using twisted I do not think we can do
Ejemplo n.º 7
0
def main(args=None, locals_=None, banner=None):
    translations.init()

    config, options, exec_args = bpargs.parse(
        args, ('curtsies options', None, [
            Option('--log',
                   '-L',
                   action='count',
                   help=_("log debug messages to bpython.log")),
            Option('--paste',
                   '-p',
                   action='store_true',
                   help=_("start by pasting lines of a file into session")),
        ]))
    if options.log is None:
        options.log = 0
    logging_levels = [logging.ERROR, logging.INFO, logging.DEBUG]
    level = logging_levels[min(len(logging_levels) - 1, options.log)]
    logging.getLogger('curtsies').setLevel(level)
    logging.getLogger('bpython').setLevel(level)
    if options.log:
        handler = logging.FileHandler(filename='bpython.log')
        logging.getLogger('curtsies').addHandler(handler)
        logging.getLogger('curtsies').propagate = False
        logging.getLogger('bpython').addHandler(handler)
        logging.getLogger('bpython').propagate = False

    interp = None
    paste = None
    if exec_args:
        if not options:
            raise ValueError("don't pass in exec_args without options")
        exit_value = ()
        if options.paste:
            paste = curtsies.events.PasteEvent()
            encoding = inspection.get_encoding_file(exec_args[0])
            with io.open(exec_args[0], encoding=encoding) as f:
                sourcecode = f.read()
            paste.events.extend(sourcecode)
        else:
            try:
                interp = code.InteractiveInterpreter(locals=locals_)
                bpargs.exec_code(interp, exec_args)
            except SystemExit as e:
                exit_value = e.args
            if not options.interactive:
                return extract_exit_value(exit_value)
    else:
        # expected for interactive sessions (vanilla python does it)
        sys.path.insert(0, '')

    print(bpargs.version_banner())
    try:
        exit_value = mainloop(config,
                              locals_,
                              banner,
                              interp,
                              paste,
                              interactive=(not exec_args))
    except (SystemExitFromCodeGreenlet, SystemExit) as e:
        exit_value = e.args
    return extract_exit_value(exit_value)
Ejemplo n.º 8
0
def main(args=None):
    translations.init()

    gtk_options = (_('gtk-specific options'),
                   _("Options specific to bpython's Gtk+ front end"),
                   [optparse.Option('--socket-id', dest='socket_id',
                                    type='int', help=_('Embed bpython'))])
    config, options, exec_args = bpython.args.parse(args, gtk_options,
                                                    True)

    interpreter = repl.Interpreter(None, getpreferredencoding())
    repl_widget = ReplWidget(interpreter, config)
    repl_widget.connect('exit-event', gtk.main_quit)

    gobject.idle_add(init_import_completion)

    if not exec_args:
        sys.path.insert(0, '')
        gobject.idle_add(repl_widget.startup)
    else:
        if options.interactive:
            gobject.idle_add(bpython.args.exec_code, interpreter, exec_args)
        else:
            bpython.args.exec_code(interpreter, exec_args)
            return 0

    sys.stderr = repl_widget
    sys.stdout = repl_widget

    if not options.socket_id:
        parent = gtk.Window()
        parent.connect('delete-event', lambda widget, event: gtk.main_quit())

        # branding
        # fix icon to be distributed and loaded from the correct path
        icon = gtk.gdk.pixbuf_new_from_file(os.path.join(os.path.dirname(__file__),
                                                         'logo.png'))

        parent.set_title('bpython')
        parent.set_icon(icon)
        parent.resize(600, 300)
    else:
        parent = gtk.Plug(options.socket_id)
        parent.connect('destroy', gtk.main_quit)

    container = gtk.VBox()
    parent.add(container)

    mb = gtk.MenuBar()
    filemenu = gtk.Menu()

    filem = gtk.MenuItem("File")
    filem.set_submenu(filemenu)

    save = gtk.ImageMenuItem(gtk.STOCK_SAVE)
    save.connect("activate", repl_widget.do_write2file)
    filemenu.append(save)

    pastebin = gtk.MenuItem("Pastebin")
    pastebin.connect("activate", repl_widget.do_paste)
    filemenu.append(pastebin)

    pastebin_partial = gtk.MenuItem(_("Pastebin selection"))
    pastebin_partial.connect("activate", repl_widget.do_partial_paste)
    filemenu.append(pastebin_partial)

    exit = gtk.ImageMenuItem(gtk.STOCK_QUIT)
    exit.connect("activate", gtk.main_quit)
    filemenu.append(exit)

    mb.append(filem)
    vbox = gtk.VBox(False, 2)
    vbox.pack_start(mb, False, False, 0)

    container.pack_start(vbox, expand=False)

    # read from config
    sw = gtk.ScrolledWindow()
    sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
    sw.add(repl_widget)
    container.add(sw)

    sb = repl_widget.interact.statusbar
    container.pack_end(sb, expand=False)

    parent.set_focus(repl_widget)
    parent.show_all()
    parent.connect('delete-event', lambda widget, event: gtk.main_quit())

    try:
        gtk.main()
    except KeyboardInterrupt:
        pass

    return repl.extract_exit_value(repl_widget.exit_value)