Skip to content

Commit fb7adc5

Browse files
committed
reuse _pyrepl.utils.gen_colors to determine whether to indent
1 parent df35507 commit fb7adc5

File tree

2 files changed

+17
-89
lines changed

2 files changed

+17
-89
lines changed

Lib/_pyrepl/readline.py

Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from .completing_reader import CompletingReader
4141
from .console import Console as ConsoleType
4242
from ._module_completer import ModuleCompleter, make_default_module_completer
43+
from .utils import gen_colors
4344

4445
Console: type[ConsoleType]
4546
_error: tuple[type[Exception], ...] | type[Exception]
@@ -251,57 +252,23 @@ def _get_first_indentation(buffer: list[str]) -> str | None:
251252
return ''.join(buffer[indented_line_start : i])
252253
return None
253254

254-
255255
def _should_auto_indent(buffer: list[str], pos: int) -> bool:
256-
# check if last character before "pos" is a colon, ignoring
257-
# whitespaces and comments.
258-
last_char = None
259-
# A stack to keep track of string delimiters. Push a quote when entering a
260-
# string, pop it when the string ends. If the stack is empty, we're not
261-
# inside a string. When see a '#', it's a comment start if we're not inside
262-
# a string; otherwise, it's just a '#' character within a string.
263-
str_delims: list[str] = []
264-
in_comment = False
265-
char_line_indent_start = None
266-
char_line_indent = 0
267-
lastchar_line_indent = 0
268-
cursor_line_indent = 0
269-
270-
i = -1
271-
while i < pos - 1:
272-
i += 1
273-
char = buffer[i]
274-
275-
# update last_char
276-
if char == "#":
277-
if str_delims:
278-
last_char = char # '#' inside a string is just a character
279-
else:
280-
in_comment = True
281-
elif char == "\n":
282-
# newline ends a comment
283-
in_comment = False
284-
if i < pos - 1 and buffer[i + 1] in " \t":
285-
char_line_indent_start = i + 1
286-
else:
287-
char_line_indent_start = None # clear last line's line_indent_start
288-
char_line_indent = 0
289-
elif char not in " \t":
290-
if char_line_indent_start is not None:
291-
char_line_indent = i - char_line_indent_start
292-
if not in_comment and not str_delims:
293-
# update last_char with non-whitespace chars outside comments and strings
294-
last_char = char
295-
lastchar_line_indent = char_line_indent
296-
297-
# update stack
298-
if char in "\"'" and (i == 0 or buffer[i - 1] != "\\"):
299-
if str_delims and str_delims[-1] == char:
300-
str_delims.pop()
301-
else:
302-
str_delims.append(char)
303-
cursor_line_indent = char_line_indent
304-
return last_char == ":" and cursor_line_indent <= lastchar_line_indent
256+
buffer_str = ''.join(buffer)
257+
colors = tuple(gen_colors(buffer_str))
258+
string_spans = tuple(c.span for c in colors if c.tag == "string")
259+
comment_spans = tuple(c.span for c in colors if c.tag == "comment")
260+
def in_span(i, spans):
261+
return any(s.start <= i <= s.end for s in spans)
262+
i = pos - 1
263+
while i >= 0:
264+
if buffer_str[i] in " \t\n":
265+
i -= 1
266+
continue
267+
if in_span(i, string_spans) or in_span(i, comment_spans):
268+
i -= 1
269+
continue
270+
break
271+
return i >= 0 and buffer_str[i] == ":"
305272

306273

307274
class maybe_accept(commands.Command):

Lib/test/test_pyrepl/test_pyrepl.py

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -593,25 +593,6 @@ def test_auto_indent_with_comment(self):
593593
output = multiline_input(reader)
594594
self.assertEqual(output, output_code)
595595

596-
# fmt: off
597-
events = code_to_events(
598-
"def f():\n"
599-
"# foo\n"
600-
"pass\n\n"
601-
)
602-
603-
output_code = (
604-
"def f():\n"
605-
" # foo\n"
606-
" pass\n"
607-
" "
608-
)
609-
# fmt: on
610-
611-
reader = self.prepare_reader(events)
612-
output = multiline_input(reader)
613-
self.assertEqual(output, output_code)
614-
615596
# fmt: off
616597
events = itertools.chain(
617598
code_to_events("def f():\n"),
@@ -703,26 +684,6 @@ def test_dont_indent_in_multiline_string(self):
703684
output = multiline_input(reader)
704685
self.assertEqual(output, output_code)
705686

706-
def test_dont_indent_already_indented(self):
707-
# fmt: off
708-
events = code_to_events(
709-
"def f():\n"
710-
"# foo\n"
711-
"pass\n\n"
712-
)
713-
714-
output_code = (
715-
"def f():\n"
716-
" # foo\n"
717-
" pass\n"
718-
" "
719-
)
720-
# fmt: on
721-
722-
reader = self.prepare_reader(events)
723-
output = multiline_input(reader)
724-
self.assertEqual(output, output_code)
725-
726687

727688
class TestPyReplOutput(ScreenEqualMixin, TestCase):
728689
def prepare_reader(self, events):

0 commit comments

Comments
 (0)