diff -uNr a/yrc/manifest b/yrc/manifest --- a/yrc/manifest e2db0fe5b97891eb86eb3421146dd0505861fa5d457a129c6a0deae8a838787ec6b436a901fbbb67cee946ee128b2bd57da05414dc65a2f95f8b76a9efd747cd +++ b/yrc/manifest cb588cedfb5c3350df728e539d79692b933cef15f3ff4670b4a1253cf9b38b35b9acfbfc9fb4b3ae5ec18a3126062b77e7d3083adf5925ec480b3356871bd934 @@ -4,3 +4,4 @@ 768773 yrc_minor_command_reorder jfw Move prompt_backspace and prompt_delete implementations to match the more sensible order in keymap and manual. 768773 yrc_input_history jfw Implement input history, by use of a new data structure for rings (cyclic lists). 768775 yrc_kill_yank jfw Implement the basic kill and yank commands. Also: rename prompt-backward command to prompt-back, to avert confusion with the anticipated prompt-back-word; update manual for the new commands plus clarifications & updated priorities. +768776 yrc_prompt_redraw_optimization jfw Optimize and clarify prompt drawing code; remove unneeded prompt_set_hscroll for consistency (this turned out to be needed after all; see an upcoming patch for fix and explanation). diff -uNr a/yrc/yrc.py b/yrc/yrc.py --- a/yrc/yrc.py 59b7e716e692e29ef4e5a39ed30eb333bb6b6e225c8e55210eb627ed7cbb6ad671f9e9c2475ddf6bbde41bb12739156439e03920ae8f28ba91d2d657750e5eb5 +++ b/yrc/yrc.py 431ad816f70f17cbc8eb50be23683af4c97a38e9bb5597d2dd6bc7b47ad5f087fe09a75682c0d92846145afb776083de91ed38e7088ce0ba244cbd4b398d576a @@ -850,6 +850,7 @@ return False def prompt_set_hscroll(s): + # This is called automatically by prompt_draw itself, but make sure a redraw gets done in case more calls are added. schedule_prompt_draw() prompt[2] = s @@ -860,7 +861,7 @@ schedule_prompt_draw() del prompt_chars()[:] prompt_set_cursor(0) - prompt_set_hscroll(0) + # hscroll and cursor_column are always updated at drawing time so no need to explicitly reset them, as with any code that changes chars or cursor. history_ring = new_ring(HISTORY_RING_SIZE) history_pos = None @@ -1045,22 +1046,26 @@ if scr_width < 4: write_out(t.ERASE_LINE_TO_END) return + # XXX Sometimes this redraws more than strictly necessary, such as when simply appending a character or moving the cursor without scrolling. Over a network the added transmission overhead is minimal (probably all fitting in the same packet as the required part of the update) but over a serial line it might be bothersome. A brute-force approach would be to stash the last rendered box contents, find the common prefix and draw only the rest. prompt_str = '> ' write_out(prompt_str) chars = prompt_chars() cursor = prompt_cursor() hscr = prompt_hscroll() + # XXX O(N) rendering (one difficulty is that hscroll is measured in rendered rather than source characters) before_cursor = asciify(chars[:cursor]) cursor_offset = len(before_cursor) - hscr max_width = scr_width - len(prompt_str) if not 0 <= cursor_offset < max_width: - hscr = max(0, hscr + cursor_offset - max_width/2) + # Cursor outside box: scroll text to center it. + hscr = max(0, len(before_cursor) - max_width/2) prompt_set_hscroll(hscr) cursor_offset = len(before_cursor) - hscr prompt_set_cursor_column(1 + len(prompt_str) + cursor_offset) - printable = (before_cursor[hscr:] + - asciify(chars[cursor:])[:max_width - cursor_offset]) - write_out(printable) + write_out(before_cursor[hscr:]) + trailing_cols = max_width - cursor_offset + # Pre-clip to skip needless O(N) rendering, then re-clip in case the rendering added characters. + write_out(asciify(chars[cursor:cursor+trailing_cols])[:trailing_cols]) write_out(t.ERASE_LINE_TO_END) schedule_refresh() prompt_draw_done()