Compare commits

...

12 Commits

8 changed files with 303 additions and 291 deletions

View File

@ -260,12 +260,12 @@ Finish up
mu4e-alert
dirvish
restclient
gptel
disaster
magit))
(setopt package-vc-selected-packages
'((dotenv :url "https://github.com/pkulev/dotenv.el")
(gptel :url "https://github.com/karthink/gptel")
(indent-bars :url "https://github.com/jdtsmith/indent-bars")
(doom-themes :url "https://github.com/JosephFerano/doom-themes")
(org-timeblock :url "https://github.com/ichernyshovvv/org-timeblock")
@ -364,12 +364,23 @@ Use Dashboard.el. First load `all-the-icons` for nicer rendering
#+begin_src emacs-lisp
(require 'olivetti)
(if (equal "flowjoe-f37" (system-name))
(setq olivetti-minimum-body-width 100)
(setq olivetti-minimum-body-width 120))
;; (if (equal "flowjoe-f37" (system-name))
;; (setq olivetti-minimum-body-width 100)
;; (setq olivetti-minimum-body-width 120))
(setq olivetti-minimum-body-width 120)
(global-set-key (kbd "C-x x o") 'olivetti-mode)
(add-hook 'prog-mode-hook 'olivetti-mode)
;; (add-hook 'prog-mode-hook 'olivetti-mode)
(defun joe/toggle-olivetti-based-on-width ()
(when (derived-mode-p 'prog-mode)
(if (> (window-total-width) 120)
(olivetti-mode 1)
(olivetti-mode -1))))
(add-hook 'window-configuration-change-hook #'joe/toggle-olivetti-based-on-width)
#+end_src
Remove this hook from Olivetti so that lines can truncate [[https://github.com/rnkn/olivetti/issues/76][Github issue]]
@ -534,12 +545,25 @@ Ligatures... are they that useful?
(interactive "r")
(if (use-region-p)
(message "%s"
(concat
(mapcar 'string-to-number
(split-string (buffer-substring-no-properties beg end) " "))))
(concat
(mapcar 'string-to-number
(split-string (buffer-substring-no-properties beg end) " "))))
(message "No region selected")))
(define-key ctl-x-x-map (kbd "a") #'joe/get-ascii-in-region)
(defun joe/project-silent-shell-command (command)
(interactive (list (or (bound-and-true-p joe/shell-command-silent-default)
(read-string "Shell command: "))))
(let* ((project-root (when (project-current)
(project-root (project-current))))
(default-directory (or project-root default-directory))
(exit-code (call-process-shell-command command nil nil)))
(unless (zerop exit-code)
(message "Command failed: %s in %s (project: %s) -> exit: %d"
command default-directory project-root exit-code))))
(global-set-key (kbd "C-M-r") #'joe/project-silent-shell-command)
#+end_src
** Text
@ -907,6 +931,7 @@ Fill region is great, except when you don't need it...
(kbd "SPC p") project-prefix-map
(kbd "SPC q") 'kill-buffer-and-window
(kbd "SPC h") 'help-command
(kbd "SPC k") 'kill-this-buffer
(kbd "SPC hf") 'helpful-callable
(kbd "SPC hv") 'helpful-variable
(kbd "SPC hk") 'helpful-key
@ -984,20 +1009,8 @@ Fill region is great, except when you don't need it...
#+end_src
** Buffers
#+begin_src emacs-lisp
(defun joe/kill-this-buffer-or-popup ()
(interactive)
"Kill the buffer normally, but if it's a popper popup, call the popper version"
(with-current-buffer (current-buffer)
(if (or (eq popper-popup-status nil)
(eq popper-popup-status 'raised))
(kill-this-buffer)
(popper-kill-latest-popup))))
(global-set-key (kbd "C-x k") #'joe/kill-this-buffer-or-popup)
(when (boundp 'evil-mode)
(evil-define-key 'normal joe/evil-space-mode-map
(kbd "SPC k") #'joe/kill-this-buffer-or-popup))
(global-set-key (kbd "C-x k") #'kill-this-buffer)
(global-set-key (kbd "C-x M-k") #'kill-buffer)
(require 'all-the-icons-ibuffer)
@ -1046,6 +1059,9 @@ Harpoon lets you quickly switch between bookmarked buffers
(global-set-key (kbd "M-3") 'harpoon-go-to-3)
(global-set-key (kbd "M-4") 'harpoon-go-to-4)
(global-set-key (kbd "M-5") 'harpoon-go-to-5)
(global-set-key (kbd "M-6") 'harpoon-go-to-6)
(global-set-key (kbd "M-7") 'harpoon-go-to-7)
(global-set-key (kbd "M-8") 'harpoon-go-to-8)
(global-set-key (kbd "C-c h 1") 'harpoon-go-to-1)
(global-set-key (kbd "C-c h 2") 'harpoon-go-to-2)
@ -1194,99 +1210,6 @@ Ace Window will show a hint if there are more than 2 windows, but I don't really
(beframe-unassume-current-frame-buffers-selectively (list curr))))
(evil-global-set-key 'normal (kbd "SPC b f") #'joe/beframe-switch-and-unassume)
#+end_src
*** Popper
#+begin_src emacs-lisp
(require 'popper)
(setq popper-reference-buffers
'("\\*compilation\\*" compilation-mode
"^\\*vterm\\*" vterm-mode
"^\\*Flymake.*" flymake-mode
"^\\*Flycheck.*" flycheck-error-list-mode
"^\\*Occur\\*$" occur-mode
"^\\*lsp-help\\*" lsp-help-mode
"^\\*eldoc\\*" special-mode
"^\\*godot.*" godot-mode
"^\\*ert\\*" ert-results-mode
"^\\*xref\\*" xref-mode
"^\\*HTTP Response\\*" javascript-mode
"^\\*SQL.*" sql-interactive-mode
"^\\*cargo-test\\*" cargo-test-mode
"^\\*cargo-run\\*" cargo-run-mode
"^\\*rustic-compilation\\*" rustic-compilation-mode
"^\\*ansi-term\\*$" term-mode
;; "^\\*Async Shell Command\\*$" shell-mode
"^\\*Async Shell Command\\*$"
("^\\*Warnings\\*$" . hide)
help-mode
helpful-mode))
(global-set-key (kbd "C-`") 'popper-toggle-latest)
(global-set-key (kbd "C-~") 'popper-cycle)
(global-set-key (kbd "C-M-`") 'popper-toggle-type)
(require 'popper-echo)
(popper-echo-mode t)
(defun joe/get-popper-dir ()
(with-current-buffer (current-buffer)
(if (or (> (window-width) 170) (eq olivetti-mode t))
joe/popper-side-toggle
'below)))
;; TODO Prot We need to revisit this function and change the rules; I
;; just saw that Popper uses side-window for it's internal popup at
;; the bottom function. I prefer the way Popper does it for anything
;; that is going to display horizontally at the bottom. However for
;; side splits I much prefer the functionality we have here where if
;; there's a window on the right, then overtake it and then when I
;; close it, keep whatever window was there open. The issue with
;; side-windows is that they keep the two window splits in tact and
;; that's not what I want. Sort of like how Magit does it, that's what
;; I want to copy. But like I have it here, it should respect my
;; "popper side" variable so I can toggle whether it appears at the
;; bottom or above.
(defun joe/popper-display-func (buffer &optional _alist)
(cond
((eq joe/popper-side-toggle 'below)
(popper-select-popup-at-bottom buffer _alist))
((when-let ((popup-buffer
(cl-find-if
#'popper-popup-p
(mapcar #'window-buffer (window-list)))))
(window--display-buffer
buffer (get-buffer-window popup-buffer) 'reuse
`((body-function . ,#'select-window)))))
((and (eq joe/popper-side-toggle 'right)
(window-in-direction 'left))
(window--display-buffer
buffer (get-buffer-window (current-buffer)) 'reuse))
((when-let ((right-window (window-in-direction 'right))
((eq joe/popper-side-toggle 'right)))
(window--display-buffer
buffer right-window 'reuse
`((body-function . ,#'select-window)))))
((and (not (window-in-direction 'right))
(not (window-in-direction 'left)))
(display-buffer-in-direction
buffer
`((window-height . 0.45)
(window-width . 0.45)
(direction . right)
(body-function . ,#'select-window))))
(t
(display-buffer-in-direction
buffer
`((window-height . 0.45)
(window-width . 0.45)
(direction . below)
(body-function . ,#'select-window))))))
(setq popper-display-function #'joe/popper-display-func)
(popper-mode t)
#+end_src
*** COMMENT Tab-bar & Tab-line
#+begin_src emacs-lisp
@ -1565,6 +1488,22 @@ These are functions to load a project specific file given the conventions I use.
(when (project-current)
(dirvish-dwim (project-root (project-current)))))
(defun joe/project-vterm ()
"Start an inferior shell in the current project's root directory.
If a buffer already exists for running a shell in the project's root,
switch to it. Otherwise, create a new shell buffer.
With \\[universal-argument] prefix arg, create a new inferior shell buffer even
if one already exists."
(interactive)
(require 'comint)
(let* ((default-directory (project-root (project-current t)))
(default-project-shell-name (project-prefixed-buffer-name "shell"))
(shell-buffer (get-buffer default-project-shell-name)))
(if (and shell-buffer (not current-prefix-arg))
(if (comint-check-proc shell-buffer)
(pop-to-buffer shell-buffer (bound-and-true-p display-comint-buffer-action))
(vterm shell-buffer))
(vterm (generate-new-buffer-name default-project-shell-name)))))
(evil-define-key 'normal joe/evil-space-mode-map (kbd "_") #'joe/project-dirvish-dwim)
(define-key project-prefix-map "t" #'joe/project-open-project-todo)
@ -1572,7 +1511,7 @@ These are functions to load a project specific file given the conventions I use.
(define-key project-prefix-map "n" #'joe/project-open-project-notes)
(define-key project-prefix-map "r" #'joe/project-open-project-readme)
(define-key project-prefix-map "l" #'joe/project-open-project-license)
(define-key project-prefix-map "s" #'eat-project)
(define-key project-prefix-map "s" #'joe/project-vterm)
(define-key project-prefix-map "S" #'eat-project-other-window)
;; Remape this
(define-key project-prefix-map "C-r" #'project-query-replace-regexp)
@ -1594,7 +1533,7 @@ Stuff to immediately switch to Jetbrains for debugging
#+begin_src emacs-lisp
(global-set-key (kbd "C-M-r") #'joe/open-in-rider)
;; (global-set-key (kbd "C-M-r") #'joe/open-in-rider)
(defun joe/raise-frame-hook ()
(select-frame-set-input-focus (selected-frame)))
(add-hook 'server-switch-hook #'joe/raise-frame-hook)
@ -1897,96 +1836,99 @@ odd looking ~'(t .t)~ is for specifying a default for all other actions.
** Email
#+begin_src emacs-lisp
(when (file-exists-p "/usr/share/emacs/site-lisp/mu4e/")
(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e/")
(require 'mu4e)
(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e/")
(require 'mu4e)
;; Attach files to a message composition buffer by going into `dired'
;; and doing C-c C-m C-a (M-x `gnus-dired-attach').
(require 'gnus-dired) ; does not require `gnus'
(add-hook 'dired-mode-hook #'gnus-dired-mode)
(add-hook 'mu4e-main-mode-hook 'olivetti-mode)
;; Attach files to a message composition buffer by going into `dired'
;; and doing C-c C-m C-a (M-x `gnus-dired-attach').
(require 'gnus-dired) ; does not require `gnus'
(add-hook 'dired-mode-hook #'gnus-dired-mode)
(add-hook 'mu4e-main-mode-hook 'olivetti-mode)
(add-to-list 'auto-mode-alist '("authinfo" . authinfo-mode))
(add-to-list 'auto-mode-alist '("authinfo" . authinfo-mode))
(setq mu4e-get-mail-command "parallel mbsync -V \"-c ~/.config/mbsync/config\" ::: ferano.io.inbox gmail.allmail")
(setq mu4e-get-mail-command "parallel mbsync -V \"-c ~/.config/mbsync/config\" ::: ferano.io gmail")
;;; Sending email (SMTP)
(require 'smtpmail)
(setq smtpmail-default-smtp-server "mail.gandi.net"
(require 'smtpmail)
(setq smtpmail-default-smtp-server "mail.gandi.net"
smtpmail-smtp-server "mail.gandi.net"
smtpmail-stream-type 'ssl
smtpmail-smtp-service 465
smtpmail-queue-mail nil)
(require 'sendmail)
(setq send-mail-function 'smtpmail-send-it)
(require 'sendmail)
(setq send-mail-function 'smtpmail-send-it)
(setq mu4e-update-interval 30)
(setq mu4e-hide-index-messages t)
(setq mu4e-completing-read-function 'completing-read)
(setq mu4e-context-policy 'pick-first)
(setq mu4e-compose-context-policy 'ask)
(setq mu4e-view-auto-mark-as-read nil)
(setq mu4e-update-interval 30)
(setq mu4e-hide-index-messages t)
(setq mu4e-completing-read-function 'completing-read)
(setq mu4e-context-policy 'pick-first)
(setq mu4e-compose-context-policy 'ask)
(setq mu4e-view-auto-mark-as-read nil)
;; (setq mu4e-sent-messages-behavior 'sent)
;; (setq mu4e-sent-messages-behavior 'sent)
(setq message-kill-buffer-on-exit t)
(setq message-kill-buffer-on-exit t)
(require 'age)
(setq age-default-identity '("~/.local/credentials/personal"))
(setq age-default-recipient '("~/.local/credentials/personal.pub"))
(require 'age)
(setq age-default-identity '("~/.local/credentials/personal"))
(setq age-default-recipient '("~/.local/credentials/personal.pub"))
(setq auth-source-do-cache nil)
(setq auth-source-do-cache nil)
(defun joe/mu4e-auth-get-field (host prop)
(defun joe/mu4e-auth-get-field (host prop)
"Find PROP in `auth-sources' for HOST entry."
(when-let ((source (auth-source-search :host host)))
(if (eq prop :secret)
(funcall (plist-get (car source) prop))
(if (eq prop :secret)
(funcall (plist-get (car source) prop))
(plist-get (flatten-list source) prop))))
(setq auth-sources '("~/.local/credentials/authinfo.age"))
(setq auth-sources '("~/.local/credentials/authinfo.age"))
(setq mu4e-change-filenames-when-moving t)
(setq mu4e-change-filenames-when-moving t)
(age-file-enable)
(age-encryption-mode +1)
(setq mu4e-bookmarks nil)
(setq mu4e-contexts
(age-file-enable)
(age-encryption-mode +1)
(setq mu4e-bookmarks nil)
(setq mu4e-contexts
`(,(make-mu4e-context
:name "Ferano.io"
:enter-func (lambda () (mu4e-message "Entering ferano.io"))
:leave-func (lambda () (mu4e-message "Leaving ferano.io"))
:match-func (lambda (msg)
(when msg
(when msg
(mu4e-message-contact-field-matches
msg :to (joe/mu4e-auth-get-field "mail.gandi.net" :user))))
msg :to (joe/mu4e-auth-get-field "mail.gandi.net" :user))))
:vars `((user-mail-address . ,(joe/mu4e-auth-get-field "mail.gandi.net" :user))
(user-full-name . "Joseph Ferano")
(mu4e-drafts-folder . "/ferano.io/Drafts/")
(mu4e-trash-folder . "/ferano.io/Trash/")
(mu4e-sent-folder . "/ferano.io/Sent/")))
,(make-mu4e-context
:name "Gmail"
:enter-func (lambda () (mu4e-message "Entering gmail"))
:leave-func (lambda () (mu4e-message "Leaving gmail"))
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches
msg :to (joe/mu4e-auth-get-field "mail.gmail.com" :user))))
:vars `((user-mail-address . ,(joe/mu4e-auth-get-field "mail.gmail.com" :user))
(user-full-name . "Joseph Ferano")
(mu4e-drafts-folder . "/gmail/[Gmail]/Drafts/")
(mu4e-trash-folder . "/gmail/[Gmail]/Trash/")
(mu4e-sent-folder . "/gmail/[Gmail]/Sent Mail/")))))
(setq mu4e-maildir-shortcuts
,(make-mu4e-context
:name "Gmail"
:enter-func (lambda () (mu4e-message "Entering gmail"))
:leave-func (lambda () (mu4e-message "Leaving gmail"))
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches
msg :to (joe/mu4e-auth-get-field "mail.gmail.com" :user))))
:vars `((user-mail-address . ,(joe/mu4e-auth-get-field "mail.gmail.com" :user))
(user-full-name . "Joseph Ferano")
(mu4e-drafts-folder . "/gmail/[Gmail]/Drafts/")
(mu4e-trash-folder . "/gmail/[Gmail]/Trash/")
(mu4e-sent-folder . "/gmail/[Gmail]/Sent Mail/")
(smtpmail-default-smtp-server . "smtp.gmail.com")
(smtpmail-smtp-server . "smtp.gmail.com")
(smtpmail-stream-type . starttls)
(smtpmail-smtp-service . 587)))))
(setq mu4e-maildir-shortcuts
'((:maildir "/ferano.io/Inbox" :key ?f)
(:maildir "/gmail/[Gmail]/All Mail" :key ?g)))
(:maildir "/gmail/Inbox" :key ?g)))
(mu4e 't)
(add-hook 'after-init-hook #'mu4e-alert-enable-mode-line-display))
;; (:name "Ferano.io Unread" :query "m:/ferano.io/Inbox AND g:unread" :key ?u)))
(mu4e 't)
(add-hook 'after-init-hook #'mu4e-alert-enable-mode-line-display))
;; (:name "Ferano.io Unread" :query "m:/ferano.io/Inbox AND g:unread" :key ?u)))
#+end_src
Fold threads. This is a gist provided by Rougier [[https://gist.github.com/rougier/98e83fb50e19fb73fe34a7ecc5fc1ccc][here]]. His other package is
@ -2274,6 +2216,7 @@ These help speed eglot up apparently [[https://www.reddit.com/r/emacs/comments/1
;; All this changes because we are using eglot now
(when (boundp 'evil-mode)
(evil-global-set-key 'normal (kbd "M-d") #'lsp-ui-doc-glance)
(evil-global-set-key 'normal (kbd "M-D") #'lsp-describe-thing-at-point)
(evil-global-set-key 'normal (kbd "M-r") #'lsp-rename)
(evil-global-set-key 'insert (kbd "M-i") #'lsp-signature-activate)
(evil-global-set-key 'normal (kbd "gD") #'xref-find-definitions-other-window)
@ -2377,71 +2320,90 @@ These help speed eglot up apparently [[https://www.reddit.com/r/emacs/comments/1
#+begin_src emacs-lisp
(setq gptel-default-mode #'org-mode)
(setq
gptel-model 'claude-3-sonnet-20240229
gptel-model 'claude-sonnet-4-20250514
gptel-backend (gptel-make-anthropic "Claude"
:stream t :key (with-temp-buffer
(insert-file-contents (expand-file-name "gptel-key" user-emacs-directory))
(buffer-string))))
(add-hook 'gptel-post-response-functions #'font-lock-ensure)
(insert-file-contents (expand-file-name "gptel-key" user-emacs-directory))
(buffer-string))))
;; (add-hook 'gptel-post-response-functions #'font-lock-ensure)
(setq gptel-prompt-prefix-alist '((markdown-mode . "### ")
(org-mode . "* ")
(text-mode . "### ")))
(evil-define-key 'normal joe/evil-space-mode-map (kbd "SPC a a") #'gptel)
(evil-define-key 'normal joe/evil-space-mode-map (kbd "SPC a RET") #'gptel-ask)
(evil-define-key 'normal joe/evil-space-mode-map (kbd "SPC a M") #'gptel-mode)
(evil-define-key 'visual joe/evil-space-mode-map (kbd "SPC a c") #'gptel-add) ;; Will delete context at point
(evil-define-key 'normal joe/evil-space-mode-map (kbd "SPC a <backspace>") #'joe/gptel-context-remove-all)
(evil-define-key 'visual joe/evil-space-mode-map (kbd "SPC a r") #'gptel-rewrite)
(evil-define-key 'visual joe/evil-space-mode-map (kbd "SPC a RET") #'gptel-ask)
(evil-define-key 'visual joe/evil-space-mode-map (kbd "SPC a c") #'gptel-add)
#+end_src
This function was suggested by Karthink in order to fix an issue where gptel
org-mode was jumping back up to the top anytime the buffer was saved. Keeping it
around just in case.
gptel-context-remove-all without confirmation
#+begin_src emacs-lisp
(defun joe/gptel-context-remove-all (&optional verbose)
"Remove all gptel context. No confirmation."
(interactive (list t))
(if (null gptel-context--alist)
(message "No gptel context sources to remove.")
(cl-loop
for (source . ovs) in gptel-context--alist
if (bufferp source) do ;Buffers and buffer regions
(mapc #'gptel-context-remove ovs)
else do (gptel-context-remove source) ;files or other types
finally do (setq gptel-context--alist nil))))
#+end_src
gptel-ask command so I can ask LLMs about whatever I have in my region. Might be
nice to add some more functionality similar to gptel-quick, like dwim behavior
#+begin_src emacs-lisp
(defvar gptel-ask--history nil)
(defun gptel-ask (prompt)
(interactive
(list (read-string (format "Ask %s: " (gptel-backend-name gptel-backend)) nil 'gptel-ask--history)))
(when (string= prompt "") (user-error "A prompt is required."))
(let ((region-text (buffer-substring-no-properties (region-beginning) (region-end)))
(buffer-existed (get-buffer "*gptel-ask*"))
(buffer (get-buffer-create "*gptel-ask*")))
(with-current-buffer buffer
(unless buffer-existed
(org-mode)
(let ((map (copy-keymap (current-local-map))))
(evil-define-key 'nomal map "q" 'quit-window)
(use-local-map map)))
(erase-buffer)
(insert (format "* %s\n\n" prompt)))
(pop-to-buffer buffer)
(gptel-request
(concat prompt "\n\nRegion text:\n" region-text)
:system "You are an LLM living inside of Emacs. Answer questions concisely, no flattery"
:stream t
:callback
(lambda (response info)
(cond
((not response)
(message "gptel-ask failed with message: %s" (plist-get info :status)))
((stringp response)
(with-current-buffer (get-buffer "*gptel-ask*")
(let ((inhibit-read-only t))
(goto-char (point-max))
(insert response)))))))))
#+end_src
https://github.com/karthink/gptel/issues/199
#+begin_src emacs-lisp :tangle no
(defun gptel--save-state ()
"Write the gptel state to the buffer.
This saves chat metadata when writing the buffer to disk. To
restore a chat session, turn on `gptel-mode' after opening the
file."
(pcase major-mode
('org-mode
(org-with-wide-buffer
(goto-char (point-min))
(when (org-at-heading-p)
(org-open-line 1))
(org-entry-put (point-min) "GPTEL_MODEL" gptel-model)
(org-entry-put (point-min) "GPTEL_BACKEND" (gptel-backend-name gptel-backend))
(unless (equal (default-value 'gptel-temperature) gptel-temperature)
(org-entry-put (point-min) "GPTEL_TEMPERATURE"
(number-to-string gptel-temperature)))
(unless (string= (default-value 'gptel--system-message)
gptel--system-message)
(org-entry-put (point-min) "GPTEL_SYSTEM"
gptel--system-message))
(when gptel-max-tokens
(org-entry-put
(point-min) "GPTEL_MAX_TOKENS" gptel-max-tokens))
;; Save response boundaries
(letrec ((write-bounds
(lambda (attempts)
(let* ((bounds (gptel--get-bounds))
(offset (caar bounds))
(offset-marker (set-marker (make-marker) offset)))
(org-entry-put (point-min) "GPTEL_BOUNDS"
(prin1-to-string (gptel--get-bounds)))
(when (and (not (= (marker-position offset-marker) offset))
(> attempts 0))
(funcall write-bounds (1- attempts)))))))
(funcall write-bounds 6))))
(_ (save-excursion
(save-restriction
(add-file-local-variable 'gptel-model gptel-model)
(add-file-local-variable 'gptel--backend-name
(gptel-backend-name gptel-backend))
(unless (equal (default-value 'gptel-temperature) gptel-temperature)
(add-file-local-variable 'gptel-temperature gptel-temperature))
(unless (string= (default-value 'gptel--system-message)
gptel--system-message)
(add-file-local-variable 'gptel--system-message gptel--system-message))
(when gptel-max-tokens
(add-file-local-variable 'gptel-max-tokens gptel-max-tokens))
(add-file-local-variable 'gptel--bounds (gptel--get-bounds)))))))
;; Quick helper to cat the key
(with-temp-buffer
(insert-file-contents (expand-file-name "gptel-key" user-emacs-directory))
(clipboard-kill-region (point-min) (point-max)))
#+end_src
** Programming Languages
*** COMMENT treesitter
@ -2508,6 +2470,19 @@ And we do the rest here, including a macro
#+begin_src emacs-lisp
(setq sly-lisp-implementations '((sbcl ("/usr/local/bin/sbcl" "--dynamic-space-size" "4096"))
(ecl ("/usr/bin/ecl"))))
(defun joe/sly-copy-call-to-repl ()
"Copy name/symbol of toplevel sexp to sly-mREPL and select sly-mREPL."
(interactive)
(let (string
replwin)
(save-excursion
(beginning-of-defun)
(forward-thing 'symbol 2)
(setq string (format "(%s )" (thing-at-point 'symbol 'no-props))))
(setq replwin (get-buffer-window (call-interactively #'sly-mrepl)))
(with-selected-window replwin
(insert string)
(forward-char -1))))
#+end_src
*** Odin
#+begin_src emacs-lisp
@ -2521,7 +2496,7 @@ And we do the rest here, including a macro
:server-id 'ols
:multi-root t))) ;; Ensures lsp-mode sends "workspaceFolders" to the server
(add-hook 'odin-mode-hook #'lsp)
;; (add-hook 'odin-mode-hook #'lsp)
(defun joe/odin-mode-hook ()
(electric-pair-local-mode))
@ -2536,14 +2511,26 @@ whether the point hasn't been moved. This way, if I switched to another popper b
it doesn't close it.
#+begin_src emacs-lisp
(require 'disaster)
(setq c-default-style "bsd")
(defun joe/c-mode-hook ()
(local-set-key (kbd "C-x c r") (defun joe/make-run () (interactive) (compile "make run")))
(local-set-key (kbd "C-x c c") (defun joe/make () (interactive) (compile "make")))
(electric-pair-local-mode t)
(c-toggle-comment-style -1))
(add-hook 'c-mode-hook #'joe/c-mode-hook)
(require 'disaster)
(defun joe/disaster (arg)
(interactive "P")
(if arg
(let ((disaster-cflags (concat disaster-cflags " -O2")))
(disaster))
(disaster)))
(defun joe/c-mode-hook ()
(setq c-default-style "bsd")
(define-key c-mode-map (kbd "C-c d") #'joe/disaster)
(local-set-key (kbd "C-x c r") (defun joe/make-run () (interactive) (compile "make run")))
(local-set-key (kbd "C-x c c") (defun joe/make () (interactive) (compile "make")))
(electric-pair-local-mode t)
(c-toggle-comment-style -1))
(with-eval-after-load 'cc-mode
(add-hook 'c-mode-hook #'joe/c-mode-hook))
#+end_src
*** Python
#+begin_src emacs-lisp
@ -2557,9 +2544,9 @@ it doesn't close it.
#+end_src
*** Rust
#+begin_src emacs-lisp
(setq rustic-lsp-setup-p nil)
(require 'rustic)
(require 'ob-rust)
;; (setq rustic-lsp-setup-p nil)
;; (require 'rustic)
;; (require 'ob-rust)
;; Org-Babel
;; Disabling until we figure out how to get it working
;; (elpaca 'parsec) ;; Required by evcxr-mode
@ -2570,10 +2557,21 @@ it doesn't close it.
;; :host github
;; :repo "serialdev/evcxr-mode"))
(defun joe/save-then-rustic-cargo-check ()
"Save the buffer before recompiling"
(interactive)
(when (buffer-file-name)
(save-buffer))
(rustic-cargo-check))
(add-hook 'rust-mode-hook
(lambda ()
;; (evcxr-minor-mode)
(electric-pair-local-mode)))
(electric-pair-local-mode)
(yas-minor-mode)
(define-key rustic-mode-map (kbd "<f9>") #'joe/save-then-rustic-cargo-check)
(define-key rustic-cargo-run-mode-map (kbd "<f9>") #'joe/save-then-rustic-cargo-check)
(define-key rustic-mode-map (kbd "<f8>") #'joe/save-then-recompile)))
;; (with-eval-after-load 'rustic
;; ;; Don't autostart
@ -2722,11 +2720,11 @@ and there's no need for a middle-man when it's already been implemented.
(evil-define-key 'insert haskell-interactive-mode-map (kbd "C-p") #'haskell-interactive-mode-history-previous)
#+end_src
*** COMMENT Clojure
*** Clojure
#+begin_src emacs-lisp
(require 'clojure-mode)
(require 'cider)
(setq cider-show-error-buffer 'only-in-repl)
;; (setq cider-show-error-buffer 'only-in-repl)
#+end_src
*** COMMENT FSharp
#+begin_src emacs-lisp
@ -3005,20 +3003,25 @@ Org mode buffers have associated files.
(ocaml . t)
(python . t)
(C . t)
(lisp . t)
(haskell . t)
;; (rust . t)
(rust . t)
(clojure . t)
(shell . t)))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("cl" . "src common-lisp"))
(add-to-list 'org-structure-template-alist '("ml" . "src ocaml"))
(add-to-list 'org-structure-template-alist '("rs" . "src rust"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(add-to-list 'org-structure-template-alist '("hs" . "src haskell"))
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("cs" . "src csharp"))
(add-to-list 'org-structure-template-alist '("clj" . "src clojure"))
(add-to-list 'org-structure-template-alist '("cc" . "src C :includes stdio.h stdlib.h"))
(setq org-edit-src-content-indentation 0)
(setq org-src-window-setup 'current-window)
(setq org-babel-lisp-eval-fn 'sly-eval)
#+end_src
@ -3043,7 +3046,7 @@ with the cursor you hit TAB and you complete the following;
(define-key global-map (kbd "C-c t a") #'org-transclusion-add)
(define-key global-map (kbd "C-c t r") #'org-transclusion-remove)
#+end_src
*** org-roam
*** COMMENT org-roam
#+begin_src emacs-lisp
(require 'org-roam)
(setq org-roam-directory "/home/joe/Notes/Roam/")
@ -3085,8 +3088,7 @@ with the cursor you hit TAB and you complete the following;
#+end_src
** Magit
The best git porcelain/client I've ever used. Also kill stray magit buffers left
over as explained [[https://manueluberti.eu/2018/02/17/magit-bury-buffer.html][here]]
The best git porcelain/client I've ever used. Also kill stray magit buffers left over as explained [[https://manueluberti.eu/2018/02/17/magit-bury-buffer.html][here]]
#+begin_src emacs-lisp
(require 'magit)
@ -3098,7 +3100,7 @@ over as explained [[https://manueluberti.eu/2018/02/17/magit-bury-buffer.html][h
(mapc #'kill-buffer buffers)))
(when (boundp 'evil-mode)
(add-hook 'with-editor-mode-hook 'evil-insert-state))
(add-hook 'with-editor-mode-hook 'evil-insert-state))
(setq magit-bury-buffer-function #'joe/magit-kill-buffers)
(setq magit-clone-set-remote.pushDefault t)
@ -3119,7 +3121,7 @@ over as explained [[https://manueluberti.eu/2018/02/17/magit-bury-buffer.html][h
** Restclient
#+begin_src emacs-lisp
(require 'restclient)
;; (require 'restclient)
(add-to-list 'auto-mode-alist '("\\.restclient\\'" . restclient-mode))

View File

@ -15,16 +15,20 @@ complete -f -c exercism -n "__fish_seen_subcommand_from download" -s u -l uuid -
# Help
complete -f -c exercism -n "__fish_use_subcommand" -a "help" -d "Shows a list of commands or help for one command"
complete -f -c exercism -n "__fish_seen_subcommand_from help" -a "configure download help open submit troubleshoot upgrade version workspace"
complete -f -c exercism -n "__fish_seen_subcommand_from help" -a "configure download help open submit test troubleshoot upgrade version workspace"
# Open
complete -f -c exercism -n "__fish_use_subcommand" -a "open" -d "Opens a browser to exercism.io for the specified submission."
complete -f -c exercism -n "__fish_use_subcommand" -a "open" -d "Opens a browser to exercism.org for the specified submission."
complete -f -c exercism -n "__fish_seen_subcommand_from open" -s h -l help -d "help for open"
# Submit
complete -f -c exercism -n "__fish_use_subcommand" -a "submit" -d "Submits a new iteration to a problem on exercism.io."
complete -f -c exercism -n "__fish_use_subcommand" -a "submit" -d "Submits a new iteration to a problem on exercism.org."
complete -f -c exercism -n "__fish_seen_subcommand_from submit" -s h -l help -d "help for submit"
# Test
complete -f -c exercism -n "__fish_use_subcommand" -a "test" -d "Run the exercise's tests."
complete -f -c exercism -n "__fish_seen_subcommand_from submit" -s h -l help -d "help for test"
# Troubleshoot
complete -f -c exercism -n "__fish_use_subcommand" -a "troubleshoot" -d "Outputs useful debug information."
complete -f -c exercism -n "__fish_seen_subcommand_from troubleshoot" -s f -l full-api-key -d "display full API key (censored by default)"

View File

@ -1,9 +1,12 @@
# This file contains fish universal variable definitions.
# VERSION: 3.0
SETUVAR --export ANDROID_AVD_HOME:/home/joe/\x2econfig/\x2eandroid/avd
SETUVAR --export ANDROID_HOME:/home/joe/Android/Sdk/
SETUVAR --export CARGO_HOME:/home/joe/\x2elocal/share/bin/cargo/
SETUVAR EDITOR:hx
SETUVAR --export LC_COLLATE:C
SETUVAR --export --path LD_LIBRARY_PATH:/usr/local/lib
SETUVAR --export NDK_HOME:/home/joe/Android/Sdk/ndk/29\x2e0\x2e13599879/
SETUVAR --export PYTHONSTARTUP:/etc/python/pythonrc
SETUVAR --export RUSTUP_HOME:/home/joe/\x2elocal/share/rustup/
SETUVAR SSH_AUTH_SOCK:/run/user/1000/ssh\x2dagent\x2esocket
@ -44,4 +47,4 @@ SETUVAR fish_pager_color_description:B3A06D\x1eyellow
SETUVAR fish_pager_color_prefix:normal\x1e\x2d\x2dbold\x1e\x2d\x2dunderline
SETUVAR fish_pager_color_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan
SETUVAR fish_pager_color_selected_background:\x2dr
SETUVAR --export fish_user_paths:/home/joe/\x2edotnet/tools\x1e/home/joe/Repositories/emsdk\x1e/home/joe/Repositories/emsdk/node/18\x2e20\x2e3_64bit/bin\x1e/home/joe/Repositories/emsdk/upstream/emscripten\x1e/home/joe/\x2elocal/bin/odin\x1e/home/joe/\x2elocal/scripts\x1e/home/joe/\x2elocal/opt/JetBrains\x20Rider\x2d2024\x2e1\x2e4/bin\x1e/home/joe/\x2elocal/share/bin/fasm\x1e/home/joe/\x2elocal/share/bin/zig\x1e/home/joe/\x2elocal/share/bin/cargo/bin\x1e/home/joe/\x2elocal/bin\x1e/home/joe/\x2enimble/bin
SETUVAR --export fish_user_paths:/home/joe/Android/Sdk/build\x2dtools\x1e/home/joe/Android/Sdk/emulator\x1e/home/joe/Android/Sdk/cmdline\x2dtools/latest/bin\x1e/home/joe/\x2elocal/android\x2dstudio/bin\x1e/home/joe/\x2edotnet/tools\x1e/home/joe/Repositories/emsdk\x1e/home/joe/Repositories/emsdk/node/18\x2e20\x2e3_64bit/bin\x1e/home/joe/Repositories/emsdk/upstream/emscripten\x1e/home/joe/\x2elocal/bin/odin\x1e/home/joe/\x2elocal/scripts\x1e/home/joe/\x2elocal/opt/JetBrains\x20Rider\x2d2024\x2e1\x2e4/bin\x1e/home/joe/\x2elocal/share/bin/fasm\x1e/home/joe/\x2elocal/share/bin/zig\x1e/home/joe/\x2elocal/share/bin/cargo/bin\x1e/home/joe/\x2elocal/bin\x1e/home/joe/\x2enimble/bin

View File

@ -56,7 +56,8 @@ map kitty_mod+j neighboring_window down
map kitty_mod+k neighboring_window up
map kitty_mod+l neighboring_window right
map ctrl+y paste_from_clipboard
map alt+y paste_from_clipboard
map alt+c copy_to_clipboard
map kitty_mod+p previous_tab
map kitty_mod+n next_tab

View File

@ -24,16 +24,6 @@ Remove Both
Expunge Both
SyncState *
Channel ferano.io.inbox
Far :ferano.io.remote:
Near :ferano.io.local:
Patterns INBOX
Sync All
Create Both
Remove Both
Expunge Both
SyncState *
IMAPAccount gmail
Host imap.gmail.com
UserCmd "age --decrypt -i ~/.local/credentials/personal ~/.local/credentials/authinfo.age | awk -F ' ' '/mail.gmail.com/ { print $(NF-2);exit; }'"
@ -45,35 +35,14 @@ Account gmail
MaildirStore gmail.local
Subfolders Verbatim
# The trailing "/" is important
Path ~/.mail/gmail/
Inbox ~/.mail/gmail/Inbox
Inbox ~/.mail/gmail/INBOX
Channel gmail
Far :gmail.remote:
Near :gmail.local:
# Include everything
Patterns *
Sync All
Create Both
Remove Both
Expunge Both
SyncState *
Channel gmail.inbox
Far :gmail.remote:
Near :gmail.local:
Patterns INBOX
Sync All
Create Both
Remove Both
Expunge Both
SyncState *
Channel gmail.allmail
Far :gmail.remote:
Near :gmail.local:
Patterns *All*
# Only sync the folders you've checked in IMAP
Patterns "INBOX" "[Gmail]/Sent Mail" "[Gmail]/Drafts" "[Gmail]/Trash"
Sync All
Create Both
Remove Both

View File

@ -131,6 +131,7 @@ keys = [
Key([mod], "w", lazy.next_layout(), desc="Toggle between layouts"),
Key([mod, "control"], "w", lazy.function(get_current_window_info), desc="Get window info"),
Key([mod], "s", lazy.spawn("flameshot gui"), desc="Flameshot screenshot"),
Key([mod], "m", lazy.spawn("/home/joe/.local/scripts/trackball.sh", shell=True)),
# TODO: Figure out another binding for this
# Key([mod], "n", lazy.layout.normalize(), desc="Reset all window sizes"),
@ -257,11 +258,10 @@ groups[0].label = '🎵'
# groups.insert(0, Group('1', screen_affinity=0, label='🎵'))
# This likely won't work when we only have 1 monitor
def go_to_group(name: str) -> Callable:
def _inner(qtile) -> None:
if num_monitors > 1:
if name == '1':
if name == '0':
qtile.focus_screen(0)
else:
qtile.focus_screen(1)

View File

@ -0,0 +1,20 @@
#!/bin/bash
curr_network=$(nmcli device wifi | rg "^\*" | awk '{print $3}')
if [ -z "$curr_network" ]; then
echo "Looks like we're not connected to any network"
exit 1
fi
path_to_net_conns="/etc/NetworkManager/system-connections"
fullpath="${path_to_net_conns}/${curr_network}.nmconnection"
if [ ! -f "$fullpath" ]; then
echo "Could not find this wifi's Network Manager entry"
exit 1
fi
password=$(sudo cat $fullpath | rg "^psk" | cut -d "=" -f 2)
echo Name: \ \ \ $curr_network
echo Password: $password

13
.local/scripts/trackball.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# Set mouse buttons for elecom
# 3 = 9 (forward)
# 8 = 3 (right click)
# 9 = 2 (middle click)
# 10 = 8 (back)
dev_id=$(xinput | rg "slave\s+pointer" | rg ELECOM | rg -o "id=(\d+)" -r '$1')
if [ -n "$dev_id" ]; then
xinput set-button-map $dev_id 1 2 9 4 5 6 7 2 3 8
echo "Button mapping applied" >> /tmp/trackball.log
else
echo "No device found" >> /tmp/trackball.log
fi