;;; init.el --- Welcome to my Emacs configuration! -*- lexical-binding: t; -*- ;; Copyright (C) 2023 Thanos Apollo ;; Author: Thanos Apollo ;; Keywords: extensions ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; ╭━━━━┳╮╱╱╱╱╱╱╱╱╱╱╱╱╱╱╭━━━╮╱╱╱╱╱╭╮╭╮╱╱╱╱╱╱╱╱╭━━━╮ ;; ┃╭╮╭╮┃┃╱╱╱╱╱╱╱╱╱╱╱╱╱╱┃╭━╮┃╱╱╱╱╱┃┃┃┃╱╱╱╱╱╱╱╱┃╭━━╯ ;; ╰╯┃┃╰┫╰━┳━━┳━╮╭━━┳━━╮┃┃╱┃┣━━┳━━┫┃┃┃╭━━╮╱╱╱╱┃╰━━┳╮╭┳━━┳━━┳━━╮ ;; ╱╱┃┃╱┃╭╮┃╭╮┃╭╮┫╭╮┃━━┫┃╰━╯┃╭╮┃╭╮┃┃┃┃┃╭╮┃╭━━╮┃╭━━┫╰╯┃╭╮┃╭━┫━━┫ ;; ╱╱┃┃╱┃┃┃┃╭╮┃┃┃┃╰╯┣━━┃┃╭━╮┃╰╯┃╰╯┃╰┫╰┫╰╯┃╰━━╯┃╰━━┫┃┃┃╭╮┃╰━╋━━┃ ;; ╱╱╰╯╱╰╯╰┻╯╰┻╯╰┻━━┻━━╯╰╯╱╰┫╭━┻━━┻━┻━┻━━╯╱╱╱╱╰━━━┻┻┻┻╯╰┻━━┻━━╯ ;; ╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱┃┃ ;; ╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╰╯ ;;; Code: (setf user-full-name "Thanos Apollo" user-mail-address "public@thanosapollo.org") (defvar is-zeus (equal (system-name) "zeus")) (defvar is-hermes (equal (system-name) "hermes")) (defvar is-phone (equal (system-name) "localhost")) (setf browse-url-browser-function 'browse-url-generic browse-url-generic-program "firefox" backup-directory-alist '((".*" . "~/.Trash")) sentence-end-double-space nil default-input-method "greek") (define-key global-map (kbd "") 'keyboard-escape-quit) (define-key global-map (kbd "M-") 'backward-kill-sexp) (add-to-list 'load-path "~/.emacs.d/modules") (setf disabled-command-function nil ;; Enable all commands url-privacy-level 'high) ;; Privacy level ;; Set and load custom.el (setf custom-file (locate-user-emacs-file "custom.el")) (load custom-file 'noerror) ;; Enable use-package support for imenu (setf use-package-enable-imenu-support t) ;; Install straight.el (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" (or (bound-and-true-p straight-base-dir) user-emacs-directory))) (bootstrap-version 7)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) (setq package-enable-at-startup nil) (require 'straight) (setf straight-use-package-by-default t) (setf straight-recipe-overrides '((transmission :type git :host nil :repo "git@thanosapollo.org:/var/git/transmission") (yeetube :type git :host nil :repo "git@thanosapollo.org:/var/git/yeetube"))) (defvar thanos/custom-packages '((yeetube :local-repo "~/Dev/emacs-lisp/yeetube") (gnosis :local-repo "~/Dev/emacs-lisp/gnosis") (copilot :host github :repo "zerolfx/copilot.el" :files ("dist" "*.el"))) "Custom package recipes.") (defun theme-invisible-dividers (_theme) "Make window dividers for THEME invisible." (let ((bg (face-background 'default))) (custom-set-faces `(fringe ((t :background ,bg :foreground ,bg))) `(window-divider ((t :background ,bg :foreground ,bg))) `(window-divider-first-pixel ((t :background ,bg :foreground ,bg))) `(window-divider-last-pixel ((t :background ,bg :foreground ,bg)))))) (add-hook 'enable-theme-functions #'theme-invisible-dividers) ;;;; Theming ;;;; (setf inhibit-startup-message t initial-scratch-message nil) (blink-cursor-mode -1) (menu-bar--visual-line-mode-enable) (global-visual-line-mode 1) (setf visible-bell t) (column-number-mode) (global-display-line-numbers-mode 1) (menu-bar--display-line-numbers-mode-relative) ;; Transparency (add-to-list 'default-frame-alist '(alpha-background . 90)) (when (equal is-phone nil) (scroll-bar-mode -1) (set-fringe-mode 10)) (tool-bar-mode -1) (tooltip-mode -1) (menu-bar-mode -1) (global-hl-line-mode) (use-package modus-themes :straight t :config (setf modus-themes-italic-constructs t modus-themes-bold-constructs nil modus-themes-mixed-fonts nil modus-themes-variable-pitch-ui nil modus-themes-custom-auto-reload t modus-themes-disable-other-themes t modus-themes-prompts '(italic bold) modus-themes-completions '((matches . (extrabold)) (selection . (semibold italic text-also underline))) modus-themes-org-blocks 'tinted-background) ;; Palette overrides (setf modus-themes-common-palette-overrides '((fg-line-number-inactive "gray40") (fg-line-number-active cyan-intense) (bg-main "#171717") ;; (overline-heading-1 gold) (fg-heading-1 red-warmer) ;; (bg-heading-1 bg-blue-nuanced) (bg-line-number-inactive unspecified) (bg-line-number-active unspecified) (bg-paren-match bg-magenta-intense) (underline-paren-match fg-main) (underline-err red-intense) (underline-warning yellow-faint) (underline-note cyan-faint) (string "#86B187") (border-mode-line-active unspecified) (border-mode-line-inactive unspecified) (bg-mode-line-active "#2f2f2f") (bg-mode-line-inactive "1D1D1D") ;; set fg from badger theme (fg-mode-line-active "#F6F3E8") (bg-hl-line bg-dim) (cursor slate) (fg-prompt yellow-faint) ,@modus-themes-preset-overrides-intense)) ;; Headings (setf modus-themes-headings '((1 . (ultrabold 1.35)) (2 . (semibold 1.2)) (agenda-date . (1.3)) (agenda-structure . (variable-pitch light 1.8)) (t . (1.15)))) ;; Load modus (load-theme 'modus-vivendi t)) (use-package vertico :ensure t :config (vertico-mode)) (use-package nerd-icons-completion :ensure t :config (nerd-icons-completion-marginalia-setup) (nerd-icons-completion-mode)) (use-package marginalia :defer t :hook (marginalia-mode . nerd-icons-completion-mode) :config (marginalia-mode)) (use-package nerd-icons-ibuffer :defer t :hook ((ibuffer-mod))) (use-package consult :defer t :bind (("C-x b" . 'consult-buffer) ("C-c m" . 'consult-imenu))) (use-package org :defer t :config (setf org-directory "~/org/" org-agenda-files '("~/org/agenda.org") org-default-notes-file (expand-file-name "notes.org" org-directory) org-ellipsis " ▼ " org-log-done 'time org-hide-emphasis-markers nil ;;change to t to hide emphasis markers org-table-convert-region-max-lines 20000 org-log-done 'time org-todo-keywords '((sequence "TODO(t)" "SEMINAR(s)" "LECTURE(l)" "DONE(d)"))) (defadvice org-edit-src-code (around set-buffer-file-name activate compile) (let ((file-name (buffer-file-name))) ad-do-it (setf buffer-file-name file-name))) (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (python . t))) (setf org-structure-template-alist '(("e" . "src emacs-lisp") ("p" . "src python") ("l" . "src lisp") ("b" . "src bash") ("q" . "QUOTE"))) :hook ((org-mode . org-auto-tangle-mode) (org-mode . (lambda () (display-line-numbers-mode -1))))) (defun org-insert-book () "Insert org-link from ~/Library for book." (interactive) (let* ((book-path (read-file-name "Book: " "~/Library/"))) (org-insert-link nil book-path (file-name-base book-path)))) (use-package org-modern :ensure t :config (global-org-modern-mode) (setf org-modern-table nil) (setf org-modern-todo nil)) ;; Create notes directory for org-roam (unless (file-exists-p "~/Notes") (make-directory "~/Notes")) (use-package org-roam :defer t :init (define-prefix-command 'thanos/notes-map) :config (setf org-roam-directory "~/Notes") (org-roam-db-autosync-enable) (setf org-roam-node-display-template (concat "${title:50} "(propertize "${tags:30}" 'face 'org-tag))) (setf org-roam-db-node-include-function (lambda () (not (or (member "journal" (org-get-tags)) (member "memorize" (org-get-tags)))))) ;; Templaes (setf org-roam-capture-templates '(("d" "default" plain "%?" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("l" "programming language" plain "* Characteristics\n\n- Family: %?\n- Inspired by: \n\n* Reference:\n\n" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("p" "MUS" plain "* Goals\n\n%?\n\n* Tasks\n\n** TODO Add initial tasks\n\n* Dates\n\n" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: MUS") :unnarrowed t))) :bind (("C-c n" . thanos/notes-map) :map thanos/notes-map ("t" . org-roam-buffer-toggle) ("f" . org-roam-node-find) ("i" . org-roam-node-insert) :map org-mode-map ("C-c C-." . org-roam-tag-add) ("C-c i" . org-id-get-create))) (use-package which-key :defer t :config (which-key-mode 1)) (defun elfeed-mpv (&optional use-generic-p) "Play video link with mpv." (interactive "P") (let ((entries (elfeed-search-selected))) (cl-loop for entry in entries do (elfeed-untag entry 'unread) when (elfeed-entry-link entry) do (start-process-shell-command "elfeed-video" nil (format "mpv \"%s\"" it))) (mapc #'elfeed-search-update-entry entries) (unless (use-region-p) (forward-line)))) (use-package elfeed :defer t :config (setf elfeed-search-filter "@1-week-ago +unread" browse-url-browser-function #'browse-url-default-browser) ;; Feeds (setf elfeed-feeds '(("https://hackaday.com/blog/feed/" hackaday linux) ("https://protesilaos.com/news.xml" protesilaos) ("https://protesilaos.com/codelog.xml" proetesilaos) ("https://guix.gnu.org/feeds/blog.atom" gnu guix) ("https://thanosapollo.com/posts/index.xml" thanos) ("http://nullprogram.com/feed/" emacs linux) ("https://drewdevault.com/blog/index.xml" sourcehut drewdevault) ("https://archlinux.org/feeds/news/" ArchLinux Latest) ("http://wikileaks.org/feed" wikileaks) ("https://hackernoon.com/feed" hackernoon) ("https://sachachua.com/blog/feed/" sacha emacs) ("https://bits.debian.org/feeds/feed.rss" debian linux) ("https://torrentfreak.com/feed" torrentfreak piracy) ("https://wp.medscape.com/cx/rssfeeds/2700.xml" med medscape) ("https://www.science.org/action/showFeed?type=etoc&feed=rss&jc=sciimmunol" science) ("https://www.who.int/rss-feeds/news-english.xml" who medicine) ("https://annas-blog.org/rss.xml" anna piracy) ("https://www.addtoany.com/add_to/feed?linkurl=http%3A%2F%2Fwww.thelancet.com%2Frssfeed%2Flancet_online.xml&type=feed&linkname=The%20Lancet%20Online%20First&linknote=" lancet medicine) ("https://www.addtoany.com/add_to/feed?linkurl=http%3A%2F%2Fwww.thelancet.com%2Frssfeed%2Flanhae_online.xml&type=feed&linkname=The%20Lancet%20Haematology%20Online%20First&linknote=" lancet haematology medicine) ("https://totsipaki.net/ikiwiki/nparafe/%CE%9C%CF%80%CE%BB%CE%BF%CE%B3%CE%BA/index.rss" nikos fsf))) :bind (("C-c a f" . elfeed) :map elfeed-search-mode-map ("v" . 'elfeed-mpv) ("U" . 'elfeed-update))) (use-package elfeed-goodies :defer t :config (setf elfeed-goodies/entry-pane-size 0.55) (elfeed-goodies/setup)) (use-package python-mode :defer t :config (add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))) (use-package emms :defer t :config (with-eval-after-load 'emms (emms-all) (setq emms-source-file-default-directory "~/Music" emms-info-asynchronously t emms-show-format "♪ %s") (emms-default-players)) (setf emms-player-mpv-parameters '("--quiet" "--really-quiet" "--no-audio-display" "--no-video")) :bind (:map emms-playlist-mode-map (("A" . 'emms-add-directory-tree)))) (use-package rainbow-delimiters :defer t :init (add-hook 'emacs-lisp-mode-hook 'prettify-symbols-mode) :hook ((emacs-lisp-mode . rainbow-delimiters-mode) (lisp-mode . rainbow-delimiters-mode) (scheme-mode . rainbow-delimiters-mode))) (use-package helpful :defer t :bind (("C-h f" . 'helpful-callable) ("C-h v" . 'helpful-variable) ("C-h k" . 'helpful-key) ("C-h x" . 'helpful-command) ("C-h ." . 'helpful-at-point) ("C-h F" . 'helpful-function) ("C-h C-k" . 'helpful-kill-buffers))) (use-package password-store :defer t) (use-package ox-hugo :ensure t) (use-package json-mode :defer t :config (add-to-list 'auto-mode-alist '("\\.json'" . json-mode))) (defun project-magit () "Run magit-status in the current project's root." (interactive) (magit-status-setup-buffer (project-root (project-current t)))) (use-package magit :defer t :config (setf magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1) :bind (:map project-prefix-map ("g" . 'project-magit))) (use-package corfu :ensure t :init (define-prefix-command 'thanos/search) :config (global-corfu-mode) (corfu-popupinfo-mode) (setf corfu-auto t corfu-auto-delay 0.1 corfu-auto-prefix 2 corfu-cycle t corfu-popupinfo-delay 0.3 corfu-quit-at-boundary 'separator corfu-quit-no-match t corfu-preselect 'first corfu-preview-current t corfu-echo-mode t) (setf indent-tabs-mode nil) :bind (("C-x r d" . 'bookmark-delete) ("C-x r C-r" . 'bookmark-rename) ("C-x r ." . 'consult-register) ("C-x r s" . 'consult-register-store) ("C-x r b" . 'consult-bookmark) ("M-y" . 'consult-yank-from-kill-ring) ("C-s" . 'thanos/search) :map thanos/search ("f" . 'isearch-forward) ("b" . 'isearch-backward) ("s" . 'consult-line) ("C-f" . 'consult-find) ("C-g" . 'consult-grep) ("C-i" . 'consult-info) ("C-l" . 'consult-locate) :map project-prefix-map ("b" . 'consult-project-buffer))) (defun insert-brackets (&optional arg) "Insert ARG brackets." (interactive "P") (insert-pair arg ?\[ ?\])) (global-set-key (kbd "C-x M-[") 'insert-brackets) (use-package orderless :init (add-to-list 'completion-styles 'initials t) :ensure t :config (setf completion-category-overrides '((file (style basic partial-completion))) completion-styles '(orderless) completion-cycle-threshold 2)) (use-package pdf-tools :ensure t :config (pdf-tools-install) (add-to-list 'auto-mode-alist '("\\.pdf\\'" . 'pdf-view-mode)) :hook ((pdf-view-mode . 'pdf-isearch-minor-mode) (pdf-view-mode . 'pdf-view-midnight-minor-mode))) (use-package markdown-mode :defer t :config (setq markdown-header-scaling t markdown-command "multimarkdown") (add-to-list 'auto-mode-alist '("\\.md\\'" . gfm-mode))) (use-package eat :defer t) (use-package org-auto-tangle :defer t) (use-package sly :init (setf inferior-lisp-program "sbcl") :defer) (use-package nov :defer t :config (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))) (use-package eshell-syntax-highlighting :defer t) (use-package emojify :ensure t :config (global-emojify-mode) (global-emojify-mode-line-mode)) (use-package flycheck :ensure t :config (setf flycheck-emacs-lisp-load-path 'inherit) :hook ((org-src-mode . (lambda () (flycheck-disable-checker 'emacs-lisp-checkdoc))))) ;; Shells (use-package vterm :defer t :bind (("C-c v" . vterm) :map vterm-mode-map ("M-&" . 'async-shell-command)) :hook ((vterm-mode . (lambda () (display-line-numbers-mode -1))))) (defvar thanos/aliases '((g . magit) (gl . magit-log) (gc . magit-clone) (d . dired) (o . find-file) (oo . find-file-other-window) (ll . (lambda () (eshell/ls '-lha))) (eshell/clear . eshell/clear-scrollback))) (defun thanos/set-eshell-aliases (aliases) "Set ALIASES as eshell aliases." (mapc (lambda (alias) (defalias (car alias) (cdr alias))) aliases)) (use-package eshell :config (setf eshell-highlight-prompt t) (eshell-syntax-highlighting-global-mode 1) :bind (("C-c e" . eshell)) :hook ((eshell-mode . (lambda () (hl-line-mode 'toggle) (thanos/set-eshell-aliases thanos/aliases) (display-line-numbers-mode -1))))) (use-package eshell-git-prompt :straight '(eshell-git-prompt :type git :host nil :repo "https://git.thanosapollo.org/eshell-git-prompt") :config (eshell-git-prompt-use-theme 'multiline)) ;; Chat (use-package telega :defer t :hook ((telega-root-mode . (lambda () emojify-mode (display-line-numbers-mode -1))) (telega-chat-mode . (lambda () (emojify-mode) (display-line-numbers-mode -1))))) (use-package erc :defer t :config (setf erc-modules '(sasl netsplit fill button match track completion readonly networks ring autojoin noncommands irccontrols move-to-prompt stamp menu list))) (defun erc-libera () "Login to liberachat with erc." (interactive) (erc-tls :server "irc.libera.chat" :port 6697 :nick "thanosapollo" :user "thanosapollo" :password (password-store-get "liberachat/thanos_apollo"))) (use-package transmission :defer t :straight (transmission :type git :host nil :repo "git@thanosapollo.org:/var/git/transmission")) (use-package nerd-icons-dired :defer t :hook ((dired-mode . nerd-icons-dired-mode))) (use-package sudo-edit :defer t :config (setf sudo-edit-local-method "doas")) (use-package jinx :defer t :bind (:map jinx-mode-map (("M-'" . jinx-correct))) :hook ((org-mode . jinx-mode))) (defun dired-watch-video () "Watch play file with mpv." (interactive) (call-process-shell-command (format "mpv \"%s\"" (dired-get-filename)) nil 0)) (defun dired-set-wallpaper () "Set NAME as wallpaper using feh." (interactive) (call-process-shell-command (format "feh --bg-scale %s" (dired-get-filename)) nil 0)) (defun dired-delete-files-except () "Delete all files inside directory except match." (interactive) (let* ((directory (read-directory-name "Select directory: ")) (files (directory-files directory t)) (except-match (read-string "Except the ones that have: "))) (dolist (file files) (unless (or (string= "." (substring file -1)) (string= ".." (substring file -2)) (string-match except-match file)) (dired-delete-file file t))))) (defun dired-delete-file-match () "Delete all files inside directory except match." (interactive) (let* ((directory (read-directory-name "Select directory: ")) (files (directory-files directory t)) (match (read-string "Delete files that match: "))) (dolist (file files) (when (string-match-p match file) (dired-delete-file file t))))) (defun dired-rename-capitalize-file () "Capitalize the base name of the file at point in a Dired buffer." (interactive) (let* ((file (dired-get-file-for-visit)) (new-file (capitalize (file-name-nondirectory file)))) (if (string-prefix-p "." file) (message "Skipping file starting with '.'") (progn (rename-file file (concat (file-name-directory file) new-file)) (revert-buffer) (message "Renamed %s to %s" file new-file))))) (use-package term :bind (("C-c t" . term) :map term-mode-map ("M-p" . term-send-up) ("M-n" . term-send-down) :map term-raw-map ("M-o" . other-window) ("M-p" . term-send-up) ("M-n" . term-send-down))) (use-package emacs :ensure t :init (require 'dired) :bind (("C-x C-b" . 'ibuffer) ("M-." . 'xref-find-definitions) ("C-c L" . 'display-line-numbers) :map dired-mode-map (("b" . 'dired-up-directory) ("v" . 'dired-watch-video) ("z" . 'wdired-change-to-wdired-mode) ("C-c w" . 'dired-set-wallpaper) ("C-c d" . 'dired-delete-files-except))) :config (custom-set-faces (if is-hermes '(default ((t (:inherit nil :height 120 :family "Jetbrains Mono")))) '(default ((t (:inherit nil :height 130 :family "Jetbrains Mono")))))) ;; Don't display battery-mode on desktop (if is-zeus (display-battery-mode 0) (display-battery-mode 1)) (savehist-mode) (save-place-mode 1) (recentf-mode 1) (electric-pair-mode 1) ;; Autoinsert (auto-insert-mode 1) (define-auto-insert '("\\.sh\\'" . "Bash skeleton") '("Description:" "#!/bin/bash\n\n")) (add-to-list 'completion-styles 'initials t) (setf tab-always-indent 'complete) ;; tramp (setf tramp-default-method "ssh") ;; xref (setf xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref) ;; dabbrev :hook ((ibuffer-mode . 'nerd-icons-ibuffer-mode) (shell-script-mode . 'auto-insert))) (use-package dabbrev :defer t :config (setf dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'"))) (use-package xref :defer t :config (setf xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref)) ;; (use-package tramp ;; :ensure t ;; :init (setf tramp-default-method "ssh")) ;; My packages (use-package yeetube :init (define-prefix-command 'thanos/yeetube-map) :straight (yeetube :local-repo "~/Dev/emacs-lisp/yeetube") :config (setf yeetube-results-limit 20 yeetube-mpv-disable-video t) :bind (("C-c y" . 'thanos/yeetube-map) :map thanos/yeetube-map ("s" . 'yeetube-search) ("b" . 'yeetube-play-saved-video) ("d" . 'yeetube-download-videos) ("C-d" . 'yeetube-download-vimeo-videos) ("p" . 'yeetube-mpv-toggle-pause) ("v" . 'yeetube-mpv-toggle-video) ("C-p" . 'yeetube-mpv-toggle-video) ("k" . 'yeetube-remove-saved-video))) (use-package gnosis :straight (gnosis :pre-build (shell-command "make") :local-repo "~/Dev/emacs-lisp/gnosis") :init (define-prefix-command 'thanos/gnosis-map) :bind (("C-r" . thanos/gnosis-map) :map thanos/gnosis-map ("r" . 'gnosis-review) ("a" . 'gnosis-add-note))) ;; AI tools (use-package gptel :defer t :config (setf gptel-api-key (password-store-get "chatgpt/api")) :bind (:map gptel-mode-map ("C-c h" . 'gptel-menu))) (use-package copilot :straight (copilot :host github :repo "zerolfx/copilot.el" :files ("dist" "*.el")) :bind (:map copilot-mode-map ("M-TAB" . 'copilot-accept-completion-by-line) ("C-M-n" . 'copilot-next-completion) ("C-M-p" . 'copilot-previous-completion))) ;; Password-store (defun thanos/pass-launcher () "Launch Emacs as a front-end for pass." (interactive) (unwind-protect (with-selected-frame (make-frame '((name . "thanos/pass-launcher") (fullscreen . 0) (undecorated . t) (minibuffer . only) (width . 70) (height . 15))) (let* ((choice (completing-read "Choose an action: " '("AUTO" "COPY PASS" "COPY USERNAME" "EDIT" "GENERATE"))) (action (pcase choice ("AUTO" #'(lambda (entry) (let ((user (password-store-get-field entry "user")) (pass (password-store-get entry))) (start-process-shell-command "xdotool" nil (format "sleep 0.3 && xdotool getactivewindow type '%s' && xdotool getactivewindow key Tab && xdotool getactivewindow type '%s'" (if user user 'thanosapollo) pass))))) ("COPY PASS" #'password-store-copy) ("COPY USERNAME" #'(lambda (entry) (password-store-copy-field entry "user"))) ("EDIT" #'password-store-edit) ("GENERATE" #'password-store-generate)))) (funcall action (completing-read "Search: " (password-store-list))) (delete-frame))))) (defun smtp-get-pass () "Get password for smtp." (interactive) (password-store-copy-field "fastmail.com/thanosapollo@fastmail.com" "smtp")) (use-package password-store :init (define-prefix-command 'thanos/pass) :ensure t :config (setf password-store-password-length (+ 20 (random 20))) :bind (("C-c p" . 'thanos/pass) :map thanos/pass ("i" . 'password-store-insert) ("e" . 'password-store-edit) ("g" . 'password-store-generate) ("c" . 'password-store-copy) ("s" . 'smtp-get-pass))) (use-package mu4e-alert :ensure t :config (mu4e-alert-enable-mode-line-display)) (require 'thanos-commands) ;; Misc commands (require 'thanos-mu4e) ;; Email client ;;; init.el ends here