Uma das principais ideias do GTD é a associação de contexto à cada tarefa para que seja muito fácil ver quais tarefas podem ser feitas no contexto atual. Eu organizo minhas tarefas com o Taskwarrior, então para utilizar contextos com ele, quando eu adiciono uma nova tarefa eu preciso vinculá-la a um contexto e também atualizar o contexto sempre que ele mudar. Há diferentes tipos de contexto, mas os mais fáceis de automatizar são os espaciais, ou seja, quais tarefas eu posso fazer onde eu estou nesse momento.
Para vincular uma tarefa a um contexto basta adicionar um rótulo a ela. Como eu
normalmente estou em um de três lugares, eu adiciono o rótulo @rep
, @sp
ou @uni
dependendo de onde a tarefa pode ser feita.
Já para atualizar o contexto atual eu precisaria indicar manualmente para o
Taskwarrior onde eu estou no momento toda vez que eu for para um outro lugar.
Por exemplo, eu precisaria digitar task context uni
toda vez que eu fosse
para a universidade. Isso além de ser bem chato é uma fonte de erros: já
aconteceu mais de uma vez de eu levar alguns segundos até entender porque
algumas tarefas estavam faltando.
Mas como todo pequeno problema na vida, isso pode ser solucionado com um pequeno script. E é por isso que eu escrevi um script em python para detectar e configurar automaticamente o contexto atual do Taskwarrior.
Script em python
A ideia é bem simples: eu quase sempre estou conectado a uma rede sem fio, já que essa conexão é automática, e cada local tem um nome específico para a rede, então eu só preciso obter o SSID da rede atual e configurar o contexto correspondente.
É isso que o seguinte programa em python faz (além de mandar uma notificação
usando notify-send
):
import subprocess
contexts = {
'rep': ["rep wifi 1", "rep wifi 2", "rep wifi 3"],
'sp': ["sp wifi 1", "sp wifi 2"],
'uni': ["eduroam"]
}
def get_context(wifi):
for context in contexts:
if wifi in contexts[context]:
return context
return None
def get_current_context():
wifi_cmd = subprocess.run(["iwgetid", "-r"], text=True, capture_output=True)
wifi = wifi_cmd.stdout.split('\n')[0]
return get_context(wifi)
def set_current_context():
context = get_current_context()
if context:
subprocess.run(["notify-send", "Taskwarrior context",
f"Setting context to <b>{context}</b>"])
subprocess.run(["task", "context", context])
else:
subprocess.run(["notify-send", "-u", "critical", "Taskwarrior context",
"Failure to detect context"])
subprocess.run(["task", "context", "none"])
Obs: Os nomes das redes dos contextos rep
e sp
foram censurados para
evitar exposição.
Serviço do systemd
Já que quando eu vou de um lugar para o outro eu sempre suspendo, hiberno ou desligo meu computador, esse programa só precisa executar depois de resumir ou ligar o computador, e é exatamente para isso que serve o seguinte serviço do systemd:
[Unit]
Description=Set taskwarrior context
Wants=network-online.target NetworkManager-wait-online.service
After=network-online.target NetworkManager-wait-online.service hibernate.target suspend.target
[Service]
User=%I
Type=oneshot
Environment=PATH=/usr/bin:/home/nfraprado/ark/code/.path/
Environment=DISPLAY=:0
Environment=XAUTHORITY=%h/.Xauthority
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
ExecStartPre=/usr/bin/sleep 30
ExecStart=/home/nfraprado/ark/code/.path/taskwarrior-update_context
ExecStartPost=
[Install]
WantedBy=multi-user.target
WantedBy=hibernate.target
WantedBy=suspend.target
Detalhes sobre esse arquivo de serviço:
- Os serviços
network-online
ewait-online
supostamente fazem com que ele espere o NetworkManager conectar a uma rede antes de executar, mas pelos meus testes isso não foi o suficiente e portanto eu acabei adicionando 30 segundos de atraso como pode ser visto emExecStartPre
. - Os alvos
hibernate
esuspend
fazem com que ele rode depois do computador resumir ou ligar. - As variáveis de ambiente
DISPLAY
,XAUTHORITY
eDBUS_SESSION_BUS_ADDRESS
permitem que a notificação apareça. taskwarrior-update_context
basicamente chamaset_current_context()
do script em python.
E é isso! Com esses dois componentes, depois que eu vou de um lugar para o outro e abro meu computador, o contexto do Taskwarrior é automaticamente atualizado, me mostrando só as tarefas relevantes para o lugar que estou atualmente.
Extra: Script anterior
Uma pequena tangente: antes daquele script em python, eu tinha feito um em bash.
Apesar de executar comandos no bash ser mais limpo do que o subprocess.run()
do python, eu acho a sintaxe do bash horrível. Eu também acho ridículo precisar
definir uma função array_contains
(que eu copiei de alguma resposta do
StackOverflow). Enfim, esse era o script em bash caso esteja com curiosidade:
#!/bin/bash
wifi="$(iwgetid -r)"
declare -a rep=("rep wifi 1" "rep wifi 2" "rep wifi 3")
declare -a sp=("sp wifi 1" "sp wifi 2")
declare -a uni=("eduroam")
array_contains () {
local array="$1[@]"
local seeking=$2
local in=1
for element in "${!array}"; do
if [[ $element == $seeking ]]; then
in=0
break
fi
done
return $in
}
array_contains rep "$wifi" && context=rep
array_contains sp "$wifi" && context=sp
array_contains uni "$wifi" && context=uni
if [ -z "$context" ];then
notify-send -u critical "Taskwarrior context" "Failure to detect context"
task context none >/dev/null 2>&1
else
notify-send "Taskwarrior context" "Setting context to <b>$context</b>"
task context $context >/dev/null 2>&1
fi