Search code examples
pythonpython-3.xcjkcurses

Is curses' window.insnstr broken in Python 3 for wide characters?


When printing wide characters using Python 3's ncurses bindings, spaces are compressed when using window.insnstr. Here's the code to reproduce the issue:

import curses


def main(window):
    window.insnstr(0, 0, "insnstr", 80)
    window.insnstr(1, 0, "赵启明          XXX", 80)
    window.insnstr(2, 0, "001122          XXX", 80)
    window.insnstr(3, 0, "赵启明          XXX", 80)
    window.insnstr(4, 0, "001122          XXX", 80)
    window.addnstr(6, 0, "addnstr", 80)
    window.addnstr(7, 0, "赵启明          XXX", 80)
    window.addnstr(8, 0, "001122          XXX", 80)
    window.addnstr(9, 0, "赵启明          XXX", 80)
    window.addnstr(10, 0, "001122          XXX", 80)
    window.addnstr(11, 0, "Press any key to exit.", 80)
    window.refresh()
    window.get_wch()


if __name__ == "__main__":
    curses.wrapper(main)

With tmux, Xterm and st, I get the following output:

insnstr
赵启明       XXX
001122          XXX
赵启明       XXX
001122          XXX

addnstr
赵启明          XXX
001122          XXX
赵启明          XXX
001122          XXX
Press any key to exit.

I expect the alignment to be the same in both blocks. Interestingly, if I replace the spaces with any other character, the alignment is consistent:

insnstr
赵启明----------XXX
001122----------XXX
赵启明----------XXX
001122----------XXX

addnstr
赵启明----------XXX
001122----------XXX
赵启明----------XXX
001122----------XXX
Press any key to exit.

Depending on your browser font, the numbers may or may not be aligned; refer to this screenshot to see how the output looks in a terminal emulator:

screenshot of terminal

Is this a bug in the ncurses library, in Python's implementation of the library, or am I misunderstanding how this curses function should work?


Solution

  • It looks like a bug in the ncurses library: addstr flavors are used far more often than the insert/delete operations, and ncurses has to do some special bookkeeping to keep track of double-width characters.

    This is fixed in patch 6.0.20160220, which eventually will be in whatever package you use.