Completed
Push — master ( f38886...764e18 )
by Lambda
57s
created

int2char()   B

Complexity

Conditions 2

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 24
rs 8.9713
c 0
b 0
f 0
1
"""Utility module."""
2
from typing import AnyStr, Union
3
from neovim import Nvim
4
5
_cached_encoding = None     # type: str
6
7
8
def get_encoding(nvim: Nvim) -> str:
9
    """Return a Vim's internal encoding.
10
11
    The retrieve encoding is cached to the function instance while encoding
12
    options should not be changed in Vim's live session (see :h encoding) to
13
    enhance performance.
14
15
    Args:
16
        nvim (neovim.Nvim): A ``neovim.Nvim`` instance.
17
18
    Returns:
19
        str: A Vim's internal encoding.
20
    """
21
    global _cached_encoding
22
    if _cached_encoding is None:
23
        _cached_encoding = nvim.options['encoding']
24
    return _cached_encoding
25
26
27
def ensure_bytes(nvim: Nvim, seed: AnyStr) -> bytes:
28
    """Encode `str` to `bytes` if necessary and return.
29
30
    Args:
31
        nvim (neovim.Nvim): A ``neovim.Nvim`` instance.
32
        seed (AnyStr): A str or bytes instance.
33
34
    Example:
35
        >>> from unittest.mock import MagicMock
36
        >>> nvim = MagicMock()
37
        >>> nvim.options = {'encoding': 'utf-8'}
38
        >>> ensure_bytes(nvim, b'a')
39
        b'a'
40
        >>> ensure_bytes(nvim, 'a')
41
        b'a'
42
43
    Returns:
44
        bytes: A bytes represantation of ``seed``.
45
    """
46
    if isinstance(seed, str):
47
        encoding = get_encoding(nvim)
48
        return seed.encode(encoding, 'surrogateescape')
49
    return seed
50
51
52
def ensure_str(nvim: Nvim, seed: AnyStr) -> str:
53
    """Decode `bytes` to `str` if necessary and return.
54
55
    Args:
56
        nvim (neovim.Nvim): A ``neovim.Nvim`` instance.
57
        seed (AnyStr): A str or bytes instance.
58
59
    Example:
60
        >>> from unittest.mock import MagicMock
61
        >>> nvim = MagicMock()
62
        >>> nvim.options = {'encoding': 'utf-8'}
63
        >>> ensure_str(nvim, b'a')
64
        'a'
65
        >>> ensure_str(nvim, 'a')
66
        'a'
67
68
    Returns:
69
        str: A str represantation of ``seed``.
70
    """
71
    if isinstance(seed, bytes):
72
        encoding = get_encoding(nvim)
73
        return seed.decode(encoding, 'surrogateescape')
74
    return seed
75
76
77
def int2char(nvim: Nvim, code: int) -> str:
78
    """Return a corresponding char of `code`.
79
80
    It uses "nr2char()" in Vim script when 'encoding' option is not utf-8.
81
    Otherwise it uses "chr()" in Python to improve the performance.
82
83
    Args:
84
        nvim (neovim.Nvim): A ``neovim.Nvim`` instance.
85
        code (int): A int which represent a single character.
86
87
    Example:
88
        >>> from unittest.mock import MagicMock
89
        >>> nvim = MagicMock()
90
        >>> nvim.options = {'encoding': 'utf-8'}
91
        >>> int2char(nvim, 97)
92
        'a'
93
94
    Returns:
95
        str: A str of ``code``.
96
    """
97
    encoding = get_encoding(nvim)
98
    if encoding in ('utf-8', 'utf8'):
99
        return chr(code)
100
    return nvim.call('nr2char', code)
101
102
103
def int2repr(nvim: Nvim, code: Union[int, bytes]) -> str:
104
    from .key import Key
105
    if isinstance(code, int):
106
        return int2char(nvim, code)
107
    return Key.represent(nvim, ensure_bytes(nvim, code))
108
109
110
def getchar(nvim: Nvim, *args) -> Union[int, bytes]:
111
    """Call getchar and return int or bytes instance.
112
113
    Args:
114
        nvim (neovim.Nvim): A ``neovim.Nvim`` instance.
115
        *args: Arguments passed to getchar function in Vim.
116
117
    Returns:
118
        Union[int, bytes]: A int or bytes.
119
    """
120
    try:
121
        ret = nvim.call('getchar', *args)
122
        if isinstance(ret, int):
123
            return ret
124
        return ensure_bytes(nvim, ret)
125
    except nvim.error as e:
126
        # NOTE:
127
        # Vim returns 0x03 when ^C is pressed but Neovim.
128
        # Additionally, KeyboardInterrupt is not raised but
129
        # A general nvim.error and only the following dirty
130
        # implementation works.
131
        if str(e) == "b'Keyboard interrupt'":
132
            return 0x03  # ^C
133
        raise e
134
135
136
def safeget(l: list, index: int, default=None):
137
    """Return an index item of list or default."""
138
    try:
139
        return l[index]
140
    except IndexError:
141
        return default
142
143
144
# http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Metaprogramming.html
145
class Singleton(type):
146
    """A singleton metaclass."""
147
148
    instance = None
149
150
    def __call__(cls, *args, **kwargs):
151
        if not cls.instance:
152
            cls.instance = super().__call__(*args, **kwargs)
153
        return cls.instance
154