When in password mode have word-oriented actions act on whole input

The idea here is that a password field should give no hint as to what's
within, length notwithstanding. To this end have the actions that (re)move
based on word boundaries act as if a password field is always just one word.

See #1692 (and previously #1676, prompted originally by #1310).
This commit is contained in:
Dave Pearson
2023-01-30 16:51:45 +00:00
parent aa03373a64
commit 12cfec7be3

View File

@@ -378,20 +378,32 @@ class Input(Widget, can_focus=True):
def action_cursor_left_word(self) -> None: def action_cursor_left_word(self) -> None:
"""Move the cursor left to the start of a word.""" """Move the cursor left to the start of a word."""
try: if self.password:
*_, hit = re.finditer(self._WORD_START, self.value[: self.cursor_position]) # This is a password field so don't give any hints about word
except ValueError: # boundaries, even during movement.
self.cursor_position = 0 self.action_home()
else: else:
self.cursor_position = hit.start() try:
*_, hit = re.finditer(
self._WORD_START, self.value[: self.cursor_position]
)
except ValueError:
self.cursor_position = 0
else:
self.cursor_position = hit.start()
def action_cursor_right_word(self) -> None: def action_cursor_right_word(self) -> None:
"""Move the cursor right to the start of a word.""" """Move the cursor right to the start of a word."""
hit = re.search(self._WORD_START, self.value[self.cursor_position :]) if self.password:
if hit is None: # This is a password field so don't give any hints about word
self.cursor_position = len(self.value) # boundaries, even during movement.
self.action_end()
else: else:
self.cursor_position += hit.start() hit = re.search(self._WORD_START, self.value[self.cursor_position :])
if hit is None:
self.cursor_position = len(self.value)
else:
self.cursor_position += hit.start()
def action_delete_right(self) -> None: def action_delete_right(self) -> None:
"""Delete one character at the current cursor position.""" """Delete one character at the current cursor position."""
@@ -404,12 +416,19 @@ class Input(Widget, can_focus=True):
def action_delete_right_word(self) -> None: def action_delete_right_word(self) -> None:
"""Delete the current character and all rightward to the start of the next word.""" """Delete the current character and all rightward to the start of the next word."""
after = self.value[self.cursor_position :] if self.password:
hit = re.search(self._WORD_START, after) # This is a password field so don't give any hints about word
if hit is None: # boundaries, even during deletion.
self.value = self.value[: self.cursor_position] self.action_delete_right_all()
else: else:
self.value = f"{self.value[: self.cursor_position]}{after[hit.end()-1 :]}" after = self.value[self.cursor_position :]
hit = re.search(self._WORD_START, after)
if hit is None:
self.value = self.value[: self.cursor_position]
else:
self.value = (
f"{self.value[: self.cursor_position]}{after[hit.end()-1 :]}"
)
def action_delete_right_all(self) -> None: def action_delete_right_all(self) -> None:
"""Delete the current character and all characters to the right of the cursor position.""" """Delete the current character and all characters to the right of the cursor position."""
@@ -437,14 +456,21 @@ class Input(Widget, can_focus=True):
"""Delete leftward of the cursor position to the start of a word.""" """Delete leftward of the cursor position to the start of a word."""
if self.cursor_position <= 0: if self.cursor_position <= 0:
return return
after = self.value[self.cursor_position :] if self.password:
try: # This is a password field so don't give any hints about word
*_, hit = re.finditer(self._WORD_START, self.value[: self.cursor_position]) # boundaries, even during deletion.
except ValueError: self.action_delete_left_all()
self.cursor_position = 0
else: else:
self.cursor_position = hit.start() after = self.value[self.cursor_position :]
self.value = f"{self.value[: self.cursor_position]}{after}" try:
*_, hit = re.finditer(
self._WORD_START, self.value[: self.cursor_position]
)
except ValueError:
self.cursor_position = 0
else:
self.cursor_position = hit.start()
self.value = f"{self.value[: self.cursor_position]}{after}"
def action_delete_left_all(self) -> None: def action_delete_left_all(self) -> None:
"""Delete all characters to the left of the cursor position.""" """Delete all characters to the left of the cursor position."""