rofi/scripts/rofi-calc 2.9 K raw
1
#!/bin/sh
2
# Requires: rofi, bc, xclip
3
# Calculator. The rofi-calc plugin wants libqalculate; this needs nothing but
4
# bc, at the cost of results arriving on Enter rather than as you type:
5
#   type an expression, Enter   evaluate it (the result becomes a row)
6
#   Enter on a result row       copy it to the clipboard
7
# Past results stay listed until cleared, so earlier answers can be copied or
8
# pasted back into a new expression.
9
set -u
10
11
HIST="${XDG_CACHE_HOME:-$HOME/.cache}/rofi-calc-history"
12
HIST_MAX=${ROFI_CALC_HISTORY_MAX:-50}
13
SCALE=${ROFI_CALC_SCALE:-10}
14
15
if [ -z "${ROFI_RETV:-}" ]; then
16
    exec rofi -show calc -modes "calc:$0"
17
fi
18
19
US=$(printf '\037')
20
touch "$HIST"
21
22
list() {
23
    printf '\0prompt%scalc\n' "$US"
24
    printf '\0message%sType an expression and press Enter. + - * / ^%%, sqrt(), s()/c()/a() trig, l()/e() log.\n' "$US"
25
    printf '\0keep-selection%strue\n' "$US"
26
    while IFS='	' read -r expr result; do
27
        [ -n "$result" ] || continue
28
        printf '%s = %s\0info%s%s\n' "$expr" "$result" "$US" "$result"
29
    done < "$HIST"
30
    [ -s "$HIST" ] && printf 'clear history\0info%s@clear\n' "$US"
31
    return 0
32
}
33
34
evaluate() {
35
    # -l pulls in the math library (sqrt, s, c, a, l, e) and sets scale=20,
36
    # so scale has to be set after it to control the printed precision.
37
    result=$(printf 'scale=%s\n%s\n' "$SCALE" "$1" | bc -l 2>/dev/null | tail -n1)
38
    [ -n "$result" ] || return 1
39
40
    # bc pads to the full scale (2/1 = .5000000000) and leads with a bare dot;
41
    # trim both so results look like results.
42
    result=$(printf '%s' "$result" | sed -e 's/\([.][0-9]*[1-9]\)0*$/\1/' -e 's/[.]0*$//' -e 's/^\([-]\{0,1\}\)[.]/\10./')
43
    printf '%s' "$result"
44
}
45
46
case "$ROFI_RETV" in
47
    0) list ;;
48
    1)
49
        info=${ROFI_INFO:-}
50
        if [ "$info" = "@clear" ]; then
51
            : > "$HIST"
52
            list
53
        elif [ -n "$info" ]; then
54
            # Redirect: xclip backgrounds itself still holding the pipe rofi
55
            # reads this script on, and rofi hangs with the keyboard grabbed
56
            # until it sees EOF there.
57
            printf '%s' "$info" | xclip -selection clipboard -i >/dev/null 2>&1
58
        fi
59
        ;;
60
    2)
61
        expr=${1:-}
62
        [ -n "$expr" ] || { list; exit 0; }
63
        if result=$(evaluate "$expr") && [ -n "$result" ]; then
64
            tmp="$HIST.$$"
65
            printf '%s\t%s\n' "$expr" "$result" > "$tmp"
66
            grep -v "^$(printf '%s' "$expr" | sed 's/[][\.*^$/]/\\&/g')	" "$HIST" >> "$tmp" 2>/dev/null
67
            head -n "$HIST_MAX" "$tmp" > "$HIST"
68
            rm -f "$tmp"
69
        else
70
            printf '\0message%s<span foreground="#bf616a">Not a valid expression</span>\n' "$US"
71
        fi
72
        list
73
        ;;
74
    3)
75
        expr=$(printf '%s' "${1:-}" | sed 's/ = .*$//')
76
        if [ -n "$expr" ]; then
77
            grep -v "^$(printf '%s' "$expr" | sed 's/[][\.*^$/]/\\&/g')	" "$HIST" > "$HIST.$$" 2>/dev/null
78
            mv "$HIST.$$" "$HIST"
79
        fi
80
        list
81
        ;;
82
esac