Skip to content

Commit 1443793

Browse files
authored
Merge pull request #78 from lysnikolaou/pyrepl-various-fixed-wide-characters
Various fixes to handle wide characters correctly
2 parents 390d778 + 4bc36ab commit 1443793

6 files changed

Lines changed: 673 additions & 335 deletions

File tree

‎Lib/_pyrepl/commands.py‎

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -236,57 +236,62 @@ class up(MotionCommand):
236236
def do(self) -> None:
237237
r = self.reader
238238
for _ in range(r.get_arg()):
239-
bol1 = r.bol()
240-
eol1 = r.eol()
241-
if bol1 == 0:
239+
x, y = r.pos2xy()
240+
new_y = y - 1
241+
242+
if new_y < 0:
242243
if r.historyi > 0:
243244
r.select_item(r.historyi - 1)
244245
return
245246
r.pos = 0
246247
r.error("start of buffer")
247248
return
248-
bol2 = r.bol(bol1 - 1)
249-
line_pos = r.pos - bol1
250-
251-
# Adjusting `pos` instead of (x, y) coordinates means that moving
252-
# between lines that have mixed single-width and double-width
253-
# characters does not align. Most editors do this, so leave it as-is.
254-
if line_pos > bol1 - bol2 - 1 or (
255-
# If at end-of-non-empty-line, move to end-of-line
256-
r.pos == eol1 and any(not i.isspace() for i in r.buffer[bol1:])
249+
250+
if (
251+
x
252+
> (
253+
new_x := r.max_column(new_y)
254+
) # we're past the end of the previous line
255+
or x == r.max_column(y)
256+
and any(
257+
not i.isspace() for i in r.buffer[r.bol() :]
258+
) # move between eols
257259
):
258-
r.pos = bol1 - 1
259-
else:
260-
r.pos = bol2 + line_pos
260+
x = new_x
261+
262+
r.setpos_from_xy(x, new_y)
261263

262264

263265
class down(MotionCommand):
264266
def do(self) -> None:
265267
r = self.reader
266268
b = r.buffer
267-
for i in range(r.get_arg()):
268-
bol1 = r.bol()
269-
eol1 = r.eol()
270-
if eol1 == len(b):
269+
for _ in range(r.get_arg()):
270+
x, y = r.pos2xy()
271+
new_y = y + 1
272+
273+
if new_y > r.max_row():
271274
if r.historyi < len(r.history):
272275
r.select_item(r.historyi + 1)
273276
r.pos = r.eol(0)
274277
return
275278
r.pos = len(b)
276279
r.error("end of buffer")
277280
return
278-
eol2 = r.eol(eol1 + 1)
279-
280-
# Adjusting `pos` instead of (x, y) coordinates means that moving
281-
# between lines that have mixed single-width and double-width
282-
# characters does not align. Most editors do this, so leave it as-is.
283-
if r.pos - bol1 > eol2 - eol1 - 1 or (
284-
# If at end-of-non-empty-line, move to end-of-line
285-
r.pos == eol1 and any(not i.isspace() for i in r.buffer[bol1:])
281+
282+
if (
283+
x
284+
> (
285+
new_x := r.max_column(new_y)
286+
) # we're past the end of the previous line
287+
or x == r.max_column(y)
288+
and any(
289+
not i.isspace() for i in r.buffer[r.bol() :]
290+
) # move between eols
286291
):
287-
r.pos = eol2
288-
else:
289-
r.pos = eol1 + (r.pos - bol1) + 1
292+
x = new_x
293+
294+
r.setpos_from_xy(x, new_y)
290295

291296

292297
class left(MotionCommand):
@@ -417,6 +422,7 @@ def do(self) -> None:
417422
class help(Command):
418423
def do(self) -> None:
419424
import _sitebuiltins
425+
420426
with self.reader.suspend():
421427
self.reader.msg = _sitebuiltins._Helper()() # type: ignore[assignment, call-arg]
422428

@@ -438,6 +444,7 @@ class show_history(Command):
438444
def do(self) -> None:
439445
from .pager import get_pager
440446
from site import gethistoryfile # type: ignore[attr-defined]
447+
441448
history = os.linesep.join(self.reader.history[:])
442449
with self.reader.suspend():
443450
pager = get_pager()

‎Lib/_pyrepl/console.py‎

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,19 @@ class Console(ABC):
3737
"""
3838

3939
@abstractmethod
40-
def refresh(self, screen: list[str], xy: tuple[int, int]) -> None:
41-
...
40+
def refresh(self, screen: list[str], xy: tuple[int, int]) -> None: ...
4241

4342
@abstractmethod
44-
def prepare(self) -> None:
45-
...
43+
def prepare(self) -> None: ...
4644

4745
@abstractmethod
48-
def restore(self) -> None:
49-
...
46+
def restore(self) -> None: ...
5047

5148
@abstractmethod
52-
def move_cursor(self, x: int, y: int) -> None:
53-
...
49+
def move_cursor(self, x: int, y: int) -> None: ...
5450

5551
@abstractmethod
56-
def set_cursor_vis(self, visible: bool) -> None:
57-
...
52+
def set_cursor_vis(self, visible: bool) -> None: ...
5853

5954
@abstractmethod
6055
def getheightwidth(self) -> tuple[int, int]:
@@ -63,7 +58,7 @@ def getheightwidth(self) -> tuple[int, int]:
6358
...
6459

6560
@abstractmethod
66-
def get_event(self, block: bool = True) -> Event:
61+
def get_event(self, block: bool = True) -> Event:
6762
"""Return an Event instance. Returns None if |block| is false
6863
and there is no event pending, otherwise waits for the
6964
completion of an event."""
@@ -77,8 +72,7 @@ def push_char(self, char: str) -> None:
7772
...
7873

7974
@abstractmethod
80-
def beep(self) -> None:
81-
...
75+
def beep(self) -> None: ...
8276

8377
@abstractmethod
8478
def clear(self) -> None:

0 commit comments

Comments
 (0)