mirror of
https://github.com/SqrtMinusOne/dotfiles.git
synced 2025-12-10 11:13:04 +03:00
emacs: some updates
This commit is contained in:
parent
6c489b4a32
commit
2e64d77ba8
5 changed files with 153 additions and 38 deletions
|
|
@ -381,14 +381,14 @@ DIR is either 'left or 'right."
|
|||
_t_: Terminal (Alacritty)
|
||||
_b_: Browser (Firefox)
|
||||
_s_: Rocket.Chat
|
||||
_e_: Element
|
||||
_d_: Discord
|
||||
_d_: DBeaver
|
||||
_c_: Chromium
|
||||
"
|
||||
("t" (lambda () (interactive) (my/run-in-background "alacritty")))
|
||||
("b" (lambda () (interactive) (my/run-in-background "firefox")))
|
||||
("s" (lambda () (interactive) (my/run-in-background "flatpak run chat.rocket.RocketChat")))
|
||||
("e" (lambda () (interactive) (my/run-in-background "flatpak run im.riot.Riot")))
|
||||
("d" (lambda () (interactive) (my/run-in-background "flatpak run com.discordapp.Discord"))))
|
||||
("s" (lambda () (interactive) (my/run-in-background "rocketchat-desktop")))
|
||||
("d" (lambda () (interactive) (my/run-in-background "dbeaver")))
|
||||
("c" (lambda () (interactive) (my/run-in-background "chromium"))))
|
||||
|
||||
(defun my/exwm-lock ()
|
||||
(interactive)
|
||||
|
|
@ -594,10 +594,10 @@ _d_: Discord
|
|||
|
||||
(my/exwm-set-wallpaper)
|
||||
(my/exwm-run-shepherd)
|
||||
(my/exwm-run-systemd)
|
||||
(my/run-in-background "gpgconf --reload gpg-agent")
|
||||
(my/exwm-run-polybar)
|
||||
(setenv "DBUS_SESSION_BUS_ADDRESS" "unix:path=/run/user/1000/bus")
|
||||
(my/exwm-run-systemd)
|
||||
(when (my/is-arch)
|
||||
(my/run-in-background "set_layout")))
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@
|
|||
;; I have everything I need in polybar
|
||||
(emms-mode-line-mode -1)
|
||||
(emms-playing-time-display-mode -1)
|
||||
(delq 'emms-mark-mode evil-emacs-state-modes)
|
||||
(delq 'emms-browser-mode evil-emacs-state-modes)
|
||||
(defun emms-info-mpd-process (track info)
|
||||
(dolist (data info)
|
||||
(let ((name (car data))
|
||||
|
|
|
|||
|
|
@ -375,8 +375,11 @@ REMOTE = '<rclone-remote>'
|
|||
FOLDERS = json.loads('<rclone-folders-json>')
|
||||
OPTIONS = json.loads('<rclone-options>')
|
||||
|
||||
for folder, i in zip(FOLDERS, range(len(FOLDERS))):
|
||||
folder['id'] = i
|
||||
|
||||
def rclone_make_command(local_path, remote_path, remote):
|
||||
|
||||
def rclone_make_command(local_path, remote_path, remote, extra_args=[]):
|
||||
return [
|
||||
'rclone',
|
||||
'bisync',
|
||||
|
|
@ -390,7 +393,8 @@ def rclone_make_command(local_path, remote_path, remote):
|
|||
'NEVER',
|
||||
'--use-json-log',
|
||||
'--stats',
|
||||
'9999m'
|
||||
'9999m',
|
||||
*extra_args
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -418,15 +422,26 @@ def process_output(output):
|
|||
except Exception:
|
||||
print(line)
|
||||
|
||||
def rclone_run(folder):
|
||||
def process_command_for_print(command):
|
||||
res = []
|
||||
for c in command:
|
||||
if ' ' in c:
|
||||
res.append(f'\\'{c}\\'')
|
||||
else:
|
||||
res.append(c)
|
||||
return ' '.join(res)
|
||||
|
||||
|
||||
def rclone_run(folder, extra_args=[]):
|
||||
command = rclone_make_command(
|
||||
folder['local-path'], folder['remote-path'], folder['remote']
|
||||
folder['local-path'], folder['remote-path'], folder['remote'], extra_args
|
||||
)
|
||||
try:
|
||||
print(str(folder['id']) + '. ' + process_command_for_print(command))
|
||||
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f'=== Error syncing {folder['local-path']} ===')
|
||||
print(f'Command: {' '.join(command)}')
|
||||
print(f'Command: {process_command_for_print(command)}')
|
||||
print(f'--- STDOUT ---')
|
||||
process_output(e.stdout)
|
||||
print(f'--- STDERR ---')
|
||||
|
|
@ -434,7 +449,6 @@ def rclone_run(folder):
|
|||
return {'success': False, 'stats': {}}
|
||||
return {'success': True, 'stats': parse_rclone_stats(result.stderr)}
|
||||
|
||||
|
||||
def notify(summary, body, level='normal', expire_time=5000):
|
||||
subprocess.run(['notify-send', '-u', level, '-t', str(expire_time), summary, body])
|
||||
|
||||
|
|
@ -447,17 +461,16 @@ def sizeof_fmt(num, suffix='B'):
|
|||
return f'{num:.1f}Yi{suffix}'
|
||||
|
||||
|
||||
def rclone_run_all(folders):
|
||||
def rclone_run_all(folders, extra_args=[]):
|
||||
error_folders = []
|
||||
total_bytes = 0
|
||||
total_transfers = 0
|
||||
total_deleted = 0
|
||||
total_renamed = 0
|
||||
for folder in folders:
|
||||
print(f'Running rclone for {folder}')
|
||||
res = rclone_run(folder)
|
||||
res = rclone_run(folder, extra_args)
|
||||
if not res['success']:
|
||||
error_folders.append(folder['local-path'])
|
||||
error_folders.append(folder)
|
||||
else:
|
||||
total_bytes += res.get('stats', {}).get('bytes', 0)
|
||||
total_transfers += res.get('stats', {}).get('transfers', 0)
|
||||
|
|
@ -469,21 +482,44 @@ def rclone_run_all(folders):
|
|||
if total_transfers > 0:
|
||||
msg += f'''Transferred {total_transfers} files ({sizeof_fmt(total_bytes)})\n'''
|
||||
if total_deleted > 0:
|
||||
msg += f'''Deleted {total_transfers} files\n'''
|
||||
msg += f'''Deleted {total_deleted} files\n'''
|
||||
if total_renamed > 0:
|
||||
msg += f'''Renamed {total_renamed} files\n'''
|
||||
|
||||
if len(error_folders) > 0:
|
||||
msg += '''\nSync errors for the following folders:'''
|
||||
for folder in error_folders:
|
||||
msg += '''\n- ''' + folder
|
||||
msg += '''\n- ''' + str(folder['id']) + '. ' + folder['local-path']
|
||||
level = 'critical'
|
||||
|
||||
if len(msg) > 0:
|
||||
notify(f'rclone sync {REMOTE}', msg, level=level)
|
||||
|
||||
def parse_arguments():
|
||||
if len(sys.argv) < 2:
|
||||
return None, []
|
||||
|
||||
id_arg = sys.argv[1]
|
||||
folder_ids = [int(x.strip()) for x in id_arg.split(',')]
|
||||
|
||||
extra_args = sys.argv[2:]
|
||||
|
||||
return folder_ids, extra_args
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
rclone_run_all(FOLDERS)
|
||||
folder_ids, extra_args = parse_arguments()
|
||||
|
||||
if folder_ids is None:
|
||||
selected_folders = FOLDERS
|
||||
else:
|
||||
selected_folders = [f for f in FOLDERS if f['id'] in folder_ids]
|
||||
found_ids = {f['id'] for f in selected_folders}
|
||||
missing_ids = set(folder_ids) - found_ids
|
||||
if missing_ids:
|
||||
print(f'Warning: folder IDs not found: {sorted(missing_ids)}')
|
||||
|
||||
rclone_run_all(selected_folders, extra_args)
|
||||
"))
|
||||
(setq script
|
||||
(thread-last script
|
||||
|
|
@ -562,6 +598,23 @@ The return value is a list of commands as defined by
|
|||
commands))
|
||||
(nreverse commands)))
|
||||
|
||||
(defun my/index-rclone-reset ()
|
||||
"Delete all rclone test files."
|
||||
(interactive)
|
||||
(let* ((tree (my/index--tree-retrive))
|
||||
(folders (my/index--rclone-get-folders tree))
|
||||
files-to-delete)
|
||||
(dolist (folder folders)
|
||||
(let ((test-file-path
|
||||
(concat
|
||||
(alist-get :local-path folder)
|
||||
(format ".rclone-test-%s" (alist-get :remote folder)))))
|
||||
(when (file-exists-p test-file-path)
|
||||
(push test-file-path files-to-delete))))
|
||||
(when (y-or-n-p (format "Delete %d files" (seq-length files-to-delete)))
|
||||
(dolist (file files-to-delete)
|
||||
(delete-file file)))))
|
||||
|
||||
(defun my/index--git-commands (tree)
|
||||
"Get commands to clone the yet uncloned git repos in TREE.
|
||||
|
||||
|
|
|
|||
14
Desktop.org
14
Desktop.org
|
|
@ -965,14 +965,14 @@ A +transient+ hydra for shortcuts for the most frequent apps.
|
|||
_t_: Terminal (Alacritty)
|
||||
_b_: Browser (Firefox)
|
||||
_s_: Rocket.Chat
|
||||
_e_: Element
|
||||
_d_: Discord
|
||||
_d_: DBeaver
|
||||
_c_: Chromium
|
||||
"
|
||||
("t" (lambda () (interactive) (my/run-in-background "alacritty")))
|
||||
("b" (lambda () (interactive) (my/run-in-background "firefox")))
|
||||
("s" (lambda () (interactive) (my/run-in-background "flatpak run chat.rocket.RocketChat")))
|
||||
("e" (lambda () (interactive) (my/run-in-background "flatpak run im.riot.Riot")))
|
||||
("d" (lambda () (interactive) (my/run-in-background "flatpak run com.discordapp.Discord"))))
|
||||
("s" (lambda () (interactive) (my/run-in-background "rocketchat-desktop")))
|
||||
("d" (lambda () (interactive) (my/run-in-background "dbeaver")))
|
||||
("c" (lambda () (interactive) (my/run-in-background "chromium"))))
|
||||
#+end_src
|
||||
*** Locking up
|
||||
Run i3lock.
|
||||
|
|
@ -1219,10 +1219,10 @@ And the EXWM config itself.
|
|||
|
||||
(my/exwm-set-wallpaper)
|
||||
(my/exwm-run-shepherd)
|
||||
(my/exwm-run-systemd)
|
||||
(my/run-in-background "gpgconf --reload gpg-agent")
|
||||
(my/exwm-run-polybar)
|
||||
(setenv "DBUS_SESSION_BUS_ADDRESS" "unix:path=/run/user/1000/bus")
|
||||
(my/exwm-run-systemd)
|
||||
(when (my/is-arch)
|
||||
(my/run-in-background "set_layout")))
|
||||
|
||||
|
|
@ -4239,6 +4239,7 @@ This section generates manifests for various desktop software that I'm using.
|
|||
| office | okular |
|
||||
| office | obs-studio |
|
||||
| office | rocketchat-desktop |
|
||||
|
||||
** LaTeX
|
||||
| Category | Arch dependency | Disabled |
|
||||
|----------+--------------------------+----------|
|
||||
|
|
@ -4540,6 +4541,7 @@ Other desktop programs I use are listed below.
|
|||
| desktop-misc | noto-fonts-emoji | |
|
||||
| desktop-misc | remmina | |
|
||||
| desktop-misc | android-file-transfer | |
|
||||
| desktop-misc | veracrypt | |
|
||||
|
||||
#+NAME: packages
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
|
|
|
|||
84
Emacs.org
84
Emacs.org
|
|
@ -10433,6 +10433,8 @@ References:
|
|||
;; I have everything I need in polybar
|
||||
(emms-mode-line-mode -1)
|
||||
(emms-playing-time-display-mode -1)
|
||||
(delq 'emms-mark-mode evil-emacs-state-modes)
|
||||
(delq 'emms-browser-mode evil-emacs-state-modes)
|
||||
<<emms-fixes>>)
|
||||
#+end_src
|
||||
**** MPD
|
||||
|
|
@ -12870,8 +12872,11 @@ REMOTE = '<rclone-remote>'
|
|||
FOLDERS = json.loads('<rclone-folders-json>')
|
||||
OPTIONS = json.loads('<rclone-options>')
|
||||
|
||||
for folder, i in zip(FOLDERS, range(len(FOLDERS))):
|
||||
folder['id'] = i
|
||||
|
||||
def rclone_make_command(local_path, remote_path, remote):
|
||||
|
||||
def rclone_make_command(local_path, remote_path, remote, extra_args=[]):
|
||||
return [
|
||||
'rclone',
|
||||
'bisync',
|
||||
|
|
@ -12885,7 +12890,8 @@ def rclone_make_command(local_path, remote_path, remote):
|
|||
'NEVER',
|
||||
'--use-json-log',
|
||||
'--stats',
|
||||
'9999m'
|
||||
'9999m',
|
||||
,*extra_args
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -12913,15 +12919,26 @@ def process_output(output):
|
|||
except Exception:
|
||||
print(line)
|
||||
|
||||
def rclone_run(folder):
|
||||
def process_command_for_print(command):
|
||||
res = []
|
||||
for c in command:
|
||||
if ' ' in c:
|
||||
res.append(f'\\'{c}\\'')
|
||||
else:
|
||||
res.append(c)
|
||||
return ' '.join(res)
|
||||
|
||||
|
||||
def rclone_run(folder, extra_args=[]):
|
||||
command = rclone_make_command(
|
||||
folder['local-path'], folder['remote-path'], folder['remote']
|
||||
folder['local-path'], folder['remote-path'], folder['remote'], extra_args
|
||||
)
|
||||
try:
|
||||
print(str(folder['id']) + '. ' + process_command_for_print(command))
|
||||
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f'=== Error syncing {folder['local-path']} ===')
|
||||
print(f'Command: {' '.join(command)}')
|
||||
print(f'Command: {process_command_for_print(command)}')
|
||||
print(f'--- STDOUT ---')
|
||||
process_output(e.stdout)
|
||||
print(f'--- STDERR ---')
|
||||
|
|
@ -12929,7 +12946,6 @@ def rclone_run(folder):
|
|||
return {'success': False, 'stats': {}}
|
||||
return {'success': True, 'stats': parse_rclone_stats(result.stderr)}
|
||||
|
||||
|
||||
def notify(summary, body, level='normal', expire_time=5000):
|
||||
subprocess.run(['notify-send', '-u', level, '-t', str(expire_time), summary, body])
|
||||
|
||||
|
|
@ -12942,17 +12958,16 @@ def sizeof_fmt(num, suffix='B'):
|
|||
return f'{num:.1f}Yi{suffix}'
|
||||
|
||||
|
||||
def rclone_run_all(folders):
|
||||
def rclone_run_all(folders, extra_args=[]):
|
||||
error_folders = []
|
||||
total_bytes = 0
|
||||
total_transfers = 0
|
||||
total_deleted = 0
|
||||
total_renamed = 0
|
||||
for folder in folders:
|
||||
print(f'Running rclone for {folder}')
|
||||
res = rclone_run(folder)
|
||||
res = rclone_run(folder, extra_args)
|
||||
if not res['success']:
|
||||
error_folders.append(folder['local-path'])
|
||||
error_folders.append(folder)
|
||||
else:
|
||||
total_bytes += res.get('stats', {}).get('bytes', 0)
|
||||
total_transfers += res.get('stats', {}).get('transfers', 0)
|
||||
|
|
@ -12964,21 +12979,44 @@ def rclone_run_all(folders):
|
|||
if total_transfers > 0:
|
||||
msg += f'''Transferred {total_transfers} files ({sizeof_fmt(total_bytes)})\n'''
|
||||
if total_deleted > 0:
|
||||
msg += f'''Deleted {total_transfers} files\n'''
|
||||
msg += f'''Deleted {total_deleted} files\n'''
|
||||
if total_renamed > 0:
|
||||
msg += f'''Renamed {total_renamed} files\n'''
|
||||
|
||||
if len(error_folders) > 0:
|
||||
msg += '''\nSync errors for the following folders:'''
|
||||
for folder in error_folders:
|
||||
msg += '''\n- ''' + folder
|
||||
msg += '''\n- ''' + str(folder['id']) + '. ' + folder['local-path']
|
||||
level = 'critical'
|
||||
|
||||
if len(msg) > 0:
|
||||
notify(f'rclone sync {REMOTE}', msg, level=level)
|
||||
|
||||
def parse_arguments():
|
||||
if len(sys.argv) < 2:
|
||||
return None, []
|
||||
|
||||
id_arg = sys.argv[1]
|
||||
folder_ids = [int(x.strip()) for x in id_arg.split(',')]
|
||||
|
||||
extra_args = sys.argv[2:]
|
||||
|
||||
return folder_ids, extra_args
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
rclone_run_all(FOLDERS)
|
||||
folder_ids, extra_args = parse_arguments()
|
||||
|
||||
if folder_ids is None:
|
||||
selected_folders = FOLDERS
|
||||
else:
|
||||
selected_folders = [f for f in FOLDERS if f['id'] in folder_ids]
|
||||
found_ids = {f['id'] for f in selected_folders}
|
||||
missing_ids = set(folder_ids) - found_ids
|
||||
if missing_ids:
|
||||
print(f'Warning: folder IDs not found: {sorted(missing_ids)}')
|
||||
|
||||
rclone_run_all(selected_folders, extra_args)
|
||||
#+end_src
|
||||
|
||||
A function that templates the script above:
|
||||
|
|
@ -13073,6 +13111,26 @@ The return value is a list of commands as defined by
|
|||
(nreverse commands)))
|
||||
#+end_src
|
||||
|
||||
Also, a command to remove all =.rclone-test-*= files. This is necessary, e.g. after a change in the filter file.
|
||||
#+begin_src emacs-lisp
|
||||
(defun my/index-rclone-reset ()
|
||||
"Delete all rclone test files."
|
||||
(interactive)
|
||||
(let* ((tree (my/index--tree-retrive))
|
||||
(folders (my/index--rclone-get-folders tree))
|
||||
files-to-delete)
|
||||
(dolist (folder folders)
|
||||
(let ((test-file-path
|
||||
(concat
|
||||
(alist-get :local-path folder)
|
||||
(format ".rclone-test-%s" (alist-get :remote folder)))))
|
||||
(when (file-exists-p test-file-path)
|
||||
(push test-file-path files-to-delete))))
|
||||
(when (y-or-n-p (format "Delete %d files" (seq-length files-to-delete)))
|
||||
(dolist (file files-to-delete)
|
||||
(delete-file file)))))
|
||||
#+end_src
|
||||
|
||||
**** Git repos
|
||||
To sync git, we just need to clone the required git repos. Removing the repos is handled by the folder sync commands.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue