@@ -428,6 +428,7 @@ def formatyear(self, theyear, w=2, l=1, c=6, m=3):
428428 headers = (header for k in months )
429429 a (formatstring (headers , colwidth , c ).rstrip ())
430430 a ('\n ' * l )
431+
431432 # max number of weeks for this row
432433 height = max (len (cal ) for cal in row )
433434 for j in range (height ):
@@ -646,6 +647,117 @@ def formatmonthname(self, theyear, themonth, withyear=True):
646647 with different_locale (self .locale ):
647648 return super ().formatmonthname (theyear , themonth , withyear )
648649
650+
651+ class _CLIDemoCalendar (TextCalendar ):
652+ def __init__ (self , highlight_day = None , * args , ** kwargs ):
653+ super ().__init__ (* args , ** kwargs )
654+ self .highlight_day = highlight_day
655+
656+ def formatweek (self , theweek , width , * , highlight_day = None ):
657+ """
658+ Returns a single week in a string (no newline).
659+ """
660+ if highlight_day :
661+ from _colorize import get_colors
662+
663+ ansi = get_colors ()
664+ highlight = f"{ ansi .BLACK } { ansi .BACKGROUND_YELLOW } "
665+ reset = ansi .RESET
666+ else :
667+ highlight = reset = ""
668+
669+ return ' ' .join (
670+ (
671+ f"{ highlight } { self .formatday (d , wd , width )} { reset } "
672+ if d == highlight_day
673+ else self .formatday (d , wd , width )
674+ )
675+ for (d , wd ) in theweek
676+ )
677+
678+ def formatmonth (self , theyear , themonth , w = 0 , l = 0 ):
679+ """
680+ Return a month's calendar string (multi-line).
681+ """
682+ if (
683+ self .highlight_day
684+ and self .highlight_day .year == theyear
685+ and self .highlight_day .month == themonth
686+ ):
687+ highlight_day = self .highlight_day .day
688+ else :
689+ highlight_day = None
690+ w = max (2 , w )
691+ l = max (1 , l )
692+ s = self .formatmonthname (theyear , themonth , 7 * (w + 1 ) - 1 )
693+ s = s .rstrip ()
694+ s += '\n ' * l
695+ s += self .formatweekheader (w ).rstrip ()
696+ s += '\n ' * l
697+ for week in self .monthdays2calendar (theyear , themonth ):
698+ s += self .formatweek (week , w , highlight_day = highlight_day ).rstrip ()
699+ s += '\n ' * l
700+ return s
701+
702+ def formatyear (self , theyear , w = 2 , l = 1 , c = 6 , m = 3 ):
703+ """
704+ Returns a year's calendar as a multi-line string.
705+ """
706+ w = max (2 , w )
707+ l = max (1 , l )
708+ c = max (2 , c )
709+ colwidth = (w + 1 ) * 7 - 1
710+ v = []
711+ a = v .append
712+ a (repr (theyear ).center (colwidth * m + c * (m - 1 )).rstrip ())
713+ a ('\n ' * l )
714+ header = self .formatweekheader (w )
715+ for (i , row ) in enumerate (self .yeardays2calendar (theyear , m )):
716+ # months in this row
717+ months = range (m * i + 1 , min (m * (i + 1 )+ 1 , 13 ))
718+ a ('\n ' * l )
719+ names = (self .formatmonthname (theyear , k , colwidth , False )
720+ for k in months )
721+ a (formatstring (names , colwidth , c ).rstrip ())
722+ a ('\n ' * l )
723+ headers = (header for k in months )
724+ a (formatstring (headers , colwidth , c ).rstrip ())
725+ a ('\n ' * l )
726+
727+ if (
728+ self .highlight_day
729+ and self .highlight_day .year == theyear
730+ and self .highlight_day .month in months
731+ ):
732+ month_pos = months .index (self .highlight_day .month )
733+ else :
734+ month_pos = None
735+
736+ # max number of weeks for this row
737+ height = max (len (cal ) for cal in row )
738+ for j in range (height ):
739+ weeks = []
740+ for k , cal in enumerate (row ):
741+ if j >= len (cal ):
742+ weeks .append ('' )
743+ else :
744+ day = (
745+ self .highlight_day .day if k == month_pos else None
746+ )
747+ weeks .append (
748+ self .formatweek (cal [j ], w , highlight_day = day )
749+ )
750+ a (formatstring (weeks , colwidth , c ).rstrip ())
751+ a ('\n ' * l )
752+ return '' .join (v )
753+
754+
755+ class _CLIDemoLocaleCalendar (LocaleTextCalendar , _CLIDemoCalendar ):
756+ def __init__ (self , highlight_day = None , * args , ** kwargs ):
757+ super ().__init__ (* args , ** kwargs )
758+ self .highlight_day = highlight_day
759+
760+
649761# Support for old module level interface
650762c = TextCalendar ()
651763
@@ -698,7 +810,7 @@ def timegm(tuple):
698810
699811def main (args = None ):
700812 import argparse
701- parser = argparse .ArgumentParser ()
813+ parser = argparse .ArgumentParser (color = True )
702814 textgroup = parser .add_argument_group ('text only arguments' )
703815 htmlgroup = parser .add_argument_group ('html only arguments' )
704816 textgroup .add_argument (
@@ -765,6 +877,7 @@ def main(args=None):
765877 sys .exit (1 )
766878
767879 locale = options .locale , options .encoding
880+ today = datetime .date .today ()
768881
769882 if options .type == "html" :
770883 if options .month :
@@ -781,23 +894,23 @@ def main(args=None):
781894 optdict = dict (encoding = encoding , css = options .css )
782895 write = sys .stdout .buffer .write
783896 if options .year is None :
784- write (cal .formatyearpage (datetime . date . today () .year , ** optdict ))
897+ write (cal .formatyearpage (today .year , ** optdict ))
785898 else :
786899 write (cal .formatyearpage (options .year , ** optdict ))
787900 else :
788901 if options .locale :
789- cal = LocaleTextCalendar ( locale = locale )
902+ cal = _CLIDemoLocaleCalendar ( highlight_day = today , locale = locale )
790903 else :
791- cal = TextCalendar ( )
904+ cal = _CLIDemoCalendar ( highlight_day = today )
792905 cal .setfirstweekday (options .first_weekday )
793906 optdict = dict (w = options .width , l = options .lines )
794907 if options .month is None :
795908 optdict ["c" ] = options .spacing
796909 optdict ["m" ] = options .months
797- if options . month is not None :
910+ else :
798911 _validate_month (options .month )
799912 if options .year is None :
800- result = cal .formatyear (datetime . date . today () .year , ** optdict )
913+ result = cal .formatyear (today .year , ** optdict )
801914 elif options .month is None :
802915 result = cal .formatyear (options .year , ** optdict )
803916 else :
0 commit comments