Adds completion support
| 249 | |
| 250 | @dataclass |
| 251 | class CompletingReader(Reader): |
| 252 | """Adds completion support""" |
| 253 | |
| 254 | ### Class variables |
| 255 | # see the comment for the complete command |
| 256 | assume_immutable_completions = True |
| 257 | use_brackets = True # display completions inside [] |
| 258 | sort_in_column = False |
| 259 | |
| 260 | ### Instance variables |
| 261 | cmpltn_menu: list[str] = field(init=False) |
| 262 | cmpltn_menu_visible: bool = field(init=False) |
| 263 | cmpltn_message_visible: bool = field(init=False) |
| 264 | cmpltn_menu_end: int = field(init=False) |
| 265 | cmpltn_menu_choices: list[str] = field(init=False) |
| 266 | cmpltn_action: CompletionAction | None = field(init=False) |
| 267 | |
| 268 | def __post_init__(self) -> None: |
| 269 | super().__post_init__() |
| 270 | self.cmpltn_reset() |
| 271 | for c in (complete, self_insert): |
| 272 | self.commands[c.__name__] = c |
| 273 | self.commands[c.__name__.replace('_', '-')] = c |
| 274 | |
| 275 | def collect_keymap(self) -> tuple[tuple[KeySpec, CommandName], ...]: |
| 276 | return super().collect_keymap() + ( |
| 277 | (r'\t', 'complete'),) |
| 278 | |
| 279 | def after_command(self, cmd: Command) -> None: |
| 280 | super().after_command(cmd) |
| 281 | if not isinstance(cmd, (complete, self_insert)): |
| 282 | self.cmpltn_reset() |
| 283 | |
| 284 | def calc_screen(self) -> list[str]: |
| 285 | screen = super().calc_screen() |
| 286 | if self.cmpltn_menu_visible: |
| 287 | # We display the completions menu below the current prompt |
| 288 | ly = self.lxy[1] + 1 |
| 289 | screen[ly:ly] = self.cmpltn_menu |
| 290 | # If we're not in the middle of multiline edit, don't append to screeninfo |
| 291 | # since that screws up the position calculation in pos2xy function. |
| 292 | # This is a hack to prevent the cursor jumping |
| 293 | # into the completions menu when pressing left or down arrow. |
| 294 | if self.pos != len(self.buffer): |
| 295 | self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu) |
| 296 | return screen |
| 297 | |
| 298 | def finish(self) -> None: |
| 299 | super().finish() |
| 300 | self.cmpltn_reset() |
| 301 | |
| 302 | def cmpltn_reset(self) -> None: |
| 303 | self.cmpltn_menu = [] |
| 304 | self.cmpltn_menu_visible = False |
| 305 | self.cmpltn_message_visible = False |
| 306 | self.cmpltn_menu_end = 0 |
| 307 | self.cmpltn_menu_choices = [] |
| 308 | self.cmpltn_action = None |
nothing calls this directly
no test coverage detected
searching dependent graphs…