From 77c344c9f18408fd4b84c126c82ccf1707289c71 Mon Sep 17 00:00:00 2001 From: fpi Date: Wed, 29 Jan 2020 17:53:34 +0100 Subject: A fresh emacs config --- init-exwm.org | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 init-exwm.org (limited to 'init-exwm.org') diff --git a/init-exwm.org b/init-exwm.org new file mode 100644 index 0000000..792dcbe --- /dev/null +++ b/init-exwm.org @@ -0,0 +1,412 @@ +#+PROPERTY: header-args:emacs-lisp :results silent +,#+PROPERTY: header-args:emacs-lisp :tangle tangle/init-exwm.el + +When stating the client from .xinitrc, `save-buffer-kill-terminal' will +force-kill Emacs before it can run through `kill-emacs-hook'. +#+BEGIN_SRC emacs-lisp +(global-set-key (kbd "C-x C-c") 'save-buffers-kill-emacs) +#+END_SRC + + + +set keyboard +#+BEGIN_SRC emacs-lisp +(shell-command "setxkbmap -layout \"de(neo),us,ru,de\"") +#+END_SRC +* functions +#+BEGIN_SRC emacs-lisp +(defun ambrevar/switch-to-last-buffer () + "Switch to last open buffer in current window." + (interactive) + (switch-to-buffer (other-buffer (current-buffer) 1))) + +(defun ambrevar/toggle-window-dedicated () + "Toggle whether the current active window is dedicated or not. +Run it in each window you want to 'freeze', i.e. prevent Emacs +from acting on it." + (interactive) + (message + (if (let ((window (get-buffer-window (current-buffer)))) + (set-window-dedicated-p window + (not (window-dedicated-p window)))) + "Window '%s' is dedicated" + "Window '%s' is normal") + (current-buffer))) + +(defun ambrevar/toggle-window-split () + "Switch between vertical and horizontal split. +It only works for frames with exactly two windows." + (interactive) + (if (= (count-windows) 2) + (let* ((this-win-buffer (window-buffer)) + (next-win-buffer (window-buffer (next-window))) + (this-win-edges (window-edges (selected-window))) + (next-win-edges (window-edges (next-window))) + (this-win-2nd (not (and (<= (car this-win-edges) + (car next-win-edges)) + (<= (cadr this-win-edges) + (cadr next-win-edges))))) + (splitter + (if (= (car this-win-edges) + (car (window-edges (next-window)))) + 'split-window-horizontally + 'split-window-vertically))) + (delete-other-windows) + (let ((first-win (selected-window))) + (funcall splitter) + (if this-win-2nd (other-window 1)) + (set-window-buffer (selected-window) this-win-buffer) + (set-window-buffer (next-window) next-win-buffer) + (select-window first-win) + (if this-win-2nd (other-window 1)))))) + +(defun ambrevar/toggle-single-window () + "Un-maximize current window. +If multiple windows are active, save window configuration and +delete other windows. If only one window is active and a window +configuration was previously save, restore that configuration." + (interactive) + (if (= (count-windows) 1) + (when single-window--last-configuration + (set-window-configuration single-window--last-configuration)) + (setq single-window--last-configuration (current-window-configuration)) + (delete-other-windows))) +#+END_SRC +** Window swapping +#+BEGIN_SRC emacs-lisp +(defun ambrevar/swap-windows (&optional w1 w2) + "If 2 windows are up, swap them. +Else if W1 is a window, swap it with current window. +If W2 is a window too, swap both." + (interactive) + (unless (or (= 2 (count-windows)) + (windowp w1) + (windowp w2)) + (error "Ambiguous window selection")) + (let* ((w1 (or w1 (car (window-list)))) + (w2 (or w2 + (if (eq w1 (car (window-list))) + (nth 1 (window-list)) + (car (window-list))))) + (b1 (window-buffer w1)) + (b2 (window-buffer w2)) + (s1 (window-start w1)) + (s2 (window-start w2))) + (with-temp-buffer + ;; Some buffers like EXWM buffers can only be in one live buffer at once. + ;; Switch to a dummy buffer in w2 so that we don't display any buffer twice. + (set-window-buffer w2 (current-buffer)) + (set-window-buffer w1 b2) + (set-window-buffer w2 b1)) + (set-window-start w1 s2) + (set-window-start w2 s1)) + (select-window w1)) + +(defun ambrevar/swap-windows-left () + "Swap current window with the window to the left." + (interactive) + (ambrevar/swap-windows (window-in-direction 'left))) +(defun ambrevar/swap-windows-below () + "Swap current window with the window below." + (interactive) + (ambrevar/swap-windows (window-in-direction 'below))) +(defun ambrevar/swap-windows-above () + "Swap current window with the window above." + (interactive) + (ambrevar/swap-windows (window-in-direction 'above))) +(defun ambrevar/swap-windows-right () + "Swap current window with the window to the right." + (interactive) + (ambrevar/swap-windows (window-in-direction 'right))) +#+END_SRC +** Volume & Brightness +#+BEGIN_SRC emacs-lisp +(defun exwm-brightness (incdec) + (shell-command (concat "xbacklight " incdec "10")) + (notifications-notify :title (substring (shell-command-to-string "xbacklight") 0 -1) + :replaces-id 6969 + :urgency 'low + :timeout 550)) + +(defun exwm-volume (incdec) + (notifications-notify + :title (format + "Volume %s" + (substring + (shell-command-to-string + (format "amixer -D pulse set Master 5%%%s|tail -n 1|cut -d '[' -f 2|cut -d ']' -f 1" + incdec)) 0 -1)) + :replaces-id 6968 + :urgency 'low + :timeout 550)) +(defun exwm-togglemute () + (interactive) + (notifications-notify + :title (format + "Volume %s" + (substring + (shell-command-to-string + "amixer -D pulse set Master toggle|tail -n 1|cut -d '[' -f 3|cut -d ']' -f 1") 0 -1)) + :replaces-id 6968 + :urgency 'low + :timeout 550)) +#+END_SRC +** XF86 Multimedia keys +#+BEGIN_SRC emacs-lisp +(defun exwm-xf86audio (cmd) + ;; Control Spotify + (shell-command (concat "dbus-send --type=method_call --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player." cmd))) +#+END_SRC +** Browser switching +#+BEGIN_SRC emacs-lisp +(defun fpi/helm-exwm-switch (class &optional program other-window) + "Switch to some EXWM windows belonging to CLASS. +If current window is not showing CLASS, switch to the last open CLASS window. +If there is none, start PROGRAM. + +If PROGRAM is nil, it defaults to CLASS. +With prefix argument or if OTHER-WINDOW is non-nil, open in other window." + ;; If current window is not in `exwm-mode' we switch to it. Therefore we must + ;; also make sure that current window is not a Helm buffer, otherwise calling + ;; this function will lose focus in Helm. + (unless helm-alive-p + (setq program (or program class) + other-window (or other-window current-prefix-arg)) + (let ((filter (lambda () + (member (downcase (or exwm-class-name "")) class)))) + (if (and (eq major-mode 'exwm-mode) + (funcall filter)) + (let ((helm-buffer-details-flag nil)) + (helm-exwm filter)) + (let ((last (buffer-list))) + (while (and last + (not (with-current-buffer (car last) + (and (eq major-mode 'exwm-mode) + (funcall filter))))) + (setq last (cdr last))) + (if last + (funcall (if other-window 'switch-to-buffer-other-window 'switch-to-buffer) (car last)) + (when other-window (select-window (split-window-sensibly))) + (start-process-shell-command program nil program))))))) + +(defun fpi/helm-exwm-switch-browser () + "Switch to some `browse-url-generic-program' windows. + +See `helm-exwm-switch'." + (interactive) + (fpi/helm-exwm-switch (quote ("qutebrowser" + "firefox")) + browse-url-generic-program)) +#+END_SRC +* config +Time & Battery display +#+BEGIN_SRC emacs-lisp +(display-time) +(display-battery-mode) +#+END_SRC +Rename buffer to window title.\\ +Spotify's title does not include "spotify" while playing music so just +append it. +#+BEGIN_SRC emacs-lisp +(defun fpie/exwm-rename-buffer-to-title () + (let ((newname (if (string-match "Spotify" (buffer-name)) + (concat exwm-title " - Spotify") + exwm-title))) + (exwm-workspace-rename-buffer newname))) + +(add-hook 'exwm-update-title-hook 'fpie/exwm-rename-buffer-to-title) +#+END_SRC +#+BEGIN_SRC emacs-lisp +(add-hook 'exwm-floating-setup-hook 'exwm-layout-hide-mode-line) +(add-hook 'exwm-floating-exit-hook 'exwm-layout-show-mode-line) +#+END_SRC + +Non-floating resizing with mouse +#+BEGIN_SRC emacs-lisp +(setq window-divider-default-bottom-width 2 + window-divider-default-right-width 2) +(window-divider-mode) +#+END_SRC +System tray +#+BEGIN_SRC emacs-lisp +(require 'exwm-systemtray) +(exwm-systemtray-enable) +(setq exwm-systemtray-height 16) +#+END_SRC ++auto focus+ +#+BEGIN_SRC emacs-lisp :tangle no +(setq mouse-autoselect-window t + focus-follows-mouse t) +#+END_SRC +List all buffers +#+BEGIN_SRC emacs-lisp +(setq exwm-workspace-show-all-buffers t) +(setq exwm-layout-show-all-buffers t) +#+END_SRC +** Helm +#+BEGIN_SRC emacs-lisp :results silent +(with-eval-after-load 'helm + ;; Need `with-eval-after-load' here since 'helm-map is not defined in 'helm-config. + (define-key helm-map (kbd "s-\\") 'helm-toggle-resplit-and-swap-windows) + (exwm-input--set-key (kbd "s-p") 'helm-run-external-command) + (exwm-input-set-key (kbd "s-c") 'helm-resume) + (exwm-input-set-key (kbd "s-b") 'helm-mini) + (exwm-input-set-key (kbd "s-f") 'helm-find-files) + (exwm-input-set-key (kbd "s-F") 'helm-locate) + ;;(when (fboundp 'ambrevar/helm-locate-meta) + ;; (exwm-input-set-key (kbd "s-F") #'ambrevar/helm-locate-meta)) + ;;(exwm-input-set-key (kbd "s-g") 'ambrevar/helm-grep-git-or-ag) + ;;(exwm-input-set-key (kbd "s-G") 'ambrevar/helm-grep-git-all-or-ag) + ) + +(use-package helm-exwm) +(exwm-input-set-key (kbd "s-w") #'fpi/helm-exwm-switch-browser) +(exwm-input-set-key (kbd "s-W") #'helm-exwm-switch-browser-other-window) +#+END_SRC +** Keys +Global bindings +#+BEGIN_SRC emacs-lisp +(exwm-input-set-key (kbd "s-K") #'exwm-reset) +(exwm-input-set-key (kbd "s-x") #'exwm-input-toggle-keyboard) + +(exwm-input-set-key (kbd "s-s") #'windmove-left) +(exwm-input-set-key (kbd "s-n") #'windmove-down) +(exwm-input-set-key (kbd "s-r") #'windmove-up) +(exwm-input-set-key (kbd "s-t") #'windmove-right) + +(exwm-input-set-key (kbd "M-s") #'ace-jump-word-mode) +(exwm-input-set-key (kbd "s-B") #'ibuffer-list-buffers) +(exwm-input-set-key (kbd "s-X") #'kill-this-buffer) + +(exwm-input-set-key (kbd "s-M") #'exwm-workspace-switch) + +(exwm-input-set-key (kbd "s-\\") 'ambrevar/toggle-window-split) +(exwm-input-set-key (kbd "s-S") 'ambrevar/swap-windows-left) +(exwm-input-set-key (kbd "s-N") 'ambrevar/swap-windows-below) +(exwm-input-set-key (kbd "s-R") 'ambrevar/swap-windows-above) +(exwm-input-set-key (kbd "s-T") 'ambrevar/swap-windows-right) + +(exwm-input-set-key (kbd "s-") #'ambrevar/switch-to-last-buffer) +(exwm-input-set-key (kbd "s-") (lambda () + (interactive) + (start-process "term" nil "tilix"))) +(exwm-input-set-key (kbd "s-h") 'bury-buffer) + +(exwm-input-set-key (kbd "s-g") 'previous-buffer) +(exwm-input-set-key (kbd "s-G") 'next-buffer) +#+END_SRC +#+BEGIN_SRC emacs-lisp +(exwm-input-set-key (kbd "s-!") 'helm-pass) +#+END_SRC +Volume & Brightness +#+BEGIN_SRC emacs-lisp +(exwm-input-set-key [XF86AudioLowerVolume] (lambda () (interactive) (exwm-volume "-"))) +(exwm-input-set-key [XF86AudioRaiseVolume] (lambda () (interactive) (exwm-volume "+"))) +(exwm-input-set-key [XF86AudioMute] 'exwm-togglemute) +(exwm-input-set-key [XF86MonBrightnessUp] (lambda () (interactive) (exwm-brightness "+"))) +(exwm-input-set-key [XF86MonBrightnessDown] (lambda () (interactive) (exwm-brightness "-"))) +#+END_SRC +XF86 Multimedia Keys +#+BEGIN_SRC emacs-lisp +(exwm-input--set-key [XF86AudioPlay] (lambda () (interactive) (exwm-xf86audio "PlayPause"))) +(exwm-input--set-key [XF86AudioPause] (lambda () (interactive) (exwm-xf86audio "PlayPause"))) +(exwm-input--set-key [XF86AudioNext] (lambda () (interactive) (exwm-xf86audio "Next"))) +(exwm-input--set-key [XF86AudioPrev] (lambda () (interactive) (exwm-xf86audio "Previous"))) +#+END_SRC +*** Local bindings +#+BEGIN_SRC emacs-lisp +(push ?\s- exwm-input-prefix-keys) +(define-key exwm-mode-map (kbd "s-SPC") #'exwm-floating-toggle-floating) +(define-key exwm-mode-map (kbd "s-i") #'follow-delete-other-windows-and-split) ;; any useful? +(define-key exwm-mode-map (kbd "s-o") #'ambrevar/toggle-single-window) +(define-key exwm-mode-map (kbd "s-O") #'exwm-layout-toggle-fullscreen) + +(define-key exwm-mode-map (kbd "C-q") #'exwm-input-send-next-key) +#+END_SRC +Allow access to my personal keymap. +#+BEGIN_SRC emacs-lisp +(push ?\C-z exwm-input-prefix-keys) +#+END_SRC + +*** Simulation keys +#+BEGIN_SRC emacs-lisp +(setq exwm-input-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]))) + ;;([?\C-k] . [S-end delete]))) ; doesn't work in tilix +#+END_SRC +** Multiple monitors +#+BEGIN_SRC emacs-lisp +(require 'exwm-randr) +(setq exwm-randr-workspace-output-plist + '(0 "DP1" 1 "HDMI1" 2 "HDMI2" 3 "eDP1")) +(exwm-randr-enable) +#+END_SRC +** Configure helm-raise-command +~(shell-command "emacsclient -e ...")~ does not work. Advice +~helm-run-or-raise~ instead and overshadow ~shell-command~. + +For now ~helm-run-or-raise~ is redefined after helm is loaded in +~emacs-init.org~ instead of advised. +#+begin_src emacs-lisp +(defun fpi/get-proc-buffers (proc) + (let ((cand (helm-exwm-candidates))) + (remove + nil (mapcar + (lambda (c) + (if (equal + (downcase proc) + (downcase (with-current-buffer c (or exwm-class-name "")))) + c + nil)) cand)))) +(defun fpi/switch-to-proc-buffer (proc) + (switch-to-buffer (car (fpi/get-proc-buffers proc)))) + +;; (setq helm-raise-command "emacsclient -e '(fpi/switch-to-proc-buffer \"%s\")'") +(setq helm-raise-command t) +#+end_src +** Screenshots +UncleDave has a nice exwm configuration in his [[https://github.com/daedreth/UncleDavesEmacs/blob/master/config.org][config]]. These snippets +are taken from there. + +A nice alternative for screenshots in org-mode is ~org-screenshot.el~. +It uses ~scrot~ to take screenshots of windows and insert a link the +image into the current org buffer. + +*** Screenshotting the entire screen +#+BEGIN_SRC emacs-lisp + (defun daedreth/take-screenshot () + "Takes a fullscreen screenshot of the current workspace" + (interactive) + (when window-system + (loop for i downfrom 3 to 1 do + (progn + (message (concat (number-to-string i) "...")) + (sit-for 1))) + (message "Cheese!") + (sit-for 1) + (start-process "screenshot" nil "import" "-window" "root" + (concat (getenv "HOME") "/" (subseq (number-to-string (float-time)) 0 10) ".png")) + (message "Screenshot taken!"))) + (global-set-key (kbd "") 'daedreth/take-screenshot) +#+END_SRC + +*** Screenshotting a region +#+BEGIN_SRC emacs-lisp +(defun daedreth/take-screenshot-region () + "Takes a screenshot of a region selected by the user." + (interactive) + (when window-system + (call-process "import" nil nil nil ".newScreen.png") + (call-process "convert" nil nil nil ".newScreen.png" "-shave" "1x1" + (concat (getenv "HOME") "/" (subseq (number-to-string (float-time)) 0 10) ".png")) + (call-process "rm" nil nil nil ".newScreen.png"))) +;; (global-set-key (kbd "") 'daedreth/take-screenshot-region) +#+END_SRC -- cgit v1.2.3