| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,9 +6,8 @@ bpython is written and maintained by Bob Farrell and Andreas Stuehrk | |||
| 6 | 6 | Other contributors are (in alphabetical order): | |
| 7 | 7 | ||
| 8 | 8 | * Federico Ceratto <federico dot ceratto at gmail dot com> | |
| 9 | - * Łukasz Langa <lukasz at langa dot pl> | ||
| 10 | 9 | * Pavel Panchekha <pavpanchekha at gmail dot com> | |
| 11 | 10 | * Simon de Vlieger <simon at ikanobori dot jp> | |
| 12 | - | ||
| 11 | + * Marien Zwart <marien dot zwart at gmail dot com> | ||
| 13 | 12 | ||
| 14 | 13 | Many thanks for all contributions! | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,3 +22,7 @@ bpython.gtk_ | |||
| 22 | 22 | ||
| 23 | 23 | common | |
| 24 | 24 | - test suite | |
| 25 | + | ||
| 26 | + v1.0 | ||
| 27 | + ---- | ||
| 28 | + - Ditch curses for an urwid/twisted loop | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,7 @@ | |||
| 1 | + bpython.gtk_ | ||
| 2 | + - make font configurable (pango.FontDescription) | ||
| 3 | + - make gtk have a seperate config/theme from the cli version | ||
| 4 | + | ||
| 5 | + bpython.urwid | ||
| 6 | + | ||
| 7 | + bpython.cli | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,11 +7,20 @@ | |||
| 7 | 7 | import sys | |
| 8 | 8 | import code | |
| 9 | 9 | from optparse import OptionParser, OptionGroup | |
| 10 | - from itertools import takewhile | ||
| 11 | 10 | ||
| 12 | 11 | from bpython import __version__ | |
| 13 | 12 | from bpython.config import loadini, Struct, migrate_rc | |
| 14 | 13 | ||
| 14 | + | ||
| 15 | + class OptionParserFailed(ValueError): | ||
| 16 | + """Raised by the RaisingOptionParser for a bogus commandline.""" | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + class RaisingOptionParser(OptionParser): | ||
| 20 | + def error(self, msg): | ||
| 21 | + raise OptionParserFailed() | ||
| 22 | + | ||
| 23 | + | ||
| 15 | 24 | def parse(args, extras=None): | |
| 16 | 25 | """Receive an argument list - if None, use sys.argv - parse all args and | |
| 17 | 26 | take appropriate action. Also receive optional extra options: this should | |
@@ -39,10 +48,16 @@ def parse(args, extras=None): | |||
| 39 | 48 | if args is None: | |
| 40 | 49 | args = sys.argv[1:] | |
| 41 | 50 | ||
| 42 | - parser = OptionParser(usage='Usage: %prog [options] [file [args]]\n' | ||
| 43 | - 'NOTE: If bpython sees an argument it does ' | ||
| 44 | - 'not know, execution falls back to the ' | ||
| 45 | - 'regular Python interpreter.') | ||
| 51 | + parser = RaisingOptionParser( | ||
| 52 | + usage='Usage: %prog [options] [file [args]]\n' | ||
| 53 | + 'NOTE: If bpython sees an argument it does ' | ||
| 54 | + 'not know, execution falls back to the ' | ||
| 55 | + 'regular Python interpreter.') | ||
| 56 | + # This is not sufficient if bpython gains its own -m support | ||
| 57 | + # (instead of falling back to Python itself for that). | ||
| 58 | + # That's probably fixable though, for example by having that | ||
| 59 | + # option swallow all remaining arguments in a callback. | ||
| 60 | + parser.disable_interspersed_args() | ||
| 46 | 61 | parser.add_option('--config', '-c', default='~/.bpython/config', | |
| 47 | 62 | help='use CONFIG instead of default config file') | |
| 48 | 63 | parser.add_option('--interactive', '-i', action='store_true', | |
@@ -59,17 +74,11 @@ def parse(args, extras=None): | |||
| 59 | 74 | extras_group.add_option(option) | |
| 60 | 75 | parser.add_option_group(extras_group) | |
| 61 | 76 | ||
| 62 | - all_args = set(parser._short_opt.keys() + parser._long_opt.keys()) | ||
| 63 | - if args and not all_args.intersection(arg.split('=')[0] for arg in args): | ||
| 77 | + try: | ||
| 78 | + options, args = parser.parse_args(args) | ||
| 79 | + except OptionParserFailed: | ||
| 64 | 80 | # Just let Python handle this | |
| 65 | 81 | os.execv(sys.executable, [sys.executable] + args) | |
| 66 | - else: | ||
| 67 | - # Split args in bpython args and args for the executed file | ||
| 68 | - real_args = list(takewhile(lambda arg: arg.split('=')[0] in all_args, | ||
| 69 | - args)) | ||
| 70 | - exec_args = args[len(real_args):] | ||
| 71 | - | ||
| 72 | - options, args = parser.parse_args(real_args) | ||
| 73 | 82 | ||
| 74 | 83 | if options.version: | |
| 75 | 84 | print 'bpython version', __version__, | |
@@ -91,7 +100,7 @@ def parse(args, extras=None): | |||
| 91 | 100 | ||
| 92 | 101 | loadini(config, options.config) | |
| 93 | 102 | ||
| 94 | - return config, options, exec_args | ||
| 103 | + return config, options, args | ||
| 95 | 104 | ||
| 96 | 105 | def exec_code(interpreter, args): | |
| 97 | 106 | """ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -237,7 +237,7 @@ def make_colors(config): | |||
| 237 | 237 | class CLIRepl(Repl): | |
| 238 | 238 | ||
| 239 | 239 | def __init__(self, scr, interp, statusbar, config, idle=None): | |
| 240 | - Repl.__init__(self, interp, config, idle) | ||
| 240 | + Repl.__init__(self, interp, config) | ||
| 241 | 241 | interp.writetb = self.writetb | |
| 242 | 242 | self.scr = scr | |
| 243 | 243 | self.list_win = newwin(get_colpair(config, 'background'), 1, 1, 1, 1) | |
@@ -250,6 +250,7 @@ def __init__(self, scr, interp, statusbar, config, idle=None): | |||
| 250 | 250 | self.last_key_press = time.time() | |
| 251 | 251 | self.s = '' | |
| 252 | 252 | self.statusbar = statusbar | |
| 253 | + self.formatter = BPythonFormatter(config.color_scheme) | ||
| 253 | 254 | ||
| 254 | 255 | def addstr(self, s): | |
| 255 | 256 | """Add a string to the current input line and figure out | |
@@ -833,6 +834,10 @@ def p_key(self, key): | |||
| 833 | 834 | elif key == 'KEY_BTAB': | |
| 834 | 835 | return self.tab(back=True) | |
| 835 | 836 | ||
| 837 | + elif key in key_dispatch[config.suspend_key]: | ||
| 838 | + self.suspend() | ||
| 839 | + return '' | ||
| 840 | + | ||
| 836 | 841 | elif len(key) == 1 and not unicodedata.category(key) == 'Cc': | |
| 837 | 842 | self.addstr(key) | |
| 838 | 843 | self.print_line(self.s) | |
@@ -855,8 +860,7 @@ def print_line(self, s, clr=False, newline=False): | |||
| 855 | 860 | self.highlighted_paren = None | |
| 856 | 861 | ||
| 857 | 862 | if self.config.syntax and (not self.paste_mode or newline): | |
| 858 | - o = format(self.tokenize(s, newline), | ||
| 859 | - BPythonFormatter(self.config.color_scheme)) | ||
| 863 | + o = format(self.tokenize(s, newline), self.formatter) | ||
| 860 | 864 | else: | |
| 861 | 865 | o = s | |
| 862 | 866 | ||
@@ -1096,20 +1100,24 @@ def lsize(): | |||
| 1096 | 1100 | if v_items: | |
| 1097 | 1101 | self.list_win.addstr('\n ') | |
| 1098 | 1102 | ||
| 1103 | + if not py3: | ||
| 1104 | + encoding = getpreferredencoding() | ||
| 1099 | 1105 | for ix, i in enumerate(v_items): | |
| 1100 | 1106 | padding = (wl - len(i)) * ' ' | |
| 1101 | 1107 | if i == current_item: | |
| 1102 | 1108 | color = get_colpair(self.config, 'operator') | |
| 1103 | 1109 | else: | |
| 1104 | 1110 | color = get_colpair(self.config, 'main') | |
| 1105 | 1111 | if not py3: | |
| 1106 | - i = i.encode(getpreferredencoding()) | ||
| 1112 | + i = i.encode(encoding) | ||
| 1107 | 1113 | self.list_win.addstr(i + padding, color) | |
| 1108 | 1114 | if ((cols == 1 or (ix and not (ix + 1) % cols)) | |
| 1109 | 1115 | and ix + 1 < len(v_items)): | |
| 1110 | 1116 | self.list_win.addstr('\n ') | |
| 1111 | 1117 | ||
| 1112 | 1118 | if self.docstring is not None: | |
| 1119 | + if not py3: | ||
| 1120 | + docstring_string = docstring_string.encode(encoding, 'ignore') | ||
| 1113 | 1121 | self.list_win.addstr('\n' + docstring_string, | |
| 1114 | 1122 | get_colpair(self.config, 'comment')) | |
| 1115 | 1123 | # XXX: After all the trouble I had with sizing the list box (I'm not very good | |
@@ -1142,6 +1150,11 @@ def size(self): | |||
| 1142 | 1150 | self.h = h - 1 | |
| 1143 | 1151 | self.x = 0 | |
| 1144 | 1152 | ||
| 1153 | + def suspend(self): | ||
| 1154 | + """Suspend the current process for shell job control.""" | ||
| 1155 | + curses.endwin() | ||
| 1156 | + os.kill(os.getpid(), signal.SIGSTOP) | ||
| 1157 | + | ||
| 1145 | 1158 | def tab(self, back=False): | |
| 1146 | 1159 | """Process the tab key being hit. If there's only whitespace | |
| 1147 | 1160 | in the line or the line is blank then process a normal tab, | |
@@ -1403,6 +1416,10 @@ def sigwinch(unused_scr): | |||
| 1403 | 1416 | global DO_RESIZE | |
| 1404 | 1417 | DO_RESIZE = True | |
| 1405 | 1418 | ||
| 1419 | + def sigcont(unused_scr): | ||
| 1420 | + sigwinch(unused_scr) | ||
| 1421 | + # Forces the redraw | ||
| 1422 | + curses.ungetch('') | ||
| 1406 | 1423 | ||
| 1407 | 1424 | def gethw(): | |
| 1408 | 1425 | """I found this code on a usenet post, and snipped out the bit I needed, | |
@@ -1522,9 +1539,10 @@ def main_curses(scr, args, config, interactive=True, locals_=None, | |||
| 1522 | 1539 | global colors | |
| 1523 | 1540 | DO_RESIZE = False | |
| 1524 | 1541 | ||
| 1525 | - # FIXME: Handle window resize without signals | ||
| 1526 | - #old_sigwinch_handler = signal.signal(signal.SIGWINCH, | ||
| 1527 | - # lambda *_: sigwinch(scr)) | ||
| 1542 | + old_sigwinch_handler = signal.signal(signal.SIGWINCH, | ||
| 1543 | + lambda *_: sigwinch(scr)) | ||
| 1544 | + # redraw window after being suspended | ||
| 1545 | + old_sigcont_handler = signal.signal(signal.SIGCONT, lambda *_: sigcont(scr)) | ||
| 1528 | 1546 | ||
| 1529 | 1547 | stdscr = scr | |
| 1530 | 1548 | try: | |
@@ -1577,9 +1595,9 @@ def main_curses(scr, args, config, interactive=True, locals_=None, | |||
| 1577 | 1595 | statusbar.win.refresh() | |
| 1578 | 1596 | curses.raw(False) | |
| 1579 | 1597 | ||
| 1580 | - # Restore SIGWINCH handler | ||
| 1581 | - # FIXME: handle window resizes without signals | ||
| 1582 | - # signal.signal(signal.SIGWINCH, old_sigwinch_handler) | ||
| 1598 | + # Restore signal handlers | ||
| 1599 | + signal.signal(signal.SIGWINCH, old_sigwinch_handler) | ||
| 1600 | + signal.signal(signal.SIGCONT, old_sigcont_handler) | ||
| 1583 | 1601 | ||
| 1584 | 1602 | return repl.getstdout() | |
| 1585 | 1603 | ||
@@ -1612,6 +1630,7 @@ def main(args=None, locals_=None, banner=None): | |||
| 1612 | 1630 | ||
| 1613 | 1631 | ||
| 1614 | 1632 | if __name__ == '__main__': | |
| 1633 | + from bpython.cli import main | ||
| 1615 | 1634 | main() | |
| 1616 | 1635 | ||
| 1617 | 1636 | # vim: sw=4 ts=4 sts=4 ai et | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -62,9 +62,12 @@ def loadini(struct, configfile): | |||
| 62 | 62 | 'pastebin': 'F8', | |
| 63 | 63 | 'save': 'C-s', | |
| 64 | 64 | 'show_source': 'F2', | |
| 65 | + 'suspend': 'C-z', | ||
| 65 | 66 | 'undo': 'C-r', | |
| 66 | 67 | 'up_one_line': 'C-p', | |
| 67 | - 'yank_from_buffer': 'C-y'}}) | ||
| 68 | + 'yank_from_buffer': 'C-y'}, | ||
| 69 | + 'gtk': { | ||
| 70 | + 'font': 'monospace 10'}}) | ||
| 68 | 71 | config.read(config_path) | |
| 69 | 72 | ||
| 70 | 73 | struct.dedent_after = config.getint('general', 'dedent_after') | |
@@ -82,6 +85,7 @@ def loadini(struct, configfile): | |||
| 82 | 85 | struct.pastebin_key = config.get('keyboard', 'pastebin') | |
| 83 | 86 | struct.save_key = config.get('keyboard', 'save') | |
| 84 | 87 | struct.show_source_key = config.get('keyboard', 'show_source') | |
| 88 | + struct.suspend_key = config.get('keyboard', 'suspend') | ||
| 85 | 89 | struct.undo_key = config.get('keyboard', 'undo') | |
| 86 | 90 | struct.up_one_line_key = config.get('keyboard', 'up_one_line') | |
| 87 | 91 | struct.down_one_line_key = config.get('keyboard', 'down_one_line') | |
@@ -99,6 +103,8 @@ def loadini(struct, configfile): | |||
| 99 | 103 | struct.pastebin_url = config.get('general', 'pastebin_url') | |
| 100 | 104 | struct.pastebin_show_url = config.get('general', 'pastebin_show_url') | |
| 101 | 105 | ||
| 106 | + struct.gtk_font = config.get('gtk', 'font') | ||
| 107 | + | ||
| 102 | 108 | color_scheme_name = config.get('general', 'color_scheme') | |
| 103 | 109 | ||
| 104 | 110 | default_colors = { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -83,16 +83,14 @@ class BPythonFormatter(Formatter): | |||
| 83 | 83 | See the Pygments source for more info; it's pretty | |
| 84 | 84 | straightforward.""" | |
| 85 | 85 | ||
| 86 | - f_strings = {} | ||
| 87 | - | ||
| 88 | 86 | def __init__(self, color_scheme, **options): | |
| 89 | - if not self.f_strings: | ||
| 90 | - for k, v in theme_map.iteritems(): | ||
| 91 | - self.f_strings[k] = '\x01%s' % (color_scheme[v],) | ||
| 92 | - if k is Parenthesis: | ||
| 93 | - # FIXME: Find a way to make this the inverse of the current | ||
| 94 | - # background colour | ||
| 95 | - self.f_strings[k] += 'I' | ||
| 87 | + self.f_strings = {} | ||
| 88 | + for k, v in theme_map.iteritems(): | ||
| 89 | + self.f_strings[k] = '\x01%s' % (color_scheme[v],) | ||
| 90 | + if k is Parenthesis: | ||
| 91 | + # FIXME: Find a way to make this the inverse of the current | ||
| 92 | + # background colour | ||
| 93 | + self.f_strings[k] += 'I' | ||
| 96 | 94 | Formatter.__init__(self, **options) | |
| 97 | 95 | ||
| 98 | 96 | def format(self, tokensource, outfile): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -260,7 +260,7 @@ def __init__(self, interpreter, config): | |||
| 260 | 260 | interpreter.writetb = self.writetb | |
| 261 | 261 | self.editing = Nested() | |
| 262 | 262 | self.reset_indent = False | |
| 263 | - self.modify_font(pango.FontDescription('terminus')) | ||
| 263 | + self.modify_font(pango.FontDescription(self.config.gtk_font)) | ||
| 264 | 264 | self.set_wrap_mode(gtk.WRAP_CHAR) | |
| 265 | 265 | self.list_win = SuggestionWindow() | |
| 266 | 266 | self.list_win.connect('selection-changed', | |
@@ -695,4 +695,5 @@ def main(args=None): | |||
| 695 | 695 | ||
| 696 | 696 | ||
| 697 | 697 | if __name__ == '__main__': | |
| 698 | + from bpython.gtk_ import main | ||
| 698 | 699 | main() | |
| Back | FazBrowse Home | New Git URL |
0 commit comments