-
-
Save c02y/3022d6942a1fecdb42e4be4c01e4b118 to your computer and use it in GitHub Desktop.
emm function for bash
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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