mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-128317: Highlight today in colour in calendar CLI output (#128318)
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
This commit is contained in:
parent
fa985bee61
commit
f21af186bf
5 changed files with 85 additions and 13 deletions
|
@ -146,26 +146,34 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
|||
the specified width, representing an empty day. The *weekday* parameter
|
||||
is unused.
|
||||
|
||||
.. method:: formatweek(theweek, w=0)
|
||||
.. method:: formatweek(theweek, w=0, highlight_day=None)
|
||||
|
||||
Return a single week in a string with no newline. If *w* is provided, it
|
||||
specifies the width of the date columns, which are centered. Depends
|
||||
on the first weekday as specified in the constructor or set by the
|
||||
:meth:`setfirstweekday` method.
|
||||
|
||||
.. versionchanged:: next
|
||||
If *highlight_day* is given, this date is highlighted in color.
|
||||
This can be :ref:`controlled using environment variables
|
||||
<using-on-controlling-color>`.
|
||||
|
||||
|
||||
.. method:: formatweekday(weekday, width)
|
||||
|
||||
Return a string representing the name of a single weekday formatted to
|
||||
the specified *width*. The *weekday* parameter is an integer representing
|
||||
the day of the week, where ``0`` is Monday and ``6`` is Sunday.
|
||||
|
||||
|
||||
.. method:: formatweekheader(width)
|
||||
|
||||
Return a string containing the header row of weekday names, formatted
|
||||
with the given *width* for each column. The names depend on the locale
|
||||
settings and are padded to the specified width.
|
||||
|
||||
.. method:: formatmonth(theyear, themonth, w=0, l=0)
|
||||
|
||||
.. method:: formatmonth(theyear, themonth, w=0, l=0, highlight_day=None)
|
||||
|
||||
Return a month's calendar in a multi-line string. If *w* is provided, it
|
||||
specifies the width of the date columns, which are centered. If *l* is
|
||||
|
@ -173,6 +181,12 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
|||
on the first weekday as specified in the constructor or set by the
|
||||
:meth:`setfirstweekday` method.
|
||||
|
||||
.. versionchanged:: next
|
||||
If *highlight_day* is given, this date is highlighted in color.
|
||||
This can be :ref:`controlled using environment variables
|
||||
<using-on-controlling-color>`.
|
||||
|
||||
|
||||
.. method:: formatmonthname(theyear, themonth, width=0, withyear=True)
|
||||
|
||||
Return a string representing the month's name centered within the
|
||||
|
@ -180,12 +194,13 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
|||
output. The *theyear* and *themonth* parameters specify the year
|
||||
and month for the name to be formatted respectively.
|
||||
|
||||
|
||||
.. method:: prmonth(theyear, themonth, w=0, l=0)
|
||||
|
||||
Print a month's calendar as returned by :meth:`formatmonth`.
|
||||
|
||||
|
||||
.. method:: formatyear(theyear, w=2, l=1, c=6, m=3)
|
||||
.. method:: formatyear(theyear, w=2, l=1, c=6, m=3, highlight_day=None)
|
||||
|
||||
Return a *m*-column calendar for an entire year as a multi-line string.
|
||||
Optional parameters *w*, *l*, and *c* are for date column width, lines per
|
||||
|
@ -194,6 +209,11 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
|||
:meth:`setfirstweekday` method. The earliest year for which a calendar
|
||||
can be generated is platform-dependent.
|
||||
|
||||
.. versionchanged:: next
|
||||
If *highlight_day* is given, this date is highlighted in color.
|
||||
This can be :ref:`controlled using environment variables
|
||||
<using-on-controlling-color>`.
|
||||
|
||||
|
||||
.. method:: pryear(theyear, w=2, l=1, c=6, m=3)
|
||||
|
||||
|
@ -549,7 +569,7 @@ The :mod:`calendar` module defines the following exceptions:
|
|||
|
||||
.. _calendar-cli:
|
||||
|
||||
Command-Line Usage
|
||||
Command-line usage
|
||||
------------------
|
||||
|
||||
.. versionadded:: 2.5
|
||||
|
@ -687,6 +707,9 @@ The following options are accepted:
|
|||
The number of months printed per row.
|
||||
Defaults to 3.
|
||||
|
||||
.. versionchanged:: next
|
||||
By default, today's date is highlighted in color and can be
|
||||
:ref:`controlled using environment variables <using-on-controlling-color>`.
|
||||
|
||||
*HTML-mode options:*
|
||||
|
||||
|
|
|
@ -296,6 +296,19 @@ ast
|
|||
* The ``repr()`` output for AST nodes now includes more information.
|
||||
(Contributed by Tomas R in :gh:`116022`.)
|
||||
|
||||
|
||||
calendar
|
||||
--------
|
||||
|
||||
* By default, today's date is highlighted in color in :mod:`calendar`'s
|
||||
:ref:`command-line <calendar-cli>` text output.
|
||||
This can be controlled via the :envvar:`PYTHON_COLORS` environment
|
||||
variable as well as the canonical |NO_COLOR|_
|
||||
and |FORCE_COLOR|_ environment variables.
|
||||
See also :ref:`using-on-controlling-color`.
|
||||
(Contributed by Hugo van Kemenade in :gh:`128317`.)
|
||||
|
||||
|
||||
concurrent.futures
|
||||
------------------
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@ COLORIZE = True
|
|||
|
||||
|
||||
class ANSIColors:
|
||||
BACKGROUND_YELLOW = "\x1b[43m"
|
||||
BOLD_GREEN = "\x1b[1;32m"
|
||||
BOLD_MAGENTA = "\x1b[1;35m"
|
||||
BOLD_RED = "\x1b[1;31m"
|
||||
BLACK = "\x1b[30m"
|
||||
GREEN = "\x1b[32m"
|
||||
GREY = "\x1b[90m"
|
||||
MAGENTA = "\x1b[35m"
|
||||
|
|
|
@ -349,11 +349,27 @@ class TextCalendar(Calendar):
|
|||
s = '%2i' % day # right-align single-digit days
|
||||
return s.center(width)
|
||||
|
||||
def formatweek(self, theweek, width):
|
||||
def formatweek(self, theweek, width, *, highlight_day=None):
|
||||
"""
|
||||
Returns a single week in a string (no newline).
|
||||
"""
|
||||
return ' '.join(self.formatday(d, wd, width) for (d, wd) in theweek)
|
||||
if highlight_day:
|
||||
from _colorize import get_colors
|
||||
|
||||
ansi = get_colors()
|
||||
highlight = f"{ansi.BLACK}{ansi.BACKGROUND_YELLOW}"
|
||||
reset = ansi.RESET
|
||||
else:
|
||||
highlight = reset = ""
|
||||
|
||||
return ' '.join(
|
||||
(
|
||||
f"{highlight}{self.formatday(d, wd, width)}{reset}"
|
||||
if d == highlight_day
|
||||
else self.formatday(d, wd, width)
|
||||
)
|
||||
for (d, wd) in theweek
|
||||
)
|
||||
|
||||
def formatweekday(self, day, width):
|
||||
"""
|
||||
|
@ -388,10 +404,11 @@ class TextCalendar(Calendar):
|
|||
"""
|
||||
print(self.formatmonth(theyear, themonth, w, l), end='')
|
||||
|
||||
def formatmonth(self, theyear, themonth, w=0, l=0):
|
||||
def formatmonth(self, theyear, themonth, w=0, l=0, *, highlight_day=None):
|
||||
"""
|
||||
Return a month's calendar string (multi-line).
|
||||
"""
|
||||
highlight_day = highlight_day.day if highlight_day else None
|
||||
w = max(2, w)
|
||||
l = max(1, l)
|
||||
s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
|
||||
|
@ -400,11 +417,11 @@ class TextCalendar(Calendar):
|
|||
s += self.formatweekheader(w).rstrip()
|
||||
s += '\n' * l
|
||||
for week in self.monthdays2calendar(theyear, themonth):
|
||||
s += self.formatweek(week, w).rstrip()
|
||||
s += self.formatweek(week, w, highlight_day=highlight_day).rstrip()
|
||||
s += '\n' * l
|
||||
return s
|
||||
|
||||
def formatyear(self, theyear, w=2, l=1, c=6, m=3):
|
||||
def formatyear(self, theyear, w=2, l=1, c=6, m=3, *, highlight_day=None):
|
||||
"""
|
||||
Returns a year's calendar as a multi-line string.
|
||||
"""
|
||||
|
@ -428,15 +445,24 @@ class TextCalendar(Calendar):
|
|||
headers = (header for k in months)
|
||||
a(formatstring(headers, colwidth, c).rstrip())
|
||||
a('\n'*l)
|
||||
|
||||
if highlight_day and highlight_day.month in months:
|
||||
month_pos = months.index(highlight_day.month)
|
||||
else:
|
||||
month_pos = None
|
||||
|
||||
# max number of weeks for this row
|
||||
height = max(len(cal) for cal in row)
|
||||
for j in range(height):
|
||||
weeks = []
|
||||
for cal in row:
|
||||
for k, cal in enumerate(row):
|
||||
if j >= len(cal):
|
||||
weeks.append('')
|
||||
else:
|
||||
weeks.append(self.formatweek(cal[j], w))
|
||||
day = highlight_day.day if k == month_pos else None
|
||||
weeks.append(
|
||||
self.formatweek(cal[j], w, highlight_day=day)
|
||||
)
|
||||
a(formatstring(weeks, colwidth, c).rstrip())
|
||||
a('\n' * l)
|
||||
return ''.join(v)
|
||||
|
@ -765,6 +791,7 @@ def main(args=None):
|
|||
sys.exit(1)
|
||||
|
||||
locale = options.locale, options.encoding
|
||||
today = datetime.date.today()
|
||||
|
||||
if options.type == "html":
|
||||
if options.month:
|
||||
|
@ -781,7 +808,7 @@ def main(args=None):
|
|||
optdict = dict(encoding=encoding, css=options.css)
|
||||
write = sys.stdout.buffer.write
|
||||
if options.year is None:
|
||||
write(cal.formatyearpage(datetime.date.today().year, **optdict))
|
||||
write(cal.formatyearpage(today.year, **optdict))
|
||||
else:
|
||||
write(cal.formatyearpage(options.year, **optdict))
|
||||
else:
|
||||
|
@ -797,10 +824,15 @@ def main(args=None):
|
|||
if options.month is not None:
|
||||
_validate_month(options.month)
|
||||
if options.year is None:
|
||||
result = cal.formatyear(datetime.date.today().year, **optdict)
|
||||
optdict["highlight_day"] = today
|
||||
result = cal.formatyear(today.year, **optdict)
|
||||
elif options.month is None:
|
||||
if options.year == today.year:
|
||||
optdict["highlight_day"] = today
|
||||
result = cal.formatyear(options.year, **optdict)
|
||||
else:
|
||||
if options.year == today.year and options.month == today.month:
|
||||
optdict["highlight_day"] = today
|
||||
result = cal.formatmonth(options.year, options.month, **optdict)
|
||||
write = sys.stdout.write
|
||||
if options.encoding:
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Highlight today in colour in :mod:`calendar`'s CLI output. Patch by Hugo van
|
||||
Kemenade.
|
Loading…
Add table
Add a link
Reference in a new issue