Welcome to my Emacs configuration, at a first glance Emacs seems like a text editor, but when you take time to play around, you will see it’s more than that. Took me a while to understand, and time to time I get surprise with their capabilities.
I use Emacs in my daily basis to work, organize my Life, programming in Javascript/Typescript, Elisp, Lua and Flutter.
As many Emacs users I update my configuration frequently with a new tool, new language or anything new I want to try.
I like to work with beautiful and fun environments, so I’m always trying to make Emacs prettier
Some screenshots
The following list is from people I have been learning and stealing Emacs configuration ideas and chunks
Sometimes there is a error on Emacs startup, so this following configs will enable to debug with some comfort.
(load-theme 'misterioso)
(when (eq system-type 'darwin)
(add-to-list 'default-frame-alist '(undecorated . t))
(setq mac-option-modifier 'alt)
(setq mac-command-modifier 'meta)
;; Keys for visiting next & previous windows
(global-set-key (kbd "<A-tab>") #'other-window)
(global-set-key (kbd "<A-S-tab>")
#'(lambda () (interactive) (other-window -1)))
;; Keys for visiting next & previous frame
(global-set-key (kbd "M-`") #'other-frame)
(global-set-key (kbd "M-~") #'(lambda () (interactive) (other-frame -1)))
;; sets fn-delete to be right-delete
(global-set-key [kp-delete] 'delete-char)
(menu-bar-mode 1)
;; Enable mac option to create accented characters
(setq ns-alternate-modifier 'none)
(setq frame-resize-pixelwise t)
(setq ns-left-alternate-modifier 'none))
Before kill a modified buffer, give option to see the diff Original code from here
(defun my/kill-this-buffer ()
(interactive)
(catch 'quit
(save-window-excursion
(let (done)
(when (and buffer-file-name (buffer-modified-p))
(while (not done)
(let ((response (read-char-choice
(format "Save file %s? (y, n, d, q) " (buffer-file-name))
'(?y ?n ?d ?q))))
(setq done (cond
((eq response ?q) (throw 'quit nil))
((eq response ?y) (save-buffer) t)
((eq response ?n) (set-buffer-modified-p nil) t)
((eq response ?d) (diff-buffer-with-file) nil))))))
(kill-buffer (current-buffer))))))
(global-set-key [s-tab] 'next-buffer)
(global-set-key [S-s-iso-lefttab] 'previous-buffer)
(global-set-key ["M-{"] 'next-buffer)
(global-set-key ["M-}"] 'previous-buffer)
;; change window
(global-set-key [(C-tab)] 'other-window)
(global-set-key [(C-M-tab)] 'other-window)
;; Remap kill buffer to my/kill-this-buffer
(global-set-key (kbd "C-x k") 'my/kill-this-buffer)
;; Revert buffer
(global-set-key (kbd "C-<f5>") 'revert-buffer)
;; Go to scratch buffer
(global-set-key (kbd "<f2>") (lambda() (interactive)(switch-to-buffer "*scratch*")))
(global-set-key (kbd "M-g") 'goto-line)
(global-set-key (kbd "C-c s") 'sort-lines)
(global-set-key (kbd "C-c c") 'comment-region)
(global-set-key (kbd "C-c d") 'uncomment-region)
(global-set-key (kbd "<f6>") (lambda() (interactive)(find-file "~/.emacs.d/readme.org")))
(setq package-enable-at-startup nil)
(defvar elpaca-installer-version 0.7)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
:ref nil
:files (:defaults "elpaca-test.el" (:exclude "extensions"))
:build (:not elpaca--activate-package)))
(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory))
(build (expand-file-name "elpaca/" elpaca-builds-directory))
(order (cdr elpaca-order))
(default-directory repo))
(add-to-list 'load-path (if (file-exists-p build) build repo))
(unless (file-exists-p repo)
(make-directory repo t)
(when (< emacs-major-version 28) (require 'subr-x))
(condition-case-unless-debug err
(if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
((zerop (call-process "git" nil buffer t "clone"
(plist-get order :repo) repo)))
((zerop (call-process "git" nil buffer t "checkout"
(or (plist-get order :ref) "--"))))
(emacs (concat invocation-directory invocation-name))
((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
"--eval" "(byte-recompile-directory \".\" 0 'force)")))
((require 'elpaca))
((elpaca-generate-autoloads "elpaca" repo)))
(progn (message "%s" (buffer-string)) (kill-buffer buffer))
(error "%s" (with-current-buffer buffer (buffer-string))))
((error) (warn "%s" err) (delete-directory repo 'recursive))))
(unless (require 'elpaca-autoloads nil t)
(require 'elpaca)
(elpaca-generate-autoloads "elpaca" repo)
(load "./elpaca-autoloads")))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))
;; Install use-package support
(elpaca elpaca-use-package
;; Enable use-package :ensure support for Elpaca.
(elpaca-use-package-mode))
;; Block until current queue processed.
(elpaca-wait)
;;Turns off elpaca-use-package-mode current declaration
;;Note this will cause the declaration to be interpreted immediately (not deferred).
;;Useful for configuring built-in emacs features.
(use-package emacs :ensure nil :config (setq ring-bell-function #'ignore))
;; Close all dired buffers after opening
(setq dired-kill-when-opening-new-dired-buffer t)
(defun dont-kill-scratch ()
"This function doesn't let you kill scratch by mistake."
(if (not (equal (buffer-name) "*scratch*"))
t
(bury-buffer)
nil))
(add-hook 'kill-buffer-query-functions #'dont-kill-scratch)
;; Don't ask about variables and functions from .dir-locals
(advice-add 'risky-local-variable-p :override #'ignore)
(use-package ls-lisp
:config
(setq ls-lisp-dirs-first t
ls-lisp-use-insert-directory-program nil))
Make startup faster by reducing the frequency of garbage collection and then use a hook to measure Emacs startup time.
;; The default is 800 kilobytes. Measured in bytes.
(setq gc-cons-threshold (* 50 1000 1000))
Silence compiler warnings as they can be pretty disruptive
(setq native-comp-async-report-warnings-errors nil)
From Doom emacs Contrary to what many Emacs users have in their configs, you don’t need more than this to make UTF-8 the default coding system:
(set-language-environment "UTF-8")
Load environment variables from the shell
;;(use-package add-node-modules-path)
(use-package exec-path-from-shell
:ensure t
:init (exec-path-from-shell-initialize)
:config
(setq exec-path-from-shell-variables '("GOPATH" "PATH" "MANPATH")))
Set the start point for the current buffer, this means if you will search for a file, the start point will be the default-directory value.
(setq default-directory "~/")
(use-package dashboard
:ensure t
:config
(setq dashboard-banner-logo-title "Olá, bem vindo ao Emacs"
dashboard-startup-banner "~/.emacs.d/nyan-cat.png"
dashboard-center-content t
dashboard-agenda-release-buffers t
dashboard-items '((projects . 5) (agenda . 5)))
:init
(add-hook 'elpaca-after-init-hook #'dashboard-open))
I don’t want a bunch of transient files showing up as untracked in the Git repo so I move them all to another location.
(setq custom-file
(if (boundp 'server-socket-dir)
(expand-file-name "custom.el" server-socket-dir)
(expand-file-name (format "emacs-custom-%s.el" (user-uid)) temporary-file-directory)))
(add-hook 'elpaca-after-init-hook (lambda () (load custom-file 'noerror)))
(setq backup-directory-alist
`((".*" . ,temporary-file-directory))
auto-save-file-name-transforms
`((".*" ,temporary-file-directory t))
create-lockfiles nil)
(setq tramp-auto-save-directory temporary-file-directory)
Start the Emacs server from this instance so that all emacsclient
calls are routed here.
It’s required to be able to use Emacs as my dropdown terminal.
(server-start)
Source: Reddit
(defadvice load-theme (before clear-previous-themes activate)
"Clear existing theme settings instead of layering them"
(mapc #'disable-theme custom-enabled-themes))
(use-package doom-themes
:ensure t
:preface
(setq
doom-themes-treemacs-theme "doom-colors"
light-theme "doom-oksolar-light"
dark-theme "doom-material-dark")
:init
(load-theme (intern dark-theme) t)
(defun gg-switch-theme()
(interactive)
(let* ((theme (car custom-enabled-themes))
(change (if (string= theme light-theme) dark-theme light-theme)))
(load-theme (intern change) t)
(setq selected-theme change)
(message "Theme switched from %s to %s" theme change)))
(global-set-key (kbd "<f8>") 'gg-switch-theme)
:config
(doom-themes-neotree-config)
(with-eval-after-load 'doom-themes
(doom-themes-treemacs-config))
(set-face-attribute 'default nil :font "Menlo 13")
(set-face-attribute 'region nil :background "#000" :foreground "#ffffff"))
(defun text-scale-twice ()
(interactive)
(progn(text-scale-adjust 0)(text-scale-decrease 2)))
(use-package neotree
:ensure t
:bind([f9] . neotree-toggle)
:hook (neo-after-create . (lambda (_)(call-interactively 'text-scale-twice)))
:config
(setq neo-autorefresh nil)
(setq neo-smart-open t)
(with-eval-after-load 'neotree
(define-key neotree-mode-map (kbd "h") 'neotree-hidden-file-toggle)))
(use-package all-the-icons :ensure t)
(use-package all-the-icons-dired
:ensure t
:hook (dired-mode . all-the-icons-dired-mode))
(use-package nyan-mode
:ensure t
:init
(nyan-mode t))
(use-package emojify
:ensure t
:hook (elpaca-after-init . global-emojify-mode))
(use-package dimmer
:ensure t
:init
(dimmer-mode t)
:config
(setq dimmer-fraction 0.3))
(scroll-bar-mode 0)
(menu-bar-mode 0)
(tool-bar-mode 0)
(column-number-mode)
(setq ring-bell-function 'ignore)
Writing yes or no is length, type y / n instead
(defalias 'yes-or-no-p 'y-or-n-p)
(use-package doom-modeline
:ensure t
:config
(setq doom-modeline-height 35)
(set-face-background 'doom-modeline-bar (face-background 'mode-line))
(setq doom-modeline-bar-width 1)
(doom-modeline-mode 1))
Don’t pop up UI dialogs when prompting
(setq use-dialog-box nil)
(use-package company
:ensure t
:hook (prog-mode . company-mode)
:config
(setq company-minimum-prefix-length 2)
(global-company-mode)
(global-set-key (kbd "TAB") #'company-indent-or-complete-common))
(setq company-tooltip-align-annotations t)
(use-package company-box
:ensure t
:hook (company-mode . company-box-mode))
;; Remembering the last place you visited in a file
(save-place-mode 1)
(setq-default truncate-lines t ;; Do not wrap lines
indent-tabs-mode nil) ;; spaces instead of tabs
(setq show-trailing-whitespace t ;; Complain about trailing white spaces
whitespace-style '(face trailing lines tabs big-indent)) ;; Cleanup white spaces before save
;; Cleanup whitespace before save
(add-hook 'before-save-hook 'whitespace-cleanup)
(use-package smartparens
:ensure t
:config
(smartparens-global-mode t))
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))
(use-package rainbow-mode :ensure t)
(use-package string-inflection
:ensure t
:bind ("C-c i" . string-inflection-cycle))
(global-hl-line-mode t)
(add-hook 'prog-mode-hook #'display-line-numbers-mode)
(add-hook 'conf-mode-hook #'display-line-numbers-mode)
(use-package highlight-indent-guides
:ensure t
:config
(setq highlight-indent-guides-method 'character))
(use-package multiple-cursors
:ensure t
:bind (("A-S-c A-S-c" . mc/edit-lines)
("C-." . mc/mark-next-like-this)
("C-," . mc/mark-previous-like-this)
("A->" . mc/mark-all-like-this)
("C-A-<mouse-1>" . mc/add-cursor-on-click)))
(defun unfill-paragraph (&optional region)
"Takes a multi-line paragraph or (REGION) and make it into a single line of text."
(interactive (progn (barf-if-buffer-read-only) '(t)))
(let ((fill-column (point-max))
;; This would override `fill-column' if it's an integer.
(emacs-lisp-docstring-fill-column t))
(fill-paragraph nil region)))
(require 'treesit)
;; modules build from https://github.com/casouri/tree-sitter-module
(setq treesit-extra-load-path '("~/Projects/tree-sitter-module/dist"))
(push '(css-mode . css-ts-mode) major-mode-remap-alist)
(push '(javascript-mode . js-ts-mode) major-mode-remap-alist)
(push '(js-json-mode . json-ts-mode) major-mode-remap-alist)
(push '(typescript-mode . typescript-ts-mode) major-mode-remap-alist)
(push '(typescript-mode . tsx-ts-mode) major-mode-remap-alist)
(push '(ruby-mode . ruby-ts-mode) major-mode-remap-alist)
(add-to-list 'auto-mode-alist '("\\.tsx?\\'" . tsx-ts-mode))
(use-package sideline-flymake
:ensure t
:hook (flymake-mode . sideline-mode)
:custom
(flymake-error-bitmap '(my-rounded-fringe-indicator compilation-error))
(flymake-note-bitmap '(my-rounded-fringe-indicator compilation-info))
(flymake-warning-bitmap '(my-rounded-fringe-indicator compilation-warning))
:init
(setq sideline-flymake-display-errors-whole-line 'point ; 'point to show errors only on point
sideline-backends-right '(sideline-flymake))) ; 'line to show errors on the current line
(when (fboundp 'define-fringe-bitmap)
(define-fringe-bitmap 'my-rounded-fringe-indicator
(vector #b00000000
#b00000000
#b00000000
#b00000000
#b00000000
#b00000000
#b00000000
#b00011100
#b00111110
#b00111110
#b00111110
#b00011100
#b00000000
#b00000000
#b00000000
#b00000000
#b00000000)))
;; source: https://github.com/angrybacon/dotemacs/blob/master/lisp/use-lint.el
(use-package flymake-eslint
:ensure t
:functions flymake-eslint-enable
:preface
(defun flymake-eslint-enable-maybe ()
"Enable `flymake-eslint' based on the project configuration.
Search for the project ESLint configuration to determine whether the buffer
should be checked."
(when-let* ((root (locate-dominating-file (buffer-file-name) "package.json"))
(rc (locate-file ".eslintrc" (list root) '(".js" ".json"))))
(make-local-variable 'exec-path)
(push (file-name-concat root "node_modules" ".bin") exec-path)
(setq-local flymake-eslint-project-root root)
(flymake-eslint-enable))))
(use-package flyspell
:ensure nil
:bind (("<f7>" . 'fd-switch-dictionary)
("C-;" . 'flyspell-correct-wrapper)))
(use-package flyspell-correct-popup
:ensure t
:config
(setq ispell-program-name "aspell")
(ispell-change-dictionary "pt_BR"))
(defun fd-switch-dictionary()
(interactive)
(let* ((dic ispell-current-dictionary)
(change (if (string= dic "pt_BR") "english" "pt_BR")))
(ispell-change-dictionary change)
(message "Dictionary switched from %s to %s" dic change)))
;; (global-set-key (kbd "<f7>") )
;; (define-key flyspell-mode-map (kbd "C-;") 'flyspell-correct-wrapper)
(use-package yasnippet
:ensure t
:init
:config
(yas-load-directory "~/.emacs.d/snippets")
(yas-global-mode 1))
(use-package yafolding
:ensure t
:hook
(prog-mode-hook . yafolding-mode)
:bind ("C-c C-f" . yafolding-toggle-element))
(use-package restclient :ensure t)
(use-package projectile
:ensure t
:init
(projectile-mode +1)
:bind (
("C-c p" . projectile-command-map)
("M-[" . projectile-previous-project-buffer)
("M-]" . projectile-next-project-buffer))
:config
(setq projectile-indexing-method 'hybrid
projectile-sort-order 'recently-active
compilation-read-command nil
projectile-comint-mode t)
(add-to-list 'projectile-globally-ignored-directories "node_modules")
(add-to-list 'projectile-globally-ignored-files "yarn.lock")
:custom
(projectile-globally-ignored-buffers '("*scratch*" "*lsp-log*" "*xref*" "*EGLOT" "*Messages*" "*compilation" "*vterm*" "*Flymake")))
(use-package magit :ensure t)
;;(use-package magit-todos :ensure t)
(use-package git-timemachine :ensure t)
(use-package blamer
:ensure t
:bind (("s-i" . blamer-show-commit-info)
("s-n" . blamer-mode))
:defer 20
:custom
(blamer-idle-time 0.3)
(blamer-min-offset 10)
:custom-face
(blamer-face ((t :foreground "#9099AB"
:background nil
:height .9
:italic t))))
(use-package org
:ensure nil
:custom
(org-agenda-files
'(
"/Users/guerra/Projects/org-files/roam/20230102102131-financeiro.org"
"/Users/guerra/Projects/org-files/roam/20230102103928-pessoal.org"
"/Users/guerra/Projects/org-files/roam/20230402214745-the_clear_cut.org"
))
(org-agenda-span 15)
(org-deadline-warning-days 0)
(org-icalendar-deadline-summary-prefix "")
(org-icalendar-timezone "")
(org-icalendar-use-deadline '(event-if-todo todo-due))
(org-icalendar-with-timestamps nil)
:bind (("C-c a" . (lambda () (interactive) (org-agenda nil "z")) )
("C-c /" . 'org-capture)
("s-c" . 'ox-clip-formatted-copy))
:hook (org-mode . turn-on-flyspell))
(use-package org-contrib
:ensure t
:config
(require 'org-inlinetask)
(require 'org-tempo)
(require 'org-collector) )
(use-package org-web-tools
:ensure t
:custom
(org-web-tools-pandoc-sleep-time 1.8))
(use-package org-ql
:ensure (org-ql
:type git :host github
:repo "alphapapa/org-ql")
:after '(org))
(use-package git-auto-commit-mode :ensure t)
(use-package ox-clip :ensure t)
(setq org-export-coding-system 'utf-8
org-directory "~/Projects/org-files/"
org-tag-alist '(("work" . ?w) ("personal" . ?p) ("meta" . ?m) ("emacsLove" . ?l) ("quotes" . ?q) ("finances" . ?f) ("howto" . ?h))
org-log-done nil
org-log-repeat nil
org-startup-indented t
org-export-with-toc nil
org-export-with-section-numbers nil
gac-automatically-push-p t)
(use-package ox-slack
:ensure t
:bind ("C-c e s" . org-slack-export-to-clipboard-as-slack))
(use-package ox-reveal :ensure t)
(setq org-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js"
org-reveal-title-slide nil
org-reveal-mathjax t)
(use-package htmlize :ensure t)
(use-package olivetti
:ensure t
:custom
(olivetti-body-width 120))
(use-package org-modern
:ensure t
:config
(setq ;; Edit settings
org-auto-align-tags nil
org-tags-column 0
org-fold-catch-invisible-edits 'show-and-error
org-special-ctrl-a/e t
org-insert-heading-respect-content t
;; Org styling, hide markup etc.
org-hide-emphasis-markers t
org-pretty-entities nil
org-ellipsis "…")
(global-org-modern-mode))
(use-package org-super-agenda
:ensure t
:after org-agenda
:config
(org-super-agenda-mode t)
(setq org-agenda-skip-scheduled-if-done t))
(setq org-agenda-custom-commands
'(("z" "Super view"
((tags "meta" ((org-agenda-overriding-header "Objetivos de 2023")))
(agenda "" ((org-agenda-span 'week)
(org-agenda-overriding-header "")
))
(alltodo "" ((org-agenda-overriding-header "")
(org-agenda-remove-tags t)
(org-super-agenda-groups
'(
(:name "🚨 Atrasados"
:deadline past
:order 7)
(:name "PrĂłximos eventos"
:discard (:tag ("finances"))
:deadline future
:order 8)
(:name "Sem data" :deadline nil :order 9)
(:discard (:tag ("Routine" "Daily" "meta" "finances")))))))
))))
Check if a billing is paid based on the date
(defun is-paid? (time)
(if (eq (string-to-number (format-time-string "%m")) (nth 4 (org-parse-time-string time)))
"-" "pago"))
Add ID to all headings source
(defun add-id-to-tasks-in-file ()
"Add ID properties to all tasks in the current file which
do not already have one."
(interactive)
(org-ql-select (buffer-file-name)
'(and
(todo))
:action #'org-id-get-create))
(use-package org-roam
:ensure t
:custom
(org-roam-directory "~/Projects/org-files/roam")
(setq org-roam-dailies-directory "daily/")
(org-roam-completion-everywhere t)
:bind (("C-c n l" . org-roam-buffer-toggle)
("<f4>" . org-roam-node-find)
("C-c n i" . org-roam-node-insert)
("<f12>" . org-roam-dailies-goto-today)
;; :map org-mode-map
;; ("C-M-i" . completion-at-point)
:map org-roam-dailies-map
("Y" . org-roam-dailies-capture-yesterday)
("T" . org-roam-dailies-capture-tomorrow))
:bind-keymap
("C-c n d" . org-roam-dailies-map)
:config
(require 'org-roam-dailies) ;; Ensure the keymap is available
(org-roam-db-autosync-mode))
(defun org-agenda-export-to-ics ()
(interactive)
(org-icalendar-combine-agenda-files)
(copy-file org-agenda-private-local-path org-agenda-private-remote-path t))
(use-package midnight
:ensure nil
:config
(midnight-delay-set 'midnight-delay 16200)
(setq midnight-period 2400 ;; in seconds
org-agenda-private-local-path "~/.org.ics"
org-agenda-private-remote-path "~/Google Drive/My Drive/org.ics")
:hook (midnight . org-agenda-export-to-ics)
:bind ("C-c e i" . org-agenda-export-to-ics))
(setq org-src-fontify-natively t)
(setq org-confirm-babel-evaluate nil)
(org-babel-do-load-languages
'org-babel-load-languages
'((python . t)
(sql . t)))
(use-package markdown-mode :ensure t)
(use-package web-mode
:ensure t
:mode (("\\.html?\\'" . web-mode))
:config
(setq web-mode-markup-indent-offset 2
web-mode-enable-auto-indentation nil
web-mode-css-indent-offset 2
web-mode-code-indent-offset 2
web-mode-block-padding 2
web-mode-comment-style 2
web-mode-enable-css-colorization t
web-mode-enable-auto-pairing t
web-mode-enable-comment-keywords t
web-mode-enable-current-element-highlight t
web-mode-enable-current-column-highlight t
web-mode-content-types-alist '(("django" . "\\.tpl\\'") ("django" . "\\.liquid\\'"))))
Auto rename tag
(use-package auto-rename-tag
:ensure t
:hook
(tsx-ts-mode . auto-rename-tag-mode))
yasnippet
(eval-after-load 'yasnippet
'(let ((dir "~/.emacs.d/snippets/web-mode"))
(add-to-list 'yas-snippet-dirs dir)
(yas-load-directory dir)))
liquid
(define-derived-mode liquid-mode web-mode "Liquid"
"Use web mode to highlight liquid files.")
(provide 'liquid-mode)
(add-to-list 'auto-mode-alist '("\\.liquid\\'" . liquid-mode))
(use-package emmet-mode
:ensure t
:hook ((web-mode tsx-ts-mode typescript-ts-mode) . emmet-mode)
:config
(setq emmet-indent-after-insert nil
emmet-indentation 2
emmet-expand-jsx-className? t
emmet-move-cursor-between-quotes t
emmet-self-closing-tag-style " /")
(add-to-list 'emmet-jsx-major-modes 'tsx-ts-mode))
(setq js-indent-level 2)
(use-package prettier-js
:ensure t
:ensure-system-package (prettier . "npm i -g prettier")
:hook ((typescript-ts-mode . prettier-js-mode)
(js-ts-mode . prettier-js-mode)
(tsx-ts-mode . prettier-js-mode)))
(use-package jest-test-mode
:ensure t
:commands jest-test-mode
:hook (typescript-mode js-mode typescript-tsx-mode))
(use-package typescript-ts-mode
:ensure nil
:ensure-system-package (typescript-language-server . "npm i -g typescript-language-server"))
(defun node-project-p ()
"Predicate for determining if the open project is a Node one."
(let ((p-root (cdr (project-current))))
(file-exists-p (concat p-root "package.json"))))
;; source: https://github.com/emacs-typescript/typescript.el
(require 'ansi-color)
(defun colorize-compilation-buffer ()
(ansi-color-apply-on-region compilation-filter-start (point-max)))
(add-hook 'compilation-filter-hook 'colorize-compilation-buffer)
(use-package ts-comint
:ensure (ts-comint
:type git :host github
:repo "nverno/ts-comint"))
(use-package flymake-ruby :ensure t)
(add-hook 'ruby-ts-mode-hook 'flymake-ruby-load)
(use-package rubocop
:ensure t)
(use-package rubocopfmt
:ensure t
:hook
(ruby-mode . rubocopfmt-mode))
(defun deno-project-p ()
"Predicate for determining if the open project is a Deno one."
(let ((p-root (cdr (project-current))))
(file-exists-p (concat p-root "deno.json"))))
Buttercup
(use-package buttercup :ensure t)
(use-package lua-mode :ensure t)
(use-package json-mode :ensure t)
(use-package prisma-mode
:straight (prisma-mode :host github :repo "pimeys/emacs-prisma-mode")
:ensure-system-package (prisma-language-server . "npm i -g @prisma/language-server"))
(use-package yaml-mode :ensure t)
(use-package dart-mode
:ensure t
:hook (dart-mode . flutter-test-mode)
(dart-mode . eglot-ensure))
(use-package flutter
:ensure t
:after (dart-mode)
:bind (:map dart-mode-map
("C-M-x" . #'flutter-run-or-hot-reload)))
;; (use-package lsp-dart
;; :ensure t
;; :hook (dart-mode . lsp)
;; :custom
;; (lsp-dart-flutter-sdk-dir "~/snap/flutter/common/flutter")
;; :config
;; (setq gc-cons-threshold (* 100 1024 1024)
;; read-process-output-max (* 1024 1024)))
Original code from joaotavora/eglot#999
(defun ecma-server-program (_)
"Decide which server to use for ECMA Script based on project characteristics."
(cond ((deno-project-p) '("deno" "lsp" :initializationOptions (:enable t :lint t)))
((node-project-p) '("typescript-language-server" "--stdio"))
(t nil)))
;; source: https://manueluberti.eu/2022/09/01/consult-xref.html
(defun mu-project-find-regexp ()
"Use `project-find-regexp' with completion."
(interactive)
(defvar xref-show-xrefs-function)
(let ((xref-show-xrefs-function #'consult-xref))
(if-let ((tap (thing-at-point 'symbol)))
(project-find-regexp tap)
(call-interactively #'project-find-regexp))))
(defun eglot-shutdown-project ()
"Kill the LSP server for the current project if it exists."
(when-let ((server (eglot-current-server)))
(ignore-errors (eglot-shutdown server))))
(use-package eglot
:ensure nil
:init
(put 'eglot-server-programs 'safe-local-variable 'listp)
:hook
(typescript-ts-mode . eglot-ensure)
(js-mode . eglot-ensure)
(js-ts-mode . eglot-ensure)
(tsx-ts-mode . eglot-ensure)
(web-mode . eglot-ensure)
(liquid-mode . eglot-ensure)
(ruby-ts-mode . eglot-ensure)
(prisma-mode . eglot-ensure)
(sql-mode . eglot-ensure)
(eglot-managed-mode . flymake-eslint-enable-maybe)
:bind (:map eglot-mode-map
("C-c ." . eglot-code-actions)
("C-c e r" . eglot-rename)
("C-c e f" . eglot-format)
("C-c C-d" . eglot-help-at-point)
("M-?" . xref-find-references)
("M-." . xref-find-definitions)
("C-c f n" . flymake-goto-next-error)
("C-c f p" . flymake-goto-prev-error)
("C-c f d" . flymake-show-project-diagnostics))
:custom
(eglot-autoshutdown t)
(eglot-menu-string "LSP")
(eglot-confirm-server-initiated-edits nil)
:config
(setq eglot-sync-connect 1)
(fset #'jsonrpc--log-event #'ignore)
(put 'eglot-error 'flymake-overlay-control nil)
(put 'eglot-note 'flymake-overlay-control nil)
(put 'eglot-warning 'flymake-overlay-control nil)
(advice-add 'eglot--apply-workspace-edit :after #'me/project-save)
(advice-add 'project-kill-buffers :before #'me/eglot-shutdown-project)
(defclass eglot-sqls (eglot-lsp-server) () :documentation "SQL's Language Server")
(add-to-list 'eglot-server-programs '((liquid-mode) . ("shopify" "theme" "language-server")))
(add-to-list 'eglot-server-programs '(sql-mode . (eglot-sqls "sqls")))
(add-to-list 'eglot-server-programs '((js-ts-mode tsx-ts-mode typescript-ts-mode) . ecma-server-program))
;; source https://github.com/joaotavora/eglot/issues/523#issuecomment-1746342643
(defun sloth/org-babel-edit-prep (info)
(setq buffer-file-name (or (alist-get :file (caddr info))
"org-src-babel-tmp"))
(eglot-ensure))
(advice-add 'org-edit-src-code
:before (defun sloth/org-edit-src-code/before (&rest args)
(when-let* ((element (org-element-at-point))
(type (org-element-type element))
(lang (org-element-property :language element))
(mode (org-src-get-lang-mode lang))
((eglot--lookup-mode mode))
(edit-pre (intern
(format "org-babel-edit-prep:%s" lang))))
(if (fboundp edit-pre)
(advice-add edit-pre :after #'sloth/org-babel-edit-prep)
(fset edit-pre #'sloth/org-babel-edit-prep))))))
(use-package eldoc-box
:ensure t
:bind ("C-h ." . eldoc-box-help-at-point))
(use-package sql-indent :ensure t)
(use-package sqlformat
:ensure t
:config
(setq sqlformat-command 'pgformatter
sqlformat-args '("-s2" "-g"))
:hook (sql-mode . sqlformat-on-save-mode)
:bind (:map sql-mode-map ("C-c C-f" . sqlformat)))
(use-package vertico
:ensure t
:init
(vertico-mode)
:custom
(vertico-group-separator ((t (:inherit all-the-icons-dorange :strike-through t))))
(vertico-group-title ((t (:inherit all-the-icons-dorange :slant italic)))))
(use-package savehist
:init
(savehist-mode))
(use-package orderless
:ensure t
:custom
(completion-styles '(orderless basic))
(completion-category-overrides '((file (styles basic partial-completion)))))
(use-package consult
:ensure t
:bind (("C-M-l" . consult-imenu)
("C-s" . consult-line)
("C-M-g" . consult-ripgrep)
("C-M-o" . consult-org-heading))
:hook (completion-list-mode . consult-preview-at-point-mode)
:init
(autoload 'projectile-project-root "projectile")
(setq register-preview-delay 0
register-preview-function #'consult-register-format
xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref))
(use-package consult-org-roam
:ensure t
:after org-roam
:init
(require 'consult-org-roam)
;; Activate the minor mode
(consult-org-roam-mode 1)
:custom
;; Use `ripgrep' for searching with `consult-org-roam-search'
(consult-org-roam-grep-func #'consult-ripgrep)
;; Configure a custom narrow key for `consult-buffer'
(consult-org-roam-buffer-narrow-key ?r)
;; Display org-roam buffers right after non-org-roam buffers
;; in consult-buffer (and not down at the bottom)
(consult-org-roam-buffer-after-buffers t)
:config
;; Eventually suppress previewing for certain functions
(consult-customize
consult-org-roam-forward-links
:preview-key (kbd "M-."))
:bind
;; Define some convenient keybindings as an addition
("C-c n e" . consult-org-roam-file-find)
("C-c n b" . consult-org-roam-backlinks)
("C-c n l" . consult-org-roam-forward-links)
("C-c n r" . consult-org-roam-search))
(use-package embark
:ensure t
:bind
(("C-." . embark-act) ;; pick some comfortable binding
("C-;" . embark-dwim) ;; good alternative: M-.
("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
;; Show the Embark target at point via Eldoc. You may adjust the Eldoc
;; strategy, if you want to see the documentation from multiple providers.
(add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
;; (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)
: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)))))
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:ensure t ; only need to install it, embark loads it after consult if found
:hook
(embark-collect-mode . consult-preview-at-point-mode))
(use-package which-key
:ensure t
:config
(which-key-mode))
Javascript
(use-package js-comint :ensure t)
(use-package read-aloud
:ensure t
:config
(setq read-aloud-engine "say"))
(use-package csv-mode :ensure t)
(use-package compile
:ensure nil
:custom
(compilation-scroll-output 'first-error)
(compilation-always-kill t)
(compilation-max-output-line-length nil)
:hook (compilation-mode . hl-line-mode)
:init
; from enberg on #emacs
(add-hook 'compilation-finish-functions
(lambda (buf str)
(if (null (string-match ".*exited abnormally.*" str))
;;no errors, make the compilation window go away in a few seconds
(progn
(run-at-time
"1 sec" nil 'delete-windows-on
(get-buffer-create "*compilation*"))
(message "No Compilation Errors!"))))))
(use-package fancy-compilation
:ensure t
:defer 3
:config
(fancy-compilation-mode)
:custom
(fancy-compilation-scroll-output 'first-error))
(use-package recompile-on-save
:ensure t
;; Kill the buffer message that pops up after running advice on compile
:hook (after-init . (lambda () (run-at-time 1 nil
(lambda ()
(when (get-buffer "*Compile-Log*")
(kill-buffer "*Compile-Log*"))
(delete-other-windows)))))
:init
(recompile-on-save-advice compile))
(use-package elfeed
:ensure t
:custom
(elfeed-db-directory
(expand-file-name "elfeed" user-emacs-directory))
(elfeed-show-entry-switch 'display-buffer))
(use-package graphql-mode
:ensure t)
(use-package with-venv
:ensure t)