572 lines
17 KiB
EmacsLisp
572 lines
17 KiB
EmacsLisp
;;; -*- lexical-binding: t; -*-
|
|
|
|
(setq gc-cons-threshold (* 800000 100))
|
|
|
|
(require 'package)
|
|
(add-to-list 'package-archives
|
|
'("melpa" . "https://melpa.org/packages/") t)
|
|
|
|
(require 'use-package)
|
|
(require 'use-package-ensure)
|
|
(require 'bind-key)
|
|
|
|
;; If startup times are slow
|
|
;; (setq use-package-verbose t)
|
|
(setq use-package-compute-statistics t)
|
|
|
|
(add-to-list 'load-path (concat user-emacs-directory "user-lisp/"))
|
|
(add-to-list 'load-path "/opt/homebrew/Cellar/mu/1.12.14/share/emacs/site-lisp/mu/mu4e")
|
|
|
|
(global-auto-revert-mode 1)
|
|
(recentf-mode 1)
|
|
(setq tab-bar-show nil)
|
|
(setq inhibit-startup-message t)
|
|
(setq initial-scratch-message nil)
|
|
(setq ring-bell-function 'ignore)
|
|
(add-hook 'window-setup-hook 'toggle-frame-maximized t)
|
|
(defalias 'yes-or-no-p 'y-or-n-p)
|
|
(setq make-backup-files nil)
|
|
(setq custom-file (concat user-emacs-directory "custom.el"))
|
|
(unless (file-exists-p custom-file)
|
|
(make-empty-file custom-file))
|
|
(load custom-file)
|
|
(scroll-bar-mode -1)
|
|
(tool-bar-mode -1)
|
|
(menu-bar-mode -1)
|
|
(delete-selection-mode 1)
|
|
(electric-pair-mode 1)
|
|
(add-hook 'before-save-hook 'delete-trailing-whitespace)
|
|
(setq reb-re-syntax 'string)
|
|
(setq default-tab-width 4)
|
|
(setq-default tab-width 4)
|
|
(set-face-attribute 'default nil :height 160 :family "Berkeley Mono")
|
|
(global-hl-line-mode 1)
|
|
(pixel-scroll-precision-mode 1)
|
|
(kill-ring-deindent-mode 1)
|
|
|
|
(setopt auto-revert-avoid-polling t)
|
|
(setopt auto-revert-interval 5)
|
|
(setopt auto-revert-check-vc-info t)
|
|
(global-auto-revert-mode 1)
|
|
(setq global-auto-revert-non-file-buffers t)
|
|
(setq-default grep-command "rg")
|
|
|
|
(setq use-package-always-ensure t)
|
|
(setq mac-command-modifier 'control)
|
|
(setq is-mac (string= system-type "darwin"))
|
|
|
|
(setq-default cursor-type 'bar)
|
|
|
|
(defun hgh/disable-cursor-blink ()
|
|
(blink-cursor-mode -1))
|
|
|
|
(defun hgh/enable-cursor-blink ()
|
|
(blink-cursor-mode 1))
|
|
|
|
(add-hook 'activate-mark-hook 'hgh/disable-cursor-blink)
|
|
(add-hook 'deactivate-mark-hook 'hgh/enable-cursor-blink)
|
|
|
|
(when is-mac
|
|
(setq dired-use-ls-dired t
|
|
insert-directory-program "gls"
|
|
dired-listing-switches "-aBhl --group-directories-first")
|
|
(setq-default manual-program "gman"))
|
|
|
|
;; Add .asdf to exec-path
|
|
(when (file-exists-p (file-truename "~/.asdf"))
|
|
(push (file-truename "~/.asdf/shims") exec-path)
|
|
(push (file-truename "~/.asdf/bin") exec-path))
|
|
|
|
;; Remove "/mnt/c/" for WSL PATH
|
|
(setq exec-path
|
|
(cl-remove-if (lambda (s)
|
|
(and (< 5 (length s))
|
|
(string= (substring s 0 6) "/mnt/c")))
|
|
exec-path))
|
|
|
|
(when exec-path
|
|
(setenv "PATH" (string-join exec-path ":")))
|
|
|
|
(defun hgh/duplicate-dwim ()
|
|
(interactive)
|
|
(duplicate-dwim)
|
|
(next-line))
|
|
|
|
(defun hgh/visit-init-file ()
|
|
(interactive)
|
|
(find-file user-init-file))
|
|
|
|
(defun hgh/project-ripgrep (regexp)
|
|
(interactive (list (read-from-minibuffer "Search (regexp): " (thing-at-point 'symbol))))
|
|
(rg regexp "*" (project-root (project-current))))
|
|
|
|
(defun hgh/current-date-time ()
|
|
(interactive)
|
|
(insert (format-time-string "%Y-%m-%d %H:%M:%S")))
|
|
|
|
(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)
|
|
|
|
(defun hgh/next-error ()
|
|
(interactive)
|
|
(if (eglot-managed-p)
|
|
(flymake-goto-next-error)
|
|
(next-error)))
|
|
|
|
;; key bindings
|
|
(keymap-global-set "M-o" #'other-window)
|
|
(keymap-global-set "M-i" #'imenu)
|
|
(keymap-global-set "<f5>" #'compile)
|
|
(keymap-global-set "C-c r r" #'revert-buffer)
|
|
(keymap-global-set "M-]" #'forward-paragraph)
|
|
(keymap-global-set "M-[" #'backward-paragraph)
|
|
(keymap-global-set "C-h h" #'eldoc)
|
|
(keymap-global-set "C-]" #'hgh/next-error)
|
|
(keymap-global-set "C-c e i" #'hgh/visit-init-file)
|
|
(keymap-global-set "C-c c" #'compile)
|
|
(keymap-global-set "C-x C-b" #'ibuffer)
|
|
(keymap-global-set "M-0" #'delete-window)
|
|
(keymap-global-set "M-1" #'delete-other-windows)
|
|
(keymap-global-set "M-2" #'split-window-below)
|
|
(keymap-global-set "M-3" #'split-window-right)
|
|
(keymap-global-set "C-," #'hgh/duplicate-dwim)
|
|
|
|
(keymap-global-set "C-c f n" #'flymake-goto-next-error)
|
|
(keymap-global-set "C-c f p" #'flymake-goto-prev-error)
|
|
(keymap-global-set "C-c f b" #'flymake-show-buffer-diagnostics)
|
|
|
|
(keymap-set completion-list-mode-map "M-n" #'minibuffer-next-completion)
|
|
(keymap-set completion-list-mode-map "M-p" #'minibuffer-previous-completion)
|
|
(keymap-set completion-in-region-mode-map "M-n" #'minibuffer-next-completion)
|
|
(keymap-set completion-in-region-mode-map "M-p" #'minibuffer-previous-completion)
|
|
|
|
(require 'dired)
|
|
(setq dired-dwim-target t)
|
|
(keymap-set dired-mode-map "C-c C-c" #'wdired-change-to-wdired-mode)
|
|
|
|
(load-theme 'modus-vivendi t)
|
|
|
|
(use-package corfu
|
|
:custom
|
|
(corfu-auto t)
|
|
(corfu-cycle t)
|
|
:config
|
|
(global-corfu-mode 1))
|
|
|
|
(use-package exec-path-from-shell
|
|
:when is-mac
|
|
:config
|
|
(exec-path-from-shell-initialize))
|
|
|
|
(use-package magit
|
|
:defer t)
|
|
|
|
(use-package tree-sitter
|
|
:mode (("\\.tsx\\'" . tsx-ts-mode)
|
|
("\\.js\\'" . typescript-ts-mode)
|
|
("\\.mjs\\'" . typescript-ts-mode)
|
|
("\\.mts\\'" . typescript-ts-mode)
|
|
("\\.cjs\\'" . typescript-ts-mode)
|
|
("\\.ts\\'" . typescript-ts-mode)
|
|
("\\.jsx\\'" . tsx-ts-mode)
|
|
("\\.json\\'" . json-ts-mode))
|
|
:custom
|
|
(treesit-extra-load-path `("~/repos/tree-sitter-module/dist" ,(concat user-emacs-directory "/tree-sitter"))))
|
|
|
|
(use-package tree-sitter-langs
|
|
:defer t)
|
|
|
|
(use-package haskell-mode
|
|
:mode "\\.hs\\'")
|
|
|
|
(use-package company)
|
|
|
|
(defun enable-parinfer ()
|
|
(require 's)
|
|
(let ((buf (or (buffer-file-name) (buffer-name) "")))
|
|
(when (and
|
|
(not (s-contains? "sbcl" buf))
|
|
(not (s-contains? "ocicl" buf))
|
|
(not (s-contains? "elpa" buf))
|
|
(not (s-contains? "emacs-plus" buf))
|
|
(not (string-prefix-p "*sly" buf)))
|
|
(parinfer-rust-mode 1))))
|
|
|
|
(use-package parinfer-rust-mode
|
|
:defer t
|
|
:hook ((lisp-mode emacs-lisp-mode) . enable-parinfer)
|
|
:custom
|
|
(parinfer-rust-disable-troublesome-modes t))
|
|
|
|
(use-package sly
|
|
:commands (sly)
|
|
:custom
|
|
(inferior-lisp-program "/opt/homebrew/bin/sbcl"))
|
|
|
|
(defun hgh/--project-execute (command name)
|
|
(require 'project)
|
|
(when (not command)
|
|
(user-error (concat "No command specified for project-" name)))
|
|
(let ((default-directory (project-root (project-current t))))
|
|
(compilation-start command
|
|
nil
|
|
(lambda (mode-name) (concat "*" (project-name (project-current)) " " name "*")))))
|
|
|
|
|
|
|
|
(defmacro hgh/define-project-command (name)
|
|
"Define a project command with NAME.
|
|
Creates a variable `hgh/project-NAME-command' and function `hgh/project-NAME'."
|
|
(let ((var-sym (intern (format "hgh/project-%s-command" name)))
|
|
(fn-sym (intern (format "hgh/project-%s" name))))
|
|
`(progn
|
|
(defvar ,var-sym nil
|
|
,(format "Command to %s the project." name))
|
|
(put ',var-sym 'safe-local-variable #'stringp)
|
|
(defun ,fn-sym ()
|
|
,(format "Execute the project %s command." name)
|
|
(interactive)
|
|
(hgh/--project-execute ,var-sym ,name)))))
|
|
|
|
|
|
(hgh/define-project-command "run")
|
|
(hgh/define-project-command "test")
|
|
(hgh/define-project-command "lint")
|
|
|
|
(use-package project
|
|
:bind (("C-x p s" . hgh/project-ripgrep)
|
|
("C-x p S" . project-shell)
|
|
("C-x p t" . hgh/project-test)
|
|
("C-x p r" . hgh/project-run)
|
|
("C-x p l" . hgh/project-lint)))
|
|
|
|
(use-package vertico
|
|
:custom
|
|
(vertico-cycle t)
|
|
:config
|
|
(vertico-mode 1))
|
|
|
|
(use-package savehist
|
|
:init
|
|
(savehist-mode))
|
|
|
|
(use-package marginalia
|
|
:config
|
|
(marginalia-mode 1))
|
|
|
|
(use-package orderless
|
|
:init
|
|
(setq completion-styles '(orderless basic)
|
|
completion-category-overrides '((file (styles basic partial-completion)))))
|
|
|
|
(use-package cape
|
|
:init
|
|
(add-to-list 'completion-at-point-functions #'cape-dabbrev))
|
|
|
|
(defun hgh/org-mode-visual-fill ()
|
|
(setq visual-fill-column-width 120
|
|
visual-fill-column-center-text t)
|
|
(visual-fill-column-mode 1))
|
|
|
|
(use-package visual-fill-column
|
|
:hook (org-mode . hgh/org-mode-visual-fill))
|
|
|
|
(use-package eglot
|
|
:hook
|
|
((clojure-mode . eglot-ensure)
|
|
(go-mode . eglot-ensure)
|
|
(rust-ts-mode . eglot-ensure)
|
|
(typescript-ts-base-mode . eglot-ensure)
|
|
(elixir-ts-mode . eglot-ensure)
|
|
(heex-ts-mode . eglot-ensure)
|
|
(java-ts-mode . eglot-ensure)
|
|
(svelte-mode . eglot-ensure)
|
|
(haskell-mode . eglot-ensure)
|
|
(terraform-mode . eglot-ensure)
|
|
(odin-mode . eglot-ensure)
|
|
(tuareg-mode . eglot-ensure)
|
|
(ruby-mode . eglot-ensure)
|
|
(dart-mode . eglot-ensure))
|
|
:bind
|
|
(:map eglot-mode-map
|
|
("C-c r" . eglot-rename)
|
|
("C-c a" . eglot-code-actions)
|
|
("C-c f" . eglot-format-buffer)
|
|
("C-c d" . xref-find-definitions))
|
|
:init
|
|
(setq eglot-events-buffer-size 0)
|
|
:config
|
|
;; Set up using clippy with rust analyzer
|
|
(setf eglot-server-programs
|
|
(cl-remove-if (lambda (c) (equal (car c) (or 'rust-mode 'tuareg-mode '(dart-mode dart-ts-mode))))
|
|
eglot-server-programs))
|
|
|
|
(setf eglot-server-programs
|
|
(append (list
|
|
(list '(rust-ts-mode rust-mode) "rust-analyzer" :initializationOptions '(:checkOnSave (:command "clippy")))
|
|
'(svelte-mode "svelteserver" "--stdio")
|
|
'(haskell-mode "haskell-language-server-wrapper" "--lsp")
|
|
'(tuareg-mode "dune" "exec" "ocamllsp")
|
|
'(reason-mode "dune" "exec" "ocamllsp")
|
|
'(ruby-mode "solargraph" "socket" "--port" :autoport)
|
|
'(dart-mode "dart" "language-server" "--client-id" "emacs.eglot-dart")
|
|
eglot-server-programs))))
|
|
|
|
(setenv "DOTNET_ROOT" "~/.local/share/mise/installs/dotnet/9")
|
|
(push '("\\.csproj$" . xml-mode) auto-mode-alist)
|
|
(push '("\\.vs$" . c-mode) auto-mode-alist)
|
|
(push '("\\.fs$" . c-mode) auto-mode-alist)
|
|
(push '("\\.sbclrc" . lisp-mode) auto-mode-alist)
|
|
(push '("dune-project\\'" . lisp-mode) auto-mode-alist)
|
|
(push '("dune\\'" . lisp-mode) auto-mode-alist)
|
|
(push '("\\.ml\\'" . tuareg-mode) auto-mode-alist)
|
|
(setf auto-mode-alist
|
|
(cl-remove-if
|
|
(lambda (tup)
|
|
(or
|
|
(and
|
|
(string-equal (car tup) "\\.ml\\'")
|
|
(eq (cdr tup) 'ocaml-ts-mode))
|
|
(and
|
|
(string-equal (car tup) "\\.ml\\'")
|
|
(eq (cdr tup) 'lisp-mode))))
|
|
auto-mode-alist))
|
|
|
|
;; paredit
|
|
|
|
; (autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t)
|
|
(defun setup-paredit ()
|
|
(load (string-join (list user-emacs-directory "paredit.el")))
|
|
(setcdr paredit-mode-map nil)
|
|
(define-key paredit-mode-map (kbd "M-'") #'paredit-forward-slurp-sexp)
|
|
(define-key paredit-mode-map (kbd "M-;") #'paredit-backward-slurp-sexp)
|
|
(define-key paredit-mode-map (kbd "M-\"") #'paredit-forward-barf-sexp)
|
|
(define-key paredit-mode-map (kbd "M-:") #'paredit-backward-barf-sexp)
|
|
(enable-paredit-mode))
|
|
|
|
(defun hgh/rg (search)
|
|
(interactive "sSearch: ")
|
|
(compilation-start
|
|
(concat "rg -S --no-heading '" search "'")
|
|
'compilation-mode
|
|
(lambda (s)
|
|
(concat
|
|
"*"
|
|
(file-name-nondirectory (directory-file-name default-directory))
|
|
" rg*"))))
|
|
|
|
(defun hgh/set-cursor-type-box (&rest _args)
|
|
(setq-local cursor-type 'box))
|
|
|
|
(defun hgh/set-cursor-type-bar (&rest _args)
|
|
(setq-local cursor-type 'bar))
|
|
|
|
(use-package multiple-cursors
|
|
:hook ((multiple-cursors-mode-disabled . hgh/set-cursor-type-bar))
|
|
:bind (("C->" . mc/mark-next-like-this)
|
|
("C-<" . mc/mark-previous-like-this))
|
|
:init
|
|
;; NOTE(grant): I have no idea if the package is deferred or autoloaded anymore
|
|
(advice-add 'mc/mark-next-like-this :before #'hgh/set-cursor-type-box)
|
|
(advice-add 'mc/mark-previous-like-this :before #'hgh/set-cursor-type-box))
|
|
|
|
(use-package yasnippet
|
|
:diminish
|
|
:defer t
|
|
:config
|
|
(yas-global-mode 1))
|
|
|
|
(use-package yasnippet-snippets
|
|
:after (yasnippet))
|
|
|
|
(use-package markdown-mode
|
|
:mode "\\.md\\'")
|
|
|
|
;; Run Prettier only in certain major-modes before saving:
|
|
(defvar hgh/prettier-modes
|
|
'(tsx-ts-mode typescript-ts-mode typescript-ts-base-mode json-ts-mode javascript-mode js2-mode typescript-mode web-mode)
|
|
"List of major modes where Prettier should auto-run on save.")
|
|
|
|
(defun hgh/run-prettier-if-appropriate ()
|
|
"Run Prettier on the buffer's file if `major-mode` is in `my/prettier-modes`."
|
|
(when (and (buffer-file-name)
|
|
(member major-mode hgh/prettier-modes))
|
|
;; call the prettier CLI; output errors to *Prettier Errors* buffer
|
|
(call-process "prettier" nil "*Prettier Errors*" t
|
|
"--write" (buffer-file-name))
|
|
;; reload the buffer if prettier modified the file
|
|
(revert-buffer :ignore-auto :noconfirm :preserve-modes)))
|
|
|
|
(add-hook 'after-save-hook #'hgh/run-prettier-if-appropriate)
|
|
|
|
(use-package terraform-mode
|
|
:mode ("\\.tf\\'" "\\.tfvars\\'"))
|
|
|
|
(use-package cider
|
|
:defer t)
|
|
|
|
(use-package org
|
|
:ensure nil
|
|
:mode ("\\.org\\'" . org-mode)
|
|
:hook (org-mode . org-indent-mode)
|
|
:custom
|
|
(org-todo-keywords '((sequence "TODO" "INPROGRESS" "DONE")))
|
|
(org-support-shift-select t)
|
|
(org-default-notes-file (concat org-directory "/captures.org"))
|
|
(org-html-validation-link nil)
|
|
(org-html-head-include-default-style nil)
|
|
(org-html-head-include-scripts nil)
|
|
(org-html-head "<link rel=\"stylesheet\" href=\"https://cdn.simplecss.org/simple.min.css\" />")
|
|
|
|
(org-capture-templates
|
|
'(("t" "Task" entry (file+headline "~/org/inbox.org" "Tasks")
|
|
"* TODO %?\n%U\n%i\n%a")
|
|
("n" "Note" entry (file+headline "~/org/inbox.org" "Notes")
|
|
"* %?\n%U\n%i\n%a")
|
|
("i" "Idea" entry (file+headline "~/org/inbox.org" "Ideas")
|
|
"* %?\n%U\n%i\n%a")))
|
|
|
|
(org-publish-use-timestamps-flag nil)
|
|
(org-publish-project-alist
|
|
(list
|
|
(list "writings"
|
|
:base-directory "~/Documents/writings/content"
|
|
:publishing-directory "~/Documents/writings/public"
|
|
:exclude "~/Documents/writings/notes"
|
|
:recursive t
|
|
:time-stamp-file nil
|
|
:section-numbers nil
|
|
:with-creator t
|
|
:with-author nil)))
|
|
|
|
:config
|
|
(require 'ox-publish)
|
|
|
|
(org-babel-do-load-languages
|
|
'org-babel-load-languages
|
|
'((shell . t))))
|
|
|
|
(use-package dumber-jump
|
|
:defer t
|
|
:init
|
|
(add-hook 'xref-backend-functions #'dumber-jump-xref-activate))
|
|
|
|
(use-package idris-mode
|
|
:mode "\\.idr\\'")
|
|
|
|
(use-package htmlize)
|
|
|
|
(use-package zig-mode
|
|
:mode "\\.zig\\'")
|
|
|
|
(use-package fsharp-mode
|
|
:mode "\\.fs\\'")
|
|
|
|
(use-package caddyfile-mode
|
|
:defer t)
|
|
|
|
(use-package dockerfile-mode
|
|
:defer t)
|
|
|
|
(use-package odin-mode
|
|
:mode "\\.odin\\'"
|
|
:ensure nil)
|
|
|
|
(use-package emacs-lisp-mode
|
|
:ensure nil
|
|
:bind (:map emacs-lisp-mode-map ("C-c C-c" . eval-defun)))
|
|
|
|
(use-package codex
|
|
:commands codex
|
|
:custom
|
|
(codex-provider nil)
|
|
(codex-model nil)
|
|
:ensure nil)
|
|
|
|
(use-package move-text
|
|
:bind (("M-<up>" . move-text-up)
|
|
("M-<down>" . move-text-down)))
|
|
|
|
(use-package emmet-mode
|
|
:hook (sgml-mode tsx-ts-mode)
|
|
:custom
|
|
(emmet-jsx-major-modes
|
|
'(rjsx-mode
|
|
typescript-tsx-mode
|
|
js-jsx-mode
|
|
js2-jsx-mode
|
|
jsx-mode
|
|
js-mode
|
|
;; Need to add this
|
|
tsx-ts-mode)))
|
|
|
|
(use-package mu4e
|
|
:ensure nil
|
|
:commands (mu4e)
|
|
:custom
|
|
(mu4e-maildir "~/Mail")
|
|
(mu4e-get-mail-command "mbsync -a")
|
|
(mu4e-update-interval 300)
|
|
(mu4e-change-filenames-when-moving t)
|
|
(mu4e-context-policy 'pick-first)
|
|
(mu4e-compose-context-policy 'ask-if-none)
|
|
(mu4e-contexts
|
|
(list
|
|
(make-mu4e-context
|
|
:name "Grant"
|
|
:match-func
|
|
(lambda (msg)
|
|
(when msg
|
|
(string-prefix-p "/grant" (mu4e-message-field msg :maildir))))
|
|
:vars '((user-mail-address . "grant@granthorner.dev")
|
|
(user-full-name . "Grant Horner")
|
|
(mu4e-drafts-folder . "/grant/Drafts")
|
|
(mu4e-sent-folder . "/grant/Sent Mail")
|
|
(mu4e-trash-folder . "/grant/Trash")
|
|
(mu4e-rstrash-folder . "/grant/Trash")))
|
|
(make-mu4e-context
|
|
:name "Gmail"
|
|
:match-func
|
|
(lambda (msg)
|
|
(when msg
|
|
(string-prefix-p "/gmail" (mu4e-message-field msg :maildir))))
|
|
:vars '((user-mail-address . "gmail@granthorner.dev")
|
|
(user-full-name . "Grant Horner")
|
|
(mu4e-drafts-folder . "/gmail/Drafts")
|
|
(mu4e-sent-folder . "/gmail/Sent Mail")
|
|
(mu4e-trash-folder . "/gmail/Trash")
|
|
(mu4e-rstrash-folder . "/gmail/Trash"))))))
|
|
|
|
(use-package tuareg
|
|
:mode "\\.ml\\'")
|
|
|
|
(defun hgh/eglot-restart ()
|
|
(interactive)
|
|
(require 'eglot)
|
|
(when eglot--managed-mode
|
|
(message "Shutting down eglot servers...")
|
|
(eglot-shutdown-all)
|
|
(message "Restarting eglot for current buffer...")
|
|
(eglot)))
|
|
|
|
(use-package reason-mode
|
|
:mode "\\.re\\'")
|
|
|
|
(use-package expand-region
|
|
:bind ("C-=" . er/expand-region))
|
|
|
|
(use-package ediff
|
|
:defer t
|
|
:custom
|
|
(ediff-window-setup-function 'ediff-setup-windows-plain)
|
|
(ediff-split-window-function 'split-window-horizontally)
|
|
(ediff-diff-options "-w")
|
|
:config
|
|
(set-face-attribute 'ediff-odd-diff-A nil :background "#75383b")
|
|
(set-face-attribute 'ediff-even-diff-A nil :background "#75383b")
|
|
(set-face-attribute 'ediff-odd-diff-B nil :background "#265441")
|
|
(set-face-attribute 'ediff-even-diff-B nil :background "#265441"))
|
|
|
|
(use-package dart-mode)
|
|
|
|
(use-package flutter)
|