readme.org) is my literate emacs configuration.
Every time I save the file, the code blocks get tangled.
By default, they get tangled (in sequence) to ./init.el.
Some blocks override this default (e.g. see the section early-init.el).
This file also is exported to HTML, it can be viewed here. See this section for my configuration. You can access my blog at the same website.
I used DOOM emacs for an year and I was an happy user. One day I woke up with the wish to understand Emacs a little more.After about a week (12/01/2021) I had restored my configuration and in the process I understood better concepts such as:
- hooks
- minor and major modes
- advices
It is still a long journey but I am glad I started it.
Having your configuration inorg-mode has some benefits and some drawbacks.
It adds a layer of abstraction between me and my init.el file, is it worth it?
The main drawback is that it can happen that the org-mode file has a mistake and tangles
an incorrect init.el file. In that case you can’t use your nice bindings but you are
thrown in barebones emacs and you have to C-x C-f your way to the init.el and run
check-parens.
You can also run org-babel-tangle-jump-to-org from the tangled file if you add:
#+PROPERTY: header-args:emacs-lisp :comments link
Another drawback is that a big configuration can be slow to tangle and tangling on save can block emacs.
See this section for a solution to this drawback.
Let’s consider some of the benefits:
- I can export this file to HTML (here)
- People can read this file on Github (here)
- I can comfortably document my configuration (and not from within comments), include links,
shcode blocks, etc. - I can organize my configuration blocks in sections, easily disable some headings with
COMMENT
lc/tangle-config, you can read source code in this section.
Every time I save this .org file, it is tangled to multiple .el files.
I achieve that by means of this file’s “local variables”, which I put at the end of the .org file:
# Local Variables:
# eval: (add-hook 'after-save-hook (lambda ()(progn (lc/org-add-ids-to-headlines-in-file) (lc/tangle-config))) nil t)
# End:
To design modules, I look at blocks in my config that I would like to toggle on and off.
For example if I am on an iPad I may want to not load anything related to Python or vterm.
I assign org properties to each heading. These are determine which .el file they will be britten to.
For example the header of the section concerning lsp-mode has the following properties:
:PROPERTIES:
:CUSTOM_ID: h:6BC08822-D2B3-4BE9-9EBE-C42F89F0E688
:header-args: :emacs-lisp :tangle ./lisp/init-prog-lsp.el
:END:
All subheadings under it will “inherit” those properties and will be tangled to the same file.
We also need to write some emacs-lisp at the end of the tanged file to “provide” those modules.
Here an example of one of these “footer” headers.
I then have a lean init.el (written in this section) which I use to control which modules I want to use in my session.
On my main computer I typically want to enable all of them.
org file as template.
You can duplicate this file, give it another name and tangle that file to your init.el.
I would start with a “small” configuration, just with the “core” functionalities. For example the Startup, the Package manager and general sections would be a good starting point.
Then, you can start importing “sections” you are curious about, for example Completion framework .
You could also COMMENT all headings and uncomment only those which are interesting to you.
You could find the org-toggle-comment command useful, after selecting all headings in the file.
- In the second section some optimization of startup time, mostly stolen from smart people.
- In the third section we bootstrap
straightanduse-package, our package managers - In the fourth section we configure
emacswith sane defaults and extend some its core features (e.g.help-mode) - In the fifth section we set up
general, which we use to manage our keybindings and lazy loading of packages. Afterwards we configureevil, for modal editing. - In the sixth section the invaluable
org-modewith several extensions - The remaining sections declare my personal configuration of UI and core packages, leveraging the great tools described in this list.
- They improve my productivity considerably
- They are non-standard solutions (or at least hard to find online)
- They are particularly fine-tuned to my workflow
Here they are, without any ranking:
- general
- eval operator
- evil-indent-plus
- evil-iedit-state
- evil-mc
- org mode
- ob-jupyter
- org-tree-slide
- evil-org-mode
- use org-id in links
- org-html-themify
- org-jupyter-mode
- Modus themes
- dashboard
- popup management
- projectile
- hydra-smerge
- envrc
- yasnippet
- dired
- web browser
- lsp mode
- dap-mode
- pytest
- jupyter
- evil-lisp state
- Adjust window size (transient)
;;; early-init.el --- Early Init File -*- lexical-binding: t; no-byte-compile: t -*-
;; NOTE: early-init.el is now generated from readme.org. Please edit that file instead
;; Defer garbage collection further back in the startup process
(setq gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.6)
;; In Emacs 27+, package initialization occurs before `user-init-file' is
;; loaded, but after `early-init-file'. Doom handles package initialization, so
;; we must prevent Emacs from doing it early!
(setq package-enable-at-startup nil)
;; Do not allow loading from the package cache (same reason).
(setq package-quickstart nil)
;; Prevent the glimpse of un-styled Emacs by disabling these UI elements early.
(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)
;; Resizing the Emacs frame can be a terribly expensive part of changing the
;; font. By inhibiting this, we easily halve startup times with fonts that are
;; larger than the system default.
(setq frame-inhibit-implied-resize t)
;; Disable GUI elements
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(setq inhibit-splash-screen t)
(setq use-file-dialog nil)
;; Prevent unwanted runtime builds in gccemacs (native-comp); packages are
;; compiled ahead-of-time when they are installed and site files are compiled
;; when gccemacs is installed.
(setq comp-deferred-compilation nil)
;;; early-init.el ends here;;; init.el --- Personal configuration file -*- lexical-binding: t; no-byte-compile: t; -*-
;; NOTE: init.el is now generated from readme.org. Please edit that file instead
;; `file-name-handler-alist' is consulted on every `require', `load' and various
;; path/io functions. You get a minor speed up by nooping this. However, this
;; may cause problems on builds of Emacs where its site lisp files aren't
;; byte-compiled and we're forced to load the *.el.gz files (e.g. on Alpine)
(unless (daemonp)
(defvar doom--initial-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)
;; Restore `file-name-handler-alist' later, because it is needed for handling
;; encrypted or compressed files, among other things.
(defun doom-reset-file-handler-alist-h ()
;; Re-add rather than `setq', because changes to `file-name-handler-alist'
;; since startup ought to be preserved.
(dolist (handler file-name-handler-alist)
(add-to-list 'doom--initial-file-name-handler-alist handler))
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
(add-hook 'emacs-startup-hook #'doom-reset-file-handler-alist-h)
(add-hook 'after-init-hook '(lambda ()
;; restore after startup
(setq gc-cons-threshold 16777216
gc-cons-percentage 0.1)))
)
;; Ensure Doom is running out of this file's directory
(setq user-emacs-directory (file-truename (file-name-directory load-file-name)));; (add-to-list 'load-path "~/.emacs.d/lisp/")
(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
(let ((file-name-handler-alist nil)
(gc-cons-threshold 100000000))
(require 'init-core)
(require 'init-ui-extra)
(require 'init-org-roam)
(require 'init-org-export)
(require 'init-prog-vterm)
(require 'init-prog-nix)
(require 'init-prog-lsp)
(require 'init-prog-python)
(require 'init-prog-jupyter)
(require 'init-prog-elisp)
(require 'init-prog-markdown)
(require 'init-prog-stan)
;; (require 'init-prog-r)
(require 'init-prog-clojure)
(require 'init-prog-tree-sitter)
(require 'init-extra-focus)
(require 'init-extra-web)
;; (require 'init-extra-rss)
;; (require 'init-extra)
)
;;; init.el ends here- Prefer
:initto:custom. Prefer multiplesetqexpressions to one. - Default to
:defer t, use:demandto force loading - When packages do not require installation e.g.
dired, we need:straight (:type built-in) - If you specify
:commands, they will be autoloaded and the package will be loaded when the commands are first executed- If you use
:generaland bind commands to keys it will automatically load the package on first invokation
- If you use
NOTE: if you change a package recipe from melpa to github in a use-package block but
that package is used as a dependency is used in a previous use-package block with a melpa
recipe, you will get a warning. Just make sure to declare the “base” package with the github recipe first.
(setq straight-use-package-by-default t)
(setq straight-vc-git-default-clone-depth 1)
(setq straight-recipes-gnu-elpa-use-mirror t)
;; (setq straight-check-for-modifications '(check-on-save find-when-checking))
(setq straight-check-for-modifications nil)
(setq use-package-always-defer t)
(defvar bootstrap-version)
(let* ((straight-repo-dir
(expand-file-name "straight/repos" user-emacs-directory))
(bootstrap-file
(concat straight-repo-dir "/straight.el/bootstrap.el"))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(shell-command
(concat
"mkdir -p " straight-repo-dir " && "
"git -C " straight-repo-dir " clone "
"https://github.com/raxod502/straight.el.git && "
"git -C " straight-repo-dir " checkout 2d407bc")))
(load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package)
;; This is a variable that has been renamed but straight still refers when
;; doing :sraight (:no-native-compile t)
(setq comp-deferred-compilation-black-list nil)M-x straight-freeze-versions to write the file straight/versions/default.el.
The content of the file can then be kept in a code block, under version control.
The code block can then be tangle again to straight/versions/default.el.
We can then restore package versions using M-x straight-thaw-versions.
(("Emacs-wgrep" . "f9687c28bbc2e84f87a479b6ce04407bb97cfb23")
("ace-window" . "0577c426a9833ab107bab46c60d1885c611b2fb9")
("all-the-icons-completion" . "9e7d456b0934ecb568b6f05a8445e3f4ce32261f")
("all-the-icons-dired" . "147ed0dfd1034a686795a08dc63e2c293128597e")
("all-the-icons.el" . "65c496d3d1d1298345beb9845840067bffb2ffd8")
("annalist.el" . "134fa3f0fb91a636a1c005c483516d4b64905a6d")
("avy" . "ba5f035be33693d1a136a5cbeedb24327f551a92")
("blacken" . "563c744f545552cb92e8e84d5be4e2cdbabc93ca")
("bui.el" . "f3a137628e112a91910fd33c0cff0948fa58d470")
("centered-cursor-mode.el" . "4093821cc9759ca5a3c6e527d4cc915fc3a5ad74")
("cfrs" . "f3a21f237b2a54e6b9f8a420a9da42b4f0a63121")
("code-cells.el" . "8660bdeedee360e5eb632f1eb1356eb09d7dfbee")
("consult" . "47c4f405efdf4692c6b7e1dd2098573db9aeae6c")
("corfu" . "c8e6607c90a89ff19062cd37afc17e8bbb86aba3")
("csv-mode" . "43f6106f0d4e21a18b5b7d7708d641d50fbdfa0b")
("dap-mode" . "f918c0580bd17105cbe50aa701a2375abca5a6ab")
("darkroom" . "27b928a6e91c3207742180f7e209bae754c9c1fe")
("dash.el" . "da167c51e9fd167a48d06c7c0ee8e3ac7abd9718")
("devdocs.el" . "4257e59dafbffb2616d240f84c5c25770ee28cac")
("diff-hl" . "4a08b02afec1fc6b1e84de46cc34f75f6c9c3bcc")
("dired-hacks" . "7c0ef09d57a80068a11edc74c3568e5ead5cc15a")
("dired-hide-dotfiles" . "6a379f23f64045f5950d229254ce6f32dbbf5364")
("docker-tramp.el" . "930d7b46c180d8a13240a028c1b40af84f2a3219")
("doom-modeline" . "edf18b93cceb5cf00e1006d0034663ef4d9fdc11")
("el-get" . "9353309744e4f8a7c9b1adf22ec99536fb2146b0")
("eldoc" . "eab3f2590621c6559cb92a5edc519fc7e51ef850")
("elisp-refs" . "8f84280997d8b233d66fb9958a34b46078c58b03")
("elisp-tree-sitter" . "5e1091658d625984c6c5756e3550c4d2eebd73a1")
("emacs-async" . "c78bab7506a70a735d2c3deab13fa87bf44a83d3")
("emacs-bind-map" . "510a24138d8de3b8df0783f1ac493a551fc9bd74")
("emacs-dashboard" . "1d3fce6e8e8605f770f2b23184b055029128c477")
("emacs-hide-mode-line" . "bc5d293576c5e08c29e694078b96a5ed85631942")
("emacs-jupyter" . "0a7055d7b12cf98723110415b08ee91869fa7d94")
("emacs-libvterm" . "a940dd2ee8a82684860e320c0f6d5e15d31d916f")
("emacs-python-pytest" . "ea53891a219659d9339220d5db50a8c525f199af")
("emacs-undo-fu" . "e81c8da4416b15cac9d5ac7574e11471417a65ca")
("emacs-web-server" . "22ce66ea43e0eadb9ec1d691a35d9695fc29cee6")
("emacs-websocket" . "82b370602fa0158670b1c6c769f223159affce9b")
("emacs-which-key" . "1217db8c6356659e67b35dedd9f5f260c06f6e99")
("emacs-winum" . "c5455e866e8a5f7eab6a7263e2057aff5f1118b9")
("emacs-zmq" . "38dc6c4119aee57666caf8f97c8a3d7f678823e0")
("emacsmirror-mirror" . "75b9477acee5ab4bf6f404d6d6700d0524cdb4e3")
("emacsql" . "374726060d74df0e2bcb9d0355ff41e2c400ed30")
("embark" . "b80d96ce0ab79e73829322e46c6d7493eb2b8c34")
("envrc" . "57d78f0138d9c676dff182e713249ad055ccf85d")
("epl" . "78ab7a85c08222cd15582a298a364774e3282ce6")
("eros" . "dd8910279226259e100dab798b073a52f9b4233a")
("evil" . "3e41a823334abbba9cf16e482855699054d9dfe0")
("evil-cleverparens" . "8c45879d49bfa6d4e414b6c1df700a4a51cbb869")
("evil-collection" . "e55718869252a8cd46e61e350bb514194a37f2f8")
("evil-goggles" . "8f20a16e74016f37ad76dc4f2230d9b00c6df3c2")
("evil-iedit-state" . "93e4cbfcee802adbb9dd0ebd5836fea4fa932849")
("evil-indent-plus" . "b4dacbfdb57f474f798bfbf5026d434d549eb65c")
("evil-lisp-state" . "3c65fecd9917a41eaf6460f22187e2323821f3ce")
("evil-mc" . "63fd2fe0c213a4cc31c464d246f92931c4cb720f")
("evil-nerd-commenter" . "42ba1a473b4f1df061baddd2f8b812a2f35e366e")
("evil-org-mode" . "a9706da260c45b98601bcd72b1d2c0a24a017700")
("evil-snipe" . "a79177df406a79b4ffa25743c752f21363bba1cc")
("evil-surround" . "282a975bda83310d20a2c536ac3cf95d2bf188a5")
("exec-path-from-shell" . "3a8d97c096c2c5714b667130fd8a80d5622ee067")
("f.el" . "50af874cd19042f17c8686813d52569b1025c76a")
("flycheck" . "278d0810f05eb03600d835c2bdd67d6b55a58034")
("gcmh" . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")
("general.el" . "9651024e7f40a8ac5c3f31f8675d3ebe2b667344")
("git-timemachine" . "ca09684e94767cc0b2339b77b778b4de4f9d104f")
("gnu-elpa-mirror" . "bc03f8141c285538418daeff450f67d90ead2403")
("goto-chg" . "278cd3e6d5107693aa2bb33189ca503f22f227d0")
("helpful" . "67cdd1030b3022d3dc4da2297f55349da57cde01")
("highlight-indent-guides" . "cf352c85cd15dd18aa096ba9d9ab9b7ab493e8f6")
("hl-todo" . "c0f0555a6b9f3818f29e6394db0b45d6d5675edf")
("ht.el" . "c4c1be487d6ecb353d07881526db05d7fc90ea87")
("hydra" . "9e9e00cb240ea1903ffd36a54956b3902c379d29")
("iedit" . "27c61866b1b9b8d77629ac702e5f48e67dfe0d3b")
("imenu-list" . "76f2335ee6f2f066d87fe4e4729219d70c9bc70d")
("inheritenv" . "7e4c8b0d0a43b6f1c6c4d6dbd2f3bf5ce7f20067")
("isearch-mb" . "e70ba8f594afef989006493dd71bd693a29e9f42")
("kind-icon" . "6e0e0c5c2f846685861ef6c157044b1a55572359")
("let-alist" . "592553db5929b54db40af0df90c5add0aaca045b")
("lsp-mode" . "95a5270ff783af063392286e8f45cf338c5a9765")
("lsp-pyright" . "fa6698a6e33880feb16d264172aa665d14cb8a6f")
("lsp-treemacs" . "72d367757a89453a712f6ba1df9b6e789ece2bbd")
("lsp-ui" . "96b1ecbfbf87a775f05b5f0b55253376a3bd61e7")
("magit" . "b1702991eec2c068d282fc2f1bd665726a14e10d")
("marginalia" . "e63d27e6fb24ed16339de9d813c555d40aa1e4ca")
("markdown-mode" . "521658eb32e456681592443e04ae507c3a59ed07")
("melpa" . "1a054aba2409fb8ae12a634952f3d1336a14eb70")
("modus-themes" . "03f7046dff86c5342af778ad3f9850af7e950aed")
("nix-mode" . "20ee8d88900b169831d6b0783bd82d2625e940c7")
("no-littering" . "13414b7a294fa6f35bbeb535cdcab6b256e39da7")
("ob-async" . "9aac486073f5c356ada20e716571be33a350a982")
("olivetti" . "a31ac05a161a91fe5c157930b62a6c07037982ee")
("orderless" . "f2c78c4a6059c5f892e48a3887d4368a547515ff")
("org" . "6304afcaa40a29291bc0705f8527e0ab75f7b807")
("org-appear" . "ffbd742267ff81ba8433177fac5d7fe22b6d68a9")
("org-fragtog" . "680606189d5d28039e6f9301b55ec80517a24005")
("org-reverse-datetree" . "c42078f8601b7f600135f66e75246a53c5f9975f")
("org-roam" . "d71675fb479d11da3ae597bb13bc1c96256ff0b0")
("org-superstar-mode" . "03be6c0a3081c46a59b108deb8479ee24a6d86c0")
("org-tree-slide" . "3faa042393ebfe5699a3bffce775f039d7416ceb")
("paredit" . "8330a41e8188fe18d3fa805bb9aa529f015318e8")
("persistent-scratch" . "4e159967801b75d07303221c4e5a2b89039c6a11")
("persp-projectile" . "4e374d7650c7e041df5af5ac280a44d4a4ec705a")
("perspective-el" . "d3afc52ed098b713b6607943bd1ee0ef899db267")
("pfuture" . "bde5b06795e3e35bfb2bba4c34b538d506a0856e")
("pkg-info" . "76ba7415480687d05a4353b27fea2ae02b8d9d61")
("posframe" . "c91d4d53fa479ceb604071008ce0a901770eff57")
("projectile" . "20df208385ce7b80207602c9931e31094eca85fb")
("python-mode" . "29c6815c585c200eda2541b678e499d06c3e14d2")
("rainbow-delimiters" . "a32b39bdfe6c61c322c37226d66e1b6d4f107ed0")
("restart-emacs" . "1607da2bc657fe05ae01f7fdf26f716eafead02c")
("s.el" . "08661efb075d1c6b4fa812184c1e5e90c08795a9")
("shrink-path.el" . "c14882c8599aec79a6e8ef2d06454254bb3e1e41")
("smartparens" . "37f77bf2e2199be9fe27e981317b02cfd0e8c70e")
("spinner" . "34905eae12a236753fa88abc831eff1e41e8576e")
("straight.el" . "af5437f2afd00936c883124d6d3098721c2d306c")
("svg-lib" . "5ff87b7f9a85e728360a63d8e4ae7aaa7eccf7d3")
("toml-mode.el" . "f6c61817b00f9c4a3cab1bae9c309e0fc45cdd06")
("transient" . "270eff1c7cc910dfe9882e97df608627028eaa40")
("transpose-frame" . "12e523d70ff78cc8868097b56120848befab5dbc")
("tree-sitter-langs" . "f4effc81fcac3592bce7072619a0e17043412cf4")
("treemacs" . "b18a05b1f62074a40e6011d83cd4c92cbee040dd")
("use-package" . "a7422fb8ab1baee19adb2717b5b47b9c3812a84c")
("vertico" . "742c57635eadf74743f0d70b9125c4d2a95e22df")
("vterm-toggle" . "2a6861ef6af91dad4be082139214a30116b50acf")
("with-editor" . "e8569e027ff5c9bef8d9ff0734e3293e1c0574a2")
("xwwp" . "f67e070a6e1b233e60274deb717274b000923231")
("yaml-mode" . "535273d5a1eb76999d20afbcf4d9f056d8ffd2da")
("yasnippet" . "5cbdbf0d2015540c59ed8ee0fcf4788effdf75b6"))use-package-compute-statistics after loading use-package but before any use-package forms,
and then run the command M-x use-package-report to see the results. The buffer displayed
is a tabulated list. You can use S in a column to sort the rows based on it.
(setq use-package-compute-statistics t)From the report:
- dashboard 3.18 (org)
- evil-collection 2.48 (evil)
- projectile 1.67
- devdocs 1.17
To debug a LISP function use debug-on-entry. You step in with d and over with e
(use-package emacs
:init
(setq inhibit-startup-screen t
initial-scratch-message nil
sentence-end-double-space nil
ring-bell-function 'ignore
frame-resize-pixelwise t)
(setq user-full-name "Luca Cambiaghi"
user-mail-address "luca.cambiaghi@me.com")
(setq read-process-output-max (* 1024 1024)) ;; 1mb
;; always allow 'y' instead of 'yes'.
(defalias 'yes-or-no-p 'y-or-n-p)
;; default to utf-8 for all the things
(set-charset-priority 'unicode)
(setq locale-coding-system 'utf-8
coding-system-for-read 'utf-8
coding-system-for-write 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(setq default-process-coding-system '(utf-8-unix . utf-8-unix))
;; write over selected text on input... like all modern editors do
(delete-selection-mode t)
;; enable recent files mode.
(recentf-mode t)
(setq recentf-exclude `(,(expand-file-name "straight/build/" user-emacs-directory)
,(expand-file-name "eln-cache/" user-emacs-directory)
,(expand-file-name "etc/" user-emacs-directory)
,(expand-file-name "var/" user-emacs-directory)))
;; don't want ESC as a modifier
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
;; Don't persist a custom file, this bites me more than it helps
(setq custom-file (make-temp-file "")) ; use a temp file as a placeholder
(setq custom-safe-themes t) ; mark all themes as safe, since we can't persist now
(setq enable-local-variables :all) ; fix =defvar= warnings
;; stop emacs from littering the file system with backup files
(setq make-backup-files nil
auto-save-default nil
create-lockfiles nil)
;; follow symlinks
(setq vc-follow-symlinks t)
;; don't show any extra window chrome
(when (window-system)
(tool-bar-mode -1)
(toggle-scroll-bar -1))
;; enable winner mode globally for undo/redo window layout changes
(winner-mode t)
(show-paren-mode t)
;; less noise when compiling elisp
(setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
(setq native-comp-async-report-warnings-errors nil)
(setq load-prefer-newer t)
;; clean up the mode line
(display-time-mode -1)
(setq column-number-mode t)
;; use common convention for indentation by default
(setq-default indent-tabs-mode t)
(setq-default tab-width 2)
;; Enable indentation+completion using the TAB key.
;; Completion is often bound to M-TAB.
(setq tab-always-indent 'complete)
)(use-package emacs
:init
(setq lc/is-ipad ( ;; <
> (length (shell-command-to-string "uname -a | grep iPad")) 0))
(setq lc/is-windows (eq system-type 'windows-nt))
(defcustom lc/default-font-family "fira code"
"Default font family"
:type 'string
:group 'lc)
(defcustom lc/variable-pitch-font-family "Sans Serif" ;; "cantarell" ;;
"Variable pitch font family"
:type 'string
:group 'lc)
(defcustom lc/laptop-font-size
(if lc/is-windows 100 150)
"Font size used for laptop"
:type 'int
:group 'lc)
(defcustom lc/monitor-font-size
150
"Font size used for laptop"
:type 'int
:group 'lc)
(defcustom lc/theme nil
"Current theme (light or dark)"
:type 'symbol
:options '(light dark)
:group 'lc)
;; (setq lc/is-low-power (string= (system-name) "pntk"))
;; (setq lc/is-slow-ssh (string= (getenv "IS_TRAMP") "true"))
)(use-package emacs
:hook (after-init . lc/set-font-size)
:init
(defun lc/get-font-size ()
"font size is calculated according to the size of the primary screen"
(let* (;; (command "xrandr | awk '/primary/{print sqrt( ($(nf-2)/10)^2 + ($nf/10)^2 )/2.54}'")
(command "osascript -e 'tell application \"finder\" to get bounds of window of desktop' | cut -d',' -f3")
(screen-width (string-to-number (shell-command-to-string command)))) ;;<
(if (> screen-width 2560) lc/monitor-font-size lc/laptop-font-size)))
(defun lc/set-font-size ()
(interactive)
;; Main typeface
(set-face-attribute 'default nil :family lc/default-font-family :height (lc/get-font-size))
;; Set the fixed pitch face (monospace)
(set-face-attribute 'fixed-pitch nil :family lc/default-font-family)
;; Set the variable pitch face
(set-face-attribute 'variable-pitch nil :family lc/variable-pitch-font-family)
;; modeline
(set-face-attribute 'mode-line nil :family lc/default-font-family :height (lc/get-font-size))
(set-face-attribute 'mode-line-inactive nil :family lc/default-font-family :height (lc/get-font-size))
)
)(use-package emacs
:init
(global-set-key (kbd "C-=") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
)(use-package emacs
:init
(defun lc/is-macos ()
(and (eq system-type 'darwin)
(= 0 (length (shell-command-to-string "uname -a | grep iPad")))))
(when (lc/is-macos)
(setq mac-command-modifier 'super) ; command as super
(setq mac-option-modifier 'meta) ; alt as meta
(setq mac-control-modifier 'control)
)
;; when on emacs-mac
(when (fboundp 'mac-auto-operator-composition-mode)
(mac-auto-operator-composition-mode) ;; enables font ligatures
(global-set-key [(s c)] 'kill-ring-save)
(global-set-key [(s v)] 'yank)
(global-set-key [(s x)] 'kill-region)
(global-set-key [(s q)] 'kill-emacs)
)
)(use-package gcmh
:demand
:config
(gcmh-mode 1))(use-package helpful
:after evil
:init
(setq evil-lookup-func #'helpful-at-point)
:bind
([remap describe-function] . helpful-callable)
([remap describe-command] . helpful-command)
([remap describe-variable] . helpful-variable)
([remap describe-key] . helpful-key))(use-package eldoc
:hook (emacs-lisp-mode cider-mode))(use-package exec-path-from-shell
;; :if (memq window-system '(mac ns))
:if (lc/is-macos)
:hook (emacs-startup . (lambda ()
(setq exec-path-from-shell-arguments '("-l")) ; removed the -i for faster startup
(exec-path-from-shell-initialize)))
;; :config
;; (exec-path-from-shell-copy-envs
;; '("GOPATH" "GO111MODULE" "GOPROXY"
;; "NPMBIN" "LC_ALL" "LANG" "LC_TYPE"
;; "SSH_AGENT_PID" "SSH_AUTH_SOCK" "SHELL"
;; "JAVA_HOME"))
)(use-package no-littering
:demand
:config
(with-eval-after-load 'recentf
(add-to-list 'recentf-exclude no-littering-var-directory)
(add-to-list 'recentf-exclude no-littering-etc-directory))
)(use-package emacs
:init
(unless (and (fboundp 'server-running-p) (server-running-p))
(server-start)))(use-package emacs
:hook
((org-jupyter-mode . (lambda () (lc/add-local-electric-pairs '())))
(org-mode . (lambda () (lc/add-local-electric-pairs '(;(?= . ?=)
(?~ . ?~))))))
:init
;; auto-close parentheses
(electric-pair-mode +1)
(setq electric-pair-preserve-balance nil)
;; don't skip newline when auto-pairing parenthesis
(setq electric-pair-skip-whitespace-chars '(9 32))
;; mode-specific local-electric pairs
(defconst lc/default-electric-pairs electric-pair-pairs)
(defun lc/add-local-electric-pairs (pairs)
"Example usage:
(add-hook 'jupyter-org-interaction-mode '(lambda () (set-local-electric-pairs '())))
"
(setq-local electric-pair-pairs (append lc/default-electric-pairs pairs))
(setq-local electric-pair-text-pairs electric-pair-pairs))
;; disable auto pairing for < >
(add-function :before-until electric-pair-inhibit-predicate
(lambda (c) (eq c ?< ;; >
)))
) You can use below block to print the value of electric-pair-pairs
(mapcar (lambda (elm) (char-to-string (car elm))) electric-pair-pairs)(use-package emacs
:init
(defun lc/rename-current-file ()
"Rename the current visiting file and switch buffer focus to it."
(interactive)
(let ((new-filename (lc/expand-filename-prompt
(format "Rename %s to: " (file-name-nondirectory (buffer-file-name))))))
(if (null (file-writable-p new-filename))
(user-error "New file not writable: %s" new-filename))
(rename-file (buffer-file-name) new-filename 1)
(find-alternate-file new-filename)
(message "Renamed to and now visiting: %s" (abbreviate-file-name new-filename))))
(defun lc/expand-filename-prompt (prompt)
"Return expanded filename prompt."
(expand-file-name (read-file-name prompt)))
)
(use-package xref
:straight (:type built-in)
:init
(setq xref-prompt-for-identifier nil) ;; always find references of symbol at point
;; configured in consult
;; (setq xref-show-definitions-function #'xref-show-definitions-completing-read)
;; (setq xref-show-xrefs-function #'xref-show-definitions-buffer) ; for grep and the like
;; (setq xref-file-name-display 'project-relative)
;; (setq xref-search-program 'grep)
)ESC kills my window layout. This advice prevents that from happening.
(use-package emacs
:init
(defadvice keyboard-escape-quit
(around keyboard-escape-quit-dont-close-windows activate)
(let ((buffer-quit-function (lambda () ())))
ad-do-it))
)
general and define bindings for generic commands e.g. find-file.
The commands provided by packages should be binded in the use-package block, thanks to the :general keyword.
NOTE: We need to load general before evil, otherwise the :general keyword in the use-package blocks won’t work.
(use-package general
:demand t
:config
(general-evil-setup)
(general-create-definer lc/leader-keys
:states '(normal insert visual emacs)
:keymaps 'override
:prefix "SPC"
:global-prefix "C-SPC")
(general-create-definer lc/local-leader-keys
:states '(normal visual)
:keymaps 'override
:prefix ","
:global-prefix "SPC m")
(general-nmap
:states 'normal
"gD" '(xref-find-references :wk "references")
)
(lc/leader-keys
"SPC" '(execute-extended-command :which-key "execute command")
"`" '((lambda () (interactive) (switch-to-buffer (other-buffer (current-buffer) 1))) :which-key "prev buffer")
"<escape>" 'keyboard-escape-quit
";" '(eval-expression :which-key "eval sexp")
"b" '(:ignore t :which-key "buffer")
"br" 'revert-buffer
;; "bs" '((lambda () (interactive)
;; (pop-to-buffer "*scratch*"))
;; :wk "scratch")
"bd" 'kill-current-buffer
"c" '(:ignore t :which-key "code")
"f" '(:ignore t :which-key "file")
"fD" '((lambda () (interactive) (delete-file (buffer-file-name))) :wk "delete")
"ff" 'find-file
"fs" 'save-buffer
"fR" '(lc/rename-current-file :wk "rename")
"g" '(:ignore t :which-key "git")
;; keybindings defined in magit
"h" '(:ignore t :which-key "describe")
"he" 'view-echo-area-messages
"hf" 'describe-function
"hF" 'describe-face
"hl" 'view-lossage
"hL" 'find-library
"hm" 'describe-mode
"hk" 'describe-key
"hK" 'describe-keymap
"hp" 'describe-package
"hv" 'describe-variable
"k" '(:ignore t :which-key "kubernetes")
;; keybindings defined in kubernetes.el
"o" '(:ignore t :which-key "org")
;; keybindings defined in org-mode
;; "p" '(:ignore t :which-key "project")
;; keybindings defined in projectile
"s" '(:ignore t :which-key "search")
;; keybindings defined in consult
"t" '(:ignore t :which-key "toggle")
"t d" '(toggle-debug-on-error :which-key "debug on error")
"t l" '(display-line-numbers-mode :wk "line numbers")
"t w" '((lambda () (interactive) (toggle-truncate-lines)) :wk "word wrap")
;; "t +" '(lc/increase-font-size :wk "+ font")
;; "t -" '(lc/decrease-font-size :wk "- font")
;; "t +" 'text-scale-increase
;; "t -" 'text-scale-decrease
;; "t 0" '(lc/reset-font-size :wk "reset font")
"u" '(universal-argument :wk "universal")
"w" '(:ignore t :which-key "window")
"wl" 'windmove-right
"wh" 'windmove-left
"wk" 'windmove-up
"wj" 'windmove-down
"wr" 'winner-redo
"wd" 'delete-window
"w=" 'balance-windows-area
"wD" 'kill-buffer-and-window
"wu" 'winner-undo
"wr" 'winner-redo
"wm" '(delete-other-windows :wk "maximize")
"x" '(:ignore t :which-key "browser")
;; keybindings defined in xwwp
)
(lc/local-leader-keys
:states 'normal
"d" '(:ignore t :which-key "debug")
"e" '(:ignore t :which-key "eval")
"t" '(:ignore t :which-key "test")))Search tricks:
*/ # to go to next/prev occurence of symbol under point/starts a search, usen/Nto go to next/prev- Use the
gnnoun to, for example, change next match withcgn
Some interesting vim nouns:
_- first character in the line (synonym to
^) g_- last character on the line (synonym to
$)
Marks:
ma- mark a position in buffer and save it to register
a 'a- go to mark
a mA- mark position and filename [
]'- go to next mark
''- go back to previous mark (kept track automatically)
g;- go to previous change location
gi- go back to insert mode where you left off
C-o- jump (out) to previous position (useful after
gd) C-i- jump (in) to previous position
Macros:
qq- record macro
q @q- execute macro
q
Registers:
"ayio- save object in register
a” "ap- paste object in register
a”- Macros are saved in registers so you can simply
"qpand paste your macro!! ”
- Macros are saved in registers so you can simply
NOTE: I inserted the above quotes because the single double quotes were breaking my VIM object detection in the rest of the file
(use-package evil
:demand
:general
(lc/leader-keys
"wv" 'evil-window-vsplit
"ws" 'evil-window-split)
:init
(setq evil-want-integration t)
(setq evil-want-keybinding nil)
(setq evil-want-C-u-scroll t)
(setq evil-want-C-i-jump t)
(setq evil-want-Y-yank-to-eol t)
;; (setq evil-respect-visual-line-mode t)
(setq evil-undo-system 'undo-fu)
(setq evil-search-module 'evil-search) ;; enables gn
;; move to window when splitting
(setq evil-split-window-below t)
(setq evil-vsplit-window-right t)
;; (setq-local evil-scroll-count 0)
(setq evil-auto-indent nil)
;; emacs bindings in insert mode
;; (setq evil-disable-insert-state-bindings t)
:config
(evil-mode 1)
(define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state)
(define-key evil-motion-state-map "_" 'evil-end-of-line)
(define-key evil-motion-state-map "0" 'evil-beginning-of-line)
(evil-set-initial-state 'messages-buffer-mode 'normal)
(evil-set-initial-state 'dashboard-mode 'normal)
;; don't move cursor after ==
(defun lc/evil-dont-move-cursor (orig-fn &rest args)
(save-excursion (apply orig-fn args)))
(advice-add 'evil-indent :around #'lc/evil-dont-move-cursor)
;; disable TAB in normal mode to jump forward
;; (with-eval-after-load 'evil-maps
;; (define-key evil-motion-state-map (kbd "TAB") nil))
)(use-package evil-collection
:after evil
:defer 1
:init
(setq evil-collection-magit-use-z-for-folds nil)
:config
(evil-collection-init))gr.
This gives you super powers when coupled with custom text objects (provided by evil-indent-plus and evil-cleverparens )
For example:
grabevals the form at pointgradevals the top-level form (e.g. use-package blocks or functions)grakevals the function inpythongrrevals the line
(use-package evil
:config
(defcustom evil-extra-operator-eval-modes-alist
'((emacs-lisp-mode eros-eval-region)
;; (scheme-mode geiser-eval-region)
(clojure-mode cider-eval-region)
(jupyter-repl-interaction-mode jupyter-eval-line-or-region) ;; when executing in src block
;; (python-mode python-shell-send-region) ;; when executing in org-src-edit mode
)
"Alist used to determine evil-operator-eval's behaviour.
Each element of this alist should be of this form:
(MAJOR-MODE EVAL-FUNC [ARGS...])
MAJOR-MODE denotes the major mode of buffer. EVAL-FUNC should be a function
with at least 2 arguments: the region beginning and the region end. ARGS will
be passed to EVAL-FUNC as its rest arguments"
:type '(alist :key-type symbol)
:group 'evil-extra-operator)
(evil-define-operator evil-operator-eval (beg end)
"Evil operator for evaluating code."
:move-point nil
(interactive "<r>")
(let* ((mode (if (org-in-src-block-p) (intern (car (org-babel-get-src-block-info))) major-mode))
(ele (assoc mode evil-extra-operator-eval-modes-alist))
(f-a (cdr-safe ele))
(func (car-safe f-a))
(args (cdr-safe f-a)))
(if (fboundp func)
(apply func beg end args)
(eval-region beg end t))))
(define-key evil-motion-state-map "gr" 'evil-operator-eval)
)
(use-package evil-goggles
:after evil
:demand
:init
(setq evil-goggles-duration 0.05)
:config
(push '(evil-operator-eval
:face evil-goggles-yank-face
:switch evil-goggles-enable-yank
:advice evil-goggles--generic-async-advice)
evil-goggles--commands)
(evil-goggles-mode)
(evil-goggles-use-diff-faces)
)(use-package evil-snipe
:after evil
:demand
:config
(evil-snipe-mode +1)
(evil-snipe-override-mode +1))(use-package evil-nerd-commenter
:general
(general-nvmap
"gc" 'evilnc-comment-operator
"gC" 'evilnc-copy-and-comment-operator)
)- Use
S)to surround something without spaces e.g.(sexp) - Use
S(to surround something with spaces e.g.( sexp )
)
(use-package evil-surround
:general
(:states 'operator
"s" 'evil-surround-edit
"S" 'evil-Surround-edit)
(:states 'visual
"S" 'evil-surround-region
"gS" 'evil-Surround-region))python:
- Stand on a line in the body of the function (root, not an if)
- Select with
vik
(use-package evil-indent-plus
:after evil
:demand
:config
(define-key evil-inner-text-objects-map "i" 'evil-indent-plus-i-indent)
(define-key evil-outer-text-objects-map "i" 'evil-indent-plus-a-indent)
(define-key evil-inner-text-objects-map "k" 'evil-indent-plus-i-indent-up)
(define-key evil-outer-text-objects-map "k" 'evil-indent-plus-a-indent-up)
(define-key evil-inner-text-objects-map "j" 'evil-indent-plus-i-indent-up-down)
(define-key evil-outer-text-objects-map "j" 'evil-indent-plus-a-indent-up-down)
)- Mark the outer form with
v a f
(use-package evil-cleverparens
:after evil
:hook (emacs-lisp-mode . lc/init-cleverparens)
:init
(defun lc/init-cleverparens ()
(require 'evil-cleverparens-util)
(evil-define-text-object evil-cp-a-defun (count &optional beg end type)
"An outer text object for a top level sexp (defun)."
(if (evil-cp--inside-form-p)
(let ((bounds (evil-cp--top-level-bounds)))
(evil-range (car bounds) (cdr bounds) 'inclusive :expanded t))
(error "Not inside a sexp.")))
(evil-define-text-object evil-cp-inner-defun (count &optional beg end type)
"An inner text object for a top level sexp (defun)."
(if (evil-cp--inside-form-p)
(let ((bounds (evil-cp--top-level-bounds)))
(evil-range (1+ (car bounds)) (1- (cdr bounds)) 'inclusive :expanded t))
(error "Not inside a sexp.")))
(define-key evil-outer-text-objects-map "f" #'evil-cp-a-defun)
(define-key evil-inner-text-objects-map "f" #'evil-cp-inner-defun)
)
)TAB- toggle occurrence
n/N- next/prev occurrence
F- restrict scope to function
J/K- extend scope of match down/up
V- toggle visibility of matches
(use-package evil-iedit-state
:straight (evil-iedit-state :type git :host github :repo "kassick/evil-iedit-state" :branch "master")
:general
(lc/leader-keys
"s e" '(evil-iedit-state/iedit-mode :wk "iedit")
"s q" '(evil-iedit-state/quit-iedit-mode :wk "iedit quit")))(use-package evil-mc
:after evil
:general
(general-nmap
"M-n" #'evil-mc-make-and-goto-next-match
)
(general-vmap
;; "gm" '(:keymap evil-mc-cursors-map)
"A" #'evil-mc-make-cursor-in-visual-selection-end
"I" #'evil-mc-make-cursor-in-visual-selection-beg)
(general-nmap
"gm" '(:keymap evil-mc-cursors-map)
"Q" #'evil-mc-undo-all-cursors
;; "M-p" #'evil-mc-make-and-goto-prev-cursor
)
:config
(global-evil-mc-mode 1)
)(use-package evil
:init
(defun lc/evil-posn-x-y (position)
(let ((xy (posn-x-y position)))
(when header-line-format
(setcdr xy (+ (cdr xy)
(or (and (fboundp 'window-header-line-height)
(window-header-line-height))
evil-cached-header-line-height
(setq evil-cached-header-line-height (evil-header-line-height))))))
(when (fboundp 'window-tab-line-height)
(setcdr xy (+ (cdr xy) (window-tab-line-height))))
xy))
:config
(advice-add 'evil-posn-x-y :override #'lc/evil-posn-x-y)
)(use-package which-key
:demand
:general
(lc/leader-keys
"?" 'which-key-show-top-level
)
:init
(setq which-key-separator " ")
(setq which-key-prefix-prefix "+")
(setq which-key-show-early-on-C-h t)
;; make sure which-key doesn't show normally but refreshes quickly after it is
;; triggered.
(setq which-key-idle-delay 10000)
(setq which-key-idle-secondary-delay 0.05)
:config
(which-key-mode))- If you use + in lists it will show up as below:
- subitem
- you can cycle to next TODO state with
org-shiftright - You can access custom agenda views with
org-agenda, mapped toSPC o A - Yo insert a src block use
, iand then type initials e.g.jpforjupyter-python
(use-package org
;; :straight org-plus-contrib
;; :straight (:type built-in)
:hook ((org-mode . prettify-symbols-mode)
(org-mode . visual-line-mode)
(org-mode . variable-pitch-mode))
:general
(lc/leader-keys
"f t" '(org-babel-tangle :wk "tangle")
"o C" '(org-capture :wk "capture")
"o l" '(org-todo-list :wk "todo list")
"o c" '((lambda () (interactive)
(persp-switch "main")
(find-file (concat user-emacs-directory "readme.org")))
:wk "open config")
)
(lc/local-leader-keys
:keymaps 'org-mode-map
"a" '(org-archive-subtree :wk "archive subtree")
"E" '(org-export-dispatch :wk "export")
"i" '(org-insert-structure-template :wk "insert src")
"l" '(:ignore true :wk "link")
"l l" '(org-insert-link :wk "insert link")
"l s" '(org-store-link :wk "store link")
"L" '((lambda () (interactive) (org-latex-preview)) :wk "latex preview")
;; "L" '((lambda () (interactive) (org--latex-preview-region (point-min) (point-max))) :wk "latex")
"r" '(org-refile :wk "refile")
"n" '(org-toggle-narrow-to-subtree :wk "narrow subtree")
"p" '(org-priority :wk "priority")
"q" '(org-set-tags-command :wk "tag")
"s" '(org-sort :wk "sort")
"t" '(:ignore true :wk "todo")
"t t" '(org-todo :wk "heading todo")
"t s" '(org-schedule :wk "schedule")
"t d" '(org-deadline :wk "deadline")
"x" '(org-toggle-checkbox :wk "toggle checkbox")
)
(org-mode-map
:states 'insert
"TAB" 'lc/org-indent-or-complete
"S-TAB" nil)
(org-mode-map
:states 'normal
"z i" '(org-toggle-inline-images :wk "inline images"))
:init
;; general settings
(when (file-directory-p "~/org")
(setq org-directory "~/org"
+org-export-directory "~/org/export"
org-default-notes-file "~/org/personal/todo.org"
org-id-locations-file "~/org/.orgids"
))
(setq ;; org-export-in-background t
org-src-preserve-indentation t ;; do not put two spaces on the left
org-startup-indented t
;; org-startup-with-inline-images t
org-hide-emphasis-markers t
org-catch-invisible-edits 'smart)
(setq org-image-actual-width nil)
(setq org-indent-indentation-per-level 1)
(setq org-list-demote-modify-bullet '(("-" . "+") ("+" . "*")))
;; disable modules for faster startup
(setq org-modules
'(ol-docview
org-habit))
(setq org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "PROG(p)" "|" "HOLD(h)" "DONE(d)")))
(setq-default prettify-symbols-alist '(("#+BEGIN_SRC" . "»")
("#+END_SRC" . "«")
("#+begin_src" . "»")
("#+end_src" . "«")
("lambda" . "λ")
("->" . "→")
("->>" . "↠")))
(setq prettify-symbols-unprettify-at-point 'right-edge)
(defun lc/org-indent-or-complete ()
"Complete if point is at end of a word, otherwise indent line."
(interactive)
(if (looking-at "\\>")
(dabbrev-expand nil)
(org-cycle)
))
(setq warning-suppress-types (append warning-suppress-types '((org-element-cache))))
:config
;; (efs/org-font-setup)
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(add-to-list 'org-structure-template-alist '("clj" . "src clojure"))
(add-to-list 'org-structure-template-alist '("jp" . "src jupyter-python"))
(add-to-list 'org-structure-template-alist '("jr" . "src jupyter-R"))
;; fontification
(add-to-list 'org-src-lang-modes '("jupyter-python" . python))
(add-to-list 'org-src-lang-modes '("jupyter-R" . R))
;; latex
;; (setq org-latex-compiler "xelatex")
;; see https://www.reddit.com/r/emacs/comments/l45528/questions_about_mving_from_standard_latex_to_org/gkp4f96/?utm_source=reddit&utm_medium=web2x&context=3
;; (setq org-latex-pdf-process '("TEXINPUTS=:$HOME/git/AltaCV//: tectonic %f"))
(setq org-latex-pdf-process '("tectonic %f"))
(setq org-export-backends '(html))
;; (add-to-list 'org-export-backends 'beamer)
(plist-put org-format-latex-options :scale 1.2)
)(use-package org
:config
(defun my-adjoin-to-list-or-symbol (element list-or-symbol)
(let ((list (if (not (listp list-or-symbol))
(list list-or-symbol)
list-or-symbol)))
(require 'cl-lib)
(cl-adjoin element list)))
(eval-after-load "org"
'(mapc
(lambda (face)
(set-face-attribute
face nil
:inherit
(my-adjoin-to-list-or-symbol
'fixed-pitch
(face-attribute face :inherit))))
(list 'org-code 'org-block
;; 'org-table 'org-block-background
)))
)
(use-package org
:general
(lc/leader-keys
"o a" '(org-agenda-list :wk "agenda")
"o A" '(org-agenda :wk "agenda")
"o C" '(org-capture :wk "capture")
"o l" '(org-todo-list :wk "todo list")
"o c" '((lambda () (interactive)
(find-file (concat user-emacs-directory "readme.org")))
:wk "open config")
"o n" '((lambda () (interactive) (org-agenda nil "n")) :wk "next")
"o i" '((lambda () (interactive)
(find-file (concat org-roam-directory "/personal/inbox.org")))
:wk "open todos"))
:init
(setq org-agenda-files '())
;; if roam work folder exists, add to agenda files
(when (file-directory-p "~/roam/work")
(setq org-agenda-files
(append org-agenda-files
'("~/roam/work/todo.org"))))
(when (file-directory-p "~/roam/personal")
(setq org-agenda-files
(append org-agenda-files
'("~/roam/personal/20210721120340-birthdays.org" "~/roam/personal/inbox.org"))))
(setq org-agenda-custom-commands
'(("d" "Dashboard"
((agenda "" ((org-deadline-warning-days 7)))
(todo "NEXT"
((org-agenda-overriding-header "Next Tasks")))
(tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects")))))
("n" "Next Tasks"
((todo "NEXT"
((org-agenda-overriding-header "Next Tasks")))))
("w" "Work Tasks" tags-todo "+work")))
)(use-package org
:init
(setq org-capture-templates
`(("b" "Blog" entry
(file+headline "personal/todo.org" "Blog")
,(concat "* WRITE %^{Title} %^g\n"
"SCHEDULED: %^t\n"
":PROPERTIES:\n"
":CAPTURED: %U\n:END:\n\n"
"%i%?"))
("d" "New Diary Entry" entry(file+olp+datetree"~/org/personal/diary.org" "Daily Logs")
"* %^{thought for the day}
:PROPERTIES:
:CATEGORY: %^{category}
:SUBJECT: %^{subject}
:MOOD: %^{mood}
:END:
:RESOURCES:
:END:
\*What was one good thing you learned today?*:
- %^{whatilearnedtoday}
\*List one thing you could have done better*:
- %^{onethingdobetter}
\*Describe in your own words how your day was*:
- %?")
("i" "Inbox" entry
(file+headline "personal/todo.org" "Inbox")
,(concat "* %^{Title}\n"
":PROPERTIES:\n"
":CAPTURED: %U\n"
":END:\n\n"
"%i%l"))
("u" "New URL Entry" entry
(file+function "~/org/personal/dailies.org" org-reverse-datetree-goto-date-in-file)
"* [[%^{URL}][%^{Description}]] %^g %?")
("w" "Work" entry
(file+headline "personal/todo.org" "Work")
,(concat "* TODO [#A] %^{Title} :@work:\n"
"SCHEDULED: %^t\n"
":PROPERTIES:\n:CAPTURED: %U\n:END:\n\n"
"%i%?"))))
)(use-package org
:init
(defun +org-cycle-only-current-subtree-h (&optional arg)
"Toggle the local fold at the point, and no deeper.
`org-cycle's standard behavior is to cycle between three levels: collapsed,
subtree and whole document. This is slow, especially in larger org buffer. Most
of the time I just want to peek into the current subtree -- at most, expand
*only* the current subtree.
All my (performant) foldings needs are met between this and `org-show-subtree'
(on zO for evil users), and `org-cycle' on shift-TAB if I need it."
(interactive "P")
(unless (eq this-command 'org-shifttab)
(save-excursion
(org-beginning-of-line)
(let (invisible-p)
(when (and (org-at-heading-p)
(or org-cycle-open-archived-trees
(not (member org-archive-tag (org-get-tags))))
(or (not arg)
(setq invisible-p (outline-invisible-p (line-end-position)))))
(unless invisible-p
(setq org-cycle-subtree-status 'subtree))
(org-cycle-internal-local)
t)))))
:config
;; Only fold the current tree, rather than recursively
(add-hook 'org-tab-first-hook #'+org-cycle-only-current-subtree-h)
)(use-package org
:config
(require 's)
(defun lc/async-process (command &optional name filter)
"Start an async process by running the COMMAND string with bash. Return the
process object for it.
NAME is name for the process. Default is \"async-process\".
FILTER is function that runs after the process is finished, its args should be
\"(process output)\". Default is just messages the output."
(make-process
:command `("bash" "-c" ,command)
:name (if name name
"async-process")
:filter (if filter filter
(lambda (process output) (message (s-trim output))))))
(defun lc/tangle-config ()
"Export code blocks from the literate config file
asynchronously."
(interactive)
(let ((command (if (file-directory-p "/Applications/Emacs.app")
"/Applications/Emacs.app/Contents/MacOS/Emacs %s --batch --eval '(org-babel-tangle nil \"%s\")'"
;; on iPad
"emacs %s --batch --eval '(org-babel-tangle nil \"%s\")'"
;; "emacs %s --batch --eval '(org-babel-tangle nil \"%s\")' 2>&1 | grep -v '^Loading.*\.\.\.$' | grep -v '^Using ' | grep -v '^dump '| grep -v '^Finding '"
)))
;; prevent emacs from killing until tangle-process finished
;; (add-to-list 'kill-emacs-query-functions
;; (lambda ()
;; (or (not (process-live-p (get-process "tangle-process")))
;; (y-or-n-p "\"fk/tangle-config\" is running; kill it? "))))
;; tangle config asynchronously
(lc/async-process
(format command
(expand-file-name "readme.org" user-emacs-directory)
(expand-file-name "init.el" user-emacs-directory))
"tangle-process")
)
)
)(use-package org-reverse-datetree
:after org :demand)(use-package org-superstar
:hook (org-mode . org-superstar-mode)
:init
(setq org-superstar-headline-bullets-list '("✖" "✚" "◉" "○" "▶")
;; org-superstar-special-todo-items t
org-ellipsis " ↴ ")
)hl-todo-keyword-faces to know the keywords (can’t get to change them..).
(use-package hl-todo
:hook ((prog-mode org-mode) . lc/hl-todo-init)
:init
(defun lc/hl-todo-init ()
(setq-local hl-todo-keyword-faces '(("HOLD" . "#cfdf30")
("TODO" . "#ff9977")
("NEXT" . "#b6a0ff")
("PROG" . "#00d3d0")
("FIXME" . "#ff9977")
("DONE" . "#44bc44")
("REVIEW" . "#6ae4b9")
("DEPRECATED" . "#bfd9ff")))
(hl-todo-mode))
)(use-package org
:general
(lc/local-leader-keys
:keymaps 'org-mode-map
"'" '(org-edit-special :wk "edit")
"-" '(org-babel-demarcate-block :wk "split block")
"z" '(org-babel-hide-result-toggle :wk "fold result"))
(lc/local-leader-keys
:keymaps 'org-src-mode-map
"'" '(org-edit-src-exit :wk "exit")) ;;FIXME
:init
(setq org-confirm-babel-evaluate nil)
:config
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
;; (clojure . t)
;; (ledger . t)
(shell . t)))
(add-hook 'org-babel-after-execute-hook 'org-display-inline-images 'append)
)
;; enable mermaid diagram blocks
;; (use-package ob-mermaid
;; :custom (ob-mermaid-cli-path "~/.asdf/shims/mmdc"))(use-package ob-async
:hook (org-load . (lambda () (require 'ob-async)))
:init
(setq ob-async-no-async-languages-alist '("jupyter-python" "jupyter-R" "jupyter-julia")))(use-package org-tree-slide
:after org
:hook ((org-tree-slide-play . (lambda () (+remap-faces-at-start-present)))
(org-tree-slide-stop . (lambda () (+remap-faces-at-stop-present))))
:general
(lc/leader-keys
"t p" '(org-tree-slide-mode :wk "present"))
(general-nmap
:keymaps '(org-tree-slide-mode-map org-mode-map)
"C-j" 'org-tree-slide-move-next-tree
"C-k" 'org-tree-slide-move-previous-tree)
:init
(setq org-tree-slide-activate-message "Presentation mode ON")
(setq org-tree-slide-deactivate-message "Presentation mode OFF")
(setq org-tree-slide-indicator nil)
(setq org-tree-slide-breadcrumbs " > ")
(setq org-tree-slide-heading-emphasis t)
(setq org-tree-slide-slide-in-waiting 0.025)
(setq org-tree-slide-content-margin-top 4)
(defun +remap-faces-at-start-present ()
(setq-local face-remapping-alist '((default (:height 1.50) variable-pitch)
(fixed-pitch (:height 1.2) fixed-pitch)
;; (org-verbatim (:height 1.2) org-verbatim)
;; (org-block (:height 1.2) org-block)
))
;; (setq-local olivetti-body-width 95)
(olivetti-mode 1)
(display-fill-column-indicator-mode 0)
(hide-mode-line-mode 1)
(diff-hl-mode 0)
(centaur-tabs-mode 0))
(defun +remap-faces-at-stop-present ()
(setq-local face-remapping-alist '((default variable-pitch default)))
;; (setq-local olivetti-body-width 120)
(olivetti-mode 0)
(display-fill-column-indicator-mode 1)
(hide-mode-line-mode 0)
(doom-modeline-mode 1)
(diff-hl-mode 1)
(centaur-tabs-mode 1))
(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 8) ;; or 0?
(setq org-tree-slide-never-touch-face t)
;; :config
;; (org-tree-slide-presentation-profile)
;; :custom-face
;; (org-tree-slide-heading-level-1 ((t (:height 1.8 :weight bold))))
;; (org-tree-slide-heading-level-2 ((t (:height 1.5 :weight bold))))
;; (org-tree-slide-heading-level-3 ((t (:height 1.5 :weight bold))))
;; (org-tree-slide-heading-level-4 ((t (:height 1.5 :weight bold))))
)- nice
+org/insert-item-belowfunction evilbindings fororg-agenda- text objects:
- use
vieto select everything inside a src block - use
virto select everything inside a heading - use ==ie= to format a code block
- use
(use-package evil-org-mode
:straight (evil-org-mode :type git :host github :repo "hlissner/evil-org-mode")
:hook ((org-mode . evil-org-mode)
(org-mode . (lambda ()
(require 'evil-org)
(evil-normalize-keymaps)
(evil-org-set-key-theme '(textobjects))
(require 'evil-org-agenda)
(evil-org-agenda-set-keys))))
:bind
([remap evil-org-org-insert-heading-respect-content-below] . +org/insert-item-below) ;; "<C-return>"
([remap evil-org-org-insert-todo-heading-respect-content-below] . +org/insert-item-above) ;; "<C-S-return>"
:general
(general-nmap
:keymaps 'org-mode-map
:states 'normal
"RET" #'org-open-at-point
;; "RET" #'+org/dwim-at-point
)
:init
(defun +org--insert-item (direction)
(let ((context (org-element-lineage
(org-element-context)
'(table table-row headline inlinetask item plain-list)
t)))
(pcase (org-element-type context)
;; Add a new list item (carrying over checkboxes if necessary)
((or `item `plain-list)
;; Position determines where org-insert-todo-heading and org-insert-item
;; insert the new list item.
(if (eq direction 'above)
(org-beginning-of-item)
(org-end-of-item)
(backward-char))
(org-insert-item (org-element-property :checkbox context))
;; Handle edge case where current item is empty and bottom of list is
;; flush against a new heading.
(when (and (eq direction 'below)
(eq (org-element-property :contents-begin context)
(org-element-property :contents-end context)))
(org-end-of-item)
(org-end-of-line)))
;; Add a new table row
((or `table `table-row)
(pcase direction
('below (save-excursion (org-table-insert-row t))
(org-table-next-row))
('above (save-excursion (org-shiftmetadown))
(+org/table-previous-row))))
;; Otherwise, add a new heading, carrying over any todo state, if
;; necessary.
(_
(let ((level (or (org-current-level) 1)))
;; I intentionally avoid `org-insert-heading' and the like because they
;; impose unpredictable whitespace rules depending on the cursor
;; position. It's simpler to express this command's responsibility at a
;; lower level than work around all the quirks in org's API.
(pcase direction
(`below
(let (org-insert-heading-respect-content)
(goto-char (line-end-position))
(org-end-of-subtree)
(insert "\n" (make-string level ?*) " ")))
(`above
(org-back-to-heading)
(insert (make-string level ?*) " ")
(save-excursion (insert "\n"))))
(when-let* ((todo-keyword (org-element-property :todo-keyword context))
(todo-type (org-element-property :todo-type context)))
(org-todo
(cond ((eq todo-type 'done)
;; Doesn't make sense to create more "DONE" headings
(car (+org-get-todo-keywords-for todo-keyword)))
(todo-keyword)
('todo)))))))
(when (org-invisible-p)
(org-show-hidden-entry))
(when (and (bound-and-true-p evil-local-mode)
(not (evil-emacs-state-p)))
(evil-insert 1))))
(defun +org/insert-item-below (count)
"Inserts a new heading, table cell or item below the current one."
(interactive "p")
(dotimes (_ count) (+org--insert-item 'below)))
(defun +org/insert-item-above (count)
"Inserts a new heading, table cell or item above the current one."
(interactive "p")
(dotimes (_ count) (+org--insert-item 'above)))
)gh-pages branch
NOTE:
- Make sure the mode is active
- Comment out
rainbow-delimiterssection and restart - Run
org-export-dispatchand export to HTML (binded to, E) - Make sure to set
org-html-themify-themesto lighter variant so it is easier to read - The second export will not generate correct .css . Restart emacs and export as first thing
(use-package org-html-themify
:after modus-themes
:straight
(org-html-themify
:type git
:host github
:repo "DogLooksGood/org-html-themify"
:files ("*.el" "*.js" "*.css"))
:hook (org-mode . org-html-themify-mode)
:init
(setq org-html-themify-themes
'((light . modus-operandi)
(dark . modus-operandi)))
:config
;; otherwise it complains about invalid face
(require 'hl-line)
)
(use-package htmlize
:after org-html-themify)(use-package ox-gfm
:commands (org-gfm-export-as-markdown org-gfm-export-to-markdown)
:after org
)#+OX-IPYNB-LANGUAGE: ipython
It seems that also jupyter-python should be replaced with ipython for the export to work.
(use-package ox-ipynb
:straight (ox-ipynb :type git :host github :repo "jkitchin/ox-ipynb")
:commands (ox-ipynb-export-org-file-to-ipynb-file))- Have a look here: https://github.com/dorneanu/slides/blob/main/.dir-locals.el
(use-package org-re-reveal
:after org
:init
;; (setq org-re-reveal-root (expand-file-name "../../" (locate-library "dist/reveal.js" t))
;; org-re-reveal-revealjs-version "4")
(setq org-re-reveal-root "./reveal.js"
org-re-reveal-revealjs-version "3.8"
org-re-reveal-external-plugins '((progress . "{ src: '%s/plugin/toc-progress/toc-progress.js', async: true, callback: function() { toc_progress.initialize(); toc_progress.create();} }"))
))(use-package weblorg)
(use-package templatel)
(use-package htmlize)(use-package ox-altacv
:straight (ox-altacv :type git :host github :repo "lccambiaghi/org-cv")
:config (require 'ox-altacv))(use-package org-appear
:straight (org-appear :type git :host github :repo "awth13/org-appear")
:hook (org-mode . org-appear-mode)
:init
(setq org-appear-autoemphasis t)
(setq org-appear-autolinks t)
(setq org-appear-autosubmarkers t)
)
(use-package org-fragtog
:hook (org-mode . org-fragtog-mode))Problem: when exporting org files to HTML, the header anchors are volatile. Once I publish a new HTML version of this file, the previous version’s links are no longer valid.
This function adds CUSTOM_ID property to all headings in a file (one-time).
We can then use this to link to that heading forever.
Adding it as a after-save-hook automatically adds a CUSTOM_ID to newly created headers.
(use-package org
:init
(defun lc/org-custom-id-get (&optional pom create prefix)
"Get the CUSTOM_ID property of the entry at point-or-marker POM.
If POM is nil, refer to the entry at point. If the entry does
not have an CUSTOM_ID, the function returns nil. However, when
CREATE is non nil, create a CUSTOM_ID if none is present
already. PREFIX will be passed through to `org-id-new'. In any
case, the CUSTOM_ID of the entry is returned."
(interactive)
(org-with-point-at pom
(let ((id (org-entry-get nil "CUSTOM_ID")))
(cond
((and id (stringp id) (string-match "\\S-" id))
id)
(create
(setq id (org-id-new (concat prefix "h")))
(org-entry-put pom "CUSTOM_ID" id)
(org-id-add-location id (buffer-file-name (buffer-base-buffer)))
id)))))
(defun lc/org-add-ids-to-headlines-in-file ()
"Add CUSTOM_ID properties to all headlines in the current
file which do not already have one. Only adds ids if the
`auto-id' option is set to `t' in the file somewhere. ie,
#+OPTIONS: auto-id:t"
(interactive)
(save-excursion
(widen)
(goto-char (point-min))
(when (re-search-forward "^#\\+OPTIONS:.*auto-id:t" 10000 t)
(org-map-entries (lambda () (lc/org-custom-id-get (point) 'create))))))
:config
(require 'org-id)
(setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)
)(use-package emacs
:hook
((org-jupyter-mode . (lambda () (visual-line-mode -1)
(advice-add 'org-cycle :around #'lc/org-cycle-or-py-complete)))
(org-mode . (lambda () (when (lc/is-jupyter-org-buffer?) (org-jupyter-mode)))))
:init
(defun lc/is-jupyter-org-buffer? ()
(with-current-buffer (buffer-name)
(goto-char (point-min))
(re-search-forward "begin_src jupyter-" 10000 t)))
(defun lc/org-cycle-or-py-complete (orig-fun &rest args)
"If in a jupyter-python code block, call py-indent-or-complete, otherwise use org-cycle"
(if (and (org-in-src-block-p)
(eq (intern (org-element-property :language (org-element-at-point))) 'jupyter-python))
(lc/py-indent-or-complete)
(apply orig-fun args)))
(define-minor-mode org-jupyter-mode
"Minor mode which is active when an org file has the string begin_src jupyter-python
in the first few hundred rows"
;; :keymap (let ((map (make-sparse-keymap)))
;; (define-key map (kbd "C-c f") 'insert-foo)
;; map)
)
)ln -s ~/OneDrive/.../worknotes ~/roam/workln -s /Users/cambiaghiluca/Library/Mobile\ Documents/iCloud\~com\~appsonthemove\~beorg/Documents/org/roam ~/roam/personal
(use-package org-roam
:after org
:init
(setq org-roam-directory (file-truename "~/roam"))
(setq org-roam-v2-ack t)
(setq org-roam-capture-templates
'(("d" "default" plain "%?" :target
(file+head "personal/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t)
("w" "work" plain "%?" :target
(file+head "work/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t)))
:general
(lc/leader-keys
"TAB n" '((lambda () (interactive) (persp-switch "notes")) :wk "notes")
"n n" '((lambda () (interactive)
(persp-switch "notes")
(org-roam-node-find))
:wk "notes workspace")
"n b" 'org-roam-buffer-toggle
"n f" 'org-roam-node-find
"n g" 'org-roam-graph
"n i" 'org-roam-node-insert
"n c" 'org-roam-capture
"n t" 'org-roam-tag-add
"n r" 'org-roam-ref-add
"n a" 'org-roam-alias-add
;; Dailies
"n j" 'org-roam-dailies-capture-today
"n J" 'org-roam-dailies-goto-today
;; todos
"o t" '((lambda () (interactive)
(persp-switch "notes")
(find-file (concat org-roam-directory "/work/todo.org")))
:wk "work todos")
"o n" '((lambda () (interactive)
(persp-switch "notes")
(org-roam-node-find))
:wk "notes")
)
:config
(org-roam-setup)
;; If using org-roam-protocol
;; (require 'org-roam-protocol)
(add-to-list 'display-buffer-alist
'(("*org-roam*"
(display-buffer-in-direction)
(direction . right)
(window-width . 0.33)
(window-height . fit-window-to-buffer))))
)(use-package all-the-icons
:if (not lc/is-ipad)
:demand
)(use-package all-the-icons-completion
:after (marginalia all-the-icons)
:hook (marginalia-mode . all-the-icons-completion-marginalia-setup)
:init
(all-the-icons-completion-mode))(use-package doom-modeline
:demand
:init
(setq doom-modeline-buffer-encoding nil)
(setq doom-modeline-env-enable-python nil)
(setq doom-modeline-project-detection 'projectile)
(setq doom-modeline-buffer-file-name-style 'relative-to-project)
:config
(doom-modeline-mode 1)
;; (set-face-attribute 'doom-modeline-evil-insert-state nil :foreground "orange")
(setq doom-modeline-height 20)
)(use-package emacs
;; :straight (modus-themes :type git :host gitlab :repo "protesilaos/modus-themes" :branch "main")
;; :demand
:if (display-graphic-p)
:hook (modus-themes-after-load-theme . lc/fix-fill-column-indicator)
:general
(lc/leader-keys
"t t" '((lambda () (interactive) (modus-themes-toggle)) :wk "toggle theme"))
:init
(setq modus-themes-italic-constructs t
;; modus-themes-no-mixed-fonts t
modus-themes-bold-constructs t
modus-themes-fringes 'nil ; {nil,'subtle,'intense}
modus-themes-mode-line '(3d) ; {nil,'3d,'moody}
modus-themes-prompts nil ; {nil,'subtle,'intense}
;; modus-themes-completions 'moderate ; {nil,'moderate,'opinionated}
;; modus-themes-diffs nil ; {nil,'desaturated,'fg-only}
modus-themes-org-blocks 'greyscale ; {nil,'greyscale,'rainbow}
;; modus-themes-headings ; Read further below in the manual for this one
;; (quote ((1 . t) ; keep the default style
;; (2 . (background overline))
;; (t . (rainbow))))
modus-themes-variable-pitch-headings t
modus-themes-scale-headings t
modus-themes-scale-1 1.1
modus-themes-scale-2 1.15
modus-themes-scale-3 1.21
modus-themes-scale-4 1.27
modus-themes-scale-5 1.33)
(defun lc/override-colors ()
(setq modus-themes-operandi-color-overrides
'((bg-main . "#fefcf4")
(bg-dim . "#faf6ef")
(bg-alt . "#f7efe5")
(bg-hl-line . "#f4f0e3")
(bg-active . "#e8dfd1")
(bg-inactive . "#f6ece5")
(bg-region . "#c6bab1")
(bg-header . "#ede3e0")
(bg-tab-bar . "#dcd3d3")
(bg-tab-active . "#fdf6eb")
(bg-tab-inactive . "#c8bab8")
(fg-unfocused ."#55556f")))
(setq modus-themes-vivendi-color-overrides
'((bg-main . "#100b17")
(bg-dim . "#161129")
(bg-alt . "#181732")
(bg-hl-line . "#191628")
(bg-active . "#282e46")
(bg-inactive . "#1a1e39")
(bg-region . "#393a53")
(bg-header . "#202037")
(bg-tab-bar . "#262b41")
(bg-tab-active . "#120f18")
(bg-tab-inactive . "#3a3a5a")
(fg-unfocused . "#9a9aab")))
)
(defun lc/load-dark-theme ()
(setq lc/theme 'dark)
;; (with-eval-after-load 'org (plist-put org-format-latex-options :foreground "whitesmoke"))
(with-eval-after-load 'org (plist-put org-format-latex-options :background "Transparent"))
(with-eval-after-load 'org-html-themify
(setq org-html-themify-themes '((light . modus-vivendi) (dark . modus-vivendi))))
(load-theme 'modus-vivendi t)
(when (bound-and-true-p centaur-tabs-mode)
(lc/update-centaur-tabs))
)
(defun lc/load-light-theme ()
(setq lc/theme 'light)
;; (with-eval-after-load 'org (plist-put org-format-latex-options :foreground "dark"))
(with-eval-after-load 'org (plist-put org-format-latex-options :background "Transparent"))
(with-eval-after-load 'org-html-themify
(setq org-html-themify-themes '((light . modus-operandi) (dark . modus-operandi))))
(setenv "BAT_THEME" "ansi")
(load-theme 'modus-operandi t)
(when (bound-and-true-p centaur-tabs-mode)
(lc/update-centaur-tabs)))
(defun lc/update-centaur-tabs ()
(centaur-tabs-display-update)
(centaur-tabs-headline-match)
(set-face-attribute 'centaur-tabs-selected nil :overline (face-background 'centaur-tabs-active-bar-face)))
(defun lc/change-theme-with-mac-system ()
(let ((appearance (plist-get (mac-application-state) :appearance)))
(cond ((equal appearance "NSAppearanceNameAqua")
(lc/load-light-theme))
((equal appearance "NSAppearanceNameDarkAqua")
(lc/load-dark-theme)))))
(defun lc/change-theme-with-timers ()
(run-at-time "00:00" (* 60 60 24) 'lc/load-dark-theme)
(run-at-time "08:00" (* 60 60 24) 'lc/load-light-theme)
(run-at-time "20:00" (* 60 60 24) 'lc/load-dark-theme))
(defun lc/fix-fill-column-indicator ()
(when (display-graphic-p)
(modus-themes-with-colors
(custom-set-faces
`(fill-column-indicator ((,class :background ,bg-inactive :foreground ,bg-inactive)))))))
(when (display-graphic-p)
(lc/override-colors))
(if (and (boundp 'mac-effective-appearance-change-hook)
(plist-get (mac-application-state) :appearance))
(progn
(add-hook 'after-init-hook 'lc/change-theme-with-mac-system)
(add-hook 'mac-effective-appearance-change-hook 'lc/change-theme-with-mac-system))
(add-hook 'emacs-startup-hook 'lc/change-theme-with-timers)
)
)(use-package dashboard
:demand
:init
(setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
(setq dashboard-center-content t)
(setq dashboard-projects-backend 'projectile)
(setq dashboard-set-heading-icons t)
(setq dashboard-set-file-icons t)
(defun lc/is-after-17-or-weekends? ()
(or (thread-first (nth 3 (split-string (current-time-string) " ")) ;; time of the day e.g. 18
;; (substring 0 2)
(string-to-number) ;;<
(> 16))
(thread-first (substring (current-time-string) 0 3) ;; day of the week e.g. Fri
(member '("Sat" "Sun")))))
(setq dashboard-banner-logo-title nil)
(setq dashboard-set-footer nil)
;; (setq dashboard-startup-banner [VALUE])
(setq dashboard-set-navigator t)
(setq dashboard-navigator-buttons
`((;; Github
(,(all-the-icons-octicon "mark-github" :height 1.1 :v-adjust 0.0)
"Github"
"Go to wondercast"
(lambda (&rest _) (browse-url "https://github.com/Maersk-Global/wondercast")))
;; Codebase
(,(all-the-icons-faicon "briefcase" :height 1.1 :v-adjust -0.1)
"JIRA"
"Go to Kanban"
(lambda (&rest _) (browse-url "https://jira.maerskdev.net/secure/RapidBoard.jspa?rapidView=6378&projectKey=AVOC&quickFilter=15697")))
;; Perspectives
(,(all-the-icons-octicon "history" :height 1.1 :v-adjust 0.0)
"Restore"
"Restore"
(lambda (&rest _) (persp-state-load persp-state-default-file)))
)))
(defun lc/dashboard-agenda-entry-format ()
"Format agenda entry to show it on dashboard. Compared to the original, we remove tags at the end"
(let* ((scheduled-time (org-get-scheduled-time (point)))
(deadline-time (org-get-deadline-time (point)))
(entry-time (or scheduled-time deadline-time))
(item (org-agenda-format-item
(dashboard-agenda--formatted-time)
(dashboard-agenda--formatted-headline)
(org-outline-level)
(org-get-category)
nil;; (org-get-tags)
))
(loc (point))
(file (buffer-file-name))
(todo-state (org-get-todo-state))
(todo-index (and todo-state
(length (member todo-state org-todo-keywords-1))))
(entry-data (list (cons 'time entry-time)
(cons 'todo-index todo-index))))
(list item loc file entry-data)))
(defun lc/dashboard-get-agenda ()
"Get agenda items for today or for a week from now."
(org-compile-prefix-format 'agenda)
(org-map-entries 'lc/dashboard-agenda-entry-format
dashboard-match-agenda-entry
'agenda
dashboard-filter-agenda-entry))
(defun lc/dashboard-get-next ()
"Get agenda items for today or for a week from now."
(org-compile-prefix-format 'agenda)
(org-map-entries 'lc/dashboard-agenda-entry-format
dashboard-match-next-entry
'agenda))
(defun lc/dashboard-insert-next (list-size)
"Add the list of LIST-SIZE items of next tasks"
(require 'org-agenda)
(let ((next (lc/dashboard-get-next)))
(dashboard-insert-section
"Next tasks"
next
list-size
'next
"n"
`(lambda (&rest ignore)
(let ((buffer (find-file-other-window (nth 2 ',el))))
(with-current-buffer buffer
(goto-char (nth 1 ',el))
(switch-to-buffer buffer))))
(format "%s" (nth 0 el)))))
:config
;; exclude work items after 17 and on weekends
(setq dashboard-match-next-entry "TODO=\"NEXT\"-work")
(run-at-time "00:00" (* 60 60 24)
(lambda ()
(if (lc/is-after-17-or-weekends?)
(setq dashboard-match-agenda-entry "life|habits"
dashboard-match-next-entry "TODO=\"NEXT\"-work")
(setq dashboard-match-agenda-entry "work|life|habits"
dashboard-match-next-entry "TODO=\"NEXT\""
))))
(dashboard-setup-startup-hook)
(set-face-attribute 'dashboard-items-face nil :height (lc/get-font-size))
;; do not show tags in agenda view
(advice-add 'dashboard-get-agenda :override #'lc/dashboard-get-agenda)
;; show next tasks in dashboard
(add-to-list 'dashboard-item-generators '(next . lc/dashboard-insert-next))
(setq dashboard-items '((agenda . 5)
(next . 10)
(bookmarks . 5)
;; (recents . 5)
;; (projects . 5)
))
)(use-package emacs
:init
(setq display-buffer-alist
`((,(rx bos (or "*Apropos*" "*Help*" "*helpful" "*info*" "*Summary*") (0+ not-newline))
(display-buffer-reuse-mode-window display-buffer-below-selected)
(window-height . 0.33)
(mode apropos-mode help-mode helpful-mode Info-mode Man-mode))))
)
;; reuse existing windows
;; (setq display-buffer-alist
;; '((".*"
;; (display-buffer-reuse-window display-buffer-same-window)
;; (reusable-frames . t))))
;; (setq even-window-sizes nil) ; display-buffer hint: avoid resizing(use-package centered-cursor-mode
:general
(lc/leader-keys
"t =" '((lambda () (interactive) (centered-cursor-mode 'toggle)) :wk "center cursor")
)
)(use-package hide-mode-line
:commands (hide-mode-line-mode))(use-package winum
:general
(lc/leader-keys
"1" '(winum-select-window-1 :wk "win 1")
"2" '(winum-select-window-2 :wk "win 2")
"3" '(winum-select-window-3 :wk "win 3")
"4" '(winum-select-window-4 :wk "win 4")
"5" '(winum-select-window-5 :wk "win 5")
"6" '(winum-select-window-6 :wk "win 6")
)
:config
(winum-mode))(use-package transpose-frame
:general
(lc/leader-keys
"w t" '(transpose-frame :wk "transpose")
"w f" '(rotate-frame :wk "flip")))evil you can:
gwwto fill the linegqqto fill the line and move to the end of itgwpto fill paragraph
(use-package display-fill-column-indicator
:straight (:type built-in)
:hook
(python-mode . display-fill-column-indicator-mode)
:init
(setq-default fill-column 90)
;; (setq display-fill-column-indicator-character "|")
);; add a visual intent guide
(use-package highlight-indent-guides
:hook (prog-mode . highlight-indent-guides-mode)
:init
;; (setq highlight-indent-guides-method 'column)
;; (setq highlight-indent-guides-method 'bitmap)
(setq highlight-indent-guides-method 'character)
(setq highlight-indent-guides-character ?‖)
(setq highlight-indent-guides-responsive 'top)
;; (setq highlight-indent-guides-responsive 'stack)
;; (setq highlight-indent-guides-auto-enabled nil)
;; (set-face-background 'highlight-indent-guides-odd-face "darkgray")
;; (set-face-background 'highlight-indent-guides-even-face "dimgray")
;; (set-face-foreground 'highlight-indent-guides-character-face "dimgray")
)(use-package emacs
:general
(lc/leader-keys
"w o" '(doom/window-enlargen :wk "enlargen"))
:init
(defun doom/window-enlargen (&optional arg)
"Enlargen the current window to focus on this one. Does not close other
windows (unlike `doom/window-maximize-buffer'). Activate again to undo."
(interactive "P")
(let ((param 'doom--enlargen-last-wconf))
(cl-destructuring-bind (window . wconf)
(or (frame-parameter nil param)
(cons nil nil))
(set-frame-parameter
nil param
(if (and (equal window (selected-window))
(not arg)
wconf)
(ignore
(let ((source-window (selected-window)))
(set-window-configuration wconf)
(when (window-live-p source-window)
(select-window source-window))))
(prog1 (cons (selected-window) (or wconf (current-window-configuration)))
(let* ((window (selected-window))
(dedicated-p (window-dedicated-p window))
(preserved-p (window-parameter window 'window-preserved-size))
(ignore-window-parameters t)
(window-resize-pixelwise nil)
(frame-resize-pixelwise nil))
(unwind-protect
(progn
(when dedicated-p
(set-window-dedicated-p window nil))
(when preserved-p
(set-window-parameter window 'window-preserved-size nil))
(maximize-window window))
(set-window-dedicated-p window dedicated-p)
(when preserved-p
(set-window-parameter window 'window-preserved-size preserved-p))
(add-hook 'doom-switch-window-hook #'doom--enlargened-forget-last-wconf-h)))))))))
)
emacs on my jailbroken iPad, I cannot set TERM=xterm-256color because of some terminfo error.
I therefore do what I can with the 8 colors I can use.
The default theme manoj-dark does a pretty good job OOTB.
I add a few manual tweaks.
The theme defintion gets saved in custom-theme-directory.
(deftheme 8colors
"Theme using only 8 colors")
;; (custom-theme-set-variables
;; '8colors
;; '(overline-margin 0)
;; )
(custom-theme-set-faces
'8colors
'(centaur-tabs-unselected ((t (:foreground "white" :background "black"))) t)
'(centaur-tabs-unselected-modified ((t (:foreground "white" :background "black"))) t)
'(tool-bar ((t (:background "black"))) t)
'(selectrum-current-candidate ((t (:background "blue"))) t)
'(org-code ((t (:foreground "magenta"))) t)
'(org-special-keyword ((t (:foreground "magenta"))) t)
'(mode-line ((t (:background "black"))) t)
'(doom-modeline-buffer-file ((t (:background "black"))) t)
'(tab-line ((t (:background "black"))) t)
'(magit-diff-removed-highlight ((t (:background "red" :foreground "white"))) t)
'(magit-diff-added-highlight ((t (:background "green" :foreground "white"))) t)
'(magit-hash ((t (:background "black" :foreground "white"))) t)
'(iedit-occurrence ((t (:background "blue" :foreground "white"))) t)
)
(provide-theme '8colors)(use-package emacs
:init
(unless (> (display-color-cells) 8)
(setq custom-theme-directory (concat user-emacs-directory "themes"))
(custom-set-variables '(custom-enabled-themes '(8colors manoj-dark)))
))(use-package emacs
:init
(set-frame-parameter (selected-frame) 'alpha '(93 . 93))
(add-to-list 'default-frame-alist '(alpha . (93 . 93)))
)(use-package marginalia
:after vertico
:init
(setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
(marginalia-mode)
(with-eval-after-load 'projectile
(add-to-list 'marginalia-command-categories '(projectile-find-file . file)))
)- You can act on candidates with
C-l - You can run
embark-exporton all results (e.g. after aconsult-line) withC-l E- You can run
embark-export-snapshotwithC-l S
- You can run
(use-package embark
:after vertico
:general
(general-nmap "C-l" 'embark-act)
(vertico-map
"C-l" #'embark-act
)
(:keymaps 'embark-file-map
;; "o" 'find-file-other-window
"x" 'lc/dired-open-externally
)
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
:config
;; Hide the mode line of the Embark live/completions buffers
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none))))
;; (add-hook 'embark-setup-hook 'selectrum-set-selected-candidate)
)embark-export, we can edit the results with wgrep and commit the edits.
This is extremely powerful for refactorings such as changing the name of a class or a function across files in the project.
(use-package wgrep
:general
(grep-mode-map "W" 'wgrep-change-to-wgrep-mode)
:init
(setq wgrep-auto-save-buffer t)
(setq wgrep-change-readonly-file t)
)- After
consult-lineyou can pressM-ntwice to search for the symbol at point
(use-package consult
:commands (consult-ripgrep)
:general
(general-nmap
:states '(normal insert)
"C-p" 'consult-yank-pop)
(lc/leader-keys
"r r" '(consult-bookmark :wk "go to bookmark")
"s i" '(consult-isearch :wk "isearch")
"s o" '(consult-outline :which-key "outline")
"s s" 'consult-line
"s p" '(consult-ripgrep :wk "ripgrep project")
"b b" 'consult-buffer
;; TODO consult mark
"f r" 'consult-recent-file
;; "s !" '(consult-flymake :wk "flymake")
)
:init
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
;; (setq consult-preview-key "C-l")
;; (setq consult-narrow-key ">")
:config
(autoload 'projectile-project-root "projectile")
(setq consult-project-root-function #'projectile-project-root)
(with-eval-after-load 'selectrum
(require 'consult-selectrum))
) (use-package embark-consult
:after (embark consult)
;; :demand t ; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
;; :hook
;; (embark-collect-mode . embark-consult-preview-minor-mode)
)vertico-indexedlets you choose candidates according to their index, e.g.C-3 RETwill select third candidate.
(use-package vertico
;; :straight (vertico :type git :host github :repo "minad/vertico")
:straight (vertico :files (:defaults "extensions/*")
:includes (vertico-indexed
vertico-flat
vertico-grid
vertico-mouse
;; vertico-quick
vertico-buffer
vertico-repeat
vertico-reverse
vertico-directory
vertico-multiform
vertico-unobtrusive
))
:demand
:hook
((minibuffer-setup . vertico-repeat-save) ; Make sure vertico state is saved for `vertico-repeat'
(rfn-eshadow-update-overlay . vertico-directory-tidy) ; Clean up file path when typing
)
:general
(:keymaps 'vertico-map
"C-j" #'vertico-next
"C-k" #'vertico-previous
"<escape>" #'minibuffer-keyboard-quit ; Close minibuffer
;; "C-;" #'kb/vertico-multiform-flat-toggle
"M-<backspace>" #'vertico-directory-delete-word
)
(lc/leader-keys
"s ." '(vertico-repeat-last :wk "repeat search")
)
;; :bind (:map vertico-map
;; ("C-j" . vertico-next)
;; ("C-k" . vertico-previous)
;; ("<escape>" . minibuffer-keyboard-quit)
;; )
:init
;; (setq vertico-resize t)
;; multiform extension
(setq vertico-grid-separator " ")
(setq vertico-grid-lookahead 50)
(setq vertico-buffer-display-action '(display-buffer-reuse-window))
(setq vertico-multiform-categories
'((file indexed)
(consult-grep buffer)
(consult-location)
(imenu buffer)
(library reverse indexed)
(org-roam-node reverse indexed)
(t reverse)
))
(setq vertico-multiform-commands
'(("flyspell-correct-*" grid reverse)
(org-refile grid reverse indexed)
(consult-yank-pop indexed)
(consult-flycheck)
(consult-lsp-diagnostics)
))
(defun kb/vertico-multiform-flat-toggle ()
"Toggle between flat and reverse."
(interactive)
(vertico-multiform--display-toggle 'vertico-flat-mode)
(if vertico-flat-mode
(vertico-multiform--temporary-mode 'vertico-reverse-mode -1)
(vertico-multiform--temporary-mode 'vertico-reverse-mode 1)))
;; Workaround for problem with `tramp' hostname completions. This overrides
;; the completion style specifically for remote files! See
;; https://github.com/minad/vertico#tramp-hostname-completion
(defun lc/basic-remote-try-completion (string table pred point)
(and (vertico--remote-p string)
(completion-basic-try-completion string table pred point)))
(defun lc/basic-remote-all-completions (string table pred point)
(and (vertico--remote-p string)
(completion-basic-all-completions string table pred point)))
(add-to-list 'completion-styles-alist
'(basic-remote ; Name of `completion-style'
lc/basic-remote-try-completion lc/basic-remote-all-completions nil))
(setq completion-in-region-function
(lambda (&rest args)
(apply (if vertico-mode
#'consult-completion-in-region
#'completion--in-region)
args)))
:config
;; (vertico-multiform-mode)
(vertico-mode)
;; (vertico-indexed-mode)
;; Prefix the current candidate with “» ”. From
;; https://github.com/minad/vertico/wiki#prefix-current-candidate-with-arrow
(advice-add #'vertico--format-candidate :around
(lambda (orig cand prefix suffix index _start)
(setq cand (funcall orig cand prefix suffix index _start))
(concat
(if (= vertico--index index)
(propertize "» " 'face 'vertico-current)
" ")
cand)))
)
(use-package orderless
:init
;; Configure a custom style dispatcher (see the Consult wiki)
;; (setq orderless-style-dispatchers '(+orderless-dispatch)
;; orderless-component-separator #'orderless-escapable-split-on-space)
(setq completion-styles '(orderless)
completion-category-defaults nil
completion-category-overrides '((file (styles partial-completion)))))
(use-package savehist
:init
(savehist-mode))
;; A few more useful configurations...
(use-package emacs
:init
;; Add prompt indicator to `completing-read-multiple'.
;; Alternatively try `consult-completing-read-multiple'.
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
;; Vertico commands are hidden in normal buffers.
;; (setq read-extended-command-predicate
;; #'command-completion-default-include-p)
;; Enable recursive minibuffers
(setq enable-recursive-minibuffers t));; Configure corfu
(use-package corfu
:straight (corfu :type git :host github :repo "minad/corfu")
;; :hook (after-init . corfu-global-mode)
:hook ((prog-mode . corfu-mode)
(org-mode . corfu-mode))
:bind
(:map corfu-map
("C-j" . corfu-next)
("C-k" . corfu-previous))
:general
(evil-insert-state-map "C-k" nil)
:init
(setq corfu-auto nil) ;; Enable auto completion
(setq corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
(setq corfu-min-width 80)
(setq corfu-max-width corfu-min-width) ; Always have the same width
(setq corfu-preselect-first t)
(defun corfu-enable-always-in-minibuffer ()
"Enable Corfu in the minibuffer if Vertico/Mct are not active."
(unless (or (bound-and-true-p mct--active) ; Useful if I ever use MCT
(bound-and-true-p vertico--input))
(setq-local corfu-auto nil) ; Ensure auto completion is disabled
(corfu-mode 1)))
(add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1)
;; :custom
;; (corfu-commit-predicate nil) ;; Do not commit selected candidates on next input
;; (corfu-quit-at-boundary t) ;; Automatically quit at word boundary
;; (corfu-quit-no-match t) ;; Automatically quit if there is no match
;; (corfu-preview-current nil) ;; Disable current candidate preview
;; (corfu-preselect-first nil) ;; Disable candidate preselection
;; (corfu-echo-documentation nil) ;; Disable documentation in the echo area
;; (corfu-scroll-margin 5) ;; Use scroll margin
);; Add extensions
(use-package cape
:hook ((org-mode . lc/add-cape-functions)
(lsp-completion-mode . lc/add-cape-functions))
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
(defun lc/add-cape-functions ()
(interactive)
(add-to-list 'completion-at-point-functions #'cape-file t)
;; (fset #'cape-path (cape-company-to-capf #'company-files))
;; (add-to-list 'completion-at-point-functions #'cape-path t)
(add-to-list 'completion-at-point-functions #'cape-dabbrev t)
)
;;(add-to-list 'completion-at-point-functions #'cape-history)
;;(add-to-list 'completion-at-point-functions #'cape-keyword)
;;(add-to-list 'completion-at-point-functions #'cape-tex)
;;(add-to-list 'completion-at-point-functions #'cape-sgml)
;;(add-to-list 'completion-at-point-functions #'cape-rfc1345)
;;(add-to-list 'completion-at-point-functions #'cape-abbrev)
;;(add-to-list 'completion-at-point-functions #'cape-ispell)
;;(add-to-list 'completion-at-point-functions #'cape-dict)
;;(add-to-list 'completion-at-point-functions #'cape-symbol)
;;(add-to-list 'completion-at-point-functions #'cape-line)
)(use-package kind-icon
:straight (kind-icon :type git :host github :repo "jdtsmith/kind-icon")
:after corfu :demand
:init
(setq kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
(setq kind-icon-blend-background nil) ; Use midpoint color between foreground and background colors ("blended")?
(setq kind-icon-blend-frac 0.08)
:config
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)
;; refresh kind icon cache to match theme
(with-eval-after-load 'modus-themes
(add-hook 'modus-themes-after-load-theme-hook #'(lambda () (interactive) (kind-icon-reset-cache))))
)(use-package emacs
:straight (:type built-in)
:general
(lc/leader-keys
"r m" '(bookmark-set :wk "set bookmark")
"r d" '(bookmark-delete :wk "delete bookmark")
)
)(use-package ace-window
:general
(lc/leader-keys
"w a" '(ace-window :wk "ace window"))
:init
(defmacro my/embark-ace-action (fn)
`(defun ,(intern (concat "my/embark-ace-" (symbol-name fn))) ()
(interactive)
(with-demoted-errors "%s"
(require 'ace-window)
(let ((aw-dispatch-always t))
(aw-switch-to-window (aw-select nil))
(call-interactively (symbol-function ',fn))))))
:config
;; from https://karthinks.com/software/fifteen-ways-to-use-embark/
(with-eval-after-load 'embark
(define-key embark-file-map (kbd "o") (my/embark-ace-action find-file))
(define-key embark-buffer-map (kbd "o") (my/embark-ace-action switch-to-buffer))
(define-key embark-bookmark-map (kbd "o") (my/embark-ace-action bookmark-jump))
)
)projectilestruggles with monorepos where.gitfolder is at the root but each subproject has e.g apyproject.toml. In those cases, we need to create a.projectilefile in the root of the subprojects.projectileexcludes git ignored files fromprojectile-find-file. Uselc/projectile-find-file-allwhen opening data
(use-package projectile
:demand
:general
(lc/leader-keys
:states 'normal
"p" '(:keymap projectile-command-map :which-key "project")
"p <escape>" 'keyboard-escape-quit
"p a" '(projectile-add-known-project :wk "add known")
"p F" '(lc/projectile-find-file-all :wk "find file (all)")
"p t" '(projectile-run-vterm :wk "term"))
:init
(when (file-directory-p "~/git")
(setq projectile-project-search-path '("~/git")))
(setq projectile-completion-system 'default)
(setq projectile-project-root-files '(".envrc" ".projectile" "project.clj" "deps.edn"))
(setq projectile-switch-project-action 'projectile-find-file)
;; Do not include straight repos (emacs packages) to project list
(setq projectile-ignored-project-function
(lambda (project-root)
(string-prefix-p (expand-file-name "straight/" user-emacs-directory) project-root)))
(defun lc/projectile-find-file-all ()
(interactive)
(let ((projectile-git-command "git ls-files -zco"))
(projectile-find-file)))
(defun lc/projectile-find-project-name-split-dots (project-root)
(thread-first (directory-file-name project-root)
(split-string "[/]") (last) (car)
(split-string "[.]") (last) (car))
)
(setq projectile-project-name-function
#'lc/projectile-find-project-name-split-dots)
:config
(defadvice projectile-project-root (around ignore-remote first activate)
(unless (file-remote-p default-directory) ad-do-it))
(projectile-mode)
;; projectile commander methods
(setq projectile-commander-methods nil)
(def-projectile-commander-method ?? "Commander help buffer."
(ignore-errors (kill-buffer projectile-commander-help-buffer))
(with-current-buffer (get-buffer-create projectile-commander-help-buffer)
(insert "Projectile Commander Methods:\n\n")
(dolist (met projectile-commander-methods)
(insert (format "%c:\t%s\n" (car met) (cadr met))))
(goto-char (point-min))
(help-mode)
(display-buffer (current-buffer) t))
(projectile-commander))
(def-projectile-commander-method ?t
"Open a *shell* buffer for the project."
(projectile-run-vterm))
(def-projectile-commander-method ?\C-? ;; backspace
"Go back to project selection."
(projectile-switch-project))
(def-projectile-commander-method ?d
"Open project root in dired."
(projectile-dired))
(def-projectile-commander-method ?f
"Find file in project."
(projectile-find-file))
(def-projectile-commander-method ?s
"Ripgrep in project."
(consult-ripgrep))
(def-projectile-commander-method ?g
"Git status in project."
(projectile-vc))
)- You can use
persp-state-loadto restore the perspective when emacs was killed
(use-package perspective
:commands (persp-new persp-switch persp-state-save)
:general
(lc/leader-keys
"TAB" '(:ignore true :wk "tab")
"TAB TAB" 'persp-switch
"TAB `" 'persp-switch-last
"TAB d" 'persp-kill
"TAB h" 'persp-prev
"TAB l" 'persp-next
"TAB x" '((lambda () (interactive)
(persp-kill (persp-current-name))) :wk "kill current")
"TAB X" '((lambda () (interactive)
(seq-doseq (name (persp-names))
(persp-kill name))
(lc/main-tab)) :wk "kill all")
"TAB m" '(lc/main-tab :wk "main")
)
:init
(setq persp-state-default-file (expand-file-name ".persp" user-emacs-directory))
(defun lc/main-tab ()
"Jump to the dashboard buffer, if doesn't exists create one."
(interactive)
(persp-switch "main")
(switch-to-buffer dashboard-buffer-name)
(dashboard-mode)
(dashboard-insert-startupify-lists)
(dashboard-refresh-buffer))
(defun lc/is-persp-empty? ()
(seq-filter
;; filter away buffers which should be hidden
(lambda (buffer-name) (not (string-prefix-p "*" buffer-name)))
;; get list of buffer names in current perspective
(mapcar (lambda (elm) (buffer-name (car elm)))
(centaur-tabs-view (centaur-tabs-current-tabset)))
))
:config
(persp-mode)
(add-hook 'kill-emacs-hook #'persp-state-save))- Use
SPC TAB rto reload a project when something went wrong withSPC p p
(use-package persp-projectile
:after projectile
:init
(defun lc/get-last-folder-from-known-proj (path)
"/path/to/something/ returns something"
(car (last (split-string path "\/") 2)))
(defun lc/find-project-from-persp (persp-name)
"known-proj returns /path/to/known-proj"
(car
(seq-filter
(lambda (proj) (string= persp-name (lc/get-last-folder-from-known-proj proj)))
projectile-known-projects-on-file)))
(defun lc/persp-reload-project ()
(interactive)
(let* ((persp (persp-current-name))
(proj-root (lc/find-project-from-persp persp)))
(persp-kill persp)
(projectile-persp-switch-project proj-root)))
:general
(lc/leader-keys
"p p" 'projectile-persp-switch-project
"TAB r" '(lc/persp-reload-project :wk "reload")
;; "TAB o" '((lambda () (interactive)
;; (let ((projectile-switch-project-action #'projectile-find-file))
;; (projectile-persp-switch-project "org")))
;; :wk "org")
)
)- Jump to current file with
SPC f j - With a
diredbuffer open, usedired-other-windowto open another folder where you want to move/copy files from/to - Hide details with
() - Show/hide dotfiles with
H - Mark with
m, unmark withu - Invert selection with
t *has some helpers for marking- First mark some files and then
Kto “hide” them - Open directory in right window with
S-RET- When copying from left window, target will be right window
- Copy with
C
- Open subdir in buffer below with
I- Open them as subtree with
i
- Open them as subtree with
- Open files with macos with
O - View files with
goand exit withq
- To get full path of a file
SPC U 0 Y
(use-package dired
:straight (:type built-in)
:hook
(dired-mode . dired-hide-details-mode)
:general
(lc/leader-keys
"f d" 'dired
"f j" 'dired-jump)
(dired-mode-map
:states 'normal
"h" 'dired-up-directory
"l" 'dired-find-file
"q" 'kill-current-buffer
"F" '((lambda () (interactive)
(let ((fn (dired-get-file-for-visit)))
(start-process "open-directory" nil "open" "-R" fn)))
:wk "open finder")
"X" '(lc/dired-open-externally :wk "open external"))
:init
(setq dired-omit-files "^\\.[^.]\\|$Rhistory\\|$RData\\|__pycache__")
(setq dired-listing-switches "-lah")
(setq ls-lisp-dirs-first t)
(setq ls-lisp-use-insert-directory-program nil)
(setq dired-dwim-target t)
(setf dired-kill-when-opening-new-dired-buffer t)
(defun lc/dired-open-externally ()
"Open marked dired file/folder(s) (or file/folder(s) at point if no marks)
with external application"
(interactive)
(let ((fn (dired-get-file-for-visit)))
(start-process "open-external" nil "open" fn)))
)
(use-package all-the-icons-dired
:if (display-graphic-p)
:hook (dired-mode . (lambda () (interactive)
(unless (file-remote-p default-directory)
(all-the-icons-dired-mode)))))
(use-package dired-hide-dotfiles
:hook (dired-mode . dired-hide-dotfiles-mode)
:config
(evil-collection-define-key 'normal 'dired-mode-map
"H" 'dired-hide-dotfiles-mode))(use-package dired-subtree
:general
(dired-mode-map
:states 'normal
"i" 'dired-subtree-toggle)
:config
(advice-add 'dired-subtree-toggle
:after (lambda () (interactive)
(when all-the-icons-dired-mode
(revert-buffer)))))(use-package dired-rsync
:general
(lc/local-leader-keys
:keymaps 'dired-mode-map
:states 'normal
"r" 'dired-rsync)
:init
(setq dired-rsync-options "-az") ;; default: "-az --info=progress2"
)(use-package persistent-scratch
:hook
(org-mode . (lambda ()
"only set initial-major-mode after loading org"
(setq initial-major-mode 'org-mode)))
:general
(lc/leader-keys
"bs" '((lambda ()
"Load persistent-scratch if not already loaded"
(interactive)
(progn
(unless (boundp 'persistent-scratch-mode)
(require 'persistent-scratch))
(pop-to-buffer "*scratch*")))
:wk "scratch"))
:init
(setq persistent-scratch-autosave-interval 60)
:config
(persistent-scratch-setup-default))(use-package rainbow-delimiters
:hook ((emacs-lisp-mode . rainbow-delimiters-mode)
(clojure-mode . rainbow-delimiters-mode))
)(use-package restart-emacs
:general
(lc/leader-keys
"R" '(restart-emacs :wk "restart"))
)(use-package term
:if lc/is-ipad
:straight (:type built-in)
:general
(lc/leader-keys
"'" (lambda () (interactive) (term "/bin/zsh")))
)
(use-package term
:if lc/is-windows
:straight (:type built-in)
:general
(lc/leader-keys
"'" (lambda () (interactive)
(let ((explicit-shell-file-name "C:/Program Files/Git/bin/bash"))
(call-interactively 'shell))))
;; (setq explicit-shell-file-name "C:/Program Files/Git/bin/bash")
;; (setq explicit-bash.exe-args '("--login" "-i"))
)
- Call e.g.
diredand input/ssh:user@hostname:/path/to/file - In
.ssh/configyou can setControlMaster Yesfor a host, then ssh with the terminal
(use-package tramp
:straight (:type built-in)
:init
;; Disable version control on tramp buffers to avoid freezes.
(setq vc-ignore-dir-regexp
(format "\\(%s\\)\\|\\(%s\\)"
vc-ignore-dir-regexp
tramp-file-name-regexp))
(setq tramp-default-method "ssh")
(setq tramp-auto-save-directory
(expand-file-name "tramp-auto-save" user-emacs-directory))
(setq tramp-persistency-file-name
(expand-file-name "tramp-connection-history" user-emacs-directory))
(setq password-cache-expiry nil)
(setq tramp-use-ssh-controlmaster-options nil)
(setq remote-file-name-inhibit-cache nil)
:config
(customize-set-variable 'tramp-ssh-controlmaster-options
(concat
"-o ControlPath=/tmp/ssh-tramp-%%r@%%h:%%p "
"-o ControlMaster=auto -o ControlPersist=yes"))
(with-eval-after-load 'lsp-mode
(lsp-register-client
(make-lsp-client :new-connection (lsp-tramp-connection "pyright")
:major-modes '(python-mode)
:remote? t
:server-id 'pyright-remote))
)
)
(use-package docker-tramp)(use-package undo-fu
;; :demand
:general
(:states 'normal
"u" 'undo-fu-only-undo
"s-z" 'undo-fu-only-undo
"\C-r" 'undo-fu-only-redo))(use-package undo-fu-session
:after undo-fu
:demand
:init
(setq undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'"))
:config
(global-undo-fu-session-mode)
)NOTE:
magit-cycle-margin-styleto show more precise commit timestamps- On iPad, we may need to
(require 'sendmail)before callingmagit-status - You can use
magit-diff-rangeto compare branches if you select the branch as target
(use-package magit
:general
(lc/leader-keys
"g b" 'magit-blame
"g g" 'magit-status
"g G" 'magit-status-here
"g l" 'magit-log)
(general-nmap
:keymaps '(magit-status-mode-map
magit-stash-mode-map
magit-revision-mode-map
magit-process-mode-map
magit-diff-mode-map)
"TAB" #'magit-section-toggle
"<escape>" #'transient-quit-one)
:init
(setq magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)
(setq magit-log-arguments '("--graph" "--decorate" "--color"))
(setq git-commit-fill-column 72)
;; (setq magit-log-margin (t "%Y-%m-%d %H:%M " magit-log-margin-width t 18))
;; (when lc/is-ipad (require 'sendmail))
:config
(setq magit-buffer-name-format (concat "*" magit-buffer-name-format "*"))
(evil-define-key* '(normal visual) magit-mode-map
"zz" #'evil-scroll-line-to-center)
; adding autostash suffix to magit-pull
(transient-append-suffix 'magit-pull "-A"
'("-A" "Autostash" "--autostash")
)
)(use-package git-timemachine
:hook (git-time-machine-mode . evil-normalize-keymaps)
:init (setq git-timemachine-show-minibuffer-details t)
:general
(general-nmap "SPC g t" 'git-timemachine-toggle)
(git-timemachine-mode-map
"C-k" 'git-timemachine-show-previous-revision
"C-j" 'git-timemachine-show-next-revision
"q" 'git-timemachine-quit))org-ellipsis not shown correctly.
This is caused by an empty line with diff-hl fringe that gets appended to the heading.
To work around this and show the ellipsis, you have to add a whitespace in that empty line.
(use-package diff-hl
:demand
:general
(lc/leader-keys
"g n" '(diff-hl-next-hunk :wk "next hunk")
"g p" '(diff-hl-previous-hunk :wk "prev hunk"))
:hook
((magit-pre-refresh . diff-hl-magit-pre-refresh)
(magit-post-refresh . diff-hl-magit-post-refresh))
:init
(setq diff-hl-draw-borders nil)
;; (setq diff-hl-global-modes '(not org-mode))
;; (setq diff-hl-fringe-bmp-function 'diff-hl-fringe-bmp-from-type)
;; (setq diff-hl-global-modes (not '(image-mode org-mode)))
:config
(global-diff-hl-mode)
)(use-package hydra
:after evil
:demand
:general
(lc/leader-keys "w w" 'evil-windows-hydra/body)
:init
(defhydra evil-windows-hydra (:hint nil
;; :pre (smerge-mode 1)
;; :post (smerge-auto-leave)
)
"
[_h_] ⇢⇠ decrease width [_l_] ⇠⇢ increase width
[_j_] decrease height [_k_] increase height
│ [_q_] quit"
("h" evil-window-decrease-width)
("l" evil-window-increase-width)
("j" evil-window-decrease-height)
("k" evil-window-increase-height)
("q" nil :color blue)
)
)
(use-package smerge-mode
:straight (:type built-in)
:after hydra
:general
(lc/leader-keys "g m" 'smerge-hydra/body)
:hook
(magit-diff-visit-file . (lambda ()
(when smerge-mode
(smerge-hydra/body))))
:init
(defhydra smerge-hydra (:hint nil
:pre (smerge-mode 1)
;; Disable `smerge-mode' when quitting hydra if
;; no merge conflicts remain.
:post (smerge-auto-leave))
"
╭────────┐
Movement Keep Diff Other │ smerge │
╭─────────────────────────────────────────────────┴────────╯
^_g_^ [_b_] base [_<_] upper/base [_C_] Combine
^_C-k_^ [_u_] upper [_=_] upper/lower [_r_] resolve
^_k_ ↑^ [_l_] lower [_>_] base/lower [_R_] remove
^_j_ ↓^ [_a_] all [_H_] hightlight
^_C-j_^ [_RET_] current [_E_] ediff ╭──────────
^_G_^ │ [_q_] quit"
("g" (progn (goto-char (point-min)) (smerge-next)))
("G" (progn (goto-char (point-max)) (smerge-prev)))
("C-j" smerge-next)
("C-k" smerge-prev)
("j" next-line)
("k" previous-line)
("b" smerge-keep-base)
("u" smerge-keep-upper)
("l" smerge-keep-lower)
("a" smerge-keep-all)
("RET" smerge-keep-current)
("\C-m" smerge-keep-current)
("<" smerge-diff-base-upper)
("=" smerge-diff-upper-lower)
(">" smerge-diff-base-lower)
("H" smerge-refine)
("E" smerge-ediff)
("C" smerge-combine-with-next)
("r" smerge-resolve)
("R" smerge-kill-current)
("q" nil :color blue)))(use-package tree-sitter
;; :straight (tree-sitter :host github :repo "ubolonton/emacs-tree-sitter" :depth full)
:hook (python-mode . (lambda ()
(require 'tree-sitter)
(require 'tree-sitter-langs)
(require 'tree-sitter-hl)
(tree-sitter-hl-mode)
)))
(use-package tree-sitter-langs)direnv is expensive so I only do it when it is necessary. I need it in two situations:
python-modeob-jupyter
Instead of simply enabling envrc-mode in every org buffer, I check with the buffer includes a jupyter-python block.
In the ob-jupyter section I then load ob-jupyter only when envrc-mode is loaded and jupyter is found on the PATH
(use-package inheritenv
:straight (inheritenv :type git :host github :repo "purcell/inheritenv"))(use-package envrc
:straight (envrc :type git :host github :repo "purcell/envrc")
:commands (envrc-mode)
:hook ((python-mode . envrc-mode)
(org-jupyter-mode . envrc-mode))
)C-TAB to expand snippets instead of TAB .
You can have #condition: 'auto for the snippet to auto-expand.
See here to share snippets across modes
(use-package yasnippet
:general
(yas-minor-mode-map
:states 'insert
"TAB" 'nil
"C-TAB" 'yas-expand)
:hook
((prog-mode org-mode dap-ui-repl-mode vterm-mode) . yas-minor-mode)
:init
;; (setq yas-prompt-functions '(yas-ido-prompt))
(defun lc/yas-try-expanding-auto-snippets ()
(when (and (boundp 'yas-minor-mode) yas-minor-mode)
(let ((yas-buffer-local-condition ''(require-snippet-condition . auto)))
(yas-expand))))
:config
(yas-reload-all)
(add-hook 'post-command-hook #'lc/yas-try-expanding-auto-snippets)
)(use-package yasnippet
:config
(setq lc/greek-alphabet
'(("a" . "\\alpha")
("b" . "\\beta" )
("g" . "\\gamma")
("d" . "\\delta")
("e" . "\\epsilon")
("z" . "\\zeta")
("h" . "\\eta")
("t" . "\\theta")
("i" . "\\iota")
("k" . "\\kappa")
("l" . "\\lambda")
("m" . "\\mu")
("n" . "\\nu")
("x" . "\\xi")
("p" . "\\pi")
("r" . "\\rho")
("s" . "\\sigma")
("t" . "\\tau")
("u" . "\\upsilon")
("f" . "\\phi")
("c" . "\\chi")
("v" . "\\psi")
("g" . "\\omega")))
(setq lc/latex-greek-prefix "'")
;; The same for capitalized letters
(dolist (elem lc/greek-alphabet)
(let ((key (car elem))
(value (cdr elem)))
(when (string-equal key (downcase key))
(add-to-list 'lc/greek-alphabet
(cons
(capitalize (car elem))
(concat
(substring value 0 1)
(capitalize (substring value 1 2))
(substring value 2)))))))
(yas-define-snippets
'latex-mode
(mapcar
(lambda (elem)
(list (concat lc/latex-greek-prefix (car elem)) (cdr elem) (concat "Greek letter " (car elem))))
lc/greek-alphabet))
(setq lc/english-alphabet
'("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"))
(dolist (elem lc/english-alphabet)
(when (string-equal elem (downcase elem))
(add-to-list 'lc/english-alphabet (upcase elem))))
(setq lc/latex-mathbb-prefix "`")
(yas-define-snippets
'latex-mode
(mapcar
(lambda (elem)
(list (concat lc/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem)))
lc/english-alphabet))
(setq lc/latex-math-symbols
'(("x" . "\\times")
("." . "\\cdot")
("v" . "\\forall")
("s" . "\\sum_{$1}^{$2}$0")
("p" . "\\prod_{$1}^{$2}$0")
("e" . "\\exists")
("i" . "\\int_{$1}^{$2}$0")
("c" . "\\cap")
("u" . "\\cup")
("0" . "\\emptyset")))
(setq lc/latex-math-prefix "''")
(yas-define-snippets
'latex-mode
(mapcar
(lambda (elem)
(let ((key (car elem))
(value (cdr elem)))
(list (concat lc/latex-math-prefix key) value (concat "Math symbol " value))))
lc/latex-math-symbols))
)(use-package vterm
:if (not lc/is-ipad)
:general
(general-imap
:keymaps 'vterm-mode-map
"M-l" 'vterm-send-right
"M-h" 'vterm-send-left)
:config
(setq vterm-shell (executable-find "fish")
vterm-max-scrollback 10000))- You can use universal argument to create a new vterm buffer (
SPC U SPC ')
(use-package vterm-toggle
:if (not lc/is-ipad)
:general
(lc/leader-keys
"'" 'vterm-toggle)
:init
(setq vterm-toggle-scope 'project)
)(use-package emacs
:general
(lc/leader-keys
"s g" '(google-search :wk "google"))
:init
(defun google-search-str (str)
(browse-url
(concat "https://www.google.com/search?q=" str)))
(defun google-search ()
"Google search region, if active, or ask for search string."
(interactive)
(if (region-active-p)
(google-search-str
(buffer-substring-no-properties (region-beginning)
(region-end)))
(google-search-str (read-from-minibuffer "Search: "))))
)(use-package emacs
:general
(lc/leader-keys
"s c" '(github-code-search :wk "code (github)"))
:init
(defun github-code-search ()
"Search code on github for a given language."
(interactive)
(let ((language (completing-read
"Language: "
'("Emacs Lisp" "Python" "Clojure" "R")))
(code (read-string "Code: ")))
(browse-url
(concat "https://github.com/search?l=" language
"&type=code&q=" code))))
)(use-package transient
:general
(lc/leader-keys
"h h" 'lc/help-transient)
:config
(transient-define-prefix lc/help-transient ()
["Help Commands"
["Mode & Bindings"
("m" "Mode" describe-mode)
("b" "Major Bindings" which-key-show-full-major-mode)
("B" "Minor Bindings" which-key-show-full-minor-mode-keymap)
("d" "Descbinds" describe-bindings)
]
["Describe"
("c" "Command" helpful-command)
("f" "Function" helpful-callable)
("v" "Variable" helpful-variable)
("k" "Key" helpful-key)
]
["Info on"
("C-c" "Emacs Command" Info-goto-emacs-command-node)
("C-f" "Function" info-lookup-symbol)
("C-v" "Variable" info-lookup-symbol)
("C-k" "Emacs Key" Info-goto-emacs-key-command-node)
]
["Goto Source"
("L" "Library" find-library)
("F" "Function" find-function)
("V" "Variable" find-variable)
("K" "Key" find-function-on-key)
]
]
[
["Internals"
("e" "Echo Messages" view-echo-area-messages)
("l" "Lossage" view-lossage)
]
["Describe"
("s" "Symbol" helpful-symbol)
("." "At Point " helpful-at-point)
;; ("C-f" "Face" counsel-describe-face)
("w" "Where Is" where-is)
("=" "Position" what-cursor-position)
]
["Info Manuals"
("C-i" "Info" info)
("C-4" "Other Window " info-other-window)
("C-e" "Emacs" info-emacs-manual)
;; ("C-l" "Elisp" info-elisp-manual)
]
["Exit"
("q" "Quit" transient-quit-one)
("<escape>" "Quit" transient-quit-one)
]
;; ["External"
;; ("W" "Dictionary" lookup-word-at-point)
;; ("D" "Dash" dash-at-point)
;; ]
]
)
)- If after increasing and resetting font size your modeline is still “fat”, you can reset, decrease and reset to fix it
(use-package default-text-scale
:hook (emacs-startup . default-text-scale-mode)
)
(use-package transient
:general
(lc/leader-keys
"t f" 'lc/font-size-transient)
:config
(transient-define-prefix lc/font-size-transient ()
"Change font size"
["Font size"
("+" "Increase" (lambda () (interactive) (default-text-scale-increase) (with-eval-after-load 'doom-modeline (doom-modeline-refresh-font-width-cache)) (lc/font-size-transient)))
("-" "Decrease" (lambda () (interactive) (default-text-scale-decrease) (with-eval-after-load 'doom-modeline (doom-modeline-refresh-font-width-cache)) (lc/font-size-transient)))
("0" "Reset" (lambda () (interactive)
(setq default-text-scale--complement 0)
(set-face-attribute 'default
nil
:height (lc/get-font-size))
(message "Default font size is now %d"
(face-attribute 'default :height))
(lc/font-size-transient)))
])
(transient-bind-q-to-quit)
)(use-package olivetti
:general
(lc/leader-keys
"t o" '(olivetti-mode :wk "olivetti"))
:init
(setq olivetti-body-width 100)
(setq olivetti-recall-visual-line-mode-entry-state t))(use-package darkroom
:init
;; Don't scale the text, so ugly man!
(setq darkroom-text-scale-increase 3)
:general
(lc/leader-keys
"t F" '(darkroom-tentative-mode :wk "focus")))(use-package avy
:general
(general-nmap
;; "gs" 'avy-goto-char-2)
"gs" 'avy-goto-char-timer)
;; :bind (("C-:" . avy-goto-char)
;; ("C-'" . avy-goto-char-2)
;; ("C-;" . avy-goto-char-2)
;; ("M-g f" . avy-goto-line)
;; ("M-g w" . avy-goto-word-1)
;; ("M-g e" . avy-goto-word-0))
:hook (after-init . avy-setup-default)
:init
(setq avy-style 'pre)
;; :custom ( avy-all-windows nil
;; avy-all-windows-alt t
;; avy-background t
;; avy-style 'pre)
)devdocs-installto install docs of e.g.pandas
(use-package devdocs
;; :demand
:general
(lc/leader-keys
"hD" 'devdocs-lookup
)
)(use-package imenu-list
:general
(lc/leader-keys
"t i" 'imenu-list-smart-toggle
)
)(use-package lsp-mode
:commands
(lsp lsp-deferred)
:hook
((lsp-mode . (lambda () (setq-local evil-lookup-func #'lsp-describe-thing-at-point)))
(lsp-mode . lsp-enable-which-key-integration))
:general
(lc/local-leader-keys
:states 'normal
:keymaps 'lsp-mode-map
"i" '(:ignore t :which-key "import")
"i o" '(lsp-organize-imports :wk "optimize")
"l" '(:keymap lsp-command-map :wk "lsp")
"a" '(lsp-execute-code-action :wk "code action")
"r" '(lsp-rename :wk "rename"))
;; (lsp-mode-map
;; :states 'normal
;; "gD" 'lsp-find-references)
:init
(setq lsp-restart 'ignore)
(setq lsp-eldoc-enable-hover nil)
(setq lsp-enable-file-watchers nil)
(setq lsp-signature-auto-activate nil)
(setq lsp-modeline-diagnostics-enable nil)
(setq lsp-keep-workspace-alive nil)
(setq lsp-auto-execute-action nil)
(setq lsp-before-save-edits nil)
(setq lsp-headerline-breadcrumb-enable nil)
(setq lsp-diagnostics-provider :none)
)(use-package lsp-ui
:hook
((lsp-mode . lsp-ui-mode)
;; (lsp-mode . (lambda () (setq-local evil-goto-definition-functions '(lambda (&rest args) (lsp-ui-peek-find-definitions)))))
)
;; :bind
;; (:map lsp-ui-mode-map
;; ([remap lsp-find-references] . lsp-ui-peek-find-references))
:general
;; (lc/local-leader-keys
;; "h" 'lsp-ui-doc-show
;; "H" 'lsp-ui-doc-hide)
(lsp-ui-peek-mode-map
:states 'normal
"C-j" 'lsp-ui-peek--select-next
"C-k" 'lsp-ui-peek--select-prev)
(outline-mode-map
:states 'normal
"C-j" 'nil
"C-k" 'nil)
:init
(setq lsp-ui-doc-show-with-cursor nil)
(setq lsp-ui-doc-show-with-mouse nil)
(setq lsp-ui-peek-always-show t)
(setq lsp-ui-peek-fontify 'always)
)(use-package dap-mode
:hook
((dap-mode . corfu-mode)
(dap-terminated . lc/hide-debug-windows)
(dap-session-created . (lambda (_arg) (projectile-save-project-buffers)))
(dap-ui-repl-mode . (lambda () (setq-local truncate-lines t))))
:general
(lc/local-leader-keys
:states '(normal)
:keymaps '(python-mode-map dap-ui-repl-mode-map)
"d d" '(dap-debug :wk "debug")
"d b" '(dap-breakpoint-toggle :wk "breakpoint toggle")
"d B" '(dap-ui-breakpoints-list :wk "breakpoint list")
"d c" '(dap-continue :wk "continue")
"d n" '(dap-next :wk "next")
"d e" '(dap-eval-thing-at-point :wk "eval")
"d i" '(dap-step-in :wk "step in")
"d l" '(dap-debug-last :wk "step in")
"d q" '(dap-disconnect :wk "quit")
"d r" '(dap-ui-repl :wk "repl")
"d h" '(dap-hydra :wk "hydra")
"d i" '(lc/dap-inspect-df :wk "view df")
;; "d t" '(lc/dap-dtale-df :wk "dtale df")
)
(dap-ui-repl-mode-map
:states '(insert)
"<up>" 'comint-previous-input
)
(:keymaps 'dap-ui-repl-mode-map
"<backtab>" 'dabbrev-completion
"TAB" 'lc/py-indent-or-complete)
:init
;; (defun lc/dap-dtale-df (dataframe)
;; "Show df in tale in default browser"
;; (interactive (list (read-from-minibuffer "DataFrame: " (evil-find-symbol nil))))
;; (dap-eval (concat "import dtale; dtale.show(" dataframe ", open_browser=True)")))
(setq lc/dap-temp-dataframe-buffer "*inspect-df*")
(setq lc/dap-temp-dataframe-path "~/tmp-inspect-df.csv")
(defun lc/dap-inspect-df (dataframe)
"Save the df to csv and open the file with csv-mode"
(interactive (list (read-from-minibuffer "DataFrame: " (evil-find-symbol nil))))
(dap-eval (format "%s.to_csv('%s', index=False)" dataframe lc/dap-temp-dataframe-path))
(sleep-for 1)
(find-file-other-window lc/dap-temp-dataframe-path)
)
;; prevent minibuffer prompt about reloading from disk
(setq revert-without-query '("~/tmp-inspect-df.csv"))
;; (setq dap-auto-configure-features '(locals repl))
(setq dap-auto-configure-features '(sessions repl))
(setq dap-python-debugger 'debugpy)
;; show stdout
(setq dap-auto-show-output t)
(setq dap-output-window-min-height 10)
(setq dap-output-window-max-height 200)
(setq dap-overlays-use-overlays nil)
;; hide stdout window when done
(defun lc/hide-debug-windows (session)
"Hide debug windows when all debug sessions are dead."
(unless (-filter 'dap--session-running (dap--get-sessions))
;; delete output buffer
;; (when-let (window (display-buffer-in-side-window
;; (dap--debug-session-output-buffer (dap--cur-session-or-die))
;; `((side . bottom) (slot . 5) (window-width . 0.20))))
;; (delete-window window))
(lc/kill-output-buffer)
;; delete dataframe inspector window
;; (when-let
;; (win (get-buffer-window (get-file-buffer lc/dap-temp-dataframe-path)))
;; (delete-window win))
)
)
(defun lc/dap-python--executable-find (orig-fun &rest args)
(executable-find "python"))
(defun lc/kill-output-buffer ()
"Go to output buffer."
(interactive)
(let ((win (display-buffer-in-side-window
(dap--debug-session-output-buffer (dap--cur-session-or-die))
`((side . bottom) (slot . 5) (window-width . 0.20)))))
(delete-window win)))
(defun lc/window-resize-to-percentage (percentage)
(interactive)
(window-resize nil (- (truncate (* percentage (frame-height))) (window-height))))
(defun lc/reset-dap-windows ()
(interactive)
;; display sessions and repl
(seq-doseq (feature-start-stop dap-auto-configure-features)
(when-let
(start-stop (alist-get feature-start-stop
;; <
dap-features->windows
))
(funcall (car start-stop))))
;; display output buffer
(save-excursion (dap-go-to-output-buffer t))
;; resize window
(save-window-excursion
;; switch to main window
(winum-select-window-1)
(lc/window-resize-to-percentage 0.66)
)
)
:config
;; configure windows
(require 'dap-ui)
(setq dap-ui-buffer-configurations
'(("*dap-ui-sessions*"
(side . bottom)
(slot . 1)
(window-height . 0.33))
("*debug-window*"
(side . bottom)
(slot . 2)
(window-height . 0.33))
("*dap-ui-repl*"
(side . bottom)
(slot . 3)
(window-height . 0.33))))
(dap-ui-mode 1)
;; python virtualenv
(require 'dap-python)
(advice-add 'dap-python--pyenv-executable-find :around #'lc/dap-python--executable-find)
;; debug templates
(defvar dap-script-args (list :type "python"
:args []
:cwd "${workspaceFolder}"
:justMyCode :json-false
:request "launch"
:debugger 'debugpy
:name "dap-debug-script"))
(defvar dap-test-args (list :type "python-test-at-point"
:args ""
:justMyCode :json-false
;; :cwd "${workspaceFolder}"
:request "launch"
:module "pytest"
:debugger 'debugpy
:name "dap-debug-test-at-point"))
(defvar eco-cold-start (list
:name "mill"
:type "python"
:request "launch"
:program (expand-file-name "~/git/ran_optimization/scripts_smart_sleep_orchestration/find_cold_start_smart_sleep_thresholds.py")
;; :env '(("NO_JSON_LOG" . "true"))
;; :args ["-m" "mill" "--config" "user_luca"]
))
(dap-register-debug-template "dap-debug-script" dap-script-args)
(dap-register-debug-template "dap-debug-test-at-point" dap-test-args)
(dap-register-debug-template "eco-cold-start" eco-cold-start)
;; bind the templates
(lc/local-leader-keys
:keymaps 'python-mode-map
"d t" '((lambda () (interactive) (dap-debug dap-test-args)) :wk "test")
"d s" '((lambda () (interactive) (dap-debug dap-script-args)) :wk "script")
)
)- In a python buffer use
run-pythonto start an inferior python process or,' - Use eval operator so eval lines with
grr
(use-package python-mode
:hook
((envrc-mode . (lambda ()
(when (executable-find "ipython")
(setq python-shell-interpreter (executable-find "ipython"))))))
:general
(lc/local-leader-keys
:keymaps 'python-mode-map
"'" 'run-python)
(python-mode-map
:states 'normal
"gz" nil
"C-j" nil)
(python-mode-map
:states 'insert
"TAB" 'lc/py-indent-or-complete)
:init
(setq python-indent-offset 0)
(defun lc/py-indent-or-complete ()
(interactive "*")
(window-configuration-to-register py--windows-config-register)
(cond ((use-region-p)
(py-indent-region (region-beginning) (region-end)))
((or (bolp)
(member (char-before) (list 9 10 12 13 32 ?: ;; ([{
?\) ?\] ?\}))
;; (not (looking-at "[ \t]*$"))
)
(py-indent-line))
((comint-check-proc (current-buffer))
(ignore-errors (completion-at-point)))
(t
(completion-at-point))))
:config
(setq python-shell-interpreter-args "-i --simple-prompt --no-color-info"
python-shell-prompt-regexp "In \\[[0-9]+\\]: "
python-shell-prompt-block-regexp "\\.\\.\\.\\.: "
python-shell-prompt-output-regexp "Out\\[[0-9]+\\]: "
python-shell-completion-setup-code
"from IPython.core.completerlib import module_completion"
python-shell-completion-string-code
"';'.join(get_ipython().Completer.all_completions('''%s'''))\n")
)(use-package lsp-pyright
:init
(setq lsp-pyright-typechecking-mode "basic") ;; too much noise in "real" projects
:hook (python-mode . (lambda ()
(require 'lsp-pyright)
(lsp-deferred))))(use-package python-pytest
:general
(lc/local-leader-keys
:keymaps 'python-mode-map
"t" '(:ignore t :wk "test")
"t d" '(python-pytest-dispatch :wk "dispatch")
"t f" '(python-pytest-file :wk "file")
"t t" '(python-pytest-function :wk "function"))
:init
(setq python-pytest-arguments '("--color" "--failed-first"))
(defun lc/pytest-use-venv (orig-fun &rest args)
(if-let ((python-pytest-executable (executable-find "pytest")))
(apply orig-fun args)
(apply orig-fun args)))
:config
(advice-add 'python-pytest--run :around #'lc/pytest-use-venv)
)flycheck-verify-setup is your best friend.
(use-package flycheck
:hook ((lsp-mode . flycheck-mode)
(envrc-mode . (lambda ()
;; (setq flycheck-python-flake8-executable (executable-find "python"))
;; (setq flycheck-checker 'python-flake8)
;; (setq flycheck-flake8rc ".flake8")
(setq flycheck-python-pylint-executable (executable-find "python"))
(setq flycheck-checker 'python-pylint)
)))
:init
(setq flycheck-indication-mode 'right-fringe)
;; only check on save
(setq flycheck-check-syntax-automatically '(mode-enabled save))
)(use-package blacken
:general
(lc/local-leader-keys
:keymaps 'python-mode-map
"=" '(blacken-buffer :wk "format"))
)(use-package csv-mode
:hook (csv-mode . lc/init-csv-mode)
:general
(lc/local-leader-keys
:keymaps 'csv-mode-map
:states 'normal
"a" '(csv-align-fields :wk "align fields")
"A" '(lc/csv-align-visible :wk "align fields, visible")
"i" '(lc/init-csv-mode :wk "init csv mode")
"u" '(csv-unalign-fields :wk "unalign fields")
"s" '(csv-sort-fields :wk "sort fields")
";" '(lc/set-csv-semicolon-separator :wk "set semicolon sep")
"," '(lc/reset-csv-separators :wk "set comma sep"))
:init
(defun lc/csv-align-visible (&optional arg)
"Align visible fields"
(interactive "P")
(csv-align-fields nil (window-start) (window-end)))
(defun lc/set-csv-semicolon-separator ()
(interactive)
(customize-set-variable 'csv-separators '(";")))
(defun lc/reset-csv-separators ()
(interactive)
(customize-set-variable 'csv-separators lc/default-csv-separators))
(defun lc/init-csv-mode ()
(interactive)
(lc/set-csv-separators)
(lc/csv-highlight)
(call-interactively 'csv-align-fields))
:config
(require 'cl)
(require 'color)
(defun lc/set-csv-separators ()
(interactive)
(let* ((n-commas (count-matches "," (point-at-bol) (point-at-eol)))
(n-semicolons (count-matches ";" (point-at-bol) (point-at-eol))))
(if ( ; <
> n-commas n-semicolons)
(customize-set-variable 'csv-separators '("," " "))
(customize-set-variable 'csv-separators '(";" " ")))))
(defun lc/csv-highlight ()
(interactive)
(font-lock-mode 1)
(let* ((separator (string-to-char (car csv-separators)))
(n (count-matches (string separator) (point-at-bol) (point-at-eol)))
(colors (loop for i from 0 to 1.0 by (/ 2.0 n)
collect (apply #'color-rgb-to-hex
(color-hsl-to-rgb i 0.3 0.5)))))
(loop for i from 2 to n by 2
for c in colors
for r = (format "^\\([^%c\n]+%c\\)\\{%d\\}" separator separator i)
do (font-lock-add-keywords nil `((,r (1 '(face (:foreground ,c)))))))))
)(use-package numpydoc
:general
(lc/local-leader-keys
:keymaps 'python-mode-map
"n" '(numpydoc-generate :wk "numpydoc"))
:init
(setq numpydoc-insertion-style nil)
(setq numpydoc-insert-examples-block nil)
)zmq installation:
- Need to have
automake,autoconf - In
straight/build/zmq/srcrunautoreconf -i - In
straight/build/zmqrunmake
emacs-zmq installation:
- In
straight/build/emacs-zmqrunwget https://github.com/nnicandro/emacs-zmq/releases/download/v0.10.10/emacs-zmq-x86_64-apple-darwin17.4.0.tar.gz - Then
tar -xzf emacs-zmq-x86_64-apple-darwin17.4.0.tar.gz - Finally
cp emacs-zmq-x86_64-apple-darwin17.4.0/emacs-zmq.so emacs-zmq.dylib - In the REPL you can use
M-p/M-nto navigate previous prompts
(use-package jupyter
:straight (:no-native-compile t :no-byte-compile t) ;; otherwise we get jupyter-channel void
:general
(lc/local-leader-keys
:keymaps '(jupyter-org-interaction-mode-map jupyter-repl-interaction-mode-map)
:states 'normal
"e" '(:ignore true :wk "eval")
"e e" '(jupyter-eval-line-or-region :wk "line")
"e d" '(jupyter-eval-defun :wk "defun")
"e b" '((lambda () (interactive) (lc/jupyter-eval-buffer)) :wk "buffer")
"e r" '(jupyter-eval-remove-overlays :wk "remove overlays")
"k" '(:ignore true :wk "kernel")
"k d" '(lc/kill-repl-kernel :wk "kill")
"k i" '(jupyter-org-interrupt-kernel :wk "interrupt")
"k r" '(jupyter-repl-restart-kernel :wk "restart")
"J" '(lc/jupyter-repl :wk "jupyter REPL")
)
(lc/local-leader-keys
:keymaps '(jupyter-org-interaction-mode-map jupyter-repl-interaction-mode-map)
:states 'visual
"e" '(jupyter-eval-line-or-region :wk "region")
)
:init
(setq jupyter-repl-prompt-margin-width 4)
(setq jupyter-eval-use-overlays t)
(defun jupyter-command-venv (&rest args)
"This overrides jupyter-command to use the virtualenv's jupyter"
(let ((jupyter-executable (executable-find "jupyter")))
(with-temp-buffer
(when (zerop (apply #'process-file jupyter-executable nil t nil args))
(string-trim-right (buffer-string))))))
(defun lc/jupyter-eval-buffer ()
"Send the contents of BUFFER using `jupyter-current-client'."
(interactive)
(jupyter-eval-string (jupyter-load-file-code (buffer-file-name))))
(defun lc/jupyter-repl ()
"If a buffer is already associated with a jupyter buffer, then pop to it. Otherwise start a jupyter kernel."
(interactive)
(if (bound-and-true-p jupyter-current-client)
(jupyter-repl-pop-to-buffer)
(call-interactively 'jupyter-repl-associate-buffer)))
(defun lc/kill-repl-kernel ()
"Kill repl buffer associated with current jupyter kernel"
(interactive)
(if jupyter-current-client
(jupyter-with-repl-buffer jupyter-current-client
(kill-buffer (current-buffer)))
(error "Buffer not associated with a REPL, see `jupyter-repl-associate-buffer'"))
)
(advice-add 'jupyter-command :override #'jupyter-command-venv)
;; TODO refactor to avoid duplication of dap code
(setq lc/jupyter-temp-dataframe-buffer "*inspect-df*")
(setq lc/jupyter-temp-dataframe-path "~/tmp-inspect-df.csv")
(defun lc/jupyter-inspect-df (dataframe)
"Save the df to csv and open the file with csv-mode"
(interactive (list (read-from-minibuffer "DataFrame: " (evil-find-symbol nil))))
(jupyter-eval (format "%s.to_csv('%s', index=False)" dataframe lc/jupyter-temp-dataframe-path))
(find-file-other-window lc/jupyter-temp-dataframe-path)
)
(add-to-list 'display-buffer-alist
'("\\*jupyter-output\\*\\|\\*jupyter-error\\*"
(cons 'display-buffer-no-window
'((allow-no-window . t)))
))
)- We can only load
ob-jupyterwhen we havejupyteron ourPATH.- We assume
jupyteris always installed in a virtual env associated with an.envrcfile - We load jupyter when we activate
envrc-modeifjupyteris available
- We assume
- We need to add a
:sessionto each code block- We can use the snippet
+ha - Also use
:display plain
- We can use the snippet
- First install
zmq. Then runenvrc-allowand thenlc/load-ob-jupyterto load it - Use
toggle-truncate-lineswhen printing dataframes
When exporting .org file to HTML, we can add this header:
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://gongzhitaao.org/orgcss/org.css"/>
We can avoid evaluation of code with:
(use-package jupyter
:straight (:no-native-compile t :no-byte-compile t) ;; otherwise we get jupyter-channel void
:general
(lc/local-leader-keys
:keymaps 'org-mode-map
"=" '((lambda () (interactive) (jupyter-org-insert-src-block t nil)) :wk "block below")
"," 'org-ctrl-c-ctrl-c
"m" '(jupyter-org-merge-blocks :wk "merge")
"+" '(jupyter-org-insert-src-block :wk "block above")
"?" '(jupyter-inspect-at-point :wk "inspect")
"x" '(jupyter-org-kill-block-and-results :wk "kill block"))
:hook ((jupyter-org-interaction-mode . (lambda () (lc/add-local-electric-pairs '((?' . ?')))))
(jupyter-repl-persistent-mode . (lambda () ;; we activate org-interaction-mode ourselves
(when (derived-mode-p 'org-mode)
;; (setq-local company-backends '((company-capf)))
(setq-local evil-lookup-func #'jupyter-inspect-at-point)
(jupyter-org-interaction-mode))))
(envrc-mode . lc/load-ob-jupyter))
:init
(setq org-babel-default-header-args:jupyter-python '((:async . "yes")
(:pandoc t)
(:kernel . "python3")))
(setq org-babel-default-header-args:jupyter-R '((:pandoc t)
(:async . "yes")
(:kernel . "ir")))
(defun lc/org-load-jupyter ()
(org-babel-do-load-languages 'org-babel-load-languages
(append org-babel-load-languages
'((jupyter . t)))))
(defun lc/load-ob-jupyter ()
;; only try to load in org-mode
(when (derived-mode-p 'org-mode)
;; skip if already loaded
(unless (member '(jupyter . t) org-babel-load-languages)
;; only load if jupyter is available
(when (executable-find "jupyter")
(lc/org-load-jupyter)))))
:config
(cl-defmethod jupyter-org--insert-result (_req context result)
(let ((str
(org-element-interpret-data
(jupyter-org--wrap-result-maybe
context (if (jupyter-org--stream-result-p result)
(thread-last result
jupyter-org-strip-last-newline
jupyter-org-scalar)
result)))))
(if (< (length str) 100000) ;; >
(insert str)
(insert (format ": Result was too long! Length was %d" (length str)))))
(when (/= (point) (line-beginning-position))
;; Org objects such as file links do not have a newline added when
;; converting to their string representation by
;; `org-element-interpret-data' so insert one in these cases.
(insert "\n")))
;;Remove text/html since it's not human readable
;; (delete :text/html jupyter-org-mime-types)
;; (with-eval-after-load 'org-src
;; (add-to-list 'org-src-lang-modes '("jupyter-python" . python))
;; (add-to-list 'org-src-lang-modes '("jupyter-R" . R)))
)(use-package ess
:general
(lc/local-leader-keys
:keymaps 'ess-r-mode-map
:states 'normal
"R" '(R :wk "R")
"q" '(ess-quit :wk "quit")
"RET" '(ess-eval-line-visibly-and-step :wk "line and step")
;; debug
"d b" '(ess-bp-set :wk "breakpoint")
"d n" '(ess-debug-command-next :wk "next")
"d q" '(ess-debug-command-quit :wk "quit")
"d c" '(ess-bp-next :wk "continue")
"d f" '(ess-debug-flag-for-debugging :wk "flag function")
"d F" '(ess-debug-unflag-for-debugging :wk "unflag function")
"d p" '(ess-debug-goto-debug-point :wk "go to point")
;; "e l" '(ess-eval-line :wk "eval line")
"e p" '(ess-eval-paragraph :wk "paragraph")
"e f" '(ess-eval-function :wk "function")
"h" '(:keymap ess-doc-map :which-key "help")
;; "h" '(ess-display-help-on-object :wk "help")
)
(lc/local-leader-keys
:keymaps 'ess-r-mode-map
:states 'visual
"RET" '(ess-eval-region-or-line-visibly-and-step :wk "line and step"))
:init
(setq ess-eval-visibly 'nowait)
(setq ess-R-font-lock-keywords '((ess-R-fl-keyword:keywords . t)
(ess-R-fl-keyword:constants . t)
(ess-R-fl-keyword:modifiers . t)
(ess-R-fl-keyword:fun-defs . t)
(ess-R-fl-keyword:assign-ops . t)
(ess-R-fl-keyword:%op% . t)
(ess-fl-keyword:fun-calls . t)
(ess-fl-keyword:numbers . t)
(ess-fl-keyword:operators . t)
(ess-fl-keyword:delimiters . t)
(ess-fl-keyword:= . t)
(ess-R-fl-keyword:F&T . t)))
;; (setq ess-first-continued-statement-offset 2
;; ess-continued-statement-offset 0
;; ess-expression-offset 2
;; ess-nuke-trailing-whitespace-p t
;; ess-default-style 'DEFAULT)
;; (setq ess-r-flymake-linters "line_length_linter = 120")
)(use-package ess-view-data
:general
(lc/local-leader-keys
:keymaps 'ess-r-mode-map
:states 'normal
"hd" 'ess-R-dv-pprint
"ht" 'ess-R-dv-ctable
))(use-package lsp-mode
:hook
(ess-r-mode . lsp-deferred)
)(use-package emacs
:straight (:type built-in)
:general
(general-nmap
:keymaps 'emacs-lisp-mode-map
:states 'normal
"gr" nil) ;; interferes with eval-operator
)- Wrap with
SPC l w - Raise with
SPC l r - Enter
lisp-statewithSPC l . - Navigate symbols with
jandk - Navigate forms with
handl - Go to parent sexp with
U
(use-package evil-lisp-state
:after evil
;; :demand
:init
(setq evil-lisp-state-enter-lisp-state-on-command nil)
(setq evil-lisp-state-global t)
;; (setq evil-lisp-state-major-modes '(org-mode emacs-lisp-mode clojure-mode clojurescript-mode lisp-interaction-mode))
:config
(evil-lisp-state-leader "SPC l")
)(use-package eros
:hook ((emacs-lisp-mode org-mode lisp-interaction-mode) . eros-mode)
:general
(lc/local-leader-keys
:keymaps '(org-mode-map emacs-lisp-mode-map lisp-interaction-mode-map)
:states 'normal
"e l" '(eros-eval-last-sexp :wk "last sexp")
;; "e d" '((lambda () (interactive) (eros-eval-defun t)) :wk "defun")
"e b" '(eval-buffer :wk "buffer"))
(lc/local-leader-keys
:keymaps '(org-mode-map emacs-lisp-mode-map lisp-interaction-mode-map)
:states 'visual
;; "e" '((lambda (start end)
;; (interactive (list (region-beginning) (region-end)))
;; (eval-region start end t))
;; :wk "region")
;; "e" '((lambda (start end)
;; (interactive (list (region-beginning) (region-end)))
;; (eros--eval-overlay
;; (eval-region start end)
;; end))
;; :wk "region")
"e" '(eros-eval-region :wk "region")
)
:init
(defun eros-eval-region (start end)
(interactive "r")
(eros--eval-overlay
(string-trim
(with-output-to-string
(eval-region start end standard-output)))
(max (point) (mark))))
)(use-package nix-mode
:mode "\\.nix\\'")(use-package clojure-mode
:mode "\\.clj$"
:init
(setq clojure-align-forms-automatically t)
)(use-package clojure-mode
:hook
((clojure-mode clojurescript-mode)
. (lambda ()
(setq-local lsp-enable-indentation nil ; cider indentation
lsp-enable-completion-at-point nil ; cider completion
)
(lsp-deferred)))
)(use-package cider
:hook ((cider-repl-mode . evil-normalize-keymaps)
(cider-mode . (lambda ()
(setq-local evil-lookup-func #'cider-doc)))
(cider-mode . eldoc-mode))
:general
(lc/local-leader-keys
:keymaps 'clojure-mode-map
"c" '(cider-connect-clj :wk "connect")
"C" '(cider-connect-cljs :wk "connect (cljs)")
"j" '(cider-jack-in :wk "jack in")
"J" '(cider-jack-in-cljs :wk "jack in (cljs)")
"d d" 'cider-debug-defun-at-point
"e b" 'cider-eval-buffer
"e l" 'cider-eval-last-sexp
"e L" 'cider-pprint-eval-last-sexp-to-comment
"e d" '(cider-eval-defun-at-point :wk "defun")
"e D" 'cider-pprint-eval-defun-to-comment
"h" 'cider-clojuredocs-web
"K" 'cider-doc
"q" '(cider-quit :qk "quit")
)
(lc/local-leader-keys
:keymaps 'clojure-mode-map
:states 'visual
"e" 'cider-eval-region)
:init
(setq nrepl-hide-special-buffers t)
(setq nrepl-sync-request-timeout nil)
(setq cider-repl-display-help-banner nil)
)(use-package org
:config
(require 'ob-clojure)
(setq org-babel-clojure-backend 'cider)
);; keep the file indented
(use-package aggressive-indent
:hook ((clojure-mode . aggressive-indent-mode)
(emacs-lisp-mode . aggressive-indent-mode)))(use-package markdown-mode
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
("\\.md\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode))
:init
(setq markdown-command "multimarkdown")
(setq markdown-fontify-code-blocks-natively t)
)(use-package yaml-mode
:mode ((rx ".yml" eos) . yaml-mode))(use-package toml-mode
:mode "\\.toml\\'")(use-package stan-mode
:mode ("\\.stan\\'" . stan-mode)
:hook (stan-mode . stan-mode-setup)
;;
:config
;; The officially recommended offset is 2.
(setq stan-indentation-offset 2))SPC x x to search the web! You can also visit a URL in the buffer.
With the web browser open, scroll with j / k .
To visit a link, SPC x l
(use-package xwwp
:straight (xwwp :type git :host github :repo "canatella/xwwp")
:commands (xwwp)
:general
(lc/leader-keys
"x x" '((lambda () (interactive)
(let ((current-prefix-arg 4)) ;; emulate C-u universal arg
(call-interactively 'xwwp)))
:wk "search or visit")
"x l" '(xwwp-follow-link :wk "link")
"x b" '(xwidget-webkit-back :wk "back"))
;; :custom
;; (setq xwwp-follow-link-completion-system 'ivy)
;; :bind (:map xwidget-webkit-mode-map
;; ("v" . xwwp-follow-link))
)- Search with
s - Open in browser with
S-RET - Open in
xwwpwithx
(use-package elfeed
:straight (elfeed :type git :host github :repo "skeeto/elfeed")
:hook (elfeed-search-mode . elfeed-update)
:general
(lc/leader-keys
"s r" '(elfeed :wk "elfeed"))
(general-nmap
:keymaps 'elfeed-search-mode-map
"x" 'lc/elfeed-xwwp-open)
:init
(defun lc/elfeed-xwwp-open (&optional use-generic-p)
"open with eww"
(interactive "P")
(let ((entries (elfeed-search-selected)))
(cl-loop for entry in entries
do (elfeed-untag entry 'unread)
when (elfeed-entry-link entry)
do (xwwp it))
(mapc #'elfeed-search-update-entry entries)
(unless (use-region-p) (forward-line))))
:config
(setq elfeed-feeds'(("https://www.reddit.com/r/emacs.rss?sort=new" reddit emacs)
("http://emacsredux.com/atom.xml" emacs)
("http://irreal.org/blog/?tag=emacs&feed=rss2" emacs)
("https://www.reddit.com/search.rss?q=url%3A%28youtu.be+OR+youtube.com%29&sort=top&t=week&include_over_18=1&type=link"
reddit youtube popular))))(provide 'init-core)
;;; init-core.el ends here(provide 'init-ui-extra)
;;; init-ui-extra.el ends here(provide 'init-org-export)
;;; init-org-export.el ends here(provide 'init-prog-tree-sitter)
;;; init-prog-tree-sitter.el ends here(provide 'init-prog-nix)
;;; init-prog-nix.el ends here(provide 'init-prog-lsp)
;;; init-prog-lsp.el ends here(provide 'init-prog-python)
;;; init-prog-python.el ends here(provide 'init-prog-jupyter)
;;; init-prog-jupyter.el ends here(provide 'init-org-roam)
;;; init-org-roam.el ends here(provide 'init-prog-elisp)
;;; init-org-prog-elisp.el ends here(provide 'init-prog-r)
;;; init-org-prog-r.el ends here(provide 'init-prog-clojure)
;;; init-org-prog-clojure.el ends here(provide 'init-prog-vterm)
;;; init-prog-vterm.el ends here(provide 'init-prog-markdown)
;;; init-prog-markdown.el ends here(provide 'init-prog-stan)
;;; init-prog-stan.el ends here(provide 'init-extra-focus)
;;; init-org-extra-focus.el ends here(provide 'init-extra-web)
;;; init-org-extra-web.el ends here(provide 'init-extra-rss)
;;; init-org-extra-rss.el ends here(provide 'init-extra)
;;; init-extra.el ends here