Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env rdmd
- /** A calendar application to inspired by github:quickfur/dcal.
- * by ARaspiK <araspik@protonmail.com>
- * The final product is envisioned to have every feature that util-linux/cal has, and is
- * meant to be a suitable and hopefully faster replacement of it.
- * This uses component-based programming (I first read of it and was inspired by it from
- * https://wiki.dlang.org/Component_programming_with_ranges) and is easy to read,
- * understand, and modify.
- * Armed with the understanding of the article's "Component Programming" section:
- * Source: List of dates
- * Target: Line-by-line formatted calendar with column-aligned day numbers and month
- * names, with distinct "month blocks".
- * Steps: dates -> by month -> format into set of lines -> add month name (centered) ->
- * join together month blocks -> formatted calendar
- * Configuration (via options):
- * First day as monday/sunday.
- * Show X months (starting with / around / ending with a specified date)
- * Show a full year / current month / X months / this week / X weeks
- * Copyright (c) 2018 ARaspiK <araspik@protonmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * [Except as contained in this notice, the name of ARaspiK
- * shall not be used in advertising or otherwise to promote the sale, use
- * or other dealings in this Software without prior written authorization
- * from ARaspiK.]
- */
- module calendar;
- import std.algorithm; // For everything ranges
- import std.array; // Arrays and ranges
- import std.datetime; // Getting date and getting basic info about it
- import std.getopt; // We use standard parsing methods
- import std.range; // RANGES EVERYWHERE
- import std.stdio; // Input/Output anyone?
- import std.string; // String manipulations during formatting
- struct CalendarConfig {
- enum StartDay {sun = false, mon = true}
- StartDay startOfWeek = StartDay.sun;
- ubyte monthsPerRow = 3;
- }
- static CalendarConfig config;
- /** Checks if the input type is an input range with element type Date. */
- enum isDateRange(R) = isInputRange!R && is(ElementType!R : Date);
- // Quick static test
- static assert(isDateRange!(typeof(dateList!(a => a.year > 2013)(2013))));
- /** Get a list of dates starting from @arg year, and keep going until @targ pred is
- * satisfied.
- */
- auto dateList(alias pred)(short year) {
- return Date(year, 1, 1).recurrence!((a,n) => a[n-1] + 1.days).until!(pred);
- }
- /** Convernience function to be used with chunkBy to split by months. */
- auto myMonth(Date a, Date b) {
- return a.month == b.month;
- }
- /** Convernience function to be used with chunkBy to split by weeks. */
- auto myWeek(Date a, Date b) {
- if (config.startOfWeek == CalendarConfig.StartDay.mon)
- return a.isoWeek() == b.isoWeek();
- return (a + 1.days).isoWeek() == (b + 1.days).isoWeek();
- }
- /** Returns the first day of the week by our configuration. */
- auto firstDayOfWeek() {
- if (config.startOfWeek == CalendarConfig.StartDay.mon)
- return DayOfWeek.mon;
- return DayOfWeek.sun;
- }
- /** Returns the last day of the week by our configuration. */
- auto lastDayOfWeek() {
- if (config.startOfWeek == CalendarConfig.StartDay.mon)
- return DayOfWeek.sun;
- return DayOfWeek.sat;
- }
- /** Formats a single given week into a fixed-length string. */
- auto formatWeek(Range)(Range week)
- if (isDateRange!Range) {
- auto firstDayInWeek = week.front.dayOfWeek;
- string result = week.map!(d => format!" %2d"(d.day)).join();
- if (firstDayInWeek != firstDayOfWeek())
- return result.rightJustify(7 * 3);
- if (week.front.dayOfWeek /* Last day */ != lastDayOfWeek())
- return result.leftJustify(7 * 3);
- return result;
- }
- /** Creates an auto-centered month title given the month. */
- string monthTitle(Month month) {
- static immutable string[] monthNames = [
- "January", "Feb", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"
- ];
- return monthNames[month - 1].center(7 * 3);
- }
- /** Formats a month by joining monthTitle and calls to chunkBy!myWeek. */
- auto formatMonth(Range)(Range monthDays)
- if (isDateRange!Range) {
- return chain([monthDays.front.month.monthTitle], monthDays.chunkBy!myWeek.array.formatWeek());
- }
- /** Formats blocks of pre-formatted months (ranges of lines) into horizontally-placed
- * blocks, without regard to how many go on each block.
- */
- auto blockMonths(Range)(Range months, string sep)
- if (isForwardRange!Range && is(ElementType!(ElementType!Range) : string)) {
- struct MonthRow {
- Range months;
- string sep;
- bool isEmpty;
- this(Range months, string sep) {
- this.months = months;
- this.sep = sep;
- isEmpty = months.empty;
- }
- @property bool empty() {return isEmpty;}
- @property auto front() {
- return months.save.map!(a => a.front.leftJustify(7 * 3)).join(sep);
- }
- void popFront() {
- assert (!empty);
- isEmpty = true; // Assume we're out of data
- ror.each!((ElementType!Range r) {
- if (!r.empty) {
- r.popFront();
- if (!r.empty) isEmpty = false;
- }
- });
- }
- }
- return MonthRow(months, sep);
- }
- /*auto formatYear(short year) {
- return dateList!(a => a.year > year)(year).chunkBy!myMonth.chunks(config.monthsPerRow)
- .map!(r => r.map!formatMonth.array().blockMonths(" ").join("\n")).join("\n\n");
- }
- int main(string[] args) {
- }*/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement