Skip to content

Commit 2277f12

Browse files
author
Jonathan Plasse
committed
Fix replace for partial selection
1 parent 400a8d2 commit 2277f12

File tree

1 file changed

+29
-14
lines changed

1 file changed

+29
-14
lines changed

src/textual/widgets/_masked_input.py

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def insert_separators(self, value: str, cursor_position: int) -> tuple[str, int]
200200
cursor_position += 1
201201
return value, cursor_position
202202

203-
def insert_text_at_cursor(self, text: str) -> tuple[str, int] | None:
203+
def insert_text_at_cursor(self, text: str, value: str, cursor_position: int) -> tuple[str, int] | None:
204204
"""Inserts `text` at current cursor position. If not present in `text`, any expected separator is automatically
205205
inserted at the correct position.
206206
@@ -211,8 +211,6 @@ def insert_text_at_cursor(self, text: str) -> tuple[str, int] | None:
211211
A tuple in the form `(value, cursor_position)` with the new control value and current cursor position if
212212
`text` matches the template, None otherwise.
213213
"""
214-
value = self.input.value
215-
cursor_position = self.input.cursor_position
216214
separators = set(
217215
[
218216
char_definition.char
@@ -612,7 +610,7 @@ def insert_text_at_cursor(self, text: str) -> None:
612610
text: New text to insert.
613611
"""
614612

615-
new_value = self._template.insert_text_at_cursor(text)
613+
new_value = self._template.insert_text_at_cursor(text, self.value, self.cursor_position)
616614
if new_value is not None:
617615
self.value, self.cursor_position = new_value
618616
else:
@@ -627,16 +625,33 @@ def replace(self, text: str, start: int, end: int):
627625
end: End index to replace (inclusive).
628626
"""
629627

630-
old_cursor_position = self.cursor_position
631-
self.cursor_position = start
632-
new_value = self._template.insert_text_at_cursor(text)
633-
if new_value is not None:
634-
value, cursor_position = new_value
635-
self.value = value[:cursor_position] + value[end:]
636-
self.cursor_position = cursor_position
637-
else:
638-
self.cursor_position = old_cursor_position
639-
self.restricted()
628+
previous_cursor_position = self.cursor_position
629+
value = self.value
630+
cursor_position = start
631+
for char in text:
632+
new_value_cursor_position = self._template.insert_text_at_cursor(char, value, cursor_position)
633+
if new_value_cursor_position is None:
634+
self.value = value
635+
self.cursor_position = previous_cursor_position
636+
self.restricted()
637+
return
638+
639+
new_value, new_cursor_position = new_value_cursor_position
640+
if new_cursor_position >= end:
641+
self.value = new_value[:end] + value[end:]
642+
self.cursor_position = new_cursor_position
643+
return
644+
645+
value = new_value
646+
cursor_position = new_cursor_position
647+
648+
self.value = value
649+
self.cursor_position = end
650+
while self.cursor_position > cursor_position:
651+
self._template.move_cursor(-1)
652+
self._template.delete_at_position()
653+
654+
self.cursor_position = cursor_position
640655

641656
def clear(self) -> None:
642657
"""Clear the masked input."""

0 commit comments

Comments
 (0)