datepicker

An fzf-like tool to interactively select a date in a provided format

git clone https://git.8pit.net/datepicker.git

 1{-# LANGUAGE CPP #-}
 2
 3module DatePicker.Util
 4  ( Week,
 5    monthWeeks,
 6    addWeeks,
 7    horizPad,
 8    horizCenter,
 9    vertCenter,
10    locale,
11    format,
12    addSep,
13    makePad,
14    periodAllMonths,
15    splitEvery,
16  )
17where
18
19import Data.List (intersperse)
20import Data.List.NonEmpty qualified as NE
21import Data.Time.Calendar qualified as Cal
22import Data.Time.Calendar.Month (Month, addMonths, diffMonths)
23import Data.Time.Format qualified as Fmt
24import Graphics.Vty.Attributes qualified as Attr
25import Graphics.Vty.Image qualified as I
26
27splitEvery :: Int -> [a] -> [[a]]
28splitEvery _ [] = []
29splitEvery n list = first : splitEvery n rest
30  where
31    (first, rest) = splitAt n list
32
33------------------------------------------------------------------------
34
35type Week = NE.NonEmpty Cal.Day
36
37monthWeeks :: Month -> Cal.DayOfWeek -> NE.NonEmpty Week
38monthWeeks m dw = NE.fromList $ map NE.fromList (monthWeeks' $ Cal.periodFirstDay m)
39  where
40    weekOfDay :: Cal.Day -> [Cal.Day]
41    weekOfDay = Cal.weekAllDays dw
42
43    monthWeeks' :: Cal.Day -> [[Cal.Day]]
44    monthWeeks' d
45      | Cal.dayPeriod d /= m = []
46      | otherwise =
47          let days = weekOfDay d
48              nday = Cal.addDays 1 $ last days
49           in filter ((==) m . Cal.dayPeriod) days : monthWeeks' nday
50
51periodAllMonths :: (Cal.DayPeriod p) => p -> [Month]
52periodAllMonths p =
53  let (fd, ld) = (Cal.periodFirstDay p, Cal.periodLastDay p)
54      (fm, lm) = (Cal.dayPeriod fd :: Month, Cal.dayPeriod ld :: Month)
55   in map (`addMonths` fm) [0 .. lm `diffMonths` fm]
56
57addWeeks :: Integer -> Cal.Day -> Cal.Day
58addWeeks n = Cal.addDays (n * 7)
59
60------------------------------------------------------------------------
61
62-- TODO: Make the default locale configurable
63locale :: Fmt.TimeLocale
64locale = Fmt.defaultTimeLocale
65
66format :: (Fmt.FormatTime t) => String -> t -> String
67format = Fmt.formatTime locale
68
69addSep :: [I.Image] -> [I.Image]
70addSep = intersperse (I.char Attr.defAttr ' ')
71
72makePad :: Int -> Int -> I.Image
73makePad = I.charFill Attr.defAttr ' '
74
75horizPad :: Int -> Bool -> I.Image -> I.Image
76horizPad w padLeft i =
77  let diff = w - I.imageWidth i
78      comb = if padLeft then I.horizJoin else flip I.horizJoin
79   in if diff > 0
80        then makePad diff 1 `comb` i
81        else i
82
83horizCenter :: Int -> I.Image -> I.Image
84horizCenter w img =
85  let diff = fromIntegral (w - I.imageWidth img) :: Double
86      ldiff = floor (diff / 2)
87      rdiff = ceiling (diff / 2)
88   in if diff > 0
89        then makePad ldiff 1 I.<|> img I.<|> makePad rdiff 1
90        else img
91
92vertCenter :: Int -> I.Image -> I.Image
93vertCenter w img =
94  let diff = fromIntegral (w - I.imageHeight img) :: Double
95      tdiff = floor (diff / 2)
96      bdiff = ceiling (diff / 2)
97   in if diff > 0
98        then makePad 1 tdiff I.<-> img I.<-> makePad 1 bdiff
99        else img