(add-to-list 'load-path (expand-file-name "~/.emacs.d/bundle/")) ;;; bundle--defaults ;; General user interface and appearance (tool-bar-mode -1) (menu-bar-mode -1) (scroll-bar-mode -1) (horizontal-scroll-bar-mode -1) (global-hl-line-mode 1) (display-time-mode 1) (global-prettify-symbols-mode -1) (set-fringe-mode 10) (setq display-time-format " W%V %a %d %b %Y %R %z") (setq display-time-24hr-format t) ;; Cursor and mouse (column-number-mode 1) (mouse-wheel-mode 1) (blink-cursor-mode -1) (use-package calendar :ensure nil :config (setq calendar-latitude 49.4) (setq calendar-longitude 11.0) (setq calendar-location-name "Nuremberg, DE") :custom (european-calendar-style t) (calendar-christian-all-holidays-flag t) (calendar-date-style (quote iso)) (calendar-view-diary-initially-flag t) (calendar-week-start-day 1) (calendar-intermonth-text '(propertize (format "%2d" (car (calendar-iso-from-absolute (calendar-absolute-from-gregorian (list month day year ))))) 'font-lock-face 'font-lock-function-name-face))) (setq ispell-program-name "hunspell") (setq grep-command "grep -i -nH -e ") (when (eq system-type 'gnu/linux) (setq shell-file-name "/bin/bash") (setq tex-shell-file-name "/bin/bash")) ;; Files and sessions (setq auto-save-timeout 60) ;; Tabs, spaces, lines and parenthesis (show-paren-mode 1) (setq indent-tabs-mode nil) (setq line-spacing nil) (setq make-backup-files nil) (setq tab-width 4) (setq sentence-end-double-space nil) (setq next-line-add-newlines t) (setq require-final-newline t) ;; Miscellaneous (require 'cl-lib) (setq default-major-mode 'text-mode) (setq inhibit-startup-buffer-menu t inhibit-startup-screen t) (setq tramp-default-method "ssh") (put 'narrow-to-region 'disabled nil) (put 'narrow-to-page 'disabled nil) (add-hook 'text-mode-hook 'turn-on-auto-fill) (defalias 'yes-or-no-p 'y-or-n-p) ;; ;; Mode line ;; (setq mode-line-format ;; '(("" ;; mode-line-modified ;; mode-line-frame-control "%b %z%n " ;; mode-name ;; vc-mode ;; " " ;; mode-line-position ;; mode-line-misc-info ;; minor-mode-alist ;; mode-line-end-spaces "%-" ;; ))) ;; Disable line numbers in modes ;; (dolist (mode '(org-mode-hook term-mode-hook shell-mode-hook eshell-mode-hook)) ;; (add-hook mode (lambda () (display-line-numbers-mode 0)))) (add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p) (global-set-key (kbd "M-i") 'imenu) (global-set-key (kbd "C-x C-b") 'ibuffer-list-buffers) ;;(global-set-key (kbd "M-[") 'tab-bar-history-back) ;;(global-set-key (kbd "M-]") 'tab-bar-history-forward) (add-hook 'diary-display-hook 'fancy-diary-display) (add-hook 'today-visible-calendar-hook 'calendar-mark-today) (add-hook 'write-file-hooks 'delete-trailing-whitespace) (add-hook 'diary-list-entries-hook 'diary-include-other-diary-files) (add-hook 'diary-mark-entries-hook 'diary-mark-included-diary-files) (setq compilation-ask-about-save nil) (setq vc-handled-backends '(Git Hg)) ;; Only use Git and Hg for VC (setq horizontal-scroll-bar nil) (setq vertical-scroll-bar nil) (setq default-frame-alist '((font . "MonoLisa-11") (width . 92) (height . 62) (alpha . 100))) (setq mouse-wheel-scroll-amount '(1 ((shift) . 1) ((meta)) ((control) . text-scale))) (require 'ido) (setq ido-enable-flex-matching t) (setq ido-everywhere t) (setq ido-create-new-buffer 'always) ;(setq ido-file-extensions-order '(".org" ".lisp" ".py" ".txt" ".el" ".epub")) (ido-mode t) (fido-mode 1) ; replace icomplete mode ;;; ;;; bundle--encoding ;; UTF-8 FTW (prefer-coding-system 'utf-8) (set-default-coding-systems 'utf-8) (set-terminal-coding-system 'utf-8) (set-keyboard-coding-system 'utf-8) (setq default-buffer-file-coding-system 'utf-8) (setenv "PYTHONIOENCODING" "UTF-8") ;;; (setq holiday-oriental-holidays nil) (setq holiday-islamic-holidays nil) (setq holiday-bahai-holidays nil) (setq holiday-hebrew-holidays nil) (setq holiday-general-holidays '((holiday-fixed 1 1 "Neujahr") (holiday-fixed 5 1 "1. Mai") (holiday-fixed 10 3 "Tag der Deutschen Einheit"))) (setq holiday-christian-holidays '((holiday-float 12 0 -4 "1. Advent" 24) (holiday-float 12 0 -3 "2. Advent" 24) (holiday-float 12 0 -2 "3. Advent" 24) (holiday-float 12 0 -1 "4. Advent" 24) (holiday-fixed 12 25 "1. Weihnachtstag") (holiday-fixed 12 26 "2. Weihnachtstag") (holiday-fixed 1 6 "Heilige Drei Könige") (holiday-easter-etc -48 "Rosenmontag") ;; (holiday-easter-etc -3 "Gründonnerstag") (holiday-easter-etc -2 "Karfreitag") (holiday-easter-etc 0 "Ostersonntag") (holiday-easter-etc +1 "Ostermontag") (holiday-easter-etc +39 "Christi Himmelfahrt") (holiday-easter-etc +49 "Pfingstsonntag") (holiday-easter-etc +50 "Pfingstmontag") (holiday-easter-etc +60 "Fronleichnam") (holiday-fixed 8 15 "Mariae Himmelfahrt") (holiday-fixed 11 1 "Allerheiligen") ;; (holiday-float 11 3 1 "Buss- und Bettag" 16) (holiday-float 11 0 1 "Totensonntag" 20))) ;;; ;;; bundle--server (require 'server) ;; Start a server if (server-running-p) does not return t (e.g. if it ;; returns nil or :other) (or (eq (server-running-p) t) (server-start)) ;;; (use-package tramp :ensure nil :config (if (eq system-name 'windows-nt) (setq tramp-default-method "sshx") (setq tramp-default-method "ssh"))) ;;; bundle--customfile (use-package doom-themes :init (setq doom-themes-enable-bold t ; if nil, bold is universally disabled doom-themes-enable-italic t) ; if nil, italics is universally disabled (load-theme 'doom-one t)) (defvar mk/hyperspec-dir-locations '("d:/visua/projects/personal/lisp-docs/HyperSpec-7-0/HyperSpec/" "~/projects/personal/lisp-docs/HyperSpec-7-0/HyperSpec/" "~/lisp-docs/HyperSpec-7-0/HyperSpec/" "~/sites/HyperSpec/") "List of possible locations where the local HyperSpec could reside.") (defun mk/find-dir (x) "Recursively search for a valid directory from a list X of directories. Returns the first valid directory, or nil if none found." (cond ((null x) nil) ((file-directory-p (car x)) (car x)) (t (mk/find-dir (cdr x))))) (defun mk/hyperspec-dir () "Finds and returns the URI of the local HyperSpec directory. Uses `mk/hyperspec-dir-locations' to find the directory." (let ((dir-prefix (if (eq system-type 'windows-nt) "file:///" ; windows needs three slashes "file://")) (dir (mk/find-dir mk/hyperspec-dir-locations))) (if dir (concat dir-prefix (expand-file-name dir)) nil))) (setq common-lisp-hyperspec-root (mk/hyperspec-dir)) ;; OS SETTINGS (when (eq system-type 'gnu/linux) (setq custom-file "~/.emacs.d/bundle/custom_gnu.el" browse-url-secondary-browser-function 'browse-url-firefox)) (when (eq system-type 'windows-nt) (setq custom-file "~/.emacs.d/bundle/custom_win32.el") (setq org-babel-python-command "python") (when (string= (system-name) "EVG02667NB") (cd "d:/opt") (setq custom-file "~/.emacs.d/bundle/custom_win32_EVG02667NB.el"))) ;; CUSTOM_FILE (load custom-file :noerror) ;;; (load "bundle--package") ;;; bundle--email (setq smtpmail-smtp-server "smtp.mailbox.org" smtpmail-smtp-service 465 smtpmail-stream-type 'ssl smtpmail-auth-credentials (expand-file-name "~/.authinfo.gpg") mml-default-sign-method "pgpmime" mml-default-encrypt-method "pgpmime" mml-secure-openpgp-sign-with-sender t mail-user-agent 'message-user-agent message-directory "~/Maildir" message-auto-save-directory "~/Maildir/Drafts" message-send-mail-function 'smtpmail-send-it compose-mail-user-agent-warnings nil) ;; (setq mml-secure-openpgp-signers '("86DB0F30F9F1661A54E21664C374817BE285268F")) ;; (add-hook 'message-send-hook 'mml-secure-message-sign-pgpmime) (defun mk/sign-email () ;; Sign an Email using the key of the sender. (interactive) (mml-secure-message-sign-pgpmime)) (defun mk/encrypt-email () ;; Encrypt an Email using the key of the recipient. (interactive) (mml-secure-message-encrypt-pgpmime)) (defvar mk/gps-location (eval '(let ((float-output-format "%.1f")) (format "%s%s, %s%s" (if (numberp calendar-latitude) (abs calendar-latitude) (+ (aref calendar-latitude 0) (/ (aref calendar-latitude 1) 60.0))) (if (numberp calendar-latitude) (if (> calendar-latitude 0) "N" "S") (if (eq (aref calendar-latitude 2) 'north) "N" "S")) (if (numberp calendar-longitude) (abs calendar-longitude) (+ (aref calendar-longitude 0) (/ (aref calendar-longitude 1) 60.0))) (if (numberp calendar-longitude) (if (> calendar-longitude 0) "E" "W") (if (eq (aref calendar-longitude 2) 'east) "E" "W")))))) (defvar mk/signature-name (concat "Cheers, " user-full-name " (" calendar-location-name ", " mk/gps-location ")\n")) (defvar mk/signature-gpg "GnuPG Key: https://meta.sr.ht/~marcuskammer.pgp\nFingerprint: 86DB 0F30 F9F1 661A 54E2 1664 C374 817B E285 268F") (defun mk/signature-time () (format-time-string "Written on: %a, %d %b %Y %R %z\n")) (defun mk/signature () (concat mk/signature-name (mk/signature-time) mk/signature-gpg)) (use-package message :ensure nil :hook (message-signature-setup . (lambda () (setf message-signature (mk/signature))))) (add-hook 'mail-send-hook #'ispell-message) (add-hook 'message-send-hook #'ispell-message) (when (eq system-type 'gnu/linux) (use-package mu4e :ensure nil :hook (mu4e-compose-pre . (lambda () (setf mu4e-compose-signature (mk/signature)))) :custom (mu4e-change-filenames-when-moving t) (mu4e-drafts-folder "/Drafts") (mu4e-get-mail-command "mbsync -a") (mu4e-headers-date-format "%Y-%m-%d %H:%M") (mu4e-refile-folder "/Archive") (mu4e-sent-folder "/Sent") (mu4e-trash-folder "/Trash") (mu4e-split-view 'horizontal) (mu4e-update-interval (* 10 60)))) (use-package gnus :ensure nil :hook (gnus-summary-prepare . gnus-summary-sort-by-most-recent-date) :custom (gnus-inhibit-startup-message t) (gnus-check-new-newsgroups nil) (gnus-select-method '(nnnil "")) (gnus-secondary-select-methods '((nntp "news.individual.de" (nntp-open-connection-function nntp-open-ssl-stream) (nntp-port-number 563) (nntp-authinfo-file "~/.authinfo.gpg")) (nnimap "mailbox" (nnimap-address "imap.mailbox.org") (nnimap-inbox "INBOX") (nnimap-server-port 993) (nnimap-stream ssl) (nnimap-authinfo-file "~/.authinfo.gpg"))))) ;;; (load "bundle--org") (load "bundle--ux") ;;; bundle--latex.el --- Configuration for Org-mode LaTeX export and AUCTeX ;;; Commentary: ;; This file contains configurations for exporting Org-mode files to LaTeX ;; PDFs using XeLaTeX. It sets up custom packages, table settings, and source ;; code listings. Also, it includes settings for AUCTeX package for enhanced ;; .tex file editing. ;; ;; Features: ;; - Uses the XeLaTeX compiler for PDF generation. ;; - Sets up various LaTeX packages like 'listings', 'booktabs', 'xcolor', etc. ;; - Provides custom LaTeX class based on KOMA-script for specific formatting. ;; - Enables SumatraPDF for PDF viewing on Windows, and Evince on other systems. ;; ;; Installation: ;; Add this file to your load-path and then add `(require 'bundle--latex)` ;; to your init.el file. ;; ;; Usage: ;; Simply save this configuration and restart Emacs or re-evaluate the buffer. ;;; Code: ;; Org-mode LaTeX export settings (require 'ox-latex) ;; Add custom LaTeX packages (setq org-latex-packages-alist '(("" "listings") ("" "booktabs") ("AUTO" "polyglossia" t ("xelatex" "lualatex")) ("" "grffile") ("" "unicode-math") ("" "xcolor"))) ;; Define the process to convert Org to PDF using XeLaTeX (setq org-latex-pdf-process '("latexmk -xelatex -shell-escape -quiet -f %f")) ;; Set the compiler to XeLaTeX (setq org-latex-compiler "xelatex") ;; Enable listings and other table-related features (setq org-latex-listings t) (setq org-latex-tables-booktabs t) (setq org-latex-images-centered t) ;; Customize the appearance of listings (source code blocks) (setq org-latex-listings-options '(("basicstyle" "\\ttfamily") ("showstringspaces" "false") ("keywordstyle" "\\color{blue}\\textbf") ("commentstyle" "\\color{gray}") ("stringstyle" "\\color{green!70!black}") ("stringstyle" "\\color{red}") ("frame" "single") ("numbers" "left") ("numberstyle" "\\ttfamily") ("columns" "fullflexible"))) ;; Set the input encoding (setq org-latex-inputenc-alist '((\"utf8\" . \"utf8x\"))) ;; Define custom LaTeX class with specific formatting (with-eval-after-load 'ox-latex (add-to-list 'org-latex-classes '("koma-general" "\\documentclass[a4paper,10pt,captions=tableheading,twoside=false]{scrartcl} \\linespread{1.25} \\usepackage{fontspec} \\defaultfontfeatures{Mapping=tex-text, RawFeature={+zero}} \\setmainfont{Noto Sans}[BoldFont=*-Medium,ItalicFont=*-Italic] \\setsansfont{Noto Sans}[BoldFont=*-Medium,ItalicFont=*-Italic] \\setmonofont{Noto Sans Mono}[BoldFont=*-Medium,Scale=0.8] \\usepackage{geometry} \\geometry{a4paper,left=2cm,right=2cm,top=1.6cm,bottom=1.6cm} \\usepackage{fancyhdr} \\pagestyle{fancy} \\fancyhf{} \\fancyhead[L]{\\leftmark} % Left header \\fancyhead[R]{\\thepage} % Right header" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))) ;; Set default LaTeX class (setq org-latex-default-class "koma-general") ;; Load KOMA letter support (eval-after-load 'ox '(require 'ox-koma-letter)) ;; TeX mode settings for editing .tex files (setq TeX-auto-save t) ; Enable auto-save (setq TeX-electric-math (cons "$" "$")) ; Shortcut for math mode (if (eq system-type 'windows-nt) (progn (setq TeX-view-program-list '(("SumatraPDF" "~/AppData/Local/SumatraPDF/SumatraPDF.exe %o"))) (setq TeX-view-program-selection '((output-pdf "SumatraPDF")))) (setq TeX-view-program-selection '((output-pdf "Evince")))) (setq TeX-source-correlate-start-server t) ; Enable source-correlate (setq TeX-master nil) ; Default master file (setq TeX-engine 'xetex) ; Set engine to XeTeX (setq TeX-command-extra-options "-shell-escape") ; Allow shell escape (use-package tex :defer t :ensure auctex :hook ((LaTeX-mode . turn-on-reftex) (LaTeX-mode . flyspell-mode) (LaTeX-mode . LaTeX-math-mode))) ;;; bundle--latex.el ends here (load "bundle--mk") ;;; bundle--linux.el --- A bundle of useful Linux information ;;; Commentary: ;; This file contains a variety of Emacs Lisp functions that provide ;; helpful descriptions for Linux directories, commands, and options. ;;; Code: (defvar linux-filesystem-alist '(( "/" . "Root directory, the base of the filesystem hierarchy") ("/bin" . "Essential command binaries, needed for booting") ("/boot" . "Bootloader files, kernel, and other files needed during booting") ("/dev" . "Device files representing hardware components") ("/etc" . "System-wide configuration files") ("/home" . "User home directories") ("/lib" . "Shared libraries and kernel modules") ("/media" . "Mount points for removable media like CDs and USBs") ("/mnt" . "Temporary mount points for filesystems") ("/opt" . "Optional application software packages") ("/proc" . "Virtual filesystem providing info about processes and system") ("/root" . "Home directory for the root user") ("/sbin" . "Essential system binaries, usually for the root user") ("/srv" . "Data directories for services like HTTP, FTP, etc.") ("/sys" . "Virtual filesystem for kernel objects") ("/tmp" . "Temporary files, cleared on reboot") ("/usr" . "User binaries, documentation, libraries, etc.") ("/var" . "Variable files like logs, databases, etc.")) "Alist mapping Linux directories to their descriptions.") (defun describe-linux-directory (dirname) "Describe the purpose of a Linux directory. Takes DIRNAME as an argument and prints its description." (interactive "sEnter Linux directory name (e.g., /bin): ") (let ((description (assoc-default dirname linux-filesystem-alist))) (if description (message "%s: %s" dirname description) (message "Unknown directory: %s" dirname)))) (defvar bash-regex-alist '(("empty line" . "^$") ("backslash" . "\\\\") ("line starts with a dot" . "^\\.") ("line ends with a dot" . "\\.$") ("line starts with a dollar sign" . "^\\$") ("line starts with a caret" . "^\\^") ("left square bracket" . "\\[") ("right square bracket" . "\\]") ("entire line" . "^.*$") ("any alphanumeric character" . "[a-zA-Z0-9]") ("IP Address" . "\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b") ("email" . "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}") ("hex color code" . "#[a-fA-F0-9]{6}") ("date in yyyy-mm-dd" . "\\b\\d{4}-\\d{2}-\\d{2}\\b") ("time in hh:mm:ss" . "\\b\\d{2}:\\d{2}:\\d{2}\\b") ("words without vowels" . "\\b[^aeiou\s]+\\b")) "Alist mapping Bash regular expressions to their descriptions.") (defun describe-bash-regex (regex) "Describe the purpose of a Bash regular expression. Takes REGEX as an argument and prints its description." (interactive "sEnter Bash regex (e.g., empty line): ") (let ((description (assoc-default regex bash-regex-alist))) (if description (message "%s: %s" regex description) (message "Unknown regular expression: %s" regex)))) (defvar linux-process-commands-alist '(("ps" . "Shows a snapshot of the current processes") ("top" . "Displays dynamic real-time view of system stats and processes") ("htop" . "An interactive process viewer, similar to top but more feature-rich") ("pgrep" . "Looks up processes based on name and other attributes") ("pstree" . "Displays the process tree in a tree-like diagram") ("ps -e" . "Lists all the processes running on the system") ("ps aux" . "Displays detailed information about all processes") ("kill" . "Terminates processes by sending signals") ("killall" . "Kills all processes that match the given name") ("pkill" . "Send signals to processes based on name and other attributes")) "Alist mapping Linux process-checking commands to their descriptions.") (defun describe-linux-process-command (command) "Describe the purpose of a Linux process-checking command. Takes COMMAND as an argument and prints its description." (interactive "sEnter Linux process command (e.g., ps): ") (let ((description (assoc-default command linux-process-commands-alist))) (if description (message "%s: %s" command description) (message "Unknown command: %s" command)))) (defvar linux-logfiles-alist '(("/var/log/syslog" . "System messages, including the messages that are logged during system startup") ("/var/log/auth.log" . "Security/authorization information, including user logins and authentication") ("/var/log/kern.log" . "Kernel logs") ("/var/log/cron.log" . "Logs for cron jobs") ("/var/log/messages" . "General system activity logs") ("/var/log/boot.log" . "System boot log") ("/var/log/daemon.log" . "Background daemon log messages") ("/var/log/dpkg.log" . "Logs for package installations and removals") ("/var/log/mail.log" . "Mail server logs") ("/var/log/user.log" . "User-level messages")) "Alist mapping Linux log files to their descriptions.") (defun describe-linux-logfile (logfile) "Describe the purpose of a Linux log file. Takes LOGFILE as an argument and prints its description." (interactive "sEnter Linux log file path (e.g., /var/log/syslog): ") (let ((description (assoc-default logfile linux-logfiles-alist))) (if description (message "%s: %s" logfile description) (message "Unknown log file: %s" logfile)))) (defvar linux-basic-commands-alist '(("list directory contents" . "ls") ("change directory" . "cd") ("move or rename files" . "mv") ("copy files" . "cp") ("remove files or directories" . "rm") ("print working directory" . "pwd") ("display variable value" . "echo") ("create an empty file" . "touch") ("change file permissions" . "chmod") ("change file ownership" . "chown")) "Alist mapping basic Linux command descriptions to their commands.") (defun describe-basic-linux-command (command) "Describe the purpose of a basic Linux command. Takes COMMAND as an argument and prints its description." (interactive "sEnter basic Linux command (e.g., ls): ") (let ((description (assoc-default command linux-basic-commands-alist))) (if description (message "%s: %s" command description) (message "Unknown command: %s" command)))) (defvar chown-options-alist '(("-R" . "Operate on files and directories recursively") ("--from" . "Change the owner and/or group of each file only if its current owner and/or group match specified values") ("--no-dereference" . "Affect symbolic links instead of the files they point to") ("--preserve-root" . "Fail when attempting to operate recursively on '/'") ("--reference" . "Use owner and group of a reference file") ("-c" . "Report when a change is made") ("-f" . "Suppress most error messages") ("-v" . "Output a diagnostic for every file processed")) "Alist mapping chown command options to their descriptions.") (defun describe-chown-option (option) "Describe the purpose of a chown option. Takes OPTION as an argument and prints its description." (interactive "sEnter chown option (e.g., -R): ") (let ((description (assoc-default option chown-options-alist))) (if description (message "%s: %s" option description) (message "Unknown chown option: %s" option)))) (defvar chmod-options-alist '(("-R" . "Operate on files and directories recursively") ("--preserve-root" . "Avoid operating recursively on '/'") ("-c" . "Report when a change is made") ("-f" . "Suppress most error messages") ("-v" . "Output a diagnostic for every file processed") ("--reference" . "Use mode of a reference file") ("-w" . "Remove write permission") ("-x" . "Remove execute permission") ("-u" . "Set user ID on execution") ("-g" . "Set group ID on execution")) "Alist mapping chmod command options to their descriptions.") (defun describe-chmod-option (option) "Describe the purpose of a chmod option. Takes OPTION as an argument and prints its description." (interactive "sEnter chmod option (e.g., -R): ") (let ((description (assoc-default option chmod-options-alist))) (if description (message "%s: %s" option description) (message "Unknown chmod option: %s" option)))) (defvar ssh-use-cases-alist '(("remote login" . "ssh user@host") ("run command" . "ssh user@host 'command'") ("file transfer" . "scp file.txt user@host:/path/") ("secure ftp" . "sftp user@host") ("port forwarding" . "ssh -L local_port:remote_host:remote_port user@host") ("dynamic port forwarding" . "ssh -D port user@host") ("remote port forwarding" . "ssh -R remote_port:local_host:local_port user@host") ("tunneling" . "ssh -L local_port:remote_host:remote_port user@host -f -N") ("agent forwarding" . "ssh -A user@host") ("ssh multiplexing" . "ssh -M -S /tmp/ssh_socket user@host; ssh -S /tmp/ssh_socket user@host")) "Alist mapping SSH use cases to their corresponding commands.") (defun describe-ssh-use-case (use-case) "Describe the SSH command for a given use case." (interactive "sEnter the SSH use case: ") (let ((command (assoc-default use-case ssh-use-cases-alist))) (if command (message "Command for %s: %s" use-case command) (message "Use case not found")))) (defvar mk/remote-*host-aliases* '(("website" . "marcus@u1.marcuskammer.dev") ("playground" . "marcus@u1.metaebene.dev")) "Alist mapping friendly host names to actual SSH-compatible host strings.") (defun mk/remote--get-real-host (alias) "Lookup the real host name based on a given ALIAS." (or (cdr (assoc alias mk/remote-*host-aliases*)) alias)) (defun mk/remote--systemctl-service (alias service command) "Execute a systemctl COMMAND on a systemd SERVICE on a remote host identified by ALIAS. ALIAS is a string that specifies the remote host; it can be an alias defined in `mk/remote-*host-aliases*'. SERVICE is the name of the systemd service to operate on. COMMAND is the systemctl command to execute on the service (e.g., 'start', 'stop', 'status')." (let* ((host (mk/remote--get-real-host alias)) (buffer (generate-new-buffer (format "*%s-%s-%s*" alias service command))) (process-name (format "systemctl-%s-%s" command service)) (sentinel (lambda (process signal) (when (memq (process-status process) '(exit signal)) (message "Process: %s %s" process signal))))) (make-process :name process-name :buffer buffer :command `("ssh" ,host "sudo" "systemctl" ,command ,service) :sentinel sentinel))) (defmacro mk/remote-define-systemctl-functions (&rest actions) "Dynamically create functions to interact with systemd services on a remote host. Each function will be named `mk/remote-ACTION-service', where ACTION is one of the symbols in ACTIONS. The functions will take an ALIAS and SERVICE as arguments and call `mk/remote--systemctl-service' accordingly." `(progn ,@(mapcar (lambda (action) `(defun ,(intern (format "mk/remote-%s-service" action)) (alias service) (interactive "sEnter the host alias or name: \nsEnter the service name: ") (mk/remote--systemctl-service alias service ,(symbol-name action)))) actions))) (mk/remote-define-systemctl-functions start stop status)