;;; -*- lexical-binding: nil -*- ;;(mapc #'package-install '(ledger-mode transpose-frame dictionary paredit expand-region 0x0 pinentry rainbow-delimiters clhs emms ebdb markdown-mode magit captain exwm go-translate plz jabber languagetool elpher)) (eval-when-compile (require 'eww)) ;; Code fixes to contribute (with-eval-after-load 'message ;; After evaluating 'message-add-openpgp-header the point changes ;; place. ;; ;; Since this function has 'message-sort-headers at the end, for me, ;; this signals that this function does need to that into account ;; the side-effect of the point being left at a certain place. ;; ;; Since putting 'message-add-openpgp-header on a hook leads to a ;; point change (even when I am writing, somewhere, at the message ;; body), and since 'message-add-header changes point position, I ;; cannot use 'message-add-openpgp-header on a custom function that ;; cares for setting up my different keyids, keyurls, etc., without ;; having the side-effect of a point change. ;; ;; This fix, is for evaluating 'message-add-openpgp-header without a ;; point change side-effect. (defun message-add-openpgp-header () "Add OpenPGP header to point to public key. Header will be constructed as specified in `message-openpgp-header'. Consider adding this function to `message-header-setup-hook'" ;; See https://tools.ietf.org/html/draft-josefsson-openpgp-mailnews-header (when (and message-openpgp-header (or (nth 0 message-openpgp-header) (nth 1 message-openpgp-header) (nth 2 message-openpgp-header))) (save-excursion (message-add-header (with-temp-buffer (insert "OpenPGP: ") ;; add ID (let (need-sep) (when (nth 0 message-openpgp-header) (insert "id=" (nth 0 message-openpgp-header)) (set 'need-sep t)) ;; add URL (when (nth 1 message-openpgp-header) (when need-sep (insert "; ")) (insert "url=\"" (nth 1 message-openpgp-header) "\"") (set 'need-sep t)) ;; add preference (when (nth 2 message-openpgp-header) (when need-sep (insert "; ")) (insert "preference=" (nth 2 message-openpgp-header)))) ;; insert header (buffer-string)))))) ;; When replying to a message, if 'message-cite-reply-position ;; variable is set to `below', and there is a message signature ;; configured, the point moves to below the signature separator; in ;; a place not ready to write. We have to move the point upwards two ;; times, in order to be in a place to begin writing. ;; ;; This fix, leaves the point above the signature separator (and ;; below the yanked reply), in *the* place to begin writing. ;; ;; I have chosen to modify 'message-goto-signature function, since ;; all the functionality needed is there (I could had also ;; duplicated almost all of its functionality to a different ;; function, but I think that would not be a good programming ;; style). Now if 'message-goto-signature function has a non-nil ;; argument it sets the point just before the message signature ;; separator. (defun message-goto-signature (&optional before) "Move point to the beginning of the message signature. If there is no signature in the article, go to the end and return nil. When BEFORE is non-nil and there is a message signature, move the point to the nearest place to begin writing. When `message-signature-insert-empty-line' is also non-nil, the point is at the correct place to begin writing a message." (interactive nil message-mode) (push-mark) (goto-char (point-min)) (if (re-search-forward message-signature-separator nil 't) (forward-line (if before -1 1)) (goto-char (point-max)) nil)) (defun message--yank-original-internal (arg) (let ((modified (buffer-modified-p)) body-text) (when (and message-reply-buffer message-cite-function) (when (equal message-cite-reply-position 'above) (save-excursion (set 'body-text (buffer-substring (message-goto-body) (point-max))) (delete-region (message-goto-body) (point-max)))) (if (bufferp message-reply-buffer) (delete-windows-on message-reply-buffer t)) (push-mark (save-excursion (cond ((bufferp message-reply-buffer) (insert-buffer-substring message-reply-buffer)) ((and (consp message-reply-buffer) (functionp (car message-reply-buffer))) (apply (car message-reply-buffer) (cdr message-reply-buffer)))) (unless (bolp) (insert ?\n)) (point))) (unless arg (funcall message-cite-function) (unless (eq (char-before (mark t)) ?\n) (let ((pt (point))) (goto-char (mark t)) (insert-before-markers ?\n) (goto-char pt)))) (pcase message-cite-reply-position ('above (message-goto-body) (insert body-text) (insert (if (bolp) "\n" "\n\n")) (message-goto-body)) ('below (message-goto-signature t))) ;; Add a `message-setup-very-last-hook' here? ;; Add `gnus-article-highlight-citation' here? (unless modified (set 'message-checksum (message-checksum))))))) (with-eval-after-load 'hashcash (defun hashcash-verify-payment (hctoken &optional resource amount) "Verify a hashcash payment." (let* ((split (split-string hctoken ":")) (key (if (< (hashcash-version hctoken) 1.2) (nth 1 split) (pcase (string-to-number (nth 0 split)) (0 (nth 2 split)) (1 (nth 3 split)))))) (cond ((null resource) (let ((elt (assoc key hashcash-accept-resources))) (hashcash-check-payment hctoken key (or (cadr elt) hashcash-default-accept-payment)))) ((equal hctoken key) (hashcash-check-payment hctoken resource (or amount hashcash-default-accept-payment))) (t nil))))) ;; My auxiliary functions ;;; Macros (defmacro dointerval (spec &rest body) "A dotimes starting at MIN." (declare (indent 1) (debug dolist)) (let ((var (nth 0 spec)) (start (nth 1 spec)) (end (nth 2 spec)) (counter (make-symbol "counter"))) `(let ((,counter ,start)) (while (<= ,counter ,end) (let ((,var ,counter)) ,@body) (set ',counter (1+ ,counter)))))) ;;; ELisp Functions (defun american-number-string-to-number (string) (string-to-number (string-replace "," "" string))) (defun random-interval (min max) "Get a random number between [MIN; MAX[." (+ min (random (- max min)))) (defun current-line-empty-p () "Check if current line is an empty line." (save-excursion (beginning-of-line) (looking-at-p "^[[:blank:]]*$"))) ;; load-path (add-to-list 'load-path (expand-file-name "~/.emacs.d/my-libs")) (add-to-list 'load-path "/usr/share/emacs/site-lisp") ;; load my elisp standard stuff (load "my-lisp") ;; unbind key (keymap-global-unset "C-x g") ;;; emacs related functions (defun emacs-eval-init-file () (interactive) (let ((buf-name "init.el")) (unless (get-buffer buf-name) (find-file (expand-file-name "~/.emacs.d/init.el")) (previous-buffer)) (set-buffer buf-name) (eval-buffer))) (keymap-global-set "C-x M-e" 'emacs-eval-init-file) (defun my-forward-sentence (&optional arg) (interactive "^p") (or arg (set 'arg 1)) (let ((sentence-end-double-space nil)) (forward-sentence arg))) (defun my-backward-sentence (&optional arg) (interactive "^p") (or arg (set 'arg 1)) (let ((sentence-end-double-space nil)) (backward-sentence arg))) (keymap-global-set "M-e" 'my-forward-sentence) (keymap-global-set "M-a" 'my-backward-sentence) (defun my-move-beginning-of-line (arg) (interactive "^p") (or arg (set 'arg 1)) (cond ((eql (point) (save-excursion (re-search-backward "^\\([[:blank:]]+\\)" nil 't) (match-end 1))) (move-beginning-of-line arg)) ('t (back-to-indentation)))) (keymap-global-set "C-a" 'my-move-beginning-of-line) (defun my-split-window-below () (interactive) (split-window-below) (set-window-buffer (next-window) (other-buffer)) (other-window 1)) (keymap-global-set "C-x 2" 'my-split-window-below) (defun my-split-window-right () (interactive) (split-window-right) (set-window-buffer (next-window) (other-buffer)) (other-window 1)) (keymap-global-set "C-x 3" 'my-split-window-right) (defun list-all-buffers (&optional files-only) "Display a list of names of existing buffers. The list is displayed in a buffer named `*Buffer List*'. Non-null optional arg FILES-ONLY means mention only file buffers. For more information, see the function `buffer-menu'." (interactive "P") (display-buffer (list-buffers-noselect files-only (buffer-list)))) (keymap-global-set "C-x C-b" 'list-all-buffers) (defun list-all-functions () "Lisp all current functions" (interactive) (apropos-command "." nil) (other-window 1) (read-only-mode -1) (goto-char (point-min)) (kill-line 2) (flush-lines "^ " nil nil 't) (re-search-forward "^\\([[:alnum:]/\\+\\*\\?!@#\\$%&_=-]+\\).*$") (replace-match "\\1") ;; (replace-match "\\1") ;; (replace-regexp ;; "^\\([[:alnum:]/\\+\\*\\?!@#\\$%&_=-]+\\).*$" "\\1" nil ;; (use-region-beginning) (use-region-end) nil (use-region-noncontiguous-p)) (save-excursion (let ((sort-fold-case 't)) (sort-lines nil (point-min) (point-max)))) (read-only-mode 1)) (keymap-global-set "ESC M-." 'xref-find-apropos) (keymap-global-set "C-h C-a" 'apropos-function) (keymap-global-set "C-h M-a" 'apropos-variable) (keymap-global-set "C-h M-i" 'info-apropos) ;;; my other functions (defun play-alarm (file) "Play a sound alarm FILE." (shell-command (concat "ffplay -v 0 -nodisp -volume 100 -autoexit " (expand-file-name file) " &>/dev/null"))) (defun quack () "Hear a duck's quack." (interactive) (play-alarm "~/.local/share/sound/duck-quack.mp3") (message "quack...")) (defun coin () "Hear a coin drop." (interactive) (play-alarm "~/.local/share/sound/coin.mp3")) (defun plink () "Hear a retro game sound." (interactive) (play-alarm "~/.local/share/sound/game-retro-beep.mp3")) (defun bip () "Hear a cool beep sound." (interactive) (play-alarm "~/.local/share/sound/error-deepin.mp3")) (defun birds () "Hear singing birds sound." (interactive) (play-alarm "~/.local/share/sound/little-birds-in-tree.mp3")) (defun heart () "Hear a heart machine sound." (interactive) (play-alarm "~/.local/share/sound/beep-heart-machine.mp3")) (defun rice-minutes (secs) "Rice alarm." (interactive "nMinutes for the rice cooking: ") (run-with-timer (* 60 secs) 0 (lambda () (dotimes (i 3) (quack) (sit-for 1)) (message "Alarm done."))) (message "Rice alarm set.")) (defun years-old (year) (interactive "nBirth year: ") (message "%d" (- (nth 5 (decode-time)) year))) (defun password-prompt () "Open a prompt, in the minibuffer, for passwords. Good when using M-x shell." (interactive) (comint-send-invisible) (clear-this-command-keys)) (keymap-global-set "C-c p" 'password-prompt) (with-eval-after-load 'eww (defun lesspass (site username counter length symbol-type) "Use lpcli on EWW." (interactive (list (read-string "Site: " (progn (string-match "https?://\\(.*\\)/+?" (eww-current-url)) (match-string 1 (plist-get eww-data :url)))) (read-string "Username: " (getenv "LESSPASS_USER")) (number-to-string (read-number "Counter: " 1)) (number-to-string (read-number "Length: " 16)) (read-string "Symbol's type: " "ulds"))) (insert (shell-command-to-string (concat "printf " (read-passwd "Password: ") " | lpcli " site " ${LESSPASS_USER} -p" symbol-type "c" counter "n" length " | grep -v -E 'Options:|Enter Password' | tr -dc '[:print:]'")))) (defalias 'lp 'lesspass)) (defun suspend-pc () "Suspend the PC." (interactive) (tab-switch "gnus") (cal) (emms-stop) (disconnect) (shell-command "sleep 0.25; mem-suspend")) (keymap-global-set "C-x C-z" 'suspend-pc) (defun my-save-buffers-kill-emacs () "Save buffers and kill Emacs daemon." (interactive) (when (y-or-n-p "Do you want to kill Emacs client and Emacs daemon? ") (save-buffers-kill-emacs))) (keymap-global-set "C-x C-c" 'my-save-buffers-kill-emacs) (keymap-global-set "C-x M-c" 'save-buffers-kill-terminal) ;; help with M-x ;; (icomplete-mode) ;; compiling (set 'compile-command "make -j $(nproc --all) ") (set 'compilation-scroll-output 't) ;; escape sequences ;;; compile with colors (no raw escape sequences) (require 'ansi-color) (add-hook 'compilation-filter-hook 'ansi-color-compilation-filter) ;;; fix raw escape sequences in shell (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) ;; emacs global keybindings (keymap-global-set "C-w" 'backward-kill-word) (keymap-global-set "M-DEL" 'kill-region) (keymap-global-set "C-x %" 'shrink-window) (keymap-global-set "C-x M-u" (lambda () (interactive) (package-upgrade-all nil))) (keymap-global-set "C-_" 'undo-only) (keymap-global-set "C-c ;" 'comment-region) (keymap-global-set "C-c e" 'end-of-buffer) (keymap-global-set "C-c b" 'beginning-of-buffer) (keymap-global-set "M-%" 'query-replace-regexp) ;; emacs default mode's hook (setq-default major-mode 'text-mode) ;; deleting trailing whitespace (add-hook 'before-save-hook 'delete-trailing-whitespace) ;; some general emacs variable options (set 'make-backup-files nil) ;;(set 'gc-cons-treshold 20000000) (set 'sentence-end-double-space 't) ;; (set 'fill-column 70) ;; dired with integration to gnus ;; (for example, attaching multiple files) (add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode) ;; LISP ;;; lisp show matching paren when cursor is after closing paren (show-paren-mode) ;;; lisp pair up parenthesis (electric-pair-mode) ;;; lisp color parenthesis automatic (package rainbow-delimiters) (add-hook 'lisp-mode-hook 'rainbow-delimiters-mode) (add-hook 'eldoc-mode-hook 'rainbow-delimiters-mode) ;;; lisp with paredit (with-eval-after-load 'paredit ;; (keymap-set paredit-mode-map "C-c M-q" 'slime-close-all-parens-in-sexp) (keymap-set paredit-mode-map "ESC DEL" 'paredit-kill-region) (keymap-set paredit-mode-map "C-c M-<" 'paredit-forward-barf-sexp) (keymap-set paredit-mode-map "C-c M->" 'paredit-forward-slurp-sexp) (keymap-set paredit-mode-map "C-c M-s" 'paredit-splice-sexp-killing-backward)) (add-hook 'lisp-mode-hook 'enable-paredit-mode) (add-hook 'emacs-lisp-mode-hook 'enable-paredit-mode) ;;; Common Lisp (set 'inferior-lisp-program "sbcl") ;;; (load (expand-file-name "~/quicklisp/slime-helper.el")) ;;; (require 'slime) ;;; (slime-setup) (set 'clhs-root "file:///usr/share/doc/clhs/HyperSpec/") (with-eval-after-load 'lisp-mode (keymap-set lisp-mode-map "C-h C-s" 'clhs-doc)) ;; ;;; Kilo Lisp ;; (defun run-klisp () ;; "Run LISP Club Language REPL." ;; (interactive) ;; (cd "~/me/programming/desktop/lisp/interpreter/klisp/klisp.new/") ;; (if (not (comint-check-proc "*inferior-kilolisp*")) ;; (let ((cmdlist (split-string-shell-command "kl")) ;; (inferior-lisp-buffer "*inferior-kilolisp*")) ;; (set-buffer (apply (function make-comint) ;; "inferior-kilolisp" (car cmdlist) nil (cdr cmdlist))))) ;; (pop-to-buffer "*inferior-kilolisp*" display-comint-buffer-action)) ;;; Scheme (set 'scheme-program-name "/usr/bin/guile") ;; (set 'scheme-program-name "/usr/bin/mit-scheme") ;; (set 'scheme-program-name "gsi -:t") ;; gambit ;; Elpher (defun my-elpher () "New Elpher session." (interactive) (elpher t)) (keymap-global-set "C-x g g" 'my-elpher) ;; EWW (set 'browse-url-browser-function 'eww-browse-url) ;; (set 'eww-search-prefix "https://duckduckgo.com/?q=") (set 'eww-search-prefix "https://searx.direitosdigitais.pt/search?q=") (set 'url-cookie-untrusted-urls '(".")) (set 'url-cookie-trusted-urls '("lists.gnupg.org" "labs.parabola.nu")) (set 'url-user-agent (shell-command-to-string "yt-dlp --dump-user-agent 2>/dev/null")) (set 'eww-download-directory (expand-file-name "~/Downloads")) (set 'shr-discard-aria-hidden 't) (set 'shr-max-width 179) ;; show eww using all of my screen width (set 'webjump-sites '(("GNU Project FTP Archive" . [mirrors "https://ftp.gnu.org/pub/gnu/" "https://ftpmirror.gnu.org"]) ("GNU Project Website" . "www.gnu.org") ("Emacs Website" . "www.gnu.org/software/emacs/emacs.html") ("Savannah Emacs page" . "savannah.gnu.org/projects/emacs") ("Emacs Lisp List" . "www.damtp.cam.ac.uk/user/eglen/emacs/ell.html") ("Savannah" . [simple-query "git.savannah.gnu.org/cgit" "https://git.savannah.gnu.org/cgit/?q=" #1=""]) ("Emacs Wiki" . [simple-query "www.emacswiki.org" "www.emacswiki.org/cgi-bin/wiki/" #1=""]) ("DuckDuckGo" . [simple-query "duckduckgo.com" "duckduckgo.com/?q=" #1#]) ("SearXNG" . [simple-query "searx.direitosdigitais.pt" "searx.direitosdigitais.pt/search?q=" #1#]) ("Google Groups" . [simple-query "groups.google.com" "groups.google.com/groups?q=" #1#]) ("Yahoo" . [simple-query "www.yahoo.com" "search.yahoo.com/search?p=" #1#]) ("Yahoo: Reference" . "www.yahoo.com/Reference/") ("Qwant Lite" . [simple-query "lite.qwant.com" "https://lite.qwant.com/?q=" #1#]) ("Mojeek" . [simple-query "www.mojeek.com" "https://www.mojeek.com/search?q=" #1#]) ("Wiby" . [simple-query "wiby.me" "https://wiby.me/?q=" #1#]) ("Marginalia" . [simple-query "old-search.marginalia.nu" "https://old-search.marginalia.nu/search?recent=&profile=&searchTitle=&adtech=&js=&query=" #1#]) ("Google" . [simple-query "www.google.com" "http://www.google.com/search?q=" #1#]) ("Marginalia" . [simple-query "old-search.marginalia.nu" "https://old-search.marginalia.nu/search?recent=default&profile=corpo&searchTitle=default&adtech=default&js=default&query=" #1#]) ("Wikipedia" . [simple-query "wikipedia.org" "https://en.wikipedia.org/wiki/Special:Search?go=Go&search=" #1#]) ("Invidious" . [simple-query "inv.nadeko.net" "https://inv.nadeko.net/search?q=" #1#]) ;; ("National Weather Service" . webjump-to-iwin) ("Usenet FAQs" . "www.faqs.org/faqs/") ("RTFM Usenet FAQs by Group" . "ftp://rtfm.mit.edu/pub/usenet-by-group/") ("RTFM Usenet FAQs by Hierarchy" . "ftp://rtfm.mit.edu/pub/usenet-by-hierarchy/") ("X Consortium Archive" . "ftp.x.org") ("Association for Computing Machinery" . "www.acm.org") ("Computer Professionals for Social Responsibility" . "www.cpsr.org") ("Electronic Frontier Foundation" . "www.eff.org") ("IEEE Computer Society" . "www.computer.org") ("Risks Digest" . webjump-to-risks) ("Supplemental Web site list for webjump" . "www.neilvandyke.org/webjump/") ("!Bangs" . "https://duckduckgo.com/bang_lite.html") ("Priberam" . [simple-query "dicionario.priberam.org" "https://dicionario.priberam.org/" #1#]) ("Chambers" . [simple-query "chambers.co.uk/search/" "https://chambers.co.uk/search/?title=21st&query=" #1#]) ("Xiph" . [simple-query "dir.xiph.org" "http://dir.xiph.org/search?q=" #1#]) ("Archwiki" . [simple-query "wiki.archlinux.org" "https://wiki.archlinux.org/index.php?search=" #1#]) ("Parabolawiki" . [simple-query "wiki.parabola.nu" "https://wiki.parabola.nu/index.php?search=" #1#]) ("AUR" . [simple-query "aur.archlinux.org" "https://aur.archlinux.org/packages?O=0&K=" #1#]) ("Archlinux Packages" . [simple-query "archlinux.org/packages/" "https://archlinux.org/packages/?q=" #1#]) ("Parabola Packages" . [simple-query "www.parabola.nu/packages/" "https://www.parabola.nu/packages/?q=" #1#]) ("Artix Packages" . [simple-query "gitea.artixlinux.org" "https://gitea.artixlinux.org/packages?language=&sort=recentupdate&q=" #1#]) ("PKGBUILD Arch" . [simple-query "archlinux.org/packages/" "https://gitlab.archlinux.org/archlinux/packaging/packages/" #1="/-/raw/main/PKGBUILD"]) ("PKGBUILD Artix" . [simple-query "archlinux.org/packages/" "https://gitea.artixlinux.org/packages/" #1="/raw/branch/master/PKGBUILD"]) ("PKGBUILD AUR" . [simple-query "aur.archlinux.org" "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=" #1=""]))) (defun eww-refresh-fingerprint () "Change EWW browser fingerprint." (interactive) (set 'url-user-agent (shell-command-to-string "yt-dlp --dump-user-agent 2>/dev/null"))) (defun my-eww (url &optional new-buffer buffer) "Fetch URL and render the page. If the input doesn't look like an URL or a domain name, the word(s) will be searched for via `eww-search-prefix'. If NEW-BUFFER is non-nil (interactively, the prefix arg), use a new buffer instead of reusing the default EWW buffer. If BUFFER, the data to be rendered is in that buffer. In that case, this function doesn't actually fetch URL. BUFFER will be killed after rendering. For more information, see Info node `(eww) Top'." (interactive (let ((uris (eww-suggested-uris)) (minibuffer-local-completion-map eww-minibuffer-url-keymap)) (list (completing-read (format-prompt "Enter URL or keywords" (and uris (car uris))) (seq-uniq (append eww-prompt-history uris)) nil nil nil 'eww-prompt-history uris) current-prefix-arg))) (setq url (eww--dwim-expand-url url)) (eww-refresh-fingerprint) (eww url new-buffer buffer)) (defun my-webjump () "Jumps to a Web site from a programmable hotlist. See the documentation for the `webjump-sites' variable for how to customize the hotlist. Please submit bug reports and other feedback to the author, Neil W. Van Dyke ." (interactive) (eww-refresh-fingerprint) (webjump)) (keymap-global-set "C-x w w" 'my-eww) (keymap-global-set "C-x w q" 'my-webjump) ;; package manager (require 'package) (with-eval-after-load 'package (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/"))) ;; unicode ;; (set-selection-coding-system 'utf-8) ;; ;;; (set 'x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)) ;; (set-language-environment "UTF-8") ;; prefer utf-8 for language settings ;; (prefer-coding-system 'utf-8) ;; (set-default-coding-systems 'utf-8) ;; (set 'sendmail-coding-system 'utf-8) ;; ispell (with-eval-after-load 'ispell ;; (setenv "LANG" "pt_PT.UTF-8") (set 'ispell-program-name "/usr/bin/hunspell") (set 'ispell-dictionary "en_GB,pt_PT") (ispell-set-spellchecker-params) (ispell-hunspell-add-multi-dic "en_GB,pt_PT") (set 'ispell-personal-dictionary (expand-file-name "~/.hunspell_personal")) (set 'ispell-alternate-dictionary "/usr/share/dict/british") (set 'ispell-message-dictionary-alist '(("^Content-Language: pt" . "pt_PT") ("^To:[^\n,]+\\.pt[ \t\n,>]" . "pt_PT") ("^Content-Language: en" . "en_GB")))) (keymap-global-set "C-c s" nil) (keymap-global-set "C-c s i" 'ispell-message) ;; languagetool (require 'languagetool) (set 'languagetool-java-arguments '("-Dfile.encoding=UTF-8" "-cp" "/usr/share/languagetool:/usr/share/java/languagetool/*")) (set 'languagetool-console-command "org.languagetool.commandline.Main") (set 'languagetool-console-arguments '("--languagemodel" "~/.local/share/languagetool/ngram/")) (set 'languagetool-server-command "org.languagetool.server.HTTPServer") (defun languagetool () "Interactively check a region or buffer for spelling errors using languagetool" (interactive) (if (region-active-p) (languagetool-console-check (region-beginning) (region-end)) (languagetool-console-check (point-min) (point-max))) (languagetool-correct-buffer)) (keymap-global-set "C-c s l" 'languagetool) (keymap-global-set "C-c s q" 'languagetool-clear-suggestions) ;; time european (set 'calendar-time-display-form '(24-hours ":" minutes (if time-zone " (") time-zone (if time-zone ")"))) (set 'display-time-24hr-format 't) ;; display time (display-time-mode) ;; switch command mode (require 'ido) (ido-mode 't) ;; winner-mode (set 'winner-dont-bind-my-keys 't) (winner-mode 1) (keymap-global-set "C-x w " 'winner-undo) (keymap-global-set "C-x w " 'winner-redo) ;; windmove (keymap-global-set "C-c " 'windmove-up) (keymap-global-set "C-c " 'windmove-left) (keymap-global-set "C-c " 'windmove-down) (keymap-global-set "C-c " 'windmove-right) ;; C language ;;; identation for C (setq-default indent-tabs-mode nil) (setq-default tab-width 3) (set 'c-basic-offset 2) ;;; gdb gud (set 'gdb-many-windows 't) ;; info (set 'Info-hide-note-references 'hide) ;; org mode (set 'org-export-with-toc nil) ;; abbrev (set 'abbrev-file-name (expand-file-name "~/.emacs.d/abbrev_defs")) (set 'save-abbrevs 'silently) (add-hook 'erc-mode-hook 'abbrev-mode) (add-hook 'jabber-chat-mode-hook 'abbrev-mode) (defun abbrev-save () (interactive) (write-abbrev-file (expand-file-name "~/.emacs.d/abbrev_defs")) (message "Abbreviations saved.")) (keymap-global-set "C-x a s" 'abbrev-save) (keymap-global-set "C-x a TAB" 'unexpand-abbrev) ;; ledger (set 'ledger-default-commodity 'EUR) ;; gnus ;;; load secret data (load "my-secret") ;;; general message config (set 'message-kill-buffer-on-exit 't) ;; C-c C-c kills the buffer (set 'message-signature-separator "^-- *$") ;; loose signature separator ;;; use bottom-posting by default (NEEDS FIX: 'below puts the point on the signature) (set 'message-cite-reply-position 'below) ;;; wide-reply prune addresses (set 'message-prine-recipient-rules '(("^\\([^@]+\\)@\\(.*\\)" "\\1@.*[.]\\2"))) ;;; open gnus in topics mode (add-hook 'gnus-group-mode-hook 'gnus-topic-mode) ;;; lines with time (set 'gnus-summary-line-format "%U%R%z%I %4L %(%[%-25,25D %-23,23f%]%) %s ") ;;; order threads by most recent date (set 'gnus-thread-sort-functions '(gnus-thread-sort-by-number)) ;;; show certain message headers (set 'gnus-visible-headers "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^Distribution:\\|^To:\\|^[BGF]?C[Cc]:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Mail-Followup-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-From:\\|^Archived-At:\\|^List-Unsubscribe:\\|^X.*-Spam.*:\\|^X-.*Complain.*:\\|^X-.*Abuse.*:\\|^OpenPGP:\\|^X.*-Key.*:\\|^X.*-PGP.*:\\|^Autocrypt:\\|^X-Payment:\\|^X-Hashcash:") ;;; remove this headers before sending mails (set 'message-ignored-mail-headers "^[GF]cc:\\|^Resent-Fcc:\\|^Xref:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:\\|^X-GDPR:") ;;; remove this headers before sending news (set 'message-ignored-news-headers "^NNTP-Posting-Host:\\|^Xref:\\|^[BGF]cc:\\|^Resent-Fcc:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:\\|^X-Message-SMTP-Method:\\|^X-Gnus-Delayed:\\|^X-GDPR:") ;;; hide summary lines of articles that have scores lower than this (set 'gnus-summary-expunge-below -9) (load "my-select-methods.el") ;;; delete bogus .newsrc groups at gnus startup ;; (set 'gnus-check-bogus-newsgroups nil) ;;; don't check for new groups ;; (set 'gnus-check-new-newsgroups nil) ;;; subscribe for new groups interactively (set 'gnus-subscribe-newsgroup-method 'gnus-subscribe-interactively) ;;; subscription method for newsgroups with "option -n" in .newsrc ;; (set 'gnus-subscribe-options-newsgroup-method 'gnus-subscribe-interactively) ;;; ignore subscribing to this groups (set 'gnus-options-not-subscribe ".*\\(gmane\\|gwene\\)\\..*") ;;; mailing list (set 'message-subscribed-address-file (expand-file-name "~/.mail.d/mailinglists")) ;; (set 'message-subscribed-address-functions ;; '(gnus-find-subscribed-addresses)) ;; (set 'gnus-group-name-charset-group-alist '((".*" . utf-8))) ;;; spam ;;;; hashcash (require 'hashcash) (set 'message-generate-hashcash 't) (set 'hashcash-double-spend-database (expand-file-name (concat (getenv "XDG_DATA_HOME") "/hashcash/hashcash.sdb"))) ;; (set 'hashcash-default-payment 30) (set 'hashcash-default-payment 28) (defun message-toggle-hashcash () "Toggle hashcash. Return `message-generate-hashcash' value." (interactive) (set 'message-generate-hashcash (not message-generate-hashcash)) (message "%s" message-generate-hashcash)) ;;;; show all headers of articles in spam newsgroup (defun gnus-spam-article-show-all-headers () (interactive) (when (equal gnus-newsgroup-name "spam") (gnus-summary-show-all-headers))) (set 'gnus-select-article-hook '(gnus-spam-article-show-all-headers)) ;;; signature to message (set 'message-signature nil) (set 'message-signature-file nil) (set 'message-signature-directory (expand-file-name "~/.mail.d/signatures")) (with-eval-after-load 'message (defun message-kill-signature () "Kill the message signature from current buffer." (interactive) (save-excursion (goto-char (point-max)) (when (re-search-backward message-signature-separator nil 't) (kill-region (1- (point)) (point-max))))) (defun my-message-insert-signature (&optional file) "Insert a signature, according to a signature FILE, to the current message." (interactive) (let ((message-signature-file (or file (read-file-name "Signature file: " (concat message-signature-directory "/"))))) (message-kill-signature) (save-excursion (message-insert-signature 0)))) (keymap-set message-mode-map "C-c C-w" 'my-message-insert-signature)) ;;; mailcap (eval-after-load 'mailcap (mailcap-parse-mailcaps)) ;;; gnus search (set 'gnus-search-default-engines '((nnimap . gnus-search-imap) (nnmaildir . gnus-search-find-grep) ;;(nnselect . gnus-search-nnselect) ;; (nnselect . gnus-search-find-grep) )) ;;;; functions (defun message-set-header (search-tag insert-line) "Set message SEARCH-TAG header line as this INSERT-LINE." (save-excursion (save-restriction (message-narrow-to-headers-or-head) (if (re-search-forward (concat "^" search-tag ":.*$") nil 't) (replace-match insert-line) (message-add-header insert-line))))) (defun gnus-style-entry-gcc (group style-entry) "Process STYLE-ENTRY given GROUP and to return its \\=gcc entry. Otherwise, nil." (let ((pred (car style-entry)) (gcc (cadr (assq 'gcc style-entry)))) (cond ((stringp pred) (cond ((null group) nil) ((string-match pred group) gcc) ((equal pred group) gcc) ('t nil))) ((and (functionp pred) (apply pred '())) gcc) ((eq pred 't) gcc)))) (defun gnus-get-default-gcc (styles) "Get the gcc entry from STYLES corresponding to `gnus-newsgroup-name'." (let ((res (gnus-style-entry-gcc gnus-newsgroup-name (car styles)))) (cond ((null styles) nil) (res (eval res)) ('t (gnus-get-default-gcc (cdr styles)))))) (defun message-set-all-of-my-headers (my-address &optional cipher-it) "Set all of my message header's fields." (let ((name (cadr (my-email-info my-address))) (gcc (cond (cipher-it "crypto-sent") ((equal my-address user-mail-address) (gnus-get-default-gcc (reverse gnus-posting-styles))) ('t (caddr (my-email-info my-address)))))) ;; set From header (message-set-header "From" (concat "From: " name " <" my-address ">")) ;; set proper Gcc header (when (message-fetch-field "Gcc") (message-set-header "Gcc" (concat "Gcc: " gcc))) ;; set/unset OpenPGP header (message-set-openpgp-header my-address) ;; set/unset GDPR header (message-set-gdpr-header my-address))) (defun message-set-my-mml-and-headers (&optional my-address) "Set message headers and default mml cryptography." (let* ((address (or my-address (message-get-from-address))) (may-sign (mml-may-sign-p address))) (cond ((and (mml-secure-is-encrypted-p) may-sign) (message-set-all-of-my-headers address 't)) (may-sign (progn (mml-secure-message-sign) (message-set-all-of-my-headers address))) ('t (progn (mml-unsecure-message) (message-set-all-of-my-headers address)))))) (add-hook 'message-setup-hook 'message-set-my-mml-and-headers) ;;; needs the below hook to properly place the mml secure tag in gnus (add-hook 'gnus-message-setup-hook 'message-set-my-mml-and-headers) (defun message-get-from-address () "Get current From email address from the email compose buffer." (let ((from (mail-fetch-field "from"))) (string-match "\\([A-z0-9_.+-]+@[A-z0-9_.+-]+\\)" from) (match-string 1 from))) (defun message-loop-email (&optional email-config-list nth-pos) "Email loop and set through all of the EMAIL-CONFIG-LIST items." (interactive) (or email-config-list (set 'email-config-list (mapcar 'car my-email-addresses))) (or nth-pos (set 'nth-pos 0)) (let ((current-address (message-get-from-address)) (next-address (nth (1+ nth-pos) email-config-list))) (cond ((length= (cdr email-config-list) nth-pos) (message-set-my-mml-and-headers (car email-config-list))) ((equal current-address (nth nth-pos email-config-list)) (message-set-my-mml-and-headers next-address)) ('t (message-loop-email email-config-list (1+ nth-pos)))))) (with-eval-after-load 'message (keymap-set message-mode-map "" 'message-loop-email) (keymap-set message-mode-map "" (lambda () (interactive) (message-loop-email (mapcar 'car my-mobile-email-addresses))))) (defun message-to-public-p (my-address) "Says if I am sending an email message to the public (mailinglist or netnews)." (cond ((message-news-p) 't) ((member my-address my-public-addresses) 't) ('t nil))) (defun sending-email () (let ((from-address (message-get-from-address))) (cond ((equal from-address user-mail-address-tilde) (smtp-tilde-club)) ((member from-address (mapcar #'car my-mobile-email-addresses)) (smtp-native)) ('t (smtp-msmtp))))) (add-hook 'message-send-hook 'sending-email) ;;; mml-attach-file goes to the end of the message (set 'mml-attach-file-at-the-end 't) ;;; gnus pgp (set 'mml-secure-openpgp-signers nil) ;; we want to be able to read the emails we wrote. (set 'mml-secure-openpgp-encrypt-to-self 't) ;; mml choose correct key for signing/ciphering (set 'mml-secure-openpgp-sign-with-sender 't) ;; always verify signatures (set 'mm-verify-option 'always) ;; show result of pgp verification (set 'gnus-buttonized-mime-types '("multipart/signed" "multipart/encrypted" "application/pgp-keys")) (set 'mm-discouraged-alternatives '("image/.*")) (set 'gnus-message-replysign 't) (set 'gnus-message-replyencrypt 't) (set 'gnus-message-replysignencrypted 't) (keymap-global-set "C-c ESC k" 'epa-list-keys) ;;; enable epa-mail-mode (add-hook 'message-setup-hook 'epa-mail-mode) (defun pgp-keyid (email-address) "Get PGP keyid (short format without \"0x\") of EMAIL-ADDRESS. Return NIL if there is no keyid for EMAIL-ADDRESS." (let ((keyid (string-trim-right (shell-command-to-string (concat "keyid " email-address))))) (cond ((string-empty-p keyid) nil) ('t keyid)))) (defun mml-may-sign-p (my-address) "Say if message can be signed, according to MY-ADDRESS." (cond ;; ((message-to-public-p my-address) nil) ((pgp-keyid my-address) 't) ('t nil))) (defun mml-secure-tag-p () "Say whether the <#secure tag is present anywhere in the buffer." (save-excursion (goto-char (point-min)) (message-goto-body) (re-search-forward "<#secure .*>$" nil 't))) ;;; openpgp header (defun message-set-openpgp-header (my-address) "Set the openpgp message header." (mail-fetch-field "openpgp" nil nil nil 't) ;;; remove OpenPGP header (let* ((pgp-keyid (pgp-keyid my-address)) (pgp-keyurl (cond ((equal my-address user-mail-address-tilde) my-wkd-tilde-url) ('t (string-trim-right (shell-command-to-string (concat "gpg-wks-client --print-wkd-url " my-address)))))) (message-openpgp-header (list (concat "0x" pgp-keyid) pgp-keyurl "signencrypt"))) (when (mml-may-sign-p my-address) (save-excursion (message-add-openpgp-header))))) (defun my-mml-unsecure-message () "Remove MML tag from message." (interactive) (mml-unsecure-message) (message-set-all-of-my-headers (message-get-from-address)) (save-excursion (message-remove-header "OpenPGP"))) ;;; attempt to sign all non-news mails I'll be sending. (defun my-mml-secure-message-sign (&optional prefix) "Add MML signing tag to message." (interactive "p") (cond ((eql prefix 4) (mml-secure-message-sign-pgp)) ('t (mml-secure-message-sign-pgpmime))) (message-set-all-of-my-headers (message-get-from-address))) ;;; gnus pgp keybindings (defun my-mml-secure-message-sign-encrypt (&optional prefix) "Add MML sign and ciphering tag to message." (interactive "p") (cond ((eql prefix 4) (mml-secure-message-encrypt-pgp)) ('t (mml-secure-message-encrypt-pgpmime))) (message-set-all-of-my-headers (message-get-from-address) 't)) (with-eval-after-load 'message (keymap-set mml-mode-map "C-c RET C-n" 'my-mml-unsecure-message) (keymap-set mml-mode-map "C-c RET C-s" 'my-mml-secure-message-sign) (keymap-set mml-mode-map "C-c RET C-e" 'my-mml-secure-message-sign-encrypt)) ;;; GDPR notice (with-eval-after-load 'message (defun message-insert-or-toggle-gdpr-header (&optional values) "Insert a \"X-GDPR: pt\" header, or cycle through this header values." (interactive nil message-mode) (or values (set 'values '("pt" "en" _))) (save-excursion (let ((cur (message-fetch-field "X-GDPR"))) (cond ((null cur) ;;; if it is the first try (message-add-header (concat "X-GDPR: " (car values)))) ((equal '_ (cadr values)) (message-remove-header "X-GDPR")) ((equal (car values) cur) (progn (message-remove-header "X-GDPR") (message-add-header (concat "X-GDPR: " (cadr values))))) ('t (message-insert-or-toggle-gdpr-header (cdr values))))))) (keymap-set message-mode-map "C-c C-f C-g" 'message-insert-or-toggle-gdpr-header)) (defun message-set-gdpr-header (my-address) "Initial set of GDPR header. Set the specific situations when GDPR notice is disabled or enabled." (save-excursion (save-restriction (message-remove-header "X-GDPR") (let ((lang (message-fetch-field "Content-Language"))) (cond ((or (message-to-public-p my-address) (mml-secure-is-encrypted-p)) '()) (lang (message-add-header (concat "X-GDPR: " lang))) ('t (message-add-header "X-GDPR: pt"))))))) (defun message-insert-gdpr-notice () "Insert GDPR notice." (let ((gdpr-field (message-fetch-field "X-GDPR"))) (when gdpr-field (save-excursion (goto-char (point-max)) (when (re-search-backward message-signature-separator nil 't) (forward-line -1) (move-end-of-line nil)) (when (not (current-line-empty-p)) (newline)) (newline) (newline) (insert-file-contents (expand-file-name (concat "~/.gdpr/" gdpr-field ".txt"))) (message-remove-header "X-GDPR"))))) ;;;; cannot be message-send-mail-hook . It is too late. (add-hook 'message-send-hook 'message-insert-gdpr-notice -90) ;;; language set-up (defun message-set-language (lang) "Set language specific headers and message signature, according to LANG." (message-set-header "Content-Language" (concat "Content-Language: " lang)) (unless (or (message-to-public-p user-mail-address) (mml-secure-is-encrypted-p)) (message-set-header "X-GDPR" (concat "X-GDPR: " lang))) (my-message-insert-signature (concat message-signature-directory "/" lang "-einstein.txt"))) (with-eval-after-load 'message (defun message-choose-language () "Choose a language for a Content-Language header." (interactive nil message-mode) (message-set-language (cadr (read-multiple-choice "Language" '((?p "pt" "Português") (?e "en" "English")))))) (keymap-set message-mode-map "C-c C-f C-l" 'message-choose-language)) ;;; gnus activate yubikey on sending (defun yubikey-pin () (interactive) (call-process (expand-file-name "~/.local/bin/gpg-pass-ask") nil nil nil)) (defalias 'y 'yubikey-pin) ;;;; cannot be message-send-mail-hook (add-hook 'message-send-hook 'yubikey-pin) ;;; gnus mail other people certificate PEM certificates (set 'smime-certificate-directory (expand-file-name "~/.certs/mail")) ;;; gnus rss (set 'nnrss-directory (expand-file-name "~/.emacs.d/gnus/rss")) ;;; gnus in M-x mail (set 'mail-user-agent 'gnus-user-agent) ;;; read mail in Gnus (set 'read-mail-command 'gnus) ;; ;;; gnus atom feeds ;; (require 'mm-url) ;; (defadvice mm-url-insert (after DE-convert-atom-to-rss () ) ;; "Converts atom to RSS by calling xsltproc." ;; (when (re-search-forward "xmlns=\"http://www.w3.org/.*/Atom\"" ;; nil 't) ;; (goto-char (point-min)) ;; (message "Converting Atom to RSS... ") ;; (call-process-region (point-min) (point-max) ;; "xsltproc" ;; 't 't nil ;; (expand-file-name "~/.emacs.d/gnus/atom2rss.xsl") ;; "-") ;; (goto-char (point-min)) ;; (message "Converting Atom to RSS... done"))) ;; ;; (ad-activate 'mm-url-insert) ;; ;; (defun mm-url-insert--DE-convert-atom-to-rss () ;; "Converts atom to RSS by calling xsltproc." ;; (when (re-search-forward "xmlns=\"http://www.w3.org/.*/Atom\"" ;; nil 't) ;; (goto-char (point-min)) ;; (message "Converting Atom to RSS... ") ;; (call-process-region (point-min) (point-max) ;; "xsltproc" ;; 't 't nil ;; (expand-file-name "~/.emacs.d/gnus/atom2rss.xsl") "-") ;; (goto-char (point-min)) ;; (message "Converting Atom to RSS... done"))) ;; ;; (advice-add 'mm-url-insert :after #'mm-url-insert--DE-convert-atom-to-rss) ;;; gnus shortcut (defun my-gnus () "My way of opening Gnus." (interactive) (tab-bar-new-tab-to 1) (tab-rename "gnus") (gnus)) (keymap-global-set "C-x g e" 'my-gnus) ;; gpg pinentry (require 'pinentry) ;;; setup the more secure loopback with pinentry (set 'epg-pinentry-mode 'loopback) (when (and (not (bound-and-true-p pinentry--server-process)) (equal (getenv "GPG_TTY") "/dev/tty1")) (pinentry-start)) (with-eval-after-load 'pinentry (defun pinentry-restart () (interactive) (shell-command "gpg-reload") (pinentry-stop) (pinentry-start))) (defalias 'pr 'pinentry-restart) (keymap-global-set "C-x g r" 'pinentry-restart) ;; get mail function (defun fetch-mail () (interactive) (eval-expression ;; the below line is a fix of (shell-command-to-string command) (with-output-to-string (with-current-buffer standard-output ;; (async-shell-command "mpop") (async-shell-command "fdm fetch")) )) (switch-to-buffer-other-window "*Async Shell Command*")) (keymap-global-set "C-x g f" 'fetch-mail) ;; tramp ;; (customize-set-variable 'tramp-default-method "ssh") (set 'ido-work-directory-list-ignore-regexps '("/ssh:" "/-:")) ;; footnotes (autoload 'footnote-mode "footnote" nil 't) (set 'footnote-section-tag "") (set 'footnote-spaced-footnotes nil) (require 'footnote) (add-hook 'message-mode-hook 'footnote-mode) (set 'footnote-index-starting-number 0) (with-eval-after-load 'footnote (defun footnote--insert-footnote (arg) "Insert a footnote numbered ARG, at (point)." (push-mark) (let ((ptr (footnote--insert-numbered-footnote arg 't))) (footnote--goto-char-point-max) (if (footnote--goto-first) (save-restriction (when footnote-narrow-to-footnotes-when-editing (footnote--narrow-to-footnotes)) (footnote-goto-footnote (1- arg)) ; evil, FIXME (less evil now) ;; (message "Inserting footnote %d" arg) (or (eq arg footnote-index-starting-number) (when (re-search-forward (if footnote-spaced-footnotes "\n\n" (concat "\n" (footnote--current-regexp))) nil 't) (beginning-of-line) 't) (footnote--goto-char-point-max) (footnote--goto-first))) (unless (looking-at "^$") (newline)) (when (eobp) (newline)) (unless (equal footnote-section-tag "") (insert footnote-section-tag "\n"))) (let ((text (footnote--insert-numbered-footnote arg nil))) (footnote--insert-markers arg text ptr)))) (defun footnote--make-hole () "Make room in the alist for a new footnote at point. Return the footnote number to use." (save-excursion (let (rc) (dolist (alist-elem footnote--markers-alist) (when (<= (point) (caddr alist-elem)) (unless rc (set 'rc (car alist-elem))) (save-excursion (message "Renumbering from %s to %s" (footnote--index-to-string (car alist-elem)) (footnote--index-to-string (1+ (car alist-elem)))) (footnote--renumber (1+ (car alist-elem)) alist-elem)))) (or rc (1+ (or (caar (last footnote--markers-alist)) (1- footnote-index-starting-number))))))) (defun footnote-renumber-footnotes () "Renumber footnotes, starting from `footnote-index-starting-number'." (interactive "*") (save-excursion (let ((i footnote-index-starting-number)) (dolist (alist-elem footnote--markers-alist) (footnote--renumber i alist-elem) (set 'i (1+ i))))))) ;; ebdb (require 'ebdb-gnus) (require 'ebdb-message) (set 'ebdb-record-self "36b79c52-1bbf-432a-9c80-c84e056fbcd1") ;; managesieve (autoload 'sieve-mode "sieve-mode") (set 'auto-mode-alist (cons '("\\.s\\(v\\|iv\\|ieve\\)\\'" . sieve-mode) auto-mode-alist)) ;; erc (set 'erc-user-full-name user-full-name) (set 'erc-session-client-certificate 't) (set 'erc-track-enable-keybindings nil) (set 'erc-track-exclude-server-buffer 't) (set 'erc-hide-list '("PART" "QUIT")) ;; hide irc part and quit messages (join allowed) (set 'erc-kill-buffer-on-part 't) ;;; erc modules (set 'erc-modules '(log autoaway netsplit fill button match track completion readonly networks ring noncommands irccontrols move-to-prompt stamp menu list)) ;;; prevent bot functions from displaying text of ignored nicks ;; (defun erc-bot-messages-ignore (string) ;; (when ;; (and ;; (or ;; (string-match ;; "^<[][:alnum:]`|^_{}[-]+> \\[Sed\\] <\\([][:alnum:]`|^_{}[-]+\\)> .*" ;; string) ;; (string-match ;; "^<[][:alnum:]`|^_{}[-]+> \\[Karma\\] .+ now has [0-9]+ karma ([0-9]+ from \\([][:alnum:]`|^_{}[-]+\\))" ;; string) ;; (string-match ;; "^<[][:alnum:]`|^_{}[-]+> \\([][:alnum:]`|^_{}[-]+\\): <[][:alnum:]`|^_{}[-]+> .*" ;; string)) ;; (member (match-string 1 string) erc-ignore-list)) ;; (set 'erc-insert-this nil))) ;; (add-hook 'erc-insert-pre-hook 'erc-bot-messages-ignore) ;;; erc auto-away (set 'erc-auto-set-away 't) (set 'erc-autoaway-use-emacs-idle 't) (set 'erc-auto-discard-away 't) (set 'erc-autoaway-idle-seconds 210) (set 'erc-autoaway-message "...") ;;; erc logging (set 'erc-log-channels-directory (expand-file-name "~/log")) ;;; erc custom function ;;;; voice and devoice nick(s) (defun erc-cmd-VOICE (&rest people) "Add the voice mode to users(s) given in PEOPLE." (when (> (length people) 0) (erc-server-send (concat "MODE " (erc-default-target) " +" (make-string (length people) ?v) " " (mapconcat #'identity people " "))) 't)) (defun erc-cmd-DEVOICE (&rest people) "Remove the voice setting from user(s) given in PEOPLE." (when (> (length people) 0) (erc-server-send (concat "MODE " (erc-default-target) " -" (make-string (length people) ?v) " " (mapconcat #'identity people " "))) 't)) ;;;; query nick (defun erc-query-channel-nick (nick) "Query a nick of the current channel." (interactive (list (completing-read "Nick: " erc-channel-users))) (erc-cmd-QUERY nick)) (with-eval-after-load 'erc (keymap-set erc-mode-map "C-c q" 'erc-query-channel-nick)) ;;;; always send a final point at the end (defun erc-insert-final-point (input-struct) (let* ((input-string (cl-struct-slot-value 'erc-input 'string input-struct)) (last-char (string-to-char (substring input-string -1))) (first-char (string-to-char (substring input-string 0 1)))) (cond ((or (eq last-char ?.) (eq last-char ?!) (eq last-char ??) (eq last-char ?,) (eq last-char ?\;) (eq last-char ?:) (eq first-char ?,) (eq first-char ?/) (string-match "^s/" input-string)) 't) ((string-match " $" input-string) (setf (cl-struct-slot-value 'erc-input 'string input-struct) (substring input-string 0 -2))) ((or ;; smiley (string-match "[:;%8>xX]\\{1\\}[`',]?-?[)(/\\ZzXxDPpSsbO]\\{1,4\\}$" input-string) ;; URLs (string-match "\\(?:http\\|ftp\\|file\\|gopher\\|gemini\\)s?://.+?[^ )]+$" input-string) ;; other (eq last-char ?^)) (setf (cl-struct-slot-value 'erc-input 'string input-struct) (concat input-string " ."))) ('t (setf (cl-struct-slot-value 'erc-input 'string input-struct) (concat input-string ".")))))) (add-hook 'erc-pre-send-functions 'erc-insert-final-point) ;;;; fix the double correction issue (defun my-erc-send-current-line () "Parse current line and send it to IRC." (interactive) (let ((now (current-time))) (if (or (not erc-accidental-paste-threshold-seconds) (time-less-p erc-accidental-paste-threshold-seconds (time-subtract now erc-last-input-time))) (save-restriction ;; If there's an abbrev at the end of the line, expand it. ;; (when (and abbrev-mode ;; (eolp)) ;; (expand-abbrev)) (widen) (let* ((str (erc-user-input)) (state (erc--make-input-split str))) (run-hook-with-args 'erc--input-review-functions state) (when-let (((not (erc--input-split-abortp state))) (inhibit-read-only t) (erc--current-line-input-split state) (old-buf (current-buffer))) (progn ; unprogn this during next major surgery (erc-set-active-buffer (current-buffer)) ;; Kill the input and the prompt (delete-region erc-input-marker (erc-end-of-input-line)) (unwind-protect (erc--send-input-lines (erc--run-send-hooks state)) ;; Fix the buffer if the command didn't kill it (when (buffer-live-p old-buf) (with-current-buffer old-buf (save-restriction (widen) (let ((buffer-modified (buffer-modified-p))) (set-buffer-modified-p buffer-modified)))))) ;; Only when last hook has been run... (run-hook-with-args 'erc-send-completed-hook str))) (set 'erc-last-input-time now))) (switch-to-buffer "*ERC Accidental Paste Overflow*") (lwarn 'erc :warning "You seem to have accidentally pasted some text!")))) (with-eval-after-load 'erc (keymap-set erc-mode-map "RET" 'my-erc-send-current-line)) ;;; other erc functions (load "my-common-system") ;; (load "my-quack-system") (load "my-erc-coins-system") (load "my-weri") (defun erc-rejoin-channel () "Rejoin current IRC channel." (interactive) (erc-join-channel (erc-channel-name (buffer-name)) nil)) (with-eval-after-load 'erc (keymap-set erc-mode-map "C-c j" 'erc-rejoin-channel)) ;; jabber (require 'jabber) ;;; disable roster keybindings menu (set 'jabber-roster-show-bindings nil) ;;; make fsm output debug buffer disappear (set 'fsm-debug nil) ;; (add-to-list 'load-path (expand-file-name "~/me/programming/desktop/emacs-jabber/lisp/")) ;; (add-to-list 'load-path (expand-file-name "~/me/programming/desktop/emacs-jabber/")) ;; (load (expand-file-name "~/me/programming/desktop/emacs-jabber/jabber-autoloads")) ;;; upload files (M-x jabber-httpupload-send-file) (require 'jabber-httpupload) (with-eval-after-load 'jabber-muc (keymap-set jabber-chat-mode-map "C-c C-n" 'jabber-muc-names) (keymap-set jabber-chat-mode-map "C-c C-t" 'jabber-muc-set-topic) (keymap-set jabber-chat-mode-map "C-c C-p" 'jabber-muc-leave) (keymap-set jabber-chat-mode-map "C-c q" 'jabber-muc-private)) (with-eval-after-load 'jabber-httpupload (keymap-set jabber-chat-mode-map "C-c a" 'jabber-httpupload-send-file)) ;; (unless (package-installed-p 'jabber) ;; (require 'package-vc) ;; (add-to-list 'package-vc-selected-packages ;; '(jabber ;; :url "https://codeberg.org/emacs-jabber/emacs-jabber" ;; :branch "production" ;; :lisp-dir "lisp" ;; :doc "README.org")) ;; ;; Change the path below to the location of your local jabber.el repository. ;; (package-vc-install-from-checkout (expand-file-name "~/me/programming/desktop/emacs-jabber/") "jabber")) (defun my-jabber () "My way of opening jabber.el." (interactive) (tab-bar-new-tab-to 2) (tab-rename "xmpp") (jabber-connect-all) (run-with-timer 5 0 (lambda () (jabber-switch-to-roster-buffer) (my-split-window-below) (jabber-activity-switch-to) (windmove-up)))) (keymap-global-set "C-x g j" 'my-jabber) ;; emms (require 'emms-info-exiftool) ;; metadata (emms-all) (set 'emms-player-list '(emms-player-vlc emms-player-alsaplayer)) ;; need pacman -S perl-image-exiftool below (set 'emms-info-functions '(emms-info-exiftool emms-info-metaflac emms-info-native)) (set 'emms-source-file-default-directory (expand-file-name "~/me/files/audio/music")) ;;; amixer (set 'emms-volume-change-amount 1) (set 'emms-volume-amixer-card 2) (set 'emms-volume-amixer-control "PCM Soft") ;;; pulseaudio volume changer ;; (set 'emms-volume-change-function 'emms-volume-pulse-change) (defun pulseaudio-sinks () (let ((output (shell-command-to-string "pactl list short sinks")) (last-match-index 0) (result nil)) (while (set 'last-match-index (and (string-match "^\\([0-9]+\\)" output last-match-index) (1+ (string-match "^\\([0-9]+\\)" output last-match-index)))) (push (string-to-number (match-string 1 output)) result)) (reverse result))) ;;; my offline music playing (defun my-play-music (dir message) "Play my music." (interactive) (emms-play-m3u-playlist (expand-file-name dir)) (emms-playlist-sort-by-random) (emms-playlist-sort-by-random) (emms-random) (emms-playlist-sort-by-random) (message message)) (defun emms-insert-show () "Insert playing music into buffer." (interactive) (insert (emms-show))) (defun fresh () "Play my new music." (interactive) (my-play-music "~/me/files/audio/playlist/new.m3u" "Fresh out...")) (defun chill () "Play my Chillhop music." (interactive) (my-play-music "~/me/files/audio/playlist/chillhop.m3u" "Sit back and Chill...")) (defun classical () "Play my Classical music." (interactive) (my-play-music "~/me/files/audio/playlist/classical.m3u" "Enjoy the art...")) (defun radio () "Play my radio playlist." (interactive) (emms-play-m3u-playlist "~/me/files/audio/playlist/radio.m3u") (message "Radio on air...")) (defun emms-restart () "Restart playing." (interactive) (emms-stop) (set-buffer " *EMMS Playlist*") (emms-playlist-mode-play-current-track)) ;;;; twitch playing (defun mando () "Play last magic_mandofox stream as audio." (interactive) (async-shell-command "yt-dlp -f Audio_Only -o - $(yt-dlp --max-downloads 1 -s https://www.twitch.tv/magic_mandofox/videos?filter=default | grep \"https://www.twitch.tv/videos/\" | awk '{print $4}') | cvlc - >/dev/null" "*mandofox*")) (defun twitch-list-channel-urls (channel &optional number) "List last video URLs of twitch CHANNEL." (interactive (list (read-string "Channel name: ") (read-number "Maximum number of last URLs: " 5))) (async-shell-command (concat "yt-dlp " (when number (concat "--max-downloads " (string-to-number number) " ")) "-s https://www.twitch.tv/" channel "/videos?filter=default | " "grep \"https://www.twitch.tv/videos/\" | " "awk '{print $4}'") "*twitch-channel-urls*")) (defun twitch-play-url (url) (interactive "MTwitch channel URL: ") (async-shell-command "yt-dlp -f Audio_Only -o - " url " | cvlc - >/dev/null") "*twitch-play*") ;;; volume mode timeout (set 'emms-volume-mode-timeout 6) ;;; emms keybindings (keymap-global-set "C-x p +" 'emms-volume-mode-plus) (keymap-global-set "C-x p -" 'emms-volume-mode-minus) (keymap-global-set "C-x p " 'chill) (keymap-global-set "C-x p " 'emms-stop) (keymap-global-set "C-x p " 'emms-next) (keymap-global-set "C-x p " 'emms-previous) (keymap-global-set "C-x p SPC" 'emms-pause) (keymap-global-set "C-x p RET" 'emms-restart) (keymap-global-set "C-x p r" 'emms-random) (keymap-global-set "C-x p t" 'emms-toggle-random-playlist) (keymap-global-set "C-x p ." 'emms-show) (keymap-global-set "C-x p i" 'emms-insert-show) ;;; set audio output ;;;; set pulseaudio's output (defun speakers-set-pulse (number) "Set audio speakers with a sink NUMBER." (interactive "NSink number: ") (shell-command (concat "pactl set-default-sink " (number-to-string number))) (set 'emms-volume-pulse-sink number)) (defun mic-mute-pulse () "Mute default mic." (interactive) (shell-command (concat "pactl set-source-mute " (string-trim-right (shell-command-to-string "pactl get-default-source")) " 1")) (message "Mic muted.")) (defun mic-unmute-pulse () "Unmute default mic." (interactive) (shell-command (concat "pactl set-source-mute " (string-trim-right (shell-command-to-string "pactl get-default-source")) " 0")) (message "Mic unmuted.")) ;;;; set amixer's output (defun speakers-toggle-alsa () "Toggle ALSA output card." (interactive) (cond ((file-exists-p "~/.asoundrc") (progn (shell-command "rm -f ~/.asoundrc") (set 'emms-volume-amixer-card 2) (set 'emms-volume-amixer-control "PCM Soft") (message "Sound in speakers."))) ('t (progn (shell-command "ln ~/.asoundrc-headphones ~/.asoundrc") (set 'emms-volume-amixer-card 0) (set 'emms-volume-amixer-control "Master") (message "Sound in headphones."))))) (defun mic-mute-alsa () "Mute default mic." (interactive) (shell-command (concat "amixer -c " (number-to-string emms-volume-amixer-card) " set " emms-volume-amixer-control " mute")) (message "Mic muted.")) (defun mic-unmute-alsa () "Unmute default mic." (interactive) (shell-command (concat "amixer -c " (number-to-string emms-volume-amixer-card) " set " emms-volume-amixer-control " unmute")) (message "Mic unmuted.")) ;;;; set preferred audio keybindings (keymap-global-set "C-x g s" 'speakers-toggle-alsa) (keymap-global-set "C-x g m" 'mic-mute-alsa) (keymap-global-set "C-x g u" 'mic-unmute-alsa) ;; calendar (defun my-calendar-exit () (interactive) (calendar-exit 't)) (keymap-set calendar-mode-map "q" 'my-calendar-exit) ;;; holidays ;;;; disable following holidays (set 'holiday-hebrew-holidays nil) (set 'holiday-islamic-holidays nil) (set 'holiday-bahai-holidays nil) (set 'holiday-oriental-holidays nil) ;;;; disable some (set 'holiday-general-holidays '((holiday-fixed 1 1 "New Year's Day") (holiday-fixed 2 14 "Valentine's Day") (holiday-fixed 3 17 "St. Patrick's Day") (holiday-fixed 4 1 "April Fools' Day"))) ;;;; portugal holidays (national and religious) (set 'holiday-portugal-holidays '((holiday-easter-etc -47 "Carnaval") (holiday-fixed 3 19 "Dia do Pai") (holiday-easter-etc -2 "Sexta-feira Santa") (holiday-fixed 4 25 "Dia da Liberdade") (holiday-fixed 5 1 "Dia do Trabalhador") (holiday-float 5 0 1 "Dia da Mãe") (holiday-easter-etc 60 "Corpo de Deus") (holiday-fixed 6 10 "Dia de Portugal") (holiday-fixed 8 15 "Assunção de Nossa Senhora") (holiday-fixed 10 5 "Implantação da República") (holiday-fixed 11 1 "Todos os Santos") (holiday-fixed 12 1 "Restauração da Independência") (holiday-fixed 12 8 "Imaculada Conceição"))) ;;;; fun days (set 'holiday-fun-days '((holiday-fixed 2 7 "Dia de Enviar um Postal a um/a Amigo/a") (holiday-float 2 1 2 "Dia de Limpar o teu Computador") (holiday-fixed 2 22 "Dia de Single Tasking") (holiday-fixed 3 1 "Dia Mundial do Elogio") (holiday-fixed 3 3 "Dia de Eu Quero que Sejas Feliz") (holiday-fixed 3 14 "Dia do PI") (holiday-fixed 3 19 "Dia de Vamos Rir") (holiday-fixed 3 25 "Dia do Waffle") (holiday-fixed 4 23 "Dia do/a Amante") (holiday-fixed 5 6 "Dia da Bebida") (holiday-fixed 5 9 "Dia da Europa") (holiday-fixed 5 28 "Dia da Hamburga") (holiday-fixed 6 4 "Dia de Abraçar o Teu Gato/a") (holiday-fixed 6 17 "Dia de Comer os Teus Vegetais") (holiday-fixed 7 12 "Dia da Simplicidade") (holiday-float 7 0 3 "Dia do Gelado") (holiday-fixed 7 24 "Dia do/a Primo/a") (holiday-fixed 7 26 "Dia do/a Tia/o") (holiday-fixed 7 29 "Dia da Lasanha") (holiday-float 8 5 1 "Dia Internacional da Cerveja") (holiday-float 8 0 1 "Dia da Irmã") (holiday-fixed 8 9 "Dia do/a Amante de Livros") (holiday-fixed 8 11 "Dia do/a Filho/a") (holiday-fixed 8 15 "Dia do Relaxamento") (holiday-fixed 9 5 "Dia da Pizza de Queijo") (holiday-fixed 9 6 "Dia de Ler um Livro") (holiday-float 10 1 3 "Dia Nacional de Limpar o Desktop Virtual") (holiday-fixed 10 27 "Dia da Cerveja Americana") (holiday-fixed 10 29 "Dia da Internet") (holiday-fixed 11 1 "Dia do/a Autor(a)") (holiday-float 11 4 1 "Dia de Homens Fazem o Jantar") (holiday-fixed 11 21 "Dia Mundial do Olá") (holiday-fixed 11 29 "Dia do Cartão Eletrónico") (holiday-fixed 12 9 "Dia do Cartão de Natal") (holiday-fixed 12 20 "Dia da Sangria"))) ;;;; United Nations days (set 'holiday-un-days '((holiday-fixed 1 24 "International Day of Education") (holiday-fixed 3 5 "International Day for Disarmament and Non-Proliferation Awareness") (holiday-fixed 3 20 "International Day of Happiness") (holiday-fixed 3 30 "International Day of Zero Waste") (holiday-fixed 4 5 "International Day of Conscience") (holiday-fixed 4 23 "World Book and Copyright Day") (holiday-fixed 5 5 "World Portuguese Language Day") (holiday-fixed 5 16 "International Day of Living Together in Peace") (holiday-fixed 5 21 "International Tea Day") (holiday-fixed 5 31 "World No-Tobacco Day") (holiday-fixed 6 21 "International Day of Yoga") (holiday-fixed 7 30 "International Day of Friendship") (holiday-fixed 9 15 "International Day of Democracy") (holiday-fixed 9 21 "International Day of Peace") (holiday-fixed 9 28 "International Day for Universal Access to Information") (holiday-fixed 10 2 "International Day of Non-Violence") (holiday-fixed 10 10 "World Mental Health Day") (holiday-fixed 10 16 "World Food Day") (holiday-fixed 12 10 "Human Rights Day") (holiday-fixed 12 12 "International Day of Neutrality"))) (set 'holiday-other-holidays (append holiday-portugal-holidays holiday-un-days holiday-fun-days)) (set 'calendar-mark-holidays-flag 't) ;; enable holidays in calendar (set 'calendar-date-style 'european) ;; diary (set 'calendar-mark-diary-entries-flag 't) ;; enable diary in calendar (set 'diary-comment-start ";") ;; set comments for diary files ;;; enable include facility in diary files (add-hook 'diary-list-entries-hook 'diary-include-other-diary-files) (add-hook 'diary-mark-entries-hook 'diary-mark-included-diary-files) ;;; cal function (defun cal () (interactive) (calendar) (kill-buffer "diary")) (keymap-global-set "C-x c" 'cal) (defun today () (interactive) (shell-command "date")) (keymap-global-set "C-x M-t" 'today) ;; remember (set 'remember-notes-initial-major-mode 'text-mode) ;; po (require 'po-mode) ;;; autofill untranslated with msgid (set 'po-auto-edit-with-msgid 't) ;;; po file preprocessing (defun po-update-this-file () (interactive) (shell-command "po-update") nil) (add-hook 'po-mode-hook 'po-update-this-file) (with-eval-after-load 'po-mode (defun po-replace-project-id-version () "Update the Project-Id-Version in the PO file header." (save-excursion (goto-char (point-min)) (if (re-search-forward "^\"Project-Id-Version:.*" nil 't) (let* ((buffer-read-only po-read-only)) (replace-match (concat "\"Project-Id-Version: " (shell-command-to-string "version") "\\n\"") 't 't)))) ;; Return nil to indicate that the buffer has not yet been saved. nil) (add-hook 'po-mode-hook 'po-replace-project-id-version)) ;;; substitution (defun subst-string (data-var) (mapc (lambda (list-pair) (goto-char (point-min)) ;; (replace-string (car list-pair) (cdr list-pair)) (search-forward (car list-pair)) (replace-match (cdr list-pair))) data-var) (goto-char (point-max))) (defun subst-bing () (interactive) (subst-string subst-data-bing)) (set 'subst-data-bing '(("senha" . "frase-secreta") ("frase secreta" . "frase-secreta") ("frases secretas" . "frases-secretas") ("SSH" . "ssh") ("o cache" . "a cache") ("um cache" . "uma cache") ("não alfa" . "não alfabéticos") ("mouse" . "rato") ("soquete" . "socket") ("agente GPG" . "gpg-agent") ("agente gpg" . "gpg-agent") ("escutando" . "ouvindo") ("o diretório" . "a pasta") ("diretório" . "pasta") ("diretoria" . "pasta") ("manipulador" . "handler") ("arquivo" . "ficheiro") ("do usuário" . "de utilizador") ("usuário" . "utilizador") ("placas" . "cartões") ("placa" . "cartão") ("cadeia de caracteres" . "string") ("criptografia" . "cifragem") ("cifragem" . "cifração") ("encripta" . "cifra") ("desencripta" . "decifra") ("administrador" . "Admin") ("modo de lote" . "modo batch") ("excluí" . "apaga") ("exclui" . "apaga") ("somente" . "só") ("(s/n)" . "(s/N)") ("e-mail" . "email") ("e armadura" . "a blindagem") ("armadura" . "blindagem") ("compactaç" . "compress") ("propriedade" . "ownership") ("listagens de assinatura" . "listagens de assinaturas") ("autoassina" . "auto-assina") ("tecla" . "chave") ("conjunto de chaves" . "porta-chaves") ("chaveiro" . "porta-chaves") ("agente" . "agent") ("mescla" . "fundi") ("detect" . "detet") ("insir" . "introduz") ("digite" . "introduza") ("cartão inteligente" . "smartcard") ("Você realmente quer" . "De certeza que você deseja") ("Você realmente" . "De certeza que você") ("você realmente quer" . "de certeza que você deseja") ("você realmente" . "de certeza que você") ("um banco de dados" . "uma base de dados") ("o banco de dados" . "a base de dados") ("Realmente" . "De certeza que deseja") ("primária" . "principal") ("primário" . "principal") ("o ID" . "a ID") ("um ID" . "uma ID") ("um documento de identificação com foto" . "uma ID fotográfica") ("o documento de identificação com foto" . "a ID fotográfica") ("portanto" . "por isso") ("resumo" . "digest") ("descriptograf" . "decifr") ("preterid" . "depreciad") ("acessar" . "aceder") ("essa" . "esta") ("esse" . "este") ("Observação:" . "Nota:") ("cadeia" . "corrente") ("assunto" . "entidade") ("gravar" . "escrever") ("registr" . "regist") ("carimbo de data/hora" . "timestamp") ("expressão S" . "S-expression") ("banco" . "base") ("sinalizador" . "flag") ("solicitação" . "pedido") ("ruim" . "inválido") ("incorret" . "inválid") ("incorrect" . "inválid") ("geral" . "genérico") ("decodificação" . "descodificação"))) (defun po-mark-whole-subedit-buffer () (interactive) (goto-char (point-min)) (push-mark (1- (point-max)) nil 't)) ;;; po send email (set 'po-default-commit-message "po: Update Portuguese Translation.") (defun po-git-commit (msg) "My function to git commit before sending a patch." (shell-command "rm 0001-*.patch") (shell-command (concat "git add " (file-name-nondirectory buffer-file-name))) (shell-command (concat "git commit " (when (yes-or-no-p "Amend commit? ") "--amend ") (when (yes-or-no-p "Signoff commit? ") "-s ") "-m \"" msg "\"")) (shell-command "git format-patch -k HEAD~1")) (defun po-send-address () (let ((gnupg "GnuPG , Werner Koch ")) (cond ((or (string-search "/gnupg/gnupg/" default-directory) (string-search "/gnupg/1-libgpg-error/" default-directory)) gnupg) ('t (po-guess-team-address))))) (defun my-po-send-mail () "My function to start composing a letter, and send git PO patch file." (interactive) (shell-command (concat "po-prod " (file-name-nondirectory buffer-file-name))) (let ((string-msg (read-string "Commit message: " po-default-commit-message)) (user-mail-address user-mail-address-translator)) (po-git-commit string-msg) (compose-mail-other-window (po-send-address) string-msg nil) (message-set-openpgp-header user-mail-address)) (message-goto-body) (newline) (newline) (mml-attach-file (shell-command-to-string "printf ${PWD}/0001-*.patch") "text/x-patch" (concat (shell-command-to-string "printf $(version | awk 'NF{NF-=1};1')") " patch.")) (message-goto-body) (open-line 2) (my-mml-secure-message-sign) (message "You may start writing the email...")) (with-eval-after-load 'po-mode (keymap-set po-subedit-mode-map "C-x h" 'po-mark-whole-subedit-buffer) (keymap-set po-subedit-mode-map "" 'subst-bing) (keymap-set po-subedit-mode-map "C-c s" nil) (keymap-set po-subedit-mode-map "C-c s i" 'ispell-message) (keymap-set po-mode-map "M" 'my-po-send-mail)) ;; go-translate (require 'go-translate) (set 'gt-langs '(pt en)) (set 'gt-preset-translators `((normal . ,(gt-translator :taker (gt-taker :text 'word :pick 'paragraph :prompt nil) :engines (gt-bing-engine) :render (gt-buffer-render))) (po . ,(gt-translator :taker (gt-taker :text 'word :pick 'paragraph :prompt nil) :engines (gt-bing-engine) :render (gt-insert-render :type 'replace :then (lambda (&rest rest) (run-with-timer 0.5 0 'subst-bing))))))) (keymap-global-set "C-c t" 'gt-do-translate) (keymap-global-set "C-c T" 'gt-do-setup) ;;; automatically translate only untranslated entries (with-eval-after-load 'po-mode (defun po-translate () (po-mark-whole-subedit-buffer) (gt-do-translate nil)) (defun my-po-edit-msgstr (&optional no-translation) "Use another window to edit the current msgstr." (interactive "p") (po-find-span-of-entry) (defvar current-po-entry-type po-entry-type) ;; added this line (defvar current-po-translate-p (eq 1 no-translation)) ;; added this line (po-edit-string (if (and po-auto-edit-with-msgid (eq po-entry-type 'untranslated)) (po-get-msgid) (po-get-msgstr-form)) 'msgstr 't)) (keymap-set po-mode-map "C-m" 'my-po-edit-msgstr) (defun po-translate-untranslated () (when (and current-po-translate-p (eq current-po-entry-type 'untranslated)) (po-translate))) (add-hook 'po-subedit-mode-hook 'po-translate-untranslated)) ;; emerge (set 'emerge-combine-versions-template "%a%b") ;; expand-region (keymap-global-set "C-c C-SPC" 'er/expand-region) (keymap-global-set "C-c DEL" 'er/contract-region) ;; dictd (set 'dictionary-server "localhost") (keymap-global-set "C-c d" 'dictionary-search) ;; captain (with-eval-after-load 'captain (defun captain--default-predicate () "The default predicate for determining whether the captain should work." 't)) ;; (defun auto-capitalization-total () ;; (defvar captain-predicate (lambda () 't))) ;; (add-hook 'erc-mode-hook 'auto-capitalization-total) ;; (add-hook 'jabber-chat-mode-hook 'auto-capitalization-total) ;; (add-hook 'message-mode-hook 'auto-capitalization-total) (add-hook 'erc-mode-hook 'captain-mode) (add-hook 'jabber-chat-mode-hook 'captain-mode) (add-hook 'message-mode-hook 'captain-mode) (defun fancy-mode () "Set all the fancy modes on a buffer." (interactive) (auto-fill-mode) (abbrev-mode) (captain-mode) (defvar captain-predicate (lambda () 't))) ;; battery (defun battery () "Get the percentage of battery charge." (interactive) (message "%d" (/ (* (string-to-number (shell-command-to-string "cat /sys/class/power_supply/BAT1/charge_now")) 100) (string-to-number (shell-command-to-string "cat /sys/class/power_supply/BAT1/charge_full"))))) ;; profanity (load "profanity") ;; other keybindings (keymap-global-set "C-x t t" 'tab-bar-mode) (keymap-global-set "C-x 7" 'flop-frame) (keymap-global-set "C-x 8" 'flip-frame) (keymap-global-set "C-x 9" 'transpose-frame) (keymap-global-set "C-x M-s" 'scratch-buffer) ;; other aliases (defalias 'u 'uncomment-region) (defalias 'sh 'shell) ;; EXWM (require 'exwm) ;;; Set the initial workspace number. (set 'exwm-workspace-number 4) ;;; Make class name the buffer name. (add-hook 'exwm-update-class-hook (lambda () (exwm-workspace-rename-buffer exwm-class-name))) ;;; my exwm functions (defun my-exwm-input--fake-key (event &optional buffer) "Fake a key event equivalent to Emacs event EVENT at the current buffer. Optionally choose a buffer." (let* ((keysyms (xcb:keysyms:event->keysyms exwm--connection event)) (target-buffer (or buffer (window-buffer (selected-window)))) keycode id) (when (= 0 (caar keysyms)) (user-error "[EXWM] Invalid key: %s" (single-key-description event))) (set 'keycode (xcb:keysyms:keysym->keycode exwm--connection (caar keysyms))) (when (/= 0 keycode) (set 'id (exwm--buffer->id target-buffer)) (exwm--log "id=#x%x event=%s keycode" id event keycode) (dolist (class '(xcb:KeyPress xcb:KeyRelease)) (xcb:+request exwm--connection (make-instance 'xcb:SendEvent :propagate 0 :destination id :event-mask xcb:EventMask:NoEvent :event (xcb:marshal (make-instance class :detail keycode :time xcb:Time:CurrentTime :root exwm--root :event id :child 0 :root-x 0 :root-y 0 :event-x 0 :event-y 0 :state (cdar keysyms) :same-screen 1) exwm--connection))))) (xcb:flush exwm--connection))) (defun exwm-send-shortcut (buffer key-event) "Activate shortcut to window." (let ((window (get-buffer buffer))) (when window (set-buffer window) ;; (run-with-timer 0.3 ;; 0 ;; `(lambda () ;; (my-exwm-input--fake-key ,key-event ,window))) (my-exwm-input--fake-key key-event window) ;; (run-with-timer 0.5 0 `(lambda () (pop-to-buffer ,cur))) ))) ;;; ;;; NOTE: use (read-event) or (read-key) ;;; (defun teams-toggle-mute () "Toggle mute in micro$oft teams." (interactive) (exwm-send-shortcut "firefox" 33554445)) (keymap-global-set "C-x g t" 'teams-toggle-mute) (defun teams-toggle-hand () "Toggle mute in micro$oft teams." (interactive) (exwm-send-shortcut "firefox" 33554443)) (keymap-global-set "C-x g h" 'teams-toggle-hand) (defun obs-stream-stop () "Stop stream in OBS Studio." (interactive) (exwm-send-shortcut "obs" 8388729) (message "OBS streaming stopped!")) (defun obs-record-stop () "Stop record in OBS Studio." (interactive) (exwm-send-shortcut "obs" 8388712) (message "OBS recording stopped!")) (defun obs-stream-start () "Start stream in OBS Studio." (interactive) (exwm-send-shortcut "obs" 8388725)) (defun obs-record-start () "Start record in OBS Studio." (interactive) (exwm-send-shortcut "obs" 8388714)) ;; Global keybindings. (set 'exwm-input-global-keys `(([?\s-y] . obs-stream-stop) ([?\s-h] . obs-record-stop) ([?\s-u] . obs-stream-start) ([?\s-j] . obs-record-start) ([?\s-r] . exwm-reset) ;; Reset (to line-mode). ([?\s-w] . exwm-workspace-swap) ;; Swap workspace. ([?\s-m] . exwm-workspace-move-window) ;; Move window. ([?\s-&] . (lambda (cmd) ;; Launch application. (interactive (list (read-shell-command "$ "))) (start-process-shell-command cmd nil cmd))) ;; s-Number: Switch to certain workspace. ,@(mapcar (lambda (i) `(,(kbd (format "s-%d" i)) . (lambda () (interactive) (exwm-workspace-switch-create ,i)))) (number-sequence 0 9)) ([?\s-s] . (lambda () (interactive) (shell-command "screenshot-save /tmp/screenshot.png") (let ((file (read-file-name "Save PNG as: " "~/Downloads/"))) (if (string-empty-p file) (message "/tmp/screenshot.png saved.") (shell-command (concat "mv /tmp/screenshot.png " file)) (message (concat file " saved.")))))) ([?\s-i] . (lambda () (interactive) (let ((cmd "icecat")) (start-process-shell-command cmd nil cmd)))) ([?\s-f] . (lambda () (interactive) (let ((cmd "firefox")) (start-process-shell-command cmd nil cmd)))) ([?\s-p] . (lambda () (interactive) (let* ((tmpdir (expand-file-name "~/.config/plugin-Autenticacao.Gov/tmp")) (cmd (concat "java -jar -Djava.io.tmpdir=" tmpdir " ~/me/programming/desktop/gov-apps/plugin-autenticacao/plugin-autenticacao-gov.jar")) (procname "autenticacao-gov-plugin")) (shell-command (concat "rm -f " tmpdir "/*")) (start-process-shell-command procname nil cmd)))) ([?\s-a] . (lambda () (interactive) (let ((cmd "env QT_QPA_PLATFORMTHEME=gtk3 eidguiV2") (procname "autenticacao-gov")) (start-process-shell-command procname nil cmd)))) ([?\s-o] . (lambda () (interactive) (let ((cmd "libreoffice") (procname "libreoffice")) (start-process-shell-command procname nil cmd)))) ([?\s-t] . (lambda () (interactive) (let ((cmd "obs") (procname "obs")) (start-process-shell-command procname nil cmd)))))) ;; key shortcuts (add-hook 'exwm-manage-finish-hook (lambda () (cond ((and exwm-class-name (or (equal exwm-class-name "icecat") (equal exwm-class-name "iceweasel") (equal exwm-class-name "firefox"))) (exwm-input-set-local-simulation-keys '(([?\C-b] . [left]) ([?\C-f] . [right]) ([?\C-p] . [up]) ([?\C-n] . [down]) ([?\C-a] . [home]) ([?\C-e] . [end]) ([?\M-v] . [prior]) ([?\C-v] . [next]) ([?\C-d] . [delete]) ([?\M-b] . [M-left]) ([?\M-f] . [M-right]) ([?\C-k] . [C-w]) ([?\M-w] . [C-c]) ([?\C-w] . [C-x]) ([?\C-y] . [C-v]) ([?\C-s] . [C-f])))) ('t (exwm-input-set-local-simulation-keys nil))))) ;;; Enable EXWM ;;(exwm-enable) ;; disable the too much stuff for graphical enviroment (tool-bar-mode -1) (menu-bar-no-scroll-bar) (menu-bar-mode -1) (tab-bar-mode (if (getenv "DISPLAY") -1 nil)) (and (fboundp 'fringe-mode) (fringe-mode '(0 . 0))) ;; other X stuff (defun x-refresh () (interactive) (shell-command "xrefresh; keyboard-x-activate") (message "X refreshed.")) (keymap-global-set "C-x x x" 'x-refresh) ;; abacus training (defun abacus-exercise (dir-str msg) (interactive) (switch-to-buffer "*Messages*") (cd dir-str) (load (concat dir-str "my.el")) (message msg) (when buffer-read-only (text-scale-increase 5)) (setq-local buffer-read-only nil) (erase-buffer)) (keymap-global-set "C-x 0" (lambda () (interactive) (abacus-exercise "~/abacus/current/0-reading/" "Reading exercise..."))) (keymap-global-set "C-x 1" (lambda () (interactive) (abacus-exercise "~/abacus/current/1-writing/" "Writing exercise..."))) (keymap-global-set "C-x 2" (lambda () (interactive) (abacus-exercise "~/abacus/current/2-yama/" "Yama exercise..."))) ;; always enable some disable commands (with M-x enable-command) (put 'list-timers 'disabled nil) ;; final message (message "GNU Emacs configuration loaded.") ;;; end of emacs configuration (custom-set-variables ;; custom-set-variables was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(package-selected-packages '(0x0 captain clhs dictionary ebdb elpher emms expand-region exwm fsm go-translate jabber languagetool ledger-mode magit markdown-mode mediawiki paredit pinentry plz rainbow-delimiters srv transpose-frame))) (custom-set-faces ;; custom-set-faces was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(erc-fool-face ((t (:strike-through t :slant italic)))) '(magit-blame-dimmed ((t (:inherit magit-dimmed)))) '(magit-diff-added ((t (:extend t :background "#335533" :foreground "black")))) '(magit-diff-added-highlight ((t (:extend t :background "#336633" :foreground "black")))) '(magit-diff-base ((t (:extend t :background "#555522" :foreground "black")))) '(magit-diff-base-highlight ((t (:extend t :background "#666622" :foreground "black")))) '(magit-diff-removed ((t (:extend t :background "#553333" :foreground "black")))) '(magit-diff-removed-highlight ((t (:extend t :background "#663333" :foreground "black")))) '(magit-dimmed ((t (:slant italic)))) '(magit-hash ((t (:slant italic)))) '(magit-reflog-checkout ((t (:background "white" :foreground "blue")))))