Posts tagged "spacemacs":
A while ago I made an attempt to improve my work habits by keeping a document
with TODO items. It lasted only for a while, and I've since had the intention to
make another attempt. Since then I've started using org-roam and I've managed to
create a habit of writing daily journal notes using org-roam's daily-notes. A
few times I've thought that it might fit me well to put TODO items in the notes,
but that would mean that I'd have to somehow keep track of them. At first I
manually added a tag to each journal fily containing a TODO item. That didn't
work very well at all, which should have been obvious up front. Then I added the
folders where I keep roam files and journals to
org-agenda-files, that worked
a lot better. I'd still be using that, even if I expected it to slow down
considerably as the number of files grow, but then I found a post on dynamic and
fast agenda with org-roam.
I adjusted it slightly to fit my own setup a bit better, i.e. I made a Spacemacs
roam-extra, I use the tag
todo, and I use a different hook to get the
tag added on opening an org-roam file.
The layer consists of a single file,
layers/roam-extra/funcs.el. In it I
define 4 functions (they are pretty much copies of the functions in the post
roam-extra:todo-p- returns non-
nilif the current current buffer contains a TODO item.
roam-extra:update-todo-tag- updates the tags of the current buffer to reflect the presence of TODO items, i.e. ensure the the tag
todois present iff there's a TODO item.
roam-extra:todo-files- uses the org-roam DB to return a list of all files containing the tag
'org-agenda-filesto contain only the files with TODO items.
I've put the full contents of the file at the end of the post.
To ensure that the
todo tag is correct in all org-mode files I've added
roam-extra:update-todo-tag to hooks that are invoked on opening an org-ram
file and when saving a file. (I would love to find a more specialise hook than
before-save-hook, but it works for now.)
(add-hook 'org-roam-file-setup-hook #'roam-extra:update-todo-tag) (add-hook 'before-save-hook #'roam-extra:update-todo-tag)
To ensure that the list of files with TODO items is kept up to date when I open
I also wrap
org-agenda in an advice so
called prior to the agenda being opened.
(advice-add 'org-agenda :before #'roam-extra:update-todo-files)
(defun roam-extra:todo-p () "Return non-nil if current buffer has any TODO entry. TODO entries marked as done are ignored, meaning the this function returns nil if current buffer contains only completed tasks." (org-element-map (org-element-parse-buffer 'headline) 'headline (lambda (h) (eq (org-element-property :todo-type h) 'todo)) nil 'first-match)) (defun roam-extra:update-todo-tag () "Update TODO tag in the current buffer." (when (and (not (active-minibuffer-window)) (org-roam--org-file-p buffer-file-name)) (let* ((file (buffer-file-name (buffer-base-buffer))) (all-tags (org-roam--extract-tags file)) (prop-tags (org-roam--extract-tags-prop file)) (tags prop-tags)) (if (roam-extra:todo-p) (setq tags (seq-uniq (cons "todo" tags))) (setq tags (remove "todo" tags))) (unless (equal prop-tags tags) (org-roam--set-global-prop "roam_tags" (combine-and-quote-strings tags)))))) (defun roam-extra:todo-files () "Return a list of note files containing todo tag." (seq-map #'car (org-roam-db-query [:select file :from tags :where (like tags (quote "%\"todo\"%"))]))) (defun roam-extra:update-todo-files (&rest _) "Update the value of `org-agenda-files'." (setq org-agenda-files (roam-extra:todo-files)))
No more Emacs packages for Nix and no need to defining functions that wrap
executables in an invocation of
There's a nice bonus too, with this setup I don't need to run
always drops me at a bash prompt, instead I get a working setup in my shell of
The steps for setting up
direnv depends a bit on your setup, but luckily I
found the official instructions for installing
direnv to be very clear and
easy to follow. There's not much I can add to that.
Setting up Spacemacs
emacs-direnv isn't included by default in Spacemacs I needed to do a bit
of setup. I opted to create a layer for it, rather than just drop it in the list
dotspacemacs-additional-packages. Yes, a little more complicated, but not
difficult and I nurture an intention of submitting the layer for inclusion in
Spacemacs itself at some point. I'll see where that goes.
For now, I put the following in the file
(defconst direnv-packages '(direnv)) (defun direnv/init-direnv () (use-package direnv :init (direnv-mode)))
Setting up the project folders
In each project folder I then add the file
.envrc containing a single line:
Then I either run
direnv allow from the command line, or run the
direnv-allow after opening the folder in Emacs.
It's as simple as moving into the folder in a shell – all required envvars are set up on entry and unset on exit.
In Emacs it's just as simple, just open a file in a project and the envvars are set. When switching to a buffer outside the project the envvars are unset.
There is only one little caveat,
nix-build doesn't work inside a Nix shell. I
found out that running
does work though.
Edit 2020-06-22: I've since found a better setup for this.
ghcide and LSP, as I wrote about in my post on Haskell, ghcide, and
Spacemacs, I found myself ending up recompiling a little too often. This pushed
me to finally start looking at Nix. After a bit of a fight I managed to
get ghcide from Nix,
which brought me the issue of setting up Spacemacs. Inspired by a gist from
Samuel Evans-Powell and a guide to setting up an environment for Reflex by
Thales Macedo Garitezi I ended up with the following setup:
(defun dotspacemacs/layers () (setq-default ... dotspacemacs-additional-packages '( nix-sandbox nix-haskell-mode ... ) ... ))
(defun dotspacemacs/user-config () ... (add-hook 'haskell-mode-hook #'lsp) (add-hook 'haskell-mode-hook 'nix-haskell-mode) (add-hook 'haskell-mode-hook (lambda () (setq-local flycheck-executable-find (lambda (cmd) (nix-executable-find (nix-current-sandbox) cmd))) (setq-local flycheck-command-wrapper-function (lambda (argv) (apply 'nix-shell-command (nix-current-sandbox) argv))) (setq-local haskell-process-wrapper-function (lambda (argv) (apply 'nix-shell-command (nix-current-sandbox) argv))) (setq-local lsp-haskell-process-wrapper-function (lambda (argv) `("nix-shell" "-I" "." "--command" "ghcide --lsp" ,(nix-current-sandbox)))))) (add-hook 'haskell-mode-hook (lambda () (flycheck-add-next-checker 'lsp-ui '(warning . haskell-stack-ghc)))) ... )
It seems to work, but please let me know if you have suggestions for improvements.
The other day I read Chris Penner's post on Haskell IDE Support and thought I'd make an attempt to use it with Spacemacs.
stack build hie-bios ghcide haskell-lsp --copy-compiler-tool I
had a look at the instructions on using
haskell-ide-engine with Spacemacs.
After a bit of trial and error I came up with these changes to my
(defun dotspacemacs/layers () (setq-default dotspacemacs-configuration-layers '( ... lsp (haskell :variables haskell-completion-backend 'lsp ) ...) ) )
(defun dotspacemacs/user-config () (setq lsp-haskell-process-args-hie '("exec" "ghcide" "--" "--lsp") lsp-haskell-process-path-hie "stack" lsp-haskell-process-wrapper-function (lambda (argv) (cons (car argv) (cddr argv))) ) (add-hook 'haskell-mode-hook #'lsp))
The slightly weird looking
lsp-haskell-process-wrapper-function is removing
--lsp inserted by this line.
That seems to work. Though I have to say I'm not ready to switch from intero just yet. Two things in particular didn't work with =ghcide=/LSP:
- Switching from one the
Main.hsin one executable to the
Main.hsof another executable in the same project didn't work as expected – I had hints and types in the first, but nothing in the second.
- Jump to the definition of a function defined in the package didn't work – I'm not willing to use GNU GLOBAL or some other source tagging system.
With the help of a work mate I've finally found this gem that's been missing from my Spacemacs setup
(with-eval-after-load 'intero (flycheck-add-next-checker 'intero '(warning . haskell-hlint)) (flycheck-add-next-checker 'intero '(warning . haskell-stack-ghc)))