Guest User

Calendar app fail

a guest
Feb 25th, 2018
45
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env rdmd
  2. /** A calendar application to inspired by github:quickfur/dcal.
  3. * by ARaspiK <araspik@protonmail.com>
  4.  
  5. * The final product is envisioned to have every feature that util-linux/cal has, and is
  6. * meant to be a suitable and hopefully faster replacement of it.
  7.  
  8. * This uses component-based programming (I first read of it and was inspired by it from
  9. * https://wiki.dlang.org/Component_programming_with_ranges) and is easy to read,
  10. * understand, and modify.
  11.  
  12. * Armed with the understanding of the article's "Component Programming" section:
  13. * Source: List of dates
  14. * Target: Line-by-line formatted calendar with column-aligned day numbers and month
  15. * names, with distinct "month blocks".
  16. * Steps: dates -> by month -> format into set of lines -> add month name (centered) ->
  17. * join together month blocks -> formatted calendar
  18.  
  19. * Configuration (via options):
  20. * First day as monday/sunday.
  21. * Show X months (starting with / around / ending with a specified date)
  22. * Show a full year / current month / X months / this week / X weeks
  23.  
  24. * Copyright (c) 2018 ARaspiK <araspik@protonmail.com>
  25. *
  26. * Permission is hereby granted, free of charge, to any person obtaining
  27. * a copy of this software and associated documentation files (the
  28. * "Software"), to deal in the Software without restriction, including
  29. * without limitation the rights to use, copy, modify, merge, publish,
  30. * distribute, sublicense, and/or sell copies of the Software, and to
  31. * permit persons to whom the Software is furnished to do so, subject to
  32. * the following conditions:
  33. *
  34. * The above copyright notice and this permission notice shall be
  35. * included in all copies or substantial portions of the Software.
  36. *
  37. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  38. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  39. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  40. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  41. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  42. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  43. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  44. *
  45. * [Except as contained in this notice, the name of ARaspiK
  46. * shall not be used in advertising or otherwise to promote the sale, use
  47. * or other dealings in this Software without prior written authorization
  48. * from ARaspiK.]
  49. */
  50.  
  51. module calendar;
  52.  
  53. import std.algorithm; // For everything ranges
  54. import std.array; // Arrays and ranges
  55. import std.datetime; // Getting date and getting basic info about it
  56. import std.getopt; // We use standard parsing methods
  57. import std.range; // RANGES EVERYWHERE
  58. import std.stdio; // Input/Output anyone?
  59. import std.string; // String manipulations during formatting
  60.  
  61. struct CalendarConfig {
  62. enum StartDay {sun = false, mon = true}
  63. StartDay startOfWeek = StartDay.sun;
  64. ubyte monthsPerRow = 3;
  65. }
  66.  
  67. static CalendarConfig config;
  68.  
  69. /** Checks if the input type is an input range with element type Date. */
  70. enum isDateRange(R) = isInputRange!R && is(ElementType!R : Date);
  71.  
  72. // Quick static test
  73. static assert(isDateRange!(typeof(dateList!(a => a.year > 2013)(2013))));
  74.  
  75. /** Get a list of dates starting from @arg year, and keep going until @targ pred is
  76. * satisfied.
  77. */
  78. auto dateList(alias pred)(short year) {
  79. return Date(year, 1, 1).recurrence!((a,n) => a[n-1] + 1.days).until!(pred);
  80. }
  81.  
  82. /** Convernience function to be used with chunkBy to split by months. */
  83. auto myMonth(Date a, Date b) {
  84. return a.month == b.month;
  85. }
  86.  
  87. /** Convernience function to be used with chunkBy to split by weeks. */
  88. auto myWeek(Date a, Date b) {
  89. if (config.startOfWeek == CalendarConfig.StartDay.mon)
  90. return a.isoWeek() == b.isoWeek();
  91. return (a + 1.days).isoWeek() == (b + 1.days).isoWeek();
  92. }
  93.  
  94. /** Returns the first day of the week by our configuration. */
  95. auto firstDayOfWeek() {
  96. if (config.startOfWeek == CalendarConfig.StartDay.mon)
  97. return DayOfWeek.mon;
  98. return DayOfWeek.sun;
  99. }
  100.  
  101. /** Returns the last day of the week by our configuration. */
  102. auto lastDayOfWeek() {
  103. if (config.startOfWeek == CalendarConfig.StartDay.mon)
  104. return DayOfWeek.sun;
  105. return DayOfWeek.sat;
  106. }
  107.  
  108. /** Formats a single given week into a fixed-length string. */
  109. auto formatWeek(Range)(Range week)
  110. if (isDateRange!Range) {
  111. auto firstDayInWeek = week.front.dayOfWeek;
  112. string result = week.map!(d => format!" %2d"(d.day)).join();
  113. if (firstDayInWeek != firstDayOfWeek())
  114. return result.rightJustify(7 * 3);
  115. if (week.front.dayOfWeek /* Last day */ != lastDayOfWeek())
  116. return result.leftJustify(7 * 3);
  117. return result;
  118. }
  119.  
  120. /** Creates an auto-centered month title given the month. */
  121. string monthTitle(Month month) {
  122. static immutable string[] monthNames = [
  123. "January", "Feb", "March", "April", "May", "June",
  124. "July", "August", "September", "October", "November", "December"
  125. ];
  126.  
  127. return monthNames[month - 1].center(7 * 3);
  128. }
  129.  
  130. /** Formats a month by joining monthTitle and calls to chunkBy!myWeek. */
  131. auto formatMonth(Range)(Range monthDays)
  132. if (isDateRange!Range) {
  133. return chain([monthDays.front.month.monthTitle], monthDays.chunkBy!myWeek.array.formatWeek());
  134. }
  135.  
  136. /** Formats blocks of pre-formatted months (ranges of lines) into horizontally-placed
  137. * blocks, without regard to how many go on each block.
  138. */
  139. auto blockMonths(Range)(Range months, string sep)
  140. if (isForwardRange!Range && is(ElementType!(ElementType!Range) : string)) {
  141. struct MonthRow {
  142. Range months;
  143. string sep;
  144. bool isEmpty;
  145.  
  146. this(Range months, string sep) {
  147. this.months = months;
  148. this.sep = sep;
  149. isEmpty = months.empty;
  150. }
  151.  
  152. @property bool empty() {return isEmpty;}
  153.  
  154. @property auto front() {
  155. return months.save.map!(a => a.front.leftJustify(7 * 3)).join(sep);
  156. }
  157.  
  158. void popFront() {
  159. assert (!empty);
  160. isEmpty = true; // Assume we're out of data
  161. ror.each!((ElementType!Range r) {
  162. if (!r.empty) {
  163. r.popFront();
  164. if (!r.empty) isEmpty = false;
  165. }
  166. });
  167. }
  168. }
  169. return MonthRow(months, sep);
  170. }
  171.  
  172. /*auto formatYear(short year) {
  173. return dateList!(a => a.year > year)(year).chunkBy!myMonth.chunks(config.monthsPerRow)
  174. .map!(r => r.map!formatMonth.array().blockMonths(" ").join("\n")).join("\n\n");
  175. }
  176.  
  177. int main(string[] args) {
  178.  
  179. }*/
RAW Paste Data