Compare commits
18 commits
b110f19584
...
3a606446ff
Author | SHA1 | Date | |
---|---|---|---|
|
3a606446ff | ||
|
c0e00547d5 | ||
|
1325a53afd | ||
|
9ab8a637f7 | ||
|
508a4967c9 | ||
|
7c676c4116 | ||
|
fa2f9a18f3 | ||
|
58787b7631 | ||
|
8dc0ec35e1 | ||
|
cdf9ae55fb | ||
|
5f114503fc | ||
|
7801922913 | ||
|
f9793c25a6 | ||
|
1b56e781c2 | ||
|
848c27d1d0 | ||
|
cdd56bfafe | ||
|
9d740dfc58 | ||
|
8a74b84b35 |
176
config.org
176
config.org
|
@ -67,12 +67,12 @@ The second block above was automatically generated by =org-mode=.
|
|||
|
||||
**** Tangle, Weave, Export, Publish
|
||||
|
||||
Since Org's ability to execute code and process its output is so robust, it's only natural that one might consider using Org to annotate a codebase, storing the code inside source blocks in the document. This would provide the space for much more thorough commentary than regular comments, but also prevent the file from being interpreted as a program, which is the important part! You could maintain both the Org file and the actual source files separately, but that would require manually duplicating edits in both files, which is not ideal.
|
||||
Since Org's ability to execute code and process its output is so robust, it's only natural that one might consider using Org to annotate a codebase, storing the code inside source blocks in the document. This would provide the space for much more thorough commentary than regular comments; however, it would prevent the file from being readable as a program, which is the entire point! You could maintain both the Org file and the actual source files separately, but that would require manually duplicating edits in both files, which is not ideal.
|
||||
|
||||
The solution is [[https://en.wikipedia.org/wiki/Literate_programming][literate programming]], the practice of embedding usable code into a markup document. Literate programming can be handled in a few different ways. A handful of languages support directly processing these markup documents, such as Haskell and Julia; however, the way Org implements it is closer to the traditional method, which involves two parallel processes:
|
||||
The solution is [[https://en.wikipedia.org/wiki/Literate_programming][literate programming]], the practice of embedding usable code into a markup document. Literate programming can be handled in a few different ways. A handful of languages support directly processing these markup documents, such as Haskell and Julia; however, the way Org implements it is closer to the traditional method, in which a singular file is processed in two different ways:
|
||||
|
||||
1. /Tangling/, converting the file into raw source code. Tangling must be performed before the code is used; in Org, code is tangled into a new file, and this can be done to generate many source files from a single Org file.
|
||||
2. /Weaving/, formatting the file into a human-readable document. Org conceptually divides this further into "exporting" and "publishing," where the latter is intended specifically for converting into web-ready HTML.
|
||||
1. /Tangling/, converting into raw source code. Tangling must be performed before the code is used; in Org, code is tangled into a new file, and this can be done to generate many source files from a single Org file.
|
||||
2. /Weaving/, formatting into a human-readable document. Org conceptually divides this further into "exporting" and "publishing," where the latter is intended specifically for converting into web-ready HTML.
|
||||
|
||||
You are currently reading the published version of this literate program[fn:1]. If you were to download this repository and use it as your config, Emacs would be running the tangled version. These versions are generated in separate processes, but both are ultimately derived from the content and metadata inside of the Org file.
|
||||
|
||||
|
@ -82,9 +82,9 @@ You are currently reading the published version of this literate program[fn:1].
|
|||
|
||||
The simultaneous handling of documentation and code inherent to literate programming is reminiscent of documentation generation (doc comments) in traditional programming. Both systems involve superimposing code and documentation into one file, but the literate style takes the concept one step further; the document isn't embedded in the code, the code is embedded in the document.
|
||||
|
||||
Instead of documentation having to be bent around the restrictions of source code, the source code can be written and organized with all the freedoms of prose. If written well, the literate program can be structured in a manner closer to how the human mind understands code, rather than how a computer processes it. This is assisted by features such as literate macros, features intended to break one's code out of the restrictions of standard programming.
|
||||
Instead of documentation having to be bent around the restrictions of source code, the source code can be written and organized with all the freedoms of prose. If written well, the literate program can be structured in a manner closer to how the human mind understands code, rather than how a computer processes it. This is assisted by features such as macros, which provide further flexibility in structure.
|
||||
|
||||
It's not the right tool for every codebase, but proper use of literate programming can make a program much, much easier to comprehend and maintain. This is especially true for configuration languages like Emacs Lisp, where much of the code is conceptually disconnected and can easily be split into categories.
|
||||
It's not the right tool for every codebase, but proper use of literate programming can make a program much, much easier to comprehend and maintain. This is especially true for configuration languages like Emacs Lisp, where much of the code is conceptually disconnected and can easily be split apart.
|
||||
|
||||
** Current Issues
|
||||
|
||||
|
@ -1392,11 +1392,11 @@ My favorite color theme has always been Tokyo Night. I use it literally everywhe
|
|||
|
||||
** Fonts
|
||||
|
||||
Victor Mono is my preferred coding font. I'm also using Source Sans Pro as my sans-serif font, though that is more an arbitrary pick than actually liking how it looks.
|
||||
[[https://rubjo.github.io/victor-mono/][Victor Mono]] has been my preferred monospace font for a few years, so we'll set it as the ~doom-font~. We'll want a non-monospace font too, and I'm currently trying out [[https://overpassfont.org/][Overpass]]. It's a bit wider than Victor Mono, but it matches well enough.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq doom-font (font-spec :family "VictorMono" :size 13)
|
||||
doom-variable-pitch-font (font-spec :family "Source Sans Pro" :size 16))
|
||||
doom-variable-pitch-font (font-spec :family "Overpass" :size 15))
|
||||
#+end_src
|
||||
|
||||
I'm a very big fan of how italics look in Victor Mono, so let's make more things italicized! While we're here, we'll also set doom's modified buffer font to be orange instead of yellow (I like how it looks better).
|
||||
|
@ -1414,9 +1414,9 @@ I'm a very big fan of how italics look in Victor Mono, so let's make more things
|
|||
Some other small aesthetic changes:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq nerd-icons-scale-factor 1.1 ; Make icons slightly larger
|
||||
doom-modeline-height 24 ; Make Doom's modeline taller
|
||||
display-line-numbers-type t) ; Line numbers (absolute)
|
||||
(setq nerd-icons-scale-factor 1.1 ; Make icons slightly larger
|
||||
doom-modeline-height 24 ; Make Doom's modeline taller
|
||||
display-line-numbers-type 'visual) ; Line numbers (relative, visual)
|
||||
#+end_src
|
||||
|
||||
** Line Wrapping
|
||||
|
@ -1467,9 +1467,13 @@ When a buffer has line numbers, they can interfere with the margins and make the
|
|||
#+begin_src emacs-lisp
|
||||
(add-hook! display-line-numbers-mode
|
||||
(require 'visual-fill-column)
|
||||
(when visual-fill-column-mode
|
||||
(setq-local visual-fill-column-extra-text-width '(0 . 6))
|
||||
(visual-fill-column--adjust-window)))
|
||||
(setq-local
|
||||
visual-fill-column-extra-text-width
|
||||
(cons 0 (if display-line-numbers-mode
|
||||
;; Width of line number + 2 padding columns
|
||||
(+ 2 (line-number-display-width))
|
||||
0)))
|
||||
(visual-fill-column--adjust-window))
|
||||
#+end_src
|
||||
|
||||
** Dashboard
|
||||
|
@ -1588,11 +1592,12 @@ Corfu's posframe buffer shouldn't be numbered by =winum=:
|
|||
|
||||
#+call: confpkg("Pkg: eldoc")
|
||||
|
||||
We'll switch the default docstring handler to ~eldoc-documentation-compose~, since that provides the most information and I don't mind the space it takes up.
|
||||
We'll switch the default docstring handler to ~eldoc-documentation-compose~, since that provides the most information and I don't mind the space it takes up. We'll also make docs appear a bit faster.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(after! eldoc
|
||||
(setq eldoc-documentation-strategy 'eldoc-documentation-compose))
|
||||
(setq eldoc-documentation-strategy 'eldoc-documentation-compose
|
||||
eldoc-idle-delay 0.3))
|
||||
#+end_src
|
||||
|
||||
** Embark
|
||||
|
@ -1837,6 +1842,7 @@ Here's the big one.
|
|||
"C" #'compile-defun
|
||||
"RET" nil "e" nil)
|
||||
(:map embark-symbol-map
|
||||
"K" #'helpful-symbol
|
||||
"s" nil "h" nil "d" nil "e" nil)
|
||||
(:map embark-variable-map
|
||||
"Y" #'embark-save-variable-value
|
||||
|
@ -2094,32 +2100,19 @@ Having an IDE-style tooltip pop up is nice, but ~flymake-popon~ is a bit ugly by
|
|||
|
||||
#+call: confpkg("Pkg: git")
|
||||
|
||||
I use GPG signing for commits, which means that committing often takes longer than the single second timeout. Eight seconds seems like a reasonable amount of time to type in a password.
|
||||
I use GPG signing for commits, which means that creating a commit typically takes longer than Emacs's timeout (1 second by default). Having a timeout doesn't really seem all that necessary in the first place, so I'll just set it to a high number.
|
||||
|
||||
Let's also increase the maximum length of commit summaries past the default of 50 characters, because that's a somewhat restrictive limit.
|
||||
Let's also increase the maximum length of commit summaries from 50 to 60 characters to give ourselves a bit more space.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(after! git-commit
|
||||
(setq git-commit-post-finish-hook-timeout 8
|
||||
(setq git-commit-post-finish-hook-timeout 999
|
||||
git-commit-summary-max-length 60))
|
||||
#+end_src
|
||||
|
||||
*** Magit Syntax Highlighting
|
||||
|
||||
Magit already looks great, but it could use some proper syntax highlighting!
|
||||
|
||||
#+begin_src emacs-lisp :tangle packages.el
|
||||
(package! magit-delta)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package! magit-delta
|
||||
:hook (magit-mode . magit-delta-mode))
|
||||
#+end_src
|
||||
|
||||
*** Forge
|
||||
|
||||
Forge is a convenient package for working with remote code forges like GitHub, GitLab, etc. These days, I've mostly switched over to my own [[https://git.tokinanpa.dev/][personal forge]] instead of something public like GitHub, so I'll need to let Forge know about that.
|
||||
Forge is a convenient package for working with remote code forges like GitHub, GitLab, etc. These days, I've mostly switched over to my own [[https://git.tokinanpa.dev/][personal forge]] instead of those more public options, so I'll need to let Forge know about that.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(after! forge
|
||||
|
@ -2238,10 +2231,7 @@ If there are any trailing newlines in the snippet file, they will be inserted wh
|
|||
When editing a snippet, the binding =C-c C-t= can be used to test it in a fresh buffer. This is very useful, but with Evil it has the issue of leaving the editor in normal state, when snippets are designed to be expanded in insert state.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defadvice! ~/yas-tryout-insert-state (&rest _)
|
||||
"Switch to Insert state when trying out a snippet."
|
||||
:after #'yas-tryout-snippet
|
||||
(evil-insert-state))
|
||||
(advice-add #'yas-tryout-snippet :after #'evil-insert-state)
|
||||
#+end_src
|
||||
|
||||
*** Creating New Snippets
|
||||
|
@ -2649,6 +2639,7 @@ Emacs Everywhere is a great idea. Unfortunately, the default package on MELPA us
|
|||
(pcase emacs-everywhere--display-server
|
||||
(`(x11 . ,_) (emacs-everywhere--app-info-linux-x11))
|
||||
(`(wayland . KDE) (emacs-everywhere--app-info-linux-kde))
|
||||
(`(wayland . sway) (emacs-everywhere--app-info-linux-sway))
|
||||
(el-patch-add
|
||||
(`(wayland . Hyprland) (emacs-everywhere--app-info-linux-hyprland)))
|
||||
(_ (user-error "Unable to fetch app info with display server %S"
|
||||
|
@ -2872,37 +2863,6 @@ There are a few useful functions Doom doesn't bind by default, so let's add them
|
|||
"v" (lookup-key org-mode-map (kbd "C-c C-v")))
|
||||
#+end_src
|
||||
|
||||
**** YASnippet
|
||||
|
||||
By default, snippet expansion doesn't work in Org mode; when =TAB= is pressed to move to the next placeholder, headline visibility cycling is triggered instead. This is because in ~org-mode-map~ =TAB= is unconditionally bound to ~org-cycle~, and for some reason this has a higher precedence than YAS's keymaps.
|
||||
|
||||
While this is a complex problem, the solution is actually rather simple: just remove the ~org-mode-map~ binding. The ~org-cycle~ command will still be triggered on =TAB= when in normal mode, as it is bound in ~evil-org-mode-map~, but when in insert mode (as one generally is during snippet expansion) the binding will fall through both maps and be handled by YASnippet.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(map! :after org
|
||||
:map org-mode-map
|
||||
"TAB" nil
|
||||
"<tab>" nil
|
||||
:i "TAB" nil
|
||||
:i "<tab>" nil)
|
||||
#+end_src
|
||||
|
||||
This also means we don't need ~org-cycle~ to emulate indentation, which is nice. Unfortunately, this breaks something else: ~org-cycle~ not only handles visibility cycling, but also navigating inside tables. If ~org-cycle~ isn't being called when in insert mode, then we can't use =TAB= to move fields. This means that we need a little extra binding configuration:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(let ((item
|
||||
`(menu-item nil org-table-next-field
|
||||
:filter ,(lambda (cmd)
|
||||
(when (org-table-p)
|
||||
cmd)))))
|
||||
(map! :after org
|
||||
:map evil-org-mode-map
|
||||
:i "TAB" item
|
||||
:i "<tab>" item))
|
||||
#+end_src
|
||||
|
||||
This makes it so that we only let tab keypresses fall through if we aren't in a table. (We'll just assume that we aren't going to be expanding any snippets while we're in a table.)
|
||||
|
||||
*** Project Links
|
||||
|
||||
It's sometimes nice to be able to click a link in an Org file that takes me to one of my projects.
|
||||
|
@ -2943,7 +2903,7 @@ It's sometimes nice to be able to click a link in an Org file that takes me to o
|
|||
|
||||
*** Modern
|
||||
|
||||
Doom Emacs's =+pretty= flag by default uses the package =org-superstar= to prettify Org files. This package is decently nice looking, but it has a much nicer and more comprehensive alternative in the form of =org-modern=.
|
||||
Doom Emacs's =org +pretty= flag by default uses the package =org-superstar= to prettify Org files. This package is decently nice looking, but it has a much nicer and more comprehensive alternative in the form of =org-modern=.
|
||||
|
||||
#+begin_src emacs-lisp :tangle packages.el
|
||||
(package! org-modern)
|
||||
|
@ -2955,7 +2915,7 @@ Doom Emacs's =+pretty= flag by default uses the package =org-superstar= to prett
|
|||
:config
|
||||
(setq org-modern-star 'replace
|
||||
org-modern-replace-stars '("◉" "○" "✸" "✿" "✤" "✜" "◆" "▶")
|
||||
org-modern-label-border 0.3
|
||||
org-modern-label-border -2
|
||||
org-modern-table-vertical 1
|
||||
org-modern-table-horizontal 0.2
|
||||
org-modern-list '((?- . "•")
|
||||
|
@ -2989,11 +2949,11 @@ Doom Emacs's =+pretty= flag by default uses the package =org-superstar= to prett
|
|||
("filetags" . "")
|
||||
("bind" . "")
|
||||
("bibliography" . "")
|
||||
("print_bibliography" . #("" 0 1 (display (raise -0.1))))
|
||||
("cite_export" . "")
|
||||
("print_bibliography" . "")
|
||||
("cite_export" . "")
|
||||
("print_glossary" . #("ᴬᶻ" 0 1 (display (raise -0.1))))
|
||||
("glossary_sources" . #("" 0 1 (display (raise -0.14))))
|
||||
("include" . "⇤")
|
||||
("include" . "")
|
||||
("setupfile" . "⇚")
|
||||
("html_head" . "🅷")
|
||||
("html" . "🅗")
|
||||
|
@ -3044,7 +3004,7 @@ The default colors for various elements of =org-modern= don't match with our the
|
|||
:foreground ,(doom-color 'brown)
|
||||
:inherit org-modern-done)
|
||||
`(org-modern-date-inactive
|
||||
:foreground ,(doom-color 'doc-comments)
|
||||
:foreground ,(doom-color 'fg)
|
||||
:inherit org-modern-date-active)
|
||||
`(org-modern-time-active
|
||||
:foreground ,(doom-color 'fg-alt)
|
||||
|
@ -3052,7 +3012,7 @@ The default colors for various elements of =org-modern= don't match with our the
|
|||
:inherit org-modern-done)
|
||||
`(org-modern-time-inactive
|
||||
:foreground ,(doom-color 'grey)
|
||||
:background ,(doom-color 'modeline-bg-l)
|
||||
:background "#262b40"
|
||||
:inherit org-modern-time-active)
|
||||
`(org-modern-progress-incomplete
|
||||
:background ,(doom-color 'bg-alt)
|
||||
|
@ -3064,7 +3024,7 @@ The default colors for various elements of =org-modern= don't match with our the
|
|||
|
||||
*** Appear
|
||||
|
||||
Since we've disabled =+pretty=, we need to add the packages we do want from it, namely =org-appear= to automatically handle emphasis markers and other nice things like that.
|
||||
Since we've disabled =+pretty=, we need to add the packages we do want from it, namely =org-appear= to automatically prettify emphasis markers and other nice things like that.
|
||||
|
||||
#+begin_src emacs-lisp :tangle packages.el
|
||||
(package! org-appear)
|
||||
|
@ -3334,12 +3294,6 @@ The simple package =org-checklist= from =org-contrib= makes it so that checkboxe
|
|||
(add-hook 'org-after-todo-state-change-hook #'org-checklist)))
|
||||
#+end_src
|
||||
|
||||
The ~org-checklist~ function will reset the checkboxes on any task, but I only want them reset when the task repeats.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(advice-add #'org-checklist :before-while #'org-get-repeat)
|
||||
#+end_src
|
||||
|
||||
I don't want to have to specify the =RESET_CHECK_BOXES= property for every TODO I write, though. I would much prefer if it was on by default, and the system allowed me to turn it off if I wanted to. Luckily, the fine control Org gives you over property inheritance nicely fixes this problem.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
|
@ -3348,9 +3302,13 @@ I don't want to have to specify the =RESET_CHECK_BOXES= property for every TODO
|
|||
|
||||
(defpatch! org-checklist
|
||||
(defun org-reset-checkbox-state-maybe) ()
|
||||
"Reset all checkboxes in an entry if the `RESET_CHECK_BOXES' property is set"
|
||||
(el-patch-concat
|
||||
"Reset all checkboxes in an entry if the `RESET_CHECK_BOXES' property is set"
|
||||
(el-patch-add " and if the entry has a repeating timestamp."))
|
||||
(interactive "*")
|
||||
(if (org-entry-get (point) "RESET_CHECK_BOXES" (el-patch-add t))
|
||||
(if (el-patch-wrap 2
|
||||
(and (org-get-repeat)
|
||||
(org-entry-get (point) "RESET_CHECK_BOXES" (el-patch-add t))))
|
||||
(org-reset-checkbox-state-subtree)))
|
||||
#+end_src
|
||||
|
||||
|
@ -3545,21 +3503,11 @@ By default, Roam generates file names containing both a timestamp and the node t
|
|||
|
||||
*** Roam Buffer
|
||||
|
||||
The unlinked references section is turned off by default for performance reasons, but sometimes I want to see that information when writing notes. I also don't want it to show up for every node, because some of my nodes have quite a large reference list. Let's add a predicate to control when unlinked references are shown.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defadvice! ~/org-roam-unlinked-references-p (node)
|
||||
"A predicate to control when unlinked references are shown in the `org-roam' buffer."
|
||||
:before-until #'org-roam-unlinked-references-section
|
||||
(assoc "ROAM_NO_UNLINKED" (org-roam-node-properties node)))
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(after! org-roam
|
||||
(setq org-roam-mode-sections
|
||||
'((org-roam-backlinks-section :unique t)
|
||||
org-roam-reflinks-section
|
||||
org-roam-unlinked-references-section)))
|
||||
org-roam-reflinks-section)))
|
||||
#+end_src
|
||||
|
||||
*** Roam Links
|
||||
|
@ -3670,6 +3618,11 @@ With those variables created, we can define our templates.
|
|||
'(("f" "Standalone file" plain ""
|
||||
:target (file+head "${file-maybe-dir}"
|
||||
"#+title: ${title}")
|
||||
:unnarrowed t)
|
||||
("n" "Bibliography note" plain ""
|
||||
:target
|
||||
(file+head "${file-maybe-cite}"
|
||||
"#+title: ${citar-author} - ${citar-title}")
|
||||
:unnarrowed t))
|
||||
org-roam-dailies-capture-templates
|
||||
'(("e" "Event" entry "* $1\n%^t\n\n$0"
|
||||
|
@ -3746,8 +3699,8 @@ A full week-long agenda is usually too cluttered for me to read, so I'll narrow
|
|||
|
||||
org-agenda-sorting-strategy
|
||||
'((agenda time-up habit-down timestamp-up priority-down category-up)
|
||||
(todo habit-down priority-down category-up)
|
||||
(tags habit-down priority-down category-up)
|
||||
(todo urgency-down category-up)
|
||||
(tags urgency-down category-up)
|
||||
(search category-up))
|
||||
|
||||
;; Agenda files
|
||||
|
@ -4091,7 +4044,7 @@ it defaults to `project-current'."
|
|||
(require 'dirvish-side)
|
||||
(let ((fullframep (when-let ((dv (dirvish-curr))) (car (dv-layout dv))))
|
||||
(visible (dirvish-side--session-visible-p))
|
||||
(path (or path (dirvish--get-project-root) default-directory)))
|
||||
(path (or path (dirvish--vc-root-dir) default-directory)))
|
||||
(cond (fullframep (user-error "Can not create side session here"))
|
||||
(visible (select-window visible))
|
||||
(t (dirvish-side--new path)))))
|
||||
|
@ -4239,15 +4192,26 @@ The =lsp-java= package provides LSP support using the standard Java language ser
|
|||
(setq lsp-java-jdt-ls-prefer-native-command t))
|
||||
(add-hook! java-mode
|
||||
(setq-local lsp-java-server-install-dir
|
||||
(concat (+lsp-java-server-store-path) "/share/java/jdtls/")))
|
||||
(f-slash (+lsp-java-server-store-path))))
|
||||
|
||||
(defadvice! ~/lsp-java-ls-command ()
|
||||
"Configure `lsp-java' to work with Nix."
|
||||
:override #'lsp-java--ls-command
|
||||
(let ((root (or (doom-project-root) (f-join (getenv "XDG_DATA_HOME") "jdtls"))))
|
||||
(list lsp-java-jdt-ls-command
|
||||
"-configuration" (f-join root "config-linux")
|
||||
"-data" (f-join root "java-workspace"))))
|
||||
;; The relative locations of the binary and jar file are different
|
||||
;; on NixOS than on most other Linux distros
|
||||
|
||||
(defadvice! ~/lsp-java-locate-server-jar (old-fn)
|
||||
:around #'lsp-java--locate-server-jar
|
||||
(let ((lsp-java-server-install-dir
|
||||
(concat lsp-java-server-install-dir "share/java/jdtls/")))
|
||||
(funcall old-fn)))
|
||||
#+end_src
|
||||
|
||||
*** Project File Conflict
|
||||
|
||||
Doom's standard library allows for an empty =.project= file to mark the root of a project directory. This is a decent idea, but unfortunately Gradle's project structure contains a file of that name that isn't necessarily at the root, and so this must be disabled to prevent Doom from breaking those projects.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(after! projectile
|
||||
(setq projectile-project-root-files-bottom-up
|
||||
(delete ".project" projectile-project-root-files-bottom-up)))
|
||||
#+end_src
|
||||
|
||||
** Language Servers
|
||||
|
|
Loading…
Reference in a new issue