Skip to content

Instantly share code, notes, and snippets.

@c02y
Last active April 26, 2019 11:32
Show Gist options
  • Save c02y/3022d6942a1fecdb42e4be4c01e4b118 to your computer and use it in GitHub Desktop.
Save c02y/3022d6942a1fecdb42e4be4c01e4b118 to your computer and use it in GitHub Desktop.
emm function for bash
#!/bin/bash
# 0. put this script into ~/.local/bin/
# 1. Create a emacsclient.desktop in ~/.local/share/applications/emacsclient.desktop
# 1.1 if you installed Emacs using pkg manager instead of anaconda3, omit this step
# 1.2 if you are using non-GUI or launcher is unnecessary, omit this step including the next
# 1.3 if you are using an OS without systemctl installed, omit this step including the next
#
# emacsclient.desktop:
#
# [Desktop Entry]
# Type=Application
# Encoding=UTF-8
# Icon=/home/chz/anaconda3/share/icons/hicolor/scalable/apps/emacs.svg
# Name=emacsclient
# Comment=Emacs daemon/client
# Type=Application
# Exec=/home/chz/.local/bin/emm
# Terminal=false
# StartupNofity=true
# Categories=
#
# 2. config your shortcut to this file in System Settings
print_usage()
{
cat <<EOF
$(basename $0) -- emacs server and emacsclient manage script
Usage: $(basename $0) [-h] [-k] [-r] [-C] [-d] [-e [file]] [-E] [-f] [-s] [-m [repo]] [-c] [-a] [-o [file]] [-q] [-t]...
-h to print this usage
-k to kill emacs daemon
-r to restart emacs daemon and start a emacsclient
-C to check the count of emacsclients
-d to start emacs --debug-init
-e to edit using emacs, default is init.el
-E to edit init.el using emacsclient
-f to edit config.fish using emacsclient
-s to edit this script using emacsclient
-m to start magit in a repo, default is ./
-c to quickly add todo using org-capture
-a to start org-agenda-list
-o to start orgmode for a file, default is ~/Org/todo.org
-q to start emacs -q --no-splash
-t to time the startup of emacs
EOF
exit 0
}
check_socket_file()
{
if [ "$flag_systemctl" -eq 1 ]; then
# this is only needed when using systemctl+emacs.service
# After emacs.service is started, it takes several seconds for the socket file to be created
# after that, emacsclient can be usable, or it will print "emacsclient: connect: Connection refused"
# so keep checking the exists of the socket
while [ -z "$(lsof -w -c emacs | grep 'server type' | tr -s " " | cut -d' ' -f8)" ] ; do # empty
sleep 0.5
done
else
return
fi
}
check_exists_emacsclient()
{
if ps -ef | grep -v grep | grep 'emacs' | grep 'daemon' >/dev/null; then
check_socket_file
# using emacsclient process won't work for GUI since no emacsclient process exists
timeout 1 emacsclient -n -e "(length (frame-list))" >/dev/null
if [ "$?" -ne 0 ]; then
# emacsclient gets stuck #
read -n 1 -p 'Running emacsclient gets stuck, kill it? [Y/n]: '
if [ "$REPLY" == "y" ]; then
echo
return 1
else
exit
fi
fi
emacsclient -n -e "(if (> (length (frame-list)) 1) 't)" | grep -q t >/dev/null
if [ "$?" -eq 0 ]; then # has emacsclient opened
read -n 1 -p 'Running emacsclient exists, kill(switch to emacs frame if unsaved)? [Y/n]: '
if [ "$REPLY" == "y" ]; then
# Note that if modified buffers unsaved, you have to switch to the emacsclient to save manually
emacsclient -n -e "(save-some-buffers)" >/dev/null
echo
else
echo "Cancel and exit!"
exit
fi
fi
fi
}
copy_service()
{
if [ ! -f ~/.config/systemd/user/emacs.service ] && [ -f ~/anaconda3/lib/systemd/user/emacs.service ]; then
mkdir -p ~/.config/systemd/user
cp -rfv ~/anaconda3/lib/systemd/user/emacs.service ~/.config/systemd/user/
fi
}
kill_emacs_server()
{
if ps -ef | grep -v grep | grep 'emacs' | grep 'daemon' >/dev/null; then # for both --daemon and --fg-daemon
# once you kill the process, it will restart automatically
ps -ef | grep -v grep | grep 'emacs' | grep 'daemon' | awk '{print $2}' | xargs kill -9
if [ "$flag_systemctl" -eq 1 ]; then
systemctl --user stop emacs.service
fi
echo "emacs server is killed!"
else
echo "No emacs daemon is running!"
fi
}
restart_emacs_server()
{
if ps -ef | grep -v grep | grep 'emacs' | grep 'daemon' >/dev/null; then # for both --daemon and --fg-daemon
# systemctl --user restart emacs.service # systemctl takes too much time
# once you kill the process, it will restart automatically
ps -ef | grep -v grep | grep 'emacs' | grep 'daemon' | awk '{print $2}' | xargs kill -9
echo "emacs server is restarted!"
fi
}
start_magit()
{
pwd_old=$PWD
if [ -d $1 ]; then
if [ "$1" != "." ]; then
cd $1
fi
# check if $1 is under git control
git rev-parse --is-inside-work-tree >/dev/null 2>&1
if [ "$?" -ne 0 ]; then
echo "$1 is not a git repo!"
cd --
exit 1
fi
# To get rid of prompt: "repo A is a repository. Create another in B"
# This works well even if A/B is a submodule
sub=0
if [[ "$PWD" =~ ^$pwd_old ]] || [[ "$pwd_old" =~ ^$PWD ]]; then
sub=1
fi
if [ "$1" == "." ] || [ "$sub" == "1" ]; then
cmd="-e '(progn (magit-status) (delete-other-windows))'"
elif [ "$1" != "." ] && [ "$sub" != "1" ]; then
repo=$PWD
cmd="-e '(progn (magit-status \"$repo\") (delete-other-windows))'"
cd --
fi
else
echo "$1 is not even a directory!"
exit 1
fi
}
repo="."
file="~/.emacs.d/init.el"
cmd=
flag_k=0 # kill emacs daemon
flag_r=0 # restart emacs daemon and start a emacsclient
flag_C=0 # check the count of emacsclients
flag_d=0 # start emacs --debug-init
flag_e=0 # edit using emacs, default is init.el
flag_E=0 # edit init.el using emacsclient
flag_f=0 # edit config.fish using emacsclient
flag_s=0 # edit this script using emacsclient
flag_m=0 # start magit in repo, default is ./
flag_c=0 # quickly add todo using org-capture
flag_a=0 # start org-agenda-list
flag_o=0 # start org-mode for a file, default is ~/Org/todo.org
flag_q=0 # start emacs -q --no-splash
flag_t=0 # time the startup of emacs
while getopts ":hkrCdeEfsmcaoqt" args; do # prefix-: no warning for illegal option
case "$args" in
h|\?) # \? for illegal option
print_usage
;;
k)
flag_k=1
;;
r)
flag_r=1
;;
C)
flag_C=1
;;
d)
flag_d=1
;;
e)
flag_e=1
if [ ! -z ${@:$OPTIND} ]; then # if no argv is given, using default
file=${@:$OPTIND}
OPTIND=$((OPTIND+1))
fi
;;
E)
flag_E=1
;;
f)
flag_f=1
file="~/.config/fish/config.fish"
;;
s)
flag_s=1
file="~/.local/bin/emm"
;;
m)
flag_m=1
if [ ! -z ${@:$OPTIND} ]; then # if no argv is given, using default
repo=${@:$OPTIND}
OPTIND=$((OPTIND+1))
fi
;;
c)
flag_c=1
;;
a)
flag_a=1
;;
o)
flag_o=1
if [ ! -z ${@:$OPTIND} ]; then # if no argv is given, using default
file=${@:$OPTIND}
OPTIND=$((OPTIND+1))
else
file="~/Org/todo.org"
fi
;;
q)
flag_q=1
;;
t)
flag_t=1
;;
esac
done
shift $((OPTIND -1)) # remove options that have already been handled from $@
if hash systemctl 2>/dev/null; then
flag_systemctl=1
else
flag_systemctl=0
fi
if [ "$flag_k" -eq 1 ]; then
check_exists_emacsclient
kill_emacs_server
exit 0
fi
if [ "$flag_r" -eq 1 ]; then
check_exists_emacsclient
restart_emacs_server
fi
if [ "$flag_C" -eq 1 ]; then
if ps -ef | grep -v grep | grep 'emacs' | grep 'daemon' >/dev/null; then
check_socket_file
timeout 1 emacsclient -n -e "(if (> (length (frame-list)) 1) 't)" >/dev/null
if [ "$?" -ne 0 ]; then
# emacsclient gets stuck #
read -n 1 -p 'Running emacsclient gets stuck, kill it? [Y/n]: '
if [ "$REPLY" == "y" ]; then
echo
kill_emacs_server
exit 1
else
exit 0
fi
fi
echo Count of emacsclients:
emacsclient -n -e "(- (length (frame-list)) 1) "
exit 0
else
echo "No emacs daemon is running!"
exit 0
fi
fi
if [ "$flag_d" -eq 1 ]; then
echo "Start 'emacs --debug-init'"
rm ~/.emacs.d/init.elc >/dev/null 2>&1
emacs --no-splash --debug-init >/dev/null 2>&1
exit 0
fi
if [ "$flag_e" -eq 1 ]; then
echo "Edit $file using emacs..."
emacs --no-splash $file >/dev/null 2>&1
exit 0
fi
if [ "$flag_E" -eq 1 ] || [ "$flag_f" -eq 1 ] || [ "$flag_s" -eq 1 ]; then
cmd="$file"
fi
if [ "$flag_m" -eq 1 ]; then
start_magit $repo
fi
if [ "$flag_c" -eq 1 ]; then
cmd="-e '(org-capture)'"
fi
if [ "$flag_a" -eq 1 ]; then
# cmd="-e '(org-agenda-list)'"
cmd="-e '(execute-kbd-macro (kbd \"C-c a c\"))'"
fi
if [ "$flag_o" -eq 1 ]; then
cmd="$file"
fi
if [ "$flag_q" -eq 1 ]; then
echo "Start emacs -q --no-splash..."
emacs -q --no-splash >/dev/null 2>&1
exit 0
fi
if [ "$flag_t" -eq 1 ]; then
echo "Time the startup of emacs..."
time emacs --debug-init -eval '(kill-emacs)'
exit 0
fi
if [ "$flag_systemctl" -eq 1 ]; then
if ! ps -ef | grep -v grep | grep 'emacs --fg-daemon' >/dev/null; then
copy_service
echo "Start emacs service..."
systemctl --user enable emacs.service
systemctl --user start emacs.service
fi
else
if ! ps -ef | grep -v grep | grep 'emacs' | grep 'daemon' >/dev/null; then
echo "Start emacs daemon..."
emacs --daemon >/dev/null 2>&1
fi
fi
if ps -ef | grep -v grep | grep 'emacs' | grep 'daemon' >/dev/null; then
check_socket_file
echo "Start emacsclient..."
if [ -z "$DISPLAY" ]; then # empty, non-GUI
# use eval since $cmd is string(command) in variable
eval emacsclient -a "" -n -c $cmd $@
else
# "" here forces the GUI running without holding the terminal, like &
eval "emacsclient -a \"\" -n -c $cmd" $@ >/dev/null
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment