diff --git a/.config/emacs/config.el b/.config/emacs/config.el new file mode 100644 index 0000000..e478f65 --- /dev/null +++ b/.config/emacs/config.el @@ -0,0 +1,821 @@ +(add-to-list 'load-path "~/.config/emacs/scripts/") + +(require 'elpaca-setup) ;; The Elpaca Package Manager +(require 'app-launchers) ;; Use emacs as a run launcher like dmenu (experimental) +(require 'buffer-move) ;; Buffer-move for better window management +(require 'eshell-prompt) ;; A fancy prompt for eshell + +(use-package all-the-icons + :ensure t + :if (display-graphic-p)) + +(use-package all-the-icons-dired + :hook (dired-mode . (lambda () (all-the-icons-dired-mode t)))) + +(setq backup-directory-alist '((".*" . "~/.local/share/Trash/files"))) + +(use-package company + :defer 2 + :diminish + :custom + (company-begin-commands '(self-insert-command)) + (company-idle-delay .1) + (company-minimum-prefix-length 2) + (company-show-numbers t) + (company-tooltip-align-annotations 't) + (global-company-mode t)) + +(use-package company-box + :after company + :diminish + :hook (company-mode . company-box-mode)) + +(use-package dashboard + :ensure t + :init + (setq initial-buffer-choice 'dashboard-open) + (setq dashboard-set-heading-icons t) + (setq dashboard-set-file-icons t) + (setq dashboard-banner-logo-title "Emacs Is More Than A Text Editor!") + ;;(setq dashboard-startup-banner 'logo) ;; use standard emacs logo as banner + (setq dashboard-startup-banner "~/.config/emacs/images/dtmacs-logo.png") ;; use custom image as banner + (setq dashboard-center-content nil) ;; set to 't' for centered content + (setq dashboard-items '((recents . 5) + (agenda . 5 ) + (bookmarks . 3) + (projects . 3))) + :custom + (dashboard-modify-heading-icons '((recents . "file-text") + (bookmarks . "book"))) + :config + (dashboard-setup-startup-hook)) + +(use-package diminish) + +(use-package dired-open + :config + (setq dired-open-extensions '(("gif" . "sxiv") + ("jpg" . "sxiv") + ("png" . "sxiv") + ("mkv" . "mpv") + ("mp4" . "mpv")))) + +(use-package peep-dired + :after dired + :hook (evil-normalize-keymaps . peep-dired-hook) + :config + (evil-define-key 'normal dired-mode-map (kbd "h") 'dired-up-directory) + (evil-define-key 'normal dired-mode-map (kbd "l") 'dired-open-file) ; use dired-find-file instead if not using dired-open package + (evil-define-key 'normal peep-dired-mode-map (kbd "j") 'peep-dired-next-file) + (evil-define-key 'normal peep-dired-mode-map (kbd "k") 'peep-dired-prev-file) +) + +(use-package drag-stuff + :init + (drag-stuff-global-mode 1) + (drag-stuff-define-keys)) + +(setq ediff-split-window-function 'split-window-horizontally + ediff-window-setup-function 'ediff-setup-windows-plain) + +(defun dt-ediff-hook () + (ediff-setup-keymap) + (define-key ediff-mode-map "j" 'ediff-next-difference) + (define-key ediff-mode-map "k" 'ediff-previous-difference)) + +(add-hook 'ediff-mode-hook 'dt-ediff-hook) + +(use-package elfeed + :config + (setq elfeed-search-feed-face ":foreground #ffffff :weight bold" + elfeed-feeds (quote + (("https://www.reddit.com/r/linux.rss" reddit linux) + ("https://www.reddit.com/r/commandline.rss" reddit commandline) + ("https://www.reddit.com/r/distrotube.rss" reddit distrotube) + ("https://www.reddit.com/r/emacs.rss" reddit emacs) + ("https://www.gamingonlinux.com/article_rss.php" gaming linux) + ("https://hackaday.com/blog/feed/" hackaday linux) + ("https://opensource.com/feed" opensource linux) + ("https://linux.softpedia.com/backend.xml" softpedia linux) + ("https://itsfoss.com/feed/" itsfoss linux) + ("https://www.zdnet.com/topic/linux/rss.xml" zdnet linux) + ("https://www.phoronix.com/rss.php" phoronix linux) + ("http://feeds.feedburner.com/d0od" omgubuntu linux) + ("https://www.computerworld.com/index.rss" computerworld linux) + ("https://www.networkworld.com/category/linux/index.rss" networkworld linux) + ("https://www.techrepublic.com/rssfeeds/topic/open-source/" techrepublic linux) + ("https://betanews.com/feed" betanews linux) + ("http://lxer.com/module/newswire/headlines.rss" lxer linux) + ("https://distrowatch.com/news/dwd.xml" distrowatch linux))))) + + +(use-package elfeed-goodies + :init + (elfeed-goodies/setup) + :config + (setq elfeed-goodies/entry-pane-size 0.5)) + +(use-package ellama + :init + (setopt ellama-keymap-prefix "C-c e") ;; keymap for all ellama functions + (setopt ellama-language "English") ;; language ellama should translate to + (require 'llm-ollama) + (setopt ellama-provider + (make-llm-ollama + ;; this model should be pulled to use it + ;; value should be the same as you print in terminal during pull + :chat-model "llama3.2" + :embedding-model "nomic-embed-text" + :default-chat-non-standard-params '(("num_ctx" . 8192)))) + ;; Predefined llm providers for interactive switching. + (setopt ellama-providers + '(("zephyr" . (make-llm-ollama + :chat-model "zephyr" + :embedding-model "zephyr")) + + ("llama3.1" . (make-llm-ollama + :chat-model "llama3.1" + :embedding-model "llama3.1")) + ("mixtral" . (make-llm-ollama + :chat-model "mixtral" + :embedding-model "mixtral")))) + (setopt ellama-naming-scheme 'ellama-generate-name-by-llm) + ;; Translation llm provider + (setopt ellama-translation-provider (make-llm-ollama + :chat-model "mixtral" + :embedding-model "nomic-embed-text")) + :config + (setq ellama-sessions-directory "~/.config/emacs/ellama-sessions/" + ellama-sessions-auto-save t)) + +(use-package eradio + :init + (setq eradio-player '("mpv" "--no-video" "--no-terminal")) + :config + (setq eradio-channels '(("Totally 80s FM" . "https://zeno.fm/radio/totally-80s-fm/") + ("Oldies Radio 50s-60s" . "https://zeno.fm/radio/oldies-radio-50s-60s/") + ("Oldies Radio 70s" . "https://zeno.fm/radio/oldies-radio-70s/") + ("Unlimited 80s" . "https://zeno.fm/radio/unlimited80s/") + ("80s Hits" . "https://zeno.fm/radio/80shits/") + ("90s Hits" . "https://zeno.fm/radio/90s_HITS/") + ("2000s Pop" . "https://zeno.fm/radio/2000s-pop/") + ("The 2000s" . "https://zeno.fm/radio/the-2000s/") + ("Hits 2010s" . "https://zeno.fm/radio/helia-hits-2010/") + ("Classical Radio" . "https://zeno.fm/radio/classical-radio/") + ("Classical Relaxation" . "https://zeno.fm/radio/radio-christmas-non-stop-classical/") + ("Classic Rock" . "https://zeno.fm/radio/classic-rockdnb2sav8qs8uv/") + ("Gangsta49" . "https://zeno.fm/radio/gangsta49/") + ("HipHop49" . "https://zeno.fm/radio/hiphop49/") + ("Madhouse Country Radio" . "https://zeno.fm/radio/madhouse-country-radio/") + ("PopMusic" . "https://zeno.fm/radio/popmusic74vyurvmug0uv/") + ("PopStars" . "https://zeno.fm/radio/popstars/") + ("RadioMetal" . "https://zeno.fm/radio/radio-metal/") + ("RocknRoll Radio" . "https://zeno.fm/radio/rocknroll-radio994c7517qs8uv/")))) + +;; Expands to: (elpaca evil (use-package evil :demand t)) +(use-package evil + :init ;; tweak evil's configuration before loading it + (setq evil-want-integration t ;; This is optional since it's already set to t by default. + evil-want-keybinding nil + evil-vsplit-window-right t + evil-split-window-below t + evil-undo-system 'undo-redo) ;; Adds vim-like C-r redo functionality + (evil-mode)) + +(use-package evil-collection + :after evil + :config + ;; Do not uncomment this unless you want to specify each and every mode + ;; that evil-collection should works with. The following line is here + ;; for documentation purposes in case you need it. + ;; (setq evil-collection-mode-list '(calendar dashboard dired ediff info magit ibuffer)) + (add-to-list 'evil-collection-mode-list 'help) ;; evilify help mode + (evil-collection-init)) + +(use-package evil-tutor) + +;; Using RETURN to follow links in Org/Evil +;; Unmap keys in 'evil-maps if not done, (setq org-return-follows-link t) will not work +(with-eval-after-load 'evil-maps + (define-key evil-motion-state-map (kbd "SPC") nil) + (define-key evil-motion-state-map (kbd "RET") nil) + (define-key evil-motion-state-map (kbd "TAB") nil)) +;; Setting RETURN key in org-mode to follow links + (setq org-return-follows-link t) + +(use-package flycheck + :ensure t + :defer t + :diminish + :init (global-flycheck-mode)) + +(set-face-attribute 'default nil + :font "JetBrains Mono" + :height 110 + :weight 'medium) +(set-face-attribute 'variable-pitch nil + :font "Ubuntu" + :height 120 + :weight 'medium) +(set-face-attribute 'fixed-pitch nil + :font "JetBrains Mono" + :height 110 + :weight 'medium) +;; Makes commented text and keywords italics. +;; This is working in emacsclient but not emacs. +;; Your font must have an italic face available. +(set-face-attribute 'font-lock-comment-face nil + :slant 'italic) +(set-face-attribute 'font-lock-keyword-face nil + :slant 'italic) + +;; This sets the default font on all graphical frames created after restarting Emacs. +;; Does the same thing as 'set-face-attribute default' above, but emacsclient fonts +;; are not right unless I also add this method of setting the default font. +(add-to-list 'default-frame-alist '(font . "JetBrains Mono-11")) + +;; Uncomment the following line if line spacing needs adjusting. +(setq-default line-spacing 0.12) +(set-face-background 'mouse "#ffffff") + +(global-set-key (kbd "C-=") 'text-scale-increase) +(global-set-key (kbd "C--") 'text-scale-decrease) +(global-set-key (kbd "") 'text-scale-increase) +(global-set-key (kbd "") 'text-scale-decrease) + +(use-package nerd-icons + ;; :custom + ;; The Nerd Font you want to use in GUI + ;; "Symbols Nerd Font Mono" is the default and is recommended + ;; but you can use any other Nerd Font if you want + ;; (nerd-icons-font-family "Symbols Nerd Font Mono") + ) + +(use-package general + :config + (general-evil-setup) + + ;; set up 'SPC' as the global leader key + (general-create-definer dt/leader-keys + :states '(normal insert visual emacs) + :keymaps 'override + :prefix "SPC" ;; set leader + :global-prefix "M-SPC") ;; access leader in insert mode + + (dt/leader-keys + "SPC" '(counsel-M-x :wk "Counsel M-x") + "." '(find-file :wk "Find file") + "=" '(perspective-map :wk "Perspective") ;; Lists all the perspective keybindings + "TAB TAB" '(comment-line :wk "Comment lines") + "u" '(universal-argument :wk "Universal argument")) + + (dt/leader-keys + "a" '(:ignore t :wk "A.I.") + "a a" '(ellama-ask-about :wk "Ask ellama about region") + "a e" '(:ignore t :wk "Ellama enhance") + "a e g" '(ellama-improve-grammar :wk "Ellama enhance wording") + "a e w" '(ellama-improve-wording :wk "Ellama enhance grammar") + "a i" '(ellama-chat :wk "Ask ellama") + "a p" '(ellama-provider-select :wk "Ellama provider select") + "a s" '(ellama-summarize :wk "Ellama summarize region") + "a t" '(ellama-translate :wk "Ellama translate region")) + + (dt/leader-keys + "b" '(:ignore t :wk "Bookmarks/Buffers") + "b b" '(switch-to-buffer :wk "Switch to buffer") + "b c" '(clone-indirect-buffer :wk "Create indirect buffer copy in a split") + "b C" '(clone-indirect-buffer-other-window :wk "Clone indirect buffer in new window") + "b d" '(bookmark-delete :wk "Delete bookmark") + "b i" '(ibuffer :wk "Ibuffer") + "b k" '(kill-current-buffer :wk "Kill current buffer") + "b K" '(kill-some-buffers :wk "Kill multiple buffers") + "b l" '(list-bookmarks :wk "List bookmarks") + "b m" '(bookmark-set :wk "Set bookmark") + "b n" '(next-buffer :wk "Next buffer") + "b p" '(previous-buffer :wk "Previous buffer") + "b r" '(revert-buffer :wk "Reload buffer") + "b R" '(rename-buffer :wk "Rename buffer") + "b s" '(basic-save-buffer :wk "Save buffer") + "b S" '(save-some-buffers :wk "Save multiple buffers") + "b w" '(bookmark-save :wk "Save current bookmarks to bookmark file")) + + (dt/leader-keys + "d" '(:ignore t :wk "Dired") + "d d" '(dired :wk "Open dired") + "d f" '(wdired-finish-edit :wk "Writable dired finish edit") + "d j" '(dired-jump :wk "Dired jump to current") + "d n" '(neotree-dir :wk "Open directory in neotree") + "d p" '(peep-dired :wk "Peep-dired") + "d w" '(wdired-change-to-wdired-mode :wk "Writable dired")) + + (dt/leader-keys + "e" '(:ignore t :wk "Ediff/Eshell/Eval/EWW") + "e b" '(eval-buffer :wk "Evaluate elisp in buffer") + "e d" '(eval-defun :wk "Evaluate defun containing or after point") + "e e" '(eval-expression :wk "Evaluate and elisp expression") + "e f" '(ediff-files :wk "Run ediff on a pair of files") + "e F" '(ediff-files3 :wk "Run ediff on three files") + "e h" '(counsel-esh-history :which-key "Eshell history") + "e l" '(eval-last-sexp :wk "Evaluate elisp expression before point") + "e n" '(eshell-new :wk "Create new eshell buffer") + "e r" '(eval-region :wk "Evaluate elisp in region") + "e R" '(eww-reload :which-key "Reload current page in EWW") + "e s" '(eshell :which-key "Eshell") + "e w" '(eww :which-key "EWW emacs web wowser")) + + (dt/leader-keys + "f" '(:ignore t :wk "Files") + "f c" '((lambda () (interactive) + (find-file "~/.config/emacs/config.org")) + :wk "Open emacs config.org") + "f e" '((lambda () (interactive) + (dired "~/.config/emacs/")) + :wk "Open user-emacs-directory in dired") + "f d" '(find-grep-dired :wk "Search for string in files in DIR") + "f g" '(counsel-grep-or-swiper :wk "Search for string current file") + "f i" '((lambda () (interactive) + (find-file "~/.config/emacs/init.el")) + :wk "Open emacs init.el") + "f j" '(counsel-file-jump :wk "Jump to a file below current directory") + "f l" '(counsel-locate :wk "Locate a file") + "f r" '(counsel-recentf :wk "Find recent files") + "f u" '(sudo-edit-find-file :wk "Sudo find file") + "f U" '(sudo-edit :wk "Sudo edit file")) + + (dt/leader-keys + "g" '(:ignore t :wk "Git") + "g /" '(magit-dispatch :wk "Magit dispatch") + "g ." '(magit-file-dispatch :wk "Magit file dispatch") + "g b" '(magit-branch-checkout :wk "Switch branch") + "g c" '(:ignore t :wk "Create") + "g c b" '(magit-branch-and-checkout :wk "Create branch and checkout") + "g c c" '(magit-commit-create :wk "Create commit") + "g c f" '(magit-commit-fixup :wk "Create fixup commit") + "g C" '(magit-clone :wk "Clone repo") + "g f" '(:ignore t :wk "Find") + "g f c" '(magit-show-commit :wk "Show commit") + "g f f" '(magit-find-file :wk "Magit find file") + "g f g" '(magit-find-git-config-file :wk "Find gitconfig file") + "g F" '(magit-fetch :wk "Git fetch") + "g g" '(magit-status :wk "Magit status") + "g i" '(magit-init :wk "Initialize git repo") + "g l" '(magit-log-buffer-file :wk "Magit buffer log") + "g r" '(vc-revert :wk "Git revert file") + "g s" '(magit-stage-file :wk "Git stage file") + "g t" '(git-timemachine :wk "Git time machine") + "g u" '(magit-stage-file :wk "Git unstage file")) + + (dt/leader-keys + "h" '(:ignore t :wk "Help") + "h a" '(counsel-apropos :wk "Apropos") + "h b" '(describe-bindings :wk "Describe bindings") + "h c" '(describe-char :wk "Describe character under cursor") + "h d" '(:ignore t :wk "Emacs documentation") + "h d a" '(about-emacs :wk "About Emacs") + "h d d" '(view-emacs-debugging :wk "View Emacs debugging") + "h d f" '(view-emacs-FAQ :wk "View Emacs FAQ") + "h d m" '(info-emacs-manual :wk "The Emacs manual") + "h d n" '(view-emacs-news :wk "View Emacs news") + "h d o" '(describe-distribution :wk "How to obtain Emacs") + "h d p" '(view-emacs-problems :wk "View Emacs problems") + "h d t" '(view-emacs-todo :wk "View Emacs todo") + "h d w" '(describe-no-warranty :wk "Describe no warranty") + "h e" '(view-echo-area-messages :wk "View echo area messages") + "h f" '(describe-function :wk "Describe function") + "h F" '(describe-face :wk "Describe face") + "h g" '(describe-gnu-project :wk "Describe GNU Project") + "h i" '(info :wk "Info") + "h I" '(describe-input-method :wk "Describe input method") + "h k" '(describe-key :wk "Describe key") + "h l" '(view-lossage :wk "Display recent keystrokes and the commands run") + "h L" '(describe-language-environment :wk "Describe language environment") + "h m" '(describe-mode :wk "Describe mode") + "h r" '(:ignore t :wk "Reload") + "h r r" '((lambda () (interactive) + (load-file "~/.config/emacs/init.el") + (ignore (elpaca-process-queues))) + :wk "Reload emacs config") + "h t" '(load-theme :wk "Load theme") + "h v" '(describe-variable :wk "Describe variable") + "h w" '(where-is :wk "Prints keybinding for command if set") + "h x" '(describe-command :wk "Display full documentation for command")) + + (dt/leader-keys + "m" '(:ignore t :wk "Org") + "m a" '(org-agenda :wk "Org agenda") + "m e" '(org-export-dispatch :wk "Org export dispatch") + "m i" '(org-toggle-item :wk "Org toggle item") + "m t" '(org-todo :wk "Org todo") + "m B" '(org-babel-tangle :wk "Org babel tangle") + "m T" '(org-todo-list :wk "Org todo list")) + + (dt/leader-keys + "m b" '(:ignore t :wk "Tables") + "m b -" '(org-table-insert-hline :wk "Insert hline in table")) + + (dt/leader-keys + "m d" '(:ignore t :wk "Date/deadline") + "m d t" '(org-time-stamp :wk "Org time stamp")) + + (dt/leader-keys + "o" '(:ignore t :wk "Open") + "o d" '(dashboard-open :wk "Dashboard") + "o e" '(elfeed :wk "Elfeed RSS") + "o f" '(make-frame :wk "Open buffer in new frame") + "o F" '(select-frame-by-name :wk "Select frame by name")) + + ;; projectile-command-map already has a ton of bindings + ;; set for us, so no need to specify each individually. + (dt/leader-keys + "p" '(projectile-command-map :wk "Projectile")) + + (dt/leader-keys + "r" '(:ignore t :wk "Radio") + "r p" '(eradio-play :wk "Eradio play") + "r s" '(eradio-stop :wk "Eradio stop") + "r t" '(eradio-toggle :wk "Eradio toggle")) + + + (dt/leader-keys + "s" '(:ignore t :wk "Search") + "s d" '(dictionary-search :wk "Search dictionary") + "s m" '(man :wk "Man pages") + "s o" '(pdf-occur :wk "Pdf search lines matching STRING") + "s t" '(tldr :wk "Lookup TLDR docs for a command") + "s w" '(woman :wk "Similar to man but doesn't require man")) + + (dt/leader-keys + "t" '(:ignore t :wk "Toggle") + "t e" '(eshell-toggle :wk "Toggle eshell") + "t f" '(flycheck-mode :wk "Toggle flycheck") + "t l" '(display-line-numbers-mode :wk "Toggle line numbers") + "t n" '(neotree-toggle :wk "Toggle neotree file viewer") + "t o" '(org-mode :wk "Toggle org mode") + "t r" '(rainbow-mode :wk "Toggle rainbow mode") + "t t" '(visual-line-mode :wk "Toggle truncated lines") + "t v" '(vterm-toggle :wk "Toggle vterm")) + + (dt/leader-keys + "w" '(:ignore t :wk "Windows/Words") + ;; Window splits + "w c" '(evil-window-delete :wk "Close window") + "w n" '(evil-window-new :wk "New window") + "w s" '(evil-window-split :wk "Horizontal split window") + "w v" '(evil-window-vsplit :wk "Vertical split window") + ;; Window motions + "w h" '(evil-window-left :wk "Window left") + "w j" '(evil-window-down :wk "Window down") + "w k" '(evil-window-up :wk "Window up") + "w l" '(evil-window-right :wk "Window right") + "w w" '(evil-window-next :wk "Goto next window") + ;; Move Windows + "w H" '(buf-move-left :wk "Buffer move left") + "w J" '(buf-move-down :wk "Buffer move down") + "w K" '(buf-move-up :wk "Buffer move up") + "w L" '(buf-move-right :wk "Buffer move right") + ;; Words + "w d" '(downcase-word :wk "Downcase word") + "w u" '(upcase-word :wk "Upcase word") + "w =" '(count-words :wk "Count words/lines for buffer")) +) + +(use-package git-timemachine + :after git-timemachine + :hook (evil-normalize-keymaps . git-timemachine-hook) + :config + (evil-define-key 'normal git-timemachine-mode-map (kbd "C-j") 'git-timemachine-show-previous-revision) + (evil-define-key 'normal git-timemachine-mode-map (kbd "C-k") 'git-timemachine-show-next-revision) +) + +(use-package hl-todo + :hook ((org-mode . hl-todo-mode) + (prog-mode . hl-todo-mode)) + :config + (setq hl-todo-highlight-punctuation ":" + hl-todo-keyword-faces + `(("TODO" warning bold) + ("FIXME" error bold) + ("HACK" font-lock-constant-face bold) + ("REVIEW" font-lock-keyword-face bold) + ("NOTE" success bold) + ("DEPRECATED" font-lock-doc-face bold)))) + +(use-package counsel + :after ivy + :diminish + :config + (counsel-mode) + (setq ivy-initial-inputs-alist nil)) ;; removes starting ^ regex in M-x + +(use-package ivy + :bind + ;; ivy-resume resumes the last Ivy-based completion. + (("C-c C-r" . ivy-resume) + ("C-x B" . ivy-switch-buffer-other-window)) + :diminish + :custom + (setq ivy-use-virtual-buffers t) + (setq ivy-count-format "(%d/%d) ") + (setq enable-recursive-minibuffers t) + :config + (ivy-mode)) + +(use-package all-the-icons-ivy-rich + :ensure t + :init (all-the-icons-ivy-rich-mode 1)) + +(use-package ivy-rich + :after ivy + :ensure t + :init (ivy-rich-mode 1) ;; this gets us descriptions in M-x. + :custom + (ivy-virtual-abbreviate 'full + ivy-rich-switch-buffer-align-virtual-buffer t + ivy-rich-path-style 'abbrev) + :config + (ivy-set-display-transformer 'ivy-switch-buffer + 'ivy-rich-switch-buffer-transformer)) + +(use-package dart-mode) +(use-package haskell-mode) +(use-package lua-mode) +(use-package php-mode) + +(global-set-key [escape] 'keyboard-escape-quit) + +(use-package doom-modeline + :ensure t + :init (doom-modeline-mode 1) + :config + (setq doom-modeline-height 35 ;; sets modeline height + doom-modeline-bar-width 5 ;; sets right bar width + doom-modeline-persp-name t ;; adds perspective name to modeline + doom-modeline-persp-icon t)) ;; adds folder icon next to persp name + +(use-package neotree + :config + (setq neo-smart-open t + neo-show-hidden-files t + neo-window-width 55 + neo-window-fixed-size nil + inhibit-compacting-font-caches t + projectile-switch-project-action 'neotree-projectile-action) + ;; truncate long file names in neotree + (add-hook 'neo-after-create-hook + #'(lambda (_) + (with-current-buffer (get-buffer neo-buffer-name) + (setq truncate-lines t) + (setq word-wrap nil) + (make-local-variable 'auto-hscroll-mode) + (setq auto-hscroll-mode nil))))) + +(setq org-agenda-files '("~/.config/emacs/agenda.org")) + +(add-hook 'org-mode-hook 'org-indent-mode) +(use-package org-bullets) +(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))) + +(eval-after-load 'org-indent '(diminish 'org-indent-mode)) + + (custom-set-faces + '(org-level-1 ((t (:inherit outline-1 :height 1.7)))) + '(org-level-2 ((t (:inherit outline-2 :height 1.6)))) + '(org-level-3 ((t (:inherit outline-3 :height 1.5)))) + '(org-level-4 ((t (:inherit outline-4 :height 1.4)))) + '(org-level-5 ((t (:inherit outline-5 :height 1.3)))) + '(org-level-6 ((t (:inherit outline-5 :height 1.2)))) + '(org-level-7 ((t (:inherit outline-5 :height 1.1))))) + +(require 'org-tempo) + +(setq org-src-preserve-indentation t) + +(use-package toc-org + :commands toc-org-enable + :init (add-hook 'org-mode-hook 'toc-org-enable)) + +(use-package ox-hugo + :ensure t ;Auto-install the package from Melpa + :after ox) + +(use-package pdf-tools + :defer t + :commands (pdf-loader-install) + :mode "\\.pdf\\'" + :bind (:map pdf-view-mode-map + ("j" . pdf-view-next-line-or-next-page) + ("k" . pdf-view-previous-line-or-previous-page) + ("C-=" . pdf-view-enlarge) + ("C--" . pdf-view-shrink)) + :init (pdf-loader-install) + :config (add-to-list 'revert-without-query ".pdf")) + +(add-hook 'pdf-view-mode-hook #'(lambda () (interactive) (display-line-numbers-mode -1) + (blink-cursor-mode -1) + (doom-modeline-mode -1))) + +(use-package perspective + :custom + ;; NOTE! I have also set 'SCP =' to open the perspective menu. + ;; I'm only setting the additional binding because setting it + ;; helps suppress an annoying warning message. + (persp-mode-prefix-key (kbd "C-c M-p")) + :init + (persp-mode) + :config + ;; Sets a file to write to when we save states + (setq persp-state-default-file "~/.config/emacs/sessions")) + +;; This will group buffers by persp-name in ibuffer. +(add-hook 'ibuffer-hook + (lambda () + (persp-ibuffer-set-filter-groups) + (unless (eq ibuffer-sorting-mode 'alphabetic) + (ibuffer-do-sort-by-alphabetic)))) + +;; Automatically save perspective states to file when Emacs exits. +(add-hook 'kill-emacs-hook #'persp-state-save) + +(use-package projectile + :config + (projectile-mode 1)) + +(use-package rainbow-delimiters + :hook ((emacs-lisp-mode . rainbow-delimiters-mode) + (clojure-mode . rainbow-delimiters-mode))) + +(use-package rainbow-mode + :diminish + :hook org-mode prog-mode) + +(delete-selection-mode 1) ;; You can select text and delete it by typing. +(electric-indent-mode -1) ;; Turn off the weird indenting that Emacs does by default. +(electric-pair-mode 1) ;; Turns on automatic parens pairing +;; The following prevents <> from auto-pairing when electric-pair-mode is on. +;; Otherwise, org-tempo is broken when you try to ") #'pcomplete-list))) + +;; A function for easily creating multiple buffers of 'eshell'. +;; NOTE: `C-u M-x eshell` would also create new 'eshell' buffers. +(defun eshell-new (name) + "Create new eshell buffer named NAME." + (interactive "sName: ") + (setq name (concat "$" name)) + (eshell) + (rename-buffer name)) + +(use-package eshell-toggle + :custom + (eshell-toggle-size-fraction 3) + (eshell-toggle-use-projectile-root t) + (eshell-toggle-run-command nil) + (eshell-toggle-init-function #'eshell-toggle-init-ansi-term)) + + (use-package eshell-syntax-highlighting + :after esh-mode + :config + (eshell-syntax-highlighting-global-mode +1)) + + ;; eshell-syntax-highlighting -- adds fish/zsh-like syntax highlighting. + ;; eshell-rc-script -- your profile for eshell; like a bashrc for eshell. + ;; eshell-aliases-file -- sets an aliases file for the eshell. + + (setq eshell-rc-script (concat user-emacs-directory "eshell/profile") + eshell-aliases-file (concat user-emacs-directory "eshell/aliases") + eshell-history-size 5000 + eshell-buffer-maximum-lines 5000 + eshell-hist-ignoredups t + eshell-scroll-to-bottom-on-input t + eshell-destroy-buffer-when-process-dies t + eshell-visual-commands'("bash" "fish" "htop" "ssh" "top" "zsh")) + +(use-package vterm + :ensure t + :config + (setq shell-file-name "/bin/sh" + vterm-max-scrollback 5000)) + +(use-package vterm-toggle + :ensure t + :after vterm + :config + ;; When running programs in Vterm and in 'normal' mode, make sure that ESC + ;; kills the program as it would in most standard terminal programs. + (evil-define-key 'normal vterm-mode-map (kbd "") 'vterm--self-insert) + (setq vterm-toggle-fullscreen-p nil) + (setq vterm-toggle-scope 'project) + (add-to-list 'display-buffer-alist + '((lambda (buffer-or-name _) + (let ((buffer (get-buffer buffer-or-name))) + (with-current-buffer buffer + (or (equal major-mode 'vterm-mode) + (string-prefix-p vterm-buffer-name (buffer-name buffer)))))) + (display-buffer-reuse-window display-buffer-at-bottom) + ;;(display-buffer-reuse-window display-buffer-in-direction) + ;;display-buffer-in-direction/direction/dedicated is added in emacs27 + ;;(direction . bottom) + ;;(dedicated . t) ;dedicated is supported in emacs27 + (reusable-frames . visible) + (window-height . 0.4)))) + +(use-package sudo-edit) + +(add-to-list 'custom-theme-load-path "~/.config/emacs/themes/") + +(use-package doom-themes + :config + (setq doom-themes-enable-bold t ; if nil, bold is universally disabled + doom-themes-enable-italic t) ; if nil, italics is universally disabled + ;; Sets the default theme to load!!! + (load-theme 'doom-one t) + ;; Enable custom neotree theme (all-the-icons must be installed!) + (doom-themes-neotree-config) + ;; Corrects (and improves) org-mode's native fontification. + (doom-themes-org-config)) + +(use-package tldr) + +(add-to-list 'default-frame-alist '(alpha-background . 100)) ; For all new frames henceforth + +(use-package which-key + :init + (which-key-mode 1) + :diminish + :config + (setq which-key-side-window-location 'bottom + which-key-sort-order #'which-key-key-order-alpha + which-key-allow-imprecise-window-fit nil + which-key-sort-uppercase-first nil + which-key-add-column-padding 1 + which-key-max-display-columns nil + which-key-min-display-lines 6 + which-key-side-window-slot -10 + which-key-side-window-max-height 0.25 + which-key-idle-delay 0.8 + which-key-max-description-length 25 + which-key-allow-imprecise-window-fit nil + which-key-separator " → " )) + +(defun reader () + (interactive) + (let ((choices '(("First" . "Hi!") + ("Second" . 'second-choice) + ("Third" . 'third-choice)))) + (alist-get + (completing-read "Choose: " choices) + choices nil nil 'message))) + +(defun github-code-search () + "Search code on github for a given language." + (interactive) + (let ((language (completing-read + "Language: " + '("Emacs Lisp" "Python" "Clojure" "R"))) + (code (read-string "Code: "))) + (browse-url + (concat "https://github.com/search?l=" language + "&type=code&q=" code)))) + +(defun dm-search () + "Search various search engines." + (interactive) + (let ((engine (completing-read + "Search Engine: " + '("Arch Wiki" + "Bing" + "Google" + "Wikipedia"))) + (query (read-string "Query: "))) + (if (equal engine "Google") + (browse-url + (concat "https://www.google.com/search?q=" query))))) + +(defun dt/key-value-completing (choice) + (interactive + (list + (let ((completions '(("1" "One") + ("2" "Two") + ("3" "Three")))) + (cadr (assoc (completing-read "Choose: " completions) completions))))) + (message "You choose `%s'" choice)) diff --git a/.config/emacs/config.org b/.config/emacs/config.org new file mode 100644 index 0000000..4b0b89f --- /dev/null +++ b/.config/emacs/config.org @@ -0,0 +1,1164 @@ +#+TITLE: DT's GNU Emacs Config +#+AUTHOR: Derek Taylor (DT) +#+DESCRIPTION: DT's personal Emacs config. +#+STARTUP: showeverything +#+OPTIONS: toc:2 + +* TABLE OF CONTENTS :toc: +- [[#important-programs-to-load-first][IMPORTANT PROGRAMS TO LOAD FIRST]] + - [[#adding-the-scripts-directory-to-path][Adding the scripts directory to path]] + - [[#sourcing-the-scripts][Sourcing the scripts]] +- [[#all-the-icons][ALL THE ICONS]] +- [[#backup][BACKUP]] +- [[#company][COMPANY]] +- [[#dashboard][DASHBOARD]] +- [[#diminish][DIMINISH]] +- [[#dired][DIRED]] +- [[#drag-stuff][DRAG-STUFF]] +- [[#ediff][EDIFF]] +- [[#elfeed][ELFEED]] +- [[#ellama][ELLAMA]] +- [[#eradio][ERADIO]] +- [[#evil][EVIL]] +- [[#flycheck][FLYCHECK]] +- [[#fonts][FONTS]] + - [[#setting-the-font-face][Setting the Font Face]] + - [[#zooming-inout][Zooming In/Out]] + - [[#nerd-fonts-for-modeline][Nerd Fonts For Modeline]] +- [[#general-keybindings][GENERAL KEYBINDINGS]] +- [[#git-programs][GIT PROGRAMS]] + - [[#git-time-machine][Git Time Machine]] +- [[#highlight-todo][HIGHLIGHT TODO]] +- [[#ivy-counsel][IVY (COUNSEL)]] +- [[#language-support][LANGUAGE SUPPORT]] +- [[#minibuffer-escape][MINIBUFFER ESCAPE]] +- [[#modeline][MODELINE]] +- [[#neotree][NEOTREE]] +- [[#org-mode][ORG MODE]] + - [[#agenda][Agenda]] + - [[#bullets][Bullets]] + - [[#diminish-org-indent-mode][Diminish Org Indent Mode]] + - [[#org-level-headers][Org Level Headers]] + - [[#org-tempo][Org-Tempo]] + - [[#preserve-indentation-on-org-babel-tangle][Preserve Indentation On Org-Babel-Tangle]] + - [[#toc-org][Toc-Org]] + - [[#ox-hugo][Ox-Hugo]] +- [[#pdfs][PDFs]] +- [[#perspective][PERSPECTIVE]] +- [[#projectile][PROJECTILE]] +- [[#rainbow-delimiters][RAINBOW DELIMITERS]] +- [[#rainbow-mode][RAINBOW MODE]] +- [[#sane-defaults][SANE DEFAULTS]] +- [[#shells-and-terminals][SHELLS AND TERMINALS]] + - [[#eshell][Eshell]] + - [[#vterm][Vterm]] + - [[#vterm-toggle][Vterm-Toggle]] +- [[#sudo-edit][SUDO EDIT]] +- [[#theme][THEME]] +- [[#tldr][TLDR]] +- [[#transparency][TRANSPARENCY]] +- [[#which-key][WHICH-KEY]] +- [[#test][TEST]] + +* IMPORTANT PROGRAMS TO LOAD FIRST +To keep this =config.org= a reasonable length, I have moved a lot of code to individual scripts that will be sourced by this config. These scripts are found in "~/.config/emacs/scripts" and do not contain any code that most people are likely to need to edit. + +** Adding the scripts directory to path +#+begin_src emacs-lisp +(add-to-list 'load-path "~/.config/emacs/scripts/") +#+end_src + +** Sourcing the scripts +#+begin_src emacs-lisp +(require 'elpaca-setup) ;; The Elpaca Package Manager +(require 'app-launchers) ;; Use emacs as a run launcher like dmenu (experimental) +(require 'buffer-move) ;; Buffer-move for better window management +(require 'eshell-prompt) ;; A fancy prompt for eshell +#+end_src + +* ALL THE ICONS +This is an icon set that can be used with dashboard, dired, ibuffer and other Emacs programs. + +#+begin_src emacs-lisp +(use-package all-the-icons + :ensure t + :if (display-graphic-p)) + +(use-package all-the-icons-dired + :hook (dired-mode . (lambda () (all-the-icons-dired-mode t)))) +#+end_src + +* BACKUP +By default, Emacs creates automatic backups of files in their original directories, such "file.el" and the backup "file.el~". This leads to a lot of clutter, so let's tell Emacs to put all backups that it creates in the =TRASH= directory. + +#+begin_src emacs-lisp +(setq backup-directory-alist '((".*" . "~/.local/share/Trash/files"))) + +#+end_src + +* COMPANY +[[https://company-mode.github.io/][Company]] is a text completion framework for Emacs. The name stands for "complete anything". Completion will start automatically after you type a few letters. Use M-n and M-p to select, to complete or to complete the common part. + +#+begin_src emacs-lisp +(use-package company + :defer 2 + :diminish + :custom + (company-begin-commands '(self-insert-command)) + (company-idle-delay .1) + (company-minimum-prefix-length 2) + (company-show-numbers t) + (company-tooltip-align-annotations 't) + (global-company-mode t)) + +(use-package company-box + :after company + :diminish + :hook (company-mode . company-box-mode)) +#+end_src + +* DASHBOARD +Emacs Dashboard is an extensible startup screen showing you recent files, bookmarks, agenda items and an Emacs banner. + +#+begin_src emacs-lisp +(use-package dashboard + :ensure t + :init + (setq initial-buffer-choice 'dashboard-open) + (setq dashboard-set-heading-icons t) + (setq dashboard-set-file-icons t) + (setq dashboard-banner-logo-title "Emacs Is More Than A Text Editor!") + ;;(setq dashboard-startup-banner 'logo) ;; use standard emacs logo as banner + (setq dashboard-startup-banner "~/.config/emacs/images/dtmacs-logo.png") ;; use custom image as banner + (setq dashboard-center-content nil) ;; set to 't' for centered content + (setq dashboard-items '((recents . 5) + (agenda . 5 ) + (bookmarks . 3) + (projects . 3))) + :custom + (dashboard-modify-heading-icons '((recents . "file-text") + (bookmarks . "book"))) + :config + (dashboard-setup-startup-hook)) + +#+end_src + +* DIMINISH +This package implements hiding or abbreviation of the modeline displays (lighters) of minor-modes. With this package installed, you can add ':diminish' to any use-package block to hide that particular mode in the modeline. + +#+begin_src emacs-lisp +(use-package diminish) + +#+end_src + +* DIRED +#+begin_src emacs-lisp +(use-package dired-open + :config + (setq dired-open-extensions '(("gif" . "sxiv") + ("jpg" . "sxiv") + ("png" . "sxiv") + ("mkv" . "mpv") + ("mp4" . "mpv")))) + +(use-package peep-dired + :after dired + :hook (evil-normalize-keymaps . peep-dired-hook) + :config + (evil-define-key 'normal dired-mode-map (kbd "h") 'dired-up-directory) + (evil-define-key 'normal dired-mode-map (kbd "l") 'dired-open-file) ; use dired-find-file instead if not using dired-open package + (evil-define-key 'normal peep-dired-mode-map (kbd "j") 'peep-dired-next-file) + (evil-define-key 'normal peep-dired-mode-map (kbd "k") 'peep-dired-prev-file) +) + +#+end_src + +* DRAG-STUFF +[[https://github.com/rejeep/drag-stuff.el][Drag Stuff]] is a minor mode for Emacs that makes it possible to drag stuff (words, region, lines) around in Emacs. When 'drag-stuff-define-keys' is enabled, then the following keybindings are set: M-up, M-down, M-left, and M-right. + +#+begin_src emacs-lisp +(use-package drag-stuff + :init + (drag-stuff-global-mode 1) + (drag-stuff-define-keys)) + +#+end_src + +* EDIFF +'ediff' is a diff program that is built into Emacs. By default, 'ediff' splits files vertically and places the 'help' frame in its own window. I have changed this so the two files are split horizontally and the 'help' frame appears as a lower split within the existing window. Also, I create my own 'dt-ediff-hook' where I add 'j/k' for moving to next/prev diffs. By default, this is set to 'n/p'. + +#+begin_src emacs-lisp +(setq ediff-split-window-function 'split-window-horizontally + ediff-window-setup-function 'ediff-setup-windows-plain) + +(defun dt-ediff-hook () + (ediff-setup-keymap) + (define-key ediff-mode-map "j" 'ediff-next-difference) + (define-key ediff-mode-map "k" 'ediff-previous-difference)) + +(add-hook 'ediff-mode-hook 'dt-ediff-hook) +#+end_src + +* ELFEED +An RSS newsfeed reader for Emacs. Move through the articles with 'j/k'. Move through the stories with 'CTRL j/k' when in other frame. + +#+begin_src emacs-lisp +(use-package elfeed + :config + (setq elfeed-search-feed-face ":foreground #ffffff :weight bold" + elfeed-feeds (quote + (("https://www.reddit.com/r/linux.rss" reddit linux) + ("https://www.reddit.com/r/commandline.rss" reddit commandline) + ("https://www.reddit.com/r/distrotube.rss" reddit distrotube) + ("https://www.reddit.com/r/emacs.rss" reddit emacs) + ("https://www.gamingonlinux.com/article_rss.php" gaming linux) + ("https://hackaday.com/blog/feed/" hackaday linux) + ("https://opensource.com/feed" opensource linux) + ("https://linux.softpedia.com/backend.xml" softpedia linux) + ("https://itsfoss.com/feed/" itsfoss linux) + ("https://www.zdnet.com/topic/linux/rss.xml" zdnet linux) + ("https://www.phoronix.com/rss.php" phoronix linux) + ("http://feeds.feedburner.com/d0od" omgubuntu linux) + ("https://www.computerworld.com/index.rss" computerworld linux) + ("https://www.networkworld.com/category/linux/index.rss" networkworld linux) + ("https://www.techrepublic.com/rssfeeds/topic/open-source/" techrepublic linux) + ("https://betanews.com/feed" betanews linux) + ("http://lxer.com/module/newswire/headlines.rss" lxer linux) + ("https://distrowatch.com/news/dwd.xml" distrowatch linux))))) + + +(use-package elfeed-goodies + :init + (elfeed-goodies/setup) + :config + (setq elfeed-goodies/entry-pane-size 0.5)) + +#+end_src + +* ELLAMA +[[https://github.com/s-kostyaev/ellama][Ellama]] is a tool for interacting with large language models from Emacs. You need to have 'ollama' installed on your computer to use 'ellama' in Emacs. You need to pull in any LLMs that you want to have available for use. For example, if you want to be able to use Llama 3.1, then you need to run 'ollama pull llama3.1'. + +#+begin_src emacs-lisp +(use-package ellama + :init + (setopt ellama-keymap-prefix "C-c e") ;; keymap for all ellama functions + (setopt ellama-language "English") ;; language ellama should translate to + (require 'llm-ollama) + (setopt ellama-provider + (make-llm-ollama + ;; this model should be pulled to use it + ;; value should be the same as you print in terminal during pull + :chat-model "llama3.2" + :embedding-model "nomic-embed-text" + :default-chat-non-standard-params '(("num_ctx" . 8192)))) + ;; Predefined llm providers for interactive switching. + (setopt ellama-providers + '(("zephyr" . (make-llm-ollama + :chat-model "zephyr" + :embedding-model "zephyr")) + + ("llama3.1" . (make-llm-ollama + :chat-model "llama3.1" + :embedding-model "llama3.1")) + ("mixtral" . (make-llm-ollama + :chat-model "mixtral" + :embedding-model "mixtral")))) + (setopt ellama-naming-scheme 'ellama-generate-name-by-llm) + ;; Translation llm provider + (setopt ellama-translation-provider (make-llm-ollama + :chat-model "mixtral" + :embedding-model "nomic-embed-text")) + :config + (setq ellama-sessions-directory "~/.config/emacs/ellama-sessions/" + ellama-sessions-auto-save t)) + +#+end_src + +* ERADIO +[[https://github.com/olavfosse/eradio][eradio]] is a simple Internet radio player for Emacs. It uses 'vlc as its backend by default, but you can change the =eradio-player= variable to use another multimedia player. I have set eradio to use 'mpv' instead of 'vlc' because it supports more types of Internet radio streams. + +#+begin_src emacs-lisp +(use-package eradio + :init + (setq eradio-player '("mpv" "--no-video" "--no-terminal")) + :config + (setq eradio-channels '(("Totally 80s FM" . "https://zeno.fm/radio/totally-80s-fm/") + ("Oldies Radio 50s-60s" . "https://zeno.fm/radio/oldies-radio-50s-60s/") + ("Oldies Radio 70s" . "https://zeno.fm/radio/oldies-radio-70s/") + ("Unlimited 80s" . "https://zeno.fm/radio/unlimited80s/") + ("80s Hits" . "https://zeno.fm/radio/80shits/") + ("90s Hits" . "https://zeno.fm/radio/90s_HITS/") + ("2000s Pop" . "https://zeno.fm/radio/2000s-pop/") + ("The 2000s" . "https://zeno.fm/radio/the-2000s/") + ("Hits 2010s" . "https://zeno.fm/radio/helia-hits-2010/") + ("Classical Radio" . "https://zeno.fm/radio/classical-radio/") + ("Classical Relaxation" . "https://zeno.fm/radio/radio-christmas-non-stop-classical/") + ("Classic Rock" . "https://zeno.fm/radio/classic-rockdnb2sav8qs8uv/") + ("Gangsta49" . "https://zeno.fm/radio/gangsta49/") + ("HipHop49" . "https://zeno.fm/radio/hiphop49/") + ("Madhouse Country Radio" . "https://zeno.fm/radio/madhouse-country-radio/") + ("PopMusic" . "https://zeno.fm/radio/popmusic74vyurvmug0uv/") + ("PopStars" . "https://zeno.fm/radio/popstars/") + ("RadioMetal" . "https://zeno.fm/radio/radio-metal/") + ("RocknRoll Radio" . "https://zeno.fm/radio/rocknroll-radio994c7517qs8uv/")))) +#+end_src + +* EVIL +[[https://github.com/emacs-evil/evil][Evil]] is an extensible vi/vim layer for Emacs. Because...let's face it. The Vim keybindings are just plain better. + +#+begin_src emacs-lisp +;; Expands to: (elpaca evil (use-package evil :demand t)) +(use-package evil + :init ;; tweak evil's configuration before loading it + (setq evil-want-integration t ;; This is optional since it's already set to t by default. + evil-want-keybinding nil + evil-vsplit-window-right t + evil-split-window-below t + evil-undo-system 'undo-redo) ;; Adds vim-like C-r redo functionality + (evil-mode)) + +(use-package evil-collection + :after evil + :config + ;; Do not uncomment this unless you want to specify each and every mode + ;; that evil-collection should works with. The following line is here + ;; for documentation purposes in case you need it. + ;; (setq evil-collection-mode-list '(calendar dashboard dired ediff info magit ibuffer)) + (add-to-list 'evil-collection-mode-list 'help) ;; evilify help mode + (evil-collection-init)) + +(use-package evil-tutor) + +;; Using RETURN to follow links in Org/Evil +;; Unmap keys in 'evil-maps if not done, (setq org-return-follows-link t) will not work +(with-eval-after-load 'evil-maps + (define-key evil-motion-state-map (kbd "SPC") nil) + (define-key evil-motion-state-map (kbd "RET") nil) + (define-key evil-motion-state-map (kbd "TAB") nil)) +;; Setting RETURN key in org-mode to follow links + (setq org-return-follows-link t) + +#+end_src + +* FLYCHECK +Install =luacheck= from your Linux distro's repositories for flycheck to work correctly with lua files. Install =python-pylint= for flycheck to work with python files. Haskell works with flycheck as long as =haskell-ghc= or =haskell-stack-ghc= is installed. For more information on language support for flycheck, [[https://www.flycheck.org/en/latest/languages.html][read this]]. + +#+begin_src emacs-lisp +(use-package flycheck + :ensure t + :defer t + :diminish + :init (global-flycheck-mode)) + +#+end_src + +* FONTS +Defining the various fonts that Emacs will use. + +** Setting the Font Face +#+begin_src emacs-lisp +(set-face-attribute 'default nil + :font "JetBrains Mono" + :height 110 + :weight 'medium) +(set-face-attribute 'variable-pitch nil + :font "Ubuntu" + :height 120 + :weight 'medium) +(set-face-attribute 'fixed-pitch nil + :font "JetBrains Mono" + :height 110 + :weight 'medium) +;; Makes commented text and keywords italics. +;; This is working in emacsclient but not emacs. +;; Your font must have an italic face available. +(set-face-attribute 'font-lock-comment-face nil + :slant 'italic) +(set-face-attribute 'font-lock-keyword-face nil + :slant 'italic) + +;; This sets the default font on all graphical frames created after restarting Emacs. +;; Does the same thing as 'set-face-attribute default' above, but emacsclient fonts +;; are not right unless I also add this method of setting the default font. +(add-to-list 'default-frame-alist '(font . "JetBrains Mono-11")) + +;; Uncomment the following line if line spacing needs adjusting. +(setq-default line-spacing 0.12) +(set-face-background 'mouse "#ffffff") + +#+end_src + +** Zooming In/Out +You can use the bindings CTRL plus =/- for zooming in/out. You can also use CTRL plus the +mouse wheel for zooming in/out. + +#+begin_src emacs-lisp +(global-set-key (kbd "C-=") 'text-scale-increase) +(global-set-key (kbd "C--") 'text-scale-decrease) +(global-set-key (kbd "") 'text-scale-increase) +(global-set-key (kbd "") 'text-scale-decrease) +#+end_src + +** Nerd Fonts For Modeline +#+begin_src emacs-lisp +(use-package nerd-icons + ;; :custom + ;; The Nerd Font you want to use in GUI + ;; "Symbols Nerd Font Mono" is the default and is recommended + ;; but you can use any other Nerd Font if you want + ;; (nerd-icons-font-family "Symbols Nerd Font Mono") + ) +#+end_src + +* GENERAL KEYBINDINGS +#+begin_src emacs-lisp +(use-package general + :config + (general-evil-setup) + + ;; set up 'SPC' as the global leader key + (general-create-definer dt/leader-keys + :states '(normal insert visual emacs) + :keymaps 'override + :prefix "SPC" ;; set leader + :global-prefix "M-SPC") ;; access leader in insert mode + + (dt/leader-keys + "SPC" '(counsel-M-x :wk "Counsel M-x") + "." '(find-file :wk "Find file") + "=" '(perspective-map :wk "Perspective") ;; Lists all the perspective keybindings + "TAB TAB" '(comment-line :wk "Comment lines") + "u" '(universal-argument :wk "Universal argument")) + + (dt/leader-keys + "a" '(:ignore t :wk "A.I.") + "a a" '(ellama-ask-about :wk "Ask ellama about region") + "a e" '(:ignore t :wk "Ellama enhance") + "a e g" '(ellama-improve-grammar :wk "Ellama enhance wording") + "a e w" '(ellama-improve-wording :wk "Ellama enhance grammar") + "a i" '(ellama-chat :wk "Ask ellama") + "a p" '(ellama-provider-select :wk "Ellama provider select") + "a s" '(ellama-summarize :wk "Ellama summarize region") + "a t" '(ellama-translate :wk "Ellama translate region")) + + (dt/leader-keys + "b" '(:ignore t :wk "Bookmarks/Buffers") + "b b" '(switch-to-buffer :wk "Switch to buffer") + "b c" '(clone-indirect-buffer :wk "Create indirect buffer copy in a split") + "b C" '(clone-indirect-buffer-other-window :wk "Clone indirect buffer in new window") + "b d" '(bookmark-delete :wk "Delete bookmark") + "b i" '(ibuffer :wk "Ibuffer") + "b k" '(kill-current-buffer :wk "Kill current buffer") + "b K" '(kill-some-buffers :wk "Kill multiple buffers") + "b l" '(list-bookmarks :wk "List bookmarks") + "b m" '(bookmark-set :wk "Set bookmark") + "b n" '(next-buffer :wk "Next buffer") + "b p" '(previous-buffer :wk "Previous buffer") + "b r" '(revert-buffer :wk "Reload buffer") + "b R" '(rename-buffer :wk "Rename buffer") + "b s" '(basic-save-buffer :wk "Save buffer") + "b S" '(save-some-buffers :wk "Save multiple buffers") + "b w" '(bookmark-save :wk "Save current bookmarks to bookmark file")) + + (dt/leader-keys + "d" '(:ignore t :wk "Dired") + "d d" '(dired :wk "Open dired") + "d f" '(wdired-finish-edit :wk "Writable dired finish edit") + "d j" '(dired-jump :wk "Dired jump to current") + "d n" '(neotree-dir :wk "Open directory in neotree") + "d p" '(peep-dired :wk "Peep-dired") + "d w" '(wdired-change-to-wdired-mode :wk "Writable dired")) + + (dt/leader-keys + "e" '(:ignore t :wk "Ediff/Eshell/Eval/EWW") + "e b" '(eval-buffer :wk "Evaluate elisp in buffer") + "e d" '(eval-defun :wk "Evaluate defun containing or after point") + "e e" '(eval-expression :wk "Evaluate and elisp expression") + "e f" '(ediff-files :wk "Run ediff on a pair of files") + "e F" '(ediff-files3 :wk "Run ediff on three files") + "e h" '(counsel-esh-history :which-key "Eshell history") + "e l" '(eval-last-sexp :wk "Evaluate elisp expression before point") + "e n" '(eshell-new :wk "Create new eshell buffer") + "e r" '(eval-region :wk "Evaluate elisp in region") + "e R" '(eww-reload :which-key "Reload current page in EWW") + "e s" '(eshell :which-key "Eshell") + "e w" '(eww :which-key "EWW emacs web wowser")) + + (dt/leader-keys + "f" '(:ignore t :wk "Files") + "f c" '((lambda () (interactive) + (find-file "~/.config/emacs/config.org")) + :wk "Open emacs config.org") + "f e" '((lambda () (interactive) + (dired "~/.config/emacs/")) + :wk "Open user-emacs-directory in dired") + "f d" '(find-grep-dired :wk "Search for string in files in DIR") + "f g" '(counsel-grep-or-swiper :wk "Search for string current file") + "f i" '((lambda () (interactive) + (find-file "~/.config/emacs/init.el")) + :wk "Open emacs init.el") + "f j" '(counsel-file-jump :wk "Jump to a file below current directory") + "f l" '(counsel-locate :wk "Locate a file") + "f r" '(counsel-recentf :wk "Find recent files") + "f u" '(sudo-edit-find-file :wk "Sudo find file") + "f U" '(sudo-edit :wk "Sudo edit file")) + + (dt/leader-keys + "g" '(:ignore t :wk "Git") + "g /" '(magit-dispatch :wk "Magit dispatch") + "g ." '(magit-file-dispatch :wk "Magit file dispatch") + "g b" '(magit-branch-checkout :wk "Switch branch") + "g c" '(:ignore t :wk "Create") + "g c b" '(magit-branch-and-checkout :wk "Create branch and checkout") + "g c c" '(magit-commit-create :wk "Create commit") + "g c f" '(magit-commit-fixup :wk "Create fixup commit") + "g C" '(magit-clone :wk "Clone repo") + "g f" '(:ignore t :wk "Find") + "g f c" '(magit-show-commit :wk "Show commit") + "g f f" '(magit-find-file :wk "Magit find file") + "g f g" '(magit-find-git-config-file :wk "Find gitconfig file") + "g F" '(magit-fetch :wk "Git fetch") + "g g" '(magit-status :wk "Magit status") + "g i" '(magit-init :wk "Initialize git repo") + "g l" '(magit-log-buffer-file :wk "Magit buffer log") + "g r" '(vc-revert :wk "Git revert file") + "g s" '(magit-stage-file :wk "Git stage file") + "g t" '(git-timemachine :wk "Git time machine") + "g u" '(magit-stage-file :wk "Git unstage file")) + + (dt/leader-keys + "h" '(:ignore t :wk "Help") + "h a" '(counsel-apropos :wk "Apropos") + "h b" '(describe-bindings :wk "Describe bindings") + "h c" '(describe-char :wk "Describe character under cursor") + "h d" '(:ignore t :wk "Emacs documentation") + "h d a" '(about-emacs :wk "About Emacs") + "h d d" '(view-emacs-debugging :wk "View Emacs debugging") + "h d f" '(view-emacs-FAQ :wk "View Emacs FAQ") + "h d m" '(info-emacs-manual :wk "The Emacs manual") + "h d n" '(view-emacs-news :wk "View Emacs news") + "h d o" '(describe-distribution :wk "How to obtain Emacs") + "h d p" '(view-emacs-problems :wk "View Emacs problems") + "h d t" '(view-emacs-todo :wk "View Emacs todo") + "h d w" '(describe-no-warranty :wk "Describe no warranty") + "h e" '(view-echo-area-messages :wk "View echo area messages") + "h f" '(describe-function :wk "Describe function") + "h F" '(describe-face :wk "Describe face") + "h g" '(describe-gnu-project :wk "Describe GNU Project") + "h i" '(info :wk "Info") + "h I" '(describe-input-method :wk "Describe input method") + "h k" '(describe-key :wk "Describe key") + "h l" '(view-lossage :wk "Display recent keystrokes and the commands run") + "h L" '(describe-language-environment :wk "Describe language environment") + "h m" '(describe-mode :wk "Describe mode") + "h r" '(:ignore t :wk "Reload") + "h r r" '((lambda () (interactive) + (load-file "~/.config/emacs/init.el") + (ignore (elpaca-process-queues))) + :wk "Reload emacs config") + "h t" '(load-theme :wk "Load theme") + "h v" '(describe-variable :wk "Describe variable") + "h w" '(where-is :wk "Prints keybinding for command if set") + "h x" '(describe-command :wk "Display full documentation for command")) + + (dt/leader-keys + "m" '(:ignore t :wk "Org") + "m a" '(org-agenda :wk "Org agenda") + "m e" '(org-export-dispatch :wk "Org export dispatch") + "m i" '(org-toggle-item :wk "Org toggle item") + "m t" '(org-todo :wk "Org todo") + "m B" '(org-babel-tangle :wk "Org babel tangle") + "m T" '(org-todo-list :wk "Org todo list")) + + (dt/leader-keys + "m b" '(:ignore t :wk "Tables") + "m b -" '(org-table-insert-hline :wk "Insert hline in table")) + + (dt/leader-keys + "m d" '(:ignore t :wk "Date/deadline") + "m d t" '(org-time-stamp :wk "Org time stamp")) + + (dt/leader-keys + "o" '(:ignore t :wk "Open") + "o d" '(dashboard-open :wk "Dashboard") + "o e" '(elfeed :wk "Elfeed RSS") + "o f" '(make-frame :wk "Open buffer in new frame") + "o F" '(select-frame-by-name :wk "Select frame by name")) + + ;; projectile-command-map already has a ton of bindings + ;; set for us, so no need to specify each individually. + (dt/leader-keys + "p" '(projectile-command-map :wk "Projectile")) + + (dt/leader-keys + "r" '(:ignore t :wk "Radio") + "r p" '(eradio-play :wk "Eradio play") + "r s" '(eradio-stop :wk "Eradio stop") + "r t" '(eradio-toggle :wk "Eradio toggle")) + + + (dt/leader-keys + "s" '(:ignore t :wk "Search") + "s d" '(dictionary-search :wk "Search dictionary") + "s m" '(man :wk "Man pages") + "s o" '(pdf-occur :wk "Pdf search lines matching STRING") + "s t" '(tldr :wk "Lookup TLDR docs for a command") + "s w" '(woman :wk "Similar to man but doesn't require man")) + + (dt/leader-keys + "t" '(:ignore t :wk "Toggle") + "t e" '(eshell-toggle :wk "Toggle eshell") + "t f" '(flycheck-mode :wk "Toggle flycheck") + "t l" '(display-line-numbers-mode :wk "Toggle line numbers") + "t n" '(neotree-toggle :wk "Toggle neotree file viewer") + "t o" '(org-mode :wk "Toggle org mode") + "t r" '(rainbow-mode :wk "Toggle rainbow mode") + "t t" '(visual-line-mode :wk "Toggle truncated lines") + "t v" '(vterm-toggle :wk "Toggle vterm")) + + (dt/leader-keys + "w" '(:ignore t :wk "Windows/Words") + ;; Window splits + "w c" '(evil-window-delete :wk "Close window") + "w n" '(evil-window-new :wk "New window") + "w s" '(evil-window-split :wk "Horizontal split window") + "w v" '(evil-window-vsplit :wk "Vertical split window") + ;; Window motions + "w h" '(evil-window-left :wk "Window left") + "w j" '(evil-window-down :wk "Window down") + "w k" '(evil-window-up :wk "Window up") + "w l" '(evil-window-right :wk "Window right") + "w w" '(evil-window-next :wk "Goto next window") + ;; Move Windows + "w H" '(buf-move-left :wk "Buffer move left") + "w J" '(buf-move-down :wk "Buffer move down") + "w K" '(buf-move-up :wk "Buffer move up") + "w L" '(buf-move-right :wk "Buffer move right") + ;; Words + "w d" '(downcase-word :wk "Downcase word") + "w u" '(upcase-word :wk "Upcase word") + "w =" '(count-words :wk "Count words/lines for buffer")) +) + +#+end_src + +* GIT PROGRAMS +** Git Time Machine +[[https://github.com/emacsmirror/git-timemachine][git-timemachine]] is a program that allows you to move backwards and forwards through a file's commits. 'SPC g t' will open the time machine on a file if it is in a git repo. Then, while in normal mode, you can use 'CTRL-j' and 'CTRL-k' to move backwards and forwards through the commits. + + +#+begin_src emacs-lisp +(use-package git-timemachine + :after git-timemachine + :hook (evil-normalize-keymaps . git-timemachine-hook) + :config + (evil-define-key 'normal git-timemachine-mode-map (kbd "C-j") 'git-timemachine-show-previous-revision) + (evil-define-key 'normal git-timemachine-mode-map (kbd "C-k") 'git-timemachine-show-next-revision) +) +#+end_src + +* HIGHLIGHT TODO +Adding highlights to TODO and related words. + +#+begin_src emacs-lisp +(use-package hl-todo + :hook ((org-mode . hl-todo-mode) + (prog-mode . hl-todo-mode)) + :config + (setq hl-todo-highlight-punctuation ":" + hl-todo-keyword-faces + `(("TODO" warning bold) + ("FIXME" error bold) + ("HACK" font-lock-constant-face bold) + ("REVIEW" font-lock-keyword-face bold) + ("NOTE" success bold) + ("DEPRECATED" font-lock-doc-face bold)))) + +#+end_src + +* IVY (COUNSEL) ++ Ivy, a generic completion mechanism for Emacs. ++ Counsel, a collection of Ivy-enhanced versions of common Emacs commands. ++ Ivy-rich allows us to add descriptions alongside the commands in M-x. + +#+begin_src emacs-lisp +(use-package counsel + :after ivy + :diminish + :config + (counsel-mode) + (setq ivy-initial-inputs-alist nil)) ;; removes starting ^ regex in M-x + +(use-package ivy + :bind + ;; ivy-resume resumes the last Ivy-based completion. + (("C-c C-r" . ivy-resume) + ("C-x B" . ivy-switch-buffer-other-window)) + :diminish + :custom + (setq ivy-use-virtual-buffers t) + (setq ivy-count-format "(%d/%d) ") + (setq enable-recursive-minibuffers t) + :config + (ivy-mode)) + +(use-package all-the-icons-ivy-rich + :ensure t + :init (all-the-icons-ivy-rich-mode 1)) + +(use-package ivy-rich + :after ivy + :ensure t + :init (ivy-rich-mode 1) ;; this gets us descriptions in M-x. + :custom + (ivy-virtual-abbreviate 'full + ivy-rich-switch-buffer-align-virtual-buffer t + ivy-rich-path-style 'abbrev) + :config + (ivy-set-display-transformer 'ivy-switch-buffer + 'ivy-rich-switch-buffer-transformer)) + +#+end_src + +* LANGUAGE SUPPORT +Emacs has built-in programming language modes for Lisp, Scheme, DSSSL, Ada, ASM, AWK, C, C++, Fortran, Icon, IDL (CORBA), IDLWAVE, Java, Javascript, M4, Makefiles, Metafont, Modula2, Object Pascal, Objective-C, Octave, Pascal, Perl, Pike, PostScript, Prolog, Python, Ruby, Simula, SQL, Tcl, Verilog, and VHDL. Other languages will require you to install additional modes. + +#+begin_src emacs-lisp +(use-package dart-mode) +(use-package haskell-mode) +(use-package lua-mode) +(use-package php-mode) + +#+end_src + +* MINIBUFFER ESCAPE +By default, Emacs requires you to hit ESC three times to escape quit the minibuffer. + +#+begin_src emacs-lisp +(global-set-key [escape] 'keyboard-escape-quit) +#+end_src + +* MODELINE +The modeline is the bottom status bar that appears in Emacs windows. While you can create your own custom modeline, why go to the trouble when Doom Emacs already has a nice modeline package available. For more information on what is available to configure in the Doom modeline, check out: [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] + +#+begin_src emacs-lisp +(use-package doom-modeline + :ensure t + :init (doom-modeline-mode 1) + :config + (setq doom-modeline-height 35 ;; sets modeline height + doom-modeline-bar-width 5 ;; sets right bar width + doom-modeline-persp-name t ;; adds perspective name to modeline + doom-modeline-persp-icon t)) ;; adds folder icon next to persp name + +#+end_src + +* NEOTREE +Neotree is a file tree viewer. When you open neotree, it jumps to the current file thanks to neo-smart-open. The neo-window-fixed-size setting makes the neotree width be adjustable. NeoTree provides following themes: classic, ascii, arrow, icons, and nerd. Theme can be config'd by setting "two" themes for neo-theme: one for the GUI and one for the terminal. I like to use 'SPC t' for 'toggle' keybindings, so I have used 'SPC t n' for toggle-neotree. + +| COMMAND | DESCRIPTION | KEYBINDING | +|----------------+---------------------------+------------| +| neotree-toggle | /Toggle neotree/ | SPC t n | +| neotree- dir | /Open directory in neotree/ | SPC d n | + +#+BEGIN_SRC emacs-lisp +(use-package neotree + :config + (setq neo-smart-open t + neo-show-hidden-files t + neo-window-width 55 + neo-window-fixed-size nil + inhibit-compacting-font-caches t + projectile-switch-project-action 'neotree-projectile-action) + ;; truncate long file names in neotree + (add-hook 'neo-after-create-hook + #'(lambda (_) + (with-current-buffer (get-buffer neo-buffer-name) + (setq truncate-lines t) + (setq word-wrap nil) + (make-local-variable 'auto-hscroll-mode) + (setq auto-hscroll-mode nil))))) + +#+end_src + +* ORG MODE +** Agenda +#+begin_src emacs-lisp +(setq org-agenda-files '("~/.config/emacs/agenda.org")) +#+end_src + +** Bullets +=Org-bullets= gives us attractive bullets rather than asterisks. + +#+begin_src emacs-lisp +(add-hook 'org-mode-hook 'org-indent-mode) +(use-package org-bullets) +(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))) +#+end_src + +** Diminish Org Indent Mode +Removes "Ind" from showing in the modeline. + +#+begin_src emacs-lisp +(eval-after-load 'org-indent '(diminish 'org-indent-mode)) +#+end_src + +** Org Level Headers +#+begin_src emacs-lisp + (custom-set-faces + '(org-level-1 ((t (:inherit outline-1 :height 1.7)))) + '(org-level-2 ((t (:inherit outline-2 :height 1.6)))) + '(org-level-3 ((t (:inherit outline-3 :height 1.5)))) + '(org-level-4 ((t (:inherit outline-4 :height 1.4)))) + '(org-level-5 ((t (:inherit outline-5 :height 1.3)))) + '(org-level-6 ((t (:inherit outline-5 :height 1.2)))) + '(org-level-7 ((t (:inherit outline-5 :height 1.1))))) +#+end_src + +** Org-Tempo +Org-tempo is not a separate package but a module within org that can be enabled. Org-tempo allows for ' from auto-pairing when electric-pair-mode is on. +;; Otherwise, org-tempo is broken when you try to ") #'pcomplete-list))) + +;; A function for easily creating multiple buffers of 'eshell'. +;; NOTE: `C-u M-x eshell` would also create new 'eshell' buffers. +(defun eshell-new (name) + "Create new eshell buffer named NAME." + (interactive "sName: ") + (setq name (concat "$" name)) + (eshell) + (rename-buffer name)) + +(use-package eshell-toggle + :custom + (eshell-toggle-size-fraction 3) + (eshell-toggle-use-projectile-root t) + (eshell-toggle-run-command nil) + (eshell-toggle-init-function #'eshell-toggle-init-ansi-term)) + + (use-package eshell-syntax-highlighting + :after esh-mode + :config + (eshell-syntax-highlighting-global-mode +1)) + + ;; eshell-syntax-highlighting -- adds fish/zsh-like syntax highlighting. + ;; eshell-rc-script -- your profile for eshell; like a bashrc for eshell. + ;; eshell-aliases-file -- sets an aliases file for the eshell. + + (setq eshell-rc-script (concat user-emacs-directory "eshell/profile") + eshell-aliases-file (concat user-emacs-directory "eshell/aliases") + eshell-history-size 5000 + eshell-buffer-maximum-lines 5000 + eshell-hist-ignoredups t + eshell-scroll-to-bottom-on-input t + eshell-destroy-buffer-when-process-dies t + eshell-visual-commands'("bash" "fish" "htop" "ssh" "top" "zsh")) +#+end_src + +** Vterm +Vterm is a terminal emulator within Emacs. The 'shell-file-name' setting sets the shell to be used in M-x shell, M-x term, M-x ansi-term and M-x vterm. By default, the shell is set to 'fish' but could change it to 'bash' or 'zsh' if you prefer. + +#+begin_src emacs-lisp +(use-package vterm + :ensure t + :config + (setq shell-file-name "/bin/sh" + vterm-max-scrollback 5000)) +#+end_src + +** Vterm-Toggle +[[https://github.com/jixiuf/vterm-toggle][vterm-toggle]] toggles between the vterm buffer and whatever buffer you are editing. + +#+begin_src emacs-lisp +(use-package vterm-toggle + :ensure t + :after vterm + :config + ;; When running programs in Vterm and in 'normal' mode, make sure that ESC + ;; kills the program as it would in most standard terminal programs. + (evil-define-key 'normal vterm-mode-map (kbd "") 'vterm--self-insert) + (setq vterm-toggle-fullscreen-p nil) + (setq vterm-toggle-scope 'project) + (add-to-list 'display-buffer-alist + '((lambda (buffer-or-name _) + (let ((buffer (get-buffer buffer-or-name))) + (with-current-buffer buffer + (or (equal major-mode 'vterm-mode) + (string-prefix-p vterm-buffer-name (buffer-name buffer)))))) + (display-buffer-reuse-window display-buffer-at-bottom) + ;;(display-buffer-reuse-window display-buffer-in-direction) + ;;display-buffer-in-direction/direction/dedicated is added in emacs27 + ;;(direction . bottom) + ;;(dedicated . t) ;dedicated is supported in emacs27 + (reusable-frames . visible) + (window-height . 0.4)))) + +#+end_src + +* SUDO EDIT +[[https://github.com/nflath/sudo-edit][sudo-edit]] gives us the ability to open files with sudo privileges or switch over to editing with sudo privileges if we initially opened the file without such privileges. + +#+begin_src emacs-lisp +(use-package sudo-edit) +#+end_src + +* THEME +The first line below designates the directory where will place all of our custom-made themes, which I have created only one (dtmacs). You can create your own Emacs themes with the help of the [[https://emacsfodder.github.io/emacs-theme-editor/][Emacs Theme Editor]]. I am also installing =doom-themes= because it contains a huge collection of themes. M-x load-theme will list all of the themes available. + +#+begin_src emacs-lisp +(add-to-list 'custom-theme-load-path "~/.config/emacs/themes/") + +(use-package doom-themes + :config + (setq doom-themes-enable-bold t ; if nil, bold is universally disabled + doom-themes-enable-italic t) ; if nil, italics is universally disabled + ;; Sets the default theme to load!!! + (load-theme 'doom-one t) + ;; Enable custom neotree theme (all-the-icons must be installed!) + (doom-themes-neotree-config) + ;; Corrects (and improves) org-mode's native fontification. + (doom-themes-org-config)) +#+end_src + +* TLDR + +#+begin_src emacs-lisp +(use-package tldr) + +#+end_src + +* TRANSPARENCY +With Emacs version 29, true transparency has been added. I have turned transparency off by setting the alpha to '100'. If you want some slight transparency, try setting alpha to '90'. Of course, if you set alpha to '0', the background of Emacs would completely transparent. + +#+begin_src emacs-lisp +(add-to-list 'default-frame-alist '(alpha-background . 100)) ; For all new frames henceforth + +#+end_src + +* WHICH-KEY +#+begin_src emacs-lisp +(use-package which-key + :init + (which-key-mode 1) + :diminish + :config + (setq which-key-side-window-location 'bottom + which-key-sort-order #'which-key-key-order-alpha + which-key-allow-imprecise-window-fit nil + which-key-sort-uppercase-first nil + which-key-add-column-padding 1 + which-key-max-display-columns nil + which-key-min-display-lines 6 + which-key-side-window-slot -10 + which-key-side-window-max-height 0.25 + which-key-idle-delay 0.8 + which-key-max-description-length 25 + which-key-allow-imprecise-window-fit nil + which-key-separator " → " )) +#+end_src + +* TEST +#+begin_src emacs-lisp +(defun reader () + (interactive) + (let ((choices '(("First" . "Hi!") + ("Second" . 'second-choice) + ("Third" . 'third-choice)))) + (alist-get + (completing-read "Choose: " choices) + choices nil nil 'message))) + +(defun github-code-search () + "Search code on github for a given language." + (interactive) + (let ((language (completing-read + "Language: " + '("Emacs Lisp" "Python" "Clojure" "R"))) + (code (read-string "Code: "))) + (browse-url + (concat "https://github.com/search?l=" language + "&type=code&q=" code)))) + +(defun dm-search () + "Search various search engines." + (interactive) + (let ((engine (completing-read + "Search Engine: " + '("Arch Wiki" + "Bing" + "Google" + "Wikipedia"))) + (query (read-string "Query: "))) + (if (equal engine "Google") + (browse-url + (concat "https://www.google.com/search?q=" query))))) + +(defun dt/key-value-completing (choice) + (interactive + (list + (let ((completions '(("1" "One") + ("2" "Two") + ("3" "Three")))) + (cadr (assoc (completing-read "Choose: " completions) completions))))) + (message "You choose `%s'" choice)) + +#+end_src diff --git a/.config/emacs/early-init.el b/.config/emacs/early-init.el index 4859fe2..512068a 100644 --- a/.config/emacs/early-init.el +++ b/.config/emacs/early-init.el @@ -1,150 +1 @@ -;;; early-init.el --- Doom's universal bootstrapper -*- lexical-binding: t -*- -;;; Commentary: -;; -;; This file, in summary: -;; - Determines where `user-emacs-directory' is by: -;; - Processing `--init-directory DIR' (backported from Emacs 29), -;; - Processing `--profile NAME' (see -;; `https://docs.doomemacs.org/-/developers' or docs/developers.org), -;; - Or assume that it's the directory this file lives in. -;; - Loads Doom as efficiently as possible, with only the essential startup -;; optimizations, and prepares it for interactive or non-interactive sessions. -;; - If Doom isn't present, then we assume that Doom is being used as a -;; bootloader and the user wants to load a non-Doom config, so we undo all our -;; global side-effects, load `user-emacs-directory'/early-init.el, and carry -;; on as normal (without Doom). -;; - Do all this without breaking compatibility with Chemacs. -;; -;; early-init.el was introduced in Emacs 27.1. It is loaded before init.el, -;; before Emacs initializes its UI or package.el, and before site files are -;; loaded. This is great place for startup optimizing, because only here can you -;; *prevent* things from loading, rather than turn them off after-the-fact. -;; -;; Doom uses this file as its "universal bootstrapper" for both interactive and -;; non-interactive sessions. That means: no matter what environment you want -;; Doom in, load this file first. -;; -;;; Code: - -(let (file-name-handler-alist) - ;; PERF: Garbage collection is a big contributor to startup times in both - ;; interactive and CLI sessions, so I defer it. - (if noninteractive ; in CLI sessions - ;; PERF: GC deferral is less important in the CLI, but still helps script - ;; startup times. Just don't set it too high to avoid runaway memory - ;; usage in long-running elisp shell scripts. - (setq gc-cons-threshold 134217728 ; 128mb - ;; Backported from 29 (see emacs-mirror/emacs@73a384a98698) - gc-cons-percentage 1.0) - ;; PERF: Doom relies on `gcmh-mode' to reset this while the user is idle, so - ;; I effectively disable GC during startup. DON'T COPY THIS BLINDLY! If - ;; it's not reset later there will be stuttering, freezes, and crashes. - (setq gc-cons-threshold most-positive-fixnum)) - - ;; PERF: Don't use precious startup time to check mtimes on elisp bytecode. - ;; Ensuring correctness is 'doom sync's job. Although stale byte-code will - ;; heavily impact startup times, performance is unimportant when Emacs is in - ;; an error state. - (setq load-prefer-newer noninteractive) - - ;; UX: Respect DEBUG envvar as an alternative to --debug-init, and to make - ;; startup more verbose sooner. - (let ((debug (getenv-internal "DEBUG"))) - (when (stringp debug) - (if (string-empty-p debug) - (setenv "DEBUG" nil) - (setq init-file-debug t - debug-on-error t)))) - - (let (;; FIX: Unset `command-line-args' in noninteractive sessions, to - ;; ensure upstream switches aren't misinterpreted. - (command-line-args (unless noninteractive command-line-args)) - ;; I avoid using `command-switch-alist' to process --profile (and - ;; --init-directory) because it is processed too late to change - ;; `user-emacs-directory' in time. - (profile (or (cadr (member "--profile" command-line-args)) - (getenv-internal "DOOMPROFILE")))) - (if (null profile) - ;; REVIEW: Backported from Emacs 29. Remove when 28 support is dropped. - (let ((init-dir (or (cadr (member "--init-directory" command-line-args)) - (getenv-internal "EMACSDIR")))) - (if (null init-dir) - ;; FIX: If we've been loaded directly (via 'emacs -batch -l - ;; early-init.el') or by a doomscript (like bin/doom), and Doom - ;; is in a non-standard location (and/or Chemacs is used), then - ;; `user-emacs-directory' will be wrong. - (when noninteractive - (setq user-emacs-directory - (file-name-directory (file-truename load-file-name)))) - ;; FIX: To prevent "invalid option" errors later. - (push (cons "--init-directory" (lambda (_) (pop argv))) command-switch-alist) - (setq user-emacs-directory (expand-file-name init-dir)))) - ;; FIX: Discard the switch to prevent "invalid option" errors later. - (push (cons "--profile" (lambda (_) (pop argv))) command-switch-alist) - ;; Running 'doom sync' or 'doom profile sync --all' (re)generates a light - ;; profile loader in $XDG_DATA_HOME/doom/profiles.X.el (or - ;; $DOOMPROFILELOADFILE), after reading `doom-profile-load-path'. This - ;; loader requires `$DOOMPROFILE' be set to function. - (setenv "DOOMPROFILE" profile) - (or (load (let ((windows? (memq system-type '(ms-dos windows-nt cygwin)))) - (expand-file-name - (format (or (getenv-internal "DOOMPROFILELOADFILE") - (file-name-concat (if windows? "doomemacs/data" "doom") - "profiles.%d")) - emacs-major-version) - (or (if windows? (getenv-internal "LOCALAPPDATA")) - (getenv-internal "XDG_DATA_HOME") - "~/.local/share"))) - 'noerror (not init-file-debug)) - (user-error "Profiles not initialized yet; run 'doom sync' first")))) - - ;; PERF: When `load'ing or `require'ing files, each permutation of - ;; `load-suffixes' and `load-file-rep-suffixes' (then `load-suffixes' + - ;; `load-file-rep-suffixes') is used to locate the file. Each permutation - ;; amounts to at least one file op, which is normally very fast, but can add - ;; up over the hundreds/thousands of files Emacs loads. - ;; - ;; To reduce that burden -- and since Doom doesn't load any dynamic modules - ;; this early -- I remove `.so' from `load-suffixes' and pass the - ;; `must-suffix' arg to `load'. See the docs of `load' for details. - (if (let ((load-suffixes '(".elc" ".el")) - (doom (expand-file-name "lisp/doom" user-emacs-directory))) - ;; I avoid `load's NOERROR argument because it suppresses other, - ;; legitimate errors (like permission or IO errors), which gets - ;; incorrectly interpreted as "this is not a Doom config". - (if (file-exists-p (concat doom ".el")) - ;; Load the heart of Doom Emacs. - (load doom nil (not init-file-debug) nil 'must-suffix) - ;; Failing that, assume we're loading a non-Doom config... - ;; HACK: `startup--load-user-init-file' resolves $EMACSDIR from a - ;; lexical (and so, not-trivially-modifiable) - ;; `startup-init-directory', so Emacs will fail to locate the - ;; correct $EMACSDIR/init.el without help. - (define-advice startup--load-user-init-file (:filter-args (args) reroute-to-profile) - (list (lambda () (expand-file-name "init.el" user-emacs-directory)) - nil (nth 2 args))) - ;; (Re)set `user-init-file' for the `load' call further below, and do - ;; so here while our `file-name-handler-alist' optimization is still - ;; effective (benefits `expand-file-name'). BTW: Emacs resets - ;; `user-init-file' and `early-init-file' after this file is loaded. - (setq user-init-file (expand-file-name "early-init" user-emacs-directory)) - ;; COMPAT: I make no assumptions about the config we're going to load, - ;; so undo this file's global side-effects. - (setq load-prefer-newer t) - ;; PERF: But make an exception for `gc-cons-threshold', which I think - ;; all Emacs users and configs will benefit from. Still, setting it - ;; to `most-positive-fixnum' is dangerous if downstream does not - ;; reset it later to something reasonable, so I use 16mb as a best - ;; fit guess. It's better than Emacs' 80kb default. - (setq gc-cons-threshold (* 16 1024 1024)) - nil)) - ;; Sets up Doom (particularly `doom-profile') for the session ahead. This - ;; loads the profile's init file, if it's available. In interactive - ;; session, a missing profile is an error state, in a non-interactive one, - ;; it's not (and left to the consumer to deal with). - (doom-initialize (not noninteractive)) - ;; If we're here, the user wants to load another config/profile (that may or - ;; may not be a Doom config). - (load user-init-file 'noerror (not init-file-debug) nil 'must-suffix))) - -;;; early-init.el ends here +(setq package-enable-at-startup nil) diff --git a/.config/emacs/eshell/aliases b/.config/emacs/eshell/aliases new file mode 100644 index 0000000..2dac14d --- /dev/null +++ b/.config/emacs/eshell/aliases @@ -0,0 +1,23 @@ +# Aliases for emacs commands +alias ff find-file $1 + +# Aliasing standard shell commands to better emacs alternatives +alias less view-file $1 + +# Changing "ls" to "exa" +alias ls eza -al --color=always --group-directories-first $* # my preferred listing +alias la eza -a --color=always --group-directories-first $* # all files and dirs +alias ll eza -l --color=always --group-directories-first $* # long format +alias lt eza -aT --color=always --group-directories-first $* # tree listing +alias l. eza -a1 $* | grep "^\." # list hidden files + +# Merge Xresources +alias merge xrdb -merge ~/.Xresources + +# Confirm before overwriting something +alias cp cp -i $1 +alias mv mv -i $1 +alias rm rm -i $1 + +# Bare git repo alias for dotfiles +alias config /usr/bin/git --git-dir=$HOME/dotfiles --work-tree=$HOME $* diff --git a/.config/emacs/eshell/profile b/.config/emacs/eshell/profile new file mode 100644 index 0000000..3c871d6 --- /dev/null +++ b/.config/emacs/eshell/profile @@ -0,0 +1 @@ +colorscript random \ No newline at end of file diff --git a/.config/emacs/init.el b/.config/emacs/init.el new file mode 100644 index 0000000..ff20d92 --- /dev/null +++ b/.config/emacs/init.el @@ -0,0 +1,4 @@ +(org-babel-load-file + (expand-file-name + "config.org" + user-emacs-directory)) diff --git a/.config/emacs/scripts/app-launchers.el b/.config/emacs/scripts/app-launchers.el new file mode 100644 index 0000000..7536a87 --- /dev/null +++ b/.config/emacs/scripts/app-launchers.el @@ -0,0 +1,56 @@ +;;; app-launchers.el --- Possible alternatives to dmenu/rofi + +;;; Code: + +;; Counsel-Linux-App +;; Since we have counsel installed, we can use 'counsel-linux-app' to launch our Linux apps. It list the apps by their executable command, so it's kind of tricky to use. + +(defun dt/emacs-counsel-launcher () + "Create and select a frame called emacs-counsel-launcher which consists only of a minibuffer and has specific dimensions. Runs counsel-linux-app on that frame, which is an emacs command that prompts you to select an app and open it in a dmenu like behaviour. Delete the frame after that command has exited" + (interactive) + (with-selected-frame + (make-frame '((name . "emacs-run-launcher") + (minibuffer . only) + (fullscreen . 0) ; no fullscreen + (undecorated . t) ; remove title bar + ;;(auto-raise . t) ; focus on this frame + ;;(tool-bar-lines . 0) + ;;(menu-bar-lines . 0) + (internal-border-width . 10) + (width . 80) + (height . 11))) + (unwind-protect + (counsel-linux-app) + (delete-frame)))) + + +;; App-Launcher +;; The 'app-launcher' is a better run launcher since it reads the desktop applications on your system and you can search them by their names as defined in their desktop file. This means that sometimes you have to search for a generic term rather than the actual binary command of the program. + +(use-package app-launcher + :ensure '(app-launcher :host github :repo "SebastienWae/app-launcher")) +;; create a global keyboard shortcut with the following code +;; emacsclient -cF "((visibility . nil))" -e "(emacs-run-launcher)" + +(defun dt/emacs-run-launcher () + "Create and select a frame called emacs-run-launcher which consists only of a minibuffer and has specific dimensions. Runs app-launcher-run-app on that frame, which is an emacs command that prompts you to select an app and open it in a dmenu like behaviour. Delete the frame after that command has exited" + (interactive) + (with-selected-frame + (make-frame '((name . "emacs-run-launcher") + (minibuffer . only) + (fullscreen . 0) ; no fullscreen + (undecorated . t) ; remove title bar + ;;(auto-raise . t) ; focus on this frame + ;;(tool-bar-lines . 0) + ;;(menu-bar-lines . 0) + (internal-border-width . 10) + (width . 80) + (height . 11))) + (unwind-protect + (app-launcher-run-app) + (delete-frame)))) + + +(provide 'app-launchers) +;;; app-launchers.el ends here + diff --git a/.config/emacs/scripts/buffer-move.el b/.config/emacs/scripts/buffer-move.el new file mode 100644 index 0000000..5dcde11 --- /dev/null +++ b/.config/emacs/scripts/buffer-move.el @@ -0,0 +1,101 @@ +;;; buffer-move.el --- Buffer move allows for better window controls. + +;; Copyright (C) 2004-2014 Lucas Bonnet + +;; Author: Lucas Bonnet +;; Keywords: lisp,convenience +;; Version: 0.5 +;; URL : https://github.com/lukhas/buffer-move + +;; 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 2 +;; 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, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA. + +;;; Commentary: + +;; This file is for lazy people wanting to swap buffers without +;; typing C-x b on each window. + +;;; Code: +(require 'windmove) + +;;;###autoload +(defun buf-move-up () + "Swap the current buffer and the buffer above the split. +If there is no split, ie now window above the current one, an +error is signaled." +;; "Switches between the current buffer, and the buffer above the +;; split, if possible." + (interactive) + (let* ((other-win (windmove-find-other-window 'up)) + (buf-this-buf (window-buffer (selected-window)))) + (if (null other-win) + (error "No window above this one") + ;; swap top with this one + (set-window-buffer (selected-window) (window-buffer other-win)) + ;; move this one to top + (set-window-buffer other-win buf-this-buf) + (select-window other-win)))) + +;;;###autoload +(defun buf-move-down () +"Swap the current buffer and the buffer under the split. +If there is no split, ie now window under the current one, an +error is signaled." + (interactive) + (let* ((other-win (windmove-find-other-window 'down)) + (buf-this-buf (window-buffer (selected-window)))) + (if (or (null other-win) + (string-match "^ \\*Minibuf" (buffer-name (window-buffer other-win)))) + (error "No window under this one") + ;; swap top with this one + (set-window-buffer (selected-window) (window-buffer other-win)) + ;; move this one to top + (set-window-buffer other-win buf-this-buf) + (select-window other-win)))) + +;;;###autoload +(defun buf-move-left () +"Swap the current buffer and the buffer on the left of the split. +If there is no split, ie now window on the left of the current +one, an error is signaled." + (interactive) + (let* ((other-win (windmove-find-other-window 'left)) + (buf-this-buf (window-buffer (selected-window)))) + (if (null other-win) + (error "No left split") + ;; swap top with this one + (set-window-buffer (selected-window) (window-buffer other-win)) + ;; move this one to top + (set-window-buffer other-win buf-this-buf) + (select-window other-win)))) + +;;;###autoload +(defun buf-move-right () +"Swap the current buffer and the buffer on the right of the split. +If there is no split, ie now window on the right of the current +one, an error is signaled." + (interactive) + (let* ((other-win (windmove-find-other-window 'right)) + (buf-this-buf (window-buffer (selected-window)))) + (if (null other-win) + (error "No right split") + ;; swap top with this one + (set-window-buffer (selected-window) (window-buffer other-win)) + ;; move this one to top + (set-window-buffer other-win buf-this-buf) + (select-window other-win)))) + +(provide 'buffer-move) +;;; buffer-move.el ends here diff --git a/.config/emacs/scripts/dtos-start.el b/.config/emacs/scripts/dtos-start.el new file mode 100644 index 0000000..852fe30 --- /dev/null +++ b/.config/emacs/scripts/dtos-start.el @@ -0,0 +1,702 @@ +;;; dtos-start.el --- Some recipes for creating widgets + +;; Copyright 2007 Ye Wenbin +;; +;; Author: wenbinye@gmail.com +;; Version: $Id: widget-demo.el,v 0.0 2007/11/13 17:50:14 ywb Exp $ +;; Keywords: +;; X-URL: not distributed yet + +;; 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 2, 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, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: +;; The widget document is not easy to understand. I think the +;; quick way to use widget is learning from examples. So I wrote +;; this library to help others understand and use widget quickly. +;; +;; I'm not expert at widget, so there may be something wrong in the +;; code. If you found it, please let me know. +;; + +;;; Add New Page: +;; You can test you widget definition by add it as a new page to +;; widget demo. You can benefit from without write the code to +;; creating buffer and the key bindings of `widget-demo-mode'. Here is +;; a simple example to add new widget demo page: +;; +;; (defun widget-demo-tree-test () +;; (widget-insert "Tree:\n") +;; (widget-create +;; '(tree-widget +;; :node (push-button :format "%[%t%]\n" :tag "hello") +;; :open t +;; (push-button :format "%[%t%]\n" :tag "node1") +;; (push-button :format "%[%t%]\n" :tag "node2")))) +;; (widget-demo-add-page "Tree Test" 'widget-demo-tree-test) + +;;; TODO: +;; 1. Add tree-widget +;; 2. Add complex widget create by using several types of widget and +;; using group. +;; 3. Add tutorial about defining new widget +;; 4. Add a macro for simplified page definition. For example: +;; (widget-demo-insert +;; "Some text here" +;; (button :notify callback "label") +;; "More text" +;; (editable-field :form-id identifier)) + +;; Put this file into your load-path and the following into your ~/.emacs: +;; (autoload 'widget-demo "widget-demo" "Show demo of widget" t) + +;;; Code: + +(eval-when-compile + (require 'cl-lib)) +(require 'info) +(require 'tree-widget) + +(defvar widget-demo-buffer-name "*DTOS Info*" + "*Name of the widget demo buffer") + +(defvar widget-demo-list + '(("Contents" widget-demo-contents :header "DTOS Info") + ("Example" widget-demo-example :header "Example in info") + ("WidgetTree" widget-tree :header "Programs") + ("Button" widget-demo-button) + ("Text" widget-demo-text) + ("Choice" widget-demo-choice) + ) + "A list of pages to show.") + +(defvar widget-demo-current nil + "Current page in `widget-demo-list'.") + +(defvar widget-demo-form nil + "A table for lookup widget created in current buffer.") + +(defvar widget-demo-anchors nil + "A table for lookup markers created in current buffer.") + +(defvar widget-demo-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map widget-keymap) + (define-key map "n" 'widget-demo-next) + (define-key map "p" 'widget-demo-previous) + (define-key map "u" 'widget-demo) + (define-key map "t" 'widget-demo) + (dolist (num (number-sequence ?1 ?9)) + (define-key map (char-to-string num) 'widget-demo-goto-page)) + ;; this command may be helpful for debug + (define-key map "r" 'widget-demo-reflesh) + (define-key map "\C-c\C-s" 'widget-demo-show-source) + (define-key map "\C-c\C-n" 'widget-demo-next) + (define-key map "\C-c\C-p" 'widget-demo-previous) + (define-key map "\C-c\C-u" 'widget-demo) + (define-key map "\C-c\C-t" 'widget-demo) + map) + "Keymap to use in *DTOS Info* buffer.") + +(defvar widget-demo-menu nil) +(unless widget-demo-menu + (easy-menu-define + widget-demo-menu widget-demo-mode-map "DTOS Info" + `("Widget" + ["Next Page" widget-demo-next t] + ["Previous Page" widget-demo-previous t] + ["Top" widget-demo t] + ["Refresh" widget-demo-reflesh t] + "--" + ,@(mapcar (lambda (p) + (vector (car p) 'widget-demo-menu-goto t)) + widget-demo-list)))) + +;;{{{ Helper functions +(defun widget-demo-menu-goto () + (interactive) + (widget-demo-goto (symbol-name last-command-event))) + +(defun widget-demo-form-create (id widget) + (if (assoc id widget-demo-form) + (error "identifier %S is used!" id) + (push (cons id widget) widget-demo-form))) + +(defun widget-demo-form-add (id widget) + (let ((old (assoc id widget-demo-form))) + (if old + (setcdr old widget) + (push (cons id widget) widget-demo-form)))) + +(defun widget-demo-form-get (id) + (cdr (assoc id widget-demo-form))) + +(defun widget-demo-create-anchor (anchor) + (push (cons anchor (point-marker)) widget-demo-anchors)) + +(defun widget-demo-resolve-link (name) + "Return the Next, Top, Next page." + (let* ((page (assoc name widget-demo-list)) + (rest (member page widget-demo-list)) + (len (length rest)) + next previous) + ;; the contents only list next + (if (eq page (car widget-demo-list)) + (list (cadr widget-demo-list)) + (if (= len 1) + (setq next nil) + (setq next (cadr rest))) + (setq previous (nth (- (length widget-demo-list) len 1) + widget-demo-list)) + (list next (car widget-demo-list) previous)))) + +(defun widget-demo-add-page (&rest page) + "add new PAGE to widget-demo. +The page is constituted by + + (PAGE-NAME PAGE-DEFINITION [KEYWORD VALUE]). + +Current only keyword :header is supported, which value is a string +to display in menu and the header of buffer instead of the page-name." + (setq widget-demo-list + (append widget-demo-list (list page)))) + +(defun widget-demo-remove-page (name) + (setq widget-demo-list + (delq (assoc name widget-demo-list) + widget-demo-list))) +;;}}} + +;;{{{ Commands +;;;###autoload +(defun dtos-demo () + "Show widget demo." + (interactive) + (switch-to-buffer widget-demo-buffer-name) + (widget-demo-goto "Contents")) + +(define-derived-mode widget-demo-mode nil "WDemo" + "Widget demo. +\\{widget-demo-mode-map}" + (make-local-variable 'widget-demo-form) + (make-local-variable 'widget-demo-anchors)) + +(defun widget-demo-goto (link) + (interactive + (list (completing-read "Goto: " widget-demo-list nil t))) + (switch-to-buffer widget-demo-buffer-name) + (widget-demo-mode) + (setq link (split-string link "#")) + (let* ((inhibit-read-only t) + (name (car link)) + (anchor (cadr link)) + (page (assoc name widget-demo-list))) + (erase-buffer) + (remove-overlays) + (setq widget-demo-current name) + ;; insert buttons + (let ((links (widget-demo-resolve-link name)) + (label '("Next" "Contents" "Prev"))) + (dolist (link links) + (when link + (widget-create 'push-button + :format + (if (string= (car label) "Contents") + "%[Contents%]" + (format "%%t: %%[%s%%]" (car link))) + :button-face 'info-xref + :tag (car label) + :notify (lambda (wid &rest ignore) + (widget-demo-goto (widget-value wid))) + (car link)) + (widget-insert " ")) + (setq label (cdr label)))) + ;; insert title + (widget-insert "\n\n ") + (widget-insert + (propertize + (or (plist-get page :header) (car page)) + 'face 'info-title-1)) + (widget-insert "\n\n") + (funcall (cadr page)) + ;; if there is an anchor, jump to the anchor + (if (and anchor + (setq anchor (assoc-default anchor widget-demo-anchors))) + (goto-char anchor) + (goto-char (point-min))) + (widget-setup) + (use-local-map widget-demo-mode-map))) + +(defun widget-demo-next () + (interactive) + (let ((links (widget-demo-resolve-link widget-demo-current))) + (if (car links) + (widget-demo-goto (caar links)) + (message "No next pages!")))) + +(defun widget-demo-previous () + (interactive) + (let ((links (widget-demo-resolve-link widget-demo-current))) + (if (nth 2 links) + (widget-demo-goto (car (nth 2 links))) + (message "No previous pages!")))) + +(defun widget-demo-goto-page () + (interactive) + (let ((num (- last-command-event ?0))) + (if (< num (length widget-demo-list)) + (widget-demo-goto (car (nth num widget-demo-list))) + (message "Only %d pages!" (length widget-demo-list))))) + +(defun widget-demo-reflesh () + (interactive) + (widget-demo-goto widget-demo-current)) + +(defun widget-demo-show-source () + (interactive) + (let ((page (assoc widget-demo-current widget-demo-list))) + (with-selected-window + (display-buffer + (find-file-noselect (find-library-name "widget-demo"))) + (imenu (symbol-name (cadr page))) + (recenter 1)))) +;;}}} + +;;{{{ Pages +(defun widget-demo-contents () + (widget-insert "Here is the *widget-demo-contents* function in action.\n\n") + (let ((idx 1)) + (dolist (page (cdr widget-demo-list)) + (widget-insert (format "%3d. " idx)) + (widget-create 'link + :format "%[%t%]" + :tag (or (plist-get page :header) (car page)) + :button-prefix "" + :button-suffix "" + :notify (lambda (widget &rest ignore) + (widget-demo-goto (widget-value widget))) + (car page)) + (widget-insert "\n") + (setq idx (1+ idx))))) + +(defun widget-demo-example () + (widget-insert "Here is some documentation.\n\n") + (widget-create 'editable-field + :size 13 + :format "Name: %v " ; Text after the field! + "My Name") + (widget-create 'menu-choice + :tag "Choose" + :value "This" + :help-echo "Choose me, please!" + :notify (lambda (widget &rest ignore) + (message "%s is a good choice!" + (widget-value widget))) + '(item :tag "This option" :value "This") + '(choice-item "That option") + '(editable-field :menu-tag "No option" "Thus option")) + (widget-create 'editable-field + :format "Address: %v" + "Some Place\nIn some City\nSome country.") + (widget-insert "\nSee also ") + (widget-create 'link + :notify (lambda (&rest ignore) + (widget-value-set + (widget-demo-form-get 'repeat) + '("En" "To" "Tre")) + (widget-setup)) + "other work") + (widget-insert + " for more information.\n\nNumbers: count to three below\n") + (widget-demo-form-create + 'repeat + (widget-create 'editable-list + :entry-format "%i %d %v" + :notify (lambda (widget &rest ignore) + (let ((old (widget-get widget + ':example-length)) + (new (length (widget-value widget)))) + (unless (eq old new) + (widget-put widget ':example-length new) + (message "You can count to %d." new)))) + :value '("One" "Eh, two?" "Five!") + '(editable-field :value "three"))) + (widget-insert "\n\nSelect multiple:\n\n") + (widget-create 'checkbox t) + (widget-insert " This\n") + (widget-create 'checkbox nil) + (widget-insert " That\n") + (widget-create 'checkbox + :notify (lambda (&rest ignore) (message "Tickle")) + t) + (widget-insert " Thus\n\nSelect one:\n\n") + (widget-create 'radio-button-choice + :value "One" + :notify (lambda (widget &rest ignore) + (message "You selected %s" + (widget-value widget))) + '(item "One") '(item "Another One.") '(item "A Final One.")) + (widget-insert "\n") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (if (= (length (widget-value (widget-demo-form-get 'repeat))) + 3) + (message "Congratulation!") + (error "Three was the count!"))) + "Apply Form") + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (widget-example)) + "Reset Form") + (widget-insert "\n")) + +(defun widget-demo-button () + ;; simplest button + (widget-insert "The action to perform when click button is set to :notify ") + (widget-create 'push-button + :notify (lambda (wid cwid &optional event) + (if event + (message "You click by mouse!") + (message "Got it!"))) + "Push me") + ;; better looking button + (widget-insert "\n\nYou can change the looking of the button by set :button-face and :format.\n") + (widget-create 'push-button + :format "This is %[ %t %] without prefix and suffix, and have different face.\n" + :button-face 'custom-button + :tag "button") + ;; deactivate button + (widget-insert "\nWidget can be activated or deactivated.\n") + (widget-create 'toggle + :format "Turn %[%v%] the button: " + :button-face 'custom-button + :notify (lambda (wid &rest ignore) + (let ((but (widget-demo-form-get 'button))) + (if (widget-apply but :active) + (widget-apply but :deactivate) + (widget-apply but :activate)))) + t) + (widget-demo-form-create + 'button + (widget-create 'push-button + :format "%[%t%]\n" + :button-face 'custom-button + :tag "Button" + :notify (lambda (wid &rest ignore) + (message "Got it!")))) + (widget-apply (widget-demo-form-get 'button) :deactivate) + ;; image button + (widget-insert "\nHere is a button which label is a image: ") + (widget-create 'push-button + :format "%[%t%]" + :tag-glyph (find-image `((:type xpm :file "refresh.xpm"))) + :tag "image" + :notify (lambda (wid &rest ingore) + (message "Create new file!"))) + ;; link + (widget-insert "\nThe link to ") + (widget-create 'link + :button-prefix "" + :button-suffix "" + :button-face 'info-xref + :action (lambda (wid &rest ignore) + (widget-demo-goto "Choice#checklist")) + "checklist") + ;; url-link + (widget-insert " in Choice page.\n") + (widget-insert "\nThe url-link to ") + (widget-create 'url-link + :button-prefix "" + :button-suffix "" + :format "%[emacswiki%]" + :button-face 'info-xref + "http://www.emacswiki.org") + (widget-insert "\n") + ;; info-link + (widget-insert "\nThe link to info node ") + (widget-create 'info-link + :button-prefix "" + :button-suffix "" + :button-face 'info-xref + "widget")) + +(defun widget-demo-text () + ;; simpliest + (widget-insert "A text field with label\n") + (widget-create 'editable-field + :format "Label: %v") + ;; textfield size + (widget-insert "\nThe size of text field can limit by setting :size\n") + (widget-create 'editable-field + :format "Size 13: %v\n" + :size 13) + ;; :notify + (widget-insert "\nYou can add callback when the text is changed.\n") + (widget-create 'editable-field + :notify (lambda (wid changed &rest ingore) + (message "Now the text is: %s" (widget-value changed)))) + ;; how to use :action + (widget-insert "\nIf you want do something when press enter, bind it to :action\n" + "Press Enter to change each other: ") + (widget-demo-form-create + 'left + (widget-create 'editable-field + :action (lambda (wid &rest ignore) + (widget-demo-change-text wid 'right)) + :size 13 + "abc")) + (widget-insert " <=> ") + (widget-demo-form-create + 'right + (widget-create 'editable-field + :action (lambda (wid &rest ignore) + (widget-demo-change-text wid 'left)) + :size 13 + "123")) + (widget-insert "\n") + ;; password + (widget-insert "\nThe textfield can used for input password\n") + (widget-create 'editable-field + :format "Password: %v\n" + :secret ?*) + ;; validate + (widget-insert "\nA regexp can set to validate the text\n") + (widget-create 'editable-field + :format "Tel: %v" + :valid-regexp "\\`\\s-*[0-9]+\\([0-9]+-\\)*[0-9]+\\s-*\\'" + :action (lambda (wid &rest ignore) + (if (widget-apply wid :validate) + (error "The telephone number is not valid: %s!" (widget-get wid :error)) + (message "%s is ok!" (widget-value wid))))) + ;; completion + (widget-insert "\nCompletion can set to :complete-function.\n" + "Try complete some symbols: ") + (widget-create 'editable-field + :complete-function 'lisp-complete-symbol) + (widget-insert (propertize (concat + "The default key to invoke completion is M-TAB, which is occupied in many window\n" + "manager. Note that widget-field-keymap is replaced by custom-field-keymap in \n" + "cus-edit.el(Line 4525). So if you want remap command widget-complete, define it\n" + "in custom-field-keymap.\n") + 'face 'widget-inactive)) + ;; deactivate text + (widget-insert "\nClick the checkbox to activate the textfield.\n") + (widget-create 'checkbox + :notify (lambda (wid &rest ignore) + (let ((text (widget-demo-form-get 'text)) + (but (widget-demo-form-get 'button))) + (if (widget-apply text :active) + (progn + (widget-apply text :deactivate) + (widget-apply but :deactivate)) + (progn + (widget-apply text :activate) + (widget-apply but :activate)))))) + (widget-demo-form-create + 'text + (widget-create 'editable-field + :format "Text: %v " + :size 20)) + (widget-apply (widget-demo-form-get 'text) :deactivate) + (widget-demo-form-create + 'button + (widget-create 'push-button + :notify (lambda (wid &rest ignore) + (let ((text (widget-demo-form-get 'text)) + start) + (save-excursion + (goto-char (widget-field-start text)) + (forward-char (length (widget-value text))) + (insert "a")))) + "Append")) + (widget-apply (widget-demo-form-get 'button) :deactivate) + (widget-insert "\n") + ;; text + (widget-insert "\nText is intended for multiline text.\n") + (widget-create 'text :format "Input text: %v") + ;; editable list + (widget-insert "\nEditable list is use for edit a list. ") + (widget-create 'push-button + :format "%[%v%]\n" + :notify (lambda (wid &rest ignore) + (message "%S" (widget-value (widget-demo-form-get 'editable-list)))) + "See Value") + (widget-demo-form-create + 'editable-list + (widget-create 'editable-list + :foramt "%v %i %d\n" + :value '("1" "2" "3") + '(editable-field + :current-index 3 + :value-to-external + (lambda (wid value) + (if (widget-get wid :parent) + value + (let ((idx (1+ (widget-get wid :current-index)))) + (widget-put wid :current-index idx) + (number-to-string idx)))))))) + +;; maybe it is not work, because marker of :to is delete also +(defun widget-demo-change-text (wid id) + (let ((other (widget-demo-form-get id))) + (save-excursion + (goto-char (widget-field-start other)) + (delete-region (point) (widget-field-end other)) + (insert (widget-value wid))))) + +(defun widget-demo-choice () + ;; menu choice + (widget-insert "Here is a menu choice. The label is set by :tag, and the default item is\n" + "the child item that :value match the :value of the menu choice.\n") + (widget-demo-form-create + 'menu-choice + (widget-create 'menu-choice + :tag "Menu choices" + :button-face 'custom-button + :notify (lambda (wid &rest ignore) + (message "Current value: %S" (widget-value wid))) + :value 'const-variable + '(push-button :tag "button" + :format "%[%t%]\n" + :notify (lambda (wid &rest ignore) + (message "button activate")) + "This is button") + '(item :tag "item" :value "This is item") + '(choice-item :tag "choice" "This is choice item") + '(const :tag "const" const-variable) + '(editable-field :menu-tag "editable field" "text"))) + ;; toggle + (widget-insert "\nToggle is used for switch a flag: ") + (widget-create 'toggle + :on "turn on" + :off "turn off" + :notify (lambda (wid &rest ignore) + (message (concat "turn the option " + (if (widget-value wid) "on" "off")))) + t) + ;; check box + (widget-insert "\nCheck box is like toggle: ") + (widget-create 'checkbox + :format "%[%v%] Option\n" + :notify (lambda (wid &rest ignore) + (message (concat "Option " + (if (widget-value wid) + "selected" "unselected")))) + t) + ;; radio button + (widget-insert "\nRadio button is used for select one from a list.\n") + (widget-create 'radio-button-choice + :value "One" + :notify (lambda (wid &rest ignore) + (message "You select %S %s" + (widget-type wid) + (widget-value wid))) + '(item "One") + '(item "Two") + '(item "Three")) + (widget-insert "\n") + ;; checklist + (widget-demo-create-anchor "checklist") + (widget-insert "Checklist is used for multiple choices from a list.\n") + (widget-create 'checklist + :notify (lambda (wid &rest ignore) + (message "The value is %S" (widget-value wid))) + '(item "one") + '(item "two") + '(item "three"))) +;;}}} + +;;{{{ Widget tree +(defun widget-tree-ancestor (widget) + (let ((parent (car (get widget 'widget-type)))) + (if parent + (cons widget (widget-tree-ancestor parent))))) + +(defvar widget-tree-list nil + "Inherit tree of all widget") + +(defun widget-tree-build () + (let (list seen ancestor tree-list) + (mapatoms (lambda (a) + (and (get a 'widget-type) + (push a list))) + obarray) + (setq list (remq 'default list)) + (while list + (setq ancestor (nreverse (widget-tree-ancestor (car list)))) + (setq parent 'default) + (dolist (type ancestor) + (unless (member type seen) + (setq alist (assoc parent tree-list) + tree-list (delq alist tree-list) + alist (cons parent (cons type (cdr alist))) + tree-list (cons alist tree-list) + list (delq type list)) + (push type seen)) + (setq parent type))) + (setq widget-tree-list tree-list))) + +(defun widget-tree-browse (but &rest ignore) + (if (= (length (window-list)) 1) + (split-window)) + (save-selected-window + (other-window 1) + (widget-browse (intern (widget-get but :tag))))) + +(defun widget-tree-widget (type) + (let ((list (assoc type widget-tree-list))) + (if list + `(tree-widget + :node (push-button + :tag ,(symbol-name type) + :format "%[%t%]\n" + :notify widget-tree-browse) + :dynargs widget-tree-expand) + `(push-button + :format "%[%t%]\n" + :tag ,(symbol-name type) + :notify widget-tree-browse)))) + +(defun widget-tree-expand (tree) + (or (widget-get tree :args) + (let ((type (intern (widget-get (tree-widget-node tree) :tag)))) + (mapcar 'widget-tree-widget + (cdr (assoc type widget-tree-list)))))) + +(defun widget-tree () + (widget-insert + "This is a list of all defined widget. The tree-widget show the +inherit relationship of the widget.\n\n") + + (widget-insert " You can click the button to browse the widget.\n\n") + (unless widget-tree-list + (widget-tree-build)) + (widget-apply-action + (widget-create (widget-tree-widget 'default))) + (if (require 'tree-mode nil t) + (tree-minor-mode t) + (widget-insert "\n\n") + (widget-insert " I recommend you use ") + (widget-create 'url-link + :button-prefix "" + :button-suffix "" + :format "%[tree-mode%]" + :button-face 'info-xref + "http://www.emacswiki.org/cgi-bin/wiki/tree-mode.el") + (widget-insert " to browse tree-widget.\n\n"))) +;;}}} + +(provide 'dtos-demo) +;;; widget-demo.el ends here diff --git a/.config/emacs/scripts/elpaca-setup.el b/.config/emacs/scripts/elpaca-setup.el new file mode 100644 index 0000000..6c5e8af --- /dev/null +++ b/.config/emacs/scripts/elpaca-setup.el @@ -0,0 +1,73 @@ + +;;; Code: + +(defvar elpaca-installer-version 0.11) +(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 (: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 :elpaca use-package keyword. + (elpaca-use-package-mode) + ;; Assume :elpaca t unless otherwise specified. + (setq elpaca-use-package-by-default t)) + +;; Block until current queue processed. +(elpaca-wait) + +;;When installing a package which modifies a form used at the top-level +;;(e.g. a package which adds a use-package key word), +;;use `elpaca-wait' to block until that package has been installed/configured. +;;For example: +;;(use-package general :demand t) +;;(elpaca-wait) + +;;Turns off elpaca-use-package-mode current declartion +;;Note this will cause the declaration to be interpreted immediately (not deferred). +;;Useful for configuring built-in emacs features. +;;(use-package emacs :elpaca nil :config (setq ring-bell-function #'ignore)) + +;; Don't install anything. Defer execution of BODY +;;(elpaca nil (message "deferred")) +(elpaca (magit :branch "main" :pre-build ("make" "info"))) +(elpaca (forge :branch "main")) +(elpaca (ghub :branch "main")) +(elpaca (transient :branch "main")) +(elpaca (with-editor :branch "main")) + +(provide 'elpaca-setup) + +;;; elpaca-setup.el ends here diff --git a/.config/emacs/scripts/eshell-prompt.el b/.config/emacs/scripts/eshell-prompt.el new file mode 100644 index 0000000..7485ec4 --- /dev/null +++ b/.config/emacs/scripts/eshell-prompt.el @@ -0,0 +1,33 @@ +;;; eshell-prompt.el --- a fancy shell prompt for eshell + +;;; Code: + +;; fancy-shell +;; A fancy shell prompt for eshell. + +(defun fancy-shell () + "A pretty shell with git status" + (let* ((cwd (abbreviate-file-name (eshell/pwd))) + (ref (magit-get-shortname "HEAD")) + (stat (magit-file-status)) + (x-stat eshell-last-command-status) + (git-chunk + (if ref + (format "%s%s%s " + (propertize (if stat "[" "(") 'font-lock-face (list :foreground (if stat "#e81050" "#9bee8b"))) + (propertize ref 'font-lock-face '(:foreground "#c897ff")) + (propertize (if stat "]" ")") 'font-lock-face (list :foreground (if stat "#e81050" "#9bee8b")))) + ""))) + (propertize + (format "\n%s %s %s$ " + (if (< 0 x-stat) (format (propertize "!%s" 'font-lock-face '(:foreground "#e81050")) x-stat) + (propertize "➤" 'font-lock-face (list :foreground (if (< 0 x-stat) "#e81050" "#9bee8b")))) + (propertize cwd 'font-lock-face '(:foreground "#45babf")) + git-chunk) + 'read-only t + 'front-sticky '(font-lock-face read-only) + 'rear-nonsticky '(font-lock-face read-only)))) + + +(provide 'eshell-prompt) +;;; eshell-prompt.el ends here diff --git a/.config/emacs/scripts/widget-example.el b/.config/emacs/scripts/widget-example.el new file mode 100644 index 0000000..78b9198 --- /dev/null +++ b/.config/emacs/scripts/widget-example.el @@ -0,0 +1,701 @@ +;;; widget-demo.el --- Some recipes for creating widgets + +;; Copyright 2007 Ye Wenbin +;; +;; Author: wenbinye@gmail.com +;; Version: $Id: widget-demo.el,v 0.0 2007/11/13 17:50:14 ywb Exp $ +;; Keywords: +;; X-URL: not distributed yet + +;; 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 2, 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, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: +;; The widget document is not easy to understand. I think the +;; quick way to use widget is learning from examples. So I wrote +;; this library to help others understand and use widget quickly. +;; +;; I'm not expert at widget, so there may be something wrong in the +;; code. If you found it, please let me know. +;; + +;;; Add New Page: +;; You can test you widget definition by add it as a new page to +;; widget demo. You can benefit from without write the code to +;; creating buffer and the key bindings of `widget-demo-mode'. Here is +;; a simple example to add new widget demo page: +;; +;; (defun widget-demo-tree-test () +;; (widget-insert "Tree:\n") +;; (widget-create +;; '(tree-widget +;; :node (push-button :format "%[%t%]\n" :tag "hello") +;; :open t +;; (push-button :format "%[%t%]\n" :tag "node1") +;; (push-button :format "%[%t%]\n" :tag "node2")))) +;; (widget-demo-add-page "Tree Test" 'widget-demo-tree-test) + +;;; TODO: +;; 1. Add tree-widget +;; 2. Add complex widget create by using several types of widget and +;; using group. +;; 3. Add tutorial about defining new widget +;; 4. Add a macro for simplified page definition. For example: +;; (widget-demo-insert +;; "Some text here" +;; (button :notify callback "label") +;; "More text" +;; (editable-field :form-id identifier)) + +;; Put this file into your load-path and the following into your ~/.emacs: +;; (autoload 'widget-demo "widget-demo" "Show demo of widget" t) + +;;; Code: + +(eval-when-compile + (require 'cl-lib)) +(require 'info) +(require 'tree-widget) + +(defvar widget-demo-buffer-name "*Widget Demo*" + "*Name of the widget demo buffer") + +(defvar widget-demo-list + '(("Contents" widget-demo-contents :header "Widget Demo") + ("Example" widget-demo-example :header "Example in info") + ("WidgetTree" widget-tree :header "Widget Tree") + ("Button" widget-demo-button) + ("Text" widget-demo-text) + ("Choice" widget-demo-choice) + ) + "A list of pages to show.") + +(defvar widget-demo-current nil + "Current page in `widget-demo-list'.") + +(defvar widget-demo-form nil + "A table for lookup widget created in current buffer.") + +(defvar widget-demo-anchors nil + "A table for lookup markers created in current buffer.") + +(defvar widget-demo-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map widget-keymap) + (define-key map "n" 'widget-demo-next) + (define-key map "p" 'widget-demo-previous) + (define-key map "u" 'widget-demo) + (define-key map "t" 'widget-demo) + (dolist (num (number-sequence ?1 ?9)) + (define-key map (char-to-string num) 'widget-demo-goto-page)) + ;; this command may be helpful for debug + (define-key map "r" 'widget-demo-reflesh) + (define-key map "\C-c\C-s" 'widget-demo-show-source) + (define-key map "\C-c\C-n" 'widget-demo-next) + (define-key map "\C-c\C-p" 'widget-demo-previous) + (define-key map "\C-c\C-u" 'widget-demo) + (define-key map "\C-c\C-t" 'widget-demo) + map) + "Keymap to use in *Widget Demo* buffer.") + +(defvar widget-demo-menu nil) +(unless widget-demo-menu + (easy-menu-define + widget-demo-menu widget-demo-mode-map "Widget Demo" + `("Widget" + ["Next Page" widget-demo-next t] + ["Previous Page" widget-demo-previous t] + ["Top" widget-demo t] + ["Refresh" widget-demo-reflesh t] + "--" + ,@(mapcar (lambda (p) + (vector (car p) 'widget-demo-menu-goto t)) + widget-demo-list)))) + +;;{{{ Helper functions +(defun widget-demo-menu-goto () + (interactive) + (widget-demo-goto (symbol-name last-command-event))) + +(defun widget-demo-form-create (id widget) + (if (assoc id widget-demo-form) + (error "identifier %S is used!" id) + (push (cons id widget) widget-demo-form))) + +(defun widget-demo-form-add (id widget) + (let ((old (assoc id widget-demo-form))) + (if old + (setcdr old widget) + (push (cons id widget) widget-demo-form)))) + +(defun widget-demo-form-get (id) + (cdr (assoc id widget-demo-form))) + +(defun widget-demo-create-anchor (anchor) + (push (cons anchor (point-marker)) widget-demo-anchors)) + +(defun widget-demo-resolve-link (name) + "Return the Next, Top, Next page." + (let* ((page (assoc name widget-demo-list)) + (rest (member page widget-demo-list)) + (len (length rest)) + next previous) + ;; the contents only list next + (if (eq page (car widget-demo-list)) + (list (cadr widget-demo-list)) + (if (= len 1) + (setq next nil) + (setq next (cadr rest))) + (setq previous (nth (- (length widget-demo-list) len 1) + widget-demo-list)) + (list next (car widget-demo-list) previous)))) + +(defun widget-demo-add-page (&rest page) + "add new PAGE to widget-demo. +The page is constituted by + + (PAGE-NAME PAGE-DEFINITION [KEYWORD VALUE]). + +Current only keyword :header is supported, which value is a string +to display in menu and the header of buffer instead of the page-name." + (setq widget-demo-list + (append widget-demo-list (list page)))) + +(defun widget-demo-remove-page (name) + (setq widget-demo-list + (delq (assoc name widget-demo-list) + widget-demo-list))) +;;}}} + +;;{{{ Commands +;;;###autoload +(defun widget-demo () + "Show widget demo." + (interactive) + (switch-to-buffer widget-demo-buffer-name) + (widget-demo-goto "Contents")) + +(define-derived-mode widget-demo-mode nil "WDemo" + "Widget demo. +\\{widget-demo-mode-map}" + (make-local-variable 'widget-demo-form) + (make-local-variable 'widget-demo-anchors)) + +(defun widget-demo-goto (link) + (interactive + (list (completing-read "Goto: " widget-demo-list nil t))) + (switch-to-buffer widget-demo-buffer-name) + (widget-demo-mode) + (setq link (split-string link "#")) + (let* ((inhibit-read-only t) + (name (car link)) + (anchor (cadr link)) + (page (assoc name widget-demo-list))) + (erase-buffer) + (remove-overlays) + (setq widget-demo-current name) + ;; insert buttons + (let ((links (widget-demo-resolve-link name)) + (label '("Next" "Contents" "Prev"))) + (dolist (link links) + (when link + (widget-create 'push-button + :format + (if (string= (car label) "Contents") + "%[Contents%]" + (format "%%t: %%[%s%%]" (car link))) + :button-face 'info-xref + :tag (car label) + :notify (lambda (wid &rest ignore) + (widget-demo-goto (widget-value wid))) + (car link)) + (widget-insert " ")) + (setq label (cdr label)))) + ;; insert title + (widget-insert "\n\n ") + (widget-insert + (propertize + (or (plist-get page :header) (car page)) + 'face 'info-title-1)) + (widget-insert "\n\n") + (funcall (cadr page)) + ;; if there is an anchor, jump to the anchor + (if (and anchor + (setq anchor (assoc-default anchor widget-demo-anchors))) + (goto-char anchor) + (goto-char (point-min))) + (widget-setup) + (use-local-map widget-demo-mode-map))) + +(defun widget-demo-next () + (interactive) + (let ((links (widget-demo-resolve-link widget-demo-current))) + (if (car links) + (widget-demo-goto (caar links)) + (message "No next pages!")))) + +(defun widget-demo-previous () + (interactive) + (let ((links (widget-demo-resolve-link widget-demo-current))) + (if (nth 2 links) + (widget-demo-goto (car (nth 2 links))) + (message "No previous pages!")))) + +(defun widget-demo-goto-page () + (interactive) + (let ((num (- last-command-event ?0))) + (if (< num (length widget-demo-list)) + (widget-demo-goto (car (nth num widget-demo-list))) + (message "Only %d pages!" (length widget-demo-list))))) + +(defun widget-demo-reflesh () + (interactive) + (widget-demo-goto widget-demo-current)) + +(defun widget-demo-show-source () + (interactive) + (let ((page (assoc widget-demo-current widget-demo-list))) + (with-selected-window + (display-buffer + (find-file-noselect (find-library-name "widget-demo"))) + (imenu (symbol-name (cadr page))) + (recenter 1)))) +;;}}} + +;;{{{ Pages +(defun widget-demo-contents () + (let ((idx 1)) + (dolist (page (cdr widget-demo-list)) + (widget-insert (format "%3d. " idx)) + (widget-create 'link + :format "%[%t%]" + :tag (or (plist-get page :header) (car page)) + :button-prefix "" + :button-suffix "" + :notify (lambda (widget &rest ignore) + (widget-demo-goto (widget-value widget))) + (car page)) + (widget-insert "\n") + (setq idx (1+ idx))))) + +(defun widget-demo-example () + (widget-insert "Here is some documentation.\n\n") + (widget-create 'editable-field + :size 13 + :format "Name: %v " ; Text after the field! + "My Name") + (widget-create 'menu-choice + :tag "Choose" + :value "This" + :help-echo "Choose me, please!" + :notify (lambda (widget &rest ignore) + (message "%s is a good choice!" + (widget-value widget))) + '(item :tag "This option" :value "This") + '(choice-item "That option") + '(editable-field :menu-tag "No option" "Thus option")) + (widget-create 'editable-field + :format "Address: %v" + "Some Place\nIn some City\nSome country.") + (widget-insert "\nSee also ") + (widget-create 'link + :notify (lambda (&rest ignore) + (widget-value-set + (widget-demo-form-get 'repeat) + '("En" "To" "Tre")) + (widget-setup)) + "other work") + (widget-insert + " for more information.\n\nNumbers: count to three below\n") + (widget-demo-form-create + 'repeat + (widget-create 'editable-list + :entry-format "%i %d %v" + :notify (lambda (widget &rest ignore) + (let ((old (widget-get widget + ':example-length)) + (new (length (widget-value widget)))) + (unless (eq old new) + (widget-put widget ':example-length new) + (message "You can count to %d." new)))) + :value '("One" "Eh, two?" "Five!") + '(editable-field :value "three"))) + (widget-insert "\n\nSelect multiple:\n\n") + (widget-create 'checkbox t) + (widget-insert " This\n") + (widget-create 'checkbox nil) + (widget-insert " That\n") + (widget-create 'checkbox + :notify (lambda (&rest ignore) (message "Tickle")) + t) + (widget-insert " Thus\n\nSelect one:\n\n") + (widget-create 'radio-button-choice + :value "One" + :notify (lambda (widget &rest ignore) + (message "You selected %s" + (widget-value widget))) + '(item "One") '(item "Another One.") '(item "A Final One.")) + (widget-insert "\n") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (if (= (length (widget-value (widget-demo-form-get 'repeat))) + 3) + (message "Congratulation!") + (error "Three was the count!"))) + "Apply Form") + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (widget-example)) + "Reset Form") + (widget-insert "\n")) + +(defun widget-demo-button () + ;; simplest button + (widget-insert "The action to perform when click button is set to :notify ") + (widget-create 'push-button + :notify (lambda (wid cwid &optional event) + (if event + (message "You click by mouse!") + (message "Got it!"))) + "Push me") + ;; better looking button + (widget-insert "\n\nYou can change the looking of the button by set :button-face and :format.\n") + (widget-create 'push-button + :format "This is %[ %t %] without prefix and suffix, and have different face.\n" + :button-face 'custom-button + :tag "button") + ;; deactivate button + (widget-insert "\nWidget can be activated or deactivated.\n") + (widget-create 'toggle + :format "Turn %[%v%] the button: " + :button-face 'custom-button + :notify (lambda (wid &rest ignore) + (let ((but (widget-demo-form-get 'button))) + (if (widget-apply but :active) + (widget-apply but :deactivate) + (widget-apply but :activate)))) + t) + (widget-demo-form-create + 'button + (widget-create 'push-button + :format "%[%t%]\n" + :button-face 'custom-button + :tag "Button" + :notify (lambda (wid &rest ignore) + (message "Got it!")))) + (widget-apply (widget-demo-form-get 'button) :deactivate) + ;; image button + (widget-insert "\nHere is a button which label is a image: ") + (widget-create 'push-button + :format "%[%t%]" + :tag-glyph (find-image `((:type xpm :file "refresh.xpm"))) + :tag "image" + :notify (lambda (wid &rest ingore) + (message "Create new file!"))) + ;; link + (widget-insert "\nThe link to ") + (widget-create 'link + :button-prefix "" + :button-suffix "" + :button-face 'info-xref + :action (lambda (wid &rest ignore) + (widget-demo-goto "Choice#checklist")) + "checklist") + ;; url-link + (widget-insert " in Choice page.\n") + (widget-insert "\nThe url-link to ") + (widget-create 'url-link + :button-prefix "" + :button-suffix "" + :format "%[emacswiki%]" + :button-face 'info-xref + "http://www.emacswiki.org") + (widget-insert "\n") + ;; info-link + (widget-insert "\nThe link to info node ") + (widget-create 'info-link + :button-prefix "" + :button-suffix "" + :button-face 'info-xref + "widget")) + +(defun widget-demo-text () + ;; simpliest + (widget-insert "A text field with label\n") + (widget-create 'editable-field + :format "Label: %v") + ;; textfield size + (widget-insert "\nThe size of text field can limit by setting :size\n") + (widget-create 'editable-field + :format "Size 13: %v\n" + :size 13) + ;; :notify + (widget-insert "\nYou can add callback when the text is changed.\n") + (widget-create 'editable-field + :notify (lambda (wid changed &rest ingore) + (message "Now the text is: %s" (widget-value changed)))) + ;; how to use :action + (widget-insert "\nIf you want do something when press enter, bind it to :action\n" + "Press Enter to change each other: ") + (widget-demo-form-create + 'left + (widget-create 'editable-field + :action (lambda (wid &rest ignore) + (widget-demo-change-text wid 'right)) + :size 13 + "abc")) + (widget-insert " <=> ") + (widget-demo-form-create + 'right + (widget-create 'editable-field + :action (lambda (wid &rest ignore) + (widget-demo-change-text wid 'left)) + :size 13 + "123")) + (widget-insert "\n") + ;; password + (widget-insert "\nThe textfield can used for input password\n") + (widget-create 'editable-field + :format "Password: %v\n" + :secret ?*) + ;; validate + (widget-insert "\nA regexp can set to validate the text\n") + (widget-create 'editable-field + :format "Tel: %v" + :valid-regexp "\\`\\s-*[0-9]+\\([0-9]+-\\)*[0-9]+\\s-*\\'" + :action (lambda (wid &rest ignore) + (if (widget-apply wid :validate) + (error "The telephone number is not valid: %s!" (widget-get wid :error)) + (message "%s is ok!" (widget-value wid))))) + ;; completion + (widget-insert "\nCompletion can set to :complete-function.\n" + "Try complete some symbols: ") + (widget-create 'editable-field + :complete-function 'lisp-complete-symbol) + (widget-insert (propertize (concat + "The default key to invoke completion is M-TAB, which is occupied in many window\n" + "manager. Note that widget-field-keymap is replaced by custom-field-keymap in \n" + "cus-edit.el(Line 4525). So if you want remap command widget-complete, define it\n" + "in custom-field-keymap.\n") + 'face 'widget-inactive)) + ;; deactivate text + (widget-insert "\nClick the checkbox to activate the textfield.\n") + (widget-create 'checkbox + :notify (lambda (wid &rest ignore) + (let ((text (widget-demo-form-get 'text)) + (but (widget-demo-form-get 'button))) + (if (widget-apply text :active) + (progn + (widget-apply text :deactivate) + (widget-apply but :deactivate)) + (progn + (widget-apply text :activate) + (widget-apply but :activate)))))) + (widget-demo-form-create + 'text + (widget-create 'editable-field + :format "Text: %v " + :size 20)) + (widget-apply (widget-demo-form-get 'text) :deactivate) + (widget-demo-form-create + 'button + (widget-create 'push-button + :notify (lambda (wid &rest ignore) + (let ((text (widget-demo-form-get 'text)) + start) + (save-excursion + (goto-char (widget-field-start text)) + (forward-char (length (widget-value text))) + (insert "a")))) + "Append")) + (widget-apply (widget-demo-form-get 'button) :deactivate) + (widget-insert "\n") + ;; text + (widget-insert "\nText is intended for multiline text.\n") + (widget-create 'text :format "Input text: %v") + ;; editable list + (widget-insert "\nEditable list is use for edit a list. ") + (widget-create 'push-button + :format "%[%v%]\n" + :notify (lambda (wid &rest ignore) + (message "%S" (widget-value (widget-demo-form-get 'editable-list)))) + "See Value") + (widget-demo-form-create + 'editable-list + (widget-create 'editable-list + :foramt "%v %i %d\n" + :value '("1" "2" "3") + '(editable-field + :current-index 3 + :value-to-external + (lambda (wid value) + (if (widget-get wid :parent) + value + (let ((idx (1+ (widget-get wid :current-index)))) + (widget-put wid :current-index idx) + (number-to-string idx)))))))) + +;; maybe it is not work, because marker of :to is delete also +(defun widget-demo-change-text (wid id) + (let ((other (widget-demo-form-get id))) + (save-excursion + (goto-char (widget-field-start other)) + (delete-region (point) (widget-field-end other)) + (insert (widget-value wid))))) + +(defun widget-demo-choice () + ;; menu choice + (widget-insert "Here is a menu choice. The label is set by :tag, and the default item is\n" + "the child item that :value match the :value of the menu choice.\n") + (widget-demo-form-create + 'menu-choice + (widget-create 'menu-choice + :tag "Menu choices" + :button-face 'custom-button + :notify (lambda (wid &rest ignore) + (message "Current value: %S" (widget-value wid))) + :value 'const-variable + '(push-button :tag "button" + :format "%[%t%]\n" + :notify (lambda (wid &rest ignore) + (message "button activate")) + "This is button") + '(item :tag "item" :value "This is item") + '(choice-item :tag "choice" "This is choice item") + '(const :tag "const" const-variable) + '(editable-field :menu-tag "editable field" "text"))) + ;; toggle + (widget-insert "\nToggle is used for switch a flag: ") + (widget-create 'toggle + :on "turn on" + :off "turn off" + :notify (lambda (wid &rest ignore) + (message (concat "turn the option " + (if (widget-value wid) "on" "off")))) + t) + ;; check box + (widget-insert "\nCheck box is like toggle: ") + (widget-create 'checkbox + :format "%[%v%] Option\n" + :notify (lambda (wid &rest ignore) + (message (concat "Option " + (if (widget-value wid) + "selected" "unselected")))) + t) + ;; radio button + (widget-insert "\nRadio button is used for select one from a list.\n") + (widget-create 'radio-button-choice + :value "One" + :notify (lambda (wid &rest ignore) + (message "You select %S %s" + (widget-type wid) + (widget-value wid))) + '(item "One") + '(item "Two") + '(item "Three")) + (widget-insert "\n") + ;; checklist + (widget-demo-create-anchor "checklist") + (widget-insert "Checklist is used for multiple choices from a list.\n") + (widget-create 'checklist + :notify (lambda (wid &rest ignore) + (message "The value is %S" (widget-value wid))) + '(item "one") + '(item "two") + '(item "three"))) +;;}}} + +;;{{{ Widget tree +(defun widget-tree-ancestor (widget) + (let ((parent (car (get widget 'widget-type)))) + (if parent + (cons widget (widget-tree-ancestor parent))))) + +(defvar widget-tree-list nil + "Inherit tree of all widget") + +(defun widget-tree-build () + (let (list seen ancestor tree-list) + (mapatoms (lambda (a) + (and (get a 'widget-type) + (push a list))) + obarray) + (setq list (remq 'default list)) + (while list + (setq ancestor (nreverse (widget-tree-ancestor (car list)))) + (setq parent 'default) + (dolist (type ancestor) + (unless (member type seen) + (setq alist (assoc parent tree-list) + tree-list (delq alist tree-list) + alist (cons parent (cons type (cdr alist))) + tree-list (cons alist tree-list) + list (delq type list)) + (push type seen)) + (setq parent type))) + (setq widget-tree-list tree-list))) + +(defun widget-tree-browse (but &rest ignore) + (if (= (length (window-list)) 1) + (split-window)) + (save-selected-window + (other-window 1) + (widget-browse (intern (widget-get but :tag))))) + +(defun widget-tree-widget (type) + (let ((list (assoc type widget-tree-list))) + (if list + `(tree-widget + :node (push-button + :tag ,(symbol-name type) + :format "%[%t%]\n" + :notify widget-tree-browse) + :dynargs widget-tree-expand) + `(push-button + :format "%[%t%]\n" + :tag ,(symbol-name type) + :notify widget-tree-browse)))) + +(defun widget-tree-expand (tree) + (or (widget-get tree :args) + (let ((type (intern (widget-get (tree-widget-node tree) :tag)))) + (mapcar 'widget-tree-widget + (cdr (assoc type widget-tree-list)))))) + +(defun widget-tree () + (widget-insert + "This is a list of all defined widget. The tree-widget show the +inherit relationship of the widget.\n\n") + + (widget-insert " You can click the button to browse the widget.\n\n") + (unless widget-tree-list + (widget-tree-build)) + (widget-apply-action + (widget-create (widget-tree-widget 'default))) + (if (require 'tree-mode nil t) + (tree-minor-mode t) + (widget-insert "\n\n") + (widget-insert " I recommend you use ") + (widget-create 'url-link + :button-prefix "" + :button-suffix "" + :format "%[tree-mode%]" + :button-face 'info-xref + "http://www.emacswiki.org/cgi-bin/wiki/tree-mode.el") + (widget-insert " to browse tree-widget.\n\n"))) +;;}}} + +(provide 'widget-demo) +;;; widget-demo.el ends here diff --git a/.config/emacs/start.org b/.config/emacs/start.org new file mode 100644 index 0000000..e126108 --- /dev/null +++ b/.config/emacs/start.org @@ -0,0 +1,45 @@ +#+STARTUP: inlineimages + +[[file:./images/dtmacs-logo.png]] + +⦿ *IMPORTANT KEYBINDINGS* +|-----------+-------------------+------------------------------------| +| M-x | [[elisp:(counsel-M-x)][counsel-M-x]] | Prompt for Emacs programs | +| SPC . | [[elisp:(counsel-find-file)][counsel-find-file]] | Find a file | +| SPC f r | [[elisp:(counsel-recentf)][counsel-recentf]] | Find a recent file | +| SPC d d | [[elisp:(dired (getenv "HOME"))][dired]] | Dired file manager | +| SPC h r r | [[elisp:(lambda () (load-file "~/.config/emacs/init.el") (ignore(elpaca-process-queues)))][reload dtmacs]] | eload dtmacs | +| SPC f u | [[elisp:(sudo-find-file)][sudo-find-file]] | Find file and open as root | +| SPC f U | [[elisp:(sudo-find-file)][sudo-find-file]] | Open current file as root | +| SPC e t | [[elisp:(+eshell/toggle nil)][+eshell/toggle]] | Toggle the eshell | +| SPC v t | [[elisp:(+vterm/toggle nil)][+vterm/toggle]] | Toggle the vterm terminal emulator | +|-----------+-------------------+------------------------------------| + +⦿ *BUFFERS AND SPLITS* +|------------------------------+------------------------------+-----------------------------| +| (SPC b i) [[elisp:(ibuffer)][ibuffer]] | (SPC b p) [[elisp:(previous-buffer)][previous-buffer]] | (SPC b n) [[elisp:(next-buffer)][next-buffer]] | +| (SPC b k) [[elisp:(kill-buffer)][kill-buffer]] | (SPC b s) [[elisp:(save-buffer)][save-buffer]] | (SPC b u) /sudo-save-buffer/ | +| (SPC w s) [[elisp:(evil-window-split)][evil-window-split]] | (SPC w v) [[elisp:(evil-window-vsplit)][evil-window-vsplit]] | (SPC w w) [[elisp:(evil-window-next)][evil-window-next]] | +| (SPC w c) [[elisp:(evil-window-delete)][evil-window-delete]] | (SPC w l) [[elisp:(evil-window-left 1)][evil-window-left]] | (SPC w h) [[elisp:(evil-window-right 1)][evil-window-right]] | +|------------------------------+------------------------------+-----------------------------| + +⦿ *HELP INFORMATION* +|-----------------------------+-----------------------------+-------------------------------| +| (SPC h d h) [[elisp:(doom/help)][doom/help]] | (SPC h d f) [[elisp:(doom/help-faq)][doom/help-faq]] | (SPC h i) [[elisp:(info)][info]] | +| (SPC h f) [[elisp:(counsel-describe-function)][describe-function]] | (SPC h v) [[elisp:(counsel-describe-variable)][describe-variable]] | (SPC h b b) [[elisp:(counsel-descbinds)][describe-bindings]] | +|-----------------------------+-----------------------------+-------------------------------| + +⦿ *DOOM EMACS CONFIGS* (Press =1-5= to immediately open a file) +|---+----------------+------------------------------------------------------------| +| =1= | [[elisp:(find-file (concat (getenv "HOME") "/.config/doom/config.org"))][config.org]] | This is the main user configuration file for Doom Emacs. | +| =2= | [[elisp:(find-file (concat (getenv "HOME") "/.config/doom/init.el"))][init.el]] | Allows you to turn on/off the standard Doom modules. | +| =3= | [[elisp:(find-file (concat (getenv "HOME") "/.config/doom/packages.el"))][packages.el]] | Easily install extra packages by adding them to this file. | +| =4= | [[elisp:(find-file (concat (getenv "HOME") "/.config/doom/eshell/aliases"))][eshell/aliases]] | Aliases file for the eshell. | +| =5= | [[elisp:(find-file (concat (getenv "HOME") "/.config/doom/eshell/profile"))][eshell/profile]] | Profile for the eshell. | +|---+----------------+------------------------------------------------------------| + +=NOTE=: 'SPC f p' [[elisp:(doom/find-file-in-private-config)][doom/find-file-in-private-config]]) + +;; Local Variables: +;; eval: (start-mode) +;; End: diff --git a/.config/emacs/themes/dtmacs-theme.el b/.config/emacs/themes/dtmacs-theme.el new file mode 100644 index 0000000..b03dc56 --- /dev/null +++ b/.config/emacs/themes/dtmacs-theme.el @@ -0,0 +1,317 @@ +;;; dtmacs-theme.el --- Theme + +;; Copyright (C) 2023 , + +;; Author: Derek Taylor (DT) +;; Version: 0.1 +;; Package-Requires: ((emacs "24.1")) +;; Created with ThemeCreator, https://github.com/mswift42/themecreator. + +;; 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 . + +;; This file is not part of Emacs. + +;;; Commentary: +;;; dtmacs-theme was created by Derek Taylor in 2023 + +;;; Code: + +(deftheme dtmacs) +(let ((class '((class color) (min-colors 89))) + (fg1 "#d3eaf4") + (fg2 "#cadae2") + (fg3 "#748895") + (fg4 "#4f545a") + (fg6 "#c4c4c4") + (bg1 "#192428") + (bg2 "#24343e") + (bg3 "#0c191d") + (bg4 "#0d6f9f") + (builtin "#41b2ea") + (keyword "#9bee8b") + (const "#96defa") + (comment "#7a95a0") + (func "#a094fb") + (str "#89e14b") + (type "#68cee8") + (var "#ff6ba9") + (bufid "#ffffff") + (selection "#e81050") + (warning "#e81050") + (warning2 "#e86310") + (todo "#c897ff") + (done "#d6ff97") + (unspec (when (>= emacs-major-version 29) 'unspecified))) + (custom-theme-set-faces + 'dtmacs + `(default ((,class (:background ,bg1 :foreground ,fg1)))) + `(dashboard-footer ((,class (:foreground ,var :italic t)))) + `(dashboard-heading ((,class (:foreground ,const :weight bold)))) + `(dashboard-text-banner ((,class (:foreground ,fg1 :weight bold)))) + `(dashboard-banner-logo-title ((,class (:foreground ,str :weight bold)))) + `(font-lock-builtin-face ((,class (:foreground ,builtin)))) + `(font-lock-comment-face ((,class (:italic t :foreground ,comment)))) + `(font-lock-negation-char-face ((,class (:foreground ,const)))) + `(font-lock-reference-face ((,class (:foreground ,const)))) + `(font-lock-constant-face ((,class (:foreground ,const)))) + `(font-lock-doc-face ((,class (:foreground ,comment)))) + `(font-lock-function-name-face ((,class (:foreground ,func )))) + `(font-lock-keyword-face ((,class (:bold ,class :foreground ,keyword)))) + `(font-lock-string-face ((,class (:foreground ,str)))) + `(font-lock-type-face ((,class (:foreground ,type )))) + `(font-lock-variable-name-face ((,class (:foreground ,var)))) + `(font-lock-warning-face ((,class (:foreground ,warning :background ,bg2)))) + `(term-color-black ((,class (:foreground ,fg2 :background ,unspec)))) + ;; `(region ((,class (:background ,fg1 :foreground ,bg1)))) + `(region ((,class (:background ,selection)))) + `(highlight ((,class (:foreground ,fg3 :background ,bg3)))) + `(hl-line ((,class (:background ,bg2)))) + `(fringe ((,class (:background ,bg1 :foreground ,fg4)))) + `(cursor ((,class (:background ,fg4)))) + `(isearch ((,class (:bold t :foreground ,warning :background ,bg3)))) + `(mode-line ((,class (:box (:line-width 4 :color ,bg2) :bold t :foreground ,fg3 :background ,bg2)))) + `(mode-line-inactive ((,class (:box (:line-width 4 :color ,bg3) :foreground ,fg3 :background ,bg3 :weight bold)))) + `(mode-line-buffer-id ((,class (:box nil :bold t :foreground ,bufid :background ,unspec)))) + `(mode-line-highlight ((,class (:box nil :foreground ,selection :weight bold)))) + `(mode-line-emphasis ((,class (:foreground ,fg1)))) + `(vertical-border ((,class (:foreground ,fg3)))) + `(minibuffer-prompt ((,class (:bold t :foreground ,builtin)))) + `(default-italic ((,class (:italic t)))) + `(link ((,class (:foreground ,const :underline t)))) + `(org-code ((,class (:foreground ,fg2)))) + `(org-hide ((,class (:foreground ,fg4)))) + `(org-level-1 ((,class (:bold t :foreground ,builtin :height 1.7)))) + `(org-level-2 ((,class (:bold t :foreground ,str :height 1.6)))) + `(org-level-3 ((,class (:bold t :foreground ,var :height 1.5)))) + `(org-level-4 ((,class (:bold t :foreground ,func :height 1.4)))) + `(org-level-5 ((,class (:bold t :foreground ,const :height 1.3)))) + `(org-level-6 ((,class (:bold t :foreground ,keyword :height 1.2)))) + `(org-level-7 ((,class (:bold t :foreground ,builtin :height 1.1)))) + `(org-level-8 ((,class (:bold t :foreground ,str :height 1.0)))) + `(org-date ((,class (:underline t :foreground ,var) ))) + `(org-footnote ((,class (:underline t :foreground ,fg4)))) + `(org-link ((,class (:underline t :foreground ,type )))) + `(org-special-keyword ((,class (:foreground ,func)))) + `(org-block ((,class (:foreground ,fg2)))) + `(org-quote ((,class (:inherit org-block :slant italic)))) + `(org-verse ((,class (:inherit org-block :slant italic)))) + `(org-todo ((,class (:foreground ,todo :bold t :italic t)))) + `(org-done ((,class (:foreground ,done :bold t :italic t)))) + `(org-warning ((,class (:underline t :foreground ,warning)))) + `(org-agenda-structure ((,class (:weight bold :foreground ,fg3 :box (:color ,fg4) :background ,bg3)))) + `(org-agenda-date ((,class (:foreground ,var :height 1.1 )))) + `(org-agenda-date-weekend ((,class (:weight normal :foreground ,fg4)))) + `(org-agenda-date-today ((,class (:weight bold :foreground ,keyword :height 1.4)))) + `(org-agenda-done ((,class (:foreground ,bg4)))) + `(org-scheduled ((,class (:foreground ,type)))) + `(org-scheduled-today ((,class (:foreground ,func :weight bold :height 1.2)))) + `(org-ellipsis ((,class (:foreground ,builtin)))) + `(org-verbatim ((,class (:foreground ,str)))) + `(org-document-info-keyword ((,class (:foreground ,func)))) + `(font-latex-bold-face ((,class (:foreground ,type)))) + `(font-latex-italic-face ((,class (:foreground ,var :italic t)))) + `(font-latex-string-face ((,class (:foreground ,str)))) + `(font-latex-match-reference-keywords ((,class (:foreground ,const)))) + `(font-latex-match-variable-keywords ((,class (:foreground ,var)))) + `(ido-only-match ((,class (:foreground ,warning)))) + `(org-sexp-date ((,class (:foreground ,fg4)))) + `(ido-first-match ((,class (:foreground ,keyword :bold t)))) + `(ivy-current-match ((,class (:foreground ,fg3 :inherit highlight :underline t)))) + `(gnus-header-content ((,class (:foreground ,keyword)))) + `(gnus-header-from ((,class (:foreground ,var)))) + `(gnus-header-name ((,class (:foreground ,type)))) + `(gnus-header-subject ((,class (:foreground ,func :bold t)))) + `(mu4e-view-url-number-face ((,class (:foreground ,type)))) + `(mu4e-cited-1-face ((,class (:foreground ,fg2)))) + `(mu4e-cited-7-face ((,class (:foreground ,fg3)))) + `(mu4e-header-marks-face ((,class (:foreground ,type)))) + `(ffap ((,class (:foreground ,fg4)))) + `(js2-private-function-call ((,class (:foreground ,const)))) + `(js2-jsdoc-html-tag-delimiter ((,class (:foreground ,str)))) + `(js2-jsdoc-html-tag-name ((,class (:foreground ,var)))) + `(js2-external-variable ((,class (:foreground ,type )))) + `(js2-function-param ((,class (:foreground ,const)))) + `(js2-jsdoc-value ((,class (:foreground ,str)))) + `(js2-private-member ((,class (:foreground ,fg3)))) + `(js3-warning-face ((,class (:underline ,keyword)))) + `(js3-error-face ((,class (:underline ,warning)))) + `(js3-external-variable-face ((,class (:foreground ,var)))) + `(js3-function-param-face ((,class (:foreground ,fg2)))) + `(js3-jsdoc-tag-face ((,class (:foreground ,keyword)))) + `(js3-instance-member-face ((,class (:foreground ,const)))) + `(warning ((,class (:foreground ,warning)))) + `(ac-completion-face ((,class (:underline t :foreground ,keyword)))) + `(info-quoted-name ((,class (:foreground ,builtin)))) + `(info-string ((,class (:foreground ,str)))) + `(icompletep-determined ((,class :foreground ,builtin))) + `(undo-tree-visualizer-current-face ((,class :foreground ,builtin))) + `(undo-tree-visualizer-default-face ((,class :foreground ,fg2))) + `(undo-tree-visualizer-unmodified-face ((,class :foreground ,var))) + `(undo-tree-visualizer-register-face ((,class :foreground ,type))) + `(slime-repl-inputed-output-face ((,class (:foreground ,type)))) + `(trailing-whitespace ((,class :foreground ,unspec :background ,warning))) + `(rainbow-delimiters-depth-1-face ((,class :foreground ,fg1))) + `(rainbow-delimiters-depth-2-face ((,class :foreground ,type))) + `(rainbow-delimiters-depth-3-face ((,class :foreground ,var))) + `(rainbow-delimiters-depth-4-face ((,class :foreground ,const))) + `(rainbow-delimiters-depth-5-face ((,class :foreground ,keyword))) + `(rainbow-delimiters-depth-6-face ((,class :foreground ,fg1))) + `(rainbow-delimiters-depth-7-face ((,class :foreground ,type))) + `(rainbow-delimiters-depth-8-face ((,class :foreground ,var))) + `(magit-item-highlight ((,class :background ,bg3))) + `(magit-section-heading ((,class (:foreground ,keyword :weight bold)))) + `(magit-hunk-heading ((,class (:background ,bg3)))) + `(magit-section-highlight ((,class (:background ,bg2)))) + `(magit-hunk-heading-highlight ((,class (:background ,bg3)))) + `(magit-diff-context-highlight ((,class (:background ,bg3 :foreground ,fg3)))) + `(magit-diffstat-added ((,class (:foreground ,type)))) + `(magit-diffstat-removed ((,class (:foreground ,var)))) + `(magit-process-ok ((,class (:foreground ,func :weight bold)))) + `(magit-process-ng ((,class (:foreground ,warning :weight bold)))) + `(magit-branch ((,class (:foreground ,const :weight bold)))) + `(magit-log-author ((,class (:foreground ,fg3)))) + `(magit-hash ((,class (:foreground ,fg2)))) + `(magit-diff-file-header ((,class (:foreground ,fg2 :background ,bg3)))) + `(lazy-highlight ((,class (:foreground ,fg2 :background ,bg3)))) + `(term ((,class (:foreground ,fg1 :background ,bg1)))) + `(term-color-black ((,class (:foreground ,bg3 :background ,bg3)))) + `(term-color-blue ((,class (:foreground ,func :background ,func)))) + `(term-color-red ((,class (:foreground ,keyword :background ,bg3)))) + `(term-color-green ((,class (:foreground ,type :background ,bg3)))) + `(term-color-yellow ((,class (:foreground ,var :background ,var)))) + `(term-color-magenta ((,class (:foreground ,builtin :background ,builtin)))) + `(term-color-cyan ((,class (:foreground ,str :background ,str)))) + `(term-color-white ((,class (:foreground ,fg2 :background ,fg2)))) + `(rainbow-delimiters-unmatched-face ((,class :foreground ,warning))) + `(helm-header ((,class (:foreground ,fg2 :background ,bg1 :underline nil :box nil)))) + `(helm-source-header ((,class (:foreground ,keyword :background ,bg1 :underline nil :weight bold)))) + `(helm-selection ((,class (:background ,bg2 :underline nil)))) + `(helm-selection-line ((,class (:background ,bg2)))) + `(helm-visible-mark ((,class (:foreground ,bg1 :background ,bg3)))) + `(helm-candidate-number ((,class (:foreground ,bg1 :background ,fg1)))) + `(helm-separator ((,class (:foreground ,type :background ,bg1)))) + `(helm-time-zone-current ((,class (:foreground ,builtin :background ,bg1)))) + `(helm-time-zone-home ((,class (:foreground ,type :background ,bg1)))) + `(helm-buffer-not-saved ((,class (:foreground ,type :background ,bg1)))) + `(helm-buffer-process ((,class (:foreground ,builtin :background ,bg1)))) + `(helm-buffer-saved-out ((,class (:foreground ,fg1 :background ,bg1)))) + `(helm-buffer-size ((,class (:foreground ,fg1 :background ,bg1)))) + `(helm-ff-directory ((,class (:foreground ,func :background ,bg1 :weight bold)))) + `(helm-ff-file ((,class (:foreground ,fg1 :background ,bg1 :weight normal)))) + `(helm-ff-executable ((,class (:foreground ,var :background ,bg1 :weight normal)))) + `(helm-ff-invalid-symlink ((,class (:foreground ,warning2 :background ,bg1 :weight bold)))) + `(helm-ff-symlink ((,class (:foreground ,keyword :background ,bg1 :weight bold)))) + `(helm-ff-prefix ((,class (:foreground ,bg1 :background ,keyword :weight normal)))) + `(helm-grep-cmd-line ((,class (:foreground ,fg1 :background ,bg1)))) + `(helm-grep-file ((,class (:foreground ,fg1 :background ,bg1)))) + `(helm-grep-finish ((,class (:foreground ,fg2 :background ,bg1)))) + `(helm-grep-lineno ((,class (:foreground ,fg1 :background ,bg1)))) + `(helm-grep-match ((,class (:foreground ,unspec :background ,unspec :inherit helm-match)))) + `(helm-grep-running ((,class (:foreground ,func :background ,bg1)))) + `(helm-moccur-buffer ((,class (:foreground ,func :background ,bg1)))) + `(helm-source-go-package-godoc-description ((,class (:foreground ,str)))) + `(helm-bookmark-w3m ((,class (:foreground ,type)))) + `(company-echo-common ((,class (:foreground ,bg1 :background ,fg1)))) + `(company-preview ((,class (:background ,bg1 :foreground ,var)))) + `(company-preview-common ((,class (:foreground ,bg2 :foreground ,fg3)))) + `(company-preview-search ((,class (:foreground ,type :background ,bg1)))) + `(company-scrollbar-bg ((,class (:background ,bg3)))) + `(company-scrollbar-fg ((,class (:foreground ,keyword)))) + `(company-tooltip ((,class (:foreground ,fg2 :background ,bg2 :bold t)))) + `(company-tooltop-annotation ((,class (:foreground ,const)))) + `(company-tooltip-common ((,class ( :foreground ,fg3)))) + `(company-tooltip-common-selection ((,class (:foreground ,str)))) + `(company-tooltip-mouse ((,class (:inherit highlight)))) + `(company-tooltip-selection ((,class (:background ,bg3 :foreground ,fg3)))) + `(company-template-field ((,class (:inherit region)))) + `(web-mode-builtin-face ((,class (:inherit ,font-lock-builtin-face)))) + `(web-mode-comment-face ((,class (:inherit ,font-lock-comment-face)))) + `(web-mode-constant-face ((,class (:inherit ,font-lock-constant-face)))) + `(web-mode-keyword-face ((,class (:foreground ,keyword)))) + `(web-mode-doctype-face ((,class (:inherit ,font-lock-comment-face)))) + `(web-mode-function-name-face ((,class (:inherit ,font-lock-function-name-face)))) + `(web-mode-string-face ((,class (:foreground ,str)))) + `(web-mode-type-face ((,class (:inherit ,font-lock-type-face)))) + `(web-mode-html-attr-name-face ((,class (:foreground ,func)))) + `(web-mode-html-attr-value-face ((,class (:foreground ,keyword)))) + `(web-mode-warning-face ((,class (:inherit ,font-lock-warning-face)))) + `(web-mode-html-tag-face ((,class (:foreground ,builtin)))) + `(jde-java-font-lock-package-face ((t (:foreground ,var)))) + `(jde-java-font-lock-public-face ((t (:foreground ,keyword)))) + `(jde-java-font-lock-private-face ((t (:foreground ,keyword)))) + `(jde-java-font-lock-constant-face ((t (:foreground ,const)))) + `(jde-java-font-lock-modifier-face ((t (:foreground ,fg2)))) + `(jde-jave-font-lock-protected-face ((t (:foreground ,keyword)))) + `(jde-java-font-lock-number-face ((t (:foreground ,var)))) + `(yas-field-highlight-face ((t (:background ,selection))))) + ;; Legacy + (if (< emacs-major-version 22) + (custom-theme-set-faces + 'dtmacs + `(show-paren-match-face ((,class (:background ,warning))))) ;; obsoleted in 22.1, removed 2016 + (custom-theme-set-faces + 'dtmacs + `(show-paren-match ((,class (:foreground ,bg1 :background ,str)))) + `(show-paren-mismatch ((,class (:foreground ,bg1 :background ,warning)))))) + ;; emacs >= 26.1 + (when (>= emacs-major-version 26) + (custom-theme-set-faces + 'dtmacs + `(line-number ((t (:inherit fringe)))) + `(line-number-current-line ((t (:inherit fringe :foreground ,fg6 :weight bold)))))) + + ;; emacs >= 27.1 + (when (>= emacs-major-version 27) + (custom-theme-set-faces + 'dtmacs + `(tab-line ((,class (:background ,bg2 :foreground ,fg4)))) + `(tab-line-tab ((,class (:inherit tab-line)))) + `(tab-line-tab-inactive ((,class (:background ,bg2 :foreground ,fg4)))) + `(tab-line-tab-current ((,class (:background ,bg1 :foreground ,fg1)))) + `(tab-line-highlight ((,class (:background ,bg1 :foreground ,fg2)))))) + (when (>= emacs-major-version 28) + (custom-theme-set-faces + 'dtmacs + `(line-number ((t (:inherit fringe)))) + `(line-number-current-line ((t (:inherit fringe :foreground ,fg6 :weight bold)))))) +;; emacs >= 27.1 +(when (>= emacs-major-version 27) + (custom-theme-set-faces + 'dtmacs + `(tab-line ((,class (:background ,bg2 :foreground ,fg4)))) + `(tab-line-tab ((,class (:inherit tab-line)))) + `(tab-line-tab-inactive ((,class (:background ,bg2 :foreground ,fg4)))) + `(tab-line-tab-current ((,class (:background ,bg1 :foreground ,fg1)))) + `(tab-line-highlight ((,class (:background ,bg1 :foreground ,fg2)))))) + (when (>= emacs-major-version 28) + (custom-theme-set-faces + 'dtmacs + `(tab-line-tab-modified ((,class (:foreground ,warning2 :weight bold)))))) + (when (boundp 'font-lock-regexp-face) + (custom-theme-set-faces + 'dtmacs + `(font-lock-regexp-face ((,class (:inherit font-lock-string-face :underline t))))))) + +;;;###autoload +(when load-file-name + (add-to-list 'custom-theme-load-path + (file-name-as-directory (file-name-directory load-file-name)))) + +(provide-theme 'dtmacs) + +;; Local Variables: +;; no-byte-compile: t +;; End: + +;;; dtmacs-theme.el ends here