Nonatomic
This commit is contained in:
parent
074a7f21ab
commit
d54d749a86
|
@ -6,6 +6,25 @@ if [[ -z "$TMUX" ]] {
|
|||
exec tmux;
|
||||
}
|
||||
}
|
||||
|
||||
# Prompt
|
||||
function default_host () {
|
||||
H="${HOST}%{%}:"
|
||||
REPLY=${H/apollo%{%}:/}
|
||||
REPLY=${REPLY/.olymp.space/}
|
||||
echo $REPLY
|
||||
}
|
||||
function default_user () {
|
||||
U=${USER}@
|
||||
REPLY=${U/maralorn@/}
|
||||
echo $REPLY
|
||||
}
|
||||
|
||||
|
||||
setopt prompt_subst
|
||||
autoload -U colors && colors # Enable colors in prompt
|
||||
PROMPT='%{%F{red}%}$(default_user)$(default_host)%{%F{blue}%}%~%{%}> %{%f%}'
|
||||
|
||||
precmd() {
|
||||
local s=$? c=( $(fc -L -D -l -1) )
|
||||
if [[ $launched && "${c[2]}" != "0:00" ]] {
|
||||
|
@ -22,10 +41,14 @@ alias m=man
|
|||
alias t="tmux attach"
|
||||
alias tn="tmux new-session"
|
||||
alias w="develop-here"
|
||||
alias ls=exa
|
||||
alias ls='exa -lh --git'
|
||||
|
||||
export BROWSER=qutebrowser
|
||||
export EDITOR=nvim
|
||||
export MANPAGER="most -s"
|
||||
autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
|
||||
add-zsh-hook chpwd chpwd_recent_dirs
|
||||
zstyle ':chpwd:*' recent-dirs-max 25
|
||||
|
||||
if [[ $PWD == "$HOME" ]] {
|
||||
cd "$(head -n1 ~/.chpwd-recent-dirs | sed s/\\$// | sed s/\'//g)"
|
||||
}
|
||||
|
||||
bindkey '^R' history-incremental-pattern-search-backward
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
{ pkgs, ... }:
|
||||
{ pkgs, config, ... }:
|
||||
let
|
||||
rust-scripts = with pkgs; callPackage ../packages/rust-scripts {};
|
||||
unstable-pkgs = import <unstable> {};
|
||||
eventd = unstable-pkgs.callPackage ../packages/eventd {};
|
||||
st = import graphical/st;
|
||||
in {
|
||||
nixpkgs.config.packageOverrides = pkgs: {
|
||||
eventd = eventd;
|
||||
st = st pkgs config.common.colors;
|
||||
};
|
||||
home.file.".tmux.conf".text = ''
|
||||
set -g default-terminal "st-256color"
|
||||
set -ga terminal-overrides ",st-256color:Tc"
|
||||
set -g history-limit 50000
|
||||
set -g status off
|
||||
set -g escape-time 1
|
||||
'';
|
||||
programs = {
|
||||
home-manager = {
|
||||
enable = true;
|
||||
|
@ -46,7 +60,7 @@ in {
|
|||
treeView = true;
|
||||
};
|
||||
ssh = {
|
||||
controlMaster = "autoask";
|
||||
controlMaster = "yes";
|
||||
enable = true;
|
||||
matchBlocks = let
|
||||
matheGwProxy = "ssh -q gw nc -q0 %h %p";
|
||||
|
@ -55,16 +69,16 @@ in {
|
|||
in [
|
||||
{ host = "charon"; hostname = "charon.olymp.space"; }
|
||||
{ host = "*.olymp.space"; user = "maralorn"; }
|
||||
{ host = "ag-forward"; hostname = agHost; proxyCommand = matheGwProxy; }
|
||||
{ host = "ag"; hostname = agHost; }
|
||||
{ host = "kiva-forward"; hostname = kivaHost; proxyCommand = matheGwProxy; }
|
||||
{ host = "kiva"; hostname = kivaHost; }
|
||||
{ host = "gw"; hostname = "gwres4.mathematik.tu-darmstadt.de"; }
|
||||
{ host = "*.mathematik.tu-darmstadt.de"; user = "brandy"; }
|
||||
{ host = "ag-forward"; hostname = agHost; proxyCommand = matheGwProxy;user="brandy";}
|
||||
{ host = "ag"; hostname = agHost;user="brandy";}
|
||||
{ host = "kiva-forward"; hostname = kivaHost; proxyCommand = matheGwProxy;user="brandy";}
|
||||
{ host = "kiva"; hostname = kivaHost;user="brandy";}
|
||||
{ host = "gw"; hostname = "gwres4.mathematik.tu-darmstadt.de";user="brandy";}
|
||||
{ host = "shells"; hostname = "shells.darmstadt.ccc.de"; }
|
||||
{ host = "vorstand"; hostname = "vorstand.darmstadt.ccc.de"; }
|
||||
{ host = "*.darmstadt.ccc.de"; user = "maralorn"; }
|
||||
{ host = "whisky"; hostname = "whisky.w17.io"; user = "chaos"; }
|
||||
{ host = "door.w17.io"; identityFile = "~/.ssh/door_rsa";}
|
||||
];
|
||||
};
|
||||
zsh = {
|
||||
|
@ -76,9 +90,20 @@ in {
|
|||
size = 100000;
|
||||
};
|
||||
initExtra = builtins.readFile ./configs/zshrc;
|
||||
oh-my-zsh = {
|
||||
enable = true;
|
||||
plugins = [ "colored-man-pages" "git-prompt" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
home.sessionVariables = {
|
||||
BROWSER="${pkgs.firefox}/bin/firefox";
|
||||
EDITOR="${pkgs.neovim}/bin/nvim";
|
||||
TERMINAL=config.common.terminal;
|
||||
};
|
||||
systemd.user.startServices = true;
|
||||
|
||||
imports = [
|
||||
|
@ -101,6 +126,7 @@ in {
|
|||
tig
|
||||
exa
|
||||
fzf
|
||||
ag
|
||||
|
||||
pythonPackages.qrcode
|
||||
ranger
|
||||
|
|
|
@ -19,7 +19,7 @@ in {
|
|||
"leisure"
|
||||
"config"
|
||||
];
|
||||
terminal = "urxvt";
|
||||
terminal = "${pkgs.st}/bin/st";
|
||||
colors = {
|
||||
"foreground" = "#dddbff";
|
||||
"background" = "#05004a";
|
||||
|
@ -44,6 +44,7 @@ in {
|
|||
home = {
|
||||
packages = with pkgs; [
|
||||
tasktree
|
||||
st
|
||||
];
|
||||
keyboard = {
|
||||
layout = "de";
|
||||
|
@ -73,7 +74,6 @@ in {
|
|||
enable = true;
|
||||
components = [
|
||||
"secrets"
|
||||
"ssh"
|
||||
];
|
||||
};
|
||||
random-background = {
|
||||
|
@ -83,6 +83,9 @@ in {
|
|||
};
|
||||
gpg-agent = {
|
||||
enable = true;
|
||||
enableSshSupport = true;
|
||||
defaultCacheTtl = 900;
|
||||
defaultCacheTtlSsh = 900;
|
||||
};
|
||||
redshift = {
|
||||
enable = true;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
eventd-pkgs = import (fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/fe61c3b84e8e81a8ec2bf6b3ed2a0e8652cea190.tar.gz) {};
|
||||
eventd = eventd-pkgs.callPackage ../../packages/eventd {};
|
||||
colors = config.common.colors;
|
||||
in {
|
||||
home = {
|
||||
|
@ -23,8 +21,8 @@ in {
|
|||
Service = {
|
||||
Type="notify";
|
||||
Sockets="eventd-control.socket eventd.socket";
|
||||
ExecStart="${eventd}/bin/eventd --listen systemd";
|
||||
ExecReload="${eventd}/bin/eventdctl reload";
|
||||
ExecStart="${pkgs.eventd}/bin/eventd --listen systemd";
|
||||
ExecReload="${pkgs.eventd}/bin/eventdctl reload";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -58,21 +56,6 @@ in {
|
|||
Spacing = 2;
|
||||
Limit = 10;
|
||||
};
|
||||
"Queue mode" = {
|
||||
Anchor = "top";
|
||||
Margin = 300;
|
||||
Limit = 1;
|
||||
};
|
||||
"Queue feedback" = {
|
||||
Anchor = "top";
|
||||
Margin = 450;
|
||||
Limit = 1;
|
||||
};
|
||||
"Queue workspace" = {
|
||||
Anchor = "bottom-left";
|
||||
Margin = 10;
|
||||
Limit = 1;
|
||||
};
|
||||
"Queue command" = {
|
||||
Anchor = "bottom-right";
|
||||
Margin = 10;
|
||||
|
@ -81,20 +64,15 @@ in {
|
|||
};
|
||||
"Queue critical" = {
|
||||
Anchor = "top";
|
||||
Margin = 10;
|
||||
Margin = 450;
|
||||
Spacing = 2;
|
||||
Limit = 10;
|
||||
};
|
||||
"Queue state" = {
|
||||
Anchor = "top-left";
|
||||
Margin = 10;
|
||||
Spacing = 2;
|
||||
Limit = 10;
|
||||
};
|
||||
"Queue music" = {
|
||||
"Queue tasks" = {
|
||||
Anchor = "bottom";
|
||||
Margin = 10;
|
||||
Limit = 1;
|
||||
Margin = 0;
|
||||
Spacing = 1;
|
||||
Limit = 20;
|
||||
};
|
||||
Notification = {
|
||||
Text = "\${message}";
|
||||
|
@ -113,17 +91,11 @@ in {
|
|||
};
|
||||
};
|
||||
"eventd/notification.event".text = lib.generators.toINI {} {
|
||||
"Event mode *" = {
|
||||
Actions = "mode";
|
||||
};
|
||||
"Event notification *" = {
|
||||
Actions = "notification";
|
||||
};
|
||||
"Event feedback *" = {
|
||||
Actions = "feedback";
|
||||
};
|
||||
"Event workspace *" = {
|
||||
Actions = "workspace";
|
||||
"Event notification kassandra" = {
|
||||
Actions = "kassandra";
|
||||
};
|
||||
"Event command success" = {
|
||||
Actions = "command-success";
|
||||
|
@ -134,25 +106,6 @@ in {
|
|||
"Event critical *" = {
|
||||
Actions = "critical";
|
||||
};
|
||||
"Event state *" = {
|
||||
Actions = "state";
|
||||
};
|
||||
};
|
||||
"eventd/mode.action".text = lib.generators.toINI {} {
|
||||
Action = {
|
||||
Name = "mode";
|
||||
};
|
||||
Notification = {
|
||||
};
|
||||
NotificationBubble = {
|
||||
Timeout = 0;
|
||||
Queue = "mode";
|
||||
Padding = 40;
|
||||
MinWidth = 10;
|
||||
};
|
||||
NotificationText = {
|
||||
Font = "Linux Libertine 40";
|
||||
};
|
||||
};
|
||||
"eventd/command-success.action".text = lib.generators.toINI {} {
|
||||
Action = {
|
||||
|
@ -163,6 +116,7 @@ in {
|
|||
};
|
||||
NotificationBubble = {
|
||||
Colour = colors.black;
|
||||
Queue = "command";
|
||||
};
|
||||
};
|
||||
"eventd/command-failure.action".text = lib.generators.toINI {} {
|
||||
|
@ -173,30 +127,31 @@ in {
|
|||
Text="<b>\${command}</b>\\nfailed after \${time} @ \${host}";
|
||||
};
|
||||
NotificationBubble = {
|
||||
Queue = "critical";
|
||||
Colour = colors.red;
|
||||
};
|
||||
};
|
||||
"eventd/workspace.action".text = lib.generators.toINI {} {
|
||||
"eventd/critical.action".text = lib.generators.toINI {} {
|
||||
Action = {
|
||||
Name = "workspace";
|
||||
Name = "critical";
|
||||
};
|
||||
Notification = {
|
||||
Text = "<b>\${title}</b>\${message/^/\\n}";
|
||||
};
|
||||
NotificationBubble = {
|
||||
Queue = "workspace";
|
||||
MinWidth = 10;
|
||||
Queue = "critical";
|
||||
Colour = colors.red;
|
||||
};
|
||||
};
|
||||
"eventd/feedback.action".text = lib.generators.toINI {} {
|
||||
"eventd/kassandra.action".text = lib.generators.toINI {} {
|
||||
Action = {
|
||||
Name = "feedback";
|
||||
Name = "kassandra";
|
||||
};
|
||||
Notification = {
|
||||
Text = "<b>\${title}</b>\${message/^/\\n}";
|
||||
};
|
||||
NotificationBubble = {
|
||||
Timeout = 500;
|
||||
Queue = "feedback";
|
||||
Colour = colors.red;
|
||||
Queue = "critical";
|
||||
};
|
||||
};
|
||||
"eventd/notification.action".text = lib.generators.toINI {} {
|
||||
|
|
|
@ -4,6 +4,18 @@ let
|
|||
workspaces = config.common.workspaces;
|
||||
terminal = config.common.terminal;
|
||||
exec = "exec --no-startup-id";
|
||||
taskstatus = pkgs.writeShellScriptBin "taskstatus" ''
|
||||
while true;
|
||||
do
|
||||
echo \
|
||||
$(date "+%Y-%m-%d %a %H:%M") "|" \
|
||||
$(cat ~/.kassandra_state | tail -n3 | sed "s/$/ | /") \
|
||||
Inbox: $(task +PENDING -BLOCKED -TAGGED count) "|" \
|
||||
Active Task: $(task rc.verbose=nothing active || echo "No task active") "|" \
|
||||
Tags: $(task +PENDING -BLOCKED -project -optional -later rc.verbose=nothing tags | sed "s/\(.\)$/\1 |/" )
|
||||
sleep 10s;
|
||||
done
|
||||
'';
|
||||
addMods = oldbindings: builtins.foldl' (newbindings: key:
|
||||
newbindings // {
|
||||
"Mod4+${key}" = oldbindings.${key};
|
||||
|
@ -12,7 +24,7 @@ let
|
|||
{}
|
||||
(builtins.attrNames oldbindings);
|
||||
in {
|
||||
imports = [
|
||||
imports = [
|
||||
./eventd.nix
|
||||
./rofi
|
||||
./urxvt.nix
|
||||
|
@ -56,7 +68,18 @@ in {
|
|||
text = colors.foreground;
|
||||
};
|
||||
};
|
||||
bars = [ {
|
||||
bars = [
|
||||
{
|
||||
statusCommand = "${taskstatus}/bin/taskstatus";
|
||||
position = "top";
|
||||
mode = "dock";
|
||||
workspaceButtons = false;
|
||||
colors = {
|
||||
separator = colors.white;
|
||||
background = colors.background;
|
||||
};
|
||||
}
|
||||
{
|
||||
mode = "hide";
|
||||
colors = {
|
||||
separator = colors.white;
|
||||
|
@ -87,28 +110,32 @@ in {
|
|||
titlebar = false;
|
||||
border = 1;
|
||||
};
|
||||
gaps = {
|
||||
inner = 0;
|
||||
outer = 0;
|
||||
smartBorders = "off";
|
||||
smartGaps = false;
|
||||
};
|
||||
keybindings = addMods ({
|
||||
# gaps = {
|
||||
# inner = 0;
|
||||
# outer = 0;
|
||||
# smartBorders = "off";
|
||||
# smartGaps = false;
|
||||
# };
|
||||
keybindings = {
|
||||
"XF86AudioMute" = "exec pactl set-sink-mute '@DEFAULT_SINK@' toggle";
|
||||
"XF86AudioLowerVolume" = "exec pactl set-sink-volume '@DEFAULT_SINK@' -5%";
|
||||
"XF86AudioRaiseVolume" = "exec pactl set-sink-volume '@DEFAULT_SINK@' +5%";
|
||||
"XF86AudioMicMute" = "exec pactl set-source-mute '@DEFAULT_SOURCE@' toggle";
|
||||
"XF86MonBrightnessUp" = "exec xbacklight +5";
|
||||
"XF86MonBrightnessDown" = "exec xbacklight -5";
|
||||
"XF86Display" = "exec arandr";
|
||||
"Ctrl+Escape" = "${exec} loginctl lock-session;";
|
||||
} //
|
||||
addMods ({
|
||||
"Left" = "focus left";
|
||||
"Down" = "focus down";
|
||||
"Up" = "focus up";
|
||||
"Right" = "focus right";
|
||||
"Tab" = "${exec} rofi -show window";
|
||||
"w" = "${exec} skippy-xd";
|
||||
"Tab" = "${exec} skippy-xd";
|
||||
"Prior" = "focus parent";
|
||||
"Next" = "focus child";
|
||||
"Ctrl+Escape" = "${exec} loginctl lock-session;";
|
||||
"Return" = "${exec} ${terminal}";
|
||||
"p" = "${exec} rofi-pass";
|
||||
"r" = "${exec} rofi -show combi";
|
||||
"o" = "${exec} rofi -show web";
|
||||
"n" = "${exec} rofi -show ssh";
|
||||
"a" = "${exec} tasklauncher";
|
||||
"shift+Left" = "move left";
|
||||
"shift+Down" = "move down";
|
||||
"shift+Up" = "move up";
|
||||
|
@ -118,8 +145,11 @@ in {
|
|||
"t" = "layout tabbed";
|
||||
"s" = "layout toggle split";
|
||||
"q" = "kill";
|
||||
"m" = "move workspace to output up";
|
||||
"n" = "move workspace to output right";
|
||||
"shift+space" = "floating toggle";
|
||||
"shift+q" = "exec i3-nagbar -t warning -m 'do you want to exit i3?' -b 'yes' 'i3-msg exit'";
|
||||
"space" = "exec ~/config/nixos/packages/rust-scripts/target/release/hotkeys";
|
||||
} // builtins.foldl' (bindings: name: let
|
||||
number = toString ((builtins.length (builtins.attrNames bindings)) / 2);
|
||||
in
|
||||
|
|
|
@ -3,25 +3,25 @@ let
|
|||
workspaces = config.common.workspaces;
|
||||
terminal = config.common.terminal;
|
||||
colors = config.common.colors;
|
||||
rofiScriptWeb = pkgs.writeShellScriptBin "rofi-script-web" ''
|
||||
if [[ -z $@ ]]; then
|
||||
sed 's/^[0-9]*\(-r\)\? \?//;s/^\([^[:space:]]*\).*$/\1/' $HOME/.local/share/qutebrowser/history | tac
|
||||
else
|
||||
${pkgs.qutebrowser}/bin/qutebrowser "$1" > /dev/null &
|
||||
fi
|
||||
'';
|
||||
rofiScriptI3 = pkgs.writeShellScriptBin "rofi-script-i3" ''
|
||||
if [ -z $@ ]; then
|
||||
(i3-msg -t get_workspaces | tr ',' '\n' | grep "name" | sed 's/"name":"\(.*\)"/\1/g';
|
||||
echo "${builtins.concatStringsSep "\n" (builtins.foldl' (labels: name: let
|
||||
number = toString (builtins.length labels);
|
||||
in
|
||||
labels ++ [ "${number}:${name}" ]
|
||||
) [] workspaces)}") | sort -u
|
||||
else
|
||||
i3-msg workspace "$@" >/dev/null
|
||||
fi
|
||||
'';
|
||||
#rofiScriptWeb = pkgs.writeShellScriptBin "rofi-script-web" ''
|
||||
#if [[ -z $@ ]]; then
|
||||
#sed 's/^[0-9]*\(-r\)\? \?//;s/^\([^[:space:]]*\).*$/\1/' $HOME/.local/share/qutebrowser/history | tac
|
||||
#else
|
||||
#${pkgs.qutebrowser}/bin/qutebrowser "$1" > /dev/null &
|
||||
#fi
|
||||
#'';
|
||||
#rofiScriptI3 = pkgs.writeShellScriptBin "rofi-script-i3" ''
|
||||
#if [ -z $@ ]; then
|
||||
#(i3-msg -t get_workspaces | tr ',' '\n' | grep "name" | sed 's/"name":"\(.*\)"/\1/g';
|
||||
#echo "${builtins.concatStringsSep "\n" (builtins.foldl' (labels: name: let
|
||||
#number = toString (builtins.length labels);
|
||||
#in
|
||||
#labels ++ [ "${number}:${name}" ]
|
||||
#) [] workspaces)}") | sort -u
|
||||
#else
|
||||
#i3-msg workspace "$@" >/dev/null
|
||||
#fi
|
||||
#'';
|
||||
rofiTask = pkgs.writeScriptBin "tasklauncher" (builtins.readFile ./tasklauncher.py);
|
||||
# recollPython = pkgs.python2.withPackages (ps: [
|
||||
# pkgs.recoll
|
||||
|
@ -31,8 +31,8 @@ in {
|
|||
home = {
|
||||
packages = with pkgs; [
|
||||
rofi
|
||||
rofiScriptWeb
|
||||
rofiScriptI3
|
||||
#rofiScriptWeb
|
||||
#rofiScriptI3
|
||||
rofiTask
|
||||
# rofiFind
|
||||
rofi-pass
|
||||
|
@ -43,22 +43,22 @@ in {
|
|||
rofi = {
|
||||
enable = true;
|
||||
extraConfig = ''
|
||||
rofi.modi: combi,window,drun,run,ssh,keys,web:rofi-script-web,i3:rofi-script-i3
|
||||
rofi.sidebar-mode: true
|
||||
rofi.modi: combi,window,drun,run,ssh,keys
|
||||
rofi.combi-modi: window,drun,run
|
||||
'';
|
||||
borderWidth = 0;
|
||||
separator = "none";
|
||||
fullscreen = false;
|
||||
width = 1920;
|
||||
terminal = terminal;
|
||||
location = "center";
|
||||
yoffset = 19;
|
||||
location = "top";
|
||||
scrollbar = false;
|
||||
padding = 200;
|
||||
padding = 10;
|
||||
cycle = false;
|
||||
lines = 30;
|
||||
colors = {
|
||||
window = {
|
||||
background = "argb:a0${builtins.substring 1 6 colors.background}";
|
||||
background = "argb:c0${builtins.substring 1 6 colors.background}";
|
||||
border = colors.blue;
|
||||
separator = colors.blue;
|
||||
};
|
||||
|
|
453
home-common/graphical/st/config.h
Normal file
453
home-common/graphical/st/config.h
Normal file
|
@ -0,0 +1,453 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
/*
|
||||
* appearance
|
||||
*
|
||||
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||
*/
|
||||
static char font[] = "Roboto Mono:pixelsize=12:antialias=true:autohint=true";
|
||||
static int borderpx = 2;
|
||||
#define histsize 20000
|
||||
|
||||
/*
|
||||
* What program is execed by st depends of these precedence rules:
|
||||
* 1: program passed with -e
|
||||
* 2: utmp option
|
||||
* 3: SHELL environment variable
|
||||
* 4: value of shell in /etc/passwd
|
||||
* 5: value of shell in config.h
|
||||
*/
|
||||
static char shell[] = "/bin/sh";
|
||||
static char *utmp = NULL;
|
||||
static char stty_args[] = "stty raw pass8 nl -echo -iexten -cstopb 38400";
|
||||
|
||||
/* identification sequence returned in DA and DECID */
|
||||
static char vtiden[] = "\033[?6c";
|
||||
|
||||
/* Kerning / character bounding-box multipliers */
|
||||
static float cwscale = 1.0;
|
||||
static float chscale = 1.0;
|
||||
|
||||
/*
|
||||
* word delimiter string
|
||||
*
|
||||
* More advanced example: " `'\"()[]{}"
|
||||
*/
|
||||
static char worddelimiters[] = " ";
|
||||
|
||||
/* selection timeouts (in milliseconds) */
|
||||
static unsigned int doubleclicktimeout = 300;
|
||||
static unsigned int tripleclicktimeout = 600;
|
||||
|
||||
/* alt screens */
|
||||
static int allowaltscreen = 1;
|
||||
|
||||
/* frames per second st should at maximum draw to the screen */
|
||||
static unsigned int xfps = 120;
|
||||
static unsigned int actionfps = 30;
|
||||
|
||||
/*
|
||||
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
|
||||
* attribute.
|
||||
*/
|
||||
static unsigned int blinktimeout = 800;
|
||||
|
||||
/*
|
||||
* thickness of underline and bar cursors
|
||||
*/
|
||||
static unsigned int cursorthickness = 2;
|
||||
|
||||
/*
|
||||
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
|
||||
* it
|
||||
*/
|
||||
static int bellvolume = 0;
|
||||
|
||||
/* default TERM value */
|
||||
static char termname[] = "st-256color";
|
||||
|
||||
/*
|
||||
* spaces per tab
|
||||
*
|
||||
* When you are changing this value, don't forget to adapt the »it« value in
|
||||
* the st.info and appropriately install the st.info in the environment where
|
||||
* you use this st version.
|
||||
*
|
||||
* it#$tabspaces,
|
||||
*
|
||||
* Secondly make sure your kernel is not expanding tabs. When running `stty
|
||||
* -a` »tab0« should appear. You can tell the terminal to not expand tabs by
|
||||
* running following command:
|
||||
*
|
||||
* stty tabs
|
||||
*/
|
||||
static unsigned int tabspaces = 3;
|
||||
static const int alpha = 0xdd;
|
||||
|
||||
/* Terminal colors (16 first used in escape sequence) */
|
||||
static const char *colorname[] = {
|
||||
/* 8 normal colors */
|
||||
"@black@",
|
||||
"@red@",
|
||||
"@green@",
|
||||
"@yellow@",
|
||||
"@blue@",
|
||||
"@magenta@",
|
||||
"@cyan@",
|
||||
"@white@",
|
||||
|
||||
/* 8 bright colors */
|
||||
"@brightBlack@",
|
||||
"@brightRed@",
|
||||
"@brightGreen@",
|
||||
"@brightYellow@",
|
||||
"@brightBlue@",
|
||||
"@brightMagenta@",
|
||||
"@brightCyan@",
|
||||
"@brightWhite@",
|
||||
|
||||
[255] = 0,
|
||||
|
||||
/* more colors can be added after 255 to use with DefaultXX */
|
||||
"@foreground@",
|
||||
"@background@",
|
||||
"@background@"
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Default colors (colorname index)
|
||||
* foreground, background, cursor, reverse cursor
|
||||
*/
|
||||
static unsigned int defaultfg = 256;
|
||||
static unsigned int defaultbg = 258;
|
||||
static unsigned int defaultcs = 256;
|
||||
static unsigned int defaultrcs = 257;
|
||||
|
||||
/*
|
||||
* Default shape of cursor
|
||||
* 2: Block ("█")
|
||||
* 4: Underline ("_")
|
||||
* 6: Bar ("|")
|
||||
* 7: Snowman ("☃")
|
||||
*/
|
||||
static unsigned int cursorshape = 4;
|
||||
|
||||
/*
|
||||
* Default colour and shape of the mouse cursor
|
||||
*/
|
||||
static unsigned int mouseshape = XC_xterm;
|
||||
static unsigned int mousefg = 7;
|
||||
static unsigned int mousebg = 0;
|
||||
|
||||
/*
|
||||
* Colors used, when the specific fg == defaultfg. So in reverse mode this
|
||||
* will reverse too. Another logic would only make the simple feature too
|
||||
* complex.
|
||||
*/
|
||||
static unsigned int defaultitalic = 11;
|
||||
static unsigned int defaultunderline = 7;
|
||||
|
||||
/*
|
||||
* Internal mouse shortcuts.
|
||||
* Beware that overloading Button1 will disable the selection.
|
||||
*/
|
||||
static MouseShortcut mshortcuts[] = {
|
||||
/* button mask string */
|
||||
{ Button4, XK_ANY_MOD, "\031" },
|
||||
{ Button5, XK_ANY_MOD, "\005" },
|
||||
};
|
||||
|
||||
/* Internal keyboard shortcuts. */
|
||||
#define MODKEY Mod1Mask
|
||||
|
||||
static char* openurlcmd[] = { "@openUrlCmd@", NULL };
|
||||
|
||||
static Shortcut shortcuts[] = {
|
||||
/* mask keysym function argument */
|
||||
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
|
||||
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
|
||||
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
|
||||
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
|
||||
{ MODKEY|ShiftMask, XK_Prior, xzoom, {.f = +1} },
|
||||
{ MODKEY|ShiftMask, XK_Next, xzoom, {.f = -1} },
|
||||
{ MODKEY|ShiftMask, XK_Home, xzoomreset, {.f = 0} },
|
||||
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||
{ MODKEY|ShiftMask, XK_Insert, clippaste, {.i = 0} },
|
||||
{ MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} },
|
||||
{ MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} },
|
||||
{ MODKEY, XK_Num_Lock, numlock, {.i = 0} },
|
||||
// { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
|
||||
// { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
|
||||
{ MODKEY|ShiftMask, XK_U, externalpipe, {.v = openurlcmd } },
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Special keys (change & recompile st.info accordingly)
|
||||
*
|
||||
* Mask value:
|
||||
* * Use XK_ANY_MOD to match the key no matter modifiers state
|
||||
* * Use XK_NO_MOD to match the key alone (no modifiers)
|
||||
* appkey value:
|
||||
* * 0: no value
|
||||
* * > 0: keypad application mode enabled
|
||||
* * = 2: term.numlock = 1
|
||||
* * < 0: keypad application mode disabled
|
||||
* appcursor value:
|
||||
* * 0: no value
|
||||
* * > 0: cursor application mode enabled
|
||||
* * < 0: cursor application mode disabled
|
||||
* crlf value
|
||||
* * 0: no value
|
||||
* * > 0: crlf mode is enabled
|
||||
* * < 0: crlf mode is disabled
|
||||
*
|
||||
* Be careful with the order of the definitions because st searches in
|
||||
* this table sequentially, so any XK_ANY_MOD must be in the last
|
||||
* position for a key.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
|
||||
* to be mapped below, add them to this array.
|
||||
*/
|
||||
static KeySym mappedkeys[] = { -1 };
|
||||
|
||||
/*
|
||||
* State bits to ignore when matching key or button events. By default,
|
||||
* numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
|
||||
*/
|
||||
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
|
||||
|
||||
/*
|
||||
* Override mouse-select while mask is active (when MODE_MOUSE is set).
|
||||
* Note that if you want to use ShiftMask with selmasks, set this to an other
|
||||
* modifier, set to 0 to not use it.
|
||||
*/
|
||||
static uint forceselmod = ShiftMask;
|
||||
|
||||
/*
|
||||
* This is the huge key array which defines all compatibility to the Linux
|
||||
* world. Please decide about changes wisely.
|
||||
*/
|
||||
static Key key[] = {
|
||||
/* keysym mask string appkey appcursor crlf */
|
||||
{ XK_KP_Home, ShiftMask, "\033[2J", 0, -1, 0},
|
||||
{ XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1, 0},
|
||||
{ XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1, 0},
|
||||
{ XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1, 0},
|
||||
{ XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0, 0},
|
||||
{ XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1, 0},
|
||||
{ XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1, 0},
|
||||
{ XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0, 0},
|
||||
{ XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1, 0},
|
||||
{ XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1, 0},
|
||||
{ XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0, 0},
|
||||
{ XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1, 0},
|
||||
{ XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1, 0},
|
||||
{ XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0, 0},
|
||||
{ XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1, 0},
|
||||
{ XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1, 0},
|
||||
{ XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0, 0},
|
||||
{ XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0, 0},
|
||||
{ XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0, 0},
|
||||
{ XK_KP_End, ControlMask, "\033[J", -1, 0, 0},
|
||||
{ XK_KP_End, ControlMask, "\033[1;5F", +1, 0, 0},
|
||||
{ XK_KP_End, ShiftMask, "\033[K", -1, 0, 0},
|
||||
{ XK_KP_End, ShiftMask, "\033[1;2F", +1, 0, 0},
|
||||
{ XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0, 0},
|
||||
{ XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0, 0},
|
||||
{ XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0, 0},
|
||||
{ XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0, 0},
|
||||
{ XK_KP_Insert, ShiftMask, "\033[4l", -1, 0, 0},
|
||||
{ XK_KP_Insert, ControlMask, "\033[L", -1, 0, 0},
|
||||
{ XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0, 0},
|
||||
{ XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0, 0},
|
||||
{ XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0, 0},
|
||||
{ XK_KP_Delete, ControlMask, "\033[M", -1, 0, 0},
|
||||
{ XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0, 0},
|
||||
{ XK_KP_Delete, ShiftMask, "\033[2K", -1, 0, 0},
|
||||
{ XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0, 0},
|
||||
{ XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0},
|
||||
{ XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0},
|
||||
{ XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0, 0},
|
||||
{ XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0, 0},
|
||||
{ XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0, 0},
|
||||
{ XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0, -1},
|
||||
{ XK_KP_Enter, XK_ANY_MOD, "\r\n", -1, 0, +1},
|
||||
{ XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0, 0},
|
||||
{ XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0, 0},
|
||||
{ XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0, 0},
|
||||
{ XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0, 0},
|
||||
{ XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0, 0},
|
||||
{ XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0, 0},
|
||||
{ XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0, 0},
|
||||
{ XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0, 0},
|
||||
{ XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0, 0},
|
||||
{ XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0, 0},
|
||||
{ XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0, 0},
|
||||
{ XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0, 0},
|
||||
{ XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0, 0},
|
||||
{ XK_Up, ShiftMask, "\033[1;2A", 0, 0, 0},
|
||||
{ XK_Up, ControlMask, "\033[1;5A", 0, 0, 0},
|
||||
{ XK_Up, Mod1Mask, "\033[1;3A", 0, 0, 0},
|
||||
{ XK_Up, XK_ANY_MOD, "\033[A", 0, -1, 0},
|
||||
{ XK_Up, XK_ANY_MOD, "\033OA", 0, +1, 0},
|
||||
{ XK_Down, ShiftMask, "\033[1;2B", 0, 0, 0},
|
||||
{ XK_Down, ControlMask, "\033[1;5B", 0, 0, 0},
|
||||
{ XK_Down, Mod1Mask, "\033[1;3B", 0, 0, 0},
|
||||
{ XK_Down, XK_ANY_MOD, "\033[B", 0, -1, 0},
|
||||
{ XK_Down, XK_ANY_MOD, "\033OB", 0, +1, 0},
|
||||
{ XK_Left, ShiftMask, "\033[1;2D", 0, 0, 0},
|
||||
{ XK_Left, ControlMask, "\033[1;5D", 0, 0, 0},
|
||||
{ XK_Left, Mod1Mask, "\033[1;3D", 0, 0, 0},
|
||||
{ XK_Left, XK_ANY_MOD, "\033[D", 0, -1, 0},
|
||||
{ XK_Left, XK_ANY_MOD, "\033OD", 0, +1, 0},
|
||||
{ XK_Right, ShiftMask, "\033[1;2C", 0, 0, 0},
|
||||
{ XK_Right, ControlMask, "\033[1;5C", 0, 0, 0},
|
||||
{ XK_Right, Mod1Mask, "\033[1;3C", 0, 0, 0},
|
||||
{ XK_Right, XK_ANY_MOD, "\033[C", 0, -1, 0},
|
||||
{ XK_Right, XK_ANY_MOD, "\033OC", 0, +1, 0},
|
||||
{ XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0, 0},
|
||||
{ XK_Return, Mod1Mask, "\033\r", 0, 0, -1},
|
||||
{ XK_Return, Mod1Mask, "\033\r\n", 0, 0, +1},
|
||||
{ XK_Return, XK_ANY_MOD, "\r", 0, 0, -1},
|
||||
{ XK_Return, XK_ANY_MOD, "\r\n", 0, 0, +1},
|
||||
{ XK_Insert, ShiftMask, "\033[4l", -1, 0, 0},
|
||||
{ XK_Insert, ShiftMask, "\033[2;2~", +1, 0, 0},
|
||||
{ XK_Insert, ControlMask, "\033[L", -1, 0, 0},
|
||||
{ XK_Insert, ControlMask, "\033[2;5~", +1, 0, 0},
|
||||
{ XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0, 0},
|
||||
{ XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0, 0},
|
||||
{ XK_Delete, ControlMask, "\033[M", -1, 0, 0},
|
||||
{ XK_Delete, ControlMask, "\033[3;5~", +1, 0, 0},
|
||||
{ XK_Delete, ShiftMask, "\033[2K", -1, 0, 0},
|
||||
{ XK_Delete, ShiftMask, "\033[3;2~", +1, 0, 0},
|
||||
{ XK_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0},
|
||||
{ XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0},
|
||||
{ XK_BackSpace, XK_NO_MOD, "\177", 0, 0, 0},
|
||||
{ XK_BackSpace, Mod1Mask, "\033\177", 0, 0, 0},
|
||||
{ XK_Home, ShiftMask, "\033[2J", 0, -1, 0},
|
||||
{ XK_Home, ShiftMask, "\033[1;2H", 0, +1, 0},
|
||||
{ XK_Home, XK_ANY_MOD, "\033[H", 0, -1, 0},
|
||||
{ XK_Home, XK_ANY_MOD, "\033[1~", 0, +1, 0},
|
||||
{ XK_End, ControlMask, "\033[J", -1, 0, 0},
|
||||
{ XK_End, ControlMask, "\033[1;5F", +1, 0, 0},
|
||||
{ XK_End, ShiftMask, "\033[K", -1, 0, 0},
|
||||
{ XK_End, ShiftMask, "\033[1;2F", +1, 0, 0},
|
||||
{ XK_End, XK_ANY_MOD, "\033[4~", 0, 0, 0},
|
||||
{ XK_Prior, ControlMask, "\033[5;5~", 0, 0, 0},
|
||||
{ XK_Prior, ShiftMask, "\033[5;2~", 0, 0, 0},
|
||||
{ XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0, 0},
|
||||
{ XK_Next, ControlMask, "\033[6;5~", 0, 0, 0},
|
||||
{ XK_Next, ShiftMask, "\033[6;2~", 0, 0, 0},
|
||||
{ XK_Next, XK_ANY_MOD, "\033[6~", 0, 0, 0},
|
||||
{ XK_F1, XK_NO_MOD, "\033OP" , 0, 0, 0},
|
||||
{ XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0, 0},
|
||||
{ XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0, 0},
|
||||
{ XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0, 0},
|
||||
{ XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0, 0},
|
||||
{ XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0, 0},
|
||||
{ XK_F2, XK_NO_MOD, "\033OQ" , 0, 0, 0},
|
||||
{ XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0, 0},
|
||||
{ XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0, 0},
|
||||
{ XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0, 0},
|
||||
{ XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0, 0},
|
||||
{ XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0, 0},
|
||||
{ XK_F3, XK_NO_MOD, "\033OR" , 0, 0, 0},
|
||||
{ XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0, 0},
|
||||
{ XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0, 0},
|
||||
{ XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0, 0},
|
||||
{ XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0, 0},
|
||||
{ XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0, 0},
|
||||
{ XK_F4, XK_NO_MOD, "\033OS" , 0, 0, 0},
|
||||
{ XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0, 0},
|
||||
{ XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0, 0},
|
||||
{ XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0, 0},
|
||||
{ XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0, 0},
|
||||
{ XK_F5, XK_NO_MOD, "\033[15~", 0, 0, 0},
|
||||
{ XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0, 0},
|
||||
{ XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0, 0},
|
||||
{ XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0, 0},
|
||||
{ XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0, 0},
|
||||
{ XK_F6, XK_NO_MOD, "\033[17~", 0, 0, 0},
|
||||
{ XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0, 0},
|
||||
{ XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0, 0},
|
||||
{ XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0, 0},
|
||||
{ XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0, 0},
|
||||
{ XK_F7, XK_NO_MOD, "\033[18~", 0, 0, 0},
|
||||
{ XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0, 0},
|
||||
{ XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0, 0},
|
||||
{ XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0, 0},
|
||||
{ XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0, 0},
|
||||
{ XK_F8, XK_NO_MOD, "\033[19~", 0, 0, 0},
|
||||
{ XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0, 0},
|
||||
{ XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0, 0},
|
||||
{ XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0, 0},
|
||||
{ XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0, 0},
|
||||
{ XK_F9, XK_NO_MOD, "\033[20~", 0, 0, 0},
|
||||
{ XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0, 0},
|
||||
{ XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0, 0},
|
||||
{ XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0, 0},
|
||||
{ XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0, 0},
|
||||
{ XK_F10, XK_NO_MOD, "\033[21~", 0, 0, 0},
|
||||
{ XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0, 0},
|
||||
{ XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0, 0},
|
||||
{ XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0, 0},
|
||||
{ XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0, 0},
|
||||
{ XK_F11, XK_NO_MOD, "\033[23~", 0, 0, 0},
|
||||
{ XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0, 0},
|
||||
{ XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0, 0},
|
||||
{ XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0, 0},
|
||||
{ XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0, 0},
|
||||
{ XK_F12, XK_NO_MOD, "\033[24~", 0, 0, 0},
|
||||
{ XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0, 0},
|
||||
{ XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0, 0},
|
||||
{ XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0, 0},
|
||||
{ XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0, 0},
|
||||
{ XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0, 0},
|
||||
{ XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0, 0},
|
||||
{ XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0, 0},
|
||||
{ XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0, 0},
|
||||
{ XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0, 0},
|
||||
{ XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0, 0},
|
||||
{ XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0, 0},
|
||||
{ XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0, 0},
|
||||
{ XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0, 0},
|
||||
{ XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0, 0},
|
||||
{ XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0, 0},
|
||||
{ XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0, 0},
|
||||
{ XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0, 0},
|
||||
{ XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0, 0},
|
||||
{ XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0, 0},
|
||||
{ XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0, 0},
|
||||
{ XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0, 0},
|
||||
{ XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0, 0},
|
||||
{ XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0, 0},
|
||||
{ XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0, 0},
|
||||
{ XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0, 0},
|
||||
{ XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0, 0},
|
||||
{ XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0, 0},
|
||||
};
|
||||
|
||||
/*
|
||||
* Selection types' masks.
|
||||
* Use the same masks as usual.
|
||||
* Button1Mask is always unset, to make masks match between ButtonPress.
|
||||
* ButtonRelease and MotionNotify.
|
||||
* If no match is found, regular selection is used.
|
||||
*/
|
||||
static uint selmasks[] = {
|
||||
[SEL_RECTANGULAR] = Mod1Mask,
|
||||
};
|
||||
|
||||
/*
|
||||
* Printable characters in ASCII, used to estimate the advance width
|
||||
* of single wide characters.
|
||||
*/
|
||||
static char ascii_printable[] =
|
||||
" !\"#$%&'()*+,-./0123456789:;<=>?"
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
|
||||
"`abcdefghijklmnopqrstuvwxyz{|}~";
|
18
home-common/graphical/st/default.nix
Normal file
18
home-common/graphical/st/default.nix
Normal file
|
@ -0,0 +1,18 @@
|
|||
pkgs: colors:
|
||||
let
|
||||
openUrlCmd = pkgs.writeScript "openUrlCmd" ''
|
||||
${pkgs.xurls}/bin/xurls | ${pkgs.rofi}/bin/rofi -dmenu | xargs -r ${pkgs.firefox}/bin/firefox
|
||||
'';
|
||||
in
|
||||
pkgs.st.overrideDerivation (old: {
|
||||
patches = old.patches ++ [
|
||||
# scrollback patches from https://st.suckless.org/patches/scrollback/
|
||||
# https://st.suckless.org/patches/scrollback/st-scrollback-0.7.diff
|
||||
./st-alpha-0.7.diff
|
||||
./st-externalpipe-0.7.diff
|
||||
];
|
||||
enableParallelBuilds = true;
|
||||
prePatch = ''
|
||||
cp ${(pkgs.substituteAll { src = ./config.h; inherit openUrlCmd; inherit (colors) black brightBlack red brightRed green brightGreen yellow brightYellow blue brightBlue magenta brightMagenta cyan brightCyan white brightWhite background foreground;})} config.h
|
||||
'';
|
||||
})
|
188
home-common/graphical/st/st-alpha-0.7.diff
Normal file
188
home-common/graphical/st/st-alpha-0.7.diff
Normal file
|
@ -0,0 +1,188 @@
|
|||
diff --git a/config.def.h b/config.def.h
|
||||
index b41747f..e22ebd2 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -82,6 +82,9 @@ static char termname[] = "st-256color";
|
||||
*/
|
||||
static unsigned int tabspaces = 8;
|
||||
|
||||
+/* bg opacity */
|
||||
+static const int alpha = 0xdd;
|
||||
+
|
||||
/* Terminal colors (16 first used in escape sequence) */
|
||||
static const char *colorname[] = {
|
||||
/* 8 normal colors */
|
||||
@@ -109,6 +112,7 @@ static const char *colorname[] = {
|
||||
/* more colors can be added after 255 to use with DefaultXX */
|
||||
"#cccccc",
|
||||
"#555555",
|
||||
+ "black",
|
||||
};
|
||||
|
||||
|
||||
@@ -117,7 +121,7 @@ static const char *colorname[] = {
|
||||
* foreground, background, cursor, reverse cursor
|
||||
*/
|
||||
static unsigned int defaultfg = 7;
|
||||
-static unsigned int defaultbg = 0;
|
||||
+static unsigned int defaultbg = 257;
|
||||
static unsigned int defaultcs = 256;
|
||||
static unsigned int defaultrcs = 257;
|
||||
|
||||
diff --git a/config.mk b/config.mk
|
||||
index c84c5ee..19a03bb 100644
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
@@ -14,7 +14,7 @@ X11LIB = /usr/X11R6/lib
|
||||
INCS = -I. -I/usr/include -I${X11INC} \
|
||||
`pkg-config --cflags fontconfig` \
|
||||
`pkg-config --cflags freetype2`
|
||||
-LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXft \
|
||||
+LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft -lXrender\
|
||||
`pkg-config --libs fontconfig` \
|
||||
`pkg-config --libs freetype2`
|
||||
|
||||
diff --git a/st.c b/st.c
|
||||
index 2594c65..f9ba75b 100644
|
||||
--- a/st.c
|
||||
+++ b/st.c
|
||||
@@ -61,6 +61,7 @@ char *argv0;
|
||||
#define XK_ANY_MOD UINT_MAX
|
||||
#define XK_NO_MOD 0
|
||||
#define XK_SWITCH_MOD (1<<13)
|
||||
+#define OPAQUE 0Xff
|
||||
|
||||
/* macros */
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
@@ -81,6 +82,8 @@ char *argv0;
|
||||
(t1.tv_nsec-t2.tv_nsec)/1E6)
|
||||
#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
|
||||
|
||||
+#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL)
|
||||
+
|
||||
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
|
||||
#define IS_TRUECOL(x) (1 << 24 & (x))
|
||||
#define TRUERED(x) (((x) & 0xff0000) >> 8)
|
||||
@@ -268,6 +271,7 @@ typedef struct {
|
||||
int w, h; /* window width and height */
|
||||
int ch; /* char height */
|
||||
int cw; /* char width */
|
||||
+ int depth; /* bit depth */
|
||||
char state; /* focus, redraw, visible */
|
||||
int cursor; /* cursor style */
|
||||
} XWindow;
|
||||
@@ -3137,7 +3141,7 @@ xresize(int col, int row)
|
||||
|
||||
XFreePixmap(xw.dpy, xw.buf);
|
||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
|
||||
- DefaultDepth(xw.dpy, xw.scr));
|
||||
+ xw.depth);
|
||||
XftDrawChange(xw.draw, xw.buf);
|
||||
xclear(0, 0, xw.w, xw.h);
|
||||
}
|
||||
@@ -3191,6 +3195,14 @@ xloadcols(void)
|
||||
else
|
||||
die("Could not allocate color %d\n", i);
|
||||
}
|
||||
+
|
||||
+ /* set alpha value of bg color */
|
||||
+ if (USE_ARGB) {
|
||||
+ dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE; //0xcccc;
|
||||
+ dc.col[defaultbg].pixel &= 0x00111111;
|
||||
+ dc.col[defaultbg].pixel |= alpha << 24; // 0xcc000000;
|
||||
+ }
|
||||
+
|
||||
loaded = 1;
|
||||
}
|
||||
|
||||
@@ -3212,6 +3224,16 @@ xsetcolorname(int x, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+void
|
||||
+xtermclear(int col1, int row1, int col2, int row2) {
|
||||
+ XftDrawRect(xw.draw,
|
||||
+ &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
|
||||
+ borderpx + col1 * xw.cw,
|
||||
+ borderpx + row1 * xw.ch,
|
||||
+ (col2-col1+1) * xw.cw,
|
||||
+ (row2-row1+1) * xw.ch);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Absolute coordinates.
|
||||
*/
|
||||
@@ -3443,7 +3465,38 @@ xinit(void)
|
||||
if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||
die("Can't open display\n");
|
||||
xw.scr = XDefaultScreen(xw.dpy);
|
||||
- xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||
+ xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr);
|
||||
+ if (! USE_ARGB)
|
||||
+ xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||
+ else {
|
||||
+ XVisualInfo *vis;
|
||||
+ XRenderPictFormat *fmt;
|
||||
+ int nvi;
|
||||
+ int i;
|
||||
+
|
||||
+ XVisualInfo tpl = {
|
||||
+ .screen = xw.scr,
|
||||
+ .depth = 32,
|
||||
+ .class = TrueColor
|
||||
+ };
|
||||
+
|
||||
+ vis = XGetVisualInfo(xw.dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &tpl, &nvi);
|
||||
+ xw.vis = NULL;
|
||||
+ for(i = 0; i < nvi; i ++) {
|
||||
+ fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual);
|
||||
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
|
||||
+ xw.vis = vis[i].visual;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ XFree(vis);
|
||||
+
|
||||
+ if (! xw.vis) {
|
||||
+ fprintf(stderr, "Couldn't find ARGB visual.\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/* font */
|
||||
if (!FcInit())
|
||||
@@ -3453,7 +3506,10 @@ xinit(void)
|
||||
xloadfonts(usedfont, 0);
|
||||
|
||||
/* colors */
|
||||
- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
|
||||
+ if (! USE_ARGB)
|
||||
+ xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
|
||||
+ else
|
||||
+ xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr), xw.vis, None);
|
||||
xloadcols();
|
||||
|
||||
/* adjust fixed window geometry */
|
||||
@@ -3476,16 +3532,17 @@ xinit(void)
|
||||
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
|
||||
parent = XRootWindow(xw.dpy, xw.scr);
|
||||
xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
|
||||
- xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
|
||||
+ xw.w, xw.h, 0, xw.depth, InputOutput,
|
||||
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
|
||||
| CWEventMask | CWColormap, &xw.attrs);
|
||||
|
||||
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||
gcvalues.graphics_exposures = False;
|
||||
- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
|
||||
+ xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, xw.depth);
|
||||
+ dc.gc = XCreateGC(xw.dpy,
|
||||
+ (USE_ARGB)? xw.buf: parent,
|
||||
+ GCGraphicsExposures,
|
||||
&gcvalues);
|
||||
- xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
|
||||
- DefaultDepth(xw.dpy, xw.scr));
|
||||
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
|
||||
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
|
||||
|
90
home-common/graphical/st/st-externalpipe-0.7.diff
Normal file
90
home-common/graphical/st/st-externalpipe-0.7.diff
Normal file
|
@ -0,0 +1,90 @@
|
|||
diff --git a/st.c b/st.c
|
||||
index 2594c65..ecd9bdc 100644
|
||||
--- a/st.c
|
||||
+++ b/st.c
|
||||
@@ -329,6 +329,7 @@ static void clipcopy(const Arg *);
|
||||
static void clippaste(const Arg *);
|
||||
static void numlock(const Arg *);
|
||||
static void selpaste(const Arg *);
|
||||
+static void externalpipe(const Arg *);
|
||||
static void xzoom(const Arg *);
|
||||
static void xzoomabs(const Arg *);
|
||||
static void xzoomreset(const Arg *);
|
||||
@@ -337,6 +338,9 @@ static void printscreen(const Arg *) ;
|
||||
static void toggleprinter(const Arg *);
|
||||
static void sendbreak(const Arg *);
|
||||
|
||||
+/* variables used in config.h */
|
||||
+static char winid[64];
|
||||
+
|
||||
/* Config.h for applying patches and the configuration. */
|
||||
#include "config.h"
|
||||
|
||||
@@ -2922,6 +2926,59 @@ eschandle(uchar ascii)
|
||||
}
|
||||
|
||||
void
|
||||
+externalpipe(const Arg *arg)
|
||||
+{
|
||||
+ int to[2];
|
||||
+ char buf[UTF_SIZ];
|
||||
+ void (*oldsigpipe)(int);
|
||||
+ Glyph *bp, *end;
|
||||
+ int lastpos, n, newline;
|
||||
+
|
||||
+ if (pipe(to) == -1)
|
||||
+ return;
|
||||
+
|
||||
+ switch (fork()) {
|
||||
+ case -1:
|
||||
+ close(to[0]);
|
||||
+ close(to[1]);
|
||||
+ return;
|
||||
+ case 0:
|
||||
+ dup2(to[0], STDIN_FILENO);
|
||||
+ close(to[0]);
|
||||
+ close(to[1]);
|
||||
+ execvp(((char **)arg->v)[0], (char **)arg->v);
|
||||
+ fprintf(stderr, "st: execvp %s ", ((char **)arg->v)[0]);
|
||||
+ perror("failed");
|
||||
+ exit(0);
|
||||
+ }
|
||||
+
|
||||
+ close(to[0]);
|
||||
+ /* ignore sigpipe for now, in case child exits early */
|
||||
+ oldsigpipe = signal(SIGPIPE, SIG_IGN);
|
||||
+ newline = 0;
|
||||
+ for (n = 0; n < term.row; n++) {
|
||||
+ bp = term.line[n];
|
||||
+ lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
|
||||
+ if (lastpos < 0)
|
||||
+ break;
|
||||
+ end = &bp[lastpos + 1];
|
||||
+ for (; bp < end; ++bp)
|
||||
+ if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
|
||||
+ break;
|
||||
+ if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
|
||||
+ continue;
|
||||
+ if (xwrite(to[1], "\n", 1) < 0)
|
||||
+ break;
|
||||
+ newline = 0;
|
||||
+ }
|
||||
+ if (newline)
|
||||
+ (void)xwrite(to[1], "\n", 1);
|
||||
+ close(to[1]);
|
||||
+ /* restore */
|
||||
+ signal(SIGPIPE, oldsigpipe);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
tputc(Rune u)
|
||||
{
|
||||
char c[UTF_SIZ];
|
||||
@@ -3479,6 +3536,7 @@ xinit(void)
|
||||
xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
|
||||
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
|
||||
| CWEventMask | CWColormap, &xw.attrs);
|
||||
+ snprintf(winid, LEN(winid), "%lu", (unsigned long)xw.win);
|
||||
|
||||
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||
gcvalues.graphics_exposures = False;
|
|
@ -60,6 +60,9 @@
|
|||
Notification = {
|
||||
Text = template;
|
||||
};
|
||||
NotificationBubble = {
|
||||
Queue = "tasks";
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
|
|
34
homes/apollo/battery.nix
Normal file
34
homes/apollo/battery.nix
Normal file
|
@ -0,0 +1,34 @@
|
|||
{pkgs, ... }:
|
||||
let
|
||||
battery-watch = pkgs.writeShellScriptBin "battery-watch" ''
|
||||
critical_level=20 #percent
|
||||
|
||||
while true
|
||||
do
|
||||
if [ "$(${pkgs.acpi}/bin/acpi -a | grep -o off)" == "off" ]; then
|
||||
battery_level=`${pkgs.acpi}/bin/acpi -b | sed 's/.*[dg], //g;s/\%,.*//g'`
|
||||
if [ $battery_level -le $critical_level ]; then
|
||||
${pkgs.eventd}/bin/eventc critical battery -d "title='Battery level is low!'" -d "message='Only $battery_level% of the charge remains.'"
|
||||
else
|
||||
${pkgs.eventd}/bin/eventc notification battery -d "title='Battery is discharging!'" -d "message='Only $battery_level% of the charge remains.'"
|
||||
sleep 18m
|
||||
fi
|
||||
fi
|
||||
sleep 2m
|
||||
done
|
||||
'';
|
||||
in {
|
||||
systemd.user = {
|
||||
services.battery = {
|
||||
Unit = {
|
||||
Description = "Watch battery state and warn user";
|
||||
};
|
||||
Service = {
|
||||
ExecStart="/bin/sh ${battery-watch}/bin/battery-watch";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,4 +1,19 @@
|
|||
{ pkgs, ... }:
|
||||
let
|
||||
jali = with pkgs.python36Packages; buildPythonApplication rec {
|
||||
name = "${pname}-${version}";
|
||||
pname = "jali";
|
||||
doCheck = false;
|
||||
version = "1d1c5d0a";
|
||||
src = pkgs.fetchgit {
|
||||
url = "https://git.darmstadt.ccc.de/jali/jali.git";
|
||||
rev = version;
|
||||
sha256 = "1nzzangp7yr2gq66qz7wk2cqqwjlhrfaqmc85qigjv4vpfmlphl0";
|
||||
};
|
||||
propagatedBuildInputs = with pkgs; [ jinja2 pendulum GitPython aqbanking ];
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
imports = [
|
||||
|
@ -6,6 +21,8 @@
|
|||
../../home-common/my-systems.nix
|
||||
../../home-common/graphical
|
||||
../../home-common/latex.nix
|
||||
./battery.nix
|
||||
./sleep-nag.nix
|
||||
];
|
||||
|
||||
programs = {
|
||||
|
@ -19,6 +36,9 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
home.sessionVariables = {
|
||||
MOZ_USE_XINPUT2 = "1";
|
||||
};
|
||||
|
||||
services = {
|
||||
udiskie = {
|
||||
|
@ -32,14 +52,31 @@
|
|||
] ++ (with pkgs; [
|
||||
# web
|
||||
chromium
|
||||
signal-desktop
|
||||
tdesktop
|
||||
acpi
|
||||
dino
|
||||
|
||||
rustracer
|
||||
|
||||
arandr
|
||||
qutebrowser
|
||||
|
||||
mumble
|
||||
|
||||
xorg.xev
|
||||
xorg.xbacklight
|
||||
meld
|
||||
|
||||
icedtea8_web
|
||||
|
||||
hledger
|
||||
haskellPackages.hledger-ui
|
||||
ledger
|
||||
jali
|
||||
|
||||
# tools & office
|
||||
feh
|
||||
gimp
|
||||
imagemagick
|
||||
libreoffice-fresh
|
||||
|
|
26
homes/apollo/sleep-nag.nix
Normal file
26
homes/apollo/sleep-nag.nix
Normal file
|
@ -0,0 +1,26 @@
|
|||
{pkgs, ... }:
|
||||
let
|
||||
sleep-nag = pkgs.writeShellScriptBin "sleep-nag" ''
|
||||
while true
|
||||
do
|
||||
if [[ `date +%H` -ge 23 ]] || [[ `date +%H` -lt 6 ]]; then
|
||||
${pkgs.eventd}/bin/eventc notification kassandra -d "title='Es ist $(date +%H:%M) Uhr: Zeit ins Bett zu gehen!'" -d "message='Du kannst das hier auch morgen tun!'"
|
||||
fi
|
||||
sleep 10m
|
||||
done
|
||||
'';
|
||||
in {
|
||||
systemd.user = {
|
||||
services.sleep-nag = {
|
||||
Unit = {
|
||||
Description = "Sleep nag";
|
||||
};
|
||||
Service = {
|
||||
ExecStart="/bin/sh ${sleep-nag}/bin/sleep-nag";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
83
homes/charon/dovecot.sieve
Normal file
83
homes/charon/dovecot.sieve
Normal file
|
@ -0,0 +1,83 @@
|
|||
require ["vnd.dovecot.duplicate", "fileinto", "regex", "imap4flags", "mailbox"];
|
||||
|
||||
if header :regex "X-spamd-result" "st-ludwig-darmstadt.de" {
|
||||
keep;
|
||||
}
|
||||
elsif anyof (
|
||||
header :regex "X-spam" "^yes$",
|
||||
header :contains "From" "paypal@mail.paypal.de",
|
||||
header :contains "To" "lac@maralorn.de",
|
||||
header :contains "To" "malte@maralorn.de",
|
||||
header :contains "To" "maltemail@maralorn.de",
|
||||
header :contains "To" "mail@maralorn.de",
|
||||
header :contains "From" "promotion5@amazon.de")
|
||||
{
|
||||
setflag "\\Seen";
|
||||
fileinto "Spam";
|
||||
}
|
||||
elsif anyof (
|
||||
duplicate
|
||||
) {
|
||||
setflag "\\Seen";
|
||||
fileinto "Trash";
|
||||
}
|
||||
elsif anyof (
|
||||
address :domain :is "From" [
|
||||
"maralorn.de",
|
||||
"facebookmail.com"
|
||||
],
|
||||
address :domain :is "From" [
|
||||
"tickets.darmstadt.ccc.de"
|
||||
],
|
||||
header :contains "List-Id" [
|
||||
"hackspace.lists.darmstadt.ccc.de",
|
||||
"members.lists.darmstadt.ccc.de",
|
||||
"darmstadt.lists.darmstadt.ccc.de"
|
||||
]
|
||||
)
|
||||
{
|
||||
setflag "\\Seen";
|
||||
}
|
||||
elsif anyof (
|
||||
header :is "From" "vib@vereinsknowhow.de",
|
||||
address :domain :is "From" [
|
||||
"dpg-physik.de",
|
||||
"physikstudenten.de"
|
||||
],
|
||||
header :contains "List-Id" [
|
||||
"intern.lists.ccc.de",
|
||||
"erfa.lists.ccc.de",
|
||||
"ctf-announce.lists.cased.de",
|
||||
"ctf-team.lists.cased.de",
|
||||
"darmstadt-freifunk.net"
|
||||
],
|
||||
header :contains "Subject" "Moodle TU Darmstadt: Zusammenfassung des Forums"
|
||||
)
|
||||
{
|
||||
setflag "\\Seen";
|
||||
fileinto :create "Move.readlater";
|
||||
}
|
||||
elsif header :contains ["To", "From", "CC"] [
|
||||
"noc@karlshof.de",
|
||||
"karlshof@whm.stwda.de",
|
||||
"noc-karlshof@maralorn.de"
|
||||
]
|
||||
{
|
||||
setflag "\\Seen";
|
||||
fileinto :create "Archiv.karlshof.noc";
|
||||
}
|
||||
|
||||
elsif header :contains "List-Id" "chor.lists.tu-darmstadt.de" {
|
||||
setflag "\\Seen";
|
||||
fileinto :create "Archiv.tuchor";
|
||||
}
|
||||
elsif header :contains "From" "kdwachlin@web.de" {
|
||||
setflag "\\Seen";
|
||||
fileinto "Archiv.unsortiert";
|
||||
}
|
||||
elsif header :contains "Subject" "[VED-Wiki]" {
|
||||
setflag "\\Seen";
|
||||
fileinto :create "Archiv.ved.wiki";
|
||||
} elsif header :regex "X-spamd-result" "[2-5]\.[0-9]\{2\} / 15\.00" {
|
||||
setflag "\\Seen";
|
||||
}
|
|
@ -1,9 +1,16 @@
|
|||
{
|
||||
imports = [
|
||||
../../snippets/everywhere.nix
|
||||
../../snippets/my-systems.nix
|
||||
../../home-common/default.nix
|
||||
../../home-common/my-systems.nix
|
||||
./morgenreport.nix
|
||||
./sort-mail.nix
|
||||
./habitask.nix
|
||||
];
|
||||
|
||||
home.forceCopies.paths = [ ".dovecot.sieve" ];
|
||||
home.file = {
|
||||
sieve-rules = {
|
||||
target = ".dovecot.sieve";
|
||||
text = builtins.readFile ./dovecot.sieve;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
{ pkgs, ... }:
|
||||
{
|
||||
let
|
||||
morgenreport-script = pkgs.writeShellScriptBin "morgenreport" ''
|
||||
cd $HOME/data/aktuell/media/ebooks/morgenreport/
|
||||
DATE=`date +%Y-%m-%d`
|
||||
PATH=$PATH:/run/wrappers/bin/
|
||||
PATH=$PATH:${pkgs.imagemagickBig}/bin
|
||||
PATH=$PATH:${pkgs.qt5.qtbase}/bin
|
||||
PATH=$PATH:${pkgs.qt5.qtsvg}/bin
|
||||
${pkgs.calibre}/bin/ebook-convert $HOME/data/aktuell/it/code/calibre-recipes/morgenreport.recipe morgenreport-$DATE.mobi --output-profile=kindle_pw3
|
||||
echo "File created, sending to kindle now …"
|
||||
echo 'Siehe Anhang' | ${pkgs.mutt}/bin/mutt -s "Morgenreport $DATE" -a morgenreport-$DATE.mobi -- maralorn@kindle.com
|
||||
'';
|
||||
in {
|
||||
home.packages = [ morgenreport-script];
|
||||
systemd.user = {
|
||||
services.morgenreport =
|
||||
let
|
||||
morgenreport-script = pkgs.writeShellScriptBin "morgenreport" ''
|
||||
cd $HOME/data/aktuell/media/ebooks/morgenreport/
|
||||
DATE=`date +%Y-%m-%d`
|
||||
${pkgs.calibre}/bin/ebook-convert $HOME/data/aktuell/it/code/calibre-recipes/morgenreport.recipe morgenreport-$DATE.mobi --output-profile=kindle_pw3
|
||||
echo "File created, sending to kindle now …"
|
||||
PATH=$PATH:/run/wrappers/bin/
|
||||
echo 'Siehe Anhang' | ${pkgs.mutt}/bin/mutt -s "Morgenreport $DATE" -a morgenreport-$DATE.mobi -- maralorn@kindle.com
|
||||
'';
|
||||
in {
|
||||
services.morgenreport = {
|
||||
Unit = {
|
||||
Description = "Send morgenreport to kindle";
|
||||
};
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
automatic = true;
|
||||
options = "--delete-older-than 5d";
|
||||
};
|
||||
package = pkgs.nixUnstable;
|
||||
optimise.automatic = true;
|
||||
};
|
||||
system.autoUpgrade.enable = true;
|
||||
|
@ -32,6 +31,10 @@
|
|||
mutableUsers = false;
|
||||
};
|
||||
|
||||
security.sudo.extraConfig = "
|
||||
Defaults timestamp_type=global, timestamp_timeout=15
|
||||
";
|
||||
|
||||
networking.firewall.allowPing = true;
|
||||
|
||||
services = {
|
||||
|
@ -44,7 +47,6 @@
|
|||
gnumake
|
||||
python3
|
||||
python
|
||||
pandoc
|
||||
mkpasswd
|
||||
rxvt_unicode.terminfo
|
||||
htop
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
hostName = "charon.olymp.space";
|
||||
|
||||
interfaces.ens3 = {
|
||||
ip4 = [ { address = "45.32.154.139"; prefixLength = 22; } ];
|
||||
ip6 = [ { address = "2001:19f0:6c01:b0d::1"; prefixLength = 64; } ];
|
||||
ipv4.addresses = [{ address = "45.32.154.139"; prefixLength = 22; }];
|
||||
ipv6.addresses = [{ address = "2001:19f0:6c01:b0d::1"; prefixLength = 64; }];
|
||||
};
|
||||
defaultGateway = "45.32.152.1";
|
||||
nameservers = [ "108.61.10.10" "2001:19f0:300:1704::6" ];
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
socketActivation = false;
|
||||
rspamd = {
|
||||
extraConfig = ''
|
||||
extended_spam_headers = yes;
|
||||
extended_spam_headers = true;
|
||||
'';
|
||||
enable = true;
|
||||
};
|
||||
|
@ -45,6 +45,8 @@
|
|||
sslServerKey = "/var/lib/acme/charon.olymp.space/key.pem";
|
||||
extraConfig =
|
||||
''
|
||||
postmaster_address=postmaster@charon.olymp.space
|
||||
|
||||
ssl = required
|
||||
service auth {
|
||||
unix_listener /var/lib/postfix/queue/private/auth {
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
server_name = "maralorn.de";
|
||||
database_type = "psycopg2";
|
||||
max_upload_size = "30M";
|
||||
create_local_database = false;
|
||||
database_args = {
|
||||
user = "matrix-synapse";
|
||||
database = "matrix-synapse";
|
||||
|
|
40
modules/mpd.nix
Normal file
40
modules/mpd.nix
Normal file
|
@ -0,0 +1,40 @@
|
|||
{ lib, config, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
{
|
||||
options = {
|
||||
mpd = {
|
||||
mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
};
|
||||
};
|
||||
};
|
||||
systemd.user = {
|
||||
services.morgenreport =
|
||||
let
|
||||
morgenreport-script = pkgs.writeShellScriptBin "morgenreport" ''
|
||||
cd $HOME/data/aktuell/media/ebooks/morgenreport/
|
||||
DATE=`date +%Y-%m-%d`
|
||||
${pkgs.calibre}/bin/ebook-convert $HOME/data/aktuell/it/code/calibre-recipes/morgenreport.recipe morgenreport-$DATE.mobi --output-profile=kindle_pw3
|
||||
echo "File created, sending to kindle now …"
|
||||
PATH=$PATH:/run/wrappers/bin/
|
||||
echo 'Siehe Anhang' | ${pkgs.mutt}/bin/mutt -s "Morgenreport $DATE" -a morgenreport-$DATE.mobi -- maralorn@kindle.com
|
||||
'';
|
||||
in {
|
||||
Unit = {
|
||||
Description = "Send morgenreport to kindle";
|
||||
};
|
||||
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart="/bin/sh ${morgenreport-script}/bin/morgenreport";
|
||||
};
|
||||
};
|
||||
timers.morgenreport = {
|
||||
Timer = {
|
||||
OnCalendar = "20:00";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{ fetchFromGitHub, stdenv, ninja, meson, pkgconfig, glib, cairo, gdk_pixbuf, glib_networking, pango, libudev, xorg, libxslt, docbook_xml_xslt, git, libuuid, dbus, libsoup, docbook_xml_dtd_45, docbook5_xsl, gettext, autoconf, libtool, utillinux, libxkbcommon }:
|
||||
stdenv.mkDerivation rec {
|
||||
name = "eventd";
|
||||
version = "279d3c3";
|
||||
version = "v0.24.1";
|
||||
src = fetchFromGitHub {
|
||||
owner = "sardemff7";
|
||||
repo = "eventd";
|
||||
|
@ -9,9 +9,6 @@ stdenv.mkDerivation rec {
|
|||
sha256 = "162gr3agmjn6d0wdj3lixv8qfvgfm9qg3wphbvwywdp4qcwvnjz8";
|
||||
fetchSubmodules = true;
|
||||
};
|
||||
patchPhase = ''
|
||||
sed s/0.44.1/0.43.0/ -i meson.build
|
||||
'';
|
||||
buildInputs = [
|
||||
ninja
|
||||
meson
|
||||
|
|
193
packages/rust-scripts/Cargo.lock
generated
193
packages/rust-scripts/Cargo.lock
generated
|
@ -1,12 +1,12 @@
|
|||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -15,7 +15,7 @@ name = "backtrace-sys"
|
|||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -26,17 +26,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.1"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.10"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -44,9 +44,9 @@ name = "chrono"
|
|||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -71,7 +71,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "dialog"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.darmstadt.ccc.de/maralorn/dialog-rs.git#f33f0c9ac4f4407899da55507147a8a808e2f521"
|
||||
dependencies = [
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustyline 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -93,7 +92,7 @@ name = "error-chain"
|
|||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -101,7 +100,7 @@ name = "fuchsia-zircon"
|
|||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -110,11 +109,30 @@ name = "fuchsia-zircon-sys"
|
|||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "iso8601"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kairos"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iso8601 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
|
@ -124,17 +142,35 @@ dependencies = [
|
|||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -147,21 +183,29 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.36"
|
||||
name = "nom"
|
||||
version = "3.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.2"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.3.6"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -177,7 +221,7 @@ name = "quote"
|
|||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -199,13 +243,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
name = "rust-scripts"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dialog 0.1.0 (git+https://git.darmstadt.ccc.de/maralorn/dialog-rs.git)",
|
||||
"task-hookrs 0.5.0 (git+https://github.com/maralorn/task-hookrs.git?branch=preview)",
|
||||
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dialog 0.1.0",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kairos 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_yaml 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"task-hookrs 0.5.0",
|
||||
"uuid 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -223,37 +275,38 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.42"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.42"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.16"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yaml-rust 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -268,10 +321,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.13.1"
|
||||
version = "0.13.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -287,15 +340,14 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "task-hookrs"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/maralorn/task-hookrs.git?branch=preview#24a3ad5519a9bb26fcf0eeee368f8899211e47e1"
|
||||
dependencies = [
|
||||
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -309,7 +361,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.39"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -337,9 +389,9 @@ name = "uuid"
|
|||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -371,46 +423,58 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e"
|
||||
"checksum backtrace 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea58cd16fd6c9d120b5bcb01d63883ae4cc7ba2aed35c1841b862a3c7ef6639"
|
||||
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
|
||||
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
|
||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||
"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
|
||||
"checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba"
|
||||
"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
|
||||
"checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6"
|
||||
"checksum derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c998e6ab02a828dd9735c18f154e14100e674ed08cb4e1938f0e4177543f439"
|
||||
"checksum derive_builder_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "735e24ee9e5fa8e16b86da5007856e97d592e11867e45d76e0c0d0a164a0b757"
|
||||
"checksum dialog 0.1.0 (git+https://git.darmstadt.ccc.de/maralorn/dialog-rs.git)" = "<none>"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
"checksum encode_unicode 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "28d65f1f5841ef7c6792861294b72beda34c664deb8be27970f36c306b7da1ce"
|
||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum iso8601 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83e03bd24a535789afdce1c8274f2f5dc1a265c39e937884426ecd5322285d1e"
|
||||
"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
|
||||
"checksum kairos 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4eb20c83592f59719373e14ef037aea9b09e11bc8b02e2f0ca2e9c8eeac6ba6b"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b"
|
||||
"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
|
||||
"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2"
|
||||
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
|
||||
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
|
||||
"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe"
|
||||
"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364"
|
||||
"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
|
||||
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
|
||||
"checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45"
|
||||
"checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28"
|
||||
"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
|
||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
|
||||
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
|
||||
"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
|
||||
"checksum rustyline 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00b06ac9c8e8e3e83b33d175d39a9f7b6c2c930c82990593719c8e48788ae2d9"
|
||||
"checksum serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "a73973861352c932ed1365ce22b32467ce260ac4c8db11cf750ce56334ff2dcf"
|
||||
"checksum serde_derive 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b392c5a0cebb98121454531c50e60e2ffe0fbeb1a44da277da2d681d08d7dc0b"
|
||||
"checksum serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d30c4596450fd7bbda79ef15559683f9a79ac0193ea819db90000d7e1cae794"
|
||||
"checksum serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6c4e049dc657a99e394bd85c22acbf97356feeec6dbf44150f2dcf79fb3118"
|
||||
"checksum serde 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "97f6a6c3caba0cf8f883b53331791036404ce3c1bd895961cf8bb2f8cecfd84b"
|
||||
"checksum serde_derive 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "f51b0ef935cf8a41a77bce553da1f8751a739b7ad82dd73669475a22e6ecedb0"
|
||||
"checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1"
|
||||
"checksum serde_yaml 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "107bb818146aaf922e7bbcf6a940f1db2f0dcf381779b451e400331b2c6f86db"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
|
||||
"checksum syn 0.13.10 (registry+https://github.com/rust-lang/crates.io-index)" = "77961dcdac942fa8bc033c16f3a790b311c8a27d00811b878ebd8cf9b7ba39d5"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum task-hookrs 0.5.0 (git+https://github.com/maralorn/task-hookrs.git?branch=preview)" = "<none>"
|
||||
"checksum termios 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70226acdf12d182df757d9fb07c0257a1558ec48c8059f607d6b38145ce4e2fa"
|
||||
"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
|
||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
|
@ -420,3 +484,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum yaml-rust 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57ab38ee1a4a266ed033496cf9af1828d8d6e6c1cfa5f643a2809effcae4d628"
|
||||
|
|
|
@ -4,5 +4,14 @@ version = "0.1.0"
|
|||
authors = ["Malte Brandy <malte.brandy@maralorn.de>"]
|
||||
|
||||
[dependencies]
|
||||
task-hookrs = { git = "https://github.com/maralorn/task-hookrs.git", branch = "preview"}
|
||||
dialog = { git = "https://git.darmstadt.ccc.de/maralorn/dialog-rs.git" }
|
||||
#task-hookrs = { git = "https://github.com/maralorn/task-hookrs.git", branch = "preview"}
|
||||
task-hookrs = { path = "/home/maralorn/code/task-hookrs"}
|
||||
dialog = { path = "/home/maralorn/code/dialog-rs" }
|
||||
lazy_static = "1.0.0"
|
||||
uuid = "0.6"
|
||||
kairos = "0.1.0"
|
||||
chrono = "0.4.2"
|
||||
error-chain = "0.11.0"
|
||||
serde_derive = "1.0"
|
||||
serde = "1.0"
|
||||
serde_yaml = "0.7"
|
||||
|
|
|
@ -1,74 +1,162 @@
|
|||
extern crate rust_scripts;
|
||||
use rust_scripts::hotkeys::*;
|
||||
extern crate task_hookrs;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
fn main() {
|
||||
let state;
|
||||
let location;
|
||||
use std::rc::Rc;
|
||||
use rust_scripts::hotkeys::{run, term, holdterm, menu, main_loop, Next};
|
||||
use rust_scripts::kassandra::{kassandra, change_state, new_tasks};
|
||||
use rust_scripts::error::Result;
|
||||
|
||||
let volume_up = (
|
||||
c("Volume up"),
|
||||
Fork(cmd(
|
||||
vec!["pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%"],
|
||||
)),
|
||||
quick_main!(|| -> Result<()> {
|
||||
let w17menu = {
|
||||
let summer = holdterm("Summer", "ssh summer@door.w17.io");
|
||||
let lock = holdterm("Lock", "ssh close@door.w17.io");
|
||||
let unlock = holdterm("Unlock", "ssh open@door.w17.io");
|
||||
let mpd_whisky = term("MPD Whisky", "ncmpcpp -h whisky");
|
||||
let hub = run("Hub", "firefox --new-window https://hub.w17.io");
|
||||
let kitchen = run("Kitchen", "firefox --new-window http://kitchen.w17.io");
|
||||
menu("w17", vec![lock, unlock, summer, hub, mpd_whisky, kitchen])
|
||||
};
|
||||
|
||||
let powermenu = {
|
||||
let inhibit = term(
|
||||
"Inhibit Suspend",
|
||||
"systemd-inhibit --what handle-lid-switch watch echo 'Lid switch inhibited'",
|
||||
);
|
||||
let logout = run("Logout", "i3-msg exit");
|
||||
let shutdown = run("Shutdown", "systemctl poweroff");
|
||||
let suspend = run("Suspend", "systemctl suspend");
|
||||
let reboot = run("Reboot", "systemctl reboot");
|
||||
let lock = run("Lock", "loginctl lock-session");
|
||||
menu(
|
||||
"Power",
|
||||
vec![shutdown, suspend, reboot, lock, inhibit, logout],
|
||||
)
|
||||
};
|
||||
let soundmenu = {
|
||||
let mpd = term("MPD", "ncmpcpp");
|
||||
let grammofy = run("Grammofy", "firefox --new-window https://grammofy.com");
|
||||
let pavucontrol = run("Lautstärke", "pavucontrol");
|
||||
menu("Sound", vec![mpd, pavucontrol, grammofy])
|
||||
};
|
||||
let apps = {
|
||||
menu(
|
||||
"Apps",
|
||||
vec![
|
||||
run("Launch", "rofi -show combi"),
|
||||
run("Private Browser", "firefox --private-window"),
|
||||
run("Browser", "firefox --new-window"),
|
||||
run("Deluge", "deluge"),
|
||||
run("Filemanager", "nautilus"),
|
||||
menu(
|
||||
"Messaging",
|
||||
vec![
|
||||
run("Mails", "evolution"),
|
||||
run("Riot", "firefox --new-window https://riot.im/app"),
|
||||
run("WhatsApp", "firefox --new-window https://web.whatsapp.com"),
|
||||
run("Telegram", "telegram-desktop"),
|
||||
run("Signal", "signal-desktop"),
|
||||
run("Jabber", "dino"),
|
||||
run(
|
||||
"Regiotelko",
|
||||
"mumble mumble://maralorn@mumble.c3pb.de/CCC/Regiotelko"
|
||||
),
|
||||
]
|
||||
),
|
||||
menu(
|
||||
"Accounting",
|
||||
vec![
|
||||
holdterm("Jali", "jali -l ."),
|
||||
run(
|
||||
"Beschlüsse",
|
||||
"firefox --new-window https://git.darmstadt.ccc.de/vorstand/beschluesse/raw/master/beschl%C3%BCsse"
|
||||
),
|
||||
term(
|
||||
"Private Buchhaltung",
|
||||
"hledger -f data/aktuell/lebenshaltung/buchhaltung/buchhaltung.ledger ui"
|
||||
),
|
||||
term(
|
||||
"CDA Buchhaltung",
|
||||
"hledger -f data/aktuell/ccc/cda/vorstand/buchhaltung/buchhaltung.ledger ui"
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
)
|
||||
};
|
||||
let maintenance = {
|
||||
let keymenu = menu(
|
||||
"Keymap",
|
||||
vec![
|
||||
run("neo", "setxkbmap de neo"),
|
||||
run("qwertz", "setxkbmap de"),
|
||||
],
|
||||
);
|
||||
let monitor = term("Monitor", "htop");
|
||||
let wifi = term("WLAN", "nmtui");
|
||||
let update_home = holdterm("Update Home", "home-manager switch");
|
||||
let update_sys = holdterm("Update Sys", "sudo nixos-rebuild switch");
|
||||
let gc = holdterm("Collect Garbage", "nix-collect-garbage -d");
|
||||
let optimise = holdterm("Optimise", "nix optimise-store");
|
||||
menu(
|
||||
"Maintenance",
|
||||
vec![
|
||||
wifi,
|
||||
update_home,
|
||||
update_sys,
|
||||
gc,
|
||||
optimise,
|
||||
monitor,
|
||||
keymenu,
|
||||
run("Bildschirme", "arandr"),
|
||||
],
|
||||
)
|
||||
};
|
||||
let ssh = menu(
|
||||
"ssh",
|
||||
vec![
|
||||
("kiva", "brandy@kiva-forward"),
|
||||
("ag", "brandy@ag-forward"),
|
||||
("whisky", "whisky"),
|
||||
("vorstand", "vorstand"),
|
||||
("shells", "shells"),
|
||||
("charon", "charon"),
|
||||
].into_iter()
|
||||
.map(|(name, login)| term(name, &format!("ssh {}", login)))
|
||||
.collect(),
|
||||
);
|
||||
let volume_down = (
|
||||
c("Volume down"),
|
||||
Fork(cmd(
|
||||
vec!["pactl", "set-sink-volume", "@DEFAULT_SINK@", "-5%"],
|
||||
)),
|
||||
);
|
||||
let ncmpcpp = (c("Music"), Exec(cmd(vec!["urxvt", "-e", "ncmpcpp"])));
|
||||
let wizard = (c("Magic"), Script);
|
||||
let startmenu = Menu((c("Hauptmenü"), vec![wizard]))
|
||||
// arandr?
|
||||
// keymap
|
||||
// shutdown options
|
||||
// lautstärken micro, lautsprecher, regler zeigen
|
||||
// zeige Buchhaltung
|
||||
// mumble
|
||||
// hub.w17.io
|
||||
// select wifi
|
||||
|
||||
// sshuttle
|
||||
// tinc
|
||||
// routes
|
||||
// debug network
|
||||
// grammofy
|
||||
// browser + pm
|
||||
// IM dienste
|
||||
// evolution
|
||||
// door options, music options, hub options
|
||||
// lock inhibit
|
||||
// suspend inhibit
|
||||
// ssh kiva, ag, whisky, vorstand, shells, charon
|
||||
let w17menu
|
||||
main_loop(startmenu);
|
||||
// Brightness -> i3
|
||||
// Basic Sound -> i3
|
||||
}
|
||||
|
||||
fn wizard() -> Next {
|
||||
// states: work, research, normal, idle
|
||||
// enter new tasks
|
||||
// always: add task/subtask
|
||||
// what about running tasks?
|
||||
// check unread E-Mail + ak?
|
||||
// update
|
||||
// system
|
||||
// home
|
||||
// inbox
|
||||
//
|
||||
// treesort
|
||||
// mails
|
||||
// sort inbox
|
||||
// sort inboxkiva
|
||||
// sort inboxak
|
||||
// sort to sort
|
||||
// go trough todo
|
||||
// go trough toread
|
||||
// go trough readlater
|
||||
// pick tasks
|
||||
// optional, later
|
||||
// await
|
||||
// do accounting own, cda
|
||||
// dirty gits
|
||||
|
||||
// task generator
|
||||
// task completion helper
|
||||
}
|
||||
let startmenu = menu(
|
||||
"Hauptmenü",
|
||||
vec![
|
||||
(
|
||||
"New Task".into(),
|
||||
Next::Do(Rc::new(|| new_tasks().map(|_| Next::Exit)))
|
||||
),
|
||||
(
|
||||
"Kassandra".into(),
|
||||
Next::Do(Rc::new(|| kassandra().map(|_| Next::Exit)))
|
||||
),
|
||||
(
|
||||
"Change State".into(),
|
||||
Next::Do(Rc::new(|| change_state().map(|_| Next::Exit)))
|
||||
),
|
||||
ssh,
|
||||
apps,
|
||||
run("Tasks", "tasklauncher"),
|
||||
run("Tasktree", "tasktree"),
|
||||
term("Files", "ranger"),
|
||||
soundmenu,
|
||||
w17menu,
|
||||
powermenu,
|
||||
maintenance,
|
||||
],
|
||||
).1;
|
||||
main_loop(startmenu)
|
||||
});
|
||||
|
|
7
packages/rust-scripts/src/bin/kassandra.rs
Normal file
7
packages/rust-scripts/src/bin/kassandra.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
extern crate rust_scripts;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
use rust_scripts::kassandra::kassandra;
|
||||
|
||||
quick_main!(kassandra);
|
323
packages/rust-scripts/src/generate.rs
Normal file
323
packages/rust-scripts/src/generate.rs
Normal file
|
@ -0,0 +1,323 @@
|
|||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
|
||||
//! This module contains the generate function and the GeneratedTask trait.
|
||||
//! You can routinely generate GeneratedTasks which represent some external state,
|
||||
//! like e-mails you need to read, tickets from an issue tracker, or updates you have to do on a
|
||||
//! system. If you pass them to the generate function, it will update your taskwarrior accordingly.
|
||||
//! Create new tasks, complete old ones and update once which have new information.
|
||||
//! Fields which you don't set in a GeneratedTask can be set in taskwarrior and won't be
|
||||
//! overwritten on calling generate again.
|
||||
use task_hookrs::task::Task;
|
||||
use task_hookrs::status::TaskStatus as TS;
|
||||
use task_hookrs::uda::UDAValue as U;
|
||||
use generate::OrphanBehavior as O;
|
||||
use task_hookrs::cache::TaskCache;
|
||||
use task_hookrs::error::{Result, ResultExt};
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
/// This trait contains additional methods for the Task struct, for representing programatically
|
||||
/// generated tasks
|
||||
pub trait GeneratedTask {
|
||||
/// The name of this generator type. e.g. "mail"
|
||||
fn gen_name(&self) -> Option<&String>;
|
||||
/// The name of this generator type. e.g. "mail", mutable
|
||||
fn gen_name_mut(&mut self) -> Option<&mut String>;
|
||||
/// Set the name of this generator type. e.g. "mail"
|
||||
fn set_gen_name<T>(&mut self, new: Option<T>)
|
||||
where
|
||||
T: Into<String>;
|
||||
/// The id of the generator type, which should be unique for all generator Tasks with the same
|
||||
/// name
|
||||
fn gen_id(&self) -> Option<&String>;
|
||||
/// The generator id, mutable
|
||||
fn gen_id_mut(&mut self) -> Option<&mut String>;
|
||||
/// Set the generator id
|
||||
fn set_gen_id<T>(&mut self, new: Option<T>)
|
||||
where
|
||||
T: Into<String>;
|
||||
/// What should happen with the task, when the generator is missing.
|
||||
/// This is relevant, when the generate method is called with one or more tasks with a
|
||||
/// generator name set, all existing tasks with that generator name will be dealt with
|
||||
/// according to this field.
|
||||
fn gen_orphan(&self) -> OrphanBehavior;
|
||||
/// Set the OrphanBehavior
|
||||
fn set_gen_orphan<T>(&mut self, new: OrphanBehavior);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref DELETE: U = U::Str("delete".into());
|
||||
static ref COMPLETE: U = U::Str("complete".into());
|
||||
static ref EMPTY: U = U::Str(String::default());
|
||||
}
|
||||
static GEN_NAME: &str = "gen_name";
|
||||
static GEN_ID: &str = "gen_id";
|
||||
static GEN_ORPHAN: &str = "gen_orphan";
|
||||
|
||||
/// The behavior if a task with missing generator is encountered.
|
||||
pub enum OrphanBehavior {
|
||||
/// Complete generated tasks, with missing generator
|
||||
CompleteOrphan,
|
||||
/// Delete generated tasks, with missing generator
|
||||
DeleteOrphan,
|
||||
/// Don't do anything with generated tasks, with missing generator
|
||||
KeepOrphan,
|
||||
}
|
||||
|
||||
impl GeneratedTask for Task {
|
||||
fn gen_name(&self) -> Option<&String> {
|
||||
self.uda().get(GEN_NAME).and_then(
|
||||
|x| if let &U::Str(ref x) = x {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn gen_name_mut(&mut self) -> Option<&mut String> {
|
||||
self.uda_mut().get_mut(GEN_NAME).and_then(|x| {
|
||||
if let &mut U::Str(ref mut x) = x {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn set_gen_name<T>(&mut self, new: Option<T>)
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
if let Some(new) = new {
|
||||
self.uda_mut().insert(GEN_NAME.into(), U::Str(new.into()));
|
||||
} else {
|
||||
self.uda_mut().remove(GEN_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_id(&self) -> Option<&String> {
|
||||
self.uda().get(GEN_ID).and_then(
|
||||
|x| if let &U::Str(ref x) = x {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn gen_id_mut(&mut self) -> Option<&mut String> {
|
||||
self.uda_mut().get_mut(GEN_ID).and_then(|x| {
|
||||
if let &mut U::Str(ref mut x) = x {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn set_gen_id<T>(&mut self, new: Option<T>)
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
if let Some(new) = new {
|
||||
self.uda_mut().insert(GEN_ID.into(), U::Str(new.into()));
|
||||
} else {
|
||||
self.uda_mut().remove(GEN_ID);
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_orphan(&self) -> OrphanBehavior {
|
||||
let u = self.uda().get(GEN_ORPHAN).unwrap_or(&*EMPTY);
|
||||
if *u == *COMPLETE {
|
||||
O::CompleteOrphan
|
||||
} else if *u == *DELETE {
|
||||
O::DeleteOrphan
|
||||
} else {
|
||||
O::KeepOrphan
|
||||
}
|
||||
}
|
||||
|
||||
fn set_gen_orphan<T>(&mut self, new: OrphanBehavior) {
|
||||
match new {
|
||||
O::DeleteOrphan => self.uda_mut().insert(GEN_ORPHAN.into(), DELETE.clone()),
|
||||
O::CompleteOrphan => self.uda_mut().insert(GEN_ORPHAN.into(), COMPLETE.clone()),
|
||||
O::KeepOrphan => self.uda_mut().remove(GEN_ORPHAN),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ignores(cache: &TaskCache) -> Result<()> {
|
||||
if cache.ignore().len() > 0 {
|
||||
return Err("Don't use generate with a TaskCache with ignores".into());
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_new(cache: &mut TaskCache, new: Vec<Task>) {
|
||||
for task in new {
|
||||
cache.set(task);
|
||||
}
|
||||
}
|
||||
|
||||
fn r<'a>(c: &'a TaskCache, u: &Uuid) -> Result<&'a Task> {
|
||||
c.get(u).chain_err(|| "Cache miss for changed task")
|
||||
}
|
||||
|
||||
fn w<'a>(c: &'a mut TaskCache, u: &Uuid) -> Result<&'a mut Task> {
|
||||
c.get_mut(u).chain_err(|| "Cache miss for changed task")
|
||||
}
|
||||
|
||||
fn process_matches(cache: &mut TaskCache, matches: Vec<(Uuid, Task)>) -> Result<()> {
|
||||
let c = cache;
|
||||
for (u, new) in matches {
|
||||
if r(c,&u)?.status() != new.status() {
|
||||
*w(c,&u)?.status_mut() = new.status().clone();
|
||||
}
|
||||
if r(c,&u)?.description() != new.description() {
|
||||
*w(c,&u)?.description_mut() = new.description().clone();
|
||||
}
|
||||
if let Some(ann) = new.annotations() {
|
||||
if r(c,&u)?.annotations().map(|x| x != ann) == Some(true) {
|
||||
w(c,&u)?.annotations_mut().map(|o| *o = ann.clone());
|
||||
}
|
||||
}
|
||||
if let Some(dep) = new.depends() {
|
||||
if r(c,&u)?.depends().map(|x| x != dep) == Some(true) {
|
||||
w(c,&u)?.depends_mut().map(|o| *o = dep.clone());
|
||||
}
|
||||
}
|
||||
if let Some(due) = new.due() {
|
||||
if r(c,&u)?.due().map(|x| x != due) == Some(true) {
|
||||
w(c,&u)?.due_mut().map(|o| *o = due.clone());
|
||||
}
|
||||
}
|
||||
if let Some(end) = new.end() {
|
||||
if r(c,&u)?.end().map(|x| x != end) == Some(true) {
|
||||
w(c,&u)?.end_mut().map(|o| *o = end.clone());
|
||||
}
|
||||
}
|
||||
if let Some(ann) = new.annotations() {
|
||||
if r(c,&u)?.annotations().map(|x| x != ann) == Some(true) {
|
||||
w(c,&u)?.annotations_mut().map(|o| *o = ann.clone());
|
||||
}
|
||||
}
|
||||
if let Some(recur) = new.recur() {
|
||||
if r(c,&u)?.recur().map(|x| x != recur) == Some(true) {
|
||||
w(c,&u)?.recur_mut().map(|o| *o = recur.clone());
|
||||
}
|
||||
}
|
||||
if let Some(scheduled) = new.scheduled() {
|
||||
if r(c,&u)?.scheduled().map(|x| x != scheduled) == Some(true) {
|
||||
w(c,&u)?.scheduled_mut().map(|o| *o = scheduled.clone());
|
||||
}
|
||||
}
|
||||
if let Some(start) = new.start() {
|
||||
if r(c,&u)?.start().map(|x| x != start) == Some(true) {
|
||||
w(c,&u)?.start_mut().map(|o| *o = start.clone());
|
||||
}
|
||||
}
|
||||
if let Some(tags) = new.tags() {
|
||||
if r(c,&u)?.tags().map(|x| x != tags) == Some(true) {
|
||||
w(c,&u)?.tags_mut().map(|o| *o = tags.clone());
|
||||
}
|
||||
}
|
||||
if let Some(until) = new.until() {
|
||||
if r(c,&u)?.until().map(|x| x != until) == Some(true) {
|
||||
w(c,&u)?.until_mut().map(|o| *o = until.clone());
|
||||
}
|
||||
}
|
||||
if let Some(wait) = new.wait() {
|
||||
if r(c,&u)?.wait().map(|x| x != wait) == Some(true) {
|
||||
w(c,&u)?.wait_mut().map(|o| *o = wait.clone());
|
||||
}
|
||||
}
|
||||
if !(r(c,&u)?.uda() >= new.uda()) {
|
||||
w(c,&u)?.uda_mut().append(&mut new.uda().clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_orphans(
|
||||
cache: &mut TaskCache,
|
||||
orphans: HashMap<String, HashMap<String, Uuid>>,
|
||||
) -> Result<()> {
|
||||
for uuid in orphans.values().flat_map(HashMap::values) {
|
||||
match cache.get(uuid).chain_err(|| "Cache miss for orphan")?.gen_orphan() {
|
||||
O::CompleteOrphan => if *cache.get(uuid).chain_err(|| "Cache miss for orphan")?.status() != TS::Completed {
|
||||
*cache.get_mut(uuid).chain_err(|| "Cache miss for orphan")?.status_mut() = TS::Completed;
|
||||
}
|
||||
O::DeleteOrphan => if *cache.get(uuid).chain_err(|| "Cache miss for orphan")?.status() != TS::Deleted {
|
||||
*cache.get_mut(uuid).chain_err(|| "Cache miss for orphan")?.status_mut() = TS::Deleted;
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Take a TaskCache (which should not ignore any task states) and make sure, that all given
|
||||
/// generator tasks are represented in taskwarrior.
|
||||
|
||||
pub trait TaskGenerator {
|
||||
fn get_by_gen(&self, generator: &Task) -> Option<&Task>;
|
||||
fn get_by_gen_mut(&mut self, generator: &Task) -> Option<&mut Task>;
|
||||
fn generate<T>(&mut self, generators: T) -> Result<()>
|
||||
where
|
||||
T: IntoIterator,
|
||||
T::Item: Into<Task>;
|
||||
}
|
||||
|
||||
fn gen_match(a: &Task, b: &Task) -> bool {
|
||||
a.gen_name() == b.gen_name() && a.gen_id() == b.gen_id()
|
||||
}
|
||||
impl TaskGenerator for TaskCache {
|
||||
fn get_by_gen(&self, generator: &Task) -> Option<&Task> {
|
||||
self.filter(|t| gen_match(t, generator)).into_iter().next()
|
||||
}
|
||||
fn get_by_gen_mut(&mut self, generator: &Task) -> Option<&mut Task> {
|
||||
self.filter_mut(|t| gen_match(t, generator)).into_iter().next()
|
||||
}
|
||||
|
||||
fn generate<T>(&mut self, generators: T) -> Result<()>
|
||||
where
|
||||
T: IntoIterator,
|
||||
T::Item: Into<Task>,
|
||||
{
|
||||
check_ignores(self)?;
|
||||
let mut orphans = HashMap::<String, HashMap<String, Uuid>>::default();
|
||||
let mut create = Vec::<Task>::default();
|
||||
let mut changes = Vec::<(Uuid, Task)>::default();
|
||||
for g in generators {
|
||||
let new = g.into();
|
||||
if let Some(old) = {
|
||||
let name = new.gen_name().chain_err(|| "gen_name missing")?;
|
||||
let id = new.gen_id().chain_err(|| "gen_id missing")?;
|
||||
orphans
|
||||
.entry(name.clone())
|
||||
.or_insert_with(|| {
|
||||
self
|
||||
.filter(|t| t.gen_name() == Some(name))
|
||||
.iter()
|
||||
.filter_map(|t| t.gen_id().map(|id| (id.clone(), t.uuid().clone())))
|
||||
.collect()
|
||||
})
|
||||
.remove(id)
|
||||
}
|
||||
{
|
||||
changes.push((old, new));
|
||||
} else {
|
||||
create.push(new);
|
||||
}
|
||||
}
|
||||
process_new(self, create);
|
||||
process_matches(self, changes)?;
|
||||
process_orphans(self, orphans)
|
||||
}
|
||||
}
|
97
packages/rust-scripts/src/hotkeys.rs
Normal file
97
packages/rust-scripts/src/hotkeys.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use std::rc::Rc;
|
||||
use dialog::DialogProvider;
|
||||
use dialog::errors::{Error, ErrorKind as EK};
|
||||
use dialog::rofi::RofiDialogProvider;
|
||||
use std::process::Command as StdCommand;
|
||||
use std::os::unix::process::CommandExt;
|
||||
use error::{Result, ResultExt};
|
||||
|
||||
use hotkeys::Next::*;
|
||||
|
||||
pub fn run<T: Into<String>>(name: T, command: &str) -> Item {
|
||||
let command = command.to_owned();
|
||||
(
|
||||
name.into(),
|
||||
Do(Rc::new(move || {
|
||||
str2cmd(&command).exec();
|
||||
Ok(Exit)
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn term<T: Into<String>>(name: T, command: &str) -> Item {
|
||||
run(name, &format!("urxvt -e {}", command))
|
||||
}
|
||||
|
||||
pub fn holdterm<T: Into<String>>(name: T, command: &str) -> Item {
|
||||
run(name, &format!("urxvt -hold -e {}", command))
|
||||
}
|
||||
|
||||
pub fn menu<T: Into<String>>(name: T, options: Vec<Item>) -> Item {
|
||||
let name = name.into();
|
||||
(name.clone(), Menu((name.clone(), options)))
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Next {
|
||||
Menu(Dialog),
|
||||
Back,
|
||||
Exit,
|
||||
Stay,
|
||||
Do(Rc<Fn() -> Result<Next>>),
|
||||
}
|
||||
|
||||
type Dialog = (String, Vec<Item>);
|
||||
|
||||
type Item = (String, Next);
|
||||
|
||||
type Command = Vec<String>;
|
||||
|
||||
fn show_menu<T: DialogProvider>(dialog_provider: &mut T, menu: Dialog) -> Result<Next> {
|
||||
let (msg, mut options) = menu;
|
||||
options.insert(0, (".Back".into(), Back));
|
||||
match dialog_provider.select_option(msg, options) {
|
||||
Ok(next) => Ok(next),
|
||||
Err(Error(EK::InvalidUserInput, _)) => Ok(Stay),
|
||||
err => err.chain_err(|| "User Input Error"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn str2cmd(cmd: &str) -> StdCommand {
|
||||
mk_cmd(
|
||||
cmd.split_whitespace()
|
||||
.map(str::to_owned)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn mk_cmd(cmd: Command) -> StdCommand {
|
||||
let mut cmd_iter = cmd.iter();
|
||||
let mut prg = StdCommand::new(cmd_iter.next().expect("Called program without name"));
|
||||
for arg in cmd_iter {
|
||||
prg.arg(arg);
|
||||
}
|
||||
prg
|
||||
}
|
||||
|
||||
pub fn main_loop(startmenu: Next) -> Result<()> {
|
||||
let mut dialog_provider = RofiDialogProvider;
|
||||
let mut history = vec![];
|
||||
let mut next = startmenu;
|
||||
loop {
|
||||
next = match next {
|
||||
Exit => break,
|
||||
Back => {
|
||||
history.pop().chain_err(|| "Empty history")?;
|
||||
Stay
|
||||
}
|
||||
Do(script) => script()?,
|
||||
Menu(menu) => {
|
||||
history.push(menu.clone());
|
||||
show_menu(&mut dialog_provider, menu)?
|
||||
}
|
||||
Stay => Menu(history.pop().chain_err(|| "Empty history")?.clone()),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
779
packages/rust-scripts/src/kassandra.rs
Normal file
779
packages/rust-scripts/src/kassandra.rs
Normal file
|
@ -0,0 +1,779 @@
|
|||
use std::fs::File;
|
||||
use std::env::home_dir;
|
||||
use std::iter::once;
|
||||
|
||||
use serde_yaml::{from_reader, to_writer, to_string};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use task_hookrs::cache::TaskCache;
|
||||
use task_hookrs::task::{Task, TaskBuilder};
|
||||
|
||||
use dialog::rofi::RofiDialogProvider;
|
||||
use dialog::DialogProvider;
|
||||
use dialog::errors::ErrorKind as DEK;
|
||||
|
||||
use update::update_tasks;
|
||||
use generate::GeneratedTask;
|
||||
use error::{Result, ResultExt, ErrorKind as EK, Error};
|
||||
use hotkeys::str2cmd;
|
||||
use tasktree::{TreeCache, TaskNode};
|
||||
|
||||
fn print_task_short(task: &Task) -> String {
|
||||
let mut info = vec![task.description().clone()];
|
||||
if let Some(tags) = task.tags() {
|
||||
info.push(format!("+{}", tags.join(",+")));
|
||||
}
|
||||
if let Some(project) = task.project() {
|
||||
info.push(format!("({})", project));
|
||||
}
|
||||
info.join(" ")
|
||||
}
|
||||
|
||||
fn print_task(task: &Task) -> String {
|
||||
let mut info = vec![task.description().clone()];
|
||||
info.push(format!("status: {}", task.status()));
|
||||
if let Some(project) = task.project() {
|
||||
info.push(format!("project: {}", project));
|
||||
}
|
||||
if let Some(tags) = task.tags() {
|
||||
info.push(format!("tags: {}", tags.join(", ")));
|
||||
}
|
||||
info.join("\n")
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
enum Mode {
|
||||
#[serde(rename = "work")]
|
||||
Work,
|
||||
#[serde(rename = "research")]
|
||||
Research,
|
||||
#[serde(rename = "orga")]
|
||||
Orga,
|
||||
#[serde(rename = "idle")]
|
||||
Idle,
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
enum Connectivity {
|
||||
#[serde(rename = "online")]
|
||||
Online,
|
||||
#[serde(rename = "offline")]
|
||||
Offline,
|
||||
#[serde(rename = "limited")]
|
||||
Limited,
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
enum Location {
|
||||
#[serde(rename = "home")]
|
||||
Home,
|
||||
#[serde(rename = "w17")]
|
||||
W17,
|
||||
#[serde(rename = "city")]
|
||||
City,
|
||||
#[serde(rename = "uni")]
|
||||
Uni,
|
||||
#[serde(rename = "anywhere")]
|
||||
Anywhere,
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
struct State {
|
||||
mode: Mode,
|
||||
location: Location,
|
||||
connectivity: Connectivity,
|
||||
}
|
||||
|
||||
fn task_blocked(cache: &TaskCache, task: &Task) -> bool {
|
||||
task.depends()
|
||||
.map(|dependencies| {
|
||||
for dependency in dependencies {
|
||||
if cache.get(dependency).map(|t| !t.obsolete()).unwrap_or(
|
||||
false,
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn task_needs_sorting(cache: &TaskCache, uuid: &Uuid) -> Result<bool> {
|
||||
Ok(!cache.is_project(&uuid) && cache.get_parent(&uuid)? == None)
|
||||
}
|
||||
|
||||
fn task_inbox(cache: &TaskCache, task: &Task) -> bool {
|
||||
task.pending() && !task.tagged() && !task_blocked(cache, task)
|
||||
}
|
||||
|
||||
fn save_state(state: &State) -> Result<()> {
|
||||
let state_path = &{
|
||||
let mut s = home_dir().chain_err(|| "No Home")?;
|
||||
s.push(".kassandra_state");
|
||||
s
|
||||
};
|
||||
let state_file = File::create(&state_path)?;
|
||||
to_writer(state_file, &state)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_state() -> Result<State> {
|
||||
let state_path = &{
|
||||
let mut s = home_dir().chain_err(|| "No Home")?;
|
||||
s.push(".kassandra_state");
|
||||
s
|
||||
};
|
||||
Ok(if let Ok(state_file) = File::open(&state_path) {
|
||||
from_reader(state_file)?
|
||||
} else {
|
||||
let state = State {
|
||||
mode: Mode::Orga,
|
||||
connectivity: Connectivity::Online,
|
||||
location: Location::Anywhere,
|
||||
};
|
||||
save_state(&state)?;
|
||||
state
|
||||
})
|
||||
}
|
||||
|
||||
fn enter_new_task<T: DialogProvider, S: Into<String>>(dialog: &mut T, msg: S) -> Result<Task> {
|
||||
Ok(TaskBuilder::default()
|
||||
.description(dialog.input_line(msg, Vec::<String>::default())?)
|
||||
.build()?)
|
||||
}
|
||||
|
||||
|
||||
struct Kassandra {
|
||||
state: State,
|
||||
dialog: RofiDialogProvider,
|
||||
cache: TaskCache,
|
||||
}
|
||||
|
||||
|
||||
impl Kassandra {
|
||||
fn new() -> Result<Self> {
|
||||
Ok(Kassandra {
|
||||
state: get_state()?,
|
||||
dialog: RofiDialogProvider {},
|
||||
cache: TaskCache::new(vec![]),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
fn run(&mut self) -> Result<()> {
|
||||
self.cache.load()?;
|
||||
update_tasks(&mut self.cache)?;
|
||||
self.cache.write()?;
|
||||
self.handle_active_tasks()?;
|
||||
self.clear_inbox()?;
|
||||
self.assure_all_sorted()?;
|
||||
|
||||
// check unread E-Mail + ak?
|
||||
// update
|
||||
// system
|
||||
// home
|
||||
// mails
|
||||
// sort inbox
|
||||
// sort inboxkiva
|
||||
// sort inboxak
|
||||
// sort to sort
|
||||
// go trough todo
|
||||
// go trough toread
|
||||
// go trough readlater
|
||||
// pick tasks
|
||||
// optional, later
|
||||
// await
|
||||
// dirty gits
|
||||
|
||||
// task generator
|
||||
// task completion helper
|
||||
self.update_accounting()?;
|
||||
self.select_next_task()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_sorted_uuids<T: Fn(&Task) -> bool>(&self, filter: T) -> Vec<Uuid> {
|
||||
self.get_sorted_tasks(filter)
|
||||
.into_iter()
|
||||
.map(|x| x.uuid().clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_sorted_tasks<T: Fn(&Task) -> bool>(&self, filter: T) -> Vec<&Task> {
|
||||
let mut tasks = self.cache.filter(filter);
|
||||
tasks.sort_unstable_by_key(|t| t.entry().date());
|
||||
tasks
|
||||
}
|
||||
|
||||
fn get_notes(&mut self) -> Result<()> {
|
||||
loop {
|
||||
match enter_new_task(
|
||||
&mut self.dialog,
|
||||
"Do you have anything to note?
|
||||
For example, what you are doing right now or still have to do today?",
|
||||
) {
|
||||
Ok(task) => {
|
||||
self.cache.set(task);
|
||||
self.cache.write()?;
|
||||
}
|
||||
Err(Error(EK::DialogError(DEK::InputCanceled), _)) => break Ok(()),
|
||||
err => {
|
||||
err?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_state(&mut self) -> Result<()> {
|
||||
loop {
|
||||
match self.dialog.select_option(
|
||||
format!(
|
||||
"State: {}
|
||||
|
||||
Do you want to change the state? (Esc to cancel)",
|
||||
to_string(&self.state)?
|
||||
),
|
||||
vec![
|
||||
("working: I am at work", "work"),
|
||||
("researching: I am researching", "research"),
|
||||
("orga: I am in normal mode", "orga"),
|
||||
("home: I am at home", "home"),
|
||||
("uni: I am at the Mathebau", "uni"),
|
||||
("hackspace: I am in the hackspace", "w17"),
|
||||
("city: I am in the city", "city"),
|
||||
("anywhere: I'm nowhere special", "anywhere"),
|
||||
(
|
||||
"idle: I am not interested in doing anything",
|
||||
"idle"
|
||||
),
|
||||
],
|
||||
)? {
|
||||
"work" => self.state.mode = Mode::Work,
|
||||
"research" => self.state.mode = Mode::Research,
|
||||
"orga" => self.state.mode = Mode::Orga,
|
||||
"home" => self.state.location = Location::Home,
|
||||
"w17" => self.state.location = Location::W17,
|
||||
"city" => self.state.location = Location::City,
|
||||
"idle" => self.state.mode = Mode::Idle,
|
||||
"uni" => self.state.location = Location::Uni,
|
||||
"anywhere" => self.state.location = Location::Anywhere,
|
||||
_ => (),
|
||||
};
|
||||
save_state(&self.state)?;
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_active_tasks(&mut self) -> Result<()> {
|
||||
while let Some(uuid) = self.get_sorted_uuids(|t| t.start().is_some() && t.pending())
|
||||
.into_iter()
|
||||
.next()
|
||||
{
|
||||
match self.dialog.select_option(
|
||||
format!(
|
||||
"You are currently working on {}
|
||||
What's the progress?",
|
||||
print_task(
|
||||
self.cache.get(&uuid).chain_err(|| "uuid miss")?,
|
||||
)
|
||||
),
|
||||
vec![
|
||||
("Continue: I'll get back to it", "continue"),
|
||||
("Done: I've done that!", "done"),
|
||||
("Later: I'll do that later", "later"),
|
||||
("Edit: I have changes to this task", "edit"),
|
||||
],
|
||||
)? {
|
||||
"done" => {
|
||||
{
|
||||
let task = self.cache.get_mut(&uuid).chain_err(|| "missing uuid")?;
|
||||
task.tw_stop();
|
||||
task.tw_done();
|
||||
}
|
||||
self.cache.write()?;
|
||||
}
|
||||
"later" => {
|
||||
self.cache
|
||||
.get_mut(&uuid)
|
||||
.chain_err(|| "missing uuid")?
|
||||
.tw_stop();
|
||||
self.cache.write()?;
|
||||
}
|
||||
"edit" => {
|
||||
self.cache
|
||||
.get_mut(&uuid)
|
||||
.chain_err(|| "missing uuid")?
|
||||
.tw_stop();
|
||||
self.cache.write()?;
|
||||
self.edit_task(&uuid)?;
|
||||
}
|
||||
_ => bail!("Continuing with task"),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn assure_all_sorted(&mut self) -> Result<()> {
|
||||
if self.cache
|
||||
.filter(|t| {
|
||||
t.gen_name() == Some(&"Sortiere Tasktree".into()) && t.pending()
|
||||
})
|
||||
.len() > 0
|
||||
{
|
||||
while let Some(uuid) = self.get_sorted_uuids(|t| {
|
||||
!t.obsolete() && task_needs_sorting(&self.cache, t.uuid()).unwrap_or(false)
|
||||
}).into_iter()
|
||||
.next()
|
||||
{
|
||||
self.sort(&uuid)?;
|
||||
}
|
||||
for task in self.cache.filter_mut(|t| {
|
||||
t.gen_name() == Some(&"Sortiere Tasktree".into()) && t.pending()
|
||||
})
|
||||
{
|
||||
task.tw_done()
|
||||
}
|
||||
self.cache.refresh_tree();
|
||||
self.cache.write()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sort(&mut self, uuid: &Uuid) -> Result<()> {
|
||||
let task_name = print_task(self.cache.get(uuid).chain_err(|| "mising uuid")?);
|
||||
let partof = self.select_entry_point(
|
||||
format!("Select Project for Task\n{}", task_name),
|
||||
uuid,
|
||||
)?;
|
||||
self.cache
|
||||
.get_mut(uuid)
|
||||
.chain_err(|| "assure_sorted: missing uuid")?
|
||||
.set_partof(partof);
|
||||
update_tasks(&mut self.cache)?;
|
||||
self.cache.write()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn select_entry_point<T: Into<String>>(
|
||||
&mut self,
|
||||
msg: T,
|
||||
uuid: &Uuid,
|
||||
) -> Result<Option<Uuid>> {
|
||||
let msg = msg.into();
|
||||
let format_msg = |cache: &TaskCache, uuid, text| -> Result<String> {
|
||||
Ok(format!(
|
||||
"{}\n{}: {}",
|
||||
&msg,
|
||||
text,
|
||||
if let Some(uuid) = uuid {
|
||||
cache.get_project_path(&uuid)?
|
||||
} else {
|
||||
String::default()
|
||||
}
|
||||
))
|
||||
};
|
||||
let mut parent = None;
|
||||
loop {
|
||||
match {
|
||||
let mut options = self.cache.filter(|t| {
|
||||
t.pending() && t.partof().map(|partof| partof == parent).unwrap_or(false) &&
|
||||
(parent.is_some() || self.cache.is_project(t.uuid()))
|
||||
});
|
||||
options.sort_unstable_by_key(|t| t.entry().date());
|
||||
match self.dialog.select_option(
|
||||
format_msg(&self.cache, parent, "currently at")?,
|
||||
vec![
|
||||
("select this level".into(), Err(0)),
|
||||
("insert new node".into(), Err(1)),
|
||||
("go one level up".into(), Err(2)),
|
||||
("edit task".into(), Err(4)),
|
||||
].into_iter()
|
||||
.chain(options.into_iter().map(|t| (print_task_short(t), Ok(t)))),
|
||||
)? {
|
||||
Ok(task) => {
|
||||
parent = Some(task.uuid().clone());
|
||||
3
|
||||
}
|
||||
Err(n) => n,
|
||||
}
|
||||
} {
|
||||
|
||||
0 => return Ok(parent),
|
||||
1 => {
|
||||
let mut task = enter_new_task(
|
||||
&mut self.dialog,
|
||||
format_msg(&self.cache, parent, "inserting new node at")?,
|
||||
)?;
|
||||
task.set_partof(parent);
|
||||
parent = Some(task.uuid().clone());
|
||||
self.cache.set(task);
|
||||
self.cache.write()?;
|
||||
}
|
||||
|
||||
2 => {
|
||||
parent = if let Some(parent) = parent {
|
||||
if let Some(parent) = self.cache.get(&parent) {
|
||||
parent.partof()?
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
3 => (),
|
||||
4 => {
|
||||
self.edit_task(uuid)?;
|
||||
parent = None;
|
||||
}
|
||||
_ => bail!("Hö?"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn edit_task(&mut self, uuid: &Uuid) -> Result<()> {
|
||||
loop {
|
||||
let task_name = print_task(
|
||||
self.cache.get(uuid).chain_err(|| "edit_task: missing uuid")?,
|
||||
);
|
||||
match self.dialog.select_option(
|
||||
format!(
|
||||
"Handling Task: {}\nDo you want to do this now? Can it be done in under 2 minutes?",
|
||||
task_name
|
||||
),
|
||||
vec![
|
||||
("Do it: I'll get to it", "do"),
|
||||
("Done: I already did this", "done"),
|
||||
("Delete: This does not need to be done anymore","delete"),
|
||||
("Edit description: I want to change the description", "edit"),
|
||||
("Move: Change position in tasktree", "move"),
|
||||
("Split: Give this tasks subtasks", "split"),
|
||||
("Depend: Set dependency", "depend"),
|
||||
("Postpone: Set wait time", "postpone"),
|
||||
("Tag: Add a tag", "tag"),
|
||||
("Clear tags", "clear_tags"),
|
||||
("Manual: I have to change something by hand", "manual"),
|
||||
("Quit", "quit"),
|
||||
],
|
||||
)? {
|
||||
"do" => {
|
||||
self.cache.get_mut(uuid).chain_err(|| "BUG!")?.tw_start();
|
||||
self.cache.write()?;
|
||||
bail!("Work on Task now!");
|
||||
}
|
||||
"done" => {
|
||||
self.cache.get_mut(uuid).chain_err(|| "BUG!")?.tw_done();
|
||||
self.cache.write()?;
|
||||
break;
|
||||
}
|
||||
"delete" => {
|
||||
self.cache
|
||||
.get_mut(uuid)
|
||||
.chain_err(|| "missing uuid")?
|
||||
.tw_delete();
|
||||
self.cache.write()?;
|
||||
break;
|
||||
}
|
||||
"edit" => {
|
||||
*self.cache
|
||||
.get_mut(uuid)
|
||||
.chain_err(|| "missing uuid")?
|
||||
.description_mut() = self.dialog.input_line(
|
||||
format!(
|
||||
"Enter new description for {}",
|
||||
task_name
|
||||
),
|
||||
vec![
|
||||
self.cache
|
||||
.get_mut(uuid)
|
||||
.chain_err(|| "missing uuid")?
|
||||
.description()
|
||||
.clone(),
|
||||
],
|
||||
)?;
|
||||
}
|
||||
"manual" => {
|
||||
str2cmd("tasklauncher").output()?;
|
||||
self.cache.refresh()?;
|
||||
}
|
||||
"move" => {
|
||||
self.sort(uuid)?;
|
||||
}
|
||||
"quit" => {break;}
|
||||
"split" => {self.make_project(uuid)?;}
|
||||
"depend" => {
|
||||
let query = format!(
|
||||
"Selecting dependency for task\n{}",
|
||||
print_task(self.cache.get(uuid).chain_err(|| "missing uuid")?)
|
||||
);
|
||||
if let Some(dependency) = self.select_entry_point(query, uuid)? {
|
||||
let task = self.cache.get_mut(uuid).chain_err(|| "missing uuid")?;
|
||||
if task.depends().is_some() {
|
||||
task.depends_mut().unwrap().push(dependency);
|
||||
} else {
|
||||
task.set_depends(Some(Some(dependency)));
|
||||
}
|
||||
}
|
||||
self.cache.write()?;
|
||||
}
|
||||
"tag" => {
|
||||
let tag = self.dialog.input_line(
|
||||
format!("Enter tag for {}", task_name),
|
||||
vec![
|
||||
"alber",
|
||||
"await",
|
||||
"city",
|
||||
"home",
|
||||
"pc",
|
||||
"research",
|
||||
"streicher",
|
||||
"uni",
|
||||
"work",
|
||||
"claire",
|
||||
"burkhard",
|
||||
"cornelia",
|
||||
"nathalie",
|
||||
],
|
||||
)?;
|
||||
self.cache
|
||||
.get_mut(uuid)
|
||||
.chain_err(|| "missing uuid")?
|
||||
.add_tag(tag);
|
||||
self.cache.write()?;
|
||||
}
|
||||
"clear_tags" => {
|
||||
self.cache
|
||||
.get_mut(uuid)
|
||||
.chain_err(|| "missing uuid")?
|
||||
.set_tags(None as Option<Vec<String>>);
|
||||
self.cache.write()?;
|
||||
}
|
||||
"postpone" => {
|
||||
str2cmd(&format!(
|
||||
"task {} mod wait:{}",
|
||||
uuid,
|
||||
self.dialog.input_line(
|
||||
format!(
|
||||
"How long do you want to postpone {}",
|
||||
task_name
|
||||
),
|
||||
vec!["tomorrow"],
|
||||
)?
|
||||
)).output()?;
|
||||
self.cache.refresh()?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clear_inbox(&mut self) -> Result<()> {
|
||||
if self.cache
|
||||
.filter(|t| {
|
||||
t.gen_name() == Some(&"Leere Inbox".into()) && t.pending()
|
||||
})
|
||||
.len() > 0
|
||||
{
|
||||
while let Some(uuid) = self.get_sorted_uuids(|t| task_inbox(&self.cache, t))
|
||||
.into_iter()
|
||||
.next()
|
||||
{
|
||||
self.handle_task(&uuid)?;
|
||||
}
|
||||
for task in self.cache.filter_mut(|t| {
|
||||
t.gen_name() == Some(&"Leere Inbox".into()) && t.pending()
|
||||
})
|
||||
{
|
||||
task.tw_done()
|
||||
}
|
||||
self.cache.write()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn make_project(&mut self, uuid: &Uuid) -> Result<bool> {
|
||||
let task_name = print_task(self.cache.get(uuid).chain_err(|| "missing uuid")?);
|
||||
let mut new_tasks = vec![];
|
||||
loop {
|
||||
match enter_new_task(
|
||||
&mut self.dialog,
|
||||
format!("Adding sub tasks of {}\n\n(Esc to cancel)", task_name),
|
||||
) {
|
||||
Ok(mut task) => {
|
||||
task.set_partof(Some(uuid.clone()));
|
||||
new_tasks.push(task.uuid().clone());
|
||||
self.cache.set(task);
|
||||
self.cache.write()?;
|
||||
}
|
||||
Err(Error(EK::DialogError(DEK::InputCanceled), _)) => break,
|
||||
err => {
|
||||
err?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if new_tasks.len() > 0 {
|
||||
for uuid in new_tasks {
|
||||
self.handle_task(&uuid)?;
|
||||
}
|
||||
update_tasks(&mut self.cache)?;
|
||||
self.cache.write()?;
|
||||
return Ok(true);
|
||||
} else {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn handle_task(&mut self, uuid: &Uuid) -> Result<()> {
|
||||
let task_name = print_task(self.cache.get(uuid).chain_err(
|
||||
|| "handle_task: missing uuid",
|
||||
)?);
|
||||
match self.dialog.select_option(
|
||||
format!(
|
||||
"Handling Task: {}\nCan this be done in under 2 minutes?",
|
||||
task_name
|
||||
),
|
||||
vec![
|
||||
("Yes: I'll get to it", Some(true)),
|
||||
(
|
||||
"No: Do you know how short 2 minutes are?",
|
||||
Some(false)
|
||||
),
|
||||
(
|
||||
"Edit: I'll change that task on my own",
|
||||
None
|
||||
),
|
||||
],
|
||||
)? {
|
||||
Some(true) => {
|
||||
self.cache.get_mut(uuid).chain_err(|| "BUG!")?.tw_start();
|
||||
self.cache.write()?;
|
||||
bail!("Work on Task now!");
|
||||
}
|
||||
Some(false) => (),
|
||||
None => {
|
||||
self.edit_task(uuid)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
if task_needs_sorting(&self.cache, uuid)? {
|
||||
self.sort(uuid)?;
|
||||
}
|
||||
if !self.make_project(uuid)? {
|
||||
if let Some(tag) = self.dialog.select_option(
|
||||
format!(
|
||||
"Handling Task: {}\nWhen will you do this?",
|
||||
print_task(
|
||||
self.cache.get(uuid).chain_err(|| "missing uuid")?,
|
||||
)
|
||||
),
|
||||
vec![
|
||||
("Optional: I might never", Some("optional")),
|
||||
("Later: This has to wait", Some("later")),
|
||||
(
|
||||
"Await: Somebody else has to do this",
|
||||
Some("await")
|
||||
),
|
||||
("PC: When I'm at my computer", Some("pc")),
|
||||
("Work: While working", Some("work")),
|
||||
(
|
||||
"Research: While doing research",
|
||||
Some("research")
|
||||
),
|
||||
("Home: When I'm at home", Some("home")),
|
||||
("Edit: This task instead", None),
|
||||
],
|
||||
)?
|
||||
{
|
||||
self.cache
|
||||
.get_mut(uuid)
|
||||
.chain_err(|| "missing uuid")?
|
||||
.add_tag(tag);
|
||||
self.cache.write()?;
|
||||
} else {
|
||||
self.edit_task(uuid)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_accounting(&mut self) -> Result<()> {
|
||||
if self.cache
|
||||
.filter(|t| {
|
||||
t.gen_name() == Some(&"Aktualisiere Buchhaltung".into()) && t.pending()
|
||||
})
|
||||
.len() > 0
|
||||
{
|
||||
str2cmd("urxvt -e sh -c")
|
||||
.arg("jali -l. && task gen_id:'Aktualisiere Buchhaltung' done")
|
||||
.output()?;
|
||||
}
|
||||
self.cache.write()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn select_next_task(&mut self) -> Result<()> {
|
||||
while self.cache
|
||||
.filter(|t| t.start().is_some() && t.pending())
|
||||
.len() == 0 &&
|
||||
self.cache
|
||||
.filter(|t| {
|
||||
t.pending() && self.is_relevant(t) && !task_blocked(&self.cache, t)
|
||||
})
|
||||
.len() > 0
|
||||
{
|
||||
if let Some(uuid) = {
|
||||
let next_tasks = self.get_sorted_tasks(|t| {
|
||||
t.pending() && self.is_relevant(t) && !task_blocked(&self.cache, t)
|
||||
}).into_iter()
|
||||
.map(|t| (print_task_short(t), Some(t.uuid().clone())))
|
||||
.collect::<Vec<_>>();
|
||||
self.dialog.select_option(
|
||||
"What are you going to do now?",
|
||||
once(("Manual: Edit my tasks".into(), None))
|
||||
.chain(next_tasks.into_iter()),
|
||||
)?
|
||||
}
|
||||
{
|
||||
self.edit_task(&uuid)?;
|
||||
} else {
|
||||
str2cmd("tasklauncher").output()?;
|
||||
self.cache.refresh()?;
|
||||
return self.select_next_task();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn is_relevant(&self, task: &Task) -> bool {
|
||||
let can_do_this_here = |location| match location {
|
||||
Location::Home => task.has_tag("home"),
|
||||
Location::City => task.has_tag("city"),
|
||||
Location::Uni => task.has_tag("uni"),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
match self.state.mode {
|
||||
Mode::Research => task.has_tag("research"),
|
||||
Mode::Work => {
|
||||
task.has_tag("work") || task.has_tag("pc") || can_do_this_here(self.state.location)
|
||||
}
|
||||
Mode::Orga => task.has_tag("pc") || can_do_this_here(self.state.location),
|
||||
Mode::Idle => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_state() -> Result<()> {
|
||||
Kassandra::new()?.confirm_state()
|
||||
}
|
||||
|
||||
pub fn new_tasks() -> Result<()> {
|
||||
Kassandra::new()?.get_notes()
|
||||
}
|
||||
|
||||
pub fn kassandra() -> Result<()> {
|
||||
Kassandra::new()?.run()
|
||||
}
|
|
@ -1,108 +1,36 @@
|
|||
extern crate dialog;
|
||||
extern crate uuid;
|
||||
extern crate task_hookrs;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate kairos;
|
||||
extern crate chrono;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_yaml;
|
||||
|
||||
pub mod hotkeys;
|
||||
pub mod generate;
|
||||
pub mod refresh;
|
||||
pub mod update;
|
||||
pub mod kassandra;
|
||||
pub mod tasktree;
|
||||
|
||||
pub mod hotkeys {
|
||||
use std::rc::Rc;
|
||||
use dialog::DialogProvider;
|
||||
use dialog::errors::Error;
|
||||
use dialog::errors::ErrorKind::*;
|
||||
use dialog::rofi::RofiDialogProvider;
|
||||
use std::process::Command as StdCommand;
|
||||
use std::os::unix::process::CommandExt;
|
||||
pub use hotkeys::Next::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Next {
|
||||
Menu(Dialog),
|
||||
TmpMenu(Dialog),
|
||||
Run(Command),
|
||||
Fork(Command),
|
||||
Exec(Command),
|
||||
Back,
|
||||
Exit,
|
||||
Stay,
|
||||
Script(Rc<Fn(State) -> Next>),
|
||||
}
|
||||
|
||||
type Dialog = (String, Vec<Item>);
|
||||
|
||||
type Item = (String, Next);
|
||||
|
||||
type Command = Vec<String>;
|
||||
|
||||
type State = String;
|
||||
|
||||
pub fn c<T>(string: T) -> String
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
string.into()
|
||||
}
|
||||
|
||||
pub fn cmd<S, K>(argv: S) -> Command
|
||||
where
|
||||
S: IntoIterator<Item = K>,
|
||||
K: Into<String>,
|
||||
{
|
||||
argv.into_iter().map(|x| x.into()).collect()
|
||||
}
|
||||
|
||||
|
||||
fn show_menu<T: DialogProvider>(dialog_provider: &mut T, menu: Dialog) -> Next {
|
||||
let (msg, options) = menu;
|
||||
match dialog_provider.select_option(msg, options) {
|
||||
Ok(next) => next,
|
||||
Err(Error(InputCanceled, _)) => Exit,
|
||||
Err(Error(InvalidUserInput, _)) => Stay,
|
||||
Err(err) => {
|
||||
println!("DialogError: {}", err);
|
||||
Stay
|
||||
}
|
||||
pub mod error {
|
||||
use task_hookrs::error as terror;
|
||||
use dialog::errors as derror;
|
||||
use serde_yaml;
|
||||
error_chain! {
|
||||
links {
|
||||
TaskError(terror::Error, terror::ErrorKind);
|
||||
DialogError(derror::Error, derror::ErrorKind);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn build_command(cmd: Command) -> StdCommand {
|
||||
let mut cmd_iter = cmd.iter();
|
||||
let mut prg = StdCommand::new(cmd_iter.next().expect("Called program without name"));
|
||||
for arg in cmd_iter {
|
||||
prg.arg(arg);
|
||||
}
|
||||
prg
|
||||
}
|
||||
|
||||
pub fn main_loop(startmenu: Next) {
|
||||
let mut dialog_provider = RofiDialogProvider;
|
||||
let mut history = vec![];
|
||||
let mut next = startmenu;
|
||||
loop {
|
||||
next = match next {
|
||||
Exit => break,
|
||||
Back => {
|
||||
history.pop().expect("Empty history");
|
||||
Stay
|
||||
}
|
||||
Script(script) => script(c("work")),
|
||||
TmpMenu(menu) => show_menu(&mut dialog_provider, menu),
|
||||
Menu(menu) => {
|
||||
history.push(menu.clone());
|
||||
show_menu(&mut dialog_provider, menu)
|
||||
}
|
||||
Fork(cmd) => {
|
||||
build_command(cmd).spawn().is_ok();
|
||||
Stay
|
||||
}
|
||||
Run(cmd) => {
|
||||
build_command(cmd).output().is_ok();
|
||||
Stay
|
||||
}
|
||||
Exec(cmd) => {
|
||||
build_command(cmd).exec();
|
||||
break;
|
||||
}
|
||||
Stay => Menu(history.pop().expect("Empty history").clone()),
|
||||
};
|
||||
foreign_links {
|
||||
Io(::std::io::Error);
|
||||
Yaml(serde_yaml::Error);
|
||||
PathError(::std::env::JoinPathsError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
74
packages/rust-scripts/src/refresh.rs
Normal file
74
packages/rust-scripts/src/refresh.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
use chrono::offset::{Local, TimeZone};
|
||||
|
||||
use kairos::timetype::TimeType as TT;
|
||||
use kairos::iter::Iter;
|
||||
use kairos::error::Result as KairosResult;
|
||||
|
||||
use task_hookrs::status::TaskStatus as TS;
|
||||
use task_hookrs::task::Task;
|
||||
use task_hookrs::cache::TaskCache;
|
||||
use task_hookrs::error::{Result, ResultExt};
|
||||
use task_hookrs::date::Date;
|
||||
|
||||
use generate::TaskGenerator;
|
||||
use tasktree::TaskNode;
|
||||
|
||||
pub enum Timer {
|
||||
DeadTime(TT),
|
||||
Repetition(Iter),
|
||||
}
|
||||
|
||||
pub trait TaskRefresher {
|
||||
fn reactivate<T>(&mut self, tasks: T, recurrence: Timer) -> Result<()>
|
||||
where
|
||||
T: IntoIterator<Item = Task>;
|
||||
}
|
||||
|
||||
impl TaskRefresher for TaskCache {
|
||||
fn reactivate<T>(&mut self, tasks: T, recurrence: Timer) -> Result<()>
|
||||
where
|
||||
T: IntoIterator<Item = Task>,
|
||||
{
|
||||
let now = TT::Moment(Local::now().naive_local());
|
||||
let recent = match recurrence {
|
||||
Timer::DeadTime(time) => {
|
||||
(now - time).calculate().chain_err(
|
||||
|| "Failed to calculate recent from deadtime",
|
||||
)?
|
||||
}
|
||||
Timer::Repetition(iter) => {
|
||||
iter.filter_map(KairosResult::ok)
|
||||
.take_while(|t| *t <= now)
|
||||
.last()
|
||||
.ok_or("Repetition starts in the future")?
|
||||
.clone()
|
||||
}
|
||||
};
|
||||
let mut uuids = vec![];
|
||||
let changes = tasks
|
||||
.into_iter()
|
||||
.filter(|task| if let Some(old) = self.get_by_gen(&task) {
|
||||
if old.obsolete() &&
|
||||
TT::Moment(
|
||||
Local
|
||||
.from_utc_datetime(
|
||||
&**old.end().expect("Ended tasks have to have an end date"),
|
||||
)
|
||||
.naive_local(),
|
||||
) < recent
|
||||
{
|
||||
uuids.push(old.uuid().clone());
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
for uuid in uuids {
|
||||
let old = self.get_mut(&uuid).expect("BUG!");
|
||||
*old.status_mut() = TS::Pending;
|
||||
old.set_end(None as Option<Date>);
|
||||
}
|
||||
self.generate(changes)
|
||||
}
|
||||
}
|
169
packages/rust-scripts/src/tasktree.rs
Normal file
169
packages/rust-scripts/src/tasktree.rs
Normal file
|
@ -0,0 +1,169 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
use task_hookrs::task::Task;
|
||||
use task_hookrs::status::TaskStatus as TS;
|
||||
use task_hookrs::cache::TaskCache;
|
||||
use task_hookrs::uda::UDAValue;
|
||||
|
||||
use error::{Result, ResultExt};
|
||||
|
||||
pub trait TaskNode {
|
||||
fn partof(&self) -> Result<Option<Uuid>>;
|
||||
fn set_partof(&mut self, Option<Uuid>);
|
||||
fn add_tag<T: Into<String>>(&mut self, T);
|
||||
fn remove_tag<T: Into<String>>(&mut self, T);
|
||||
fn has_tag<T: Into<String>>(&self, T) -> bool;
|
||||
fn tagged(&self) -> bool;
|
||||
fn pending(&self) -> bool;
|
||||
fn obsolete(&self) -> bool;
|
||||
}
|
||||
|
||||
impl TaskNode for Task {
|
||||
fn partof(&self) -> Result<Option<Uuid>> {
|
||||
Ok(if let Some(uuid) = self.uda().get("partof".into()) {
|
||||
if let &UDAValue::Str(ref uuid) = uuid {
|
||||
Some(Uuid::parse_str(uuid).chain_err(|| "No uuid in partof uda")?)
|
||||
} else {
|
||||
Err("No String in partof uda")?
|
||||
}
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
fn set_partof(&mut self, partof: Option<Uuid>) {
|
||||
if let Some(uuid) = partof {
|
||||
self.uda_mut().insert(
|
||||
"partof".into(),
|
||||
UDAValue::Str(uuid.to_string()),
|
||||
);
|
||||
} else {
|
||||
self.uda_mut().remove("partof".into());
|
||||
}
|
||||
}
|
||||
|
||||
fn add_tag<T: Into<String>>(&mut self, tag: T) {
|
||||
let tag = tag.into();
|
||||
if !self.has_tag(tag.clone()) {
|
||||
if self.tags().is_some() {
|
||||
self.tags_mut().unwrap().push(tag);
|
||||
} else {
|
||||
self.set_tags(Some(Some(tag)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_tag<T: Into<String>>(&mut self, tag: T) {
|
||||
if let Some(tags) = self.tags_mut() {
|
||||
let tag = tag.into();
|
||||
tags.retain(|t| *t != tag);
|
||||
}
|
||||
}
|
||||
|
||||
fn has_tag<T: Into<String>>(&self, tag: T) -> bool {
|
||||
self.tags()
|
||||
.map(|tags| tags.contains(&tag.into()))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn tagged(&self) -> bool {
|
||||
self.tags().map(|t| t.len() > 0).unwrap_or(false)
|
||||
}
|
||||
|
||||
fn pending(&self) -> bool {
|
||||
*self.status() == TS::Pending
|
||||
}
|
||||
|
||||
fn obsolete(&self) -> bool {
|
||||
*self.status() == TS::Completed || *self.status() == TS::Deleted
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TreeCache {
|
||||
fn get_parent(&self, uuid: &Uuid) -> Result<Option<&Task>>;
|
||||
fn get_parent_mut(&mut self, uuid: &Uuid) -> Result<Option<&mut Task>>;
|
||||
fn get_children(&self, uuid: &Uuid) -> Vec<&Task>;
|
||||
fn get_children_mut(&mut self, uuid: &Uuid) -> Vec<&mut Task>;
|
||||
fn get_project_path(&self, uuid: &Uuid) -> Result<String>;
|
||||
fn is_project(&self, uuid: &Uuid) -> bool;
|
||||
fn refresh_tree(&mut self);
|
||||
}
|
||||
fn get_project_name(cache: &TaskCache, task: &Task) -> Result<Option<String>> {
|
||||
Ok(if let Some(parent_uuid) = task.partof()? {
|
||||
Some(cache.get_project_path(&parent_uuid)?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
impl TreeCache for TaskCache {
|
||||
fn get_parent(&self, uuid: &Uuid) -> Result<Option<&Task>> {
|
||||
let task = self.get(uuid).chain_err(|| "task uuid not found")?;
|
||||
Ok(if let Some(uuid) = task.partof()? {
|
||||
Some(self.get(&uuid).chain_err(|| "parent uuid not found")?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
fn get_parent_mut(&mut self, uuid: &Uuid) -> Result<Option<&mut Task>> {
|
||||
let parent_option = self.get(uuid).chain_err(|| "task uuid not found")?.partof()?;
|
||||
Ok(if let Some(uuid) = parent_option {
|
||||
Some(self.get_mut(&uuid).chain_err(|| "parent uuid not found")?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
fn get_children(&self, uuid: &Uuid) -> Vec<&Task> {
|
||||
self.filter(|t| t.partof().unwrap_or(None) == Some(*uuid))
|
||||
}
|
||||
|
||||
fn get_children_mut(&mut self, uuid: &Uuid) -> Vec<&mut Task> {
|
||||
self.filter_mut(|t| t.partof().unwrap_or(None) == Some(*uuid))
|
||||
}
|
||||
|
||||
fn get_project_path(&self, uuid: &Uuid) -> Result<String> {
|
||||
let task = self.get(uuid).chain_err(|| "Uuid not found in Cache")?;
|
||||
let end = task.description().to_lowercase().replace(
|
||||
char::is_whitespace,
|
||||
"",
|
||||
);
|
||||
Ok(if let Some(parent) = task.partof()? {
|
||||
format!("{}.{}", self.get_project_path(&parent)?, end)
|
||||
} else {
|
||||
end
|
||||
})
|
||||
}
|
||||
|
||||
fn is_project(&self, uuid: &Uuid) -> bool {
|
||||
self.get_children(uuid)
|
||||
.iter()
|
||||
.filter(|t| !t.obsolete())
|
||||
.count() > 0
|
||||
}
|
||||
|
||||
fn refresh_tree(&mut self) {
|
||||
let task_uuids = self.filter(|t| {
|
||||
!t.obsolete() &&
|
||||
(get_project_name(self, t)
|
||||
.map(|path| path.as_ref() != t.project())
|
||||
.unwrap_or(false) ||
|
||||
(self.is_project(t.uuid()) != t.has_tag("project")))
|
||||
}).iter()
|
||||
.map(|t| t.uuid().clone())
|
||||
.collect::<Vec<_>>();
|
||||
for task_uuid in task_uuids {
|
||||
let new_project_name = get_project_name(self, self.get(&task_uuid).expect("Bug"))
|
||||
.expect("Bug");
|
||||
let is_project = self.is_project(&task_uuid);
|
||||
let task = self.get_mut(&task_uuid).expect("Bug");
|
||||
task.set_project(new_project_name);
|
||||
if is_project {
|
||||
task.add_tag("project");
|
||||
} else {
|
||||
task.remove_tag("project");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
packages/rust-scripts/src/update.rs
Normal file
106
packages/rust-scripts/src/update.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
use task_hookrs::error::Result;
|
||||
use task_hookrs::cache::TaskCache;
|
||||
use task_hookrs::task::{Task, TaskBuilder};
|
||||
use generate::GeneratedTask;
|
||||
use refresh::{TaskRefresher, Timer};
|
||||
use tasktree::TreeCache;
|
||||
use chrono::NaiveDate;
|
||||
use kairos::timetype::TimeType as TT;
|
||||
use kairos::iter::extensions::{Weekly, Monthly, Daily};
|
||||
|
||||
fn simple_task(name: &str) -> Task {
|
||||
let mut task = TaskBuilder::default().description(name).build().expect(
|
||||
"TaskBuilding failed inspite of set description",
|
||||
);
|
||||
task.set_gen_name(Some(name));
|
||||
task.set_gen_id(Some(name));
|
||||
task
|
||||
}
|
||||
|
||||
fn simple_tasks<'a, T>(names: T) -> Vec<Task>
|
||||
where
|
||||
T: IntoIterator<Item = &'a str>,
|
||||
{
|
||||
names.into_iter().map(simple_task).collect()
|
||||
}
|
||||
|
||||
pub fn update_tasks(cache: &mut TaskCache) -> Result<()> {
|
||||
let daily = || {
|
||||
Timer::Repetition(
|
||||
TT::moment(NaiveDate::from_ymd(2018, 5, 8).and_hms(20, 0, 0))
|
||||
.daily(1)
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
let weekly = || {
|
||||
Timer::Repetition(
|
||||
TT::moment(NaiveDate::from_ymd(2018, 5, 8).and_hms(20, 0, 0))
|
||||
.weekly(1)
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
let monthly = || {
|
||||
Timer::Repetition(
|
||||
TT::moment(NaiveDate::from_ymd(2018, 5, 3).and_hms(20, 0, 0))
|
||||
.monthly(1)
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
cache.reactivate(
|
||||
simple_tasks(vec![
|
||||
"Staubsaugen",
|
||||
"Putze Waschbecken",
|
||||
"Wäsche sortieren und entscheiden, welche Waschgänge notwendig sind",
|
||||
]),
|
||||
Timer::DeadTime(TT::weeks(2)),
|
||||
)?;
|
||||
cache.reactivate(
|
||||
simple_tasks(
|
||||
vec!["Reinige Toilette", "Zehennägel schneiden"],
|
||||
),
|
||||
Timer::DeadTime(TT::weeks(4)),
|
||||
)?;
|
||||
cache.reactivate(
|
||||
simple_tasks(vec!["Friseurtermin machen"]),
|
||||
Timer::DeadTime(TT::weeks(6)),
|
||||
)?;
|
||||
cache.reactivate(
|
||||
simple_tasks(vec![
|
||||
"Aktualisiere Buchhaltung",
|
||||
"Leere Inbox",
|
||||
"Sortiere Tasktree",
|
||||
"Sortiere Inbox",
|
||||
"Sortiere Inbox Auslandskoordination",
|
||||
"Sortiere Inbox Kiva",
|
||||
"Update nixos apollo",
|
||||
"Update home apollo",
|
||||
"Update home fb4",
|
||||
"Update home hera",
|
||||
"Update home charon",
|
||||
"Klavier üben",
|
||||
]),
|
||||
daily(),
|
||||
)?;
|
||||
cache.reactivate(
|
||||
simple_tasks(vec!["Verbuche Kontoauszüge"]),
|
||||
monthly(),
|
||||
)?;
|
||||
cache.reactivate(
|
||||
simple_tasks(vec![
|
||||
"Kontrolliere Spam",
|
||||
"Korrigiere Portemonnaiezählstand",
|
||||
"Sortiere Archiv",
|
||||
"Sortiere Archiv Kiva",
|
||||
"Sortiere Archiv Auslandskoordination",
|
||||
"Kontrolliere +later",
|
||||
"Kontrolliere +optional",
|
||||
"Kontrolliere +await",
|
||||
"Block leeren und wegsortieren",
|
||||
"Leere Kiva Fächer",
|
||||
"Inbox zu Hause wegsortieren",
|
||||
]),
|
||||
weekly(),
|
||||
)?;
|
||||
cache.refresh_tree();
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in a new issue