Skip to content

Commit 6054b16

Browse files
committed
Implemented highlighting of matching parentheses
1 parent 08c5b26 commit 6054b16

File tree

2 files changed

+80
-4
lines changed

2 files changed

+80
-4
lines changed

bpython/cli.py

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@
5656
from pygments import format
5757
from pygments.lexers import PythonLexer
5858
from pygments.token import Token
59-
from bpython.formatter import BPythonFormatter
60-
from itertools import chain
59+
from bpython.formatter import BPythonFormatter, Parenthesis
6160

6261
# This for import completion
6362
from bpython import importcompletion
@@ -352,6 +351,7 @@ def __init__(self, scr, interp, statusbar=None, idle=None):
352351
self.argspec = None
353352
self.s = ''
354353
self.inside_string = False
354+
self.highlighted_paren = None
355355
self.list_win_visible = False
356356
self._C = {}
357357
sys.stdin = FakeStdin(self)
@@ -1303,9 +1303,13 @@ def p_key(self):
13031303

13041304
elif self.c == 'KEY_LEFT': # Cursor Left
13051305
self.mvc(1)
1306+
# Redraw (as there might have been highlighted parens)
1307+
self.print_line(self.s)
13061308

13071309
elif self.c == 'KEY_RIGHT': # Cursor Right
13081310
self.mvc(-1)
1311+
# Redraw (as there might have been highlighted parens)
1312+
self.print_line(self.s)
13091313

13101314
elif self.c in ("KEY_HOME", '^A', chr(1)): # home or ^A
13111315
self.mvc(len(self.s) - self.cpos)
@@ -1442,6 +1446,8 @@ def lf(self):
14421446
self.inside_string = next_token_inside_string(self.s,
14431447
self.inside_string)
14441448

1449+
# Reprint the line (as there was maybe a highlighted paren in it)
1450+
self.print_line(self.s)
14451451
self.echo("\n")
14461452

14471453
def addstr(self, s):
@@ -1469,9 +1475,75 @@ def print_line(self, s, clr=False):
14691475
tokens = PythonLexer().get_tokens(self.inside_string + s)
14701476
token, value = tokens.next()
14711477
if token is Token.String.Doc:
1472-
tokens = chain([(Token.String, value[3:])], tokens)
1478+
tokens = [(Token.String, value[3:])] + list(tokens)
14731479
else:
1474-
tokens = PythonLexer().get_tokens(s)
1480+
tokens = list(PythonLexer().get_tokens(s))
1481+
# Highlight matching parentheses
1482+
def reprint_line(lineno, s, to_replace=[]):
1483+
if lineno < 0:
1484+
return
1485+
t = list(PythonLexer().get_tokens(s))
1486+
for (i, token) in to_replace:
1487+
t[i] = token
1488+
o = format(t, BPythonFormatter(OPTS.color_scheme))
1489+
self.scr.move(lineno, 4)
1490+
map(self.echo, o.split('\x04'))
1491+
if self.highlighted_paren:
1492+
# Clear previous highlighted paren
1493+
reprint_line(*self.highlighted_paren)
1494+
self.highlighted_paren = None
1495+
stack = list()
1496+
source = '\n'.join(self.buffer) + '\n%s' % (s, )
1497+
i = line = 0
1498+
pos = 3
1499+
y, x = self.scr.getyx()
1500+
for (token, value) in PythonLexer().get_tokens(source):
1501+
pos += len(value)
1502+
under_cursor = (line == len(self.buffer) and pos == x)
1503+
if token is Token.Punctuation:
1504+
if value == '(':
1505+
if under_cursor:
1506+
tokens[i] = (Parenthesis, '(')
1507+
# Push marker on the stack
1508+
stack.append(Parenthesis)
1509+
else:
1510+
stack.append((line, i))
1511+
elif value == ')':
1512+
try:
1513+
value = stack.pop()
1514+
except IndexError:
1515+
# SyntaxError.. more closed parentheses than
1516+
# opened
1517+
break
1518+
if value is Parenthesis:
1519+
# Marker found
1520+
tokens[i] = (Parenthesis, ')')
1521+
break
1522+
elif under_cursor:
1523+
tokens[i] = (Parenthesis, ')')
1524+
(line, i) = value
1525+
screen_line = y - len(self.buffer) + line
1526+
if line == len(self.buffer):
1527+
self.highlighted_paren = (screen_line, s)
1528+
tokens[i] = (Parenthesis, '(')
1529+
else:
1530+
self.highlighted_paren = (screen_line,
1531+
self.buffer[line])
1532+
# We need to redraw a line
1533+
reprint_line(
1534+
screen_line,
1535+
self.buffer[line],
1536+
[(i, (Parenthesis, '('))]
1537+
)
1538+
elif under_cursor:
1539+
break
1540+
elif under_cursor:
1541+
break
1542+
elif token is Token.Text and value == '\n':
1543+
line += 1
1544+
i = -1
1545+
pos = 3
1546+
i += 1
14751547
o = format(tokens, BPythonFormatter(OPTS.color_scheme))
14761548
else:
14771549
o = s

bpython/formatter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
5353
"""
5454

55+
Parenthesis = Token.Punctuation.Parenthesis
56+
5557
f_strings = {
5658
Keyword: "\x01y",
5759
Name: "\x01w\x02",
@@ -64,6 +66,7 @@
6466
Number: "\x01g",
6567
Operator: "\x01c\x02",
6668
Operator.Word: "\x01c\x02",
69+
Parenthesis: "\x01r\x02",
6770
Punctuation: "\x01c\x02",
6871
Generic: "\x01d",
6972
Token: "\x01g",
@@ -82,6 +85,7 @@
8285
Number: "\x01g",
8386
Operator: "\x01b\x02",
8487
Operator.Word: "\x01k\x02",
88+
Parenthesis: "\x01r\x02",
8589
Punctuation: "\x01b\x02",
8690
Generic: "\x01d",
8791
Token: "\x01r\x02",

0 commit comments

Comments
 (0)