The goal
In the summer of 2016 I started my masters in software development at IT University in Copenhagen. Knowing myself I knew I was going to need a system for keeping track of all my reading and assignments. I needed an overview that was easily accessible and easily kept up to date in regards to upcoming deadlines across different courses.
The finished product
What I ended up with was this: An addition to my conky setup which shows all upcoming deadlines within the next seven days, grouped by date and course.
The script can be found on my github account.
The deadlines.md files and folder structure
The first problem was to keep everything synchronized between my desktop and laptop machine so that I would have all updates from the night before on my laptop while at ITU. To get up and running I decided on a simple folder structure in Dropbox, which I was using anyway.
For each semester I create a folder for each course. The folder will hold my notes, downloaded articles, lecture slides and other relevant files. All notes will be managed in markdown files since it is a simple and easy way to structure a document and still have it available in the online viewer on dropbox.com and to allow it to be downloaded to my phone or other devices.
Each course will have a deadlines.md
file. This is where I fill in all deadlines for the course. In some courses all deadlines will be published right away, in others they will be published continuously. every time I prepare for a lecture I will look in the deadlines.md
file to find out what I need to do, and if it is empty I will look at our course web site.
I wish to use the deadlines.md
files both as a regular markdown file that can be compiled with software, shown on dropbox or on a github-like system, so I need to follow the markdown structure. I also want the information to be parsable by a script in order to use the information elsewhere - i.e. in my conky
script.
I have decided on the following rules.
- All files start with a headlines (#) stating that this is the deadlines for the given course.
- After the headlines follows zero or more paragraphs with minor information such as a legend for abbreviations for the course material.
- For each date that is relevant I have a second level headline (##) with a date in
YYYY-MM-DD
format followed by a description such as "Lecture 3" or "Hand-in". - For each date I have a bullet item with all the things I need to do, for example "* Read [SCP] chapter 5-6, skip section 6.9" where [SCP] is a reference to the course book. Each item can also have additional notes which are added on a new line and indented.
- When an item has been done I will add in capitals "DONE" at the end of the line with the bullet. This will be a signal to my script. and to myself.
The above rules are simple enough to follow when keeping the deadlines files updated and they are useful enough to be parsed by a script and be visually distinct when parsed as markdown.
Example deadlines.md
:
# Basic Programming
[CS1] = Primary book for the course.
## 2017-02-01 Lecture 1 Introduction
* Install c++ compiler DONE
* Read chapter 1+2 of [CS1] DONE
## 2017-02-08 Lecture 2
* Read chp 2 DONE
* Read chp 3
Read until page 56
* Do main assignment for week 2 (see course website)
## 2017-03-01 Mandatory Hand-in
* Mandatory project MyProgram.c
The script
After I setup the deadlines.md
files and filled it with data I need to make the data available as a data structure. Since I am most familiar with PHP I decided to make a simple PHP script. It ended up being a single file with a few functions and some logic to a) parse the files, b) restructure the data, c) sort by date, and d) format it for output. Since I can use a text editor or a markdown parser to parse the files to HTML I just need the output in CLI friendly format.
This is a prototype that I only use for my studies which consist of four courses for every six month. For this reason I found it easiest to just hard code the paths to each of the four deadlines.md
files. See below for a discussion of updates regarding this. The script does take one argument which is the max lenght of the truncated text to output.
I ended up with this script which is further explained below.
1) The parser
There are a lot of markdown parsers to be found on the Internet. PHP flavored parsers too. I chose to make a parser myself even though I am a strong supporter of not reinventing the wheel. In this case I prefer to have a single file script to solve my problem, which would be tricky if I were to have a composer file with dependencies. I also do not need to be able to parse all types of syntax in the markdown files only two levels of headlines, paragraphs, bullets, and newlines in bullets.
The parsing functionality is found in the 'parse_markdown` function. The function takes a course name and a boolean of whether the result should include items that are marked as done. This goes beyond the responsibility of a parser which is discussed at the end of this post.
The parsing is done in a loop using preg_match
. It extracts the date, title, and items including notes and adds the info to an array which is returned. All the notes are added with their date as key. The entire structure is that all items are added to the list of deadlines in the structure as shown here: $deadlines['YYYY-MM-DD']['course_name']
.
2) The sorter and filtering by date and done
After parsing all the markdown files I would like the deadlines to be chronological so I see the most urgent first. I do this simply by using the ksort
function which sort the array by the key, i.e. the date.
As I mentioned earlier some of the courses have been planned ahead while others are doing ad hoc planning so just listing all future deadlines would overwhelm me. For this reason I have added a filter to make sure that I only display items with a date earlier than a week into the future.
3) The output/formatter
After all the parsing, sorting and filtering I am finally ready to output the data. I am going to use this in my conky setup, so I have mixed in some flags used by conky to change the output so the text color will match the rest. This is bad practice, which is discussed at the end.
Aside from the conky flags what's basically happening is that for each date I output the date as a headline and then all items for that date, prefixed with a course code in square brackets and truncated to not fill the entire screen. This gives me some freedom when writing the items. If any items are past due the date will be marked with a red color in order to stand out.
The conky setting
Now everything is set up. I have my data files. I have my script. Now all I need is to set up conky to make use of the output of my script.
In my .conkyrc
file I call my script and end up with the output as seen in the picture above.
$hr
${color 009ee0}Homework${color}
${execp /usr/bin/php /path_to_script/markdown-reader-conky.php}
$hr
Future work
The setup as it is now works for me. Updating the deadlines.md
files is part of my daily routine so having the output as part of my conky is now a non-effort bonus, but still gives me the benefit of having an eye-catching effect when I turn on my machine. That being said there are of course things that could be improved. I will go through some of them here. If you have any additional suggestions or comments in general about my setup or code feel free to contact me either on twitter, github, or as a comment to this post.
1) auto-find deadlines.md files.
The script has a hard coded list of paths to check for the deadlines.md
files. An improvement would be to at the very least add the paths as arguments to the list or to programmatically look for the files given a file pattern.
2) parser should not decide if "done" should be included
I mentioned this briefly above. When parsing the markdown files I also check if the items are marked as done and decide if they should be added to the result. This is strictly speaking not the responsibility of the parser. Following the single responsibility principle I should have the parser only do the parsing, and then have a filter to handle which items to include in the result base on their date and whether or not they are marked as done.
3) mixing output.
When outputting the deadlines I also print flags that conky will interpret and use when displaying the data. This is a mix of concerns. The output of the data should be clean so that it would be readable if I just ran the script in a terminal or if I were to use the output in other systems. Adding the conky flags should either be done in a separate conky script or using a special conky output formatter.
4) past dates shown as red after they are due - which is too late.
With the current setup I get a visual warning when I have undone items after a deadline has passed. This is not optimal since it is too late to do anything about it when the visual warning comes. An expansion could be to show the warning earlier, e.g. 24 hours before the deadline. Of course that requires me to check the status at least every 24 hours, so that might not work during the weekend. For example if I have a deadline on Sunday but I don't sit at my computer after Friday. An expansion here would mean that I have to make some decisions, which might not meet the requirements of all possible scenarios.
5) script path and files path not usable on both desktop and laptop.
I currently only use this setup on my desktop computer, but it would be great if I could reuse the setup of my laptop. As it is now I can't do that. In order to have a similar setup on all my machines I have a git repository with all my dot-files (configuration files). This means that the .conkyrc
file is expecting both the PHP script and the deadlines.md
files to be in a certain place, which isn't the case. E.g. the user name is not the same on both machines. I'm not sure how to fix this, but it will probably been something with the .concyrc
not depending on the local user name for the script and the deadline files.
Conclusion
With the current setup it works. I have a pretty good overview of all deadlines for my studies. The deadlines list are easily written and marked as done. It can be improved in many ways, but considering the fact that I am only going to use this for three semesters (one of them already done) then I will probably not make any changes. That being said I have still learned a bit from having to do this setup. It made me reflect on my projects (courses) and the tasks I had for each of them. Hopefully in the future I will find it easier to manage multiple tasks on multiple projects. I might build on the setup I have described in this blog post or I might do something completely different.