[script] Add simple due script for bibtex file

Scrapes a bibtex file for 'due' field, and outputs all found entries
with their priority and sorted for date.
This commit is contained in:
Marty Oehme 2020-05-16 17:05:09 +00:00
parent 1f25f86290
commit f96f9f2211
24 changed files with 455 additions and 27 deletions

BIN
.assets/bibtex/list.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

BIN
.assets/bibtex/rofi.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 KiB

BIN
.assets/polybar/clock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
.assets/polybar/full.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
.assets/polybar/i3-mode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
.assets/polybar/minimal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
.assets/polybar/mpris.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
.assets/polybar/network.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
.assets/polybar/system.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -45,7 +45,7 @@ Enjoy!
* [`nvim`](https://neovim.io/) - Neovim configuration
* [`pandoc`](https://pandoc.org) - Pandoc plaintext transformation options (mostly latex templates)
* [`picom`](https://github.com/yshui/picom) - X11 compositor (maintained fork from compton)
* [`polybar`](https://github.com/polybar/polybar) - Easy to customize statusbar
* [`polybar`](polybar/README.md) - Easy to customize statusbar
* [`qutebrowser`](https://github.com/qutebrowser/qutebrowser) - vim-key enabled web browser
* [`rofi`](https://github.com/davatorium/rofi) - Application launcher, dmenu replacement
* [`sxhkd`](https://github.com/baskerville/sxhkd) - X11 hotkey manager
@ -60,7 +60,7 @@ Enjoy!
* `rofi` contains additional scripts and a simple theming framework for rofi and should probably be reorganized to put the correct files into the correct directories (per xdg) at some point.
* `.local/bin` in `scripts` `stow` unit contains most executable user scripts. Most of these have been migrated to their corresponding modules (e.g. if a script exclusively targets git functionality, it will live there), some stand-alone scripts remain however.
* `.local/share/pandoc` contains configuration for academic latex (pandoc, really) writing and is of interest if you want to use this functionality.
* `.xinitrc` is used for x initialization and program startup.
* `.xinitrc` is used for x initialization and program startup. At some point, some of the consistently running applications may be moved to runit as supervised services.
* Generally, directories starting with a . are only meaningful for the *repository* not for the functionality of the machine that these dotfiles are deployed on. That means `.gitlab-ci.yml`, `.assets/`, `.stowrc` and similar files and directories will not show up in the final deployment in any home directory. Perhaps they should be called dotdot-files since they're the dotfiles for my dotfiles. 🙂 (Also, 'dotfiles'.)
[^shreq]: I may remove this requirement in the future to make modules more self-contained. However, relying on some base utility scripts makes it easier to avoid duplicating such functionality for each individual script in other modules.

147
bibtex/.local/bin/bib-due Executable file
View file

@ -0,0 +1,147 @@
#!/usr/bin/env sh
# shows due entries of bibtex file passed in
# HACK: brittle! will break on various bibfile abnormities (even just on due date w/o priority)
# FIXME: reimplementation with real library needed
#
OPTIND=1 # Reset in case getopts has been used previously in the shell.
fields="due|priority|\bauthor\b|\btitle\b"
filterby="due"
file="${BIBFILE}"
until=""
show_help() {
printf "%s\n" \
"" \
" bib-due Show due readings from bibtex file." \
"" \
" Usage: bib-due [-hv] -i input.bib -r 'due|priority|\bauthor|\btitle' -l 'due' -u '2020-05-12'" \
"" \
" Options:" \
"" \
" -i [bibtex-file] Input bibtex file to scrape and get items from." \
"" \
" -r [fields] Field values to read in file." \
"" \
" -l [filter] Field to use as filter entity." \
" This field is required for the scraper to pick entries up." \
"" \
" help | -h | --help Print out this help." \
"" \
" Invoked without arguments, bib-due will scrape the file defined in BIBFILE environment variable, " \
" filtering entries with the 'due' field, and getting the values for 'due', 'priority', 'author', " \
" and 'title' fields. It will then print the entries to stdout." \
"" \
" Example output line:" \
"" \
' 2020-06-25 (1): Sergei Gerasymchuk -- “Ze” time in Ukraine (Gerasymchuk2019) ' \
""
}
filter_until() {
# filter for dates, with line numbers
filtered=$(echo "$entries" | grep -noE '[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}')
# redirect entries to fifo pipe
mkfifo filteredentries
finish() {
rm filteredentries
}
trap finish EXIT
echo "$filtered" >filteredentries &
# find first date past until filter
lastline=""
while IFS= read -r line; do
cond=$(printf '%s' "$line" | cut -d: -f2)
cond=$(date -d "$cond" +%s)
if [ "$cond" -gt "$until" ]; then
lastline=$(printf '%s' "$line" | cut -d: -f1)
break
fi
done <filteredentries
# special cases all in filter, or none in filter
if [ -z "$lastline" ]; then
return
elif [ "$lastline" -eq 1 ]; then
entries=""
# filter
else
# remove lines below found
lastprinted="$((lastline - 1))"
entries=$(echo "$entries" | sed -n "1,${lastprinted}p;${lastline}q")
fi
}
filter_priority() {
priority="$1"
# filter for dates, with line numbers
# filtered=$(echo "$entries" | grep -noE '[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}')
filtered=""
while [ "$priority" -gt 0 ]; do
current=$(echo "$entries" | grep -E "\($priority\)")
# append found to filtered entries
filtered=$(printf "%s\n%s" "$filtered" "$current")
# go to next 'higher' priority
priority="$((priority - 1))"
done
# sort them chronologically again, remove empty lines
entries="$(echo "$filtered" | sed -e '/^$/d' | sort)"
}
main() {
if [ -z "$file" ]; then
echo "Requires a bibtex file as argument."
exit 1
fi
# filter all entries for those containing filterby field (default: due)
# retain values of all fields mentioned in fields variable
entries=$(grep -E "^@|$fields" "$file" | awk 1 ORS=' ' | sed -E 's/@\w+\{/\n/g' | grep "$filterby" | tail -n +2 | sed -E 's/(,\s+(\w+)\s+=\s+|,\s*$)/\t/g' | awk -F'\t' '{ print $4 "\t" $5 "\t" $2 "\t" $3 "\t" $1 }')
# prettify and sort the entries for display (remove {}, order by date,prio,author,title)
entries=$(echo "$entries" | awk -F'\t' '{ gsub(/{/,""); gsub(/}/,""); gsub(/prio/,"",$2) } { print $1 " (" $2 "): " $3 " -- " $4 " (" $5 ")"}' | sort)
if [ -n "$until" ]; then
filter_until
fi
if [ -n "$priority" ]; then
filter_priority "$priority"
fi
echo "$entries"
}
while getopts "h?i:u:r:l:p:" opt; do
case "$opt" in
h | \?)
show_help
exit 0
;;
# v) verbose=1
# ;;
r)
fields="$OPTARG"
;;
l)
filterby="$OPTARG"
;;
i)
file="$OPTARG"
;;
u)
until="$(date -d "$OPTARG" +%s)"
;;
p)
priority="$OPTARG"
;;
esac
done
shift $((OPTIND - 1))
[ "${1:-}" = "--" ] && shift
main "$@"

29
bibtex/.local/bin/rofi-bib-due Executable file
View file

@ -0,0 +1,29 @@
#!/usr/bin/env sh
exist rofi normal
_rofi() {
rofi -dmenu -no-auto-select -i -theme themes/dropdown -p "papers" -l 25 -yoffset 20 -columns 1 -u "$urgent"
}
# call for whatever file is passed in
results="$(bib-due "$@")"
# mark priority 1 items as urgent in rofi
urgent="$(
# find all lines with priority 1, (marked as `(1):` );
# print them on 1 line, -1 since dmenu is 0 indexed
echo "$results" | grep -n '(1):' | cut -d: -f1 | awk '{ $0=$0-1; print $0 }' ORS=','
)"
# get user choice, exit if nothing selected
choice=$(echo "$results" | _rofi)
[ -z "$choice" ] && exit 0
key=$(echo "$choice" | sed -E 's/.*\((\w+)\)$/\1/')
# get library pdf folder (only searches for default ./pdf path)
library="$(dirname "$(realpath "$BIBFILE")")/pdf"
# find and open the key-associated pdf file
${FILEREADER:-xdg-open} "$(find "$library" -type f -name "$key *.pdf")"

59
bibtex/README.md Normal file
View file

@ -0,0 +1,59 @@
# Bibtex module
[bibtex](https://en.wikipedia.org/wiki/BibTeX) - plain-text reference management
## bib-due
The `bib-due` script depends on (gnu) grep, awk, and sed, date if using date filtering capabilities. It is currently written in a rather haphazard way, and prone to breakage.
On the other hand, it does what it's supposed to do: list bibtex entries which have their due-date coming up.
The script needs bibtex entries to be marked with two fields: `due`, containing a due date (ideally in YYYY-MM-DD format, for easy sorting), and `priority` containing a read priority. It will also, by default attempt to grab the values of the fields `author` and `title`, as well as the name of the bibtex key of the entry.
It can be invoked with the path to a bibtex file `bib-due path/to/library.bib`, and will gather the entries from the respective file. It can be invoked without an argument if the environment variable `$BIBFILE` is declared (pointing to a bibtex file).
Example output looks as follows:
![bib-due example output](.assets/bibtex/list.png)
The output can then be filtered further through other programs.
Bib-due itself allows 2 filtering options: *until* a certain date (`-u`), and *at least* a certain priority (`-p`).
Using priority is relatively self-explanatory: 1 is the highest priority, 3 the lowest (technically, no priority is the lowest). Choosing `-p3` means priority 1, 2, and 3 will be displayed. Choosing `-p1` will only display the highest priority items.
Using the date works as a cut-off for the future, and it uses gnu `date` to calculate the correct date. That makes things like `-u 'fri this week'` possible, showing only upcoming items until the end of the week. Read the `date` manual for more information.
There will likely not be a new option for filtering dates *from* a certain point forward since I don't need it and before implementing more stuff what's there should be more solid. (and read your damn overdue texts!)
Again, this script will (for now[^time]) break when bibtex files are formatted in any way other than what it expects.
An example of a working entry:
[^time]: And probably for some time since I don't see myself sinking too much more time into this in the near future. I actually need to get some of the upcoming readings done that I can now list! 🙂
```
@InBook{Borhi2016,
author = {László Borhi},
chapter = {1956: Self-Liberation},
pages = {117--137},
publisher = {Indiana University Press},
title = {Dealing with dictators: the {United States}, {Hungary}, and {East Central Europe}, 1942-1989},
year = {2016},
due = {2020-05-07},
file = {:Borhi2016 - Dealing with Dictators_ the United States, Hungary, and East Central Europe, 1942 1989.pdf:PDF},
pagetotal = {564},
priority = {prio1},
timestamp = {2020-05-08},
}
```
Important fields are author, title, due, priority. These need to exist, and need to be ordered alphabetically. Otherwise there will probably be some breakage.
## rofi-bib-due
The `rofi-bib-due` script utilizes the `bib-due` script and depends on an existing installed `rofi` module (see [here](rofi/)).
On invocation, it creates a list of upcoming readings, and allows selecting one of the readings. The selected reading will be passed along to `$FILEREADER` if it is declared, falling back to `xdg-open` if not.
Currently, the path to the reading pdf is hard-coded to be `path/to/bibtex.bib/pdf`, and the name has to begin with the exact bibtex key; otherwise the script will not be able to find the pdf.
An example of the script in action: (window size has been reduced for the recording, cutting off most entry names)
![rofi-bib-due demonstration](.assets/bibtex/rofi.gif)

View file

@ -17,10 +17,8 @@
;==========================================================
[colors]
;background = ${xrdb:color0:#222}
background = ${xrdb:background}
background-alt = ${xrdb:color8}
;foreground = ${xrdb:color7:#222}
foreground = ${xrdb:foreground}
foreground-alt = ${xrdb:color3}
primary = ${xrdb:color1}
@ -46,6 +44,10 @@ margin-top = 0
margin-bottom = 0
[bar/simple-top]
; enable inter process communication, so that we can send messages
; to polybar via polybar-msg command
enable-ipc = true
; Put the bar at the bottom of the screen
bottom=false
@ -56,7 +58,7 @@ padding-right = 0
module-margin-left = 2
modules-left = workspaces
modules-center = mprisdisplay date
modules-center = music date papersdue
modules-right = networkspeed archupdates cpu temp backlight volume battery
; do not use offsets for the bar, would only work with override-redirect
; and will mess up tray https://github.com/polybar/polybar/issues/1355
@ -85,7 +87,7 @@ fixed-center = true
; See the Fonts wiki page for more details
font-0 = Comic Neue
font-1 = NotoSans
font-2 = Iosevka:size=18
font-2 = Iosevka:size=18;1
cursor-click = pointer
@ -177,12 +179,12 @@ interval = 1.0
; To list all the zone types, run
; $ for i in /sys/class/thermal/thermal_zone*; do echo "$i: $(<$i/type)"; done
; Default: 0
thermal-zone = 0
thermal-zone = 2
; Use `sensors` to find preferred temperature source, then run
; $ for i in /sys/class/hwmon/hwmon*/temp*_input; do echo "$(<$(dirname $i)/name): $(cat ${i%_*}_label 2>/dev/null || echo $(basename ${i%_*})) $(readlink -f $i)"; done
; hwmon-path = /sys/devices/platform/coretemp.0/hwmon/hwmon0/temp1_input
; Base temperature for where to start the ramp (in degrees celsius)
base-temperature = 40
base-temperature = 50
; Threshold temperature to display warning label (in degrees celsius)
warn-temperature = 70
units = true
@ -209,26 +211,44 @@ date-alt = %A, %d %B %Y (W %V)
time-alt = %H:%M
label = %date% %{T2} %{T-}%time%
; display information on currently playing track, allows simple track manipulation
[module/music]
type = custom/script
exec = $XDG_CONFIG_HOME/polybar/scripts/poly-mprisdisplay
exec-if = type $XDG_CONFIG_HOME/polybar/scripts/poly-mprisdisplay
tail = true
click-left = kill -USR1 %pid%
click-right = kill -USR2 %pid%
; TODO: add album art display (on click?) - retrieved by playerctl metadata mpris:artUrl
; display information on remaining papers to read for the upcoming week
[module/papersdue]
type = custom/script
exec = $XDG_CONFIG_HOME/polybar/scripts/poly-papersdue
exec-if = type bib-due
tail = true
click-left = exist rofi-bib-due normal "opening due papers" && rofi-bib-due -p1 -u $(date --date='fri this week' +%Y-%m-%d)
; format-foreground = ${colors.primary}
format-prefix = " "
interval = 120
; display unified available packages for update on arch from repos/aur
; uses pacman-contrib/checkupdates if available to avoid partial arch upgrades
[module/archupdates]
type = custom/script
exec = $XDG_CONFIG_HOME/polybar/scripts/poly-archupdates
exec-if = type $XDG_CONFIG_HOME/polybar/scripts/poly-archupdates
interval = 600
format = <label>
format-foreground = ${colors.primary}
label = %output%
format-padding = 2
format-prefix = " "
; format-foreground = ${colors.primary}
[module/networkspeed]
type = custom/script
exec = $XDG_CONFIG_HOME/polybar/scripts/poly-networkspeed
tail = true
[module/mprisdisplay]
type = custom/script
exec = $XDG_CONFIG_HOME/polybar/scripts/poly-mprisdisplay
interval = 3
click-left = playerctl play-pause &
; TODO: add album art display (on click?) - retrieved by playerctl metadata mpris:artUrl
[module/volume]
type = internal/pulseaudio
; Available tags:

View file

@ -5,7 +5,7 @@
# returns empty string when 0 packages are available, so
# that polybar simply displays nothing.
#
# dependendies: yay, bc, (pacman-contrib optional)
# dependendies: yay, (pacman-contrib optional)
# prefer checkupdates since it allows checking w/o partial upgrade
if command -v "checkupdates" >/dev/null; then
@ -21,7 +21,7 @@ updates_aur="$(yay -Qum 2>/dev/null | wc -l)"
# if ! updates_aur=$(pikaur -Qua 2> /dev/null | wc -l); then
# if ! updates_aur=$(rua upgrade --printonly 2> /dev/null | wc -l); then
updates="$(echo "$updates_repo + $updates_aur" | bc)"
updates="$((updates_repo + updates_aur))"
if [ "$updates" -gt 0 ]; then
echo "$updates"

View file

@ -1,11 +1,47 @@
#!/bin/sh
# script to echo the current playback situation
#
# call without args to return playing symbol or empty, depending on current playback status
# call with 1 to return 'artist - title' metadata (verbose mode)
# send SIGUSR2 signal to toggle pause/playing state of song (e.g. kill -USR2 %PID)
#
# depends on playerctl being installed
player_status=$(playerctl status 2>/dev/null)
exist playerctl low "polybar music" || exit 1
if [ "$player_status" = "Playing" ]; then
echo "ﱘ $(playerctl metadata artist) - $(playerctl metadata title)"
elif [ "$player_status" = "Paused" ]; then
echo " $(playerctl metadata artist) - $(playerctl metadata title)"
else
mode=${1:-0}
update_time=1
symbol_playing=""
symbol_paused=""
modetoggle() {
mode=$(((mode + 1) % 2))
}
trap "modetoggle" USR1
playpause() {
playerctl play-pause
}
trap "playpause" USR2
decorate() {
if [ "$player_status" = "Playing" ]; then
echo "${symbol_playing}$1"
elif [ "$player_status" = "Paused" ]; then
echo "${symbol_paused}$1"
else
echo ""
fi
fi
}
while true; do
player_status=$(playerctl status 2>/dev/null)
if [ $mode -eq 0 ]; then
decorate ""
elif [ $mode -eq 1 ]; then
decorate " $(playerctl metadata artist) - $(playerctl metadata title)"
fi
sleep $update_time &
wait
done

View file

@ -0,0 +1,15 @@
#!/usr/bin/env sh
while true; do
all="$(bib-due -u "$(date --date='fri this week' +%Y-%m-%d)" | wc -l)"
required="$(bib-due -u "$(date --date='fri this week' +%Y-%m-%d)" -p1 | wc -l)"
# add polybar formatting to color required readings red
# https://github.com/polybar/polybar/wiki/Formatting#format-tags
# TODO use xresources
colorreq=$(xrdb -query | grep -e '\*color1:' | cut -f2)
colorall=$(xrdb -query | grep -e '\*foreground:' | cut -f2)
printf "%s%s%s(%s)\n" "%{F${colorall:-#000}}" "$all" "%{F${colorreq:-#d00}}" "$required"
sleep 120
done

View file

@ -1,4 +1,6 @@
#!/usr/bin/env bash
# force start or restart (all) polybar instances
# if ipc is enabled, can be replaced with `polybar-msg cmd restart`, provided polybar is not stuck
# Terminate already running bar instances
killall -q polybar

85
polybar/README.md Normal file
View file

@ -0,0 +1,85 @@
# Polybar module
[polybar](https://polybar.github.io/) - a fast and easy-to-use statusbar
[[_TOC_]]
## Polybar look
minimal look:
![minimal](.assets/polybar/minimal.png)
Active i3 workspaces are displayed left with current workspace highlighted, and any active i3 modes. The center contains information on the currently playing song, displaying notes if something is playing, date and time, and upcoming bib readings from the library. The right contains system information and the task tray.
with network activity:
![network](.assets/polybar/network.png)
full-load and temperature warning:
![full](.assets/polybar/full.png)
In general, the bar's colors are derived from the colors defined in xresources. It follows the base16 color template, as does every module in these dotfiles. That means the bar can be quickly re-themed using base16 color themes and the process can be automated (e.g. with styler).
## i3 Workspaces
![normal](.assets/polybar/i3-normal.png) -- focus on workspace 4
The i3 workspaces module is pretty simple and self-explanatory. It shows all existing workspaces, and highlights the one that is currently active. It also highlights any workspaces on which an event took place.
![highlight](.assets/polybar/i3-highlight.png) -- focus on workspace 2, workspace 1 highlighted
Additionally, if an i3 mode is active, it will be displayed next to the workspaces in a stark color to notice the mode being active.
![mode](.assets/polybar/i3-mode.png) -- focus on workspace 3, 'Media' mode active
Workspaces can be cycled with the mouse-wheel when hovering over the module, or can be invoked by clicking on the icons.
## Current track information
By default, the track information panel is very minimal. It simply displays a note when something is currently playing, a pause symbol when the current track is pause, and nothing at all when no track is currently available. (no media player open, all tracks stopped, etc.)
When clicked, the track metadata is revealed, displaying track artist and title. Another click toggles it off again.
![mpris](.assets/polybar/mpris.png)
When right-clicked, the current track can be toggled between playing and paused.
The `poly-mprisdisplay` script implementation requires `playerctl` available on the system to be run. It will return with an error message if the binary is not found. Symbols used can be easily customized in the script.
## Date
The standard polybar date display. Displays current date (DD/MM) and current time (24-hours) by default. On click, toggles to an expanded date display with current weekday and current week of the year.
![clock](.assets/polybar/clock.png)
![extended clock](.assets/polybar/clock_alt.png)
## Upcoming Bibtex readings
Depends on the [`bibtex`](bibtex/) module being installed, more specifically:
* the `bib-due` script accessible as a program
* a `$BIBFILE` environment variable pointing to the bibtex library (or at least, the relevant library of the system)
* optionally: `rofi` (or `dmenu`) to enable listing of readings on click
Displays the library readings remaining for the week in simple numerical fashion. On click invokes the full `bib_due` script to show further information on the upcoming readings, requiring either `dmenu` or `rofi` to display them.
## System information
Contains various system-relevant details.
![system info](.assets/polybar/system.png)
If the network has activity, it shows upload and download speeds (dynamically switching between displaying Kb/s, Mb/s). The script `poly-networkspeed` as of now uses hard-coded network interface names. If network interfaces have a different name, this will need to be adjusted.
If updates for arch packages are available (from repositories or aur) it displays the number of available updates. The script `poly-archupdates` requires `yay` to be available. If checkupdates is available it will use this to check for repo packages, which can avoid partial arch updates in rare circumstances. (contained in `pacman-contrib` package)
The volume module simply displays the current pulseaudio volume as a ramped version of the volume symbol. On click it toggles mute and un-mute.
If xbacklight is available, the current display brightness is displayed as a symbol between a moon (dark) and a sun (bright).
If a battery is available, it will display its current status, percentage, and whether it is charging.
The cpu load is displayed as a simple vertical bar, changing color at specific intervals to be more noticeable. When the cpu gets warm, a temperature warning will be displayed, along with current numeric temperature value (in °C). The correct sensor may have to be changed in the polybar config file; as well as useful limits for the display of temperature information.

View file

@ -0,0 +1,17 @@
/**
* This theme is intended for a full-width dropdown. It will dynamically resize, depending on the amount of list items.
*/
@import "./layouts/list-vertical-dynamic.rasi"
#window {
width: 100%;
location:north;
anchor:north;
}
#listview {
dynamic: true;
fixed-height: false;
}

View file

@ -0,0 +1,18 @@
/**
* This theme is intended for a normal vertical list, which can fill the width of the screen.
*/
@import "../settings.rasi"
#window {
padding: 5;
}
#listview {
layout: vertical;
spacing: @option-5-listview-spacing;
}
#element {
padding: 10;
}