Skip to content

Commit e6d27d9

Browse files
committed
Address review: rename bow_ws, move tests to TestReader, add tab support
- Rename bow_whitespace() to bow_ws() for shorter naming convention - Move tests from separate TestBowWhitespace class into TestReader - Add tab character to whitespace set (space, newline, tab) - Add test_bow_ws_with_tabs for tab handling - Fix link format to #146044 - Remove LLM-style long dashes from comments - Update NEWS wording per review
1 parent 99023b2 commit e6d27d9

4 files changed

Lines changed: 35 additions & 48 deletions

File tree

Lib/_pyrepl/commands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class unix_word_rubout(KillCommand):
169169
def do(self) -> None:
170170
r = self.reader
171171
for i in range(r.get_arg()):
172-
self.kill_range(r.bow_whitespace(), r.pos)
172+
self.kill_range(r.bow_ws(), r.pos)
173173

174174

175175
class kill_word(KillCommand):

Lib/_pyrepl/reader.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -417,19 +417,20 @@ def bow(self, p: int | None = None) -> int:
417417
p -= 1
418418
return p + 1
419419

420-
def bow_whitespace(self, p: int | None = None) -> int:
420+
def bow_ws(self, p: int | None = None) -> int:
421421
"""Return the 0-based index of the whitespace-delimited word break
422422
preceding p most immediately.
423423
424424
p defaults to self.pos; only whitespace is considered a word
425-
boundary, matching the behavior of unix-word-rubout in bash/readline."""
425+
boundary, matching the behavior of unix-word-rubout in bash/readline.
426+
See https://github.com/python/cpython/issues/146044"""
426427
if p is None:
427428
p = self.pos
428429
b = self.buffer
429430
p -= 1
430-
while p >= 0 and b[p] in (" ", "\n"):
431+
while p >= 0 and b[p] in " \n\t":
431432
p -= 1
432-
while p >= 0 and b[p] not in (" ", "\n"):
433+
while p >= 0 and b[p] not in " \n\t":
433434
p -= 1
434435
return p + 1
435436

Lib/test/test_pyrepl/test_reader.py

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,34 @@ def test_setpos_from_xy_for_non_printing_char(self):
358358
reader.setpos_from_xy(8, 0)
359359
self.assertEqual(reader.pos, 7)
360360

361+
def test_bow_ws_stops_at_whitespace(self):
362+
# See https://github.com/python/cpython/issues/146044
363+
reader = prepare_reader(prepare_console([]))
364+
reader.buffer = list("foo.bar baz")
365+
reader.pos = len(reader.buffer)
366+
self.assertEqual(reader.bow_ws(), 8)
367+
368+
def test_bow_ws_includes_punctuation_in_word(self):
369+
reader = prepare_reader(prepare_console([]))
370+
reader.buffer = list("foo.bar(baz) qux")
371+
reader.pos = 12
372+
self.assertEqual(reader.bow_ws(), 0)
373+
374+
def test_bow_vs_bow_ws(self):
375+
reader = prepare_reader(prepare_console([]))
376+
reader.buffer = list("foo.bar")
377+
reader.pos = len(reader.buffer)
378+
# bow() stops at '.' so we return the index of 'b' in "bar"
379+
self.assertEqual(reader.bow(), 4)
380+
# bow_ws() treats entire "foo.bar" as one word
381+
self.assertEqual(reader.bow_ws(), 0)
382+
383+
def test_bow_ws_with_tabs(self):
384+
reader = prepare_reader(prepare_console([]))
385+
reader.buffer = list("foo\tbar")
386+
reader.pos = len(reader.buffer)
387+
self.assertEqual(reader.bow_ws(), 4)
388+
361389
@force_colorized_test_class
362390
class TestReaderInColor(ScreenEqualMixin, TestCase):
363391
def test_syntax_highlighting_basic(self):
@@ -560,45 +588,3 @@ def test_control_characters(self):
560588
self.assert_screen_equal(reader, 'flag {o}={z} {s}"🏳️\\u200d🌈"{z}'.format(**colors))
561589

562590

563-
class TestBowWhitespace(TestCase):
564-
def test_bow_whitespace_stops_at_whitespace(self):
565-
# GH#146044
566-
# unix-word-rubout (ctrl-w) should use whitespace boundaries,
567-
# not punctuation boundaries like bow() does
568-
reader = prepare_reader(prepare_console([]))
569-
reader.buffer = list("foo.bar baz")
570-
reader.pos = len(reader.buffer) # cursor at end
571-
572-
# bow_whitespace from end should jump to start of "baz"
573-
result = reader.bow_whitespace()
574-
self.assertEqual(result, 8) # index of 'b' in "baz"
575-
576-
def test_bow_whitespace_includes_punctuation_in_word(self):
577-
# GH#146044
578-
reader = prepare_reader(prepare_console([]))
579-
reader.buffer = list("foo.bar(baz) qux")
580-
reader.pos = 12 # cursor after ")"
581-
582-
# bow_whitespace should treat "foo.bar(baz)" as one word
583-
result = reader.bow_whitespace()
584-
self.assertEqual(result, 0)
585-
586-
def test_bow_stops_at_punctuation(self):
587-
# Verify existing bow() still uses syntax_table (punctuation boundary)
588-
reader = prepare_reader(prepare_console([]))
589-
reader.buffer = list("foo.bar baz")
590-
reader.pos = len(reader.buffer)
591-
592-
result = reader.bow()
593-
self.assertEqual(result, 8) # same — "baz" is all word chars
594-
595-
def test_bow_vs_bow_whitespace_difference(self):
596-
# The key difference: bow() stops at '.', bow_whitespace() does not
597-
reader = prepare_reader(prepare_console([]))
598-
reader.buffer = list("foo.bar")
599-
reader.pos = len(reader.buffer)
600-
601-
# bow() stops at '.' → returns index of 'b' in "bar"
602-
self.assertEqual(reader.bow(), 4)
603-
# bow_whitespace() treats entire "foo.bar" as one word
604-
self.assertEqual(reader.bow_whitespace(), 0)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Fix ``unix-word-rubout`` (Ctrl-W) in the REPL to use whitespace-only word
2-
boundaries, matching bash/readline behavior. Previously it used
2+
boundaries, matching behavior of the basic REPL. Previously it used
33
syntax-table boundaries which treated punctuation as word separators.

0 commit comments

Comments
 (0)