This is my configuration file for Doom Emacs. It is a self contained document
with everything needed to set up Doom. Normally you customize Doom by editing
three .el files, which are config.el, packages.el and init.el. Thanks to
the literate config module, it is possible to have all three in the same org
document and they get automatically tangled in the right place upon saving this
file.
- Doom Emacs
- I use Doom Emacs as my configuration framework. I used to have a rather lengthy hand-rolled literate configuration file. In a lot of cases, I was reinventing the wheel by configuring stuff in a way that was similar to what Doom has to offer (or other configuration frameworks for that matter). So I just decided that I might as well use a configuration framework and have stuff work out of the box. I chose Doom because it enables excellent evil support across all the modules (so I don’t have to go through the pain of configuring everything to get a consistent evil experience). It’s also very fast, and has a very active community. I want to extend my thanks to Henrik Lissner who is the maintainer of the framework, as well as all contributors to the project.
- gcc emacs
-
I build Emacs from source and I am on the
native-compbranch. Native compilation helps me achieve better performances without headaches, and the branch is now stable enough to be used without running into issues. It’s most likely going to be included in the next release of Emacs (Emacs 28) and I would like to extend my thanks to Andrea Corallo who did a fantastic job on this feature, as well as all the contributors to this feature. - The Emacs community
- Thank you to all the community in making Emacs such great software. It is really hard to express how much Emacs has impacted me. I really like how Emacs behaves as a platform and I find it much more pleasant to use a computer through Emacs. Thank you to the maintainers across the years, to contributors, package developers and users as a whole that make this tool such a polyvalent swiss-army kitchen sink.
This is my doom block. What it contains is pretty self explanatory.
;;; init.el -*- lexical-binding: t; -*-
(doom! :input
;;chinese
;;japanese
:completion
company ; the ultimate code completion backend
;;(helm +fuzzy +icons +childframe) ; the *other* search engine for love and life
;;ido ; the other *other* search engine...
;;(ivy +icons +prescient) ; a search engine for love and life
:ui
deft ; notational velocity for Emacs
doom ; what makes DOOM look the way it does
doom-dashboard ; a nifty splash screen for Emacs
doom-quit ; DOOM quit-message prompts when you quit Emacs
;;fill-column ; a `fill-column' indicator
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
;;hydra
indent-guides ; highlighted indent columns
modeline ; snazzy, Atom-inspired modeline, plus API
nav-flash ; blink the current line after jumping
;;neotree ; a project drawer, like NERDTree for vim
ophints ; highlight the region an operation acts on
;;(popup +hacks) ; tame sudden yet inevitable temporary windows
;;ligatures ; ligatures or substitute text with pretty symbols
;;tabs ; an tab bar for Emacs
treemacs ; a project drawer, like neotree but cooler
;;unicode ; extended unicode support for various languages
;;vc-gutter ; vcs diff in the fringe
;;vi-tilde-fringe ; fringe tildes to mark beyond EOB
;;window-select ; visually switch windows
;;workspaces ; tab emulation, persistence & separate workspaces
;;zen ; distraction-free coding or writing
:editor
(evil +everywhere); come to the dark side, we have cookies
file-templates ; auto-snippets for empty files
;;fold ; (nigh) universal code folding
;;(format +onsave) ; automated prettiness
;;god ; run Emacs commands without modifier keys
;;lispy ; vim for lisp, for people who don't like vim
;;multiple-cursors ; editing in many places at once
;;objed ; text object editing for the innocent
;;parinfer ; turn lisp into python, sort of
;;rotate-text ; cycle region at point between text candidates
snippets ; my elves. They type so I don't have to
;;word-wrap ; soft wrapping with language-aware indent
:emacs
(dired +icons) ; making dired pretty [functional]
electric ; smarter, keyword-based electric-indent
ibuffer ; interactive buffer management
vc ; version-control and Emacs, sitting in a tree
:term
eshell ; a consistent, cross-platform shell (WIP)
;;shell ; a terminal REPL for Emacs
;;term ; terminals in Emacs
vterm ; another terminals in Emacs
:checkers
;syntax ; tasing you for every semicolon you forget
;;spell ; tasing you for misspelling mispelling
;;grammar ; tasing grammar mistake every you make
:tools
;;ansible
;;debugger ; FIXME stepping through code, to help you add bugs
;;direnv
;;docker
;;editorconfig ; let someone else argue about tabs vs spaces
;; ein ; tame Jupyter notebooks with emacs
(eval +overlay) ; run code, run (also, repls)
;;gist ; interacting with github gists
(lookup +docsets +dictionnary +offline) ; navigate your code and its documentation
(lsp +peek)
;;macos ; MacOS-specific commands
magit ; a git porcelain for Emacs
make ; run make tasks from Emacs
;;pass ; password manager for nerds
pdf ; pdf enhancements
;;prodigy ; FIXME managing external services & code builders
;;rgb ; creating color strings
;;terraform ; infrastructure as code
;;tmux ; an API for interacting with tmux
upload ; map local to remote projects via ssh/ftp
:lang
;;agda ; types of types of types of types...
;;assembly ; assembly for fun or debugging
cc ; C/C++/Obj-C madness
;clojure ; java with a lisp
;;common-lisp ; if you've seen one lisp, you've seen them all
;;coq ; proofs-as-programs
;;crystal ; ruby at the speed of c
;;csharp ; unity, .NET, and mono shenanigans
data ; config/data formats
;;(dart +flutter) ; paint ui and not much else
;;elixir ; erlang done right
;;elm ; care for a cup of TEA?
emacs-lisp ; drown in parentheses
;;erlang ; an elegant language for a more civilized age
;;ess ; emacs speaks statistics
;;faust ; dsp, but you get to keep your soul
;;fsharp ; ML stands for Microsoft's Language
;;fstar ; (dependent) types and (monadic) effects and Z3
;;go ; the hipster dialect
;;(haskell +dante) ; a language that's lazier than I am
;;hy ; readability of scheme w/ speed of python
;;idris ;
;;(java +meghanada) ; the poster child for carpal tunnel syndrome
;;javascript ; all(hope(abandon(ye(who(enter(here))))))
julia ; a better, faster MATLAB
;;kotlin ; a better, slicker Java(Script)
latex ; writing papers in Emacs has never been so fun
;;lean
;;factor
ledger ; an accounting system in Emacs
lua ; one-based indices? one-based indices
markdown ; writing docs for people to ignore
;;matlab
;;nim ; python + lisp at the speed of c
;;nix ; I hereby declare "nix geht mehr!"
;;ocaml ; an objective camel
(org +roam +noter +pretty +pomodoro) ; organize your plain life in plain text
;;perl ; write code no one else can comprehend
;;php ; perl's insecure younger brother
;;plantuml ; diagrams for confusing people more
;;purescript ; javascript, but functional
(python +lsp) ; beautiful is better than ugly
;;qt ; the 'cutest' gui framework ever
;;racket ; a DSL for DSLs
;;rest ; Emacs as a REST client
;;rst ; ReST in peace
;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
;;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
;;scala ; java, but good
;;scheme ; a fully conniving family of lisps
sh ; she sells {ba,z,fi}sh shells on the C xor
;;sml
;;solidity ; do you need a blockchain? No.
;;swift ; who asked for emoji variables?
;;terra ; Earth and Moon in alignment for performance.
;;web ; the tubes
:email
(mu4e +gmail)
;;notmuch
;;(wanderlust +gmail)
:app
;;calendar
;;irc ; how neckbeards socialize
(rss +org) ; emacs as an RSS reader
;;twitter ; twitter client https://twitter.com/vnought
:config
literate
(default +bindings +smartparens)
:personal
eaf
exwm
selectrum);; -*- no-byte-compile: t; -*-
(package! modus-themes)
(package! theme-magic)
(package! windower)
(package! solaire-mode :disable t)
(package! rg)
(package! zoom)
;; (package! org-mode
;; :recipe (:host github
;; :repo "yantar92/org"
;; :branch "feature/org-fold"
;; :files ("*.el" "lisp/*.el" "contrib/lisp/*.el")
;; :pre-build (with-temp-file (expand-file-name "org-version.el" (straight--repos-dir "org"))
;; (insert "(fset 'org-release (lambda () \"9.5\"))\n"
;; "(fset 'org-git-version #'ignore)\n"
;; "(provide 'org-version)\n")))
;; :shadow 'org)
(package! org-tree-slide)
(package! org-superstar)
(package! org-sidebar)
(package! org-emms)
(package! org-ref)
(package! ox-report)
(package! org-msg)
(package! emms)
(package! company-prescient)
(package! spotify
:recipe (:host github
:repo "danielfm/spotify.el"))
(package! centaur-tabs
:recipe (:host github
:repo "ema2159/centaur-tabs"))
(package! posframe)
(package! fast-scroll
:recipe (:host github
:repo "ahungry/fast-scroll"))
;(package! monkeytype)
(package! hercules)
(package! windresize)
(package! edwina)
(package! scroll-on-jump
:recipe (:host gitlab
:repo "ideasman42/emacs-scroll-on-jump"))
(package! good-scroll
:recipe (:host github
:repo "io12/good-scroll.el"))
(package! fish-completion
:recipe (:host gitlab
:repo "ambrevar/emacs-fish-completion"))
(package! olivetti)
(package! ytel)
;; (package! guix)
(package! pdf-continuous-scroll-mode
:recipe (:host github
:repo "dalanicolai/pdf-continuous-scroll-mode.el"))
(package! disk-usage)
(package! howdoyou)
(package! reddigg)
(package! ytdl)
(package! ytdl-show
:recipe (:host github
:repo "xFA25E/ytel-show"))
(package! ytdious)
(package! elpher)
(package! zotxt)
(package! smudge
:recipe (:host github
:repo "danielfm/smudge"))
(package! vterm)
(package! lispy)
(package! outshine)
(package! webkit
:recipe (:host github
:files (:defaults "*.js" "*.css" "*.so")
:repo "akirakyle/emacs-webkit"))
(package! bongo)
(package! volume)(setq doom-leader-alt-key "M-SPC")Emacs is a fantastic tool, that we can use to help manage our system in better ways. I use guix on Debian at the moment, but I plan on migrating most of the package management to guix once I get more comfortable using it.
(use-package! guix)(after! dired
(map! :map dired-mode-map
:n "h" #'dired-up-directory
:n "l" #'dired-find-file)
(add-hook 'dired-mode-hook #'dired-hide-details-mode))Add some support for EXWM buffers. I chose a random icon that looked nice, like the toggle-on icon.
(after! all-the-icons
(add-to-list 'all-the-icons-mode-icon-alist
'(exwm-mode all-the-icons-faicon "toggle-on" :height 1.0 :v-adjust -0.2
:face all-the-icons-green))
(add-to-list 'all-the-icons-icon-alist
'("\\.m$" all-the-icons-fileicon "matlab" :face all-the-icons-orange)))(fringe-mode -1)(after! doom-modeline
(setq doom-modeline-buffer-file-name-style 'auto)
(setq doom-modeline-height 21)
(setq doom-modeline-icon t)
(setq doom-modeline-major-mode-icon t)
(setq all-the-icons-scale-factor 1)
(setq display-time-format " %H:%M - %Y/%m/%d ")
;; redefing segment to show workspace even when tab-bar-mode is disabled
(doom-modeline-def-segment workspace-name
"The current workspace name or number.
Requires `eyebrowse-mode' or `tab-bar-mode' to be enabled."
(when doom-modeline-workspace-name
(when-let
((name (cond
((and (bound-and-true-p eyebrowse-mode)
(< 1 (length (eyebrowse--get 'window-configs))))
(assq-delete-all 'eyebrowse-mode mode-line-misc-info)
(when-let*
((num (eyebrowse--get 'current-slot))
(tag (nth 2 (assoc num (eyebrowse--get 'window-configs)))))
(if (< 0 (length tag)) tag (int-to-string num))))
(t
(let* ((current-tab (tab-bar--current-tab))
(tab-index (tab-bar--current-tab-index))
(explicit-name (alist-get 'explicit-name current-tab))
(tab-name (alist-get 'name current-tab)))
(if explicit-name tab-name (+ 1 tab-index)))))))
(propertize (format " %s " name) 'face
(if (doom-modeline--active)
'doom-modeline-buffer-major-mode
'mode-line-inactive)))))
(doom-modeline-def-modeline 'exwm
'(bar workspace-name window-number modals buffer-info)
'(objed-state misc-info persp-name battery grip irc mu4e gnus major-mode process vcs checker))
(defun doom-modeline-set-exwm-modeline ()
"Set exwm mode-line."
(doom-modeline-set-modeline 'exwm))
(add-hook 'exwm-mode-hook #'doom-modeline-set-exwm-modeline)
(display-time-mode -1))(use-package olivetti
:commands olivetti-mode
:config
(setq olivetti-body-width 0.7)
(setq olivetti-minimum-body-width 80))Tabs are a relatively new feature in emacs. They come in two different flavors,
tab-bar-mode and tab-line-mode. The first one is a great way to have
different window layouts (what people would usually call workspaces) and the
second is a way to display buffers that have been opened in a window (what
people actually expect from tabs).
The tab-bar, much like the tool bar or the menu bar, is related to the frame. The tab-line, much like the mode-line or header-line, is exclusive to the buffer.
(use-package! tab-bar
:init
(map! :nvi ;;"C-t" #'prot/tab-bar-select-tab-dwim
"s-M" #'lg/tab-previous-and-hide-maybe
"s-<" #'lg/tab-next-and-hide-maybe
"s-?" #'lg/tab-bar-mode-toggle
(:leader
:prefix ("t" . "toggle/tab")
:desc "new tab" "n" #'tab-new
:desc "delete tab" "d" #'tab-close
:desc "next tab" "j" #'tab-next
:desc "next tab" "k" #'tab-previous))
:config
(setq tab-bar-close-button-show nil)
(setq tab-bar-new-button "+")
(setq tab-bar-new-button-show nil)
(setq tab-bar-close-last-tab-choice 'tab-bar-mode-disable)
(setq tab-bar-close-tab-select 'recent)
(setq tab-bar-new-tab-choice t)
(setq tab-bar-new-tab-to 'right)
(setq tab-bar-position nil)
(setq tab-bar-show t)
(setq tab-bar-separator nil)
(setq tab-bar-tab-hints nil)
(setq tab-bar-tab-name-function 'tab-bar-tab-name-truncated)
(defun prot/tab-bar-select-tab-dwim ()
"Do-What-I-Mean function for getting to a `tab-bar-mode' tab.
If no other tab exists, create one and switch to it. If there is
one other tab (so two in total) switch to it without further
questions. Else use completion to select the tab to switch to."
(interactive)
(let ((tabs (mapcar (lambda (tab)
(alist-get 'name tab))
(tab-bar--tabs-recent))))
(cond ((eq tabs nil)
(tab-new))
((eq (length tabs) 1)
(tab-next))
(t
(call-interactively #'tab-bar-switch-to-tab)))))
;; auto-hide the bar, inspired by https://github.com/ema2159/centaur-tabs/issues/129
;; and adapted for the tab-bar
(defvar tab-bar-timer nil)
(defun tab-bar-timer-initialize ()
(setq tab-bar-timer (run-with-timer 3 nil (lambda () (tab-bar-mode -1)))))
(add-hook 'window-setup-hook 'tab-bar-timer-initialize)
(defun lg/tab-change-and-hide (arg)
"Change to next tab and hide"
(cancel-timer tab-bar-timer)
(if arg
(tab-next)
(tab-previous))
(tab-bar-mode +1)
(setq tab-bar-timer (run-with-timer 1 nil (lambda () (tab-bar-mode -1)))))
(defvar tab-bar-mode-force-display nil)
(defun lg/tab-bar-mode-toggle ()
"Toggle the tab bar and don't hide it with tab-change-and-hide"
(interactive)
(if tab-bar-mode
(progn
(tab-bar-mode -1)
(setq tab-bar-mode-force-display nil))
(tab-bar-mode +1)
(setq tab-bar-mode-force-display t)))
(defun lg/tab-next-and-hide-maybe ()
"Show tab-bar, switch to next tab and hide"
(interactive)
(if (not tab-bar-mode-force-display)
(lg/tab-change-and-hide t)
(tab-next)))
(defun lg/tab-previous-and-hide-maybe ()
"Show tab-bar, switch to next tab and hide"
(interactive)
(if (not tab-bar-mode-force-display)
(lg/tab-change-and-hide nil)
(tab-previous)))
(tab-bar-mode -1))Centaur-tabs is a useful package that builds on the built-in tab-line to provide nice looking tabs, as well as a grouping mechanism. Therefore you are only shown tabs from the same group (based on the major mode for instance, you can write you own grouping rules). As of writing this ([2021-03-27 Sat]) I have a pull request for a new tab button, that can adapt to the context to open new tabs. This effectively enables one to use centaur-tabs everywhere, and I do mean everywhere if you use EXWM, you can ditch the tabs for any application (terminal emulator, internet browser, file manager…) by using standalone X windows instead. This makes all “tabs” available for emacs through their respective buffer, in a unified and consistent way. Therefore you can use all of Emacs’ power : completion framework, filtering in iBuffer, group closing on tabs matching a specific pattern, etc.
(use-package! centaur-tabs
:init
(map! :n "gt" #'centaur-tabs-forward
:n "gT" #'centaur-tabs-backward
"s-m" #'centaur-tabs-backward
"s-," #'centaur-tabs-forward
"s-/" #'centaur-tabs-mode
:nvi "C-t" #'centaur-tabs--create-new-tab)
:hook
(calendar-mode . centaur-tabs-local-mode)
(dired-mode . centaur-tabs-local-mode)
(pdf-outline-buffer-mode . centaur-tabs-local-mode)
(exwm-floating-setup . centaur-tabs-local-mode)
(calc-mode . centaur-tabs-local-mode)
(calc-trail-mode . centaur-tabs-local-mode)
:config
(setq centaur-tabs-style "bar")
(setq centaur-tabs-set-modified-marker t)
(setq centaur-tabs-set-icons t)
(setq centaur-tabs-gray-out-icons t)
(setq centaur-tabs-set-bar 'under)
(setq centaur-tabs-show-navigation-buttons t)
(setq centaur-tabs-show-new-tab-button t)
(setq centaur-tabs-height 21)
(setq centaur-tabs-enable-ido-completion nil)
(setq centaur-tabs-cycle-scope 'tabs)
(setq centaur-tabs-plain-icons nil)
(setq centaur-tabs-label-fixed-length 15)
(setq uniquify-separator "/")
(centaur-tabs-mode +1)
(use-package lg-centaur-tabs
:load-path "~/.config/doom/lisp/"))(setq! doom-font (font-spec :family "Iosevka" :weight 'semi-light :size 15))
(setq! doom-variable-pitch-font (font-spec :family "DejaVu Sans Condensed" :size 15))
(set-face-attribute 'default nil :family "Iosevka" :weight 'normal :height 110)
(set-face-attribute 'fixed-pitch nil :family "Iosevka" :weight 'normal :height 110)
;(set-face-attribute 'variable-pitch nil :family "DejaVu Sans Condensed" :weight 'semi-light :height 110)
(set-face-attribute 'variable-pitch nil :family "Roboto Mono" :height 110 :width 'normal)end_src
I use the modus themes most of the times. I use the light version during the day and the dark version very late at night.
(use-package modus-themes
:config
(setq modus-themes-slanted-constructs t)
(setq modus-themes-bold-constructs nil)
(setq modus-themes-fringes 'subtle) ; {nil,'subtle,'intense})
;; Options for `modus-themes-lang-checkers': nil,
;; 'straight-underline, 'subtle-foreground,
;; 'subtle-foreground-straight-underline, 'intense-foreground,
;; 'intense-foreground-straight-underline, 'colored-background
(setq modus-themes-lang-checkers 'straight-underline)
;; Options for `modus-themes-mode-line': nil, '3d, 'moody,
;; 'borderless, 'borderless-3d, 'borderless-moody, 'accented,
;; 'accented-3d, 'accented-moody
(setq modus-themes-mode-line 'accented)
;; Options for `modus-themes-syntax': nil, 'faint,
;; 'yellow-comments, 'green-strings,
;; 'yellow-comments-green-strings, 'alt-syntax,
;; 'alt-syntax-yellow-comments, 'faint-yellow-comments
(setq modus-themes-syntax nil)
;; Options for `modus-themes-hl-line': nil, 'intense-background,
;; 'accented-background, 'underline-neutral,
;; 'underline-accented, 'underline-only-neutral,
;; 'underline-only-accented
(setq modus-themes-intense-hl-line 'accented-background)
(setq modus-themes-subtle-line-numbers nil)
(setq modus-themes-paren-match 'subtle-bold) ; {nil,'subtle-bold,'intense,'intense-bold}
;; Options for `modus-themes-links': nil, 'faint,
;; 'neutral-underline, 'faint-neutral-underline, 'no-underline,
;; 'underline-only, 'neutral-underline-only
(setq modus-themes-links 'neutral-underline)
;; Options for `modus-themes-prompts': nil, 'subtle-accented,
;; 'intense-accented, 'subtle-gray, 'intense-gray
(setq modus-themes-prompts 'intense-gray)
(setq modus-themes-completions 'moderate) ; {nil,'moderate,'opinionated})
;; Options for `modus-themes-region': nil, 'no-extend, 'bg-only,
;; 'bg-only-no-extend, 'accent, 'accent-no-extend
(setq modus-themes-region 'accent)
;; Options for `modus-themes-diffs': nil, 'desaturated,
;; 'fg-only, 'bg-only, 'deuteranopia,
(setq modus-themes-diffs 'deuteranopia) ;
(setq modus-themes-org-blocks 'rainbow) ; {nil,'greyscale,'rainbow}
(setq modus-themes-org-habit nil) ; {nil,'simplified,'traffic-light}
(setq modus-themes-headings '((t . highlight)))
(setq modus-themes-variable-pitch-ui nil)
(setq modus-themes-variable-pitch-headings t)
(setq modus-themes-scale-headings t)
(setq modus-themes-scale-1 1.1)
(setq modus-themes-scale-2 1.15)
(setq modus-themes-scale-3 1.21)
(setq modus-themes-scale-4 1.27)
(setq modus-themes-scale-5 1.33)
;(modus-themes-load-themes)
(load! "lisp/modus-theme-exporter.el"))
(defun lg/theme-propagate ()
"Apply system wide settings that are consistent with the
modus themes. A suitable gtk theme is applied, icon theme is
applied, Xresources are computed based on the
modus-themes-exporter package and the programs that use the
Xresources have the settings applied to them."
(interactive)
(pcase doom-theme
('doom-one
(shell-command "sed -i 's/ThemeName \"Adwaita\"/ThemeName \"Adwaita-dark\"/g' ~/.xsettingsd")
(shell-command "sed -i 's/IconThemeName \"Papirus-Light\"/IconThemeName \"Papirus-Dark\"/g' ~/.xsettingsd"))
('modus-vivendi
(shell-command "sed -i 's/ThemeName \"Adwaita\"/ThemeName \"Adwaita-dark\"/g' ~/.xsettingsd")
(shell-command "sed -i 's/IconThemeName \"Papirus-Light\"/IconThemeName \"Papirus-Dark\"/g' ~/.xsettingsd")
(modus-themes-exporter-export "xcolors" "~/.Xresources"))
('modus-operandi
(shell-command "sed -i 's/ThemeName \"Adwaita-dark\"/ThemeName \"Adwaita\"/g' ~/.xsettingsd")
(shell-command "sed -i 's/IconThemeName \"Papirus-Dark\"/IconThemeName \"Papirus-Light\"/g' ~/.xsettingsd")
(modus-themes-exporter-export "xcolors" "~/.Xresources")))
(shell-command "killall -HUP xsettingsd")
(shell-command "xrdb ~/.Xresources")
;(shell-command "~/spicetify-cli/spicetify apply")
(efs/start-panel))
(add-hook 'doom-load-theme-hook #'lg/theme-propagate)
(map!
:leader
(:prefix ("t" . "toggle")
:desc "modus-theme" "m" #'modus-themes-toggle))
;(setq doom-theme 'modus-vivendi)(setq frame-alpha-lower-limit 1)
(defvar lg/transparency-alpha 80
"Transparency of all frames.")
(defvar lg/transparency-default-increment 5
"Default {in, de}-crement value for the transparency alpha")
(defun lg/toggle-transparency ()
"Toggle the transparency of Emacs on and off"
(interactive)
(let ((alpha (frame-parameter nil 'alpha)))
(set-frame-parameter
nil 'alpha
(if (eql (cond ((numberp alpha) alpha)
((numberp (cdr alpha)) (cdr alpha))
;; Also handle undocumented (<active> <inactive>) form.
((numberp (cadr alpha)) (cadr alpha)))
100)
lg/transparency-alpha '(100 . 100)))))
(defun lg/transparency-alpha-increase (arg)
"Increase transparency of the frame"
(interactive "P")
(let ((inc (if arg arg lg/transparency-default-increment)))
(setq lg/transparency-alpha (+ lg/transparency-alpha inc)))
(lg/transparency-apply))
(defun lg/transparency-alpha-decrease (arg)
"Increase transparency of the frame"
(interactive "P")
(let ((inc (if arg arg lg/transparency-default-increment)))
(setq lg/transparency-alpha (- lg/transparency-alpha inc)))
(lg/transparency-apply))
(defun lg/transparency-apply ()
"Apply the transparency parameter to the frame"
(interactive)
(when (< 100 lg/transparency-alpha) (setq lg/transparency-alpha 100))
(when (> 0 lg/transparency-alpha) (setq lg/transparency-alpha 0))
(set-frame-parameter
nil 'alpha lg/transparency-alpha))(set-popup-rules!
'(("^\\*Completions" :ignore t)
("^\\*vterm" :ignore t)
("^\\*Local variables\\*$"
:vslot -1 :slot 1 :size +popup-shrink-to-fit)
("^\\*\\(?:[Cc]ompil\\(?:ation\\|e-Log\\)\\|Messages\\)"
:vslot -2 :size 0.3 :autosave t :quit t :ttl nil)
;; ("^\\*\\(?:doom \\|Pp E\\)" ; transient buffers (no interaction required)
;; :vslot -3 :size +popup-shrink-to-fit :autosave t :select ignore :quit t :ttl 0)
;; ("^\\*doom:" ; editing buffers (interaction required)
;; :vslot -4 :size 0.35 :autosave t :select t :modeline t :quit nil :ttl t)
("^\\*doom:\\(?:v?term\\|e?shell\\)-popup" ; editing buffers (interaction required)
:ignore t)
;; :vslot -5 :size 0.35 :select t :modeline nil :quit nil :ttl nil)
("^\\*\\(?:Wo\\)?Man "
:ignore t)
;; :vslot -6 :size 0.45 :select t :quit t :ttl 0)
("^\\*Calc"
:vslot -7 :side bottom :size 0.4 :select t :quit nil :ttl 0)
("^\\*Customize"
:slot 2 :side right :size 0.5 :select t :quit nil)
("^ \\*undo-tree\\*"
:slot 2 :side left :size 20 :select t :quit t)
;; `help-mode', `helpful-mode'
("^\\*[Hh]elp"
;; :slot 2 :vslot -8 :size 0.35 :select t)
;; ("^\\*eww\\*" ; `eww' (and used by dash docsets)
:vslot -11 :size 0.35 :select t)
("^\\*info\\*$" ; `Info-mode'
:ignore t)
("^\\*ytel-show\\*" ; `ytel-show'
:vslot -12 :size 0.5)
;; :slot 2 :vslot 2 :size 0.45 :select t)
("^\\*Warnings" :vslot 99 :size 0.25)
("^\\*Backtrace" :vslot 99 :size 0.4 :quit nil)
("^\\*CPU-Profiler-Report " :side bottom :vslot 100 :slot 1 :height 0.4 :width 0.5 :quit nil)
("^\\*Memory-Profiler-Report " :side bottom :vslot 100 :slot 2 :height 0.4 :width 0.5 :quit nil)
("^\\*Process List\\*" :side bottom :vslot 101 :size 0.25 :select t :quit t)
("^\\*\\(?:Proced\\|timer-list\\|Abbrevs\\|Output\\|Occur\\|unsent mail\\)\\*" :ignore t)))Zoom is a nice package for window management in emacs. It enlarges the window that has focus.
(use-package! zoom
:config
(map!
:leader
(:prefix ("t" . "toggle")
:desc "Zoom mode" "Z" #'zoom-mode))
(zoom-mode -1))(use-package! windmove
:init
(map! "s-h" #'windmove-left
"s-j" #'windmove-down
"s-k" #'windmove-up
"s-l" #'windmove-right)
:config
(setq windmove-wrap-around nil)
(setq windmove-window-distance-delta 1))Framemove extends windmove and allows to move from frame to frame. It makes switching from screen to screen easier in EXWM.
(use-package! framemove
:after exwm-randr
:load-path "lisp"
:config
(setq framemove-hook-into-windmove t))(use-package! windower
:init
(setq windower-border-move-distance 1)
(map! "s-H" #'windower-swap-left
"s-J" #'windower-swap-below
"s-K" #'windower-swap-above
"s-L" #'windower-swap-right
"s-M-h" #'windower-move-border-left
"s-M-j" #'windower-move-border-below
"s-M-k" #'windower-move-border-above
"s-M-l" #'windower-move-border-right
"s-<tab>" #'windower-switch-to-last-buffer
"s-r" #'windower-switch-to-last-buffer
"s-o" #'windower-toggle-single
"s-\\" #'windower-toggle-split))(use-package windresize)(use-package edwina
:commands (edwina-mode lg/edwina-popup)
:hook (edwina-mode . lg/edwina-remove-or-restore-buffer-behaviour)
:init
(defun lg/edwina-popup ()
"Dummy function to access edwina-mode-map with Hercules"
(interactive))
:config
(defvar display-buffer-alist-save nil)
(defvar display-buffer-base-action-save nil)
(defun lg/edwina-remove-or-restore-buffer-behaviour ()
"If edwina-mode is active, save and set to nil the following variables:
- display-buffer-alist
- display-buffer-base-action
or restore it if edwina mode is inactive."
(if edwina-mode
(progn
(setq display-buffer-base-action-save display-buffer-base-action)
(setq display-buffer-base-action '(display-buffer-below-selected))
(setq display-buffer-alist-save display-buffer-alist)
(setq display-buffer-alist nil))
(setq display-buffer-base-action display-buffer-base-action-save)
(setq display-buffer-alist display-buffer-alist-save)))
(setq edwina-mode-map (make-sparse-keymap))
(map! (:map edwina-mode-map
"k" #'edwina-inc-nmaster
"j" #'edwina-dec-nmaster
"h" #'edwina-dec-mfact
"l" #'edwina-inc-mfact)))(package! xelb)
(package! exwm)
(package! exwm-outer-gaps
:recipe
(:host github
:repo "lucasgruss/exwm-outer-gaps"))
(package! exwm-firefox-core)
(package! exwm-firefox-evil)
(package! exwm-firefox
:recipe
(:host github
:repo "ieure/exwm-firefox"))
(package! exwm-background
:recipe
(:host github
:repo "pestctrl/exwm-background"))
(package! exwm-x
:recipe
(:host github
:repo "tumashu/exwm-x"))The following snippet should go into the file
/usr/share/xsessions/emacs.desktop to make EXWM a possible choice in the
display manager.
[Desktop Entry]
Name=EXWM
Comment=Emacs is awesome!
Exec=emacs
Type=applicationMedia keys need to be explicitely bound, as we might not use EXWM in a DE.
(defun lg/volume-down ()
"Lower volume of the computer"
(interactive)
(shell-command "~/scripts/volume.sh down"))
(defun lg/volume-up ()
"Increase volume of the computer"
(interactive)
(shell-command "~/scripts/volume.sh up"))
(defun lg/brightness-down ()
"Lower brightness of the screen"
(interactive)
(shell-command "xbacklight -dec 10"))
(defun lg/brightness-up ()
"Increase brightness of the screen"
(interactive)
(shell-command "xbacklight -inc 10"))(after! exwm
(map! "<mode-line> <double-mouse-3>" #'exwm-floating-toggle-floating))EXWM has built in support for multi-monitor.
(use-package! exwm-randr
:config
(setq! exwm-randr-workspace-monitor-plist '(0 "eDP-1" 1 "DP-2"))
(setq! exwm-randr-screen-change-hook nil)
(defun lg/setup-screens ()
(start-process-shell-command
"xrandr" nil "sh ~/.screenlayout/arandr.layout.sh"))
(add-hook 'exwm-randr-screen-change-hook #'lg/setup-screens)
(exwm-randr-enable))(use-package! exwm-systemtray
:disabled
:config
(setq! exwm-systemtray-height 18
exwm-systemtray-icon-gap 3
exwm-systemtray-background-color "black")
(exwm-systemtray-enable))EXWM is seriously awesome. Now I don’t have to exit emacs ever and I get to configure my window manager with emacs lisp. Life is good.
(use-package! exwm
:if window-system
:config
(defun lg/exwm-async-run (name)
"Run a process asynchronously"
(interactive)
(start-process name nil name))
(defun lg/run-or-raise-or-dismiss (program program-buffer-name)
"If no instance of the program is running, launch the program.
If an instance already exists, and its corresponding buffer is
displayed on the screen, move to the buffer. If the buffer is not
visible, switch to the buffer in the current window. Finally, if
the current buffer is already that of the program, bury the
buffer (=minimizing in other WM/DE)"
;; check current buffer
(if (string= (buffer-name) program-buffer-name)
(bury-buffer)
;; either switch to or launch program
(progn
(if (get-buffer program-buffer-name)
(progn
(if (get-buffer-window program-buffer-name)
(select-window (display-buffer program-buffer-name) nil)
(exwm-workspace-switch-to-buffer program-buffer-name)))
;; start program
(progn
(lg/exwm-async-run program)
(message (format "Launching %s" program)))))))
(defun lg/run-or-raise-or-dismiss-firefox ()
(interactive)
(lg/run-or-raise-or-dismiss "firefox" "Firefox-esr"))
(defun lg/run-or-raise-or-dismiss-firefox ()
(interactive)
(let ((buf-list (->> (buffer-list)
(--reject (not (string= "Firefox-esr" (buffer-local-value 'exwm-class-name it))))))
buf)
(if buf-list
(progn
(setq buf (car buf-list))
(if (eq (current-buffer) buf)
(windower-switch-to-last-buffer)
(if (get-buffer-window buf)
(select-window (display-buffer buf) nil)
(exwm-workspace-switch-to-buffer buf))))
;; start program
(lg/exwm-async-run "firefox")
(message (format "Launching %s" "firefox")))))
(defun lg/run-or-raise-or-dismiss-spotify ()
(interactive)
(lg/run-or-raise-or-dismiss "spotify" "Spotify"))
(defun lg/run-or-raise-or-dismiss-thunderbird ()
(interactive)
(lg/run-or-raise-or-dismiss "thunderbird" "thunderbird"))
(defun lg/toggle-line-char-modes ()
"If on a EXWM buffer, toggle 'line' or 'char'"
(interactive)
(if exwm-window-type
(if (string= exwm--input-mode "line-mode")
(call-interactively #'exwm-input-release-keyboard) ; switch to char mode
(call-interactively #'exwm-input-grab-keyboard)))) ; switch to line mode
(defun lg/lock-screen ()
"Lock screen with slock"
(interactive)
(start-process "" nil "/usr/local/bin/slock"))
(defun efs/run-in-background (command)
(let ((command-parts (split-string command "[ ]+")))
(apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
(defvar efs/polybar-process nil
"Holds the process of the running Polybar instance, if any")
(defun efs/kill-panel ()
(interactive)
(when efs/polybar-process
(ignore-errors
(kill-process efs/polybar-process)))
(setq efs/polybar-process nil))
(defun efs/start-panel ()
(interactive)
(efs/kill-panel)
(setq efs/polybar-process (start-process-shell-command "polybar" nil "polybar -r panel")))
(defun lg/exwm-init-hook ()
(interactive)
(shell-command "setxkbmap gb -variant extd -option ctrl:nocaps")
(shell-command "xset r rate 300 40")
(shell-command "killall pasystray")
(shell-command "killall blueman-applet")
(shell-command "killall nm-applet")
(shell-command "killall compton")
(shell-command "killall kdeconnect-indicator")
(shell-command "killall xsettingsd")
;(shell-command "feh --bg-fill ~/Images/Wallpaper/landscapes_sand_desert_dunes.jpg")
(shell-command "feh --bg-fill ~/Images/Wallpaper/solid_blue.jpeg")
;; (shell-command "feh --bg-fill ~/Images/Wallpaper/mountain.png")
(efs/run-in-background "pasystray")
(efs/run-in-background "compton")
(efs/run-in-background "xfce4-power-manager")
(efs/run-in-background "xfce4-panel")
(efs/run-in-background "blueman-applet")
(efs/run-in-background "nm-applet")
(efs/run-in-background "kdeconnect-indicator")
(efs/run-in-background "xsettingsd")
(efs/start-panel))
(add-hook 'exwm-init-hook #'lg/exwm-init-hook)
(defun lg/exwm-update-title-hook ()
"Hook to be ran when window title is updated"
(if (not (string= exwm-class-name "Firefox-esr"))
(exwm-workspace-rename-buffer exwm-class-name)
(exwm-workspace-rename-buffer exwm-title)))
(add-hook 'exwm-update-title-hook #'lg/exwm-update-title-hook)
;; disable tab bar for floating frames
(add-hook 'exwm-floating-setup-hook
(lambda ()
(toggle-tab-bar-mode-from-frame -1)))
(setq exwm-input-global-keys
`(([S-s-backspace] . exwm-workspace-delete)
([?\s-f] . exwm-layout-toggle-fullscreen)
([?\s-F] . exwm-floating-toggle-floating)
([?\s-R] . exwm-reset)
([?\s-w] . exwm-utils-workspace-switch-cyclically)
([?\s-W] . exwm-utils-workspace-move-cyclically)
([?\s-\'] . consult-buffer)
([?\s-\@] . ibuffer)
([?\s-b] . bury-buffer)
([s-f2] . lg/lock-screen)
([?\s-d] . app-launcher-run-app)
([?\s-i] . lg/run-or-raise-or-dismiss-firefox)
([?\s-t] . lg/run-or-raise-or-dismiss-thunderbird)
([?\s-s] . lg/run-or-raise-or-dismiss-spotify)
([?\s-u] . lg/toggle-line-char-modes)
([s-return] . vterm)
([s-escape] . lg/kill-this-buffer)
([?\s-/] . centaur-tabs-mode)
([?\s-m] . centaur-tabs-backward)
([?\s-,] . centaur-tabs-forward)
([?\s-?] . tab-bar-mode)
([?\s-M] . lg/tab-previous-and-hide-maybe)
([?\s-<] . lg/tab-next-and-hide-maybe)
([?\s-O] . exwm-outer-gaps-mode)
([?\s-y] . exwm-outer-gaps-increment)
([?\s-p] . exwm-outer-gaps-decrement)
;; Everything window
([?\s-q] . evil-window-delete)
([?\s-v] . split-window-horizontally)
([?\s-z] . split-window-vertically)
([s-tab] . windower-switch-to-last-buffer)
([?\s-r] . windower-switch-to-last-buffer)
([?\s-\\] . windower-toggle-split)
([?\s-o] . windower-toggle-single)
([142606440] . windower-move-border-left) ; M-s-h
([142606442] . windower-move-border-below); M-s-j
([142606443] . windower-move-border-above); M-s-k
([142606444] . windower-move-border-right); M-s-l
([?\s-h] . windmove-left) ([?\s-H] . windower-swap-left)
([?\s-j] . windmove-down) ([?\s-J] . windower-swap-below)
([?\s-k] . windmove-up) ([?\s-K] . windower-swap-above)
([?\s-l] . windmove-right) ([?\s-L] . windower-swap-right)))
(setq exwm-workspace-show-all-buffers t)
(setq exwm-layout-show-all-buffers t)
(setq exwm-workspace-number 2)
(setq exwm-workspace-minibuffer-position nil)
(setq exwm-workspace-display-echo-area-timeout 1)
(setq! exwm-manage-configurations
'(((or (equal "hl2-linux" exwm-class-name)
(equal "hl2-linux" exwm-title))
floating nil
fullscreen nil
tiling-mode-line nil
;;char-mode t
managed t)
((equal exwm-class-name "openspades")
floating nil
managed t)
((equal exwm-class-name "Firefox-esr")
floating-mode-line nil)
))
(push (aref (kbd "<escape>") 0) exwm-input-prefix-keys)
(push (aref (kbd "<return>") 0) exwm-input-prefix-keys)
(push (aref (kbd "s-<SPC>") 0) exwm-input-prefix-keys)
;; relaunch the panel so that it auto-hide correctly
(load "~/.config/doom/lisp/exwm-utils.el")
;(shell-command "xfce4-panel --restart")
(exwm-enable))I wrote EXWM outer gaps to add some useless gaps to EXWM. I seldom use them, but they are there. Since I use polybar on top of the echo area, I set some environment variables that are used in polybar’s configuration file and that basically tell it where to draw the bar, taking the gaps into account.
(use-package exwm-outer-gaps
:after (xelb exwm hercules)
:init
(defvar exwm-outer-gaps-polybar-timer nil
"Timer to trigger redisplay of polybar on the minibuffer")
(setq exwm-outer-gaps-polybar-timer
(run-with-timer 1 nil (lambda () (efs/start-panel))))
:config
(setq exwm-outer-gaps-increment-step 10)
(defvar exwm-outer-gaps-keymap nil
"keymap to resize gaps")
(setq exwm-outer-gaps-keymap (make-sparse-keymap))
(defvar lg/exwm-outer-gaps--is-minibuffer-shown t
"Whether minibuffer is hidden away or not")
(defun lg/exwm-outer-gaps-toggle-minibuffer ()
(interactive)
(lg/exwm-outer-gaps-hide-show-minibuffer lg/exwm-outer-gaps--is-minibuffer-shown)
(setq lg/exwm-outer-gaps--is-minibuffer-shown
(not lg/exwm-outer-gaps--is-minibuffer-shown)))
(defun lg/exwm-outer-gaps-hide-show-minibuffer (hide)
"Hide or show the minibuffer by ajusting the bottom gap.
Argument hide is t if minibuffer should be hidden, true if shown."
(if hide
(exwm-outer-gaps-set 3 -20 nil)
;(setq exwm-outer-gaps-width [0 0 0 -20])
;; (setq exwm-outer-gaps-width [0 0 0 0]))
(exwm-outer-gaps-set 3 0 nil))
(exwm-outer-gaps-apply))
(defun lg/exwm-outer-gaps-show-minibuffer ()
"Show the minibuffer"
(interactive)
(lg/exwm-outer-gaps-hide-show-minibuffer nil)
(efs/start-panel))
(defun lg/exwm-outer-gaps-hide-minibuffer ()
"Hide the minibuffer"
(interactive)
(lg/exwm-outer-gaps-hide-show-minibuffer t)
(efs/kill-panel))
(defun lg/exwm-outer-gaps-show-minibuffer-init-hook ()
(when (not lg/exwm-outer-gaps--is-minibuffer-shown)
(lg/exwm-outer-gaps-hide-show-minibuffer nil)))
(defun lg/exwm-outer-gaps-hide-minibuffer-exit-hook ()
(when (not lg/exwm-outer-gaps--is-minibuffer-shown)
(lg/exwm-outer-gaps-hide-show-minibuffer t)))
(map! (:map exwm-outer-gaps-keymap
:desc "Decrease left" "h" (lambda () (interactive) (exwm-outer-gaps-decrement 0))
:desc "Increase left" "H" (lambda () (interactive) (exwm-outer-gaps-increment 0))
:desc "Decrease right" "l" (lambda () (interactive) (exwm-outer-gaps-decrement 1))
:desc "Increase right" "L" (lambda () (interactive) (exwm-outer-gaps-increment 1))
:desc "Decrease top" "k" (lambda () (interactive) (exwm-outer-gaps-decrement 2))
:desc "Increase top" "K" (lambda () (interactive) (exwm-outer-gaps-increment 2))
:desc "Decrease bottom" "j" (lambda () (interactive) (exwm-outer-gaps-decrement 3))
:desc "Increase bottom" "J" (lambda () (interactive) (exwm-outer-gaps-increment 3))
:desc "Shift frame left" "y" (lambda () (interactive)
(exwm-outer-gaps-increment 1)
(exwm-outer-gaps-decrement 0))
:desc "Shift frame right" "o" (lambda () (interactive)
(exwm-outer-gaps-increment 0)
(exwm-outer-gaps-decrement 1))
:desc "Shift frame down" "u" (lambda () (interactive)
(exwm-outer-gaps-increment 2)
(exwm-outer-gaps-decrement 3))
:desc "Shift frame up" "i" (lambda () (interactive)
(exwm-outer-gaps-increment 3)
(exwm-outer-gaps-decrement 2))))
(defun lg/exwm-outer-gaps-hercules ()
(interactive))
(hercules-def
:toggle-funs #'lg/exwm-outer-gaps-hercules
:keymap 'exwm-outer-gaps-keymap
:transient t)
(defun lg/exwm-outer-gaps-setenv-and-polybar ()
"Set environment variables that are used by polybar to overlay
the minibuffer, and restart polybar after a timer."
(setenv "GAP_RIGHT" "65%")
(setenv "GAP_BOTTOM" (number-to-string
(if exwm-outer-gaps-mode
(aref exwm-outer-gaps-width 3)
0)))
(setenv "PANEL_WIDTH" (concat "35%:-"
(number-to-string
(if exwm-outer-gaps-mode
(aref exwm-outer-gaps-width 0)
0))))
(cancel-timer exwm-outer-gaps-polybar-timer)
(setq exwm-outer-gaps-polybar-timer
(run-with-timer 1 nil (lambda () (efs/start-panel)))))
(advice-add #'exwm-outer-gaps-apply :before #'lg/exwm-outer-gaps-setenv-and-polybar)
;; (add-hook 'minibuffer-setup-hook #'lg/exwm-outer-gaps-show-minibuffer-init-hook 100)
;; (add-hook 'minibuffer-exit-hook #'lg/exwm-outer-gaps-hide-minibuffer-exit-hook 100)
(exwm-outer-gaps-mode +1))With EXWM emulation keys, you can have vi-style keybindings within firefox, without having to install anything on the browser. Have I mentioned how awesome EXWM is? My next objective will probably be to bring firefox even closer to emacs by enabling new tabs within new windows and have emacs handle all windows with iBuffer.
(use-package! exwm-firefox-evil
:hook ((exwm-manage-finish . exwm-firefox-evil-activate-if-firefox)
;; (exwm-manage-finish . lg/exwm-firefox-force-fullscreen)
(exwm-firefox-evil-mode . lg/exwm-firefox-hook))
:init
(setq exwm-firefox-evil-firefox-class-name '("Firefox" "Firefox-esr" "Nightly" "Iceweasel" "Icecat"))
:config
(defun exwm-input--on-ButtonPress-line-mode (buffer button-event)
"Handle button events in line mode.
BUFFER is the `exwm-mode' buffer the event was generated
on. BUTTON-EVENT is the X event converted into an Emacs event.
The return value is used as event_mode to release the original
button event."
(with-current-buffer buffer
(let ((read-event (exwm-input--mimic-read-event button-event)))
(exwm--log "%s" read-event)
(if (and read-event
(exwm-input--event-passthrough-p read-event))
;; The event should be forwarded to emacs
(progn
(exwm-input--cache-event read-event)
(exwm-input--unread-event button-event)
xcb:Allow:ReplayPointer)
;; xcb:Allow:SyncPointer)
;; The event should be replayed
xcb:Allow:ReplayPointer))))
(defun lg/exwm-firefox-force-fullscreen ()
"Send F11 to firefox to always be in full screen.
Whenever you switch to another window and then come back to
firefox, it leaves fullscreen mode."
(interactive)
(exwm-input--fake-key 'f11))
(defun lg/exwm-firefox-toggle-tree-tab ()
"Toggle the tree tab extension"
(interactive)
(exwm-input--fake-key 'f1))
(defun lg/exwm-firefox-hook ()
"Hook to be run after entering exwm-firefox-evil-mode"
(interactive)
(exwm-firefox-intercept-next-ret)
(exwm-firefox-evil-insert))
(defun lg/exwm-firefox-hint ()
"Highlights hints on the page."
(interactive)
(exwm-input--fake-key 'C-m)
(exwm-firefox-evil-insert))
;; go back to normal mode after pressing return
(defun exwm-firefox-intercept-next-ret ()
(interactive)
(setq-local exwm-firefox-next-ret-normal t))
(defun exwm-firefox-intercept-return ()
(interactive)
(exwm-input--fake-key (aref (kbd "<return>") 0))
(when (and (boundp 'exwm-firefox-next-ret-normal)
exwm-firefox-next-ret-normal)
(exwm-firefox-evil-normal)
(setq-local exwm-firefox-next-ret-normal nil)))
(advice-add #'exwm-firefox-core-tab-new :after #'exwm-firefox-intercept-next-ret)
(advice-add #'lg/exwm-firefox-hint :after #'exwm-firefox-intercept-next-ret)
(advice-add #'exwm-firefox-core-focus-search-bar :after #'exwm-firefox-intercept-next-ret)
(advice-add #'exwm-firefox-core-quick-find :after #'exwm-firefox-intercept-next-ret)
(evil-initial-state 'exwm-firefox-evil-mode 'insert)
(define-key! 'normal exwm-firefox-evil-mode-map
"m" nil
"t" #'exwm-firefox-core-window-new
"f" #'lg/exwm-firefox-hint
"F" #'lg/exwm-firefox-force-fullscreen
"T" #'lg/exwm-firefox-toggle-tree-tab
"q" #'exwm-input-send-next-key
"<return>" #'exwm-firefox-intercept-return)
(define-key! 'insert exwm-mode-map
"<return>" #'exwm-firefox-intercept-return
"C-h" #'exwm-firefox-core-left
"C-j" #'exwm-firefox-core-down
"C-k" #'exwm-firefox-core-up
"C-l" #'exwm-firefox-core-right)
(define-key! exwm-mode-map
"<return>" #'(lambda ()
(interactive)
(unless exwm-firefox-evil-mode
(exwm-input--fake-key (aref (kbd "<return>") 0))))))
(use-package! exwm-firefox
:after exwm-firefox-evil
:config
(defun exwm-firefox-open-in-mpv ()
(interactive)
(exwm-firefox-core-focus-search-bar)
(exwm-firefox-core-copy)
(emms-play-url (current-kill 0 nil)))
;; I have different keybinding in firefox for tabdetach-attach : M-S-t
(defun lg/exwm-firefox-attach ()
"Attach the current tab into its parent window.
This requires the tabdetach extension to work."
(interactive)
(exwm-input--fake-key ?\M-\S-T))
(define-key! 'normal exwm-firefox-evil-mode-map
"A" #'lg/exwm-firefox-attach
"D" #'exwm-firefox-split-detach
"M" #'exwm-firefox-merge)
;; I don't like renaming the name of the firefox window
;(remove-hook 'exwm-update-title-hook 'exwm-firefox--update-title))
)(use-package exwm-background)EXWM-x is a package that extends EXWM to bring interesting features, like enhanced mouse control, buttons for your X-applications, etc. I don’t use all of its features, but rather cherry pick those I find interesting.
(use-package exwmx-button
:config
(exwmx-button-enable)
(defun exwmx-button-disable ()
"Disable exmwx-button"
(remove-hook 'exwm-update-class-hook #'exwmx-button--update-button-line)
(remove-hook 'exwm-update-title-hook #'exwmx-button--update-button-line)
(remove-hook 'buffer-list-update-hook #'exwmx-button--update-button-line))(use-package exwmx-floating)I use polybar and make it draw on top of the echo area, on the right half. The echo area is empty most of the time, and messages displayed there are usually short enough to be less than half a line. I add some more configuration to hide polybar when entering the minibuffer, and restoring it when leaving it.
(defun lg/polybar-minibuffer-hide ()
(call-process "polybar-msg" nil 0 nil "cmd" "hide"))
(defun lg/polybar-minibuffer-show ()
(call-process "polybar-msg" nil 0 nil "cmd" "show"))
(add-hook 'minibuffer-setup-hook #'lg/polybar-minibuffer-hide)
(add-hook 'minibuffer-exit-hook #'lg/polybar-minibuffer-show)EXWM is older than the tab-line, and does not take it into account. We have
to modify exwm to make it draw X windows below the tab-line (the top border
of the window has to be lower), otherwise they will overlap it. Centaur-tabs
uses the tab-line to render its tab-line, and I use it rather than tab-line,
therefore I make the frames lower by centaur-tabs-height pixels.
(after! exwm
(defun exwm-layout--show (id &optional window)
"Show window ID exactly fit in the Emacs window WINDOW."
(exwm--log "Show #x%x in %s" id window)
(let* ((edges (window-inside-absolute-pixel-edges window))
(x (pop edges))
(y (pop edges))
(width (- (pop edges) x))
(height (- (pop edges) y))
frame-x frame-y frame-width frame-height)
(with-current-buffer (exwm--id->buffer id)
(when exwm--floating-frame
(setq frame-width (frame-pixel-width exwm--floating-frame)
frame-height (+ (frame-pixel-height exwm--floating-frame)
;; Use `frame-outer-height' in the future.
exwm-workspace--frame-y-offset))
(when exwm--floating-frame-position
(setq frame-x (elt exwm--floating-frame-position 0)
frame-y (elt exwm--floating-frame-position 1)
x (+ x frame-x (- exwm-layout--floating-hidden-position))
y (+ y frame-y (- exwm-layout--floating-hidden-position)))
(setq exwm--floating-frame-position nil))
(exwm--set-geometry (frame-parameter exwm--floating-frame
'exwm-container)
frame-x frame-y frame-width frame-height))
(when (exwm-layout--fullscreen-p)
(with-slots ((x* x)
(y* y)
(width* width)
(height* height))
(exwm-workspace--get-geometry exwm--frame)
(setq x x*
y y*
width width*
height height*)))
;; edited here
(when
(and (not (bound-and-true-p centaur-tabs-local-mode))
(not (exwm-layout--fullscreen-p))
(or (bound-and-true-p centaur-tabs-mode)
(bound-and-true-p tab-line-mode)))
(setq y (+ y centaur-tabs-height)))
;; edited here
(exwm--set-geometry id x y width height)
(xcb:+request exwm--connection (make-instance 'xcb:MapWindow :window id))
(exwm-layout--set-state id xcb:icccm:WM_STATE:NormalState)
(setq exwm--ewmh-state
(delq xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state))
(exwm-layout--set-ewmh-state id)
(exwm-layout--auto-iconify)))
(xcb:flush exwm--connection)))(load! "private.el") ; credentials and private info
(setq! org-directory "~/org/"
display-line-numbers-type `relative
idle-update-delay 0.3
x-select-enable-primary t
select-enable-clipboard t
x-select-enable-clipboard-manager t)
(defun lg/kill-this-buffer ()
"Kill the current buffer without confirmation"
(interactive)
(kill-buffer (current-buffer)))
(map! "s-<escape>" #'lg/kill-this-buffer)Which key is one of the killer features for using emacs, it’s good to discover commands and also to not worry about remembering keybindings. I have nothing but praise for this package but the way Doom Emacs sets it makes it pop too slowly. I want it to appear almost instantaneously.
(after! which-key
;; which-key-idle-delay must be set before enabling the mode
;; so we disable it, set the variable and re-enable it
(which-key-mode -1)
(setq! which-key-idle-delay 0.7)
(which-key-mode +1))Hercules is a hydra banisher. Hydra is an excellent package, but you have to declare them explicitely, which makes it cumbersome. Hercules leverages which key to provide similar features.
(use-package hercules
:config
(hercules-def
:show-funs #'windresize
:hide-funs '(windresize-exit windresize-cancel-and-quit)
:keymap 'windresize-map)
(hercules-def
:show-funs #'lg/edwina-popup
:keymap 'edwina-mode-map
:transient t))(setq deft-directory "~/org")(use-package fast-scroll
:config
(fast-scroll-mode +1))(use-package scroll-on-jump
:after evil
:config
(scroll-on-jump-advice-add evil-undo)
(scroll-on-jump-advice-add evil-redo)
(scroll-on-jump-advice-add evil-jump-item)
(scroll-on-jump-advice-add evil-jump-forward)
(scroll-on-jump-advice-add evil-jump-backward)
(scroll-on-jump-advice-add evil-ex-search-next)
(scroll-on-jump-advice-add evil-ex-search-previous)
(scroll-on-jump-advice-add evil-forward-paragraph)
(scroll-on-jump-advice-add evil-backward-paragraph)
(setq scroll-on-jump-duration 0.2))(use-package good-scroll
:config
(good-scroll-mode +1));;; found at https://tsdh.wordpress.com/2015/03/03/swapping-emacs-windows-using-dragndrop/
(defun th/swap-window-buffers-by-dnd (drag-event)
"Swaps the buffers displayed in the DRAG-EVENT's start and end
window."
(interactive "e")
(let ((start-win (cl-caadr drag-event))
(end-win (cl-caaddr drag-event)))
(when (and (windowp start-win)
(windowp end-win)
(not (eq start-win end-win))
(not (memq (minibuffer-window)
(list start-win end-win))))
(let ((bs (window-buffer start-win))
(be (window-buffer end-win)))
(unless (eq bs be)
(set-window-buffer start-win be)
(set-window-buffer end-win bs))))))
(map! "<mode-line> <s-drag-mouse-1>" #'th/swap-window-buffers-by-dnd
"<mode-line> <double-mouse-1>" #'windower-toggle-single
"<mode-line> <mouse-3>" nil
"<mode-line> <mouse-2>" #'mouse-delete-window)
(use-package! strokes
:if window-system
:config
(map! "<mouse-8>" #'strokes-do-stroke
"<S-down-mouse-1>" #'strokes-do-stroke
"<s-down-mouse-1>" #'strokes-do-stroke)
(setq! strokes-file "~/.config/doom/strokes")
(setq! strokes-use-strokes-buffer nil)
(strokes-mode +1))(after! org
(setq org-fontify-quote-and-verse-blocks nil)
(setq org-fontify-whole-heading-line nil)
(setq org-agenda-include-diary t)
(setq org-startup-with-latex-preview t)
(setq org-hide-leading-stars t)
(setq org-startup-indented nil)
(setq org-archive-location "archive/%s_archive::")
(setq org-src-block-faces
`(("emacs-lisp" modus-themes-nuanced-magenta)
("elisp" modus-themes-nuanced-magenta)
("clojure" modus-themes-nuanced-magenta)
("clojurescript" modus-themes-nuanced-magenta)
("c" modus-themes-nuanced-blue)
("c++" modus-themes-nuanced-blue)
("sh" modus-themes-nuanced-green)
("shell" modus-themes-nuanced-green)
("html" modus-themes-nuanced-yellow)
("xml" modus-themes-nuanced-yellow)
("css" modus-themes-nuanced-red)
("scss" modus-themes-nuanced-red)
("matlab" modus-themes-nuanced-red)
("octave" modus-themes-nuanced-red)
("python" modus-themes-nuanced-green)
("ipython" modus-themes-nuanced-magenta)
("r" modus-themes-nuanced-cyan)
("yaml" modus-themes-nuanced-cyan)
("conf" modus-themes-nuanced-cyan)
("docker" modus-themes-nuanced-cyan))))
(defun org-latex-preview-latex-image-clear-directory ()
(interactive)
(delete-directory org-preview-latex-image-directory t nil))(use-package! org-sidebar
:disabled
:after org)(use-package! org-superstar ; supersedes `org-bullets'
:after org
:disabled
:config
(setq org-superstar-remove-leading-stars t)
(setq org-superstar-headline-bullets-list
'("🞛" "◉" "○" "▷"))
(setq org-superstar-item-bullet-alist
'((?+ . ?•)
(?* . ?➤)
(?- . ?–)))
(org-superstar-mode 1))(use-package! org-tree-slide
:after org
:commands prot/org-presentation-mode
:init
(map! (:leader
(:prefix ("t" . "toggle")
:desc "Org presentation mode" "P" #'prot/org-presentation-mode)))
:config
(setq org-tree-slide-breadcrumbs nil)
(setq org-tree-slide-header nil)
(setq org-tree-slide-slide-in-effect nil)
(setq org-tree-slide-heading-emphasis nil)
(setq org-tree-slide-cursor-init t)
(setq org-tree-slide-modeline-display nil)
(setq org-tree-slide-skip-done nil)
(setq org-tree-slide-skip-comments t)
(setq org-tree-slide-fold-subtrees-skipped t)
(setq org-tree-slide-skip-outline-level 2)
(setq org-tree-slide-never-touch-face t)
(setq org-tree-slide-activate-message
(propertize "Presentation mode ON" 'face 'success))
(setq org-tree-slide-deactivate-message
(propertize "Presentation mode OFF" 'face 'error))
(define-minor-mode prot/org-presentation-mode
"Parameters for plain text presentations with `org-mode'."
:init-value nil
:global nil
(if prot/org-presentation-mode
(progn
(unless (eq major-mode 'org-mode)
(user-error "Not in an Org buffer"))
(org-tree-slide-mode 1)
(writeroom-mode 1)
(org-superstar-mode 1)
(setq-local display-line-numbers nil)
(org-indent-mode 1))
(org-tree-slide-mode -1)
(writeroom-mode -1)
(org-superstar-mode -1)
(setq-local display-line-numbers 'relative)
(org-indent-mode -1)))
:bind (("C-c P" . prot/org-presentation-mode)
:map org-tree-slide-mode-map
("C-h" . org-tree-slide-display-header-toggle)
("C-l" . org-tree-slide-display-header-toggle)
("C-j" . org-tree-slide-move-next-tree)
("C-k" . org-tree-slide-move-previous-tree)))(use-package! org-noter
:after org
:defer t
:preface
;; Allow the user to preempt this and set the document search path
;; If not set then use `org-directory'
(defvar org-noter-notes-search-path nil)
:config
(unless org-noter-notes-search-path
(setq org-noter-notes-search-path (list org-directory)))
(setq org-noter-auto-save-last-location t
org-noter-default-notes-file-names '("lecture.org")
org-noter-separate-notes-from-heading t
org-noter-always-create-frame nil
org-noter-kill-frame-at-session-end nil)
(map!
(:after (org-noter)
:map pdf-view-mode-map
:n "i" #'org-noter-insert-note)))Create nice report for meetings.
(use-package! ox-report
:after org)(use-package! org-ref
:after org)(use-package org-contacts
:after org
:config
(setq org-contacts-files '("~/org/contacts.org"))
;; (setq org-contacts-keymap)
(setq org-contacts-matcher "EMAIL<>\"\"|ALIAS<>\"\"|TEL<>\"\"|ADRESSE<>\"\"|ANNIVERSAIRE<>\"\"")
(setq org-contacts-icon-size 32)
(setq org-contacts-vcard-file "~/org/contacts.vcf")
;; (setq org-contacts-last-update nil)
(setq org-contacts-tel-property "TEL")
(setq org-contacts-group-prefix "+")
(setq org-contacts-icon-property "ICON")
(setq org-contacts-note-property "NOTE")
(setq org-contacts-alias-property "ALIAS")
(setq org-contacts-email-property "EMAIL")
(setq org-contacts-ignore-property "IGNORE")
(setq org-contacts-birthday-format "Anniversaire: %l (%Y)")
(setq org-contacts-address-property "ADRESSE")
(setq org-contacts-tags-props-prefix "#")
(setq org-contacts-icon-use-gravatar t)
(setq org-contacts-enable-completion t)
(setq org-contacts-birthday-property "ANNIVERSAIRE")
(setq org-contacts-nickname-property "NICKNAME")
;; (setq org-contacts-complete-functions )
(setq org-contacts-completion-ignore-case t)
(setq org-contacts-last-read-mail-property "DERNIER_MAIL")
(setq org-contacts-property-values-separators "[,; \f\11\n\15\13]+")
(setq org-contacts-email-link-description-format "%s (%d)")
;;(setq calendar-date-style 'american)
(defun org-contacts-anniversaries (&optional field format)
"Compute FIELD anniversary for each contact, returning FORMAT.
Default FIELD value is \"BIRTHDAY\".
Format is a string matching the following format specification:
%h - Heading name
%l - Link to the heading
%y - Number of year
%Y - Number of year (ordinal)"
(let ((calendar-date-style 'american)
(entry ""))
(unless format (setq format org-contacts-birthday-format))
(cl-loop for contact in (org-contacts-filter)
for anniv = (let ((anniv (cdr (assoc-string
(or field org-contacts-birthday-property)
(nth 2 contact)))))
(when anniv
(calendar-gregorian-from-absolute
(org-time-string-to-absolute anniv))))
;; Use `diary-anniversary' to compute anniversary.
if (and anniv (apply 'diary-anniversary anniv))
collect (format-spec format
`((?l . ,(org-with-point-at (cadr contact) (org-store-link nil)))
(?h . ,(car contact))
(?y . ,(- (calendar-extract-year date)
(calendar-extract-year anniv)))
(?Y . ,(let ((years (- (calendar-extract-year date)
(calendar-extract-year anniv))))
(format "%d%s" years (diary-ordinal-suffix years))))))))))(use-package org-protocol
:after org)(use-package org-capture
:after org
:config
(setq org-capture-templates '(("t" "Personal todo" entry
(file+headline +org-capture-todo-file "Inbox")
"* [ ] %?\n%i\n%a" :prepend t)
("n" "Personal notes" entry
(file+headline +org-capture-notes-file "Inbox")
"* %u %?\n%i\n%a" :prepend t)
("j" "Journal" entry
(file+olp+datetree +org-capture-journal-file)
"* %U %?\n%i\n%a" :prepend t)
("p" "Templates for projects")
("pt" "Project-local todo" entry
(file+headline +org-capture-project-todo-file "Inbox")
"* TODO %?\n%i\n%a" :prepend t)
("pn" "Project-local notes" entry
(file+headline +org-capture-project-notes-file "Inbox")
"* %U %?\n%i\n%a" :prepend t)
("pc" "Project-local changelog" entry
(file+headline +org-capture-project-changelog-file "Unreleased")
"* %U %?\n%i\n%a" :prepend t)
("o" "Centralized templates for projects")
("ot" "Project todo" entry #'+org-capture-central-project-todo-file "* TODO %?\n %i\n %a" :heading "Tasks" :prepend nil)
("on" "Project notes" entry #'+org-capture-central-project-notes-file "* %U %?\n %i\n %a" :heading "Notes" :prepend t)
("oc" "Project changelog" entry #'+org-capture-central-project-changelog-file "* %U %?\n %i\n %a" :heading "Changelog" :prepend t)
("l" "Link" entry (file+headline "~/org/links.org" "Links")
"* %a %^g\n %?\n %T\n %i"))))(use-package org-pomodoro
:after org
:config
(setq org-pomodoro-length 45)
(setq org-pomodoro-short-break-length 10)
(setq org-pomodoro-long-break-frequency 3)
(setq org-pomodoro-ticking-sound-p nil)
(setq org-pomodoro-play-sounds nil)
(setq org-pomodoro-short-break-sound "/usr/share/sounds/freedesktop/stereo/complete.oga")
(setq org-pomodoro-long-break-sound "/usr/share/sounds/freedesktop/stereo/complete.oga")
(setq org-pomodoro-finished-sound "/usr/share/sounds/freedesktop/stereo/complete.oga"))(use-package zotxt)
(use-package org-zotxt)
(use-package org-zotxt-noter)(use-package pdf-tools
:config
(setq pdf-view-midnight-colors '("#ffffff" . "#000000")))(use-package! pdf-continuous-scroll-mode
:after pdf-tools
:init
(map!
(:map pdf-continuous-scroll-mode-map
:n "j" #'pdf-continuous-scroll-forward
:n "k" #'pdf-continuous-scroll-backward)))
;; (map!
;; (:map pdf-view-mode-map
;; :n "j" #'evil-collection-pdf-view-next-line-or-next-page
;; :n "k" #'evil-collection-pdf-view-previous-line-or-previous-page)))(after! company
(setq company-idle─delay 0.1)
(setq company-minimum-prefix-length 1)
(set-company-backend! 'sh-mode
'company-shell))(use-package! company-prescient
:after company
:config
(company-prescient-mode +1))(package! selectrum
:recipe (:host github
:repo "raxod502/selectrum"))
(package! prescient
:recipe (:host github
:repo "raxod502/prescient.el"))
(package! orderless)
(package! selectrum-prescient
:recipe (:host github
:repo "raxod502/prescient.el"
:files ("selectrum-prescient.el")))
(package! consult
:recipe (:host github
:repo "minad/consult"))
(package! marginalia
:recipe (:host github
:repo "minad/marginalia"))
(package! consult-selectrum
:recipe (:host github
:repo "minad/consult"
:files ("consult-selectrum.el")))
(package! embark
:recipe (:host github
:repo "oantolin/embark"))
(package! app-launcher
:recipe (:host github
:repo "SebastienWae/app-launcher"))(use-package! selectrum
:init
(setq projectile-completion-system 'default)
:config
(setq selectrum-num-candidates-displayed 10)
(setq selectrum-fix-minibuffer-height nil)
(setq selectrum-display-action nil)
(setq selectrum-refine-candidates-function #'orderless-filter)
(setq selectrum-highlight-candidates-function #'orderless-highlight-matches)
(selectrum-mode +1))
(use-package! prescient
:after selectrum
:config
(prescient-persist-mode +1))
(use-package! orderless
:config
(setq orderless-skip-highlighting (lambda () selectrum-is-active))
(setq completion-styles '(orderless)))
(use-package! selectrum-prescient
:after (selectrum prescient)
:config
(setq selectrum-prescient-enable-filtering nil)
(selectrum-prescient-mode +1)
(map! (:map selectrum-minibuffer-map
"C-j" #'selectrum-next-candidate
"s-'" #'selectrum-next-candidate
"<mouse-5>" #'selectrum-next-candidate
"C-k" #'selectrum-previous-candidate
"s-@" #'selectrum-previous-candidate
"<mouse-4>" #'selectrum-previous-candidate
"C-l" #'selectrum-insert-current-candidate
"<ESC>" #'exit-minibuffer)))
(use-package! marginalia
:init
(marginalia-mode)
(setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light)))
(use-package! consult
:init
(map! (:leader
(:prefix ("f" . "files")
:desc "Recent files" "r" #'consult-recent-file)
(:prefix ("s" . "search")
"s" #'consult-line)
(:prefix ("b" . "buffer")
"b" #'consult-buffer
"o" #'consult-buffer-other-window))
"s-\'" #'consult-buffer
"M-y" #'consult-yank)
:config
(setq consult-preview-key nil))
(use-package app-launcher)
(use-package! consult-selectrum
:after consult)
(use-package embark
:config
(map! "s-;" #'embark-act)
;; For Selectrum users:
(setq embark-action-indicator
(lambda (map)
(which-key--show-keymap "Embark" map nil nil 'no-paging)
#'which-key--hide-popup-ignore-command)
embark-become-indicator embark-action-indicator)
(defun current-candidate+category ()
(when selectrum-is-active
(cons (selectrum--get-meta 'category)
(selectrum-get-current-candidate))))
(add-hook 'embark-target-finders #'current-candidate+category)
(defun current-candidates+category ()
(when selectrum-is-active
(cons (selectrum--get-meta 'category)
(selectrum-get-current-candidates
;; Pass relative file names for dired.
minibuffer-completing-file-name))))
(add-hook 'embark-candidate-collectors #'current-candidates+category)
;; No unnecessary computation delay after injection.
(defun shrink-selectrum ()
(when (eq embark-collect--kind :live)
(with-selected-window (active-minibuffer-window)
(setq-local selectrum-num-candidates-displayed 1)
(setq-local selectrum-display-style
'(horizontal :before-candidates "[" :after-candidates "]"
:more-candidates "" :candidates-separator "")))))
(add-hook 'embark-collect-mode-hook #'shrink-selectrum) (add-hook 'embark-setup-hook 'selectrum-set-selected-candidate))
(use-package consult-spotify
:load-path "~/.config/doom/espotify/"
:init
(load! "~/.config/doom/private.el"))(use-package bongo
:disabled t
:custom
(bongo-enabled-backends . '(mpv))
:config
(map!
(:map dired-mode-map
:localleader
"m" #'bongo-dired-play-line)
(:map emms-playlist-mode-map
:n "q" #'emms-playlist-mode-bury-buffer)
(:leader
(:prefix ("e" . "emms")
"j" #'bongo-next
"k" #'bongo-previous
"s" #'bongo-stop
"e" #'bongo-pause/resume
"S" #'bongo-play-random))))(use-package! smudge)(use-package espotify
:load-path "./espotify"
:init
(load! "private.el" )
(setq espotify-use-system-bus-p nil)
(setq espotify-service-name "spotify")
(map! (:leader
(:prefix ("a" . "audio")
:desc "pause spotify" "a" #'espotify-play-pause
:desc "next spotify track" "j" #'espotify-next
:desc "previous spotify track" "k" #'espotify-previous))))Emms is a huge package that helps you manage your media files like movies,
music, playlists and streams. You need an external player to play the media
since Emacs is not capable of such feature. My player of choice is mpv, along
with youtube-dl for content hosted on youtube.
(use-package! emms
:init
(setq emms-source-file-default-directory "~/Audio/Musique/")
(setq emms-streams-file "~/.config/doom/emms/streams.emms")
(setq emms-playlist-buffer-name "*Music*")
(setq emms-info-asynchronously t) ; update tags asynchronously)
(setq emms-source-file-directory-tree-function 'emms-source-file-directory-tree-find)
;;emms-player-list '(emms-player-mpg321 emms-player-ogg123 emms-player-mplayer-playlist emms-player-mplayer emms-player-mpv emms-player-vlc emms-player-vlc-playlist)
(setq emms-player-list '(emms-player-mplayer emms-player-mpv))
;(setq emms-mode-line-mode-line-function nil)
(setq emms-player-mpv-parameters '("--quiet" "--really-quiet" "--no-audio-display"))
(defun lg/find-music-directory ()
(interactive)
(find-file "~/Audio/Musique"))
(map!
(:map emms-playlist-mode-map
:n "q" #'emms-playlist-mode-bury-buffer)
(:map dired-mode-map
:localleader
"m" #'emms-play-dired
"M" #'emms-add-dired)
(:leader
(:prefix ("e" . "emms")
"j" #'emms-next
"k" #'emms-previous
"s" #'emms-stop
"e" #'emms-pause
"S" #'emms-shuffle
"a" #'emms-show-all
"b" #'lg/find-music-directory
"m" #'emms
:desc "radio / streams" "r" #'emms-streams)))
:config
(emms-all)
(defun lg/emms-kill-mpv ()
(interactive)
(shell-command "killall mpv"))
(setq emms-info-functions '(emms-info-mp3info emms-info-cueinfo))
(add-hook 'emms-player-stopped-hook #'lg/emms-kill-mpv))Here is the file that contains all the streams that I listen to (radios), all defined here and tangled to the right file.
;;; This is an EMMS playlist file
;; This includes the built-in list of streams which come with Emms by
;; default. Emms has no affiliation of any kind with the streaming
;; audio stations listed below, nor is this an endorsement of these
;; stations. Instead, this is a collection of stations submitted to
;; the project over the years by people who enjoy Emms. We hope you
;; will enjoy them too.
;; DO NOT EDIT HERE, THIS FILE WAS TANGLED FROM THE CONFIG.ORG FILE
((*track* (type . streamlist) (name . "http://www.somafm.com/beatblender.pls") (metadata "SomaFM: Beatblender" "http://www.somafm.com/beatblender.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://www.somafm.com/secretagent.pls") (metadata "SomaFM: Secret Agent" "http://www.somafm.com/secretagent.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://www.somafm.com/groovesalad.pls") (metadata "SomaFM: Groove Salad" "http://www.somafm.com/groovesalad.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://www.somafm.com/dronezone.pls") (metadata "SomaFM: Drone Zone" "http://www.somafm.com/dronezone.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://www.somafm.com/tagstrance.pls") (metadata "SomaFM: Tag's Trance" "http://www.somafm.com/tagstrance.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://www.somafm.com/indiepop.pls") (metadata "SomaFM: Indie Pop Rocks" "http://www.somafm.com/indiepop.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://www.somafm.com/doomed.pls") (metadata "SomaFM: Doomed" "http://www.somafm.com/doomed.pls" 1 streamlist))
(*track* (type . url) (name . "http://listen.radionomy.com:80/-PHILOSOMATIKAPROGRESSIVE-") (metadata "P H I L O S O M A T I K A - Progressive Psytrance" "http://listen.radionomy.com:80/-PHILOSOMATIKAPROGRESSIVE-" 1 url))
(*track* (type . streamlist) (name . "http://www.bassdrive.com/BassDrive.m3u") (metadata "Drum and Bass Radio, BassDrive" "http://www.bassdrive.com/BassDrive.m3u" 1 streamlist))
(*track* (type . streamlist) (name . "http://www.ibiblio.org/wcpe/wcpe.pls") (metadata "WCPE, Classical Music" "http://www.ibiblio.org/wcpe/wcpe.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://stream.nute.net/kohina/stream.ogg.m3u") (metadata "Kohina - Old school game and demo music" "http://stream.nute.net/kohina/stream.ogg.m3u" 1 streamlist))
(*track* (type . streamlist) (name . "http://privat.is-by.us:8000/necta192.mp3.m3u") (metadata "Nectarine, Demoscene Radio, DE Continuum's relay 192 mp3" "http://privat.is-by.us:8000/necta192.mp3.m3u" 1 streamlist))
(*track* (type . streamlist) (name . "http://nectarine.from-de.com/necta192.m3u") (metadata "Nectarine, Demoscene Radio, DE stream (High Bitrate)" "http://nectarine.from-de.com/necta192.m3u" 1 streamlist))
(*track* (type . streamlist) (name . "http://www.wfmu.org/wfmu.pls") (metadata "WFMU, Freeform radio" "http://www.wfmu.org/wfmu.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://wfmu.org/wfmu_rock.pls") (metadata "WFMU, Rock'n'Soul Ichiban!" "http://www.wfmu.org/wfmu.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://wfmu.org/wfmu_drummer.pls") (metadata "WFMU, Give the Drummer Radio" "http://www.wfmu.org/wfmu.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://wfmu.org/wfmu_sheena.pls") (metadata "WFMU, Sheena's Jungle Room" "http://www.wfmu.org/wfmu.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://nyc01.egihosting.com:6232/listen.pls") (metadata "WBCR-LP - Berkshire Community Radio" "http://nyc01.egihosting.com:6232/listen.pls" 1 streamlist))
(*track* (type . streamlist) (name . "http://199.244.85.125:8000/wxhq1") (metadata "WXHQ-LP - Newport Radio" "http://199.244.85.125:8000/wxhq1" 1 streamlist))
(*track (type . url) (name . "http://direct.franceinter.fr/live/franceinter-lofi.mp3"))
(*track (type . url) (name . "http://direct.franceinter.fr/live/franceinter-midfi.mp3")))Mpv helper functions.
(defun mpv-v-open (url)
"Watch a video from URL in MPV"
(async-shell-command (format "mpv %s" url)
(format "*mpv %s*" url))
(switch-to-buffer-other-window (format "*mpv %s*" url)))
(defun mpv-a-open (url)
"Listen to a video from URL in MPV"
(async-shell-command (format "mpv %s --no-video" url)
(format "*mpv %s*" url))
(switch-to-buffer-other-window (format "*mpv %s*" url)))Ytel is a youtube frontend for Emacs. It is a rather new tool as of writing
these lines. It uses the invidious api (calling it through curl), and an
instance of the API has to be chosen. Instances might come and go, so it might
be necessary to check the available instances.
(use-package! ytel
:commands ytel
:hook (ytel-mode . (lambda () (interactive) (evil-snipe-local-mode -1)))
:init
(map! (:leader (:prefix ("o" . "open")
:desc "ytel (youtube client)" "y" #'ytel)))
(evil-define-key 'normal ytel-mode-map
"q" #'ytel-quit
"v" #'ytel-watch
"a" #'ytel-listen
"V" #'ytel-watch-later
"A" #'ytel-listen-later
"J" #'ytel-search-next-page
"K" #'ytel-search-next-page
"s" #'ytel-search
(kbd "RET") #'ytel-show
"Y" #'ytel-yank-channel-feed)
:config
(defvar ytel-mpv-listen-bool nil "Whether we want to only
listen or not")
(defun ytel-watch ()
"Stream video at point in mpv."
(interactive)
(when ytel-mpv-listen-bool
(shell-command "killall mpv")
(setq emms-player-mpv-parameters '("--quiet" "--really-quiet" "--no-audio-display"))
(setq ytel-mpv-listen-bool nil))
(let* ((video (ytel-get-current-video))
(id (ytel-video-id video))
(video-api-url (emms-play-url (concat "https://invidio.us/watch?v=" id))))))
(defun ytel-listen ()
"Stream video at point in mpv."
(interactive)
(unless ytel-mpv-listen-bool
(shell-command "killall mpv")
(setq emms-player-mpv-parameters '("--quiet" "--really-quiet" "--vid=no"))
(setq ytel-mpv-listen-bool t))
(let* ((video (ytel-get-current-video))
(id (ytel-video-id video))
;;(video-api-url (mpv-a-open (concat "https://invidio.us/watch?v=" id))))))
(video-api-url (emms-play-url (concat "https://invidio.us/watch?v=" id))))))
(defun ytel-yank-channel-feed (&optional arg)
"Yank channel's Invidious RSS feed for the current video at point.
If ARG is given, format it as a Youtube RSS feed."
(interactive "P")
(let* ((author (ytel-video-author (ytel-get-current-video)))
(authorId (ytel-video-authorId (ytel-get-current-video)))
(url (if arg
(concat "https://invidio.us/feed/channel/" authorId)
(concat "https://www.youtube.com/feeds/videos.xml?channel_id=" authorId))))
(kill-new url)
(message "Copied RSS feed for: %s -- %s" author url)))
(setq! ytel-invidious-api-url "https://invidious.snopyta.org"))
;; (setq! ytel-invidious-api-url "https://invidious.tube"))(use-package ytel-show
:after ytel
:config
(setq ytel-show-image-max-height 150
ytel-show-image-max-width 300))(use-package ytdious
:after ytel
:config
(setq ytdious-invidious-api-url ytel-invidious-api-url))(after! elfeed
(progn
(use-package lg-elfeed
:load-path "lisp")
(map!
(:map elfeed-search-mode-map
:n "v" #'elfeed-view-mpv
:n "a" #'elfeed-listen-mpv)
(:map elfeed-show-mode-map
:n "v" #'elfeed-view-mpv
:n "a" #'elfeed-listen-mpv))))
(map!
(:leader
(:prefix ("o" . "open")
:desc "El[f]eed" "f" #'elfeed
:desc "El[F]eed update" "F" #'elfeed-update)))(use-package rg :commands rg)(when (featurep! :ui treemacs)
(map! (:leader
(:prefix ("t" . "toggle")
:desc "Treemacs" "T" #'treemacs)))
(setq treemacs-width 20))
(after! treemacs
(dolist (face '(treemacs-root-face
treemacs-git-unmodified-face
treemacs-git-modified-face
treemacs-git-renamed-face
treemacs-git-ignored-face
treemacs-git-untracked-face
treemacs-git-added-face
treemacs-git-conflict-face
treemacs-directory-face
treemacs-directory-collapsed-face
treemacs-file-face
treemacs-tags-face))
(set-face-attribute face nil :family (face-attribute 'default :family))))I tend to switch back and forth between vterm and eshell a lot, so I try to keep a nice configuration for both.
Eshell has superb integration with Emacs. It’s no surprise, it’s written in
Elisp, but I like how it’s able to hook into emacs to improve some commands.
Take man for instance, if you use it in eshell, you will actually use the
man page reader built into emacs. I want to be able to do similar things in
any shell. The way to go is to write aliases that call emacsclient with the
right functions and arguments.
Interface to yt-download.
(use-package ytdl
:init
(setq ytdl-music-folder "~/Musique"
ytdl-video-folder "~/Vidéos"))Interface to disk-usage.
function du(){
if [ $# -eq 0 ]
then
emacsclient -e "(call-interactively #'disk-usage)"
else
case $1 in
/*) emacsclient -e "(disk-usage $1)";;
*) emacsclient -e "(disk-usage \"$PWD/$1\")";;
esac
fi
}Interface to man page reader
function man(){
if [ $# -eq 0 ]
then
emacsclient -e "(call-interactively #'man)"
else
emacsclient -e "(man $1)"
fi
}function info(){
if [ $# -eq 0 ]
then
emacsclient -e "(call-interactively #'info)"
else
emacsclient -e "(info $1)"
fi
}Vterm is really nice, I like it.
(use-package! vterm
:defer t
:init
(setq vterm-shell "zsh")
(setq vterm-always-compile-module t)
(setq vterm-module-cmake-args "-DUSE_SYSTEM_VTERM=YES")
(map! "s-<return>" #'+vterm/toggle)
:config
(set-popup-rule! "^vterm" :ignore t) )In most cases, eshell is sufficient for all my needs. It works really well, and another advantage is that it works cross platforms. I only have linux on my computer but it’s nice for emacs users on windows out there !
(after! eshell
(setq eshell-kill-on-exit nil)
(setq eshell-kill-processes-on-exit nil))This package provide completion thanks to fish.
(use-package fish-completion
:disabled
:after eshell
:config
(global-fish-completion-mode))EWW stands for the Emacs Web Wowser, and it is a web browser written in emacs
lisp. It relies on shr (simple html renderer), and is only capable of
rendering you guessed it : html. I find myself using it more and more, as it
is really lightweight, and is a really nice interface to read online
documentation, as you can easily copy and paste the snippets to your project.
(use-package eww
:commands (eww eww-browse-with-history)
:init
(map! (:leader
:prefix ("o" . "open")
:desc "eww" "w" #'eww-browse-with-history)
(:map eww-link-keymap
;"v" #'eww-mpv-video-at-point
"a" #'eww-mpv-audio-at-point
"C-j" #'eww-next-url
"C-k" #'eww-previous-url))
:config
(setq eww-download-directory "~/Téléchargements/eww/")
(setq eww-desktop-data-save '(:url :title))
(add-hook 'eww-after-render-hook #'prot-eww--rename-buffer)
(advice-add 'eww-back-url :after #'prot-eww--rename-buffer)
(advice-add 'eww-forward-url :after #'prot-eww--rename-buffer)
(use-package lg-eww
:load-path "lisp"))Elpher is a gopher and gemini client for Emacs.
(use-package elpher
:commands elpher)(use-package webkit)(package! matlab-mode);;;###autoload
(defun +matlab/open-repl ()
"Open the Matlab REPL."
(interactive)
(if (string= (buffer-name) *MATLAB*)
(matlab-shell)
(pop-to-buffer *MATLAB*)))
(use-package! matlab-shell
:config
(setq matlab-shell-command "~/MATLAB/R2020b/bin/matlab")
(setq matlab-shell-command-switches '("-nosplash" "-nodesktop"))
(set-repl-handler! 'matlab-mode #'+matlab/open-repl :persist t))
(use-package! ob-octave
:config
(setq org-babel-matlab-shell-command "~/MATLAB/R2020b/bin/matlab -nosplash -nodesktop"))
(use-package! matlab
:config
(map! :map matlab-mode-map
:v "gr" #'matlab-shell-run-region-or-line
:n "gr" #'matlab-shell-run-region-or-line))(after! python
(set-repl-handler! 'python-mode #'+python/open-ipython-repl :persist t))This is the module for the emacs application framework.
(package! epc)
(package! ctable)
(package! deferred)
(package! s)
(package! eaf
:recipe (:host github
:repo "manateelazycat/emacs-application-framework"))(use-package epc :defer t :ensure t)
(use-package ctable :defer t :ensure t)
(use-package deferred :defer t :ensure t)
(use-package s :defer t :ensure t)
(use-package eaf
:load-path "~/.config/emacs/.local/straight/repos/emacs-application-framework" ; Set to "/usr/share/emacs/site-lisp/eaf" if installed from AUR
:after (epc ctable deferred s)
:custom
(eaf-browser-continue-where-left-off t)
:config
(eaf-setq eaf-browser-enable-adblocker "true")
(eaf-bind-key scroll_up "C-n" eaf-pdf-viewer-keybinding)
(eaf-bind-key scroll_down "C-p" eaf-pdf-viewer-keybinding)
(eaf-bind-key take_photo "p" eaf-camera-keybinding)
(eaf-bind-key nil "M-q" eaf-browser-keybinding)) ;; unbind, see more in the Wiki
(use-package eaf-evil
:init
(define-key key-translation-map (kbd "SPC")
(lambda (prompt)
(if (derived-mode-p 'eaf-mode)
(pcase eaf--buffer-app-name
("browser" (if (string= (eaf-call-sync "call_function" eaf--buffer-id "is_focus") "True")
(kbd "SPC")
(kbd eaf-evil-leader-key)))
("pdf-viewer" (kbd eaf-evil-leader-key))
("image-viewer" (kbd eaf-evil-leader-key))
(_ (kbd "SPC")))
(kbd "SPC")))))(after! evil
(map! :n "C-e" #'end-of-line))(map! "M-j" #'drag-stuff-down
"M-k" #'drag-stuff-up
"<key-chord> e r" #'execute-extended-command
(:leader
:desc "Control-x" "x" ctl-x-map
(:prefix ("f" . "file")
"o" #'find-file-other-window
"C-f" #'find-file-other-window)
(:prefix ("o" . "open")
:desc "Spotify" "s" #'lg/run-or-raise-or-dismiss-spotify
:desc "Firefox" "i" #'lg/run-or-raise-or-dismiss-firefox))
(:n "gss" #'avy-goto-char-timer))