File: detect-multibyte.py

package info (click to toggle)
python-blessed 1.25-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,812 kB
  • sloc: python: 14,645; makefile: 13; sh: 7
file content (94 lines) | stat: -rwxr-xr-x 2,833 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/usr/bin/env python
"""
Determines whether the attached terminal supports multibyte encodings.

Problem: A screen drawing application wants to detect whether the terminal
client is capable of rendering utf-8.  Some transports, such as a serial link,
often cannot forward their ``LANG`` environment preference, or protocols such
as telnet and rlogin often assume mutual agreement by manual configuration.

We can interactively determine whether the connecting terminal emulator is
rendering in utf8 by making an inquiry of their cursor position:

    - request cursor position (p0).

    - display multibyte character.

    - request cursor position (p1).

If the horizontal distance of (p0, p1) is 1 cell, we know the connecting
client is certainly matching our intended encoding.

As a (tough!) exercise, it may be possible to use this technique to accurately
determine the remote encoding without protocol negotiation using cursor
positioning alone through a complex state decision tree, as demonstrated
by the following diagram:

.. image:: _static/soulburner-ru-family-encodings.jpg
    :alt: Cyrillic encodings flowchart
"""


# pylint: disable=invalid-name
#         Invalid module name "detect-multibyte"

# std imports
import sys
import collections

# local
from blessed import Terminal


def get_pos(term):
    """Get cursor position, calling os.exit(2) if not determined."""
    # pylint: disable=invalid-name
    #         Invalid variable name "Position"
    Position = collections.namedtuple('Position', ('row', 'column'))

    pos = Position(*term.get_location())

    if -1 in pos:
        print('stdin: not a human', file=sys.stderr)
        exit(2)

    return pos


def main():
    """Program entry point."""
    term = Terminal()

    # move to bottom of screen, temporarily, where we're likely to do
    # the least damage, as we are performing something of a "destructive
    # write and erase" onto this screen location.
    with term.cbreak(), term.location(y=term.height - 1, x=0):

        # store first position
        pos0 = get_pos(term)

        # display multibyte character
        print('⦰', end='')

        # store second position
        pos1 = get_pos(term)

        # determine distance
        horizontal_distance = pos1.column - pos0.column
        multibyte_capable = horizontal_distance == 1

        # rubout character(s)
        print('\b \b' * horizontal_distance, end='')

    # returned to our original starting position,
    if not multibyte_capable:
        print(f'multibyte encoding failed, horizontal distance is {horizontal_distance}, '
              'expected 1 for unicode point https://codepoints.net/U+29B0',
              file=sys.stderr)
        exit(1)

    print(f"{term.bold_green('✓')} multibyte encoding supported!")


if __name__ == '__main__':
    exit(main())