Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 72 additions & 10 deletions prompt_toolkit/shortcuts/progress_bar/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Each progress bar consists of a list of these formatters.
"""
import datetime
import math
import time
from abc import ABCMeta, abstractmethod
from typing import TYPE_CHECKING, List, Tuple
Expand All @@ -12,9 +13,10 @@
AnyFormattedText,
StyleAndTextTuples,
to_formatted_text,
merge_formatted_text,
)
from prompt_toolkit.formatted_text.utils import fragment_list_width
from prompt_toolkit.layout.dimension import AnyDimension, D
from prompt_toolkit.layout.dimension import AnyDimension, D, to_dimension
from prompt_toolkit.layout.utils import explode_text_fragments
from prompt_toolkit.utils import get_cwidth

Expand All @@ -27,6 +29,8 @@
"Label",
"Percentage",
"Bar",
"Total",
"Counter",
"Progress",
"TimeElapsed",
"TimeLeft",
Expand Down Expand Up @@ -211,12 +215,63 @@ def get_width(self, progress_bar: "ProgressBar") -> AnyDimension:
return D(min=9)


class Progress(Formatter):
class Total(Formatter):
"""
Display the total items to compete as text. E.g. "20"
"""

total_template = "<total>{{total:>{digits}}}</total>"

def _get_digits(self, n: int) -> int:
return int(math.log10(n)) + 1

def format(
self,
progress_bar: "ProgressBar",
progress: "ProgressBarCounter[object]",
width: int,
) -> AnyFormattedText:

return (
HTML(self.total_template)
.format(digits=self._get_digits(progress.total or 0))
.format(total=progress.total or "?")
)

def get_width(self, progress_bar: "ProgressBar") -> AnyDimension:
biggest = max(c.total or 0 for c in progress_bar.counters)
return D.exact(self._get_digits(biggest))


class Counter(Total):
"""
Display the items competed as text. E.g. "8"
"""

current_template = "<current>{{current:>{digits}}}</current>"

def format(
self,
progress_bar: "ProgressBar",
progress: "ProgressBarCounter[object]",
width: int,
) -> AnyFormattedText:

current = progress.items_completed
digits = self._get_digits(progress.total or current)
return HTML(self.current_template).format(digits=digits).format(current=current)

def get_width(self, progress_bar: "ProgressBar") -> AnyDimension:
biggest = max(c.total or c.items_completed for c in progress_bar.counters)
return D.exact(self._get_digits(biggest))


class Progress(Counter):
"""
Display the progress as text. E.g. "8/20"
"""

template = "<current>{current:>3}</current>/<total>{total:>3}</total>"
sep_template = "/"

def format(
self,
Expand All @@ -225,16 +280,23 @@ def format(
width: int,
) -> AnyFormattedText:

return HTML(self.template).format(
current=progress.items_completed, total=progress.total or "?"
return merge_formatted_text(
(
Counter.format(self, progress_bar, progress, width),
"/",
Total.format(self, progress_bar, progress, width),
)
)

def get_width(self, progress_bar: "ProgressBar") -> AnyDimension:
all_lengths = [
len("{0:>3}".format(c.total or "?")) for c in progress_bar.counters
]
all_lengths.append(1)
return D.exact(max(all_lengths) * 2 + 1)
counter = to_dimension(Counter.get_width(self, progress_bar))
sep = len(self.sep_template)
total = to_dimension(Total.get_width(self, progress_bar))
return D(
min=counter.min + sep + total.min,
max=counter.max + sep + total.max,
preferred=counter.preferred + sep + total.preferred,
)


def _format_timedelta(timedelta: datetime.timedelta) -> str:
Expand Down