mirror of https://github.com/Textualize/rich.git
fix for line wrapping
This commit is contained in:
parent
34cfcee6e7
commit
e69d216d97
|
@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- Added Console.show_cursor method
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed wrapping when a single word was too large to fit in a line
|
||||
|
||||
## [0.6.0] - 2020-03-03
|
||||
|
||||
### Added
|
||||
|
|
|
@ -4,24 +4,28 @@ from typing import Iterable, List, Tuple
|
|||
re_word = re.compile(r"\s*\S+\s*")
|
||||
|
||||
|
||||
def words(text: str) -> Iterable[Tuple[int, str]]:
|
||||
def words(text: str) -> Iterable[Tuple[int, int, str]]:
|
||||
position = 0
|
||||
word_match = re_word.match(text, position)
|
||||
while word_match is not None:
|
||||
start, position = word_match.span()
|
||||
start, end = word_match.span()
|
||||
word = word_match.group(0)
|
||||
yield start, word
|
||||
word_match = re_word.match(text, position)
|
||||
yield start, end, word
|
||||
word_match = re_word.match(text, end)
|
||||
|
||||
|
||||
def divide_line(text: str, width: int) -> List[int]:
|
||||
divides: List[int] = []
|
||||
append = divides.append
|
||||
line_size = 0
|
||||
for position, word in words(text):
|
||||
if line_size + len(word.rstrip()) > width:
|
||||
if position:
|
||||
append(position)
|
||||
line_size = 0
|
||||
line_size += len(word)
|
||||
line_position = 0
|
||||
for start, end, word in words(text):
|
||||
if line_position + len(word.rstrip()) > width:
|
||||
if line_position and start:
|
||||
append(start)
|
||||
line_position = len(word)
|
||||
else:
|
||||
divides.extend(range(start or width, end + 1, width))
|
||||
line_position = len(word) % width
|
||||
else:
|
||||
line_position += len(word)
|
||||
return divides
|
||||
|
|
|
@ -57,6 +57,9 @@ class Lines:
|
|||
def __init__(self, lines: Iterable["Text"] = ()) -> None:
|
||||
self._lines: List["Text"] = list(lines)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Lines({self._lines!r})"
|
||||
|
||||
def __iter__(self) -> Iterator["Text"]:
|
||||
return iter(self._lines)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from dataclasses import dataclass, field
|
|||
import sys
|
||||
from time import monotonic
|
||||
from threading import Event, RLock, Thread
|
||||
from typing import Callable, Dict, List, Optional, NewType, Union
|
||||
from typing import Any, Callable, Dict, List, Optional, NewType, Union
|
||||
|
||||
from .bar import Bar
|
||||
from .console import Console, RenderableType
|
||||
|
@ -29,7 +29,7 @@ class Task:
|
|||
total: float
|
||||
completed: float
|
||||
visible: bool = True
|
||||
fields: Dict[str, str] = field(default_factory=dict)
|
||||
fields: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
@property
|
||||
def finished(self) -> bool:
|
||||
|
@ -45,7 +45,7 @@ class Task:
|
|||
|
||||
|
||||
class RefreshThread(Thread):
|
||||
"""A thread that calls refresh on the Process object at regular intervals."""
|
||||
"""A thread that calls refresh() on the Process object at regular intervals."""
|
||||
|
||||
def __init__(self, progress: "Progress", refresh_per_second: int = 10) -> None:
|
||||
self.progress = progress
|
||||
|
@ -59,10 +59,7 @@ class RefreshThread(Thread):
|
|||
|
||||
def run(self) -> None:
|
||||
while not self.done.wait(1.0 / self.refresh_per_second):
|
||||
try:
|
||||
self.progress.refresh()
|
||||
except Exception as error:
|
||||
raise
|
||||
self.progress.refresh()
|
||||
|
||||
|
||||
def bar_widget(task: Task) -> Bar:
|
||||
|
@ -95,11 +92,13 @@ class Progress:
|
|||
|
||||
@property
|
||||
def tasks(self) -> List[TaskID]:
|
||||
"""Get a list of task IDs."""
|
||||
with self._lock:
|
||||
return list(self._tasks.keys())
|
||||
|
||||
@property
|
||||
def finished(self) -> bool:
|
||||
"""Check if all tasks have been completed."""
|
||||
with self._lock:
|
||||
if not self._tasks:
|
||||
return True
|
||||
|
@ -125,11 +124,12 @@ class Progress:
|
|||
def update(
|
||||
self,
|
||||
task_id: TaskID,
|
||||
*,
|
||||
total: float = None,
|
||||
completed: float = None,
|
||||
advance: float = None,
|
||||
visible: bool = None,
|
||||
**fields: RenderableType
|
||||
**fields: Any
|
||||
) -> None:
|
||||
with self._lock:
|
||||
task = self._tasks[task_id]
|
||||
|
@ -143,6 +143,7 @@ class Progress:
|
|||
task.visible = True
|
||||
|
||||
def refresh(self) -> None:
|
||||
"""Refresh (render) the progress information."""
|
||||
with self._lock:
|
||||
self._live_render.set_renderable(self._table)
|
||||
self.console.print(self._live_render)
|
||||
|
@ -192,14 +193,14 @@ class Progress:
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import random
|
||||
|
||||
import time
|
||||
|
||||
with Progress() as progress:
|
||||
|
||||
task1 = progress.add_task("[red]Downloading")
|
||||
task2 = progress.add_task("[green]Processing")
|
||||
task3 = progress.add_task("[cyan]Cooking...")
|
||||
task3 = progress.add_task("[cyan]Cooking")
|
||||
|
||||
while not progress.finished:
|
||||
progress.update(task1, advance=1.0)
|
||||
|
|
|
@ -303,6 +303,7 @@ class Table:
|
|||
flex_widths = [_range.span for _range in width_ranges]
|
||||
if not any(flex_widths):
|
||||
flex_widths = [1] * len(flex_widths)
|
||||
flex_widths = [0 if column.no_wrap else 1 for column in columns]
|
||||
excess_width = table_width - max_width
|
||||
widths = [
|
||||
width - excess_width
|
||||
|
@ -457,29 +458,15 @@ class Table:
|
|||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
from .console import Console
|
||||
from . import box
|
||||
|
||||
c = Console(markup=True)
|
||||
table = Table(
|
||||
Column(
|
||||
"Foo", footer=Text("Total", justify="right"), footer_style="bold", ratio=1
|
||||
),
|
||||
Column("Bar", style="red", footer="123", ratio=1),
|
||||
expand=True,
|
||||
show_footer=True,
|
||||
show_edge=True,
|
||||
style="on blue",
|
||||
c = Console(width=80)
|
||||
table = Table()
|
||||
table.add_column(no_wrap=True)
|
||||
table.add_column()
|
||||
table.add_row(
|
||||
"Magnet",
|
||||
"pneumonoultramicroscopicsilicovolcanoconiosispneumonoultramicroscopicsilicovolcanoconiosispneumonoultramicroscopicsilicovolcanoconiosis",
|
||||
)
|
||||
# table.columns[0].width = 50
|
||||
# table.columns[1].ratio = 1
|
||||
|
||||
table.add_row("Hello, [b]World[/b]! " * 3, "cake" * 10)
|
||||
from .markdown import Markdown
|
||||
|
||||
table.add_row(Markdown("# This is *Markdown*!"), "More text", "Hello WOrld")
|
||||
table.columns[0].justify = "center"
|
||||
table.columns[1].justify = "right"
|
||||
|
||||
c.print(table)
|
||||
|
||||
|
|
13
rich/text.py
13
rich/text.py
|
@ -644,16 +644,3 @@ class Text:
|
|||
append(line)
|
||||
return lines
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
from .console import Console
|
||||
|
||||
console = Console()
|
||||
text = Text(
|
||||
"""Hello, self! hello World
|
||||
|
||||
hello worhello\n"""
|
||||
)
|
||||
text.highlight_regex("self", "reverse")
|
||||
console.print(text)
|
||||
|
||||
|
|
Loading…
Reference in New Issue