-
Notifications
You must be signed in to change notification settings - Fork 43
/
auto-notify.plugin.zsh
188 lines (161 loc) · 5.95 KB
/
auto-notify.plugin.zsh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
export AUTO_NOTIFY_VERSION="0.10.2"
# Time it takes for a notification to expire
[[ -z "$AUTO_NOTIFY_EXPIRE_TIME" ]] &&
export AUTO_NOTIFY_EXPIRE_TIME=8000
# Threshold in seconds for when to automatically show a notification
[[ -z "$AUTO_NOTIFY_THRESHOLD" ]] &&
export AUTO_NOTIFY_THRESHOLD=10
# List of commands/programs to ignore sending notifications for
[[ -z "$AUTO_NOTIFY_IGNORE" ]] &&
export AUTO_NOTIFY_IGNORE=(
'vim'
'nvim'
'less'
'more'
'man'
'tig'
'watch'
'git commit'
'top'
'htop'
'ssh'
'nano'
)
function _auto_notify_format() {
local MESSAGE="$1"
local command="$2"
local elapsed="$3"
local exit_code="$4"
MESSAGE="${MESSAGE//\%command/$command}"
MESSAGE="${MESSAGE//\%elapsed/$elapsed}"
MESSAGE="${MESSAGE//\%exit_code/$exit_code}"
printf "%s" "$MESSAGE"
}
function _auto_notify_message() {
local command="$1"
local elapsed="$2"
local exit_code="$3"
local platform="$(uname)"
# Run using echo -e in order to make sure notify-send picks up new line
local DEFAULT_TITLE="\"%command\" Completed"
local DEFAULT_BODY="$(echo -e "Total time: %elapsed seconds\nExit code: %exit_code")"
local title="${AUTO_NOTIFY_TITLE:-$DEFAULT_TITLE}"
local text="${AUTO_NOTIFY_BODY:-$DEFAULT_BODY}"
title="$(_auto_notify_format "$title" "$command" "$elapsed" "$exit_code")"
body="$(_auto_notify_format "$text" "$command" "$elapsed" "$exit_code")"
if [[ "$platform" == "Linux" ]]; then
local urgency="normal"
local transient="--hint=int:transient:1"
local icon=${AUTO_NOTIFY_ICON_SUCCESS:-""}
# Exit code 130 is returned when a process is terminated with SIGINT.
# Since the user is already interacting with the program, there is no
# need to make the notification persistent.
if [[ "$exit_code" != "0" ]] && [[ "$exit_code" != "130" ]]; then
urgency="critical"
transient=""
icon=${AUTO_NOTIFY_ICON_FAILURE:-""}
fi
local arguments=("$title" "$body" "--app-name=zsh" "$transient" "--urgency=$urgency" "--expire-time=$AUTO_NOTIFY_EXPIRE_TIME")
if [[ -n "$icon" ]]; then
arguments+=("--icon=$icon")
fi
notify-send ${arguments[@]}
elif [[ "$platform" == "Darwin" ]]; then
osascript \
-e 'on run argv' \
-e 'display notification (item 1 of argv) with title (item 2 of argv)' \
-e 'end run' \
"$body" "$title"
else
printf "Unknown platform for sending notifications: $platform\n"
printf "Please post an issue on gitub.com/MichaelAquilina/zsh-auto-notify/issues/\n"
fi
}
function _is_auto_notify_ignored() {
local command="$1"
# split the command if its been piped one or more times
local command_list=("${(@s/|/)command}")
local target_command="${command_list[-1]}"
# Remove leading whitespace
target_command="$(echo "$target_command" | sed -e 's/^ *//')"
# If the command is being run over SSH, then ignore it
if [[ -n ${SSH_CLIENT-} || -n ${SSH_TTY-} || -n ${SSH_CONNECTION-} ]]; then
print "yes"
return
fi
# Remove sudo prefix from command if detected
if [[ "$target_command" == "sudo "* ]]; then
target_command="${target_command/sudo /}"
fi
# If AUTO_NOTIFY_WHITELIST is defined, then auto-notify will ignore
# any item not defined in the white list
# Otherwise - the alternative (default) approach is used where the
# AUTO_NOTIFY_IGNORE blacklist is used to ignore commands
if [[ -n "$AUTO_NOTIFY_WHITELIST" ]]; then
for allowed in $AUTO_NOTIFY_WHITELIST; do
if [[ "$target_command" == "$allowed"* ]]; then
print "no"
return
fi
done
print "yes"
else
for ignore in $AUTO_NOTIFY_IGNORE; do
if [[ "$target_command" == "$ignore"* ]]; then
print "yes"
return
fi
done
print "no"
fi
}
function _auto_notify_send() {
# Immediately store the exit code before it goes away
local exit_code="$?"
if [[ -z "$AUTO_COMMAND" && -z "$AUTO_COMMAND_START" ]]; then
return
fi
if [[ "$(_is_auto_notify_ignored "$AUTO_COMMAND_FULL")" == "no" ]]; then
local current="$(date +"%s")"
let "elapsed = current - AUTO_COMMAND_START"
if [[ $elapsed -gt $AUTO_NOTIFY_THRESHOLD ]]; then
_auto_notify_message "$AUTO_COMMAND" "$elapsed" "$exit_code"
fi
fi
# Empty tracking so that notifications are not
# triggered for any commands not run (e.g ctrl+C when typing)
_auto_notify_reset_tracking
}
function _auto_notify_track() {
# $1 is the string the user typed, but only when history is enabled
# $2 is a single-line, size-limited version of the command that is always available
# To still do something useful when history is disabled, although with reduced functionality, fall back to $2 when $1 is empty
AUTO_COMMAND="${1:-$2}"
AUTO_COMMAND_FULL="$3"
AUTO_COMMAND_START="$(date +"%s")"
}
function _auto_notify_reset_tracking() {
# Command start time in seconds since epoch
unset AUTO_COMMAND_START
# Full command that the user has executed after alias expansion
unset AUTO_COMMAND_FULL
# Command that the user has executed
unset AUTO_COMMAND
}
function disable_auto_notify() {
add-zsh-hook -D preexec _auto_notify_track
add-zsh-hook -D precmd _auto_notify_send
}
function enable_auto_notify() {
autoload -Uz add-zsh-hook
add-zsh-hook preexec _auto_notify_track
add-zsh-hook precmd _auto_notify_send
}
_auto_notify_reset_tracking
platform="$(uname)"
if [[ "$platform" == "Linux" ]] && ! type notify-send > /dev/null; then
printf "'notify-send' must be installed for zsh-auto-notify to work\n"
printf "Please install it with your relevant package manager\n"
else
enable_auto_notify
fi