Commit 6f760e2658e2
Changed files (241)
home
common
desktop
sway
tools
emacs
config
eshell
etc
eshell
orgmode
yasnippet
snippets
c++-mode
c-mode
go-mode
haskell-mode
haskell-mode
js-mode
lisp-mode
python-mode
text-mode
lisp
transient
home/common/desktop/sway/default.nix
@@ -4,10 +4,6 @@ let
#!/usr/bin/env bash
fd . -d 3 --type d ~/src | ${pkgs.wofi}/bin/wofi -dmenu | xargs -I {} zsh -i -c "cd {}; emacs ."
'';
- emacs-mini = pkgs.writeScript "emacs-mini" ''
- #!/usr/bin/env bash
- emacs --init-directory=$HOME/src/home/tools/emacs/mini
- '';
fontConf = {
names = [ "JetBrains Mono" ];
size = 12.0;
@@ -124,7 +120,7 @@ in
"${mod}+Shift+Return" = "exec emacsclient -c";
"${mod}+Control+Return" = "exec emacs";
"${mod}+Control+Shift+Return" = "exec ${emacs-in-folder}";
- "${mod}+Control+Alt+Return" = "exec ${emacs-mini}";
+ "${mod}+Control+Alt+Return" = "exec emacs"; # TODO: remove this
"${mod}+Left" = "focus left";
"${mod}+Down" = "focus down";
@@ -232,7 +228,7 @@ in
always = true;
}
# Probably put a condition here.
- { command = "emacs --init-directory=$HOME/src/home/tools/emacs/mini --fg-daemon"; }
+ { command = "emacs --init-directory=$HOME/src/home/tools/emacs --fg-daemon"; }
{ command = "i3-back"; }
{ command = "firefox"; }
{ command = "${pkgs.kitty}/bin/kitty --title metask --class metask"; }
@@ -244,7 +240,7 @@ in
inherit (config.wayland.windowManager.sway.config) menu;
in
''
- bindcode ${mod}+Control+Shift+Alt+41 exec ${emacs-mini}
+ bindcode ${mod}+Control+Shift+Alt+41 exec emacs
bindcode ${mod}+33 exec "${menu}"
bindcode ${mod}+Shift+33 exec "raffi -I"
bindcode ${mod}+Control+33 exec "${pkgs.wofi-emoji}/bin/wofi-emoji -G"
tools/emacs/config/00-clean.el
@@ -1,79 +0,0 @@
-;;; 00-clean.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; no-littering and recentf configurations
-;;; Note: this file is autogenerated from an org-mode file.
-;;; Code:
-
-(setopt make-backup-files nil)
-(setopt backup-inhibited nil) ; Not sure if needed, given `make-backup-files'
-(setopt create-lockfiles nil)
-
-(use-package recentf
- :hook (after-init . recentf-mode)
- :custom
- (recentf-max-saved-items 500)
- (recentf-save-file (locate-user-emacs-file "auto-save-list/recent-file-list.el"))
- (recentf-auto-cleanup "8:00am")
- (recentf-show-file-shortcuts-flag nil)
- (recentf-exclude
- '("\\.?cache" ".cask" "url" "COMMIT_EDITMSG\\'" "bookmarks"
- "\\.\\(?:gz\\|gif\\|svg\\|elc\\|png\\|jpe?g\\|bmp\\|xpm\\)$"
- "\\.?ido\\.last$" "\\.revive$" "/G?TAGS$" "/.elfeed/"
- "^/tmp/" "^/var/folders/.+$" "^/sudo:" "^/su:" "^/ssh:" "^/sshfs:"
- (lambda (file) (file-in-directory-p file package-user-dir))))
- :config
- (push (expand-file-name recentf-save-file) recentf-exclude)
- ;; Magic advice to rename entries in recentf when moving files in
- ;; dired.
- (defun rjs/recentf-rename-notify (oldname newname &rest args)
- (if (file-directory-p newname)
- (rjs/recentf-rename-directory oldname newname)
- (rjs/recentf-rename-file oldname newname)))
-
- (defun rjs/recentf-rename-file (oldname newname)
- (setq recentf-list
- (mapcar (lambda (name)
- (if (string-equal name oldname)
- newname
- oldname))
- recentf-list))
- recentf-cleanup)
-
- (defun rjs/recentf-rename-directory (oldname newname)
- ;; oldname, newname and all entries of recentf-list should already
- ;; be absolute and normalised so I think this can just test whether
- ;; oldname is a prefix of the element.
- (setq recentf-list
- (mapcar (lambda (name)
- (if (string-prefix-p oldname name)
- (concat newname (substring name (length oldname)))
- name))
- recentf-list))
- recentf-cleanup)
- (add-to-list 'recentf-filename-handlers 'abbreviate-file-name)
- (advice-add 'dired-rename-file :after #'rjs/recentf-rename-notify))
-
-
-;; 2024-07-08: Do I have to setup this, or should I do like prot, disable *all* backup, lockfile, …
-(use-package no-littering ; Keep .emacs.d clean
- :config
- (require 'recentf)
- (add-to-list 'recentf-exclude no-littering-var-directory)
- (add-to-list 'recentf-exclude no-littering-etc-directory)
-
- ;; Move this in its own thing
- (setq
- create-lockfiles nil
- delete-old-versions t
- kept-new-versions 6
- kept-old-versions 2
- version-control t)
-
- (setq
- backup-directory-alist
- `((".*" . ,(no-littering-expand-var-file-name "backup/")))
- auto-save-file-name-transforms
- `((".*" ,(no-littering-expand-var-file-name "auto-save/") t))))
-
-(provide '00-clean)
-;;; 00-clean.el ends here
tools/emacs/config/config-appearance.el
@@ -1,164 +0,0 @@
-;;; config-appearance.el --- -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Appearance configuration
-;;; Code:
-
-(set-face-attribute 'fill-column-indicator nil
- :foreground "#717C7C") ; katana-gray
-(global-display-fill-column-indicator-mode 1)
-
-(setopt echo-keystrokes 0.1
- line-number-display-limit-width 10000
- indicate-buffer-boundaries 'left
- indicate-empty-lines +1)
-
-(line-number-mode 1)
-(column-number-mode 1)
-
-;; let's enable it for all programming major modes
-(add-hook 'prog-mode-hook #'hl-line-mode)
-;; and for all modes derived from text-mode
-(add-hook 'text-mode-hook #'hl-line-mode)
-
-(use-package frame
- :unless noninteractive
- :commands vde/cursor-type-mode
- :config
- (setq-default cursor-type 'box)
- (setq-default cursor-in-non-selected-windows '(bar . 2))
- (setq-default blink-cursor-blinks 50)
- (setq-default blink-cursor-interval nil) ; 0.75 would be my choice
- (setq-default blink-cursor-delay 0.2)
-
- (blink-cursor-mode -1)
-
- (define-minor-mode vde/cursor-type-mode
- "Toggle between static block and pulsing bar cursor."
- :init-value nil
- :global t
- (if vde/cursor-type-mode
- (progn
- (setq-local blink-cursor-interval 0.75
- cursor-type '(bar . 2)
- cursor-in-non-selected-windows 'hollow)
- (blink-cursor-mode 1))
- (dolist (local '(blink-cursor-interval
- cursor-type
- cursor-in-non-selected-windows))
- (kill-local-variable `,local))
- (blink-cursor-mode -1))))
-
-(use-package emacs
- :config
- (setq-default custom-safe-themes t)
- (setq-default custom--inhibit-theme-enable nil)
-
- (defun vde/before-load-theme (&rest args)
- "Clear existing theme settings instead of layering them.
-Ignores `ARGS'."
- (mapc #'disable-theme custom-enabled-themes))
-
- (advice-add 'load-theme :before #'vde/before-load-theme))
-
-(use-package emacs
- :config
- (setq window-divider-default-right-width 1)
- (setq window-divider-default-bottom-width 1)
- (setq window-divider-default-places 'right-only)
- :hook (after-init . window-divider-mode))
-
-(use-package tab-bar
- :unless noninteractive
- :config
- (setq-default tab-bar-close-button-show nil)
- (setq-default tab-bar-close-last-tab-choice 'tab-bar-mode-disable)
- (setq-default tab-bar-close-tab-select 'recent)
- (setq-default tab-bar-new-tab-choice t)
- (setq-default tab-bar-new-tab-to 'right)
- (setq-default tab-bar-position nil)
- (setq-default tab-bar-show t)
- (setq-default tab-bar-tab-hints nil)
- (setq-default tab-bar-tab-name-function 'vde/tab-bar-tab-name)
-
- (defun vde/tab-bar-tab-name ()
- "Generate tab name from the buffer of the selected window *or* projectile."
- (cond
- ((project-current) (let ((project-path (vde-project--project-current)))
- (cond ((string-prefix-p "~/src" project-path)
- (directory-file-name (file-relative-name project-path "~/src")))
- ((string-prefix-p "~/desktop" project-path)
- (directory-file-name (file-relative-name project-path "~/desktop")))
- ((string-prefix-p "/etc" project-path)
- (directory-file-name (file-relative-name project-path "/etc")))
- (t
- (file-relative-name project-path)))))
- (t (tab-bar-tab-name-current-with-count))))
-
- (defun vde/complete-tab-bar-tab-dwim ()
- "Do-What-I-Mean function for getting to a `tab-bar-mode' tab.
-If no other tab exists, create one and switch to it. If there is
-one other tab (so two in total) switch to it without further
-questions. Else use completion to select the tab to switch to."
- (interactive)
- (let ((tabs (mapcar (lambda (tab)
- (alist-get 'name tab))
- (tab-bar--tabs-recent))))
- (cond ((eq tabs nil)
- (tab-new))
- ((eq (length tabs) 1)
- (tab-next))
- (t
- (tab-bar-switch-to-tab
- (completing-read "Select tab: " tabs nil t))))))
-
- :bind (("C-x t t" . vde/complete-tab-bar-tab-dwim)
- ("C-x t s" . tab-switcher)
- ("C-<next>" . tab-next)
- ("C-<prior>" . tab-previous)))
-
-(use-package minions
- :hook (after-init . minions-mode)
- :config
- (add-to-list 'minions-prominent-modes 'flymake-mode))
-
-(use-package time
- :unless noninteractive
- :config
- (setq-default display-time-24hr-format t
- display-time-day-and-date t
- display-time-world-list '(("Europe/Paris" "Paris")
- ("Europe/London" "London")
- ("America/New_York" "Boston")
- ("America/Los_Angeles" "San Francisco")
- ("Asia/Calcutta" "Bangalore")
- ("Australia/Brisbane" "Brisbane"))
- display-time-string-forms
- '((format "%s %s %s, %s:%s"
- dayname
- monthname day
- 24-hours minutes)))
- (display-time))
-
-(use-package tooltip
- :unless noninteractive
- :config
- (setq tooltip-delay 0.5)
- (setq tooltip-short-delay 0.5)
- (setq x-gtk-use-system-tooltips nil)
- (setq tooltip-frame-parameters
- '((name . "tooltip")
- (internal-border-width . 6)
- (border-width . 0)
- (no-special-glyphs . t)))
- :hook (after-init . tooltip-mode))
-
-(use-package alert
- :init
- (defun alert-after-finish-in-background (buf str)
- (when (or (not (get-buffer-window buf 'visible)) (not (frame-focus-state)))
- (alert str :buffer buf)))
- :config
- (setq alert-default-style 'libnotify))
-
-(provide 'config-appearance)
-;;; config-appearance.el ends here
tools/emacs/config/config-buffers.el
@@ -1,109 +0,0 @@
-;;; config-buffers.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Buffer related configurations
-;;; Code:
-
-(use-package savehist
- :unless noninteractive
- :hook (after-init . savehist-mode)
- :init
- (setq savehist-file (no-littering-expand-var-file-name "savehist"))
- :config
- (setq-default history-length 10000
- savehist-save-minibuffer-history t
- savehist-delete-duplicates t
- savehist-autosave-interval 180
- savehist-additional-variables '(extended-command-history
- search-ring
- regexp-search-ring
- comint-input-ring
- compile-history
- last-kbd-macro
- shell-command-history)))
-
-(use-package uniquify
- :unless noninteractive
- :config
- (setq-default uniquify-buffer-name-style 'post-forward
- uniquify-separator ":"
- uniquify-ignore-buffers-re "^\\*"
- uniquify-after-kill-buffer-p t))
-
-(use-package ibuffer
- :unless noninteractive
- :commands (ibuffer)
- :bind (("C-x C-b" . ibuffer)
- ([remap list-buffers] . ibuffer))
- :config
- (setq-default ibuffer-expert t
- ibuffer-filter-group-name-face 'font-lock-doc-face
- ibuffer-default-sorting-mode 'filename/process
- ibuffer-use-header-line t
- ibuffer-show-empty-filter-groups nil)
- ;; Use human readable Size column instead of original one
- (define-ibuffer-column size-h
- (:name "Size" :inline t)
- (cond
- ((> (buffer-size) 1000000) (format "%7.1fM" (/ (buffer-size) 1000000.0)))
- ((> (buffer-size) 1000) (format "%7.1fk" (/ (buffer-size) 1000.0)))
- (t (format "%8d" (buffer-size)))))
-
- ;; (setq ibuffer-formats
- ;; '((mark modified read-only " "
- ;; (name 18 18 :left :elide)
- ;; " "
- ;; (size-h 9 -1 :right)
- ;; " "
- ;; (mode 16 16 :left :elide)
- ;; " "
- ;; filename-and-process)
- ;; (mark modified read-only " "
- ;; (name 18 18 :left :elide)
- ;; " "
- ;; (size 9 -1 :right)
- ;; " "
- ;; (mode 16 16 :left :elide)
- ;; " "
- ;; (vc-status 16 16 :left)
- ;; " "
- ;; filename-and-process)))
- )
-
-(use-package ibuffer-vc
- :unless noninteractive
- :commands (ibuffer-vc-set-filter-groups-by-vc-root)
- :hook (ibuffer . (lambda ()
- (ibuffer-vc-set-filter-groups-by-vc-root)
- (unless (eq ibuffer-sorting-mode 'filename/process)
- (ibuffer-do-sort-by-filename/process)))))
-
-;; (unless noninteractive
-;; (require 'popper)
-;; (setq popper-reference-buffers
-;; '("\\*Messages\\*"
-;; "Output\\*$"
-;; "\\*Async Shell Command\\*"
-;; "\\*Warnings\\*"
-;; "\\*Compile-Log\\*"
-;; help-mode
-;; helpful-mode
-;; compilation-mode
-;; flymake-diagnostics-buffer-mode
-;; flymake-project-diagnostics-mode
-;; Man-mode
-;; woman-mode))
-;; (global-set-key (kbd "C-`") 'popper-toggle)
-;; (global-set-key (kbd "M-`") 'popper-cycle)
-;; (global-set-key (kbd "C-M-`") 'popper-toggle-type)
-;; (popper-mode +1)
-;;
-;; ;; For echo-area hints
-;; (require 'popper-echo)
-;; (popper-echo-mode +1))
-
-(use-package goto-addr
- :hook ((text-mode . goto-address-mode)
- (prog-mode . goto-address-prog-mode)))
-
-(provide 'config-buffers)
-;;; config-buffers.el ends here
tools/emacs/config/config-compile.el
@@ -1,104 +0,0 @@
-;;; config-compile.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Generic compilation configuration
-;;; Code:
-
-(defun my-recompile (args)
- (interactive "P")
- (cond
- ((eq major-mode #'emacs-lisp-mode)
- (call-interactively 'eros-eval-defun))
- ((bound-and-true-p my-vterm-command)
- (my-vterm-execute-region-or-current-line my-vterm-command))
- ((get-buffer "*compilation*")
- (with-current-buffer"*compilation*"
- (recompile)))
- ((get-buffer "*Go Test*")
- (with-current-buffer "*Go Test*"
- (recompile)))
- ((and (eq major-mode #'go-mode)
- buffer-file-name
- (string-match
- "_test\\'" (file-name-sans-extension buffer-file-name)))
- (my-gotest-maybe-ts-run))
- ((and (get-buffer "*cargo-test*")
- (boundp 'my-rustic-current-test-compile)
- my-rustic-current-test-compile)
- (with-current-buffer "*cargo-test*"
- (rustic-cargo-test-run my-rustic-current-test-compile)))
- ((get-buffer "*cargo-run*")
- (with-current-buffer "*cargo-run*"
- (rustic-cargo-run-rerun)))
- ((get-buffer "*pytest*")
- (with-current-buffer "*pytest*"
- (recompile)))
- ((eq major-mode #'python-mode)
- (compile (concat python-shell-interpreter " " (buffer-file-name))))
- ((call-interactively 'compile))))
-
-;; UseCompile
-(use-package compile
- :unless noninteractive
- :commands (compile)
- :preface
- (autoload 'ansi-color-apply-on-region "ansi-color")
-
- (defvar compilation-filter-start)
-
- (defun vde/colorize-compilation-buffer ()
- (unless (or (derived-mode-p 'grep-mode)
- (derived-mode-p 'ag-mode)
- (derived-mode-p 'rg-mode))
- (let ((inhibit-read-only t))
- (ansi-color-apply-on-region compilation-filter-start (point)))))
- :config
- (setq-default compilation-scroll-output t
- ;; I'm not scared of saving everything.
- compilation-ask-about-save nil
- ;; Automatically scroll and jump to the first error
- ;; compilation-scroll-output 'next-error
- ;; compilation-scroll-output 'first-error
- ;; compilation-auto-jump-to-first-error t
- ;; Skip over warnings and info messages in compilation
- compilation-skip-threshold 2
- ;; Don't freeze when process reads from stdin
- compilation-disable-input t
- ;; Show three lines of context around the current message
- compilation-context-lines 3
- )
- (add-hook 'compilation-finish-functions #'alert-after-finish-in-background)
- (add-hook 'comint-output-filter-functions
- 'comint-watch-for-password-prompt)
- (setq-default comint-password-prompt-regexp
- (concat
- "\\("
- "^Enter passphrase.*:"
- "\\|"
- "^Repeat passphrase.*:"
- "\\|"
- "[Pp]assword for '[a-z0-9_-.]+':"
- "\\|"
- "\\[sudo\\] [Pp]assword for [a-z0-9_-.]+:"
- "\\|"
- "[a-zA-Z0-9]'s password:"
- "\\|"
- "^[Pp]assword:"
- "\\|"
- "^[Pp]assword (again):"
- "\\|"
- ".*\\([Ww]ork\\|[Pp]ersonal\\).* password:"
- "\\|"
- "Password for '([^()]+)' GNOME keyring"
- "\\|"
- "Password for 'http.*github.*':"
- "\\)"))
- (add-hook 'compilation-filter-hook #'vde/colorize-compilation-buffer))
-
-(use-package emacs
- :bind
- (:map prog-mode-map
- ("C-M-<return>" . compile)
- ("C-<return>" . my-recompile)))
-
-(provide 'config-compile)
-;;; config-compile.el ends here
tools/emacs/config/config-completion.el
@@ -1,342 +0,0 @@
-;;; config-completion.el --- -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Setup completion framework
-;;; Code
-
-(use-package which-key
- :custom
- (which-key-separator " → " )
- :hook
- (after-init . which-key-mode)
- :config
-
- ;; Define custom, concise descriptions for `tab-bar` commands under "C-x t"
- (which-key-add-key-based-replacements
- "C-x t C-f" "Open file in new tab"
- "C-x t RET" "Switch tabs"
- "C-x t C-r" "Open file (read-only) in new tab"
- "C-x t 0" "Close current tab"
- "C-x t 1" "Close other tabs"
- "C-x t 2" "New empty tab"
- "C-x t G" "Group tabs"
- "C-x t M" "Move tab to position"
- "C-x t N" "New tab and switch to it"
- "C-x t O" "Previous tab"
- "C-x t b" "Switch buffer in new tab"
- "C-x t d" "Dired in new tab"
- "C-x t f" "Open file in new tab"
- "C-x t m" "Move tab left/right"
- "C-x t n" "Duplicate tab"
- "C-x t o" "Next tab"
- "C-x t p" "Project in new tab"
- "C-x t r" "Rename tab"
- "C-x t t" "Switch to other tab"
- "C-x t u" "Undo tab close"
- "C-x t ^ f" "Detach tab window"))
-
-(use-package consult
- :bind
- ("M-g M-g" . consult-goto-line)
- ("M-K" . consult-keep-lines)
- ("M-s M-b" . consult-buffer)
- ("M-s M-f" . consult-find)
- ("M-s M-g" . consult-grep)
- ("M-s M-r" . consult-ripgrep)
- ("M-s M-h" . consult-history)
- ("M-s M-l" . consult-line)
- ("M-s M-m" . consult-mark)
- ("M-s M-y" . consult-yank-pop)
- ("M-s M-s" . consult-outline)
- :config
- ;; (general-leader
- ;; "y" #'(consult-yank-pop :which-key "Clipboard history")
- ;; "b" '(:ignore t :which-key "buffer")
- ;; "bb" #'(consult-buffer :which-key "switch buffer")
- ;; "bd" #'(kill-current-buffer :which-key "kill buffer")
- ;; "bD" #'((lambda ()(interactive)(kill-current-buffer)(tab-close)) :wk "Kill buffer and tab")
- ;; "bn" #'(next-buffer :which-key "next buffer")
- ;; "bp" #'(previous-buffer :which-key "previous buffer")
- ;; "s" '(:ignore t :which-key "search")
- ;; "sg" #'(consult-grep :which-key "Consult grep in current directory")
- ;; "sR" #'(consult-ripgrep :which-key "Consult ripgrep in current directory")
- ;; "sr" '(:ignore t :which-key "rg.el")'
- ;; "srp" #'(rg-project :which-key "rg.el in current project")
- ;; "srs" #'(rg-dwim :which-key "rg.el Do What I Mean")
- ;; "sh" #'(Info-goto-emacs-command-node :wk "Search help")
- ;; "sc" #'(consult-mode-command :wk "Mode Command")
- ;; "s/" #'(consult-isearch-history :wk "Consult Isearch history")
- ;; "g" '(:ignore t :which-key "go")
- ;; "gu" #'(ffap-next-url :which-key "next url")
- ;; "gd" #'(xref-find-definitions :which-key "find definition")
- ;; "gD" #'(xref-find-definitions-other-window :which-key "find definition (other window)"))
- )
-
-(use-package consult-imenu
- :after (consult)
- :commands (consult-imenu)
- :bind
- ("M-s M-i" . consult-imenu))
-
-(use-package consult-xref
- :after (consult)
- :commands (consult-xref)
- :config
- (setq xref-show-xrefs-function #'consult-xref
- xref-show-definitions-function #'consult-xref)
- (defvar consult--xref-history nil
- "History for the `consult-recent-xref' results.")
-
- (defun consult-recent-xref (&optional markers)
- "Jump to a marker in MARKERS list (defaults to `xref--history'.
-
-The command supports preview of the currently selected marker position.
-The symbol at point is added to the future history."
- (interactive)
- (consult--read
- (consult--global-mark-candidates
- (or markers (flatten-list xref--history)))
- :prompt "Go to Xref: "
- :annotate (consult--line-prefix)
- :category 'consult-location
- :sort nil
- :require-match t
- :lookup #'consult--lookup-location
- :history '(:input consult--xref-history)
- :add-history (thing-at-point 'symbol)
- :state (consult--jump-state))))
-
-;; https://github.com/oantolin/embark/blob/master/embark-consult.el
-(use-package embark
- :unless noninteractive
- :commands (emark-act embark-dwim embark-prefix-help-command)
- :bind
- ("C-." . embark-act)
- ("M-." . embark-dwim)
- ("C-h b" . embark-bindings)
- ("C-h B" . embark-bindings-at-point)
- ("C-h M" . embark-bindings-in-keymap)
- ("C-h E" . embark-on-last-message)
- (:map completion-list-mode-map
- ("." . embark-act))
- (:map embark-collect-mode-map
- ("a") ; I don't like my own default :)
- ("." . embark-act)
- ("F" . consult-focus-lines))
- (:map embark-package-map
- ("t" . try))
- (:map embark-identifier-map
- ("(" . insert-parentheses)
- ("[" . insert-pair-map))
- (:map embark-expression-map
- ("(" . insert-parentheses)
- ("[" . insert-pair-map))
- (:map embark-region-map
- ("(" . insert-parentheses)
- ("[" . insert-pair-map)
- ("D" . dictionary-search))
- (:map embark-email-map
- ("+" . add-email-to-ecomplete)
- ("\\" . remove-email-from-ecomplete))
- (:map embark-encode-map
- ("p" . topaz-paste-region))
- (:map embark-url-map
- ("x" . browse-url-generic)
- ("p" . pocket-lib-add-urls))
- (:map embark-identifier-map
- ("D" . dictionary-lookup-definition))
- :custom
- (embark-quit-after-action t)
- (prefix-help-command #'embark-prefix-help-command)
- (embark-indicators '(embark-minimal-indicator
- embark-highlight-indicator
- embark-isearch-highlight-indicator))
- (embark-cycle-key ".")
- (embark-help-key "?")
- (embark-confirm-act-all nil)
- :config
- (setq embark-candidate-collectors
- (cl-substitute 'embark-sorted-minibuffer-candidates
- 'embark-minibuffer-candidates
- embark-candidate-collectors))
- (dolist (cmd '(comment-dwim
- insert-parentheses
- insert-pair
- markdown-insert-code
- markdown-insert-italic
- markdown-insert-bold
- org-emphasize
- cdlatex-math-modify
- TeX-font))
- (push #'embark--mark-target (alist-get cmd embark-around-action-hooks)))
- (push #'embark--xref-push-marker
- (alist-get 'find-file embark-pre-action-hooks))
- (defun embark-on-last-message (arg)
- "Act on the last message displayed in the echo area."
- (interactive "P")
- (with-current-buffer "*Messages*"
- (goto-char (1- (point-max)))
- (embark-act arg)))
-
- (defmacro ct/embark-display-in-side-window (side)
- `(defun ,(intern (concat "display-in-side-window--" (symbol-name side))) (&optional buffer)
- (interactive "b")
- (when-let* ((buffer (or buffer (current-buffer)))
- (display-buffer-overriding-action '((display-buffer-in-side-window)
- (dedicated . t)
- (side . ,side)
- (window-parameters . ((no-delete-other-windows . t))))))
- (display-buffer buffer))))
- (define-key embark-buffer-map (kbd "s b") (ct/embark-display-in-side-window bottom))
- (define-key embark-buffer-map (kbd "s l") (ct/embark-display-in-side-window left))
- (define-key embark-buffer-map (kbd "s r") (ct/embark-display-in-side-window right))
-
- (defun embark-which-key-indicator ()
- "An embark indicator that displays keymaps using which-key.
-The which-key help message will show the type and value of the
-current target followed by an ellipsis if there are further
-targets."
- (lambda (&optional keymap targets prefix)
- (if (null keymap)
- (which-key--hide-popup-ignore-command)
- (which-key--show-keymap
- (if (eq (plist-get (car targets) :type) 'embark-become)
- "Become"
- (format "Act on %s '%s'%s"
- (plist-get (car targets) :type)
- (embark--truncate-target (plist-get (car targets) :target))
- (if (cdr targets) "…" "")))
- (if prefix
- (pcase (lookup-key keymap prefix 'accept-default)
- ((and (pred keymapp) km) km)
- (_ (key-binding prefix 'accept-default)))
- keymap)
- nil nil t (lambda (binding)
- (not (string-suffix-p "-argument" (cdr binding))))))))
-
- (setq embark-indicators
- '(embark-which-key-indicator
- embark-highlight-indicator
- embark-isearch-highlight-indicator))
-
- (defun embark-hide-which-key-indicator (fn &rest args)
- "Hide the which-key indicator immediately when using the completing-read prompter."
- (which-key--hide-popup-ignore-command)
- (let ((embark-indicators
- (remq #'embark-which-key-indicator embark-indicators)))
- (apply fn args)))
-
- (advice-add #'embark-completing-read-prompter
- :around #'embark-hide-which-key-indicator))
-
-(use-package embark-consult
- :after (embark consult)
- :unless noninteractive
- :hook
- (embark-collect-mode . consult-preview-at-point-mode))
-
-(setq minibuffer-prompt-properties
- '(read-only t cursor-intangible t face minibuffer-prompt))
-(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
-
-(use-package emacs
- :unless noninteractive
- :custom
- (completion-cycle-threshold 2)
- (completion-ignore-case t)
- (completion-show-inline-help nil)
- (completions-detailed t)
- (enable-recursive-minibuffers t)
- (read-buffer-completion-ignore-case t)
- (read-file-name-completion-ignore-case t)
- (resize-mini-windows t)
- (tab-always-indent 'complete)
- :config
- (minibuffer-depth-indicate-mode 1)
- (minibuffer-electric-default-mode 1))
-
-(use-package vertico
- :unless noninteractive
- :hook (after-init . vertico-mode))
-
-(use-package marginalia
- :unless noninteractive
- :hook (after-init . marginalia-mode))
-
-(use-package corfu
- :unless noninteractive
- :bind (("C-<tab>" . corfu-candidate-overlay-complete-at-point))
- :hook (after-init . global-corfu-mode)
- :init
- (require 'corfu-popupinfo)
- (require 'corfu-history)
- (require 'corfu-candidate-overlay)
- :config
- (setq corfu-popupinfo-delay '(1.25 . 0.5))
- (corfu-popupinfo-mode 1)
- (corfu-candidate-overlay-mode)
- ;; Sort by input history (no need to modify `corfu-sort-function').
- (with-eval-after-load 'savehist
- (corfu-history-mode 1)
- (add-to-list 'savehist-additional-variables 'corfu-history))
-
- ;; Adapted from Corfu's manual.
- (defun contrib/corfu-enable-always-in-minibuffer ()
- "Enable Corfu in the minibuffer if MCT or Vertico is not active.
-Useful for prompts such as `eval-expression' and `shell-command'."
- (unless (or (bound-and-true-p vertico--input)
- (bound-and-true-p mct--active))
- (corfu-mode 1)))
-
- (add-hook 'minibuffer-setup-hook #'contrib/corfu-enable-always-in-minibuffer 1))
-
-;; Seems like it is a bit impacting the performance somehow.
-;; (use-package corfu-candidate-overlay
-;; :after corfu
-;; :bind (("C-<tab>" . corfu-candidate-overlay-complete-at-point))
-;; :config
-;; (corfu-candidate-overlay-mode +1))
-
-(use-package cape
- :bind (("C-c p f" . cape-file)
- ("C-c p /" . cape-dabbrev)
- :map corfu-map
- ("M-/" . cape-dabbrev)
- ("C-x C-f" . cape-file))
- :config
- (add-to-list 'completion-at-point-functions #'cape-file))
-
-(use-package orderless
- :unless noninteractive
- :config
- (setq completion-styles
- '(orderless basic substring initials flex partial-completion))
- (setq completion-category-defaults nil)
- (setq completion-category-overrides nil)
- )
-
-(use-package tempel
- :bind (("M-+" . tempel-complete) ;; Alternative tempel-expand
- ("M-*" . tempel-insert))
- :init
- ;; (defun tempel-setup-capf ()
- ;; ;; Add the Tempel Capf to `completion-at-point-functions'.
- ;; ;; `tempel-expand' only triggers on exact matches. Alternatively use
- ;; ;; `tempel-complete' if you want to see all matches, but then you
- ;; ;; should also configure `tempel-trigger-prefix', such that Tempel
- ;; ;; does not trigger too often when you don't expect it. NOTE: We add
- ;; ;; `tempel-expand' *before* the main programming mode Capf, such
- ;; ;; that it will be tried first.
- ;; (setq-local completion-at-point-functions
- ;; (cons #'tempel-expand
- ;; completion-at-point-functions)))
- (setq tempel-path (expand-file-name "templates" user-emacs-directory))
- ;; (add-hook 'conf-mode-hook 'tempel-setup-capf)
- ;; (add-hook 'prog-mode-hook 'tempel-setup-capf)
- ;; (add-hook 'text-mode-hook 'tempel-setup-capf)
- )
-
-(use-package tempel-collection
- :after tempel)
-
-(provide 'config-completion)
-;;; config-completion.el ends here
tools/emacs/config/config-dired.el
@@ -1,244 +0,0 @@
-;;; config-dired.el -- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Configuration of Dired
-;;; Code:
-
-(defun my-substspaces (str)
- (subst-char-in-string ?\s ?_ str))
-
-(defmacro vde/dired-fd (name doc prompt &rest flags)
- "Make commands for selecting 'fd' results with completion.
-NAME is how the function should be named. DOC is the function's
-documentation string. PROMPT describes the scope of the query.
-FLAGS are the command-line arguments passed to the 'fd'
-executable, each of which is a string."
- `(defun ,name (&optional arg)
- ,doc
- (interactive "P")
- (let* ((vc (vc-root-dir))
- (dir (expand-file-name (if vc vc default-directory)))
- (regexp (read-regexp
- (format "%s matching REGEXP in %s: " ,prompt
- (propertize dir 'face 'bold))))
- (names (process-lines "fd" ,@flags regexp dir))
- (buf "*FD Dired*"))
- (if names
- (if arg
- (dired (cons (generate-new-buffer-name buf) names))
- (find-file
- (completing-read (format "Items matching %s (%s): "
- (propertize regexp 'face 'success)
- (length names))
- names nil t))))
- (user-error (format "No matches for « %s » in %s" regexp dir)))))
-
-(use-package dired
- :unless noninteractive
- :commands (dired find-name-dired)
- :hook ((dired-mode . dired-hide-details-mode)
- (dired-mode . toggle-truncate-lines)
- (dired-mode . hl-line-mode))
- :bind (("C-c RET" . vde/open-in-external-app)
- ("C-c f g" . vde/dired-get-size)
- ("M-s d" . vde/dired-fd-dirs)
- ("M-s z" . vde/dired-fd-files-and-dirs)
- ("C-c f f" . find-name-dired)
- (:map dired-mode-map
- ("M-p" . vde/dired-up)
- ("^" . vde/dired-up)
- ("<backspace>" . vde/dired-up)
- ("M-n" . vde/dired-down)
- ("!" . vde/sudired)
- ("<prior>" . beginend-dired-mode-goto-beginning)
- ("<next>" . beginend-dired-mode-goto-end)
- ("b" . dired-do-open)))
- :config
- (setq-default dired-auto-revert-buffer t
- dired-recursive-copies 'always
- dired-recursive-deletes 'always
- dired-isearch-filenames 'dwim
- delete-by-moving-to-trash t
- dired-listing-switches "-lFaGh1v --group-directories-first"
- dired-ls-F-marks-symlinks t
- dired-dwim-target t)
-
- (when (string= system-type "darwin")
- (setq dired-use-ls-dired t
- insert-directory-program "/usr/local/bin/gls"))
-
- ;; Enable dired-find-alternate-file
- (put 'dired-find-alternate-file 'disabled nil)
-
- (defun vde/dired-substspaces (&optional arg)
- "Rename all marked (or next ARG) files so that spaces are replaced with underscores."
- (interactive "P")
- (dired-rename-non-directory #'my-substspaces "Rename by substituting spaces" arg))
- (if (keymap-lookup dired-mode-map "% s")
- (message "Error: %% s already defined in dired-mode-map")
- (define-key dired-mode-map "%s" 'vde/dired-substspaces))
-
- (defun vde/dired-up ()
- "Go to previous directory."
- (interactive)
- (find-alternate-file ".."))
-
- (defun vde/dired-down ()
- "Enter directory."
- (interactive)
- (dired-find-alternate-file))
-
- (defun vde/open-in-external-app ()
- "Open the file(s) at point with an external application."
- (interactive)
- (let* ((file-list
- (dired-get-marked-files)))
- (mapc
- (lambda (file-path)
- (let ((process-connection-type nil))
- (start-process "" nil "xdg-open" file-path))) file-list)))
-
- (defun find-file-reuse-dir-buffer ()
- "Like `dired-find-file', but reuse Dired buffers."
- (interactive)
- (set-buffer-modified-p nil)
- (let ((file (dired-get-file-for-visit)))
- (if (file-directory-p file)
- (find-alternate-file file)
- (find-file file))))
-
- (defun vde/sudired ()
- "Open directory with sudo in Dired."
- (interactive)
- (require 'tramp)
- (let ((dir (expand-file-name default-directory)))
- (if (string-match "^/sudo:" dir)
- (user-error "Already in sudo")
- (dired (concat "/sudo::" dir)))))
-
- (defun vde/dired-get-size ()
- "Quick and easy way to get file size in Dired."
- (interactive)
- (let ((files (dired-get-marked-files)))
- (with-temp-buffer
- (apply 'call-process "du" nil t nil "-sch" files)
- (message
- "Size of all marked files: %s"
- (progn
- (re-search-backward "\\(^[0-9.,]+[A-Za-z]+\\).*total$")
- (match-string 1))))))
-
- (vde/dired-fd
- vde/dired-fd-dirs
- "Search for directories in VC root or PWD.
-With \\[universal-argument] put the results in a `dired' buffer.
-This relies on the external 'fd' executable."
- "Subdirectories"
- "-i" "-H" "-a" "-t" "d" "-c" "never")
-
- (vde/dired-fd
- vde/dired-fd-files-and-dirs
- "Search for files and directories in VC root or PWD.
-With \\[universal-argument] put the results in a `dired' buffer.
-This relies on the external 'fd' executable."
- "Files and dirs"
- "-i" "-H" "-a" "-t" "d" "-t" "f" "-c" "never")
- )
-
-(use-package find-dired
- :after dired
- :commands (find-name-dired)
- :config
- (setq-default find-ls-option ;; applies to `find-name-dired'
- '("-ls" . "-AFhlv --group-directories-first")
- find-name-arg "-iname"))
-
-(use-package dired-x
- :after dired
- :bind (("C-x C-j" . dired-jump))
- :commands (dired-jump dired-omit-mode)
- :config
- (setq-default dired-omit-files (concat dired-omit-files "\\|^\\.+$\\|^\\..+$")
- dired-omit-verbose nil
- dired-clean-confirm-killing-deleted-buffers nil))
-
-(use-package dired-aux
- :unless noninteractive
- :after dired
- :config
- (setq-default
- ;; Ask for creation of missing directories when copying/moving
- dired-create-destination-dirs 'ask
- dired-create-destination-dirs-on-trailing-dirsep t
- ;; Search only file names when point is on a file name
- dired-isearch-filenames'dwim))
-
-(use-package async)
-(use-package dired-async
- :unless noninteractive
- :after (dired async)
- :commands (dired-async-mode)
- :hook (dired-mode . dired-async-mode))
-
-(use-package dired-narrow
- :unless noninteractive
- :after dired
- :commands (dired-narrow)
- :bind (:map dired-mode-map
- ("M-s n" . dired-narrow))
- :config
- (setq-default dired-narrow-exit-when-one-left t
- dired-narrow-enable-blinking t
- dired-narrow-blink-time 0.3))
-
-(use-package wdired
- :unless noninteractive
- :after dired
- :commands (wdired-mode
- wdired-change-to-wdired-mode)
- :bind (:map dired-mode-map
- ("E" . wdired-change-to-wdired-mode))
- :config
- (setq-default wdired-allow-to-change-permissions t
- wdired-create-parent-directories t))
-
-(use-package dired-rsync
- :unless noninteractive
- :after dired
- :commands (dired-rsync)
- :bind (:map dired-mode-map
- ("r" . dired-rsync)))
-
-(use-package trashed
- :unless noninteractive
- :commands (trashed)
- :config
- (setq trashed-action-confirmer 'y-or-n-p)
- (setq trashed-use-header-line t)
- (setq trashed-sort-key '("Date deleted" . t))
- (setq trashed-date-format "%Y-%m-%d %H:%M:%S"))
-
-;; (use-package dired-sidebar
-;; :unless noninteractive
-;; :commands (dired-sidebar-toggle-sidebar)
-;; :bind ("C-c C-n" . dired-sidebar-toggle-sidebar)
-;; :init
-;; (add-hook 'dired-sidebar-mode-hook
-;; (lambda ()
-;; (unless (file-remote-p default-directory)
-;; (auto-revert-mode))))
-;; :config
-;; (push 'toggle-window-split dired-sidebar-toggle-hidden-commands)
-;; (push 'rotate-windows dired-sidebar-toggle-hidden-commands)
-;;
-;; ;; (setq dired-sidebar-subtree-line-prefix "__")
-;; ;;(setq dired-sidebar-use-custom-font t)
-;; (setq dired-sidebar-theme 'arrow)
-;; (setq dired-sidebar-use-term-integration t))
-
-(use-package casual-dired
- :after dired
- :commands (casual-dired-tmenu)
- :bind (:map dired-mode-map ("C-o" . 'casual-dired-tmenu)))
-
-(provide 'config-dired)
-;; config-dired.el ends here
tools/emacs/config/config-editing.el
@@ -1,164 +0,0 @@
-;;; config-editing.el --- -*- lexical-binding: t; -*-
-;; Time-stamp: <Last changed 2025-05-07 22:55:12 by vincent>
-;;; Commentary:
-;;; Editing configuration
-;;; Code:
-
-(setq-default enable-remote-dir-locals t)
-
-;; When finding file in non-existing directory, offer to create the
-;; parent directory.
-(defun with-buffer-name-prompt-and-make-subdirs ()
- (let ((parent-directory (file-name-directory buffer-file-name)))
- (when (and (not (file-exists-p parent-directory))
- (y-or-n-p (format "Directory `%s' does not exist! Create it? " parent-directory)))
- (make-directory parent-directory t))))
-
-(add-to-list 'find-file-not-found-functions #'with-buffer-name-prompt-and-make-subdirs)
-
-;; Fix long line "problems"
-;; Disable some right-to-left behavior that might not be needed.
-;; Learning arabic might make me change this, but for now..
-(setq-default bidi-paragraph-direction 'left-to-right)
-(if (version<= "27.1" emacs-version)
- (setq bidi-inhibit-bpa t))
-;; Detect if the line in a buffer are so long they could have a performance impact
-(if (version<= "27.1" emacs-version)
- (global-so-long-mode 1))
-
-(use-package saveplace
- :unless noninteractive
- :config
- (save-place-mode 1))
-
-(use-package vundo
- :bind (("M-u" . undo)
- ("M-U" . undo-redo)
- ("C-x u" . vundo)))
-
-(use-package whitespace
- :unless noninteractive
- :commands (whitespace-mode vde/toggle-invisibles)
- :config
- (setq-default whitespace-style '(face tabs spaces trailing space-before-tab newline indentation empty space-after-tab space-mark tab-mark newline-mark))
- (defun vde/toggle-invisibles ()
- "Toggles the display of indentation and space characters."
- (interactive)
- (if (bound-and-true-p whitespace-mode)
- (whitespace-mode -1)
- (whitespace-mode)))
- :bind ("<f6>" . vde/toggle-invisibles))
-
-(use-package easy-kill
- :unless noninteractive
- :commands (easy-kill easy-mark)
- :bind
- (([remap kill-ring-save] . easy-kill)
- ([remap mark-sexp] . easy-mark)
- ("M-r" . easy-mark)))
-
-(use-package display-line-numbers
- :unless noninteractive
- :hook (prog-mode . display-line-numbers-mode)
- :config
- (setq-default display-line-numbers-type 'relative)
- (defun vde/toggle-line-numbers ()
- "Toggles the display of line numbers. Applies to all buffers."
- (interactive)
- (if (bound-and-true-p display-line-numbers-mode)
- (display-line-numbers-mode -1)
- (display-line-numbers-mode)))
- :bind ("<f7>" . vde/toggle-line-numbers))
-
-(add-hook 'prog-mode-hook 'toggle-truncate-lines)
-
-;; (use-package comment-dwim-2
-;; :bind (([remap comment-dwim] . comment-dwim-2)))
-(use-package newcomment
- :unless noninteractive
- :config
- (setq-default comment-empty-lines t
- comment-fill-column nil
- comment-multi-line t
- comment-style 'multi-line)
- (defun prot/comment-dwim (&optional arg)
- "Alternative to `comment-dwim': offers a simple wrapper
-around `comment-line' and `comment-dwim'.
-
-If the region is active, then toggle the comment status of the
-region or, if the major mode defines as much, of all the lines
-implied by the region boundaries.
-
-Else toggle the comment status of the line at point."
- (interactive "*P")
- (if (use-region-p)
- (comment-dwim arg)
- (save-excursion
- (comment-line arg))))
-
- :bind (("C-;" . prot/comment-dwim)
- ("C-:" . comment-kill)
- ("M-;" . comment-indent)
- ("C-x C-;" . comment-box)))
-
-(use-package delsel
- :unless noninteractive
- :config
- (delete-selection-mode 1))
-
-(use-package emacs
- :unless noninteractive
- :custom
- (repeat-on-final-keystroke t)
- (set-mark-command-repeat-pop t)
- :bind (("M-z" . zap-up-to-char)
- ("M-S-<up>" . duplicate-dwim)))
-
-(use-package visual-regexp
- :unless noninteractive
- :commands (vr/replace vr/query-replace)
- :bind (("C-c r" . vr/replace)
- ("C-c %" . vr/query-replace)))
-
-(use-package emacs
- :config
- :bind (("M-SPC" . cycle-spacing)
- ("M-o" . delete-blank-lines)
- ("<C-f6>" . tear-off-window)))
-
-(use-package subword
- :diminish
- :hook (prog-mode-hook . subword-mode))
-
-(use-package surround
- :bind-keymap ("M-'" . surround-keymap))
-
-(use-package substitute
- :bind (("M-<insert> s" . substitute-target-below-point)
- ("M-<insert> r" . substitute-target-above-point)
- ("M-<insert> d" . substitute-target-in-defun)
- ("M-<insert> b" . substitute-target-in-buffer)))
-
-(use-package jinx
- :hook (emacs-startup . global-jinx-mode)
- :bind (([remap ispell-word] . jinx-correct) ;; ("M-$" . jinx-correct)
- ("C-M-$" . jinx-languages)))
-
-(use-package re-builder)
-(use-package casual-re-builder
- :bind (:map
- reb-mode-map ("C-o" . casual-re-builder-tmenu)
- :map
- reb-lisp-mode-map ("C-o" . casual-re-builder-tmenu))
- :after (re-builder))
-
-(use-package time-stamp
- :custom
- (time-stamp-active t)
- (time-stamp-line-limit 10) ; Check first 10 buffer lines for Time-stamp: <>
- (time-stamp-format "Last changed %Y-%02m-%02d %02H:%02M:%02S by %u")
- :hook
- (before-save . time-stamp))
-
-(provide 'config-editing)
-;;; config-editing.el ends here
tools/emacs/config/config-emms.el
@@ -1,78 +0,0 @@
-;;; config-emms.el --- EMMS configuration to play music from Emacs -*- lexical-binding: t -*-
-
-;; Author: Vincent Demeester
-
-;; This file is not part of GNU Emacs
-
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This configuration is used for controlling playing music from Emacs.
-
-;;; Code:
-
-(use-package emms
- :custom
- (emms-player-list '(emms-player-mpv))
- (emms-source-file-default-directory "~/desktop/music")
- (emms-player-mpv-parameters '("--quiet" "--really-quiet" "--no-audio-display" "--force-window=no" "--vo=null"))
- :config
- (require 'emms-source-file)
- (require 'emms-source-playlist)
- (require 'emms-player-simple)
- (require 'emms-player-mpv)
- (require 'emms-playlist-mode)
- (require 'emms-info)
- (require 'emms-info-mp3info)
- (require 'emms-info-ogginfo)
- (require 'emms-info-opusinfo)
- (require 'emms-info-metaflac)
- (require 'emms-info-tinytag)
- (require 'emms-info-exiftool)
- (require 'emms-info-native)
- (require 'emms-cache)
- (require 'emms-mode-line)
- (require 'emms-mark)
- (require 'emms-show-all)
- (require 'emms-streams)
- (require 'emms-playing-time)
- (require 'emms-browser)
- (require 'emms-mode-line-icon)
- (require 'emms-cue)
- (require 'emms-bookmarks)
- (require 'emms-last-played)
- (require 'emms-metaplaylist-mode)
- (require 'emms-stream-info)
- (require 'emms-history)
- (require 'emms-i18n)
- (require 'emms-volume)
- (require 'emms-playlist-limit)
- (require 'emms-mpris)
- (require 'emms-idapi-musicbrainz)
- (require 'emms-idapi-browser)
-
- (setq emms-playlist-default-major-mode #'emms-playlist-mode)
- (add-to-list 'emms-track-initialize-functions #'emms-info-initialize-track)
- (setq emms-info-functions '(emms-info-native emms-info-cueinfo))
- (setq emms-track-description-function #'emms-info-track-description)
- (when (fboundp 'emms-cache) ; work around compiler warning
- (emms-cache 1))
- (emms-mode-line-mode 1)
- (emms-mode-line-blank)
- (emms-playing-time-mode 1)
- (add-hook 'emms-player-started-hook #'emms-last-played-update-current))
-
-(provide 'config-emms)
-;;; config-emms.el ends here
tools/emacs/config/config-files.el
@@ -1,89 +0,0 @@
-;;; config-files.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Files related configurations
-;;; Code:
-(use-package ffap
- :hook
- (after-init . ffap-bindings))
-;; (use-package autoinsert
-;; :init
-;; (setq-default auto-insert-query nil
-;; auto-insert-alist nil)
-;; :config
-;; (auto-insert-mode 1))
-
-(require 'hardhat)
-(global-hardhat-mode)
-
-(use-package files
- :commands (revert-buffer)
- :bind (("<f5>" . revert-buffer))
- :config
- (setq-default view-read-only t))
-
-(use-package envrc
- :defer 2
- :if (executable-find "direnv")
- :bind (:map envrc-mode-map
- ("C-c e" . envrc-command-map))
- :config (envrc-global-mode))
-
-(use-package highlight-indentation
- :unless noninteractive
- :commands (highlight-indentation-mode highlight-indentation-current-column-mode)
- :config
- (set-face-background 'highlight-indentation-face "#e3e3d3")
- (set-face-background 'highlight-indentation-current-column-face "#c3b3b3"))
-
-(defun vde/delete-this-file ()
- "Delete the current file, and kill the buffer."
- (interactive)
- (or (buffer-file-name) (error "No file is currently being edited"))
- (when (yes-or-no-p (format "Really delete '%s'?"
- (file-name-nondirectory buffer-file-name)))
- (delete-file (buffer-file-name))
- (kill-this-buffer)))
-
-(defun vde/rename-this-file-and-buffer (new-name)
- "Renames both current buffer and file it's visiting to NEW-NAME."
- (interactive "sNew name: ")
- (let ((name (buffer-name))
- (filename (buffer-file-name)))
- (unless filename
- (error "Buffer '%s' is not visiting a file!" name))
- (if (get-buffer new-name)
- (message "A buffer named '%s' already exists!" new-name)
- (progn
- (when (file-exists-p filename)
- (rename-file filename new-name 1))
- (rename-buffer new-name)
- (set-visited-file-name new-name)))))
-
-(bind-key "C-c f D" #'vde/delete-this-file)
-(bind-key "C-c f R" #'vde/rename-this-file-and-buffer)
-
-;; Additional bindings for built-ins
-(bind-key "C-c f v d" #'add-dir-local-variable)
-(bind-key "C-c f v l" #'add-file-local-variable)
-(bind-key "C-c f v p" #'add-file-local-variable-prop-line)
-
-(defun vde/reload-dir-locals-for-current-buffer ()
- "Reload dir locals for the current buffer."
- (interactive)
- (let ((enable-local-variables :all))
- (hack-dir-local-variables-non-file-buffer)))
-
-(defun vde/reload-dir-locals-for-all-buffers-in-this-directory ()
- "Reload dir-locals for all buffers in current buffer's `default-directory'."
- (interactive)
- (let ((dir default-directory))
- (dolist (buffer (buffer-list))
- (with-current-buffer buffer
- (when (equal default-directory dir))
- (vde/reload-dir-locals-for-current-buffer)))))
-
-(bind-key "C-c f v r" #'vde/reload-dir-locals-for-current-buffer)
-(bind-key "C-c f v r" #'vde/reload-dir-locals-for-all-buffers-in-this-directory)
-
-(provide 'config-files)
-;;; config-files.el ends here
tools/emacs/config/config-keybindings.el
@@ -1,61 +0,0 @@
-;;; config-keybindings.el --- -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Key binding specific configuration
-;;; Code:
-
-;; Disable C-x C-n to avoid the disabled command buffer
-(unbind-key "C-x C-n" global-map)
-
-;; Remap dynamic-abbrev to hippie-expand
-;; See https://www.masteringemacs.org/article/text-expansion-hippie-expand
-(global-set-key [remap dabbrev-expand] 'hippie-expand)
-
-(use-package vde-simple
- :demand t
- :preface
- (dolist (key '("C-M-<SPC>" "M-<SPC>"))
- (global-unset-key (kbd key)))
- :bind
- (("M-<SPC> e" . dired-jump)
- ("M-<SPC> x" . execute-extended-command)
- ("M-<SPC> :" . eval-expression)
- ("M-<SPC> <SPC>" . (lambda()(interactive)
- (let ((consult-buffer-filter))
- (add-to-list 'consult-buffer-filter "\\*")
- (call-interactively 'consult-buffer))))
- ("M-<SPC> f f" . project-find-file)
- ("M-<SPC> f o" . ffap)
- ("M-<SPC> f q" . read-only-mode)
- ("M-<SPC> f r" . consult-recent-file)
- ("M-<SPC> q q" . save-buffers-kill-terminal)))
-
-;; TODO add general configuration here
-;; (use-package general
-;; :config
-;; (dolist (key '("C-M-<SPC>" "M-<SPC>"))
-;; (global-unset-key (kbd key)))
-;; (general-create-definer general-leader :prefix "M-<SPC>")
-;; (general-def "C-M-<SPC>" 'cycle-spacing)
-;;
-;; (general-leader
-;; "z" #'(repeat :which-key "Repeat")
-;; "u" #'(universal-argument :which-key "Universal argument")
-;; "e" #'(dired-jump :which-key "Dired")
-;; "x" #'(execute-extended-command :which-key "M-x")
-;; "f" '(:ignore t :which-key "File")
-;; "SPC" #'((lambda()(interactive)
-;; (let ((consult-buffer-filter))
-;; (add-to-list 'consult-buffer-filter "\\*")
-;; (call-interactively 'consult-buffer))) :wk "Switch to Buffer")
-;; ":" #'(eval-expression :wk "Eval expression")
-;; "ff" #'(project-find-file :which-key "Find in Project")
-;; "fo" #'(ffap :which-key "Find with context")
-;; "fq" #'(read-only-mode :which-key "Toggle Read Only")
-;; "fr" #'(consult-recent-file :which-key "Recent File")
-;; "q" #'(:ignore t :wk "Quit")
-;; "qq" #'(save-buffers-kill-terminal :wk "Quit Emacs")
-;; ))
-
-;;
-(provide 'config-keybindings)
-;;; config-keybindings.el ends here
tools/emacs/config/config-llm.el
@@ -1,283 +0,0 @@
-;;; config-llm.el --- -*- lexical-binding: t -*-
-;;; Commentary:
-;;; LLM configuration
-;;; Code:
-
-(use-package copilot
- ;; :hook
- ;; (prog-mode . copilot-mode)
- ;; (markdown-mode . copilot-mode) ;; Enable this on-demand only
- ;; (text-mode . copilot-mode) ;; I may not want copilot in org-mode for example.
- ;; (log-edit-mode . copilot-mode)
- ;; (vc-git-log-edit-mode . copilot-mode)
- :bind
- (:map copilot-completion-map
- ("C-g" . copilot-clear-overlay)
- ("C-j" . copilot-next-completion)
- ("C-k" . copilot-previous-completion)
- ("M-RET" . copilot-accept-completion)
- ("C-f" . copilot-accept-completion)
- ("C-l" . copilot-panel-complete))
- :custom
- (copilot-idle-delay 1)
- (copilot-max-char -1)
- (copile-indent-offset-warning-disable t))
-
-(setq copilot-chat-commit-prompt "Here is the result of running `git diff --cached`. Based on this, suggest a **Conventional Commit message**. Ensure the message includes both a clear title describing the change and a body explaining the change. Do not invent anything new; just comprehend the diff and explain it.
-
-- Do not add extra markdown formatting.
-- Always make sure the commit message is in markdown format.
-- Do not include any additional text outside the commit message.
-- Make sure the title is a max of 50 characters long and not more.
-- The summaries need to be wrapped to 80 characters long and not more (or break the line).
-- Avoid overused words and phrases often associated with AI-generated text. Do not use the following words: *delve, tapestry, vibrant, landscape, realm, embark, excels, vital, comprehensive, intricate, pivotal, moreover, arguably, notably.*
-- Avoid the following phrases: *dive into, it’s important to note, it’s important to remember, certainly, here are, important to consider, based on the information provided, remember that, navigating the [landscape]/[complexities of], delving into the intricacies of, a testament to.*
-- Do not include any generic AI disclaimers or self-references (e.g., \"As an AI language model...\").
-
-# Conventional Commits 1.0.0
-
-## Summary
-
-Conventional Commits is a specification for commit messages that follows these rules to ensure clarity and consistency:
-
-### Format
-
-`<type>[optional scope]: <description>`
-
-`[body]`
-
-### Types
-
-1. **fix:** A bug fix correlating to a PATCH version.
-2. **feat:** A new feature correlating to a MINOR version.
-
-Other types include:
-
-- **build:** Changes to build systems or dependencies.
-- **chore:** Maintenance tasks (e.g., dependency updates).
-- **ci:** Changes to CI configuration.
-- **refactor:** Code changes not adding features or fixing bugs.
-- **test:** Changes to or addition of tests.
-
-Here is the result of `git diff --cached`:")
-
-(use-package copilot-chat
- :custom
- (copilot-chat-model "claude-3.7-sonnet")
- :bind
- (("C-c a c p" . copilot-chat-prompt-transient-menu)
- ("C-c a c c" . copilot-chat-insert-commit-message)
- ("C-c a c o" . copilot-chat-optimize)
- ("C-c a c m" . copilot-chat-set-model)
- ("C-c a c w" . my-copilot-chat-copy-source-block)
- ("C-c a c y" . copilot-chat-yank)
- ("C-c a c Y" . copilot-chat-yank-pop)
- ("C-c a c b" . copilot-chat-display)
- ("C-c a c a" . copilot-chat-switch-to-buffer)
- ("C-c a c f" . copilot-chat-custom-prompt-function)
- ("C-c a c s" . copilot-chat-custom-prompt-selection)
- (:map embark-general-map
- ("M a d" . copilot-chat-doc)
- ("M a e" . copilot-chat-explain)
- ("M a o" . copilot-chat-optimize)
- ("M a p" . copilot-chat-custom-prompt-selection)
- ("M a r" . copilot-chat-review))
- (:map copilot-chat-prompt-mode-map
- ("C-M-w" . my-copilot-chat-copy-source-block)
- ("C-q" . delete-window)))
- :config
- (setq copilot-chat-prompts copilot-chat-markdown-prompt)
- (defun my-copilot-chat-copy-source-block ()
- "Copy the source block at point to kill ring."
- (interactive)
- (let* ((temp-buffer-name "*copilot-kr-temp*"))
- (with-current-buffer (get-buffer-create temp-buffer-name)
- (erase-buffer)
- (copilot-chat-yank)
- (kill-ring-save (point-min) (point-max))
- (kill-buffer))
- (message "Source block copied to kill ring")))
-
- (defun copilot-chat-prompt-transient-menu ()
- "Show a transient menu for Copilot Chat actions."
- (interactive)
- (unless (use-region-p)
- (mark-defun))
- (transient-define-prefix copilot-chat-prompt-menu ()
- "Copilot Chat Menu"
- ["Copilot Chat Actions"
- ["Target"
- ("c" "Commit" copilot-chat-insert-commit-message)
- ("o" "Optimize" copilot-chat-optimize)
- ("r" "Review" copilot-chat-review)
- ("f" "Fix" copilot-chat-fix)
- ("e" "Explain" copilot-chat-explain)
- ("d" "Doc" copilot-chat-doc)]
- ["Commands"
- ("d" "Display chat" copilot-chat-display)
- ("h" "Hide chat" copilot-chat-hide)
- ("R" "Reset & reopen" (lambda ()
- (interactive)
- (copilot-chat-reset)
- (copilot-chat-display)))
- ("x" "Reset" copilot-chat-reset)
- ("g" "Go to buffer" copilot-chat-switch-to-buffer)
- ("m" "Set model" copilot-chat-set-model)
- ("q" "Quit" transient-quit-one)]
- ["Actions"
- ("p" "Custom prompt" copilot-chat-custom-prompt-selection)
- ("i" "Ask and insert" copilot-chat-ask-and-insert)
- ("m" "Insert commit message" copilot-chat-insert-commit-message)
- ("b" "Buffers" copilot-chat-transient-buffers)]
- ["Data"
- ("y" "Yank last code block" copilot-chat-yank)
- ("s" "Send code to buffer" copilot-chat-send-to-buffer)]])
- (copilot-chat-prompt-menu))
- :after (copilot embark)
- :commands
- (copilot-chat-mode))
-
-(use-package aidermacs
- :bind (("C-c a a m" . aidermacs-transient-menu))
- :custom
- (aidermacs-use-architect-mode t)
- (aidermacs-auto-commits nil)
- :config
- (aidermacs-setup-minor-mode))
-
-(use-package gptel
- :commands (gptel gptel-mode)
- :bind (("C-c a g" . gptel))
- :hook
- (gptel-mode . visual-line-mode)
- :bind
- (:map gptel-mode-map
- ("C-c C-k" . gptel-abort)
- ("C-c C-m" . gptel-menu)
- ("C-c C-c" . gptel-send))
- :custom
- (gptel-default-mode #'markdown-mode)
- :config
- ;; (general-leader
- ;; "o" '(:ignore t :wk "GPTel")
- ;; "o o" '(gptel :wk "Start GPTel")
- ;; "o m" '(gptel-menu :wk "GPTel menu"))
- (setq mcp-hub-servers
- `(("jira" :command "/home/vincent/src/github.com/chmouel/jayrah/.venv/bin/jayrah" :args ("mcp"))
- ("github" :command "github-mcp-server" :args ("stdio")
- :env (:GITHUB_PERSONAL_ACCESS_TOKEN ,(passage-get "github/vdemeester/github-mcp-server")))))
- (require 'gptel-curl)
- (require 'gptel-gemini)
- (require 'gptel-ollama)
- (require 'gptel-transient)
- (require 'gptel-integrations)
- (require 'gptel-rewrite)
- (require 'gptel-org)
- (require 'gptel-openai)
- (require 'gptel-openai-extras)
- (require 'gptel-autoloads)
- (gptel-mcp-connect)
- (setq gptel-model 'gemini-2.0-flash
- gptel-backend (gptel-make-gemini "Gemini"
- :key (passage-get "ai/gemini/api_key"))
- )
-
- (gptel-make-deepseek "Deepseek"
- :key (passage-get "ai/deepseek/api_key")
- ;; :models '("deepseek-reasoner" "deepseek-chat" )
- )
-
- (gptel-make-openai "MistralLeChat"
- :host "api.mistral.ai/v1"
- :endpoint "/chat/completions"
- :protocol "https"
- :key (passage-get "ai/mistralai/api_key")
- :models '("mistral-small"))
-
- (gptel-make-openai "OpenRouter"
- :host "openrouter.ai"
- :endpoint "/api/v1/chat/completions"
- :stream t
- :key (passage-get "ai/openroute/api_key")
- :models '(cognitivecomputations/dolphin3.0-mistral-24b:free
- cognitivecomputations/dolphin3.0-r1-mistral-24b:free
- deepseek/deepseek-r1-zero:free
- deepseek/deepseek-chat:free
- deepseek/deepseek-r1-distill-qwen-32b:free
- deepseek/deepseek-r1-distill-llama-70b:free
- google/gemini-2.0-flash-lite-preview-02-05:free
- google/gemini-2.0-pro-exp-02-05:free
- google/gemini-2.5-pro-exp-03-25
- google/gemini-2.5-pro-exp-03-25:free
- google/gemma-3-12b-it:free
- google/gemma-3-27b-it:free
- google/gemma-3-4b-it:free
- mistralai/mistral-small-3.1-24b-instruct:free
- open-r1/olympiccoder-32b:free
- qwen/qwen2.5-vl-3b-instruct:free
- qwen/qwen-2.5-coder-32b-instruct:free
- qwen/qwq-32b:free
- codellama/codellama-70b-instruct
- google/gemini-pro
- google/palm-2-codechat-bison-32k
- meta-llama/codellama-34b-instruct
- mistralai/mixtral-8x7b-instruct
- openai/gpt-3.5-turbo))
-
- (gptel-make-openai "Groq"
- :host "api.groq.com"
- :endpoint "/openai/v1/chat/completions"
- :stream t
- :key (passage-get "ai/groq/wakasu")
- :models '("llama-3.3-70b-versatile"
- "llama-3.1-70b-versatile"
- "llama-3.1-8b-instant"
- "llama3-70b-8192"
- "llama3-8b-8192"
- "deepseek-r1-distill-qwen-32b"
- "deepseek-r1-distill-llama-70b-specdec"
- "qwen-2.5-coder-32b"
- "mixtral-8x7b-32768"
- "gemma-7b-it"))
-
- (gptel-make-ollama "Ollama"
- :host "localhost:11434"
- :stream t
- :models '("smollm:latest"
- "llama3.1:latest"
- "deepseek-r1:latest"
- "mistral-small:latest"
- "deepseek-r1:7b"
- "nomic-embed-text:latest")))
-
-(use-package gptel-context
- :after gptel
- :config
- ;; (general-leader
- ;; "o c" '(:ignore t :which-key "GPTel Context")
- ;; "o c a" 'gptel-context-add
- ;; "o c r" 'gptel-context-remove
- ;; "o c s" '(lambda ()
- ;; (interactive)
- ;; (gptel-context-remove-all nil)
- ;; (unless (use-region-p)
- ;; (mark-defun))
- ;; (gptel-context-add)
- ;; (my-switch-to-gptel-buffer)))
- )
-
-(defun my-switch-to-gptel-buffer (&optional arg)
- "Switch to the most recent buffer with gptel-mode enabled or start it."
- (interactive "P")
- (let (target-buffer)
- (setq target-buffer (cl-find-if
- (lambda (buf)
- (with-current-buffer buf
- (bound-and-true-p gptel-mode)))
- (buffer-list)))
- (unless target-buffer
- (call-interactively 'gptel))
- (pop-to-buffer target-buffer)))
-
-(provide 'config-llm)
-;;; config-llm.el ends here
tools/emacs/config/config-misc.el
@@ -1,29 +0,0 @@
-;;; config-misc.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Miscellaneous modes configuration
-;;; Code:
-
-;; (use-package password-store
-;; :custom
-;; (password-store-executable "passage"))
-
-(defvar passage-program "passage"
- "The path to the `passage` executable.")
-
-(defun passage-get (password-name)
- "Return the password for PASSWORD-NAME from `passage show`."
- (let ((password (shell-command-to-string (concat passage-program " show " (shell-quote-argument password-name)))))
- (string-trim password))) ; Trim whitespace here
-
-(use-package helpful
- :unless noninteractive
- :bind (("C-h f" . helpful-callable)
- ("C-h F" . helpful-function)
- ("C-h M" . helpful-macro)
- ("C-c h S" . helpful-at-point)
- ("C-h k" . helpful-key)
- ("C-h v" . helpful-variable)
- ("C-h C" . helpful-command)))
-
-(provide 'config-misc)
-;;; config-misc.el ends here
tools/emacs/config/config-mouse.el
@@ -1,20 +0,0 @@
-;;; config-mouse.el --- -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Mouse configuration
-;;; Code:
-
-(use-package mouse
- :unless noninteractive
- :config
- (setq mouse-wheel-scroll-amount
- '(1
- ((shift) . 5)
- ((meta) . 0.5)
- ((control) . text-scale)))
- (setq make-pointer-invisible t
- mouse-wheel-progressive-speed t
- mouse-wheel-follow-mouse t)
- :hook (after-init . mouse-wheel-mode))
-
-(provide 'config-mouse)
-;;; config-mouse.el ends here
tools/emacs/config/config-mu4e.el
@@ -1,164 +0,0 @@
-;;; config-mu4e.el -- mu emacs client configuration -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Code:
-
-(use-package mu4e
- :commands (mu4e)
- :custom
- (mu4e-mu-home "/home/vincent/.local/cache/mu")
- (mu4e-context-policy 'pick-first)
- (mu4e-change-filenames-when-moving t)
- (mu4e-attachment-dir "~/desktop/downloads")
- :config
- (setq mu4e-get-mail-command (concat (executable-find "mbsync") " --all"))
- (setq mu4e-update-interval 1800) ; 30m
-
- (defun vde-mu4e--mark-get-copy-target ()
- "Ask for a copy target, and propose to create it if it does not exist."
- (let* ((target (mu4e-ask-maildir "Copy message to: "))
- (target (if (string= (substring target 0 1) "/")
- target
- (concat "/" target)))
- (fulltarget (mu4e-join-paths (mu4e-root-maildir) target)))
- (when (mu4e-create-maildir-maybe fulltarget)
- target)))
-
- (defun copy-message-to-target(docid msg target)
- (let (
- (new_msg_path nil) ;; local variable
- (msg_flags (mu4e-message-field msg :flags))
- )
- ;; 1. target is already determined interactively when executing the mark (:ask-target)
-
- ;; 2. Determine the path for the new file: we use mu4e~draft-message-filename-construct from
- ;; mu4e-draft.el to create a new random filename, and append the original's msg_flags
- (setq new_msg_path (format "%s/%s/cur/%s" mu4e-maildir target (mu4e~draft-message-filename-construct
- (mu4e-flags-to-string msg_flags))))
-
- ;; 3. Copy the message using file system call (copy-file) to new_msg_path:
- ;; (See e.g. mu4e-draft.el > mu4e-draft-open > resend)
- (copy-file (mu4e-message-field msg :path) new_msg_path)
-
- ;; 4. Add the information to the database (may need to update current search query with 'g' if duplicating to current box. Try also 'V' to toggle the display of duplicates)
- (mu4e~proc-add new_msg_path (mu4e~mark-check-target target))
- )
- )
-
- (defun vde-mu4e--refile (msg)
- "Refile function to smartly move `MSG' to a given folder."
- (cond
- ;; FIXME
- ((string= (plist-get (car-safe (mu4e-message-field msg :cc)) :email) "ci_activity@noreply.github.com")
- "/icloud/Deleted Messages")
- (t
- (let ((year (format-time-string "%Y" (mu4e-message-field msg :date))))
- (format "/icloud/Archives/%s" year)))))
-
- (setq
- mu4e-headers-draft-mark '("D" . "💈")
- mu4e-headers-flagged-mark '("F" . "📍")
- mu4e-headers-new-mark '("N" . "🔥")
- mu4e-headers-passed-mark '("P" . "❯")
- mu4e-headers-replied-mark '("R" . "❮")
- mu4e-headers-seen-mark '("S" . "☑")
- mu4e-headers-trashed-mark '("T" . "💀")
- mu4e-headers-attach-mark '("a" . "📎")
- mu4e-headers-encrypted-mark '("x" . "🔒")
- mu4e-headers-signed-mark '("s" . "🔑")
- mu4e-headers-unread-mark '("u" . "⎕")
- mu4e-headers-list-mark '("l" . "🔈")
- mu4e-headers-personal-mark '("p" . "👨")
- mu4e-headers-calendar-mark '("c" . "📅"))
-
- (setopt mu4e-completing-read-function completing-read-function)
- (setq mu4e-refile-folder 'vde-mu4e--refile)
- (setq mu4e-contexts `( ,(make-mu4e-context
- :name "icloud"
- :match-func (lambda (msg) (when msg
- (string-prefix-p "/icloud" (mu4e-message-field msg :maildir))))
- :vars '(
- (user-mail-address . "vincent@demeester.fr")
- (mu4e-trash-folder . "/icloud/Deleted Messages")
- (mu4e-sent-folder . "/icloud/Sent Messages")
- (mu4e-draft-folder . "/icloud/Drafts")
- ;; (mu4e-get-mail-command . "mbsync icloud")
- ))
- ,(make-mu4e-context
- :name "gmail"
- :match-func (lambda (msg) (when msg
- (string-prefix-p "/gmail" (mu4e-message-field msg :maildir))))
- :vars '(
- (user-mail-address . "vinc.demeester@gmail.com")
- (mu4e-drafts-folder . "/gmail/[Gmail]/Drafts")
- (mu4e-sent-folder . "/gmail/[Gmail]/Sent Mail")
- ;; (mu4e-refile-folder . "/gmail/[Gmail]/All Mail")
- (mu4e-trash-folder . "/gmail/[Gmail]/Trash")
- ;; (mu4e-get-mail-command . "mbsync gmail")
- ))
- ,(make-mu4e-context
- :name "redhat"
- :match-func (lambda (msg) (when msg
- (string-prefix-p "/redhat" (mu4e-message-field msg :maildir))))
- :vars '(
- (user-mail-address . "vdemeest@redhat.com")
- (mu4e-drafts-folder . "/redhat/[Gmail]/Drafts")
- (mu4e-sent-folder . "/redhat/[Gmail]/Sent Mail")
- ;; (mu4e-refile-folder . "/redhat/[Gmail]/All Mail")
- (mu4e-trash-folder . "/redhat/[Gmail]/Trash")
- ;; (mu4e-get-mail-command . "mbsync redhat")
- ))
- ))
- (add-to-list 'mu4e-bookmarks
- '( :name "All Inboxes"
- :query "maildir:/icloud/INBOX OR maildir:/gmail/INBOX OR maildir:/redhat/INBOX"
- :key ?b))
- (with-eval-after-load "mm-decode"
- (add-to-list 'mm-discouraged-alternatives "text/html")
- (add-to-list 'mm-discouraged-alternatives "text/richtext")))
-
-(setq sendmail-program "msmtp"
- send-mail-function 'smtpmail-send-it
- message-sendmail-f-is-evil t
- message-sendmail-extra-arguments '("--read-envelope-from")
- message-send-mail-function 'message-send-mail-with-sendmail)
-
-(use-package consult-mu
- :after mu4e
- :custom
- ;;maximum number of results shown in minibuffer
- (consult-mu-maxnum 200)
- ;;show preview when pressing any keys
- (consult-mu-preview-key 'any)
- ;;do not mark email as read when previewed. If you turn this to t, be aware that the auto-loaded preview if the preview-key above is 'any would also get marked as read!
- (consult-mu-mark-previewed-as-read nil)
- ;;mark email as read when selected.
- (consult-mu-mark-viewed-as-read t)
- ;;use reply to all when composing reply emails
- (consult-mu-use-wide-reply t)
- ;; define a template for headers view in minibuffer. The example below adjusts the width based on the width of the screen.
- (consult-mu-headers-template (lambda () (concat "%f" (number-to-string (floor (* (frame-width) 0.15))) "%s" (number-to-string (floor (* (frame-width) 0.5))) "%d13" "%g" "%x")))
-
- :config
- ;;create a list of saved searches for quick access using `histroy-next-element' with `M-n' in minibuffer. Note the "#" character at the beginning of each query! Change these according to
- (setq consult-mu-saved-searches-dynamics '("#flag:unread"))
- (setq consult-mu-saved-searches-async '("#flag:unread"))
- ;; require embark actions for marking, replying, forwarding, etc. directly from minibuffer
- (require 'consult-mu-embark)
- ;; require extra module for composing (e.g. for interactive attachment) as well as embark actions
- (require 'consult-mu-compose)
- (require 'consult-mu-compose-embark)
- ;; require extra module for searching contacts and runing embark actions on contacts
- (require 'consult-mu-contacts)
- (require 'consult-mu-contacts-embark)
- ;; change the prefiew key for compose so you don't open a preview of every file when selecting files to attach
- (setq consult-mu-compose-preview-key "M-o")
- ;; pick a key to bind to consult-mu-compose-attach in embark-file-map
- (setq consult-mu-embark-attach-file-key "C-a")
- (setq consult-mu-contacts-ignore-list '("^.*no.*reply.*"))
- (setq consult-mu-contacts-ignore-case-fold-search t)
- (consult-mu-compose-embark-bind-attach-file-key)
- ;; choose if you want to use dired for attaching files (choice of 'always, 'in-dired, or nil)
- (setq consult-mu-compose-use-dired-attachment 'in-dired))
-
-(provide 'config-mu4e)
-;;; config-mu4e.el ends here
tools/emacs/config/config-org.el
@@ -1,714 +0,0 @@
-;;; config-org.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Configuration of orgmode.
-;;; Code:
-
-(use-package s)
-(use-package dash)
-
-(defconst org-directory "~/desktop/org/"
- "org-mode directory, where most of the org-mode file lives")
-(defconst org-notes-directory (expand-file-name "notes" org-directory)
- "org-mode notes directory, for notes, managed by denote")
-(defconst org-inbox-file (expand-file-name "inbox.org" org-directory)
- "New stuff collected in this file.")
-(defconst org-todos-file (expand-file-name "todos.org" org-directory)
- "TODOs collected in this file.")
-;; I am not using this too much
-(defconst org-remember-file (expand-file-name "remember.org" org-directory)
- "Remember file, very quick and dirty scratch notes, to be refiled later on.")
-
-(defconst org-archive-dir (expand-file-name "archive" org-directory)
- "Directory of archived files.")
-
-(defconst org-people-dir (expand-file-name "people" org-notes-directory)
- "People files directory.")
-
-(defconst src-www-dir (expand-file-name "~/src/www" org-directory)
- "Directory of my www repository, can contain todos there.")
-
-(defconst org-babel-library-file (expand-file-name "org_library_of_babel.org" org-directory)
- "Org babel library.")
-
-(set-register ?i `(file . ,org-inbox-file))
-(set-register ?t `(file . ,org-todos-file))
-(set-register ?o `(file . ,org-directory))
-(set-register ?P `(file . ,org-people-dir))
-
-(defun vde/agenda-goto-view ()
- "Jump to the task narrowed but in view mode only to get a glance."
- (interactive)
- (org-agenda-goto)
- (org-narrow-to-subtree)
- (view-mode t))
-
-(defun vde/org-mode-hook ()
- "Org-mode hook."
- (setq show-trailing-whitespace t)
- (when (not (eq major-mode 'org-agenda-mode))
- (setq fill-column 90)
- (auto-revert-mode 1)
- (auto-fill-mode 1)
- (org-indent-mode 1)
- (visual-line-mode 1)
- (add-hook 'before-save-hook 'org-update-all-dblocks)
- (add-hook 'auto-save-hook 'org-update-all-dblocks)
- (add-hook 'before-save-hook #'save-and-update-includes nil 'make-it-local)))
-
-(use-package org
- :mode (("\\.org$" . org-mode)
- ("\\.org.draft$" . org-mode))
- :commands (org-agenda org-capture)
- :bind (("C-c o l" . org-store-link)
- ("C-c o r r" . org-refile)
- ("C-c o r R" . vde/reload-org-refile-targets)
- ("C-c o a a" . org-agenda)
- ("C-c o a r" . vde/reload-org-agenda-files)
- ("C-c C-x i" . vde/org-clock-in-any-heading)
- ("C-c o s" . org-sort)
- ("C-c O" . org-open-at-point-global)
- ("<f12>" . org-agenda))
- :hook (org-mode . vde/org-mode-hook)
- :custom
- ;; (org-reverse-note-order '((org-inbox-file . t) ;; Insert items on top of inbox
- ;; (".*" . nil))) ;; On any other file, insert at the bottom
- (org-archive-location (concat org-archive-dir "/%s::datetree/"))
- (org-agenda-file-regexp "^[a-zA-Z0-9-_]+.org$")
- (org-agenda-remove-tags t)
- (org-use-speed-commands t)
- (org-special-ctrl-a/e t)
- (org-special-ctrl-k t)
- (org-hide-emphasis-markers t)
- (org-pretty-entities t)
- (org-ellipsis "…")
- (org-return-follows-link t)
-
- (org-todo-keywords '((sequence "STRT(s)" "NEXT(n)" "TODO(t)" "WAIT(w)" "|" "DONE(d!)" "CANX(c@/!)")))
- (org-todo-state-tags-triggers '(("CANX" ("CANX" . t))
- ("WAIT" ("WAIT" . t))
- (done ("WAIT"))
- ("TODO" ("WAIT") ("CANX"))
- ("NEXT" ("WAIT") ("CANX"))
- ("DONE" ("WAIT") ("CANX"))))
- (org-tag-alist
- '((:startgroup)
- ("Handson" . ?o)
- (:grouptags)
- ("Write" . ?w) ("Code" . ?c)
- (:endgroup)
-
- (:startgroup)
- ("Handsoff" . ?f)
- (:grouptags)
- ("Read" . ?r) ("Watch" . ?W) ("Listen" . ?l)
- (:endgroup)))
-
- (org-log-done 'time)
- (org-log-redeadline 'time)
- (org-log-reschedule 'time)
- (org-log-into-drawer t)
- (org-refile-use-cache t)
- (org-refile-use-outline-path 'file)
- (org-refile-allow-creating-parent-nodes 'confirm)
- (org-list-demote-modify-bullet '(("+" . "-") ("-" . "+")))
- (org-agenda-span 'day)
- (org-agenda-start-on-weekday 1)
- (org-agenda-window-setup 'current-window)
- (org-agenda-skip-scheduled-if-deadline-is-shown t)
- (org-agenda-skip-timestamp-if-deadline-is-shown t)
- (org-agenda-skip-scheduled-if-done nil)
- (org-agenda-current-time-string "")
- (org-agenda-time-grid '((daily) () "" ""))
- ;; ((agenda . " %i %-12:c%?-12t% s")
- ;; (todo . " %i %-12:c")
- ;; (tags . " %i %-12:c")
- ;; (search . " %i %-12:c"))
- ;; (org-agenda-prefix-format " %i %?-2 t%s")
- (org-agenda-prefix-format '((agenda . " %i %?-12t% s")
- (todo . " %i")
- (tags . " %i")
- (search . " %i")))
- (org-insert-heading-respect-content t)
- (org-M-RET-may-split-line '((default . nil)))
- (org-goto-interface 'outline-path-completion)
- (org-outline-path-complete-in-steps nil)
- (org-goto-max-level 2)
-
- (org-agenda-category-icon-alist `(("personal" ,(list (propertize "🏡")))
- ("work" ,(list (propertize "🏢")))
- ("appointments" ,(list (propertize "📅")))
- ("health" ,(list (propertize "⚕️")))
- ("systems" ,(list (propertize "🖥️")))
- ("journal" ,(list (propertize "📝")))
- ("project--" ,(list (propertize "💼" )))
- ("tekton", (list (propertize "😼")))
- ("openshift-pipelines", (list (propertize "🎩")))
- ("redhat", (list (propertize "🎩")))
- ("area--" ,(list (propertize"🏢" )))
- ("area--home" ,(list (propertize "🏡")))
- ("home" ,(list (propertize "🏡")))
- ("home-services" ,(list (propertize "☕ ")))
- ("email" ,(list (propertize"📨" )))
- ("people" ,(list (propertize"👤" )))
- ("machine" ,(list (propertize "🖥️")))
- ("website" ,(list (propertize "🌍")))
- ("bike" ,(list (propertize "🚴♂️")))
- ("security" ,(list (propertize "🛡️")))
- ("i*" ,(list (propertize "📒")))))
- (org-agenda-sticky t)
- :config
-
- (defun vde/org-use-speed-commands-for-headings-and-lists ()
- "Activate speed commands on list items too."
- (or (and (looking-at org-outline-regexp) (looking-back "^\**" nil))
- (save-excursion (and (looking-at (org-item-re)) (looking-back "^[ \t]*" nil)))))
- (setq org-use-speed-commands 'vde/org-use-speed-commands-for-headings-and-lists)
- ;; TODO: see https://sachachua.com/blog/2025/03/org-mode-cutting-the-current-list-item-including-nested-lists-with-a-speed-command/
-
- ;; Refile org-mode cache when emacs has been idled for 5 minutes
- (run-with-idle-timer 300 t (lambda ()
- (org-refile-cache-clear)
- (org-refile-get-targets)))
-
- ;; Org Babel configurations
- (when (file-exists-p org-babel-library-file)
- (org-babel-lob-ingest org-babel-library-file))
- (defun vde/all-org-agenda-files ()
- (seq-filter (lambda(x) (and (not (string-match "/archive/" (file-name-directory x)))
- (not (string-match ".*==readwise=.*" x))))
- (apply 'append
- (mapcar
- (lambda (directory)
- (directory-files-recursively
- directory org-agenda-file-regexp))
- `(,org-directory)))))
- ;; (defun vde/reload-org-agenda-files ()
- ;; "Reload org-agenda-files variables with up-to-date org files"
- ;; (interactive)
- ;; (setq org-agenda-files (vde/org-agenda-files)))
- (defun vde/reload-org-refile-targets ()
- "Reload org-refile-targets variables with up-to-date org files"
- (interactive)
- (setq org-refile-targets (vde/org-refile-targets)))
- (defun vde/org-refile-targets ()
- (append '((org-inbox-file :level . 0))
- (->>
- (directory-files org-directory nil ".org$")
- (--remove (s-starts-with? "." it))
- (--map (format "%s/%s" org-directory it))
- (--map `(,it :maxlevel . 3)))
- (->>
- (directory-files org-notes-directory nil ".org$")
- (--remove (s-starts-with? "." it))
- (--map (format "%s/%s" org-notes-directory it))
- (--map `(,it :maxlevel . 3)))
- (->>
- (directory-files-recursively org-people-dir ".org$")
- (--remove (s-starts-with? (format "%s/legacy" org-people-dir) it))
- (--map (format "%s" it))
- (--map `(,it :maxlevel . 3)))))
- (setq org-agenda-files `(,org-inbox-file ,org-todos-file)
- ;; TODO: extract org-refile-targets into a function
- org-refile-targets (vde/org-refile-targets))
- (setopt org-agenda-sorting-strategy
- '((agenda time-up deadline-up scheduled-up todo-state-up priority-down)
- (todo todo-state-up priority-down deadline-up)
- (tags todo-state-up priority-down deadline-up)
- (search todo-state-up priority-down deadline-up)))
- (setq org-agenda-custom-commands
- '(
- ;; Archive tasks
- ("#" "To archive" todo "DONE|CANX")
- ;; TODO take inspiration from those
- ;; ("$" "Appointments" agenda* "Appointments")
- ;; ("b" "Week tasks" agenda "Scheduled tasks for this week"
- ;; ((org-agenda-category-filter-preset '("-RDV")) ; RDV for Rendez-vous
- ;; (org-agenda-use-time-grid nil)))
- ;;
- ;; ;; Review started and next tasks
- ;; ("j" "STRT/NEXT" tags-todo "TODO={STRT\\|NEXT}")
- ;;
- ;; ;; Review other non-scheduled/deadlined to-do tasks
- ;; ("k" "TODO" tags-todo "TODO={TODO}+DEADLINE=\"\"+SCHEDULED=\"\"")
- ;;
- ;; ;; Review other non-scheduled/deadlined pending tasks
- ;; ("l" "WAIT" tags-todo "TODO={WAIT}+DEADLINE=\"\"+SCHEDULED=\"\"")
- ;;
- ;; ;; Review upcoming deadlines for the next 60 days
- ;; ("!" "Deadlines all" agenda "Past/upcoming deadlines"
- ;; ((org-agenda-span 1)
- ;; (org-deadline-warning-days 60)
- ;; (org-agenda-entry-types '(:deadline))))
-
- ("d" "Daily Agenda"
- ((agenda ""
- ((org-agenda-span 'day)
- (org-deadline-warning-days 5)))
- (tags-todo "+PRIORITY=\"A\""
- ((org-agenda-overriding-header "High Priority Tasks")))
- (todo "NEXT"
- ((org-agenda-overriding-header "Next Tasks")))))
- ("D" "Daily Agenda (old)"
- ((agenda ""
- ((org-agenda-files (vde/all-org-agenda-files))
- (org-agenda-span 'day)
- (org-deadline-warning-days 5)))
- (tags-todo "+PRIORITY=\"A\""
- ((org-agenda-files (vde/all-org-agenda-files))
- (org-agenda-overriding-header "High Priority Tasks")))
- (todo "NEXT"
- ((org-agenda-files (vde/all-org-agenda-files))
- (org-agenda-overriding-header "Next Tasks")))))
- ("i" "Inbox (triage)"
- ((tags-todo ".*"
- ((org-agenda-files `(,org-inbox-file)) ;; FIXME use constant here
- (org-agenda-overriding-header "Unprocessed Inbox Item")))))
- ("A" "All (old)"
- ((tags-todo ".*"
- ((org-agenda-files (vde/all-org-agenda-files))))))
- ("u" "Untagged Tasks"
- ((tags-todo "-{.*}"
- ((org-agenda-overriding-header "Untagged tasks")))))
- ("w" "Weekly Review"
- ((agenda ""
- ((org-agenda-overriding-header "Completed Tasks")
- (org-agenda-skip-function '(org-agenda-skip-entry-if 'nottodo 'done))
- (org-agenda-span 'week)))
- (agenda ""
- ((org-agenda-overriding-header "Unfinished Scheduled Tasks")
- (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
- (org-agenda-span 'week)))))
- ;; FIXME Should only take into account projects and areas ?
- ("R" "Review projects" tags-todo "-CANX/"
- ((org-agenda-overriding-header "Reviews Scheduled")
- (org-agenda-skip-function 'org-review-agenda-skip)
- (org-agenda-cmp-user-defined 'org-review-compare)
- (org-agenda-sorting-strategy '(user-defined-down)))))))
-
-(use-package org-review
- :defer t
- :after (org)
- :config
- (setopt org-review-delay "+1w")
- (add-hook 'org-agenda-mode-hook
- (lambda ()
- (local-set-key (kbd "C-c C-r")
- 'org-review-insert-last-review))))
-
-;; Make sure we load org-protocol
-(use-package org-protocol
- :after org)
-
-(use-package org-tempo
- :after (org)
- :custom
- (org-structure-template-alist '(("a" . "aside")
- ("c" . "center")
- ("C" . "comment")
- ("e" . "example")
- ("E" . "export")
- ("Ea" . "export ascii")
- ("Eh" . "export html")
- ("El" . "export latex")
- ("q" . "quote")
- ("s" . "src")
- ("se" . "src emacs-lisp")
- ("sE" . "src emacs-lisp :results value code :lexical t")
- ("sg" . "src go")
- ("sr" . "src rust")
- ("sp" . "src python")
- ("v" . "verse"))))
-
-(use-package org-id
- :after org
- :commands contrib/org-id-headlines
- :init
- (defun contrib/org-id-headlines ()
- "Add CUSTOM_ID properties to all headlines in the current
-file which do not already have one."
- (interactive)
- (org-map-entries
- (funcall 'contrib/org-get-id (point) 'create)))
- :config
- (setq org-id-link-to-org-use-id
- 'create-if-interactive-and-no-custom-id))
-
-(use-package org-capture
- :after org
- :commands (org-capture)
- :config
-
- ;; TODO: refine this, create a function that reset this
- (add-to-list 'org-capture-templates
- `("l" "Link" entry
- (file ,org-inbox-file)
- "* %a\n%U\n%?\n%i"
- :empty-lines 1))
- (add-to-list 'org-capture-templates
- `("d" "daily entry" entry
- (function denote-journal-extras-new-or-existing-entry)
- "* %a\n%U\n%?\n%i"
- :empty-lines 1))
- (add-to-list 'org-capture-templates
- `("t" "Tasks"))
- (add-to-list 'org-capture-templates
- `("tt" "New task" entry
- (file ,org-inbox-file)
- "* %?\n:PROPERTIES:\n:CREATED:\t%U\n:END:\n\n%i\n\nFrom: %a"
- :empty-lines 1))
- ;; Refine this
- (add-to-list 'org-capture-templates
- `("tr" "PR Review" entry
- (file ,org-inbox-file)
- "* TODO review gh:%^{issue} :review:\n:PROPERTIES:\n:CREATED:%U\n:END:\n\n%i\n%?\nFrom: %a"
- :empty-lines 1))
- ;; emails
- (add-to-list 'org-capture-templates
- `("m" "Email Workflow"))
- (add-to-list 'org-capture-templates
- `("mf" "Follow Up" entry
- (file ,org-inbox-file)
- "* TODO Follow up with %:from on %a\nSCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%i"
- :immediate-finish t))
- (add-to-list 'org-capture-templates
- `("mr" "Read Later" entry
- (file ,org-inbox-file)
- "* TODO Read %:subject\nSCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%a\n\n%i" :immediate-finish t))
- ;; (add-to-list 'org-capture-templates
- ;; `("m" "Meeting notes" entry
- ;; (file+datetree ,org-meeting-notes-file)
- ;; (file ,(concat user-emacs-directory "/etc/orgmode/meeting-notes.org"))))
-
- (add-to-list 'org-capture-templates
- `("w" "Writing"))
- (add-hook 'org-capture-after-finalize-hook #'vde/window-delete-popup-frame)
- :bind (("C-c o c" . org-capture)))
-
-(defun vde/dired-notes ()
- "Open a dired buffer with all my notes"
- (interactive)
- (find-dired org-directory "-type f -not -path '*/archive/*'"))
-
-;; Using denote as the "source" of my second brain *in* org-mode.
-(use-package denote
- :commands (denote denote-region denote-type denote-date
- denote-signature denote-subdirectory
- denote-template denote-link-or-create
- denote-add-links denote-find-link
- denote-find-backlink denote-rename-file
- denote-rename-file-using-front-matter)
- :bind (("C-c n n" . vde/dired-notes)
- ("C-c n N" . denote)
- ("C-c n c" . denote-region)
- ("C-c n N" . denote-type)
- ("C-c n d" . denote-date)
- ("C-c n z" . denote-signature)
- ("C-c n S" . denote-subdirectory)
- ("C-c n t" . denote-template)
- ;; Links
- ("C-c n i" . denote-link-or-create)
- ("C-c n I" . denote-add-links)
- ("C-c n b" . denote-backlinks)
- ("C-c n F f" . denote-find-link)
- ("C-c n F b" . denote-find-backlink)
- ;; Renaming
- ("C-c n r" . denote-rename-file)
- ("C-c n R" . denote-rename-file-using-front-matter)
- ;; Dired
- (:map dired-mode-map
- ("C-c C-d C-i" . denote-link-dired-marked-notes)))
- :custom
- (denote-directory org-notes-directory)
- (denote-rename-buffer-format "📝 %t")
- (denote-date-prompt-denote-date-prompt-use-org-read-date t)
- (denote-prompts '(subdirectory title keywords))
- (denote-backlinks-display-buffer-action
- '((display-buffer-reuse-window
- display-buffer-in-side-window)
- (side . bottom)
- (slot . 99)
- (window-width . 0.3)
- (dedicated . t)
- (preserve-size . (t . t))))
- :hook (dired-mode . denote-dired-mode)
- :config
- (denote-rename-buffer-mode 1)
- (defun my-denote-always-rename-on-save-based-on-front-matter ()
- "Rename the current Denote file, if needed, upon saving the file.
-Rename the file based on its front matter, checking for changes in the
-title or keywords fields.
-
-Add this function to the `after-save-hook'."
- (let ((denote-rename-confirmations nil)
- (denote-save-buffers t)) ; to save again post-rename
- (when (and buffer-file-name (denote-file-is-note-p buffer-file-name))
- (ignore-errors (denote-rename-file-using-front-matter buffer-file-name))
- (message "Buffer saved; Denote file renamed"))))
-
- (add-hook 'after-save-hook #'my-denote-always-rename-on-save-based-on-front-matter)
-
- (with-eval-after-load 'org-capture
- (setq denote-org-capture-specifiers "%l\n%i\n%?")
- (add-to-list 'org-capture-templates
- '("n" "New note (with denote.el)" plain
- (file denote-last-path)
- #'denote-org-capture
- :no-save t
- :immediate-finish nil
- :kill-buffer t
- :jump-to-captured t)))
- (defun vde/org-category-from-buffer ()
- "Get the org category (#+category:) value from the buffer"
- (cond
- ((string-match "__journal.org$" (buffer-file-name))
- "journal")
- (t
- (denote-sluggify (denote--retrieve-title-or-filename (buffer-file-name) 'org))))))
-
-(use-package denote-journal
- :commands (denote-journal-new-entry
- denote-journal-new-or-existing-entry
- denote-journal-link-or-create-entry)
- :custom
- (denote-journal-directory nil) ;; use denote-directory
- (denote-journal-title-format 'day-date-month-year)
- :hook (calendar-mode . denote-journal-calendar-mode)
- :bind (("C-c n j j" . denote-journal-new-or-existing-entry)
- ("C-c n j i" . denote-journal-link-or-create-entry)
- ("C-c n j n" . denote-journal-new-entry)))
-
-(use-package denote-org
- :after denote)
-
-(use-package denote-menu
- :after denote
- :bind (("C-c n m" . list-denotes)
- (:map denote-menu-mode-map
- ("c" . denote-menu-clear-filters)
- ("/ r" . denote-menu-filter)
- ("/ k" . denote-menu-filter-by-keyword)
- ("/ o" . denote-menu-filter-out-keyword)
- ("e" . denote-menu-export-to-dired))))
-
-(use-package consult-denote
- :commands (consult-denote-mode
- consult-denote-find
- consult-denote-grep)
- :bind (("C-c n f" . consult-denote-find)
- ("C-c n s" . consult-denote-grep))
- :config
- (consult-denote-mode 1))
-
-(use-package orgit
- :defer t)
-
-(use-package ob-async
- :after org
- :commands (ob-async-org-babel-execute-src-block))
-(use-package ob-emacs-lisp
- :after org
- :commands (org-babel-execute:emacs-lisp org-babel-execute:elisp))
-(use-package ob-go
- :after org
- :commands (org-babel-execute:go))
-(use-package ob-python
- :after org
- :commands (org-babel-execute:python))
-(use-package ob-shell
- :after org
- :commands (org-babel-execute:ash
- org-babel-execute:bash
- org-babel-execute:csh
- org-babel-execute:dash
- org-babel-execute:fish
- org-babel-execute:ksh
- org-babel-execute:mksh
- org-babel-execute:posh
- org-babel-execute:sh
- org-babel-execute:shell
- org-babel-execute:zsh))
-;; my personal
-(use-package ol-github
- :after (org))
-(use-package ol-gitlab
- :after (org))
-(use-package ol-rg
- :disabled
- :after (org))
-(use-package ol-grep
- :after (org))
-
-;; built-in org-mode
-(use-package ol-eshell
- :after (org))
-(use-package ol-git-link
- :defer 2
- :after (org))
-(use-package ol-gnus
- :defer 2
- :after (org))
-(use-package ol-irc
- :defer 2
- :after (org))
-(use-package ol-info
- :defer 2
- :after (org))
-(use-package ol-man
- :defer 2
- :after (org))
-;; (use-package ol-notmuch
-;; :defer 2
-;; :after (org))
-;; (use-package ob-dot
-;; :after org
-;; :commands (org-babel-execute:dot))
-;; (use-package ob-ditaa
-;; :after org
-;; :commands (org-babel-execute:ditaa)
-;; :config
-;; (setq org-ditaa-jar-path "/home/vincent/.nix-profile/lib/ditaa.jar"))
-;; (use-package ob-doc-makefile
-;; :after org
-;; :commands (org-babel-execute:makefile))
-
-(use-package org-nix-shell
- :hook (org-mode . org-nix-shell-mode))
-
-(use-package org-rich-yank
- :after org
- :bind (:map org-mode-map
- ("C-M-y" . org-rich-yank)))
-
-;; from https://sachachua.com/blog/2024/01/using-consult-and-org-ql-to-search-my-org-mode-agenda-files-and-sort-the-results-to-prioritize-heading-matches/
-(defun my-consult-org-ql-agenda-jump ()
- "Search agenda files with preview."
- (interactive)
- (let* ((marker (consult--read
- (consult--dynamic-collection
- #'my-consult-org-ql-agenda-match)
- :state (consult--jump-state)
- :category 'consult-org-heading
- :prompt "Heading: "
- :sort nil
- :lookup #'consult--lookup-candidate))
- (buffer (marker-buffer marker))
- (pos (marker-position marker)))
- ;; based on org-agenda-switch-to
- (unless buffer (user-error "Trying to switch to non-existent buffer"))
- (pop-to-buffer-same-window buffer)
- (goto-char pos)
- (when (derived-mode-p 'org-mode)
- (org-fold-show-context 'agenda)
- (run-hooks 'org-agenda-after-show-hook))))
-
-(defun my-consult-org-ql-agenda-format (o)
- (propertize
- (org-ql-view--format-element o)
- 'consult--candidate (org-element-property :org-hd-marker o)))
-
-(defun my-consult-org-ql-agenda-match (string)
- "Return candidates that match STRING.
-Sort heading matches first, followed by other matches.
-Within those groups, sort by date and priority."
- (let* ((query (org-ql--query-string-to-sexp string))
- (sort '(date reverse priority))
- (heading-query (-tree-map (lambda (x) (if (eq x 'rifle) 'heading x)) query))
- (matched-heading
- (mapcar #'my-consult-org-ql-agenda-format
- (org-ql-select 'org-agenda-files heading-query
- :action 'element-with-markers
- :sort sort)))
- (all-matches
- (mapcar #'my-consult-org-ql-agenda-format
- (org-ql-select 'org-agenda-files query
- :action 'element-with-markers
- :sort sort))))
- (append
- matched-heading
- (seq-difference all-matches matched-heading))))
-
-(use-package org-ql
- :after org
- :bind ("M-s a" . my-consult-org-ql-agenda-jump))
-
-(use-package org-ql-view
- :after org-ql)
-
-(defun my-org-todo-set-keyword-faces ()
- (setq org-todo-keyword-faces
- `(("TODO" . (:foreground ,(modus-themes-get-color-value 'red-faint) :weight bold))
- ("NEXT" . (:foreground ,(modus-themes-get-color-value 'yellow-warmer) :weight bold))
- ("STARTED" . (:foreground ,(modus-themes-get-color-value 'yellow-intense) :weight bold))
- ("IN-REVIEW" . (:foreground ,(modus-themes-get-color-value 'blue-faint) :weight bold))
- ("DONE" . (:foreground ,(modus-themes-get-color-value 'green-warmer) :weight bold))
- ("CANX" . (:foreground ,(modus-themes-get-color-value 'comment) :weight bold))
- ("WAIT" . (:foreground ,(modus-themes-get-color-value 'magenta-faint) :weight bold))
- ("SOMEDAY" . (:foreground ,(modus-themes-get-color-value 'cyan-warmer) :weight bold))
- ("IDEA" . (:foreground ,(modus-themes-get-color-value 'magenta-cooler) :weight bold))))
- (when (derived-mode-p 'org-mode)
- (font-lock-fontify-buffer)))
-(my-org-todo-set-keyword-faces)
-(with-eval-after-load 'modus-themes
- (add-hook 'modus-themes-after-load-theme-hook #'my-org-todo-set-keyword-faces))
-
-(use-package ox-publish
- :after org
- :commands (org-publish org-publish-all org-publish-project org-publish-current-project org-publish-current-file)
- :config
- (setq org-html-coding-system 'utf-8-unix
- org-publish-use-timestamps-flag nil)
- (defun vde-org-git-exportable-files (directory)
- "Return a list of files from `DIRECTORY' that can be exported."
- (directory-files directory nil ".*_www.*\\.org$"))
- (setq org-publish-project-alist
- `(("resources"
- :base-directory ,org-directory
- :base-extension "org"
- ;; :include ".*_www*.org"
- :include ,(vde-org-git-exportable-files org-directory)
- :exclude ".*"
- :publishing-directory ,(expand-file-name "resources" src-www-dir)
- :publishing-function org-html-publish-to-html
- :recursive t
- :with-toc nil
- :section-numbers nil
- :html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"../css/2022.css\" />"
- :html-head-extra "<link rel=\"stylesheet\" type=\"text/css\" href=\"../css/syntax.css\" />"
- :html-preamble t
- :html-postamble t
- :auto-sitemap t
- :sitemap-filename "index.org"
- :sitemap-title "Resources"
- :sitemap-sort-files anti-chronologically
- :sitemap-file-entry-format "%d %t"
- :sitemap-date-format "%Y-%m-%d"
- ;; :sitemap-function org-publish-org-sitemap
- ))))
-(use-package org-habit
- :after (org)
- :config
- (setq org-habit-show-habits-only-for-today nil
- org-habit-graph-column 80))
-(use-package org-download
- :after (org)
- :hook ((dired-mode . org-download-enable)
- (org-mode . org-download-enable))
- :config
- (org-download-enable)
- (setq org-startup-with-inline-images t)
- (setq org-download-display-inline-images t)
- (setq org-download-method 'attach))
-
-;; Persistent notes (like persistent-scratch, but built-in)
-(setq remember-data-file org-remember-file
- remember-handler-functions '(remember-append-to-file)
- remember-notes-initial-major-mode 'org-mode
- remember-notes-auto-save-visited-file-name t
- remember-in-new-frame t)
-
-(use-package consult-org
- :after (consult org)
- :commands (consult-org-agenda consult-org-heading))
-
-(provide 'config-org)
-;;; config-org.el ends here
tools/emacs/config/config-programming.el
@@ -1,120 +0,0 @@
-;;; config-programming.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Configure general programming
-;;; Code:
-
-(declare-function vde-project--project-root-or-default-directory "proj-func")
-
-(defun my-recompile (args)
- (interactive "P")
- (cond
- ((eq major-mode #'emacs-lisp-mode)
- (call-interactively 'eros-eval-defun))
- ((bound-and-true-p my-vterm-command)
- (my-vterm-execute-region-or-current-line my-vterm-command))
- ((get-buffer "*compilation*")
- (with-current-buffer"*compilation*"
- (recompile)))
- ((get-buffer "*Go Test*")
- (with-current-buffer "*Go Test*"
- (recompile)))
- ((and (eq major-mode #'go-mode)
- buffer-file-name
- (string-match
- "_test\\'" (file-name-sans-extension buffer-file-name)))
- (my-gotest-maybe-ts-run))
- ((and (get-buffer "*cargo-test*")
- (boundp 'my-rustic-current-test-compile)
- my-rustic-current-test-compile)
- (with-current-buffer "*cargo-test*"
- (rustic-cargo-test-run my-rustic-current-test-compile)))
- ((get-buffer "*cargo-run*")
- (with-current-buffer "*cargo-run*"
- (rustic-cargo-run-rerun)))
- ((get-buffer "*pytest*")
- (with-current-buffer "*pytest*"
- (recompile)))
- ((eq major-mode #'python-mode)
- (compile (concat python-shell-interpreter " " (buffer-file-name))))
- ((call-interactively 'compile))))
-
-(defun run-command-recipes-make--commands (makefile)
- "Return the list of commands names that was defined in MAKEFILE."
- (let ((s (f-read makefile))
- (commands nil)
- (pos 0))
- (while (string-match "^\\([^ \n]+\\):" s pos)
- (push (match-string 1 s) commands)
- (setq pos (match-end 0)))
- commands))
-
-;; TODO github run-command: if remote is github.com, add a gh create pr command, and other "goodies"…
-;; TODO tektoncd run-command: if project is tektoncd
-;; TODO redhat run-command: if it's a redhat project
-;; TODO local run-command: figure out how it works
-
-(use-package run-command
- :bind ("C-c c" . run-command)
- :config
- (defun run-command-recipe-make()
- "Returns a dynamic list of commands based of a Makefile.
-
-This is condition to the following:
-- `make' executable found
-- `Makefile' file present in project root *or* the default directory."
- (let* ((dir (vde-project--project-root-or-default-directory))
- (makefile (expand-file-name "Makefile" dir)))
- (when (and
- (executable-find "make")
- (file-exists-p makefile))
- (message "Makefile present")
- (let ((targets (run-command-recipes-make--commands makefile)))
- (mapcar (lambda (target)
- (unless (or (string-prefix-p "." target)
- (string-prefix-p "$" target)
- (string= "FORCE" target))
- (list :command-line (concat "make " target)
- :command-name target
- :working-dir dir
- :runner 'run-command-runner-compile)))
- targets)))))
- (defun run-command-recipe-hack ()
- "Returns a dynamic list of commands based of the presence of an `hack' folder
-in the project root *or* the default-directory."
- (let* ((dir (vde-project--project-root-or-default-directory))
- (hack-dir (expand-file-name "hack" dir))
- (files (or (ignore-errors (directory-files hack-dir)) [])))
- (when (file-accessible-directory-p hack-dir)
- (mapcar (lambda (file)
- (let ((hack-file (expand-file-name file hack-dir)))
- (when (and (file-regular-p hack-file)
- (file-executable-p hack-file))
- (list :command-line hack-file
- :command-name file
- :working-dir dir
- :runner 'run-command-runner-compile))))
- files))))
- (add-to-list 'run-command-recipes 'run-command-recipe-hack)
- (add-to-list 'run-command-recipes 'run-command-recipe-make))
-
-(defvar highlight-codetags-keywords
- '(("\\<\\(TODO\\|FIXME\\|BUG\\|XXX\\)\\>" 1 font-lock-warning-face prepend)
- ("\\<\\(NOTE\\|HACK\\)\\>" 1 font-lock-doc-face prepend)))
-
-(define-minor-mode highlight-codetags-local-mode
- "Highlight codetags like TODO, FIXME..."
- :global nil
- (if highlight-codetags-local-mode
- (font-lock-add-keywords nil highlight-codetags-keywords)
- (font-lock-remove-keywords nil highlight-codetags-keywords))
-
- ;; Fontify the current buffer
- (when (bound-and-true-p font-lock-mode)
- (if (fboundp 'font-lock-flush)
- (font-lock-flush)
- (with-no-warnings (font-lock-fontify-buffer)))))
-
-(add-hook 'prog-mode-hook #'highlight-codetags-local-mode)
-
-(provide 'config-programming)
-;;; config-programming.el ends here
tools/emacs/config/config-projects.el
@@ -1,91 +0,0 @@
-;;; config-projects.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Project related configuration.
-;;; Code:
-
-(require 'json)
-
-(use-package project
- :commands (project-find-file project-find-regexp vde/project-vterm vde/project-run-in-vterm)
- :custom ((project-switch-commands '((?f "File" project-find-file)
- (?g "Grep" project-find-regexp)
- (?d "Dired" project-dired)
- (?b "Buffer" project-switch-to-buffer)
- (?q "Query replace" project-query-replace-regexp)
- (?m "Magit" vde-project-magit-status)
- (?e "Eshell" project-eshell)
- (?E "Eat" vde/project-eat)
- (?s "Vterm" vde/project-vterm)
- (?R "README" vde/open-readme)
- (?g "Checkout GitHub PR" checkout-github-pr)))
- (project-mode-line t))
- :bind (("C-x p v" . vde-project-magit-status)
- ("C-x p s" . vde/project-vterm)
- ("C-x p X" . vde/project-run-in-vterm)
- ("C-x p E" . vde/project-eat)
- ("C-x p G" . checkout-github-pr))
- :init
- ;; (require project-rootfile)
- ;; (add-to-list 'project-find-functions #'project-rootfile-try-detect t)
- ;; (setq project-rootfile-list '(".project"
- ;; "default.nix" "flake.nix" ; nix
- ;; "Makefile" "GNUMakefile" "CMakeLists.txt" ; Make & CMake
- ;; "Cask" "Eldev" "Keg" "Eask" ; Emacs
- ;; "stack.yaml" ; Haskell
- ;; "Cargo.toml" ; Rust
- ;; "go.mod" ; Go
- ;; ))
- :config
- (setq vde/project-local-identifier '(".project")) ;; "go.mod"
-
- ;; (add-hook 'project-find-functions #'vde/project-try-local)
-
- (setq-default project-compilation-buffer-name-function 'project-prefixed-buffer-name)
- (defun vde-project-magit-status ()
- "Run `magit-status' on project."
- (interactive)
- (magit-status (vde-project--project-current)))
-
- ;; (general-leader
- ;; "p" '(:ignore :which-key "Project")
- ;; "pp" #'(project-switch-project :which-key "Switch to Project")
- ;; "ps" #'(project-search :which-key "Grep in Project")
- ;; "pf" #'(project-find-file :which-key "Find in Project")
- ;; "pd" #'(project-dired :which-key "Dired in Project")
- ;; "pc" #'(project-compile :which-key "Compile in Project")
- ;; "pb" #'(project-switch-to-buffer :which-key "Switch to Project Buffer")
- ;; "pk" #'(project-kill-buffers :which-key "Kill Project Buffers")
- ;; "ps" #'(vde/project-vterm :which-key "Start a vterm in Project")
- ;; "pe" #'(project-eshell :which-key "Start a eshell in Project")
- ;; "pE" #'(vde/project-eat :which-key "Start a eat term in Project")
- ;; "px" #'(vde/project-run-in-vterm :which-key "Execute command in vterm in Project"))
- )
-
-(use-package conner
- :bind (("C-x p C" . conner-run-project-command))
- :commands (conner-run-project-command)
- :config
- (require 'vterm))
-
-(use-package project-x
- :after project
- :config
- (add-hook 'project-find-functions 'project-x-try-local 90)
- (add-hook 'kill-emacs-hook 'project-x--window-state-write)
- (add-to-list 'project-switch-commands
- '(?j "Restore windows" project-x-windows) t)
- :bind (("C-x p w" . project-x-window-state-save)
- ("C-x p j" . project-x-window-state-load)))
-
-(use-package jira
- :commands (jira-issues)
- :config
- (setq jira-base-url "https://issues.redhat.com"
- jira-username "vdemeest@redhat.com"
- jira-token (passage-get "redhat/issues/token/myji")
- jira-token-is-personal-access-token t
- jira-api-version 2
- jira-issues-max-results 500))
-
-(provide 'config-projects)
-;;; config-projects.el ends here
tools/emacs/config/config-search.el
@@ -1,183 +0,0 @@
-;;; config-search.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Search related configuration
-;;; Code:
-
-(setq xref-search-program
- (cond
- ((or (executable-find "ripgrep")
- (executable-find "rg"))
- 'ripgrep)
- ((executable-find "ugrep")
- 'ugrep)
- (t
- 'grep)))
-
-;; UseISearch
-(use-package isearch
- :unless noninteractive
- :config
- (defun my-project-search-from-isearch ()
- (interactive)
- (let ((query (if isearch-regexp
- isearch-string
- (regexp-quote isearch-string))))
- (isearch-update-ring isearch-string isearch-regexp)
- (let (search-nonincremental-instead)
- (ignore-errors (isearch-done t t)))
- (project-find-regexp query)))
- (defun my-occur-from-isearch ()
- (interactive)
- (let ((query (if isearch-regexp
- isearch-string
- (regexp-quote isearch-string))))
- (isearch-update-ring isearch-string isearch-regexp)
- (let (search-nonincremental-instead)
- (ignore-errors (isearch-done t t)))
- (occur query)))
- (setq-default search-whitespace-regexp ".*?"
- isearch-lax-whitespace t
- isearch-regexp-lax-whitespace nil
- isearch-lazy-count t
- lazy-count-prefix-format nil
- lazy-count-suffix-format " (%s/%s)")
- (defun stribb/isearch-region (&optional not-regexp no-recursive-edit)
- "If a region is active, make this the isearch default search
-pattern."
- (interactive "P\np")
- (when (use-region-p)
- (let ((search (buffer-substring-no-properties
- (region-beginning)
- (region-end))))
- (message "stribb/ir: %s %d %d" search (region-beginning) (region-end))
- (setq deactivate-mark t)
- (isearch-yank-string search))))
- (advice-add 'isearch-forward-regexp :after 'stribb/isearch-region)
- (advice-add 'isearch-forward :after 'stribb/isearch-region)
- (advice-add 'isearch-backward-regexp :after 'stribb/isearch-region)
- (advice-add 'isearch-backward :after 'stribb/isearch-region)
-
- (defun contrib/isearchp-remove-failed-part-or-last-char ()
- "Remove failed part of search string, or last char if successful.
-Do nothing if search string is empty to start with."
- (interactive)
- (if (equal isearch-string "")
- (isearch-update)
- (if isearch-success
- (isearch-delete-char)
- (while (isearch-fail-pos) (isearch-pop-state)))
- (isearch-update)))
-
- (defun contrib/isearch-done-opposite-end (&optional nopush edit)
- "End current search in the opposite side of the match.
-Particularly useful when the match does not fall within the
-confines of word boundaries (e.g. multiple words)."
- (interactive)
- (funcall #'isearch-done nopush edit)
- (when isearch-other-end (goto-char isearch-other-end)))
- :bind (("M-s M-o" . multi-occur)
- :map isearch-mode-map
- ("C-o" . my-occur-from-isearch)
- ("C-f" . my-project-search-from-isearch)
- ("C-d" . isearch-forward-symbol-at-point)
- ("DEL" . contrib/isearchp-remove-failed-part-or-last-char)
- ("<C-return>" . contrib/isearch-done-opposite-end)))
-;; -UseISearch
-
-;; UseGrep
-(use-package grep
- :commands (find-grep grep find-grep-dired find-name-dired)
- :bind (("M-s n" . find-name-dired)
- ("M-s F" . find-grep)
- ("M-s G" . grep)
- ("M-s d" . find-grep-dired))
- :hook ((hook-mode . toggle-truncate-lines))
- :config
- (setq-default grep-template (string-join '("ugrep"
- "--color=always"
- "--ignore-binary"
- "--ignore-case"
- "--include=<F>"
- "--line-number"
- "--null"
- "--recursive"
- "--regexp=<R>")
- " "))
- (add-to-list 'grep-find-ignored-directories "auto")
- (add-to-list 'grep-find-ignored-directories "elpa"))
-;; -UseGrep
-
-;; UseWgrep
-(use-package wgrep
- :unless noninteractive
- :commands (wgrep-change-to-wgrep-mode)
- :defer 2
- :custom
- (wgrep-auto-save-buffer t)
- (wgrep-change-readonly-file t))
-;; -UseWgrep
-
-;; UseRG
-(use-package rg
- :if (executable-find "rg")
- :commands (rg rg-project rg-dwim)
- :bind (("M-s r r" . rg)
- ("M-s r p" . rg-project)
- ("M-s r s" . rg-dwim))
- :config
- (setq rg-group-result t)
- (setq rg-hide-command t)
- (setq rg-show-columns nil)
- (setq rg-show-header t)
- (setq rg-default-alias-fallback "all")
- (cl-pushnew '("tmpl" . "*.tmpl") rg-custom-type-aliases)
- (cl-pushnew '("gotest" . "*_test.go") rg-custom-type-aliases)
- (defun vde/rg-buffer-name ()
- "Generate a rg buffer name from project if in one"
- (let ((p (project-root (project-current))))
- (if p
- (format "rg: %s" (abbreviate-file-name p))
- "rg")))
- (setq rg-buffer-name #'vde/rg-buffer-name)
- ;; (when (f-dir-p "~/src/home/")
- ;; (rg-define-search rg-projects-dotemacs
- ;; "Search home"
- ;; :dir "~/src/home/"
- ;; :files "*.*"
- ;; :menu ("Projects" "H" "home")))
- ;; (when (f-dir-p "~/src/github.com/NixOS/nixpkgs/")
- ;; (rg-define-search rg-projects-nixpkgs
- ;; "Search nixpkgs"
- ;; :dir "~/src/github.com/NixOS/nixpkgs/"
- ;; :files "*.*"
- ;; :menu ("Projects" "N" "nixpkgs")))
- ;; (when (f-dir-p "~/src/tektoncd/pipeline/")
- ;; (rg-define-search rg-projects-tektoncd-pipeline
- ;; "Search tektoncd/pipeline"
- ;; :dir "~/src/tektoncd/pipeline/"
- ;; :files "*.*"
- ;; :menu ("tektoncd" "P" "pipeline")))
- ;; (when (f-dir-p "~/src/tektoncd/operator/")
- ;; (rg-define-search rg-projects-tektoncd-operator
- ;; "Search tektoncd/operator"
- ;; :dir "~/src/tektoncd/operator/"
- ;; :files "*.*"
- ;; :menu ("tektoncd" "P" "operator")))
- ;; (when (f-dir-p "~/src/tektoncd/cli/")
- ;; (rg-define-search rg-projects-tektoncd-cli
- ;; "Search tektoncd/cli"
- ;; :dir "~/src/tektoncd/cli/"
- ;; :files "*.*"
- ;; :menu ("tektoncd" "C" "cli")))
- ;; (when (f-dir-p "~/src/chmouel/")
- ;; (rg-define-search rg-projects-chmouel
- ;; "Search chmouel"
- ;; :dir "~/src/chmouel/"
- ;; :files "*.*"
- ;; :menu ("Configs" "ch" "chmouel")))
- )
-
-;; -UseRG
-
-(provide 'config-search)
-;;; config-search.el ends here
tools/emacs/config/config-shells.el
@@ -1,442 +0,0 @@
-;;; config-shells.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Shell scripting
-;;; Code:
-
-(defvar ISATUIN (executable-find "atuin")
- "Whether atuin is available for shell/eshell history.")
-
-(use-package shell
- :commands (shell)
- :bind (("<f1>" . shell)
- (:map shell-mode-map
- ("<tab>" . completion-at-point)))
- :config
- (setq-default explicit-shell-file-name "zsh"
- shell-file-name "zsh")
- (unbind-key "C-c C-l" shell-mode-map)
- (bind-key "C-c C-l" #'counsel-shell-history shell-mode-map))
-
-(defun run-in-compile (base-cmd &rest ARGS)
- "Use `compile' to run the BASE-CMD and ARGS, from eshell."
- (compile (concat base-cmd " " (apply #'concat ARGS))))
-
-;; TODO: understand and rework eshell completion
-(use-package eshell
- :commands (eshell eshell-here)
- :bind* ("C-x m t" . eshell-here)
- :config
- (defun eshell/make (&rest ARGS)
- "Shortcut to more easily run builds in a compile buffer"
- (cond ((or (file-exists-p "Makefile")
- (file-exists-p "makefile"))
- (run-in-compile "make" ARGS))
- ((file-exists-p "build.zig")
- (run-in-compile "zig build"))
- (t "No supported build system found.")))
- (defun eshell-here ()
- "Open EShell in the directory associated with the current buffer's file.
-The EShell is renamed to match that directory to make multiple windows easier."
- (interactive)
- (let* ((parent (if (buffer-file-name)
- (file-name-directory (buffer-file-name))
- default-directory))
- (name (car (last (split-string parent "/" t)))))
- (eshell "new")
- (rename-buffer (concat "*eshell: " name "*"))))
-
- ;; Handy aliases
- (defalias 'ff 'find-file)
- (defalias 'emacs 'find-file)
- (defalias 'e 'find-file)
- (defalias 'ec 'find-file)
- (defalias 'd 'dired)
-
- (defun eshell/gs (&rest args)
- (magit-status (pop args) nil)
- (eshell/echo)) ; The echo command suppresses output
-
- (defun eshell/cdg ()
- "Change directory to the project's root."
- (eshell/cd (locate-dominating-file default-directory ".git")))
-
- (defun eshell/extract (file)
- "One universal command to extract FILE (for bz2, gz, rar, etc.)"
- (eshell-command-result (format "%s %s" (cond ((string-match-p ".*\.tar.bz2" file)
- "tar xzf")
- ((string-match-p ".*\.tar.gz" file)
- "tar xzf")
- ((string-match-p ".*\.bz2" file)
- "bunzip2")
- ((string-match-p ".*\.rar" file)
- "unrar x")
- ((string-match-p ".*\.gz" file)
- "gunzip")
- ((string-match-p ".*\.tar" file)
- "tar xf")
- ((string-match-p ".*\.tbz2" file)
- "tar xjf")
- ((string-match-p ".*\.tgz" file)
- "tar xzf")
- ((string-match-p ".*\.zip" file)
- "unzip")
- ((string-match-p ".*\.jar" file)
- "unzip")
- ((string-match-p ".*\.Z" file)
- "uncompress")
- (t
- (error "Don't know how to extract %s" file)))
- file)))
-
- ;; From https://karthinks.com/software/jumping-directories-in-eshell/
- (defun eshell/j (&optional regexp)
- "Navigate to a previously visited directory in eshell, or to
-any directory proferred by `consult-dir'."
- (let ((eshell-dirs (delete-dups
- (mapcar 'abbreviate-file-name
- (ring-elements eshell-last-dir-ring)))))
- (cond
- ((and (not regexp) (featurep 'consult-dir))
- (let* ((consult-dir--source-eshell `(:name "Eshell"
- :narrow ?e
- :category file
- :face consult-file
- :items ,eshell-dirs))
- (consult-dir-sources (cons consult-dir--source-eshell
- consult-dir-sources)))
- (eshell/cd (substring-no-properties
- (consult-dir--pick "Switch directory: ")))))
- (t (eshell/cd (if regexp (eshell-find-previous-directory regexp)
- (completing-read "cd: " eshell-dirs)))))))
-
- (add-hook
- 'eshell-mode-hook
- (lambda ()
- (let ((ls (if (executable-find "exa") "exa" "ls")))
- (eshell/alias "ls" (concat ls " $*"))
- (eshell/alias "ll" (concat ls " -l $*"))
- (eshell/alias "l" (concat ls " -lah $*")))
- (eshell-smart-initialize)
- (eshell-dirs-initialize)
- (bind-keys :map eshell-mode-map
- ("C-c C-l" . counsel-esh-history)
- ([remap eshell-pcomplete] . completion-at-point)
- )))
-
- ;; Use system su/sudo
- (with-eval-after-load "em-unix"
- '(progn
- (unintern 'eshell/su nil)
- (unintern 'eshell/sudo nil)))
-
- (add-hook 'eshell-mode-hook #'with-editor-export-editor))
-
-(use-package eshell-atuin
- :when ISATUIN
- :after eshell
- ;; :bind* ( :map eshell-mode-map
- ;; ([remap eshell-previous-matching-input] . eshell-atuin-history))
- :bind (("C-r" . eshell-atuin-history)
- ([remap eshell-list-history] . eshell-atuin-history))
- :config
- (eshell-atuin-mode)
- (setopt eshell-atuin-filter-mode 'global
- eshell-atuin-search-fields '(time duration command directory host)
- eshell-atuin-search-options '() ;; default --exit 0 ignores all the one imported… which is a shame
- eshell-atuin-history-format "%-80c %-40i %>10t %h"))
-
-(use-package em-prompt
- :after eshell
- :config
- (defun vde/eshell-quit-or-delete-char (arg)
- "Use C-d to either delete forward char or exit EShell."
- (interactive "p")
- (if (and (eolp) (looking-back eshell-prompt-regexp nil nil))
- (progn
- (eshell-life-is-too-much))
- (delete-char arg)))
-
- (add-hook 'eshell-mode-hook
- (lambda ()
- (bind-key "C-d"
- #'vde/eshell-quit-or-delete-char eshell-mode-map))))
-
-(use-package esh-mode
- :disabled
- :after eshell
- :bind (:map eshell-mode-map
- ("<tab>" . vde/esh-mode-completion-at-point))
- :config
- (setq-default eshell-scroll-to-bottom-on-input 'all)
- (defun vde/esh-mode-completion-at-point ()
- "Same as `completion-at-point' except for some commands."
- (interactive)
- ;; unbinding pcomplete/make gives a chance to `bash-completion'
- ;; to complete make rules. Bash-completion is indeed more
- ;; powerfull than `pcomplete-make'.
- (cl-letf (((symbol-function 'pcomplete/make) nil))
- (completion-at-point))))
-
-(use-package em-smart
- :after eshell)
-(use-package em-dirs
- :after eshell)
-
-(use-package em-cmpl
- :after eshell
- :hook (eshell-mode . eshell-cmpl-initialize)
- :config
- (defun my/eshell-bash-completion ()
- (let ((bash-completion-nospace t))
- (while (pcomplete-here
- (nth 2 (bash-completion-dynamic-complete-nocomint
- (save-excursion (eshell-bol) (point))
- (point)))))))
- (when (require 'bash-completion nil t)
- (setq eshell-default-completion-function #'my/eshell-bash-completion))
-
- (add-to-list 'eshell-command-completions-alist
- '("gunzip" "gz\\'"))
- (add-to-list 'eshell-command-completions-alist
- '("tar" "\\(\\.tar|\\.tgz\\|\\.tar\\.gz\\)\\'")))
-
-(use-package em-hist
- :after eshell
- :config (setq eshell-hist-ignoredups t))
-
-(use-package em-tramp
- :after eshell)
-
-(use-package em-term
- :after eshell
- :config
- (add-to-list 'eshell-visual-commands "ssh")
- (add-to-list 'eshell-visual-commands "htop")
- (add-to-list 'eshell-visual-commands "top")
- (add-to-list 'eshell-visual-commands "tail")
- (add-to-list 'eshell-visual-commands "npm")
- (add-to-list 'eshell-visual-commands "ncdu"))
-
-(use-package em-banner
- :after eshell
- :config
- (setq eshell-banner-message "
- Welcome to the Emacs
-
- _/ _/ _/
- _/_/ _/_/_/ _/_/_/ _/_/ _/ _/
- _/_/_/_/ _/_/ _/ _/ _/_/_/_/ _/ _/
- _/ _/_/ _/ _/ _/ _/ _/
- _/_/_/ _/_/_/ _/ _/ _/_/_/ _/ _/
-
-"))
-
-(use-package eshell-prompt-extras
- :after eshell
- :custom
- (eshell-highlight-prompt nil)
- (eshell-prompt-function 'vde-theme-lambda)
- :config
- (setq epe-path-style 'fish
- epe-fish-path-max-len 20)
- (defun vde-kubernetes-current-context ()
- "Return the current context"
- (if (not (string-empty-p (getenv "KUBECONFIG")))
- (epe-trim-newline (shell-command-to-string (concat
- "env KUBECONFIG="
- (getenv "KUBECONFIG")
- " kubectl config current-context")))
- (epe-trim-newline (shell-command-to-string "kubectl config current-context"))))
- (defun vde-kubernetes-p ()
- "If you have kubectl install and a config set,
-using either KUBECONFIG or ~/.kube/config"
- (and (eshell-search-path "kubectl")
- (not (string-empty-p (vde-kubernetes-current-context)))
- (not (string-match-p "error: current-context is not set" (vde-kubernetes-current-context)))))
- ;; From epe-theme-lambda
- (defun vde-theme-lambda ()
- "A eshell-prompt lambda theme."
- (setq eshell-prompt-regexp "^[^#\nλ]*[#λ] ")
- (concat
- (when (epe-remote-p)
- (epe-colorize-with-face
- (concat (epe-remote-user) "@" (epe-remote-host) " ")
- 'epe-remote-face))
- (when (and epe-show-python-info (bound-and-true-p venv-current-name))
- (epe-colorize-with-face (concat "(" venv-current-name ") ") 'epe-venv-face))
- (let ((f (cond ((eq epe-path-style 'fish) 'epe-fish-path)
- ((eq epe-path-style 'single) 'epe-abbrev-dir-name)
- ((eq epe-path-style 'full) 'abbreviate-file-name))))
- (epe-colorize-with-face (funcall f (eshell/pwd)) 'epe-dir-face))
- (when (epe-git-p)
- (concat
- (epe-colorize-with-face ":" 'epe-dir-face)
- (epe-colorize-with-face
- (concat (epe-git-branch)
- (epe-git-dirty)
- (epe-git-untracked)
- (let ((unpushed (epe-git-unpushed-number)))
- (unless (= unpushed 0)
- (concat ":" (number-to-string unpushed)))))
- 'epe-git-face)))
- (when (vde-kubernetes-p)
- (concat (epe-colorize-with-face " (" 'epe-dir-face)
- (epe-colorize-with-face (vde-kubernetes-current-context) 'epe-dir-face)
- (epe-colorize-with-face ")" 'epe-dir-face)))
- (epe-colorize-with-face " λ" 'epe-symbol-face)
- (epe-colorize-with-face (if (= (user-uid) 0) "#" "") 'epe-sudo-symbol-face)
- " ")))
-
-(use-package eat
- :commands (eat)
- :init (setq eat-kill-buffer-on-exit t
- eat-enable-yank-to-terminal t)
- :hook ((eshell-mode . eat-eshell-mode)
- (eshell-mode . eat-eshell-visual-command-mode)))
-
-(use-package xterm-color
- :after eshell
- :init
- ;; (setq comint-output-filter-functions
- ;; (remove 'ansi-color-process-output comint-output-filter-functions))
- (add-hook 'shell-mode-hook
- (lambda ()
- ;; Disable font-locking in this buffer to improve performance
- (font-lock-mode -1)
- ;; Prevent font-locking from being re-enabled in this buffer
- (make-local-variable 'font-lock-function)
- (setq font-lock-function (lambda (_) nil))
- (add-hook 'comint-preoutput-filter-functions 'xterm-color-filter nil t)))
- (add-hook 'eshell-before-prompt-hook
- (lambda ()
- (setenv "TERM" "xterm-256color")
- (setq xterm-color-preserve-properties t)))
- (add-to-list 'eshell-preoutput-filter-functions 'xterm-color-filter)
- (setq eshell-output-filter-functions (remove 'eshell-handle-ansi-color eshell-output-filter-functions))
- (setq compilation-environment '("TERM=xterm-256color")))
-
-(use-package vterm
- :commands (vterm vde/vterm-toggle)
- :bind (("C-c t v" . vde/vterm-toggle)
- ("C-c t r" . vde/run-in-vterm))
- :custom
- (vterm-kill-buffer-on-exit t)
- (vterm-max-scrollback 100000)
- (vterm-tramp-shells '(("scp" "/usr/bin/env zsh")
- ("ssh" "/usr/bin/env zsh")
- ("sshx" "/usr/bin/env zsh")
- ("sshfs" "/usr/bin/env zsh")
- ("docker" "/bin/sh")))
- :config
- (defun vde/vterm-tramp-get-method-parameter (method param)
- "Return the method parameter PARAM.
-If the `tramp-methods' entry does not exist, return NIL."
- (let ((entry (assoc param (assoc method tramp-methods))))
- (when entry (cadr entry))))
- (add-hook 'vterm-set-title-functions 'vterm--rename-buffer-as-title)
- ;; TODO: hook into projectile-run-vterm instead
- ;; Also, look into vterm-toggle way of doing things.. I thing it is trying to be too smart about it..
- ;; I prefer an easy projectile integration (or projects integration)
- (defun vde/vterm ()
- ""
- (interactive)
- (let* ((dir (expand-file-name default-directory))
- cd-cmd cur-host vterm-dir vterm-host cur-user cur-port remote-p cur-method login-cmd)
- (if (ignore-errors (file-remote-p dir))
- (with-parsed-tramp-file-name dir nil
- (setq remote-p t)
- (setq cur-host host)
- (setq cur-method (tramp-find-method method user cur-host))
- (setq cur-user (or (tramp-find-user cur-method user cur-host) ""))
- (setq cur-port (or port ""))
- (setq dir localname))
- (setq cur-host (system-name)))
- (setq login-cmd (vde/vterm-tramp-get-method-parameter cur-method 'tramp-login-program))
- (setq cd-cmd (concat " cd " (shell-quote-argument dir)))
- (setq shell-buffer (format "vterm %s %s" cur-host dir))
- (if (buffer-live-p shell-buffer)
- (switch-to-buffer shell-buffer)
- (progn
- (message (format "buffer '%s' doesn't exists" shell-buffer))
- (vterm shell-buffer)
- (with-current-buffer shell-buffer
- (message (format "%s" remote-p))
- (when remote-p
- (let* ((method (if (string-equal login-cmd "ssh") "ssh" cur-method))
- (login-opts (vde/vterm-tramp-get-method-parameter method 'tramp-login-args))
- (login-shell (vde/vterm-tramp-get-method-parameter method 'tramp-remote-shell))
- (login-shell-args (tramp-get-sh-extra-args login-shell))
- ;; (vterm-toggle-tramp-get-method-parameter cur-method 'tramp-remote-shell)
- (spec (format-spec-make
- ?h cur-host ?u cur-user ?p cur-port ?c ""
- ?l (concat login-shell " " login-shell-args)))
- (cmd
- (concat login-cmd " "
- (mapconcat
- (lambda (x)
- (setq x (mapcar (lambda (y) (format-spec y spec)) x))
- (unless (member "" x) (string-join x " ")))
- login-opts " "))))
- (vterm-send-string cmd)
- (vterm-send-return)))
- (vterm-send-string cd-cmd)
- (vterm-send-return))))))
- (defun vde/vterm-toggle ()
- "Toggle between the main vterm buffer and the current buffer.
-If you are in a vterm buffer, switch the window configuration
-back to your code buffers. Otherwise, create at least one vterm
-buffer if it doesn't exist already, and switch to it. On every
-toggle, the current window configuration is saved in a register."
- (interactive)
- (if (eq major-mode 'vterm-mode)
- (jump-to-register ?W)
- ;; Save current window config and jump to shell
- (window-configuration-to-register ?W)
- (condition-case nil
- (jump-to-register ?Z)
- (error
- (vterm)
- (when (= (length (window-list)) 2)
- (other-window 1)
- (vterm 1)
- (other-window 1))))
- (window-configuration-to-register ?Z)))
- (buffer-name)
- (defun vde/run-in-vterm ()
- (interactive)
- (with-current-buffer "vterm"
- (vterm-send-string (read-string "Command: "))
- (vterm-send-C-j))))
-
-(use-package multi-vterm
- :commands (multi-vterm multi-vterm-projectile multi-vterm-dedicated-toggle)
- :bind (("C-c t t" . multi-vterm-dedicated-toggle)
- ("C-c t p" . multi-vterm-prev)
- ("C-c t n" . multi-vterm-next)
- ("C-c t s" . multi-vterm)))
-;; for fish in ansi-term
-(add-hook 'term-mode-hook 'toggle-truncate-lines)
-
-(use-package tramp
- :defer t
- :config
- (setq-default tramp-use-ssh-controlmaster-options nil ; Don't override SSH config.
- tramp-default-method "ssh") ; ssh is faster than scp and supports ports.
- (add-to-list 'tramp-remote-path "/run/current-system/sw/bin")
- (add-to-list 'tramp-remote-path "/etc/profiles/per-user/root/bin/")
- (add-to-list 'tramp-remote-path "/etc/profiles/per-user/vincent/bin/")
- (add-to-list 'tramp-remote-path "~/.nix-profile/bin")
- (add-to-list 'tramp-remote-path "~/bin")
- (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
-
-(defun generic-term-init ()
- (visual-line-mode -1)
- (setq-local global-hl-line-mode nil)
- (setq-local scroll-margin 0))
-
-(add-hook 'term-mode-hook #'generic-term-init)
-(add-hook 'shell-mode-hook #'generic-term-init)
-(add-hook 'eshell-mode-hook #'generic-term-init)
-
-(provide 'config-shells)
-;;; config-shells.el ends here
tools/emacs/config/config-vcs.el
@@ -1,395 +0,0 @@
-;;; config-vcs.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Version control configuration
-;;; Code:
-
-
-(defun vde/vc-browse-remote (&optional current-line)
- "Open the repository's remote URL in the browser.
-If CURRENT-LINE is non-nil, point to the current branch, file, and line.
-Otherwise, open the repository's main page."
- (interactive "P")
- (let* ((remote-url (string-trim (vc-git--run-command-string nil "config" "--get" "remote.origin.url")))
- (branch (string-trim (vc-git--run-command-string nil "rev-parse" "--abbrev-ref" "HEAD")))
- (file (string-trim (file-relative-name (buffer-file-name) (vc-root-dir))))
- (line (line-number-at-pos)))
- (message "Opening remote on browser: %s" remote-url)
- (if (and remote-url (string-match "\\(?:git@\\|https://\\)\\([^:/]+\\)[:/]\\(.+?\\)\\(?:\\.git\\)?$" remote-url))
- (let ((host (match-string 1 remote-url))
- (path (match-string 2 remote-url)))
- ;; Convert SSH URLs to HTTPS (e.g., git@github.com:user/repo.git -> https://github.com/user/repo)
- (when (string-prefix-p "git@" host)
- (setq host (replace-regexp-in-string "^git@" "" host)))
- ;; Construct the appropriate URL based on CURRENT-LINE
- (browse-url
- (if current-line
- (format "https://%s/%s/blob/%s/%s#L%d" host path branch file line)
- (format "https://%s/%s" host path))))
- (message "Could not determine repository URL"))))
-
-(global-set-key (kbd "C-x v B") 'vde/vc-browse-remote)
-
-(use-package vc
- :config
- (setq-default vc-find-revision-no-save t
- vc-follow-symlinks t)
- :bind (("C-x v f" . vc-log-incoming) ; git fetch
- ("C-x v F" . vc-update)
- ("C-x v d" . vc-diff)))
-
-(use-package vc-dir
- :config
- (defun vde/vc-dir-project ()
- "Unconditionally display `vc-diff' for the current project."
- (interactive)
- (vc-dir (vc-root-dir)))
-
- (defun vde/vc-dir-jump ()
- "Jump to present directory in a `vc-dir' buffer."
- (interactive)
- (vc-dir default-directory))
- :bind (("C-x v p" . vde/vc-dir-project)
- ("C-x v j" . vde/vc-dir-jump) ; similar to `dired-jump'
- :map vc-dir-mode-map
- ("f" . vc-log-incoming) ; replaces `vc-dir-find-file' (use RET)
- ("F" . vc-update) ; symmetric with P: `vc-push'
- ("d" . vc-diff) ; align with D: `vc-root-diff'
- ("k" . vc-dir-clean-files)))
-
-(use-package vc-git
- :config
- (setq vc-git-diff-switches "--patch-with-stat")
- (setq vc-git-print-log-follow t))
-
-(use-package vc-annotate
- :config
- (setq vc-annotate-display-mode 'scale)
- :bind (("C-x v a" . vc-annotate)
- :map vc-annotate-mode-map
- ("t" . vc-annotate-toggle-annotation-visibility)))
-
-(use-package ediff
- :commands (ediff ediff-files ediff-merge ediff3 ediff-files3 ediff-merge3)
- :config
- (setq ediff-window-setup-function 'ediff-setup-windows-plain)
- (setq ediff-split-window-function 'split-window-horizontally)
- (setq ediff-diff-options "-w")
- (add-hook 'ediff-after-quit-hook-internal 'winner-undo))
-
-(use-package diff
- :config
- (setq diff-default-read-only nil)
- (setq diff-advance-after-apply-hunk t)
- (setq diff-update-on-the-fly t)
- (setq diff-refine 'font-lock)
- (setq diff-font-lock-prettify nil)
- (setq diff-font-lock-syntax nil))
-
-(use-package magit-popup)
-
-(defun th/magit--with-difftastic (buffer command)
- "Run COMMAND with GIT_EXTERNAL_DIFF=difft then show result in BUFFER."
- (let ((process-environment
- (cons (concat "GIT_EXTERNAL_DIFF=difft --width="
- (number-to-string (frame-width)))
- process-environment)))
- ;; Clear the result buffer (we might regenerate a diff, e.g., for
- ;; the current changes in our working directory).
- (with-current-buffer buffer
- (setq buffer-read-only nil)
- (erase-buffer))
- ;; Now spawn a process calling the git COMMAND.
- (make-process
- :name (buffer-name buffer)
- :buffer buffer
- :command command
- ;; Don't query for running processes when emacs is quit.
- :noquery t
- ;; Show the result buffer once the process has finished.
- :sentinel (lambda (proc event)
- (when (eq (process-status proc) 'exit)
- (with-current-buffer (process-buffer proc)
- (goto-char (point-min))
- (ansi-color-apply-on-region (point-min) (point-max))
- (setq buffer-read-only t)
- (view-mode)
- (end-of-line)
- ;; difftastic diffs are usually 2-column side-by-side,
- ;; so ensure our window is wide enough.
- (let ((width (current-column)))
- (while (zerop (forward-line 1))
- (end-of-line)
- (setq width (max (current-column) width)))
- ;; Add column size of fringes
- (setq width (+ width
- (fringe-columns 'left)
- (fringe-columns 'right)))
- (goto-char (point-min))
- (pop-to-buffer
- (current-buffer)
- `(;; If the buffer is that wide that splitting the frame in
- ;; two side-by-side windows would result in less than
- ;; 80 columns left, ensure it's shown at the bottom.
- ,(when (> 80 (- (frame-width) width))
- #'display-buffer-at-bottom)
- (window-width
- . ,(min width (frame-width))))))))))))
-(defun th/magit-show-with-difftastic (rev)
- "Show the result of \"git show REV\" with GIT_EXTERNAL_DIFF=difft."
- (interactive
- (list (or
- ;; If REV is given, just use it.
- (when (boundp 'rev) rev)
- ;; If not invoked with prefix arg, try to guess the REV from
- ;; point's position.
- (and (not current-prefix-arg)
- (or (magit-thing-at-point 'git-revision t)
- (magit-branch-or-commit-at-point)))
- ;; Otherwise, query the user.
- (magit-read-branch-or-commit "Revision"))))
- (if (not rev)
- (error "No revision specified")
- (th/magit--with-difftastic
- (get-buffer-create (concat "*git show difftastic " rev "*"))
- (list "git" "--no-pager" "show" "--ext-diff" rev))))
-(defun th/magit-diff-with-difftastic (arg)
- "Show the result of \"git diff ARG\" with GIT_EXTERNAL_DIFF=difft."
- (interactive
- (list (or
- ;; If RANGE is given, just use it.
- (when (boundp 'range) range)
- ;; If prefix arg is given, query the user.
- (and current-prefix-arg
- (magit-diff-read-range-or-commit "Range"))
- ;; Otherwise, auto-guess based on position of point, e.g., based on
- ;; if we are in the Staged or Unstaged section.
- (pcase (magit-diff--dwim)
- ('unmerged (error "unmerged is not yet implemented"))
- ('unstaged nil)
- ('staged "--cached")
- (`(stash . ,value) (error "stash is not yet implemented"))
- (`(commit . ,value) (format "%s^..%s" value value))
- ((and range (pred stringp)) range)
- (_ (magit-diff-read-range-or-commit "Range/Commit"))))))
- (let ((name (concat "*git diff difftastic"
- (if arg (concat " " arg) "")
- "*")))
- (th/magit--with-difftastic
- (get-buffer-create name)
- `("git" "--no-pager" "diff" "--ext-diff" ,@(when arg (list arg))))))
-
-(use-package magit
- :unless noninteractive
- :commands (magit-status magit-clone magit-pull magit-blame magit-log-buffer-file magit-log)
- :bind (("C-c v c" . magit-commit)
- ("C-c v C" . magit-checkout)
- ("C-c v b" . magit-branch)
- ("C-c v d" . magit-dispatch)
- ("C-c v f" . magit-fetch)
- ("C-c v g" . magit-blame)
- ("C-c v l" . magit-log-buffer-file)
- ("C-c v L" . magit-log)
- ("C-c v p" . magit-pull)
- ("C-c v P" . magit-push)
- ("C-c v r" . magit-rebase)
- ("C-c v s" . magit-stage)
- ("C-c v v" . magit-status))
- :config
- (transient-define-prefix th/magit-aux-commands ()
- "My personal auxiliary magit commands."
- ["Auxiliary commands"
- ("d" "Difftastic Diff (dwim)" th/magit-diff-with-difftastic)
- ("s" "Difftastic Show" th/magit-show-with-difftastic)])
- (transient-append-suffix 'magit-dispatch "!"
- '("#" "My Magit Cmds" th/magit-aux-commands))
- (setq-default magit-save-repository-buffers 'dontask
- magit-refs-show-commit-count 'all
- magit-branch-prefer-remote-upstream '("main")
- magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1
- magit-bury-buffer-function #'magit-restore-window-configuration
- magit-refresh-status-buffer nil)
-
- (setq-default git-commit-summary-max-length 50
- git-commit-style-convention-checks
- '(non-empty-second-line
- overlong-summary-line))
-
-;; TODO: complete with list of issues (async ?)
-;; (transient-append-suffix 'git-commit-insert-trailer "t"
-;; '("i" "Issue numero" hello))
-;;
-;; (defun hello (foo)
-;; (interactive (list (completing-read "Foo number"
-;; '("foo" "bar" "baz"))))
-;; (message foo)
-;; (git-commit--insert-trailer "Hello" foo))
-
- ;; (magit-define-popup-option 'magit-rebase-popup
- ;; ?S "Sign using gpg" "--gpg-sign=" #'magit-read-gpg-secret-key)
- (magit-define-popup-switch 'magit-log-popup
- ?m "Omit merge commits" "--no-merges")
- ;; cargo-culted from https://github.com/magit/magit/issues/3717#issuecomment-734798341
- ;; valid gitlab options are defined in https://docs.gitlab.com/ee/user/project/push_options.html
- ;;
- ;; the second argument to transient-append-suffix is where to append
- ;; to, not sure what -u is, but this works
- (transient-append-suffix 'magit-push "-u"
- '(1 "=s" "Skip gitlab pipeline" "--push-option=ci.skip"))
- (transient-append-suffix 'magit-push "=s"
- '(1 "=m" "Create gitlab merge-request" "--push-option=merge_request.create"))
- (transient-append-suffix 'magit-push "=m"
- '(1 "=o" "Set push option" "--push-option=")) ;; Will prompt, can only set one extra
-
- (defun vde/fetch-and-rebase-from-upstream ()
- ""
- (interactive)
- (magit-fetch-all "--quiet")
- (magit-git-rebase (concat "upstream/" (vc-git--symbolic-ref (buffer-file-name))) "-sS"))
-
- ;; Hide "Recent Commits"
- (magit-add-section-hook 'magit-status-sections-hook
- 'magit-insert-modules
- 'magit-insert-unpushed-to-upstream
- 'magit-insert-unpulled-from-upstream)
- ;; No need for tag in the status header
- (remove-hook 'magit-status-sections-hook 'magit-insert-tags-header)
- (setq-default magit-module-sections-nested nil)
-
- ;; Show refined hunks during diffs
- (set-default 'magit-diff-refine-hunk t))
-
-(use-package gitconfig-mode
- :commands (gitconfig-mode)
- :mode (("/\\.gitconfig\\'" . gitconfig-mode)
- ("/\\.git/config\\'" . gitconfig-mode)
- ("/git/config\\'" . gitconfig-mode)
- ("/\\.gitmodules\\'" . gitconfig-mode)))
-
-(use-package gitignore-mode
- :commands (gitignore-mode)
- :mode (("/\\.gitignore\\'" . gitignore-mode)
- ("/\\.git/info/exclude\\'" . gitignore-mode)
- ("/git/ignore\\'" . gitignore-mode)))
-
-(use-package gitattributes-mode
- :commands (gitattributes-mode)
- :mode (("/\\.gitattributes" . gitattributes-mode)))
-
-(use-package dired-git-info
- :disabled
- :bind (:map dired-mode-map
- (")" . dired-git-info-mode))
- :defer 2)
-
-(defun git-blame-line ()
- "Runs `git blame` on the current line and
- adds the commit id to the kill ring"
- (interactive)
- (let* ((line-number (save-excursion
- (goto-char (point-at-bol))
- (+ 1 (count-lines 1 (point)))))
- (line-arg (format "%d,%d" line-number line-number))
- (commit-buf (generate-new-buffer "*git-blame-line-commit*")))
- (call-process "git" nil commit-buf nil
- "blame" (buffer-file-name) "-L" line-arg)
- (let* ((commit-id (with-current-buffer commit-buf
- (buffer-substring 1 9)))
- (log-buf (generate-new-buffer "*git-blame-line-log*")))
- (kill-new commit-id)
- (call-process "git" nil log-buf nil
- "log" "-1" "--pretty=%h %an %s" commit-id)
- (with-current-buffer log-buf
- (message "Line %d: %s" line-number (buffer-string)))
- (kill-buffer log-buf))
- (kill-buffer commit-buf)))
-
-(use-package diff-hl
- :hook (find-file . diff-hl-mode)
- :hook (prog-mode . diff-hl-mode)
- :hook (magit-post-refresh . diff-hl-magit-post-refresh)
- :bind
- (:map diff-hl-command-map
- ("n" . diff-hl-next-hunk)
- ("p" . diff-hl-previous-hunk)
- ("[" . nil)
- ("]" . nil)
- ("DEL" . diff-hl-revert-hunk)
- ("<delete>" . diff-hl-revert-hunk)
- ("SPC" . diff-hl-mark-hunk)
- :map vc-prefix-map
- ("n" . diff-hl-next-hunk)
- ("p" . diff-hl-previous-hunk)
- ("s" . diff-hl-stage-dwim)
- ("DEL" . diff-hl-revert-hunk)
- ("<delete>" . diff-hl-revert-hunk)
- ("SPC" . diff-hl-mark-hunk))
- :config
- (put 'diff-hl-inline-popup-hide
- 'repeat-map 'diff-hl-command-map))
-
-(use-package diff-hl-inline-popup
- :after (diff-hl))
-(use-package diff-hl-show-hunk
- :after (diff-hl))
-
-(use-package diff-hl-dired
- :after (diff-hl)
- :hook (dired-mode . diff-hl-dired-mode))
-
-(use-package consult-vc-modified-files
- :after consult
- :bind
- ("C-x v /" . consult-vc-modified-files))
-
-;; FIXME bind pr-review-submit-review
-(use-package pr-review
- :commands (pr-review pr-review-open pr-review-submit-review)
-;; :bind
-;; (("M-<SPC> p r" . pr-review-submit-review))
- :custom
- (pr-review-ghub-host "api.github.com")
- (pr-review-notification-include-read nil)
- (pr-review-notification-include-unsubscribed nil))
-
-(use-package pr-review-search
- :commands (pr-review-search pr-review-search-open pr-review-current-repository pr-review-current-repository-search)
-;; :bind
-;; (("M-<SPC> p a" . pr-review-current-repository)
-;; ;; FIXME understand why this one doesn't work
- ;; ("M-<SPC> p s" . pr-review-current-repository-search)))
- )
-
-(use-package pr-review-notification
- :commands (pr-review-notification)
-;; :bind
- ;; (("M-<SPC> p n" . pr-review-notification)))
- )
-
-(defun pr-review-current-repository-search (query)
- "Run pr-review-search on the current repository."
- (interactive "sSearch query: ")
- (pr-review-search (format "is:pr archived:false is:open repo:%s %s" (vde/gh-get-current-repo) query)))
-
-(defun pr-review-current-repository ()
- "Run pr-review-search on the current repository."
- (interactive)
- (pr-review-search (format "is:pr archived:false is:open repo:%s" (vde/gh-get-current-repo))))
-
-;; (pr-review-search "build is:pr archive:false is:open repo:tektoncd/pipeline")
-;; (pr-review-search "build")
-
-;; TODO this is relatively slow. Cache result or ?
-(defun vde/gh-get-current-repo ()
- "Get the current repository name using the `gh' command line."
- (unless (executable-find "gh")
- (error "GitHub CLI (gh) command not found"))
-
- (with-temp-buffer
- (let ((exit-code (call-process "gh" nil t nil "repo" "view" "--json" "owner,name" "--template" "{{.owner.login}}/{{.name}}")))
- (unless (= exit-code 0)
- (error "Failed to get repository info: gh command exited with code %d" exit-code))
- (string-trim (buffer-string)))))
-
-
-(provide 'config-vcs)
-;;; config-vcs.el ends here
tools/emacs/config/config-web.el
@@ -1,97 +0,0 @@
-;;; config-web.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Web related configuration, notably the built-in web browser.
-;;; Code:
-
-;; (use-package shr
-;; :config
-;; (setq shr-use-fonts nil)
-;; (setq shr-use-colors nil)
-;; (setq shr-bullet "• ")
-;; (setq shr-folding-mode t)
-;;
-;; (setq shr-max-image-proportion 0.7)
-;; (setq shr-image-animate nil)
-;; (setq shr-width (current-fill-column)))
-;;
-;; (use-package shr-tag-pre-highlight
-;; :after shr
-;; :config
-;; (add-to-list 'shr-external-rendering-functions
-;; '(pre . shr-tag-pre-highlight))
-;; (when (version< emacs-version "26")
-;; (with-eval-after-load 'eww
-;; (advice-add 'eww-display-html :around
-;; 'eww-display-html--override-shr-external-rendering-functions))))
-;;
-;; (use-package eww
-;; :commands (eww
-;; eww-browse-url
-;; eww-search-words
-;; eww-open-in-new-buffer
-;; eww-open-file
-;; vde/eww-visit-history)
-;; :config
-;; (setq eww-restore-desktop nil)
-;; (setq eww-desktop-remove-duplicates t)
-;; (setq eww-header-line-format "%u")
-;; (setq eww-search-prefix "https://duckduckgo.com/html/?q=")
-;; (setq url-privacy-level '(email agent cookies lastloc))
-;; (setq eww-download-directory "~/desktop/downloads/")
-;; (setq eww-suggest-uris
-;; '(eww-links-at-point
-;; thing-at-point-url-at-point))
-;; (setq eww-bookmarks-directory "~/.emacs.d/eww-bookmarks/")
-;; (setq eww-history-limit 150)
-;; (setq eww-use-external-browser-for-content-type
-;; "\\`\\(video/\\|audio/\\|application/pdf\\)")
-;; (setq eww-browse-url-new-window-is-tab nil)
-;; (setq eww-form-checkbox-selected-symbol "[X]")
-;; (setq eww-form-checkbox-symbol "[ ]")
-;;
-;; ;; eww-view-source
-;;
-;; (defvar vde/eww-mode-global-map
-;; (let ((map (make-sparse-keymap)))
-;; (define-key map "s" 'eww-search-words)
-;; (define-key map "o" 'eww-open-in-new-buffer)
-;; (define-key map "f" 'eww-open-file)
-;; map)
-;; "Key map to scope `eww' bindings for global usage.
-;; The idea is to bind this to a prefix sequence, so that its
-;; defined keys follow the pattern of <PREFIX> <KEY>.")
-;; :bind-keymap ("C-x w" . vde/eww-mode-global-map)
-;; :bind (:map eww-mode-map
-;; ("n" . next-line)
-;; ("p" . previous-line)
-;; ("f" . forward-char)
-;; ("b" . backward-char)
-;; ("B" . eww-back-url)
-;; ("N" . eww-next-url)
-;; ("P" . eww-previous-url)))
-
-(use-package browse-url
- :after eww
- :config
-
- ;; (defun browse-url-xdg-desktop-portal (url &rest args)
- ;; "Open URL via a portal backend."
- ;; (dbus-call-method :session
- ;; "org.freedesktop.portal.Desktop"
- ;; "/org/freedesktop/portal/desktop"
- ;; "org.freedesktop.portal.OpenURI"
- ;; "OpenURI"
- ;; "" url '(:array :signature "{sv}")))
- ;; (setopt browse-url-browser-function #'browse-url-xdg-desktop-portal)
- ;; (setq browse-url-browser-function #'eww-browse-url)
-
- ;; (setq browse-url-generic-program "google-chrome-stable")
- (setq browse-url-handlers '(("^https://gitlab.com.*" . browse-url-default-browser)
- ("^https://github.com.*" . browse-url-default-browser)
- ("^https://issues.redhat.com.*" . browse-url-default-browser)
- ("^https://.*redhat.com.*" . browse-url-default-browser)
- ("^https://docs.jboss.org.*" . browse-url-default-browser)
- (".*" . eww-browse-url))))
-
-(provide 'config-web)
-;;; config-web.el ends here
tools/emacs/config/config-windows.el
@@ -1,304 +0,0 @@
-;;; config-windows.el --- -*- lexical-binding: t; -*-
-;; Commentary:
-;;; Windows configuration
-;; Code:
-
-(setq switch-to-buffer-obey-display-actions t)
-
-(defun vde/window-delete-popup-frame (&rest _)
- "Kill selected selected frame if it has parameter `prot-window-popup-frame'.
-Use this function via a hook."
- (when (frame-parameter nil 'vde/window-popup-frame)
- (delete-frame)))
-
-(defun vde/save-desktop-no-ask ()
- "Save the desktop without asking questions by modifying the modtime."
- (interactive)
- (require 'desktop)
- (desktop--get-file-modtime)
- (desktop-save (concat desktop-dirname)))
-(defun vde/desktop-load ()
- "Load saved desktop"
- (interactive)
- (require 'desktop)
- (desktop-read desktop-dirname))
-
-(bind-key "C-c d s" #'vde/save-desktop-no-ask)
-(bind-key "C-c d l" #'vde/desktop-load)
-
-;; Winner
-(use-package winner
- :unless noninteractive
- :defer 5
- :config
- (winner-mode 1))
-;; -UseWinner
-
-(defun toggle-maximize-buffer ()
- "Maximize buffer"
- (interactive)
- (if (one-window-p)
- (winner-undo)
- (delete-other-windows)))
-
-;; UseAceWindow
-(use-package ace-window
- :unless noninteractive
- :commands (ace-window ace-swap-window)
- :bind (("C-x o" . ace-window)
- ("C-c w w" . ace-window)
- ("C-c w s" . ace-swap-window))
- :config
- (setq-default aw-keys '(?a ?u ?i ?e ?, ?c ?t ?r ?m)
- aw-scope 'frame
- aw-dispatch-always t
- aw-dispatch-alist
- '((?s aw-swap-window "Swap Windows")
- (?2 aw-split-window-vert "Split Window Vertically")
- (?3 aw-split-window-horz "Split Window Horizontally")
- (?? aw-show-dispatch-help))
- aw-minibuffer-flag t
- aw-ignore-current nil
- aw-display-mode-overlay t
- aw-background t))
-;; -UseAceWindow
-
-;; UseWindmove
-(use-package windmove
- :unless noninteractive
- :commands (windmove-left windmove-right windmove-down windmove-up)
- :custom
- (windmove-allow-all-windows t)
- :bind (("C-M-<up>" . windmove-up)
- ("C-M-<right>" . windmove-right)
- ("C-M-<down>" . windmove-down)
- ("C-M-<left>" . windmove-left)))
-;; -UseWindmove
-
-;; UseWindow
-(use-package window
- :unless noninteractive
- :commands (shrink-window-horizontally shrink-window enlarge-window-horizontally enlarge-window)
- :bind (("S-C-<left>" . shrink-window-horizontally)
- ("S-C-<right>" . enlarge-window-horizontally)
- ("S-C-<down>" . shrink-window)
- ("S-C-<up>" . enlarge-window)))
-;; -UseWindow
-
-;;;###autoload
-(defun prot-common-window-small-p ()
- "Return non-nil if window is small.
-Check if the `window-width' or `window-height' is less than
-`split-width-threshold' and `split-height-threshold',
-respectively."
- (or (and (numberp split-width-threshold)
- (< (window-total-width) split-width-threshold))
- (and (numberp split-height-threshold)
- (> (window-total-height) split-height-threshold))))
-
-(defun prot-common-three-or-more-windows-p (&optional frame)
- "Return non-nil if three or more windows occupy FRAME.
-If FRAME is non-nil, inspect the current frame."
- (>= (length (window-list frame :no-minibuffer)) 3))
-
-(defun prot-window--get-display-buffer-below-or-pop ()
- "Return list of functions for `prot-window-display-buffer-below-or-pop'."
- (list
- #'display-buffer-reuse-mode-window
- (if (or (prot-common-window-small-p)
- (prot-common-three-or-more-windows-p))
- #'display-buffer-below-selected
- #'display-buffer-pop-up-window)))
-
-(defun prot-window-display-buffer-below-or-pop (&rest args)
- "Display buffer below current window or pop a new window.
-The criterion for choosing to display the buffer below the
-current one is a non-nil return value for
-`prot-common-window-small-p'.
-
-Apply ARGS expected by the underlying `display-buffer' functions.
-
-This as the action function in a `display-buffer-alist' entry."
- (let ((functions (prot-window--get-display-buffer-below-or-pop)))
- (catch 'success
- (dolist (fn functions)
- (when (apply fn args)
- (throw 'success fn))))))
-
-(defvar prot-window-window-sizes
- '( :max-height (lambda () (floor (frame-height) 3))
- :min-height 10
- :max-width (lambda () (floor (frame-width) 4))
- :min-width 20)
- "Property list of maximum and minimum window sizes.
-The property keys are `:max-height', `:min-height', `:max-width',
-and `:min-width'. They all accept a value of either a
-number (integer or floating point) or a function.")
-
-(defun prot-window--get-window-size (key)
- "Extract the value of KEY from `prot-window-window-sizes'."
- (when-let ((value (plist-get prot-window-window-sizes key)))
- (cond
- ((functionp value)
- (funcall value))
- ((numberp value)
- value)
- (t
- (error "The value of `%s' is neither a number nor a function" key)))))
-
-(defun prot-window-select-fit-size (window &rest _)
- "Select WINDOW and resize it.
-The resize pertains to the maximum and minimum values for height
-and width, per `prot-window-window-sizes'.
-
-Use this as the `body-function' in a `display-buffer-alist' entry."
- (select-window window)
- (fit-window-to-buffer
- window
- (prot-window--get-window-size :max-height)
- (prot-window--get-window-size :min-height)
- (prot-window--get-window-size :max-width)
- (prot-window--get-window-size :min-width)))
-
-(defun prot-window-shell-or-term-p (buffer &rest _)
- "Check if BUFFER is a shell or terminal.
-This is a predicate function for `buffer-match-p', intended for
-use in `display-buffer-alist'."
- (when (string-match-p "\\*.*\\(e?shell\\|v?term\\).*" (buffer-name (get-buffer buffer)))
- (with-current-buffer buffer
- ;; REVIEW 2022-07-14: Is this robust?
- (and (not (derived-mode-p 'message-mode 'text-mode))
- (derived-mode-p 'eshell-mode 'shell-mode 'comint-mode 'fundamental-mode)))))
-
-;; (setq display-buffer-alist
-;; `(;; Default to no window
-;; ("\\`\\*Async Shell Command\\*\\'"
-;; (display-buffer-no-window))
-;; ("\\`\\*Warnings\\*\\'"
-;; (display-buffer-no-window)
-;; (allow-no-window . t))
-;; ("\\`\\*\\(Compile-Log\\|Org Links\\)\\*\\'"
-;; (display-buffer-no-window))
-;; ;; bottom side window
-;; ("\\*Org \\(Select\\|Note\\)\\*" ; the `org-capture' key selection and `org-add-log-note'
-;; (display-buffer-in-side-window)
-;; (dedicated . t)
-;; (side . bottom)
-;; (slot . 0)
-;; (window-parameters . ((mode-line-format . none))))
-;; ;; bottom buffer (NOT side window)
-;; ((or . ((derived-mode . flymake-diagnostics-buffer-mode)
-;; (derived-mode . flymake-project-diagnostics-mode)
-;; (derived-mode . messages-buffer-mode)
-;; (derived-mode . backtrace-mode)))
-;; (display-buffer-reuse-mode-window display-buffer-at-bottom)
-;; (window-height . 0.3)
-;; (dedicated . t)
-;; (preserve-size . (t . t)))
-;; ;; ((or . ((derived-mode . Man-mode)
-;; ;; (derived-mode . woman-mode)
-;; ;; "\\*\\(Man\\|woman\\).*"))
-;; ;; (display-buffer-reuse-mode-window display-buffer-below-selected)
-;; ;; (window-height . 0.3) ; note this is literal lines, not relative
-;; ;; (dedicated . t)
-;; ;; (preserve-size . (t . t)))
-;; ;; below current window
-;; ("\\(\\*Capture\\*\\|CAPTURE-.*\\)"
-;; (display-buffer-reuse-mode-window display-buffer-below-selected))
-;; ((derived-mode . reb-mode) ; M-x re-builder
-;; (display-buffer-reuse-mode-window display-buffer-below-selected)
-;; (window-height . 4) ; note this is literal lines, not relative
-;; (dedicated . t)
-;; (preserve-size . (t . t)))
-;; ((or . ((derived-mode . occur-mode)
-;; (derived-mode . grep-mode)
-;; (derived-mode . Buffer-menu-mode)
-;; (derived-mode . log-view-mode)
-;; (derived-mode . helpful-mode)
-;; (derived-mode . help-mode) ; See the hooks for `visual-line-mode'
-;; "\\*\\(|Buffer List\\|Occur\\|vc-change-log\\).*"
-;; prot-window-shell-or-term-p
-;; ,world-clock-buffer-name))
-;; (prot-window-display-buffer-below-or-pop)
-;; (dedicated . t)
-;; (body-function . prot-window-select-fit-size))
-;; ))
-
-(use-package auto-side-windows
- :custom
- ;; Top side window configurations
- (auto-side-windows-top-buffer-names
- '("^\\*Backtrace\\*$" "^\\*Compile-Log\\*$" "^COMMIT_EDITMSG$"
- "^\\*Org Src.*\\*" "^\\*Agenda Commands\\*$" "^\\*Org Agenda\\*$"
- "^\\*Quick Help\\*$" "^\\*Multiple Choice Help\\*$" "^\\*TeX Help\\*$"
- "^\\*TeX errors\\*$" "^\\*Warnings\\*$" "^\\*diff-hl\\*$"
- "^\\*Process List\\*$"))
- (auto-side-windows-top-buffer-modes
- '(flymake-diagnostics-buffer-mode locate-mode occur-mode grep-mode
- xref--xref-buffer-mode))
-
- ;; Bottom side window configurations
- (auto-side-windows-bottom-buffer-names
- '("^\\*.*eshell.*\\*$" "^\\*.*shell.*\\*$" "^\\*.*term.*\\*$"
- "^\\*.*vterm.*\\*$" "^\\*.*eat.*\\*$"))
- (auto-side-windows-bottom-buffer-modes
- '(eshell-mode shell-mode term-mode vterm-mode comint-mode compilation-mode debugger-mode))
-
- ;; Right side window configurations
- (auto-side-windows-right-buffer-names
- '("^\\*eldoc.*\\*$" "^\\*info\\*$" "^\\*Metahelp\\*$"))
- (auto-side-windows-right-buffer-modes
- '(Info-mode TeX-output-mode pdf-view-mode eldoc-mode help-mode
- helpful-mode shortdoc-mode))
-
- ;; Example: Custom parameters for top windows (e.g., fit height to buffer)
- ;; (auto-side-windows-top-alist '((window-height . fit-window-to-buffer)))
- ;; (auto-side-windows-top-window-parameters '((mode-line-format . ...))) ;; Adjust mode-line
-
- ;; Maximum number of side windows on the left, top, right and bottom
- (window-sides-slots '(1 1 1 1)) ; Example: Allow one window per side
-
- ;; Force left and right side windows to occupy full frame height
- (window-sides-vertical t)
- (window-combination-resize t)
-
- ;; Make changes to tab-/header- and mode-line-format persistent when toggleling windows visibility
- (window-persistent-parameters
- (append window-persistent-parameters
- '((tab-line-format . t)
- (header-line-format . t)
- (mode-line-format . t))))
- :bind ;; Example keybindings (adjust prefix as needed)
- (:map global-map ; Or your preferred keymap prefix
- ("C-c w t" . auto-side-windows-display-buffer-top)
- ("C-c w b" . auto-side-windows-display-buffer-bottom)
- ("C-c w l" . auto-side-windows-display-buffer-left)
- ("C-c w r" . auto-side-windows-display-buffer-right)
- ("C-c w T" . auto-side-windows-toggle-side-window)) ; Toggle current buffer in/out of side window
- :hook
- (after-init . auto-side-windows-mode)) ; Activate the mode
-
-(use-package popper
- :after auto-side-windows ; Ensure auto-side-windows variables are defined
- :hook (auto-side-windows-mode . popper-mode) ; Activate popper alongside
- :custom
- ;; Tell Popper to consider buffers matching auto-side-windows rules as popups
- (popper-reference-buffers
- (append auto-side-windows-top-buffer-names auto-side-windows-top-buffer-modes
- auto-side-windows-left-buffer-names auto-side-windows-left-buffer-modes
- auto-side-windows-right-buffer-names auto-side-windows-right-buffer-modes
- auto-side-windows-bottom-buffer-names auto-side-windows-bottom-buffer-modes))
- ;; Optional: Don't let Popper decide where to display, auto-side-windows handles that
- (popper-display-control nil) ; Or 'user if you prefer popper commands for display
- :config
- (require 'popper-echo)
- (popper-mode +1) ; Enable popper-mode
- (popper-echo-mode +1) ; Optional: echo area notifications
- :bind
- (("C-`" . popper-toggle)
- ("C-M-`" . popper-toggle-type)
- ("M-`" . popper-cycle)))
-;; TODO: Move display-buffer-alist here
-
-(provide 'config-windows)
-;;; config-windows ends here
tools/emacs/config/programming-config.el
@@ -1,227 +0,0 @@
-;;; programming-config.el --- -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Configuration files mode configuration
-;;; Code:
-
-(defconst src-dir "~/src/"
- "Where all my sources are.")
-(set-register ?s `(file . ,src-dir))
-
-(use-package symbol-overlay
- :custom
- (symbol-overlay-idle-time 0.2)
- :bind
- ("M-s s i" . symbol-overlay-put)
- ("M-N" . symbol-overlay-jump-next)
- ("M-P" . symbol-overlay-jump-prev)
- ("M-s s r" . symbol-overlay-rename)
- ("M-s s c" . symbol-overlay-remove-all)
- :hook
- (prog-mode . symbol-overlay-mode))
-
-(use-package devdocs
- :commands (devdocs-lookup devdocs-install vde/install-devdocs)
- :bind (("C-h D" . devdocs-lookup))
- :config
- (defun vde/install-devdocs ()
- "Install the devdocs I am using the most."
- (interactive)
- (dolist (docset '("bash"
- "c"
- "click"
- "cpp"
- "css"
- "elisp"
- "flask"
- "git"
- "gnu_make"
- "go"
- "html"
- "htmx"
- "http"
- "javascript"
- "jq"
- "jquery"
- "kubectl"
- "kubernetes"
- "lua~5.4"
- "nix"
- "python~3.13"
- "python~3.12"
- "requests"
- "sqlite"
- "terraform"
- "werkzeug"
- "zig"))
- (devdocs-install docset))))
-
-(use-package yaml-ts-mode
- :mode "\\.ya?ml\\'"
- :hook ((yaml-ts-mode . display-line-numbers-mode)
- (yaml-ts-mode . outline-minor-mode)
- (yaml-ts-mode . electric-pair-local-mode))
- :config
- (setq-local outline-regexp "^ *\\([A-Za-z0-9_-]*: *[>|]?$\\|-\\b\\)")
- (font-lock-add-keywords
- 'yaml-ts-mode
- '(("\\($(\\(workspaces\\|context\\|params\\)\.[^)]+)\\)" 1 'font-lock-constant-face prepend)
- ("kind:\s*\\(.*\\)\n" 1 'font-lock-keyword-face prepend))))
-
-;; TODO https://github.com/zkry/yaml-pro?tab=readme-ov-file#easy-movement-with-repeat-map
-;; FIXME it currently gets in the way…
-;; (use-package yaml-pro
-;; :after yaml-ts-mode
-;; :hook (yaml-ts-mode . yaml-pro-ts-mode))
-
-(use-package consult-flymake
- :after (consult)
- :bind
- ("M-s M-d" . consult-flymake)
- :config
- ;; (general-leader
- ;; "sd" #'(consult-flymake :which-key "Flymake diagnostics"))
- )
-
-(use-package flymake-yamllint
- :after yaml-ts-mode
- :hook
- (yaml-ts-mode . flymake-yamllint-setup))
-
-(use-package conf-mode
- :mode ("\\.to?ml\\'" . conf-toml-mode))
-
-(use-package adoc-mode
- :mode ("\\.adoc\\'" . conf-toml-mode))
-
-(defun repeatize (keymap)
- "Add `repeat-mode' support to a KEYMAP."
- (map-keymap
- (lambda (_key cmd)
- (when (symbolp cmd)
- (put cmd 'repeat-map keymap)))
- (symbol-value keymap)))
-
-(defvar flymake-repeat-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "n") 'flymake-goto-next-error)
- (define-key map (kbd "p") 'flymake-goto-prev-error)
- (define-key map (kbd "f") 'attrap-flymake)
- (define-key map (kbd "M-n") 'flymake-goto-next-error)
- (define-key map (kbd "M-p") 'flymake-goto-prev-error)
- map))
-
-(use-package flymake
- :defer t
- :bind
- (("C-c f e" . flymake-show-project-diagnostics))
- (:map flymake-mode-map
- ("M-n" . flymake-goto-next-error)
- ("M-p" . flymake-goto-prev-error))
- (
- :map flymake-diagnostics-buffer-mode-map
- ("p" .
- (lambda()(interactive)
- (previous-line)
- (save-excursion
- (flymake-show-diagnostic(point)))))
- ("n" .
- (lambda()(interactive)
- (next-line)
- (save-excursion
- (flymake-show-diagnostic(point)))))
- (
- :map flymake-project-diagnostics-mode-map
- ("p" .
- (lambda()(interactive)
- (previous-line)
- (save-excursion
- (flymake-show-diagnostic(point)))))
- ("n" .
- (lambda()(interactive)
- (next-line)
- (save-excursion
- (flymake-show-diagnostic(point)))))))
- :config
- (repeatize 'flymake-repeat-map)
- :hook
- ;; (prog-mode . flyspell-prog-mode) rebind flyspell-auto-correct-previous-word
- (prog-mode . flymake-mode))
-
-(defun my-gotest-get-current-test()
- "Get the current test name, if we have a subtest (starting with name) then use it."
- (interactive)
- (require 'which-func)
- (let ((subtest (when-let* ((subtest
- (progn
- (save-excursion
- (goto-char (line-beginning-position))
- (re-search-forward "name:[[:blank:]]*\"\\([^\"]*\\)\"" (line-end-position) t)))))
- (if subtest
- (shell-quote-argument (replace-regexp-in-string " " "_" (match-string-no-properties 1))))))
- (gotest (when-let* ((test-name (which-function)))
- (if test-name test-name
- (error "No test selected")))))
- (concat (format "^%s%s$" gotest (if subtest (concat "/" subtest) "")))))
-
-(use-package dape
- :commands (my-dape-go-test-at-point)
- :after go-ts-mode
- :bind
- (:map go-ts-mode-map
- ("<f5>" . (lambda()(interactive)
- (if (dape--live-connections)
- (call-interactively 'dape-continue)
- (call-interactively 'dape))))
- ("S-<f5>" . dape-stop)
- ("C-S-<f5>" . dape-restart)
- ("<f9>" . dape-breakpoint-toggle)
- ("<f10>" . dape-next)
- ("<f11>" . dape-step-in)
- ("S-<f11>" . dape-step-out))
- :hook
- (go-ts-mode . (lambda()
- (interactive)
- (if (string-suffix-p "_test.go" (buffer-name))
- (setq-local dape-command '(delve-unit-test)))))
- :config
- (defun my-dape-go-test-at-point ()
- (interactive)
- (dape (dape--config-eval-1
- `(modes (go-mode go-ts-mode)
- ensure dape-ensure-command
- fn dape-config-autoport
- command "dlv"
- command-args ("dap" "--listen" "127.0.0.1::autoport")
- command-cwd dape-cwd-fn
- port :autoport
- :type "debug"
- :request "launch"
- :mode "test"
- :cwd dape-cwd-fn
- :program (lambda () (concat "./" (file-relative-name default-directory (funcall dape-cwd-fn))))
- :args (lambda ()
- (when-let* ((test-name (my-gotest-get-current-test)))
- (if test-name `["-test.run" ,test-name]
- (error "No test selected")))))))))
-
-(defconst markdown-regex-italic
- "\\(?:^\\|[^\\]\\)\\(?1:\\(?2:[_]\\)\\(?3:[^ \n\t\\]\\|[^ \n\t]\\(?:.\\|\n[^\n]\\)[^\\ ]\\)\\(?4:\\2\\)\\)")
-;; and/or
-(defconst markdown-regex-gfm-italic
- "\\(?:^\\|[^\\]\\)\\(?1:\\(?2:[_]\\)\\(?3:[^ \\]\\2\\|[^ ]\\(?:.\\|\n[^\n]\\)\\)\\(?4:\\2\\)\\)")
-
-(use-package markdown-mode
- :commands (markdown-mode gfm-mode)
- :mode (("README\\.md\\'" . gfm-mode)
- ("\\.md\\'" . markdown-mode)
- ("\\.markdown\\'" . markdown-mode))
- :hook ((markdown-mode . visual-line-mode)
- (gfm-mode . visual-line-mode)))
-
-(use-package orgalist
- :commands (orgalist-mode)
- :hook ((markdown-mode . orgalist-mode)
- (gfm-mode . orgalist-mode)))
-
-(provide 'programming-config)
-;;; programming-config.el ends here
tools/emacs/config/programming-containers.el
@@ -1,31 +0,0 @@
-;;; programming-containers.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Containers configuration
-;;; Code:
-(use-package dockerfile-mode
- :mode ("Dockerfile\\'" . dockerfile-mode))
-
-;; I have a bunch of different 'profiles' for kubernetes by different cluster so
-;; i don't mess between things
-;; This allow me to set the KUBECONFIG variable between those easily
-;; TODO: add the current profile in modeline
-(defun my-switch-kubeconfig-env (&optional kubeconfig)
- "Set KUBECONFIG environment variable for the current session"
- (interactive
- (list
- (completing-read
- "Kubeconfig: "
- (mapcar
- (lambda (x)
- (replace-regexp-in-string
- "^config\." ""
- (file-name-nondirectory(directory-file-name x))))
- (directory-files-recursively
- (expand-file-name "~/.kube") "^config\.")) nil t )))
- (setq kubeconfig (expand-file-name (format "~/.kube/config.%s" kubeconfig)))
- (if (file-exists-p kubeconfig)
- (setenv "KUBECONFIG" kubeconfig)
- (error "Cannot find kubeconfig: %s" kubeconfig)))
-
-(provide 'programming-containers)
-;;; programming-containers.el ends here
tools/emacs/config/programming-cue.el
@@ -1,9 +0,0 @@
-;;; programming-cue.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Cue "data" language configuration
-;;; Code:
-(use-package cue-mode
- :commands (cue-mode)
- :mode "\\.cue$")
-
-(provide 'programming-cue)
tools/emacs/config/programming-eglot.el
@@ -1,49 +0,0 @@
-;;; programming-eglot.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Eglot configuration
-;;; Code:
-(use-package eglot
- :bind
- (:map eglot-mode-map
- ("C-c e a" . eglot-code-actions)
- ("C-c e r" . eglot-reconnect)
- ("<f2>" . eglot-rename)
- ("C-c e ?" . eldoc-print-current-symbol-info))
- :config
- (add-to-list 'eglot-ignored-server-capabilities :documentHighlightProvider)
- (add-to-list 'eglot-server-programs `(json-mode "vscode-json-language-server" "--stdio"))
- (add-to-list 'eglot-server-programs '(nix-mode . ("nil")))
- (setq-default eglot-workspace-configuration
- '(:gopls (:usePlaceholders t)))
- (setq-default
- eglot-workspace-configuration
- '((:gopls . ((gofumpt . t)))))
- :hook
- (before-save . gofmt-before-save)
- (before-save . eglot-format-buffer)
- (nix-mode . eglot-ensure)
- (nix-ts-mode . eglot-ensure)
- (rust-mode . eglot-ensure)
- (rust-ts-mode . eglot-ensure)
- (sh-script-mode . eglot-ensure)
- (python-mode . eglot-ensure)
- (json-mode . eglot-ensure)
- (yaml-mode . eglot-ensure)
- (c-mode . eglot-ensure)
- (cc-mode . eglot-ensure)
- (go-mode . eglot-ensure)
- (go-ts-mode . eglot-ensure)
- (js-mode . eglot-ensure)
- (js2-mode . eglot-ensure)
- (typescript-mode . eglot-ensure)
- (typescript-ts-mode . eglot-ensure))
-
-(use-package eldoc-box
- :hook
- (eglot-managed-mode . eldoc-box-hover-mode)
- :custom
- (eldoc-box-max-pixel-width 1024))
-
-
-(provide 'programming-eglot)
-;;; programming-eglot.el ends here
tools/emacs/config/programming-elisp.el
@@ -1,9 +0,0 @@
-;;; programming-elisp.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Emacs lisp programming language configuration
-;;; Code:
-(use-package smartparens
- :hook ((emacs-lisp-mode . smartparens-mode)))
-
-(provide 'programming-elisp)
-;;; programming-elisp.el ends here
tools/emacs/config/programming-go.el
@@ -1,107 +0,0 @@
-;;; programming-go.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Go programming language configuration
-;;; Code:
-
-(declare-function project-root "project")
-(declare-function project-current "project")
-(declare-function vde-project--project-root-or-default-directory "proj-func")
-(declare-function go-test--get-current-file-tests "gotest")
-
-(use-package gotest
- :commands (my-gotest-maybe-ts-run go-test--get-current-test-info go-test--get-current-file-tests)
- :after go-ts-mode
- :custom
- (go-test-verbose t)
- :hook
- (go-test-mode . (lambda () (pop-to-buffer (get-buffer "*Go Test*"))))
- (go-mode . (lambda ()(interactive) (setq go-run-args "-v")))
- (go-ts-mode . (lambda ()(interactive) (setq go-run-args "-v")))
- :config
- (defun my-go-test-current-project()
- (interactive)
- (let ((default-directory (project-root (project-current t))))
- (go-test-current-project)))
- (defun my-gotest-maybe-ts-run()
- (interactive)
- (let ((testrunname)
- (gotest (cadr (go-test--get-current-test-info))))
- (save-excursion
- (goto-char (line-beginning-position))
- (re-search-forward "name:[[:blank:]]*\"\\([^\"]*\\)\"" (line-end-position) t))
- (setq testrunname (match-string-no-properties 1))
- (if testrunname
- (setq gotest (format "%s/%s" gotest (shell-quote-argument
- (replace-regexp-in-string " " "_" testrunname)))))
- (go-test--go-test (concat "-run " gotest "\\$ .")))))
-
-(use-package gotest-ts
- :bind (("C-c C-t t" . gotest-ts-run-dwim)))
-
-(defun go-mode-p ()
- "Return non-nil value when the major mode is `go-mode' or `go-ts-mode'."
- (memq major-mode '(go-ts-mode go-mode)))
-
-;; TODO (defun run-command-recipe-ko ())
-
-(defun run-command-recipe-go ()
- "Go `run-command' recipes."
- (when (buffer-file-name) ;; no buffer-file-name means virtual buffer (dired, …)
-
- (let* ((dir (vde-project--project-root-or-default-directory))
- (package (file-name-directory (concat "./" (file-relative-name (buffer-file-name) dir)))))
- (when (or (go-mode-p) (file-exists-p (expand-file-name "go.mod" dir)))
- (append
- (and (buffer-file-name) (go-mode-p)
- (list
- (list :command-name "gofumpt"
- :command-line (concat "gofumpt -extra -w " (buffer-file-name))
- :working-dir dir
- :display "gofumpt (reformat) file")
- (list :command-name "go-fmt"
- :command-line (concat "go fmt " (buffer-file-name))
- :working-dir dir
- :display "gofmt (reformat) file")
- (list :command-name "go-run"
- :command-line (concat "go run " (buffer-file-name))
- :working-dir dir
- :display "Compile, execute file")))
- (and (string-suffix-p "_test.go" buffer-file-name) (go-mode-p)
- (list
- (let ((runArgs (go-test--get-current-file-tests)))
- ;; go test current test
- ;; go test current file
- (list :command-name "go-test-file"
- :command-line (concat "go test -v " package " -run " (shell-quote-argument runArgs))
- :working-dir dir
- :display (concat "Test file " (concat "./"(file-relative-name (buffer-file-name) dir)))
- :runner 'run-command-runner-compile)
- )))
- ;; TODO: handle test file as well
- (list
- (list :command-name "go-build-project"
- :command-line "go build -v ./..."
- :working-dir dir
- :display "compile package and dependencies"
- :runner 'run-command-runner-compile)
- (list :command-name "go-test-project"
- :command-line "go test ./..."
- :working-dir dir
- :display "test all"
- :runner 'run-command-runner-compile)
- (list :command-name "go-test-package"
- :command-line (concat "go test -v " package)
- :working-dir dir
- :display (concat "Test package " package)
- :runner 'run-command-runner-compile)))))))
-
-(with-eval-after-load 'run-command
- (add-to-list 'run-command-recipes 'run-command-recipe-go))
-
-(use-package go-ts-mode
- :mode (("\\.go$" . go-ts-mode)
- ("\\.go" . go-ts-mode)
- ("\\.go\\'" . go-ts-mode)))
-
-(provide 'programming-go)
-;;; programming-go.el ends here
tools/emacs/config/programming-js.el
@@ -1,24 +0,0 @@
-;;; programming-js.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Javascript and Typescript programming language configuration
-;;; Code:
-
-(use-package js2-mode
- :hook
- (js2-mode . js-ts-mode-hook))
-
-(use-package typescript-mode
- :hook
- (typescript-mode . typescript-ts-mode-hook))
-
-(use-package typescript-ts-mode
- :mode (("\\.ts\\'" . typescript-ts-mode)
- ("\\.tsx\\'" . tsx-ts-mode)))
-
-(use-package json-mode
- :mode (("\\.json\\'" . json-ts-mode))
- :hook
- (json-mode . json-ts-mode-hook))
-
-(provide 'programming-js)
-;;; programming-js.el ends here
tools/emacs/config/programming-nix.el
@@ -1,28 +0,0 @@
-;;; programming-nix.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Nix configuration
-;;; Code:
-(use-package nix-ts-mode
- :if (executable-find "nix")
- :mode ("\\.nix\\'" "\\.nix.in\\'"))
-
-(use-package nix-drv-mode
- :if (executable-find "nix")
- :after nix-mode
- :mode "\\.drv\\'")
-
-(use-package nix-shell
- :if (executable-find "nix")
- :after nix-mode
- :commands (nix-shell-unpack nix-shell-configure nix-shell-build))
-
-(use-package nixpkgs-fmt
- :if (executable-find "nix")
- :after nix-ts-mode
- ;; :custom
- ;; (nixpkgs-fmt-command "nixfmt")
- :config
- (add-hook 'nix-ts-mode-hook 'nixpkgs-fmt-on-save-mode))
-
-(provide 'programming-nix)
-;;; programming-nix.el ends here
tools/emacs/config/programming-treesitter.el
@@ -1,22 +0,0 @@
-;;; programming-treesitter.el --- -*- lexical-binding: t; -*-
-;;; Commentary:
-;;; Treesitter configuration
-;;; Code:
-
-
-(use-package indent-bars
- :if (eq system-type 'gnu/linux)
- :hook
- (python-mode . indent-bars-mode)
- (yaml-ts-mode . indent-bars-mode)
- :config
- (require 'indent-bars-ts)
- :custom
- (indent-bars-no-descend-lists t)
- (indent-bars-treesit-support t)
- (indent-bars-treesit-ignore-blank-lines-types '("module"))
- (indent-bars-treesit-scope '((python function_definition class_definition for_statement
- if_statement with_statement while_statement))))
-
-(provide 'programming-treesitter)
-;;; programming-treesitter.el ends here
tools/emacs/config/programming-web.el
@@ -1,41 +0,0 @@
-;;; programming-web.el --- -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Programming the Web related configuration
-;;; Code:
-
-(use-package web-mode
- :commands (web-mode)
- :mode
- ("\\.html\\'" . web-mode)
- ("\\.phtml\\'" . web-mode)
- ("\\.[agj]sp\\'" . web-mode)
- ("\\.as[cp]x\\'" . web-mode)
- ("\\.erb\\'" . web-mode)
- ("\\.mustache\\'" . web-mode)
- ("\\.djhtml\\'" . web-mode)
- ("\\.jsp\\'" . web-mode)
- ("\\.eex\\'" . web-mode)
- ("\\.tsx\\'" . web-mode)
- :config
- (setq web-mode-attr-indent-offset 2)
- (setq web-mode-code-indent-offset 2)
- (setq web-mode-css-indent-offset 2)
- (setq web-mode-indent-style 2)
- (setq web-mode-markup-indent-offset 2)
- (setq web-mode-sql-indent-offset 2)
- (eval-after-load 'smartparens
- (lambda ()
- (setq web-mode-enable-auto-pairing nil)
- (sp-with-modes '(web-mode)
- (sp-local-pair "%" "%"
- :unless '(sp-in-string-p)
- :post-handlers '(((lambda (&rest _ignored)
- (just-one-space)
- (save-excursion (insert " ")))
- "SPC" "=" "#")))
- (sp-local-tag "%" "<% " " %>")
- (sp-local-tag "=" "<%= " " %>")
- (sp-local-tag "#" "<%# " " %>")))))
-
-(provide 'programming-web)
-;;; programming-web.el ends here
tools/emacs/eshell/lastdir
@@ -1,8 +0,0 @@
-~
-/ssh:aomi.home:/home/vincent
-/ssh:aomi.home:/home/vincent/src
-/ssh:aomi.home:/home/vincent/src/osp
-/ssh:aomi.home:/home/vincent/src/osp/p12n
-/ssh:aomi.home:/home/vincent/src/osp/p12n/p12n
-/ssh:aomi.home:/home/vincent/src/osp/p12n/p12n/versions/1.9
-/ssh:aomi.home:/home/vincent/src/osp/p12n/p12n
tools/emacs/etc/eshell/aliases
@@ -1,3 +0,0 @@
-alias l exa -lah $*
-alias ll exa -l $*
-alias ls exa $*
tools/emacs/etc/orgmode/meeting-notes.org
@@ -1,20 +0,0 @@
-* %^{meeting}
-
-- Actions ::
- #+BEGIN: columnview :id local :match "/TODO|DONE" :format "%ITEM(What) %TAGS(Who) %DEADLINE(When) %TODO(State)"
- | What | Who | When | State |
- |-------------------------------------+------------+------+-------|
- #+END:
-- Decisions ::
- #+BEGIN: columnview :id local :match "Decision" :format "%ITEM(Decisions)"
- | Decisions |
- |-----------|
- #+END:
-
-** Present at meeting
- - [ ]
-** Agenda
-- %?
-** Notes
-- Use =:Decision:= tag for decision
-- Use entry with =TODO= (or =DONE=) for actions
tools/emacs/etc/orgmode/weekly.org
@@ -1,20 +0,0 @@
-** %(format-time-string org-journal-time-format) weekly review :weekly:review:
-%U
-
-- [ ] review [[file:../projects/inbox.org][~inbox.org~]]
- Clean the file by either
- - refiling it to ~incubate.org~
- - removing it / archiving it
-- [ ] review [[file:../projects/incubate.org][~incubate.org~]]
- - Is something worth becoming a project
- - Is something not worth thinking about anymore ?
-- [ ] empty mail inbox (and create task if needed)
- - [ ] work
- - [ ] perso
-- [ ] Review next week ~F12 n w f~
-- [ ] review ~org-mode~ workflow
- - *what works, what doesn't ?*
- - *is there task / stuck projects ?*
- - *enhancement possible ?*
-- Additional /notes/:
- + …
tools/emacs/etc/transient/levels.el
@@ -1,4 +0,0 @@
-((magit-commit
- (magit:--gpg-sign . 3))
- (magit-rebase
- (magit:--gpg-sign . 3)))
tools/emacs/etc/transient/values.el
@@ -1,4 +0,0 @@
-((magit-commit "--signoff")
- (magit-fetch "--prune")
- (magit-submodule "--recursive" "--rebase" "--remote")
- (magit-tag "--sign"))
tools/emacs/etc/yasnippet/snippets/c++-mode/.yas-parents
@@ -1,1 +0,0 @@
-cc-mode
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/c-mode/.yas-parents
@@ -1,1 +0,0 @@
-cc-mode
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/cc-mode/add
@@ -1,4 +0,0 @@
-#name : /*** START TI ADD ***/ ... /*** END TI ADD ***/
-# --
-/*** START TI ADD ***/
-$0/*** END TI ADD ***/
tools/emacs/etc/yasnippet/snippets/cc-mode/addif
@@ -1,7 +0,0 @@
-#name : START TI ADD + #if OPENCL
-# --
-/*** START TI ADD ***/
-#if OPENCL_EXTENSIONS_SUPPORTED
-$0
-#endif /* OPENCL_EXTENSIONS_SUPPORTED */
-/*** END TI ADD ***/
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/cc-mode/class
@@ -1,71 +0,0 @@
-#name : class ... { ... }
-# --
-/**
- * @brief Summary
- *
- * Description.
- */
-class $1
-{
- $0
-
-public:
- /** @name Construction and Destruction
- @{ */
-
- $1() noexcept? {
- TRACE_CTOR($1, "");
- }
-
-#if defined(DEBUG_MODE)
- virtual? ~$1() {
- try {
- TRACE_DTOR($1);
- }
- catch (...) {
- std::terminate();
- }
- }
-#else
- ~$1() = default|delete;
-#endif
-
- /*@}*/
-
- /** @name Assignment, Copy and Move
- @{*/
-
-#if defined(DEBUG_MODE)
- $1(const $1& rhs) noexcept? {
- TRACE_CTOR($1, "copy");
- *this = rhs;
- }
-#else
- $1(const $1&) = default|delete;
-#endif
-
- $1& operator=(const $1&) = default|delete;
- $1& operator=(const $1& rhs) noexcept? {
- //if (this != &rhs) {
- //}
- return *this;
- }
-
-#if defined(DEBUG_MODE)
- $1($1&&r rhs) noexcept? {
- TRACE_CTOR($1, "move");
- *this = rhs;
- }
-#else
- $1($1&&r) = default|delete;
-#endif
-
- $1& operator=($1&&r) = default|delete;
- $1& operator=($1&&r rhs) noexcept? {
- //if (this != &rhs) {
- //}
- return *this;
- }
-
- /*@}*/
-}; // class $1
tools/emacs/etc/yasnippet/snippets/cc-mode/com
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: TI comment
-# --
-/*------------------------------------------------------------*/
-/* $0 */
-/*------------------------------------------------------------*/
tools/emacs/etc/yasnippet/snippets/cc-mode/fopen
@@ -1,3 +0,0 @@
-#name : FILE *fp = fopen(..., ...);
-# --
-FILE *${fp} = fopen(${"file"}, "${r}");
tools/emacs/etc/yasnippet/snippets/cc-mode/inc
@@ -1,3 +0,0 @@
-#name : #include "..."
-# --
-#include "$1"
tools/emacs/etc/yasnippet/snippets/cc-mode/inc.1
@@ -1,3 +0,0 @@
-#name : #include <...>
-# --
-#include <$1>
tools/emacs/etc/yasnippet/snippets/cc-mode/main
@@ -1,7 +0,0 @@
-#name: int main(argc, argv) { ... }
-# --
-int main(int argc, char *argv[])
-{
- $0
- return 0;
-}
tools/emacs/etc/yasnippet/snippets/cc-mode/misra
@@ -1,14 +0,0 @@
-#name : MISRA-C:2004 rule implementation
-# --
-/*** START TI ADD ***/
-#if MISRA_C_2004_VALIDATION
- if (check_misra_c_2004)
- {
- /*----------------------------------------------------------------*/
- /* MISRA-C:2004 - Rule ${1:Rule} (${2:required}) */
- /* ${3:Description} $0*/
- /*----------------------------------------------------------------*/
- diagnostic(misra_${2:required}_severity, ec_misra_c_2004_$1);
- } /* if */
-#endif /* MISRA_C_2004_VALIDATION */
-/*** END TI ADD ***/
tools/emacs/etc/yasnippet/snippets/cc-mode/ns
@@ -1,5 +0,0 @@
-#name : namespace ...
-# --
-namespace $1 {
- $0
-}
tools/emacs/etc/yasnippet/snippets/cc-mode/once
@@ -1,8 +0,0 @@
-#name : #ifndef XXX; #define XXX; #endif
-# --
-#ifndef ${1:_`(upcase (file-name-nondirectory (file-name-sans-extension (buffer-file-name))))`_H_}
-#define $1
-
-$0
-
-#endif /* $1 */
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/cc-mode/tfunc
@@ -1,11 +0,0 @@
-#name : Texas Instruments function
-# --
-/******************************************************************************/
-/* jww (`(format-time-string "%Y-%m-%d")`): NYI */
-/******************************************************************************/
-a_boolean $1($2)
-{
- a_boolean result = FALSE;
- $0
- return result;
-} /* $1 */
tools/emacs/etc/yasnippet/snippets/cc-mode/using
@@ -1,4 +0,0 @@
-#name : using namespace ...
-# --
-using namespace ${std};
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/emacs-lisp-mode/hdr
@@ -1,36 +0,0 @@
-;;; `(file-name-sans-extension (file-name-nondirectory buffer-file-name))` --- $1
-
-;; Copyright (C) `(format-time-string "%Y")` `user-full-name`
-
-;; Author: `user-full-name` <`user-mail-address`>
-;; Created: `(format-time-string "%d %b %Y")`
-;; Version: 1.0
-;; Keywords: $2
-;; X-URL: https://github.com/jwiegley/${3:`(file-name-sans-extension (file-name-nondirectory buffer-file-name))`}
-
-;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;; $0
-
-(defgroup `(file-name-sans-extension (file-name-nondirectory buffer-file-name))` nil
- "$1"
- :group '$4)
-
-(provide '`(file-name-sans-extension (file-name-nondirectory buffer-file-name))`)
-
-;;; `(file-name-nondirectory buffer-file-name)` ends here
tools/emacs/etc/yasnippet/snippets/emacs-lisp-mode/test
@@ -1,2 +0,0 @@
-(ert-deftest $1 ()
- (should (equal $0)))
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/fundamental-mode/date
@@ -1,3 +0,0 @@
-#name : (current date)
-# --
-`(format-time-string "%Y-%m-%d")`
tools/emacs/etc/yasnippet/snippets/fundamental-mode/mail
@@ -1,3 +0,0 @@
-#name : (user's email)
-# --
-`user-mail-address`
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/fundamental-mode/time
@@ -1,3 +0,0 @@
-#name : (current time)
-# --
-`(current-time-string)`
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/coloneq
@@ -1,5 +0,0 @@
-# -*- mode: snippet -*-
-# name: ... := ...
-# key: :=
-# --
-${1:x} := ${2:`%`}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/f
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: func
-# --
-func ${1:fun}($2) {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/fm
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: func (target) name(args) (results) { ... }
-# --
-func (${1:target}) ${2:name}(${3:args}) (${4:results}) {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/for
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: for ... { ... }
-# --
-for $1 {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/fore
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: for key, value := range ... { ... }
-# --
-for ${1:key}, ${2:value} := range ${3:target} {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/foreach
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: for key, value := range ... { ... }
-# --
-for ${1:key}, ${2:value} := range ${3:target} {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/fori
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: for i := 0; i < n; i++ { ... }
-# --
-for ${1:i} := ${2:0}; $1 < ${3:10}; $1++ {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/forw
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name : for ... { ... }
-# --
-for $1 {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/func
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: func
-# --
-func ${1:fun}($2) {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/iferr
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: if err != nil { ... }
-# --
-if err != nil {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/ifunc
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: func (...) ... { ... }
-# --
-func ($1) $2 {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/imp
@@ -1,4 +0,0 @@
-# -*- mode: snippet -*-
-# name: import
-# --
-import ${1:package}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/import
@@ -1,4 +0,0 @@
-# -*- mode: snippet -*-
-# name: import
-# --
-import ${1:package}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/main
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: func main() { ... }
-# --
-func main() {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/map
@@ -1,4 +0,0 @@
-# -*- mode: snippet -*-
-# name: map
-# --
-map[${1:KeyType}]${2:ValueType}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/method
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: func (target) name(args) (results) { ... }
-# --
-func (${1:target}) ${2:name}(${3:args}) (${4:results}) {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/package
@@ -1,4 +0,0 @@
-# -*- mode: snippet -*-
-# name: package
-# --
-package ${1:`(car (last (split-string (file-name-directory buffer-file-name) "/") 2))`}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/pkg
@@ -1,4 +0,0 @@
-# -*- mode: snippet -*-
-# name: package
-# --
-package ${1:`(car (last (split-string (file-name-directory buffer-file-name) "/") 2))`}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/pr
@@ -1,4 +0,0 @@
-# -*- mode: snippet -*-
-# name: printf
-# --
-fmt.Printf("$1\n"${2:, ${3:str}})
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/printf
@@ -1,4 +0,0 @@
-# -*- mode: snippet -*-
-# name: printf
-# --
-fmt.Printf("$1\n"${2:, ${3:str}})
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/struct
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: type ... struct { ... }
-# --
-type $1 struct {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/switch
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# name: switch
-# key: switch
-# --
-switch {
- case ${1:cond}:
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/test
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: func Test...() { ... }
-# --
-func Test${1:Name}(${2:t *testing.T}) {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/go-mode/while
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name : for ... { ... }
-# --
-for $1 {
- `%`$0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/break
@@ -1,1 +0,0 @@
-break _ZL12diag_message13an_error_codeP17a_source_position17an_error_severity30a_diagnostic_category_kind_tag
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/cd
@@ -1,1 +0,0 @@
-cd ~/Contracts/TI/bugslayer/cl_
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/const
@@ -1,1 +0,0 @@
-(void)_Z11db_constantP10a_constant($0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/cree
@@ -1,1 +0,0 @@
-run --gcc -DUSE_ASCII -I/usr/local/opt/libffi/lib/libffi-3.0.11/include --llvm_file_name - ~/src/cree/test/wc.c
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/expr
@@ -1,1 +0,0 @@
-(void)_Z13db_expressionP12an_expr_node($0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/iar
@@ -1,1 +0,0 @@
-run --advice:power=all --diag_suppress=163 --ulp_standalone_mode=iar -D__IAR_SYSTEMS_ICC__ -D__TID__=11008 -D__intrinsic= -D__no_init= -D__persistent= --c iar.c
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/icd
@@ -1,1 +0,0 @@
-cd ~/Contracts/TI/tmp/iar
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/line
@@ -1,1 +0,0 @@
-(a_line_number)_Z15db_line_for_seqm (pos_curr_token.seq)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/mrun
@@ -1,1 +0,0 @@
-run -I../../exec/arm -Imc2_headers --check_misra=all,-5.3 --c mc2_$0.c
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/opencl
@@ -1,1 +0,0 @@
-run --abi=eabi --opencl --c -I.. cl_$0.c
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/oper
@@ -1,1 +0,0 @@
-(void)_Z10db_operandP10an_operand($0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/operkind
@@ -1,1 +0,0 @@
-(an_expr_operator_kind_tag)$0->variant.operation.kind
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/run
@@ -1,1 +0,0 @@
-run --abi=eabi --opencl --c -I.. cl_$0.c
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/type
@@ -1,1 +0,0 @@
-(void)_Z7db_typeP6a_type($0->type)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/ulpcd
@@ -1,1 +0,0 @@
-cd ~/Contracts/TI/bugslayer/ulp_
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/gud-mode/ulprun
@@ -1,1 +0,0 @@
-run --abi=eabi --advice:power=all --remarks --c -I.. ulp_$0.c
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/.yas-ignore-filenames-as-triggers
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/.yas-make-groups
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/case
@@ -1,9 +0,0 @@
-# -*- mode: snippet -*-
-# key: case
-# name: case
-# expand-env: ((yas-indent-line 'fixed))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-case ${1:x} of
- ${2:Data} -> ${4:expression}
- ${3:Data} -> ${5:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/comment.block
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# key: {-
-# name: block comment
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-{- $0 -}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/constraint
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# key: =>
-# name: Type constraint
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-(${1:Class} ${2:m}) => $0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/data.inline
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# key: data
-# name: inline data
-# condition: (= (length "data") (current-column))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-data ${1:Type} = ${2:Data}$0 ${3:deriving (${4:Show, Eq})}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/data.record
@@ -1,10 +0,0 @@
-# -*- mode: snippet -*-
-# key: data
-# name: record data
-# condition: (= (length "data") (current-column))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-data ${1:Type} = $1
- { ${2:field} :: ${3:Type}
- , ${4:field} :: ${5:Type}$0
- } ${6:deriving (${7:Show, Eq})}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/fn
@@ -1,9 +0,0 @@
-# -*- mode: snippet -*-
-# key: fn
-# name: simple function
-# condition: (= (length "fn") (current-column))
-# expand-env: ((yas-indent-line 'fixed))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-${1:f} :: ${2:a} ${3:-> ${4:b}}
-$1 ${5:x} = ${6:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/fn.clause
@@ -1,10 +0,0 @@
-# -*- mode: snippet -*-
-# key: fn
-# name: clause function
-# condition: (= (length "fn") (current-column))
-# expand-env: ((yas-indent-line 'fixed))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-${1:f} :: ${2:a} ${3:-> ${4:b}}
-$1 ${5:pattern} = ${7:expression}
-$1 ${6:pattern} = ${8:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/fn.guarded
@@ -1,11 +0,0 @@
-# -*- mode: snippet -*-
-# key: fn
-# name: guarded function
-# condition: (= (length "fn") (current-column))
-# expand-env: ((yas-indent-line 'fixed))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-${1:f} :: ${2:a} ${3:-> ${4:b}}
-$1 ${5:x}
- | ${6:conditional} = ${8:expression}
- | ${7:conditional} = ${9:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/get
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# key: <-
-# name: monadic get
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-${1:x} <- ${2:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/if.block
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# key: if
-# name: block if
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-if ${1:condition}
- then ${2:expression}
- else ${3:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/if.inline
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# key: if
-# name: inline if
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-if ${1:condition} then ${2:expression} else ${3:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/import
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# key: imp
-# name: simple import
-# condition: (= (length "imp") (current-column))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-import ${1:Module} ${2:(${3:f})}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/import.qualified
@@ -1,9 +0,0 @@
-# -*- mode: snippet -*-
-# key: imp
-# name: qualified import
-# condition: (= (length "imp") (current-column))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-import qualified ${1:Module} as ${2:${1:$(let ((name (car (last (split-string yas-text "\\\.")))))
- (if (not (nil-blank-string name)) ""
- (subseq name 0 1)))}}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/instance
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# key: inst
-# name: instance
-# condition: (= (length "inst") (current-column))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-instance ${1:Class} ${2:Data} where
- ${3:f} = ${4:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/lambda
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# key: \
-# name: lambda
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-\\${1:x} -> ${2:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/lang-pragma
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# key: lang
-# name: language pragma
-# condition: (= (length "lang") (current-column))
-# contributor: Luke Hoersten <luke@hoersten.org>, John Wiegley
-# --
-{-# LANGUAGE `(progn (require 'haskell-yas) (haskell-yas-complete "Extension: " haskell-yas-ghc-language-pragmas))` #-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/let
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# key: let
-# name: let
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-let ${1:x} = ${2:expression}$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/main
@@ -1,13 +0,0 @@
-# -*- mode: snippet -*-
-# key: main
-# name: main module
-# condition: (= (length "main") (current-column))
-# expand-env: ((yas-indent-line 'fixed))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-module Main where
-
-main :: IO ()
-main = do
- ${1:expression}$0
- return ()
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/module
@@ -1,14 +0,0 @@
-# -*- mode: snippet -*-
-# key: mod
-# name: simple module
-# condition: (= (length "mod") (current-column))
-# expand-env: ((yas-indent-line 'fixed))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-module ${1:`(if (not buffer-file-name) "Module"
- (let ((name (file-name-sans-extension (buffer-file-name))))
- (if (search "src/" name)
- (replace-regexp-in-string "/" "." (car (last (split-string name "src/"))))
- (file-name-nondirectory name))))`} where
-
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/module.exports
@@ -1,17 +0,0 @@
-# -*- mode: snippet -*-
-# key: mod
-# name: exports module
-# condition: (= (length "mod") (current-column))
-# expand-env: ((yas-indent-line 'fixed))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-module ${1:`(if (not buffer-file-name) "Module"
- (let ((name (file-name-sans-extension (buffer-file-name))))
- (if (search "src/" name)
- (replace-regexp-in-string "/" "." (car (last (split-string name "src/"))))
- (file-name-nondirectory name))))`}
- ( ${3:export}
- ${4:, ${5:export}}
- ) where
-
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/haskell-mode/newtype
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# key: new
-# name: newtype
-# condition: (= (length "new") (current-column))
-# contributor: Luke Hoersten <luke@hoersten.org>
-# --
-newtype ${1:Type} = $1 { un$1 :: ${2:a} } ${3:deriving (${4:Show, Eq})}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/.hgignore
@@ -1,7 +0,0 @@
-syntax: regexp
-~$
-\#.*$
-\.DS_Store
-\.yas-compiled-snippets\.el$
-
-
tools/emacs/etc/yasnippet/snippets/haskell-mode/hdr.yasnippet
@@ -1,23 +0,0 @@
-# -*- mode: snippet -*-
-# key: hdr
-# name: haskell header
-# expand-env: ((yas-indent-line 'fixed))
-# contributor: John Wiegley <johnw@newartisans.com>
-# --
-{-# LANGUAGE OverloadedStrings #-}
-
-module `(file-name-sans-extension (buffer-name))` where
-
-import Control.Applicative
-import Control.Monad
-import Control.Monad.IO.Class
-import Control.Monad.Trans.Class
-import Control.Monad.Trans.Control
-import Data.Maybe
-import Data.Monoid
-
-$1 :: $0
-$1 = undefined
-
-main :: IO ()
-main = undefined
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/haskell-mode/README.md
@@ -1,89 +0,0 @@
-# Shnippet
-
-
-**Shnippet** is a collection of
-[YASnippet][yas]
-[Haskell][haskell] snippets for Emacs.
-
-
-## Installation
-
-Clone repository:
-
- $ cd ~/.emacs.d/snippets
- $ git clone https://github.com/LukeHoersten/shnippet
- OR
- $ hg clone https://bitbucket.org/LukeHoersten/shnippet
-
-Add the cloned repository to YASnippet's `yas-snippet-dirs`:
-
- (setq yas-snippet-dirs
- '("~/.emacs.d/snippets/shnippet"
- "/other/paths/"
- ))
-
-Snippets may have to be recompiled and reloaded in Emacs if YASnippet
-is already in use:
-
- M-x yas-recompile-all
- M-x yas-reload-all
-
-
-Haskell snippts should now be available to use! In a `haskell-mode`
-buffer, type `fn<TAB>`. A prompt should appear asking which `fn`
-snippet to expand.
-
-I **highly** recommend using YASnippet with [ido-mode]. Configure
-Emacs:
-
- (setq-default yas-prompt-functions '(yas-ido-prompt yas-dropdown-prompt))
-
-This is important so that alternatives (like `import` vs. `import
-qualified`) can quickly be selected with a single key stroke.
-
-
-## Available Expansion Keys
-
-* `new` - newtype
-* `mod` - module [simple, exports]
-* `main ` - main module and function
-* `let` - let bindings
-* `lang` - language extension pragmas
-* `\` - lambda function
-* `inst` - instance declairation
-* `imp` - import modules [simple, qualified]
-* `if` - if conditional [inline, block]
-* `<-` - monadic get
-* `fn` - top level function [simple, guarded, clauses]
-* `data` - data type definition [inline, record]
-* `=>` - type constraint
-* `{-` - block comment
-* `case` - case statement
-
-
-## Design Ideals
-
-* Keep snippet keys (the prefix used to auto-complete) to four
- characters or less while still being as easy to guess as possible.
-
-* Have as few keys as possible. The more keys there are to remember,
- the harder snippets are to use and learn.
-
-* Leverage [ido-mode][] when reasonable. For instance, to keep the
- number of snippet keys to a minimum as well as auto complete things
- like [Haskell Langauge Extension Pragmas][lang-pragma]. When
- multiple snippets share a key (ex: `fn`), the `ido-mode` prompts are
- unique to one character (ex: `guarded function` and `simple
- function` are `g` and `s` respectively).
-
-
-## Authors
-
-This code is written and maintained by Luke Hoersten,
-<luke@hoersten.org>.
-
-
-[yas]: https://github.com/capitaomorte/yasnippet
-[ido-mode]: http://www.emacswiki.org/emacs/InteractivelyDoThings
-[lang-pragma]: http://hackage.haskell.org/packages/archive/Cabal/1.16.0.3/doc/html/Language-Haskell-Extension.html#t:KnownExtension
-[haskell]: http://haskell.org/
tools/emacs/etc/yasnippet/snippets/haskell-mode/tr.yasnippet
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# key: tr
-# name: trace
-# contributor: John Wiegley <johnw@newartisans.com>
-# --
-trace ("$1: " ++ show ($1)) $
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/js-mode/commonjs.require
@@ -1,5 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: commonjs.require
-# key: req
-# --
-var ${3:${1:$(s-lower-camel-case (file-name-nondirectory yas/text))}} = require("${1:module}")$2;$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/js-mode/es6.import
@@ -1,6 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: es6.import
-# key: imp
-# binding: direct-keybinding
-# --
-import ${3:${1:$(s-lower-camel-case (file-name-nondirectory yas/text))}} from "${1:module}";$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/js-mode/js.es5exportedfunction
@@ -1,6 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: js.exportedfunction
-# key: 5xf
-# --
-function $1($2) {$0};
-module.exports.$1 = $1;
tools/emacs/etc/yasnippet/snippets/js-mode/js.exportedconst
@@ -1,5 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: js.exportedconst
-# key: xc
-# --
-export const $1 = $0;
tools/emacs/etc/yasnippet/snippets/js-mode/js.exportedfunction
@@ -1,7 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: js.exportedfunction
-# key: xf
-# --
-export function ${1:f}($2) {
- $0
-}
tools/emacs/etc/yasnippet/snippets/js-mode/js.exportedvar
@@ -1,5 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: js.exportedvar
-# key: xv
-# --
-var $1 = module.exports.$1 = $0;
tools/emacs/etc/yasnippet/snippets/js-mode/js.function
@@ -1,5 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: js.function
-# key: fn
-# --
-function($1) {$0}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/js-mode/js.generator
@@ -1,5 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: js.generator
-# key: gen
-# --
-function*() {$0}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/js-mode/jsdoc
@@ -1,7 +0,0 @@
-# -*- mode: snippet; require-final-newline: nil -*-
-# name: jsdoc
-# key: jd
-# --
-/**
- * $0
- */
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/latex-mode/acro
@@ -1,1 +0,0 @@
-\newacronym{$1}{${1:$(upcase yas-text)}}{$0}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/latex-mode/code
@@ -1,10 +0,0 @@
-# -*- mode: snippet -*-
-# key: code
-# expand-env: ((yas-indent-line 'fixed))
-# --
-\begin{listing}[!ht]
- \begin{minted}[frame=single,gobble=4]{coq}
- $0
- \end{minted}
- \caption{$1}
-\end{listing}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/latex-mode/gloss
@@ -1,4 +0,0 @@
-\newglossaryentry{$1}{
- name={$1},
- description={$0}
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/latex-mode/hafez
@@ -1,3 +0,0 @@
-\begin{hafez}{$1}{${2:pp.~1--2}}
- $0
-\end{hafez}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/case
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: case
-# key: case
-# --
-(case ${1:key-form}
- (${2:match} ${3:result})${4:
- (t ${5:otherwise})})
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/ccase
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: ccase
-# key: ccase
-# --
-(ccase ${1:key-form}
- (${2:match} ${3:result}))
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/cond
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: cond
-# key: cond
-# --
-(cond (${1:test} ${2:then})
- (t ${3:else}))
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/ctypecase
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: ctypecase
-# key: ctypecase
-# --
-(ctypecase ${1:key-form}
- (${2:match} ${3:result}))
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defclass
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defclass
-# key: defclass
-# --
-(defclass ${1:name} (${2:parents})
- ($0)${3:
- (:documentation "${4:doc}")})
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defconstant
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defconstant
-# key: defconstant
-# --
-(defconstant +${1:name}+ ${2:nil}${3:
- "${4:doc}"})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defgeneric
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defgeneric
-# key: defgeneric
-# --
-(defgeneric ${1:name} (${2:args})${3:
- (:documentation "${4:doc}")})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/define-compiler-macro
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: define-compiler-macro
-# key: define-compiler-macro
-# --
-(define-compiler-macro ${1:name} (${2:args})
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/define-condition
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: define-condition
-# key: define-condition
-# --
-(define-condition ${1:name} (${2:parents})
- ($0)${3:
- (:documentation "${4:doc}")})
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/define-symbol-macro
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: define-symbol-macro
-# key: define-symbol-macro
-# --
-(define-symbol-macro ${1:name} ${2:expansion})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defmacro
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defmacro
-# key: defmacro
-# --
-(defmacro ${1:name} (${2:args }${3:&body body})${4:
- "${5:doc}"}
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defmethod
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defmethod
-# key: defmethod
-# --
-(defmethod ${1:name} (${2:args})
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defpackage
@@ -1,12 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defpackage
-# key: defpackage
-# --
-(defpackage :${1:package}${2:
- (:nicknames ${3:nicks})}${4:
- (:use ${5:packages})}${6:
- (:shadow ${7:packages})}${8:
- (:export ${9:packages})}${10:
- (:documentation "${11:doc}")})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defparameter
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defparameter
-# key: defparameter
-# --
-(defparameter *${1:name}* ${2:nil}${3:
- "${4:doc}"})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defstruct
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defstruct
-# key: defstruct
-# --
-(defstruct ${1:name}${2:
- "${3:doc}"}
- ($0))
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defsystem
@@ -1,14 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defsystem
-# key: defsystem
-# --
-(asdf:defsystem :${1:system}${2:
- :version "${3:0.1.0}"}${4:
- :description "${5:description}"}${6:
- :author "${7:`user-full-name` <`user-mail-address`>}"}${8:
- :serial t}${10:
- :license "${11:GNU GPL, version 3}"}${12:
- :components (${13:(:file "file.lisp")})}${14:
- :depends-on (${15:#:alexandria})})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/deftype
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: deftype
-# key: deftype
-# --
-(deftype ${1:name} (${2:args})${3:
- "${4:doc}"}
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defun
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defun
-# key: defun
-# --
-(defun ${1:name} (${2:args})${3:
- "${4:doc}"}
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/defvar
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: defvar
-# key: defvar
-# --
-(defvar *${1:name}*${2: nil}${3:
- "${4:doc}"})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/destructuring-bind
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: destructuring-bind
-# key: dbind
-# --
-(destructuring-bind (${1:vars}) ${2:value}
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/do
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: do
-# key: do
-# --
-(do (${1:vars})
- (${2:end-test-form}${3: result})
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/do_
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: do*
-# key: do*
-# --
-(do* (${1:vars})
- (${2:end-test-form}${3: result})
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/dolist
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: dolist
-# key: dolist
-# --
-(dolist (${1:var} ${2:list}${3: result})
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/dotimes
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: dotimes
-# key: dotimes
-# --
-(dotimes (${1:var} ${2:count}${3: result})
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/ecase
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: ecase
-# key: ecase
-# --
-(ecase ${1:key-form}
- (${2:match} ${3:result}))
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/etypecase
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: etypecase
-# key: etypecase
-# --
-(etypecase ${1:key-form}
- (${2:match} ${3:result}))
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/flet
@@ -1,9 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Toni Querol
-# name: flet
-# key: flet
-# --
-(flet ((${1:name} (${2:args})${3:
- "${4:doc}"}
- ${5:body}))
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/format
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: format
-# key: format
-# --
-(format ${1:nil} ${2:str} $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/gnugpl
@@ -1,25 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: GNU GPL 3 Header
-# key: gnugpl
-# --
-;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; -*-
-;;;
-;;; ${1:description}
-;;;
-;;; Copyright © ${2:`(format-time-string "%Y")`} `user-full-name` <`user-mail-address`>
-;;;
-;;; ${3:This program$(prog1 yas-text (fill-paragraph))} 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.
-;;;
-;;; ${3:$(prog1 yas-text (fill-paragraph))} 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 <http://www.gnu.org/licenses/>.
-
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/if
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: if
-# key: if
-# --
-(if ${1:test} ${2:then}${3: else})
tools/emacs/etc/yasnippet/snippets/lisp-mode/in-package
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: in-package
-# key: in-package
-# --
-(in-package #:${1:package})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/labels
@@ -1,9 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Toni Querol
-# name: labels
-# key: labels
-# --
-(labels ((${1:name} (${2:args})${3:
- "${4:doc}"}
- ${5:body}))
- $0)
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/let
@@ -1,6 +0,0 @@
-# -*- mode: snippet -*-
-# name: let
-# key: let
-# --
-(let ((${1:var} ${2:val}))
- $0)
tools/emacs/etc/yasnippet/snippets/lisp-mode/mapc
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: mapc
-# key: mapc
-# --
-(mapc ${1:fnc} ${2:list})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/mapcar
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: mapcar
-# key: mapcar
-# --
-(mapcar ${1:fnc} ${2:list})
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/mitlic
@@ -1,31 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: MIT License Header
-# key: mitlic
-# --
-;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; -*-
-;;;
-;;; ${1:description}
-;;;
-;;; Copyright © ${2:`(format-time-string "%Y")`} `user-full-name` <`user-mail-address`>
-;;;
-;;; Permission is hereby granted, free of charge, to any person obtaining a
-;;; copy of this software and associated documentation files (the
-;;; "Software"), to deal in the Software without restriction, including
-;;; without limitation the rights to use, copy, modify, merge, publish,
-;;; distribute, sublicense, and/or sell copies of the Software, and to
-;;; permit persons to whom the Software is furnished to do so, subject to
-;;; the following conditions:
-;;;
-;;; The above copyright notice and this permission notice shall be included
-;;; in all copies or substantial portions of the Software.
-;;;
-;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-;;; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-;;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-;;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-;;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-$0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/lisp-mode/typecase
@@ -1,8 +0,0 @@
-# -*- mode: snippet -*-
-# contributor: Mark Karpov
-# name: typecase
-# key: typecase
-# --
-(typecase ${1:key-form}
- (${2:match} ${3:result})${4:
- (t ${5:otherwise})})
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/message-mode/check
@@ -1,4 +0,0 @@
-Hi $1,
-
-On $2 you mentioned you were going to check part $3. How's it going?
-
tools/emacs/etc/yasnippet/snippets/message-mode/granted
@@ -1,38 +0,0 @@
-# expand-env: ((yas-indent-line 'fixed) (yas-wrap-around-region 'nil))
-# --
-
-Your wish has been granted. You can commit to Emacs and GNU ELPA. Feel free to
-use this power, but please try to be extra careful and prove yourself worthy
-of this privilege:
-
-- Send your patches for review before installing them.
-
-- Only install changes whose code follows the usual coding conventions. Some
- of those conventions are documented in http://www.gnu.org/prep/standards;
- you'll discover others during code review.
-
-- Always provide a good commit message (copied into or from the ChangeLog for
- emacs.git), following the GNU coding standards (e.g. using the
- present/imperative tense, and syntax described at
- http://www.gnu.org/prep/standards/html_node/Change-Logs.html), and properly
- labelling the author of the code.
-
-- If the change is a new feature or a change in behavior, don't forget to
- mention it in the etc/NEWS file and to update the Texinfo doc accordingly.
-
-- Be sure your change is accepted as being for the better by the package's
- maintainer. As a general rule send your patch for review before installing
- it, unless you're absolutely positively 200% sure that everyone will be
- pleased with the content and the form of the patch.
-
-Last but not least:
-
-- And make extra sure that all the code you install has the proper copyright:
- if it is not your own code, make sure the author has signed the relevant
- copyright papers (for non-trivial contributions), and indicate the author
- correctly in the commit (and the ChangeLog if applicable).
-
-If you have the slightest doubt about any of those points, send your question
-or your patch to emacs-devel@gnu.org (or bug-gnu-emacs@gnu.org).
-
-Thank you very much for your contribution to Emacs,
tools/emacs/etc/yasnippet/snippets/message-mode/proof
@@ -1,22 +0,0 @@
-The list of sections still needing to be proofread is here:
-
- http://ftp.newartisans.com/pub/emacs-manual.html
-
-If you'd like a suggestion, how about:
-
-| Chapter | Part | Title | Page | Length |
-|---------+------+--------------------------------+------+--------|
-| 24 | 17 | Compiling and Testing Programs | 277 | 20 |
-
-Otherwise, please pick any section(s) without a "Checked By" name, and e-mail
-emacs-manual-bugs@gnu.org with the Ch/Pt numbers. I'll then add you to the
-volunteered list. Once you have some edits, send them to the same list, and
-I'll add you to the Checked By column for that section.
-
-It's OK to proofread something that's already been done, if you were hoping to
-brush up on that part of the manual. It's our goal to make sure everything is
-seen at least three times.
-
-Richard has sent instructions to many of you, but in case you haven't received
-them yet, they can be found here:
-https://lists.gnu.org/archive/html/help-gnu-emacs/2018-01/msg00295.html
tools/emacs/etc/yasnippet/snippets/message-mode/suggest
@@ -1,21 +0,0 @@
-Hi $1,
-
-I was wondering if you'd be willing to check any of these parts for us:
-
-| Ch | Pt | Title | Page | Len |
-|----+-----+---------------------------------------------+------+-----|
-| 11 | 7a | Chapter Beginning - Font Lock mode | 72 | 9 |
-| 13 | 9 | Commands for Fixing Typos | 119 | 6 |
-| 14 | | Keyboard Macros | 125 | 8 |
-| | 10b | Reverting a Buffer - Chapter End | | 13 |
-| 17 | | Multiple Windows | 167 | 7 |
-| 24 | 17 | Compiling and Testing Programs | 277 | 20 |
-| | 18b | Change Logs - Chapter End | | 13 |
-| 28 | 21 | The Calendar and the Diary | 351 | 19 |
-| 30 | 23 | Reading Mail with Rmail | 379 | 20 |
-| | 26b | Customizing Key Bindings - Chapter End | | 14 |
-| C | 29 | Command Line Arguments for Emacs Invocation | 507 | 15 |
-| E | | Emacs 25 Antinews | 529 | 3 |
-| F | 31 | Emacs and Mac OS / GNUstep | 532 | 3 |
-| G | | Emacs and Microsoft Windows/MS-DOS | 535 | 10 |
-| GL | 33 | Glossary | 553 | 23 |
tools/emacs/etc/yasnippet/snippets/org-mode/appt
@@ -1,7 +0,0 @@
-#name : APPT
-# --
-APPT $0
-SCHEDULED: `(with-temp-buffer (org-insert-time-stamp (current-time)))`
-:PROPERTIES:
-:ID: `(shell-command-to-string "uuidgen")`:CREATED: `(with-temp-buffer (org-insert-time-stamp (current-time) t t))`
-:END:
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/org-mode/assem
@@ -1,31 +0,0 @@
-* NOTE Assembly meeting agenda for `(with-temp-buffer (org-insert-time-stamp (current-time) nil t))`
-:PROPERTIES:
-:ID: `(shell-command-to-string "uuidgen")`:CREATED: `(with-temp-buffer (org-insert-time-stamp (current-time) t t))`
-:OVERLAY: (face (:background "#e8f9e8"))
-:END:
-** Opening Prayers
-** Attendance [0/9]
-- [$0 ] Caroline Delaney
-- [ ] Todd Zeigler
-- [ ] Becky Thomas
-- [ ] Pamela Fox
-- [ ] Nasim Wiegley
-- [ ] Beth Youker-Schwab
-- [ ] Gail Hill
-- [ ] Christina Stone
-- [ ] John Wiegley
-** Review prior minutes of [2013-01-01 Tue]
-** New Business
-** Outstanding business
-** Upcoming events
-** Secretary's report
-** Feast suggestions
-** Treasurer's Report
-** Consultation
-** Affairs of the Local Spiritual Assembly
-*** P.I. Rep: Caroline
-*** Center Manager: Caroline
-*** Children's Education: Mary Anne, Sisi, Keith
-*** Teaching Committee: Mary Anne, Christina, JohnW and Katy
-*** Center Improvement Committee: Beth, Pamela
-** Next Assembly meeting is [2013-01-01 Tue 00:00]
tools/emacs/etc/yasnippet/snippets/org-mode/bbdb
@@ -1,3 +0,0 @@
-#name : bbdb
-# --
-[[bbdb:$1][$1]] $0
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/org-mode/hask
@@ -1,2 +0,0 @@
-#+begin_src haskell
-$0#+end_src
tools/emacs/etc/yasnippet/snippets/org-mode/list
@@ -1,7 +0,0 @@
-#name : List NOTE
-# --
-*** NOTE $1 [/]
-- [ ] $0
-:PROPERTIES:
-:ID: `(shell-command-to-string "uuidgen")`:CREATED: `(with-temp-buffer (org-insert-time-stamp (current-time) t t))`
-:END:
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/org-mode/note
@@ -1,6 +0,0 @@
-#name : NOTE
-# --
-NOTE $0
-:PROPERTIES:
-:ID: `(shell-command-to-string "uuidgen")`:CREATED: `(with-temp-buffer (org-insert-time-stamp (current-time) t t))`
-:END:
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/org-mode/out
@@ -1,4 +0,0 @@
-#name : :OUTPUT: ... :END:
-# --
-:OUTPUT:
-$0:END:
tools/emacs/etc/yasnippet/snippets/org-mode/proj
@@ -1,6 +0,0 @@
-#name : PROJECT
-# --
-PROJECT $0
-:PROPERTIES:
-:ID: `(shell-command-to-string "uuidgen")`:CREATED: `(with-temp-buffer (org-insert-time-stamp (current-time) t t))`
-:END:
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/org-mode/sh
@@ -1,2 +0,0 @@
-#+begin_src sh
-$0#+end_src
tools/emacs/etc/yasnippet/snippets/org-mode/skip
@@ -1,3 +0,0 @@
-:PROPERTIES:
-:BEAMER_act: <2->
-:END:
tools/emacs/etc/yasnippet/snippets/org-mode/src
@@ -1,4 +0,0 @@
-# --
-#+begin_src $1
-$0
-#+end_src
tools/emacs/etc/yasnippet/snippets/org-mode/status
@@ -1,23 +0,0 @@
-**** NOTE Status Report for `(with-temp-buffer (org-insert-time-stamp (current-time) nil t))`
-:PROPERTIES:
-:ID: `(shell-command-to-string "uuidgen")`:CREATED: `(with-temp-buffer (org-insert-time-stamp (current-time) t t))`
-:END:
-***** Planned and implemented
-
--
-
-***** Not planned but implemented
-
--
-
-***** Planned but not implemented
-
--
-
-***** Planned for next week
-
--
-
-***** Questions and concerns
-
-- None this week.
tools/emacs/etc/yasnippet/snippets/org-mode/teach
@@ -1,21 +0,0 @@
-* NOTE Assembly meeting agenda for `(with-temp-buffer (org-insert-time-stamp (current-time) nil t))`
-:PROPERTIES:
-:ID: `(shell-command-to-string "uuidgen")`:CREATED: `(with-temp-buffer (org-insert-time-stamp (current-time) t t))`
-:OVERLAY: (face (:background "#e8f9e8"))
-:END:
-** Opening Prayers
-** Attendance [0/9]
-- [$0 ] Caroline Delaney
-- [ ] Sisi Mereness
-- [ ] John Tempey
-- [ ] Pamela Fox
-- [ ] Nami Peymani
-- [ ] Beth Youker-Schwab
-- [ ] Gail Hill
-- [ ] Christina Stone
-- [ ] John Wiegley
-** Not reviewing prior minutes at this meeting
-** Teaching
-** Consultation
-** New Business
-** Next Assembly meeting is [2013-01-01 Tue 00:00]
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/org-mode/todo
@@ -1,7 +0,0 @@
-#name : TODO
-# --
-TODO $0
-SCHEDULED: `(with-temp-buffer (org-insert-time-stamp (current-time)))`
-:PROPERTIES:
-:ID: `(shell-command-to-string "uuidgen")`:CREATED: `(with-temp-buffer (org-insert-time-stamp (current-time) t t))`
-:END:
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/python-mode/def
@@ -1,36 +0,0 @@
-# -*- coding: utf-8 -*-
-# name: de
-# contributor: Orestis Markou
-# contributor: Yasser González Fernández <yglez@uh.cu>
-# contributor: Tibor Simko <tibor.simko@cern.ch>
-# --
-def ${1:name}($2):
- """
- $3
- ${2:$
- (let* ((indent
- (concat "\n" (make-string (current-column) 32)))
- (args
- (mapconcat
- '(lambda (x)
- (if (not (string= (nth 0 x) ""))
- (concat "@param " (nth 0 x) ": " indent
- "@type " (nth 0 x) ": ")))
- (mapcar
- '(lambda (x)
- (mapcar
- '(lambda (x)
- (replace-regexp-in-string "[[:blank:]]*$" ""
- (replace-regexp-in-string "^[[:blank:]]*" "" x)))
- x))
- (mapcar '(lambda (x) (split-string x "="))
- (split-string yas-text ",")))
- indent)))
- (if (string= args "")
- (concat indent "@return: " indent "@rtype: " indent (make-string 3 34))
- (mapconcat
- 'identity
- (list "" args "@return: " "@rtype: " (make-string 3 34))
- indent)))
- }
- $0
tools/emacs/etc/yasnippet/snippets/rust-mode/clone
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# name: clone
-# key: clone
-# --
-clone(&self) -> Self {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/rust-mode/default
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# name: default
-# key: default
-# --
-default() -> Self {
- ${0:Self::new()}
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/rust-mode/fmt
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# name: fmt
-# key: fmt
-# --
-fmt(&self, f: &mut Formatter) -> Result<(), Error> {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/rust-mode/impl
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# name: impl
-# key: impl
-# --
-impl$3 ${1:Trait} for ${2:Type}$3 {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/rust-mode/implClone
@@ -1,9 +0,0 @@
-# -*- mode: snippet -*-
-# name: implClone
-# key: Clone
-# --
-impl$2 Clone for ${1:Type}$2 {
- fn clone(&self) -> Self {
- $0
- }
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/rust-mode/implDefault
@@ -1,9 +0,0 @@
-# -*- mode: snippet -*-
-# name: implDefault
-# key: Default
-# --
-impl$2 Default for ${1:Type}$2 {
- fn default() -> Self {
- ${0:Self::new()}
- }
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/rust-mode/is_empty
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# name: is_empty
-# key: is_empty
-# --
-is_empty(&self) -> bool {
- ${0:self.len() == 0}
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/rust-mode/len
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# name: len
-# key: len
-# --
-len(&self) -> usize {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/rust-mode/new
@@ -1,7 +0,0 @@
-# -*- mode: snippet -*-
-# name: new
-# key: new
-# --
-new() -> Self {
- $0
-}
\ No newline at end of file
tools/emacs/etc/yasnippet/snippets/text-mode/ggit
@@ -1,1 +0,0 @@
-https://github.com/vdemeester/$0
tools/emacs/etc/pandoc.css
@@ -1,245 +0,0 @@
-/***************************************************************************/
-/* My Stylesheet for Pandoc generated files */
-/* Copyright (c) 2015 Sebastian Wiesner <swiesner@lunaryorn.com> */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining a */
-/* copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be included */
-/* in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS */
-/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
-/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE */
-/* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION */
-/* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION */
-/* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/***************************************************************************/
-
-body {
- font-family: "Source Sans Pro", sans-serif;
- font-size: 16px;
- line-height: 1.35;
- color: #444;
- font-feature-settings: "onum", "kern", "liga", "clig", "dlig", "calt";
- -webkit-font-feature-settings: "onum", "kern", "liga", "clig", "dlig", "calt";
- margin: 0 auto;
- padding: 15px;
- margin-bottom: 1.35em;
- word-wrap: break-word;
-}
-
-p {
- margin: 0 0;
- text-indent: 1.5em;
- text-align: left;
-}
-
-p:only-child {
- text-indent: 0;
-}
-
-strong {
- font-weight: 600;
-}
-
-ul, ol {
- margin: 1em 4em;
- padding: 0;
-}
-
-ol {
- list-style-type: decimal;
-}
-
-ul {
- list-style-type: disc;
-}
-
-small, sup {
- font-size: 0.86em;
-}
-
-h1 small, h2 small, h3 small, h4 small {
- font-weight: normal;
- font-size: 0.65em;
- line-height: 1;
- color: #777;
-}
-
-blockquote {
- margin: 1.2em 0;
- padding: 0 2em;
- line-height: 1.25;
- font-size: 0.9em;
- border-left: 5px solid #EEE;
-}
-
-a {
- color: #333;
- text-decoration: underline;
-}
-
-a:hover {
- background-color: #fbf3f3;
- border-radius: 4px;
- transition-property: background;
- transition-duration: 0.2s;
-}
-
-.footnoteRef { /* Use body font for footnotes */
- font-size: 1rem;
- text-decoration: none;
-}
-
-h1, h2, h3, h4 { /* Text headings*/
- font-family: "Source Sans Pro", sans-serif;
- font-weight: 600;
- line-height: 1;
- color: #222;
- margin-top: 2em;
- margin-bottom: 0.8em;
- hyphens: none;
- font-feature-settings: "salt", "lnum";
- -webkit-font-feature-settings: "salt", "lnum";
-}
-
-h1 {
- font-size: 1.2em;
-}
-
-h2 {
- font-size: 1.1em;
-}
-
-h3 {
- font-size: 1em;
-}
-
-.header-section-number {
- margin-right: 0.5em;
-}
-
-.header-section-number:after {
- content: "."
-}
-
-hr {
- border-width: 1px;
- border-color: #CCC;
- border-style: none none solid;
- margin: 1.35em 0;
-}
-
-/* Images and figures */
-img {
- max-width: 100%;
- max-height: 100%;
-}
-
-figure {
- margin: 2em;
-}
-
-figcaption {
- margin-top: 0.8em;
- text-align: center;
- font-size: 0.9em;
-}
-
-figcaption:before {
- content: "Figure.";
- font-weight: 700;
- margin-right: 0.5em;
-}
-
-/* Code and pre-formatted text */
-kbd, code {
- font-family: "Source Code Pro", monospace;
- font-size: 0.83em;
-}
-
-kbd {
- border: 1px solid #CCC;
- border-radius: 4px;
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px #FFF inset;
- padding: 0 4px;
-}
-
-code {
- padding: 0.11em 0.22em;
-}
-
-pre {
- overflow: auto;
- padding: 10px;
- border: 1px solid #CCC;
- border-radius: 4px;
-}
-
-pre:hover { /* Auto-expand pre on hover */
- position: relative;
- width: 900px;
- z-index: 99;
-}
-
-pre code {
- padding: 0;
-}
-
-.title { /* Page title */
- font-size: 1.5rem;
- font-weight: 700;
- margin-bottom: 0.2em;
- margin-top: 0;
-}
-
-nav {
- margin: 1em;
- font-feature-settings: "salt", "lnum";
- -webkit-font-feature-settings: "salt", "lnum";
-}
-
-nav a {
- text-decoration: none;
-}
-
-nav ul {
- list-style: none inside disc;
- margin: 0;
- padding: 0 0.5em;
-}
-
-header {
- border-width: 1px;
- border-color: #CCC;
- border-style: none none solid;
- margin: 1.35em 0;
-}
-
-
-@media print {
- body {
- width: auto;
- height: auto;
- font-size: 10pt;
- }
-}
-
-@media screen and (min-width: 650px) { /* Larger devices */
- body {
- width: 600px;
- }
-}
-
-@page
-{
- size: A4;
- margin: 24.75mm 17.50mm;
-}
tools/emacs/host/naruhodo.el
@@ -1,1 +0,0 @@
-../../sync/emacs/naruhodo.el
\ No newline at end of file
tools/emacs/host/README.org
@@ -1,1 +0,0 @@
-Put stuff here that are local to a specific machine, those are private, aka not shared via this git repository.
tools/emacs/host/wakasu.el
@@ -1,1 +0,0 @@
-../../sync/emacs/wakasu.el
\ No newline at end of file
tools/emacs/lisp/auto-side-windows
@@ -1,1 +0,0 @@
-Subproject commit a18be7988b8f0f329b53f117dd517b2340bd4bc4
tools/emacs/lisp/consult-mu
@@ -1,1 +0,0 @@
-Subproject commit e1dc63674b924698b30a9ecc0400a05864711c85
tools/emacs/lisp/gh-notifications-mode.el
@@ -1,513 +0,0 @@
-;;; github-notifications-gh.el --- Display GitHub notifications in Emacs using gh CLI -*- lexical-binding: t -*-
-
-;; Author: Your Name
-;; Version: 1.0
-;; Package-Requires: ((emacs "27.1"))
-
-;;; Commentary:
-;; This package provides functionality to fetch and display GitHub notifications
-;; in a dedicated buffer using the GitHub CLI (gh) and tabulated-list-mode.
-;; Make sure you have gh installed and authenticated before using this package.
-
-;;; For pull-request, fetch the diff from the diff_url field
-;;; For CI status, use the statuses_url
-
-;;; Code:
-
-(require 'json)
-(require 'tabulated-list)
-(require 'diff-mode)
-
-(defgroup github-notifications nil
- "GitHub notifications in Emacs."
- :group 'applications)
-
-(defcustom github-notifications-refresh-interval 300
- "Number of seconds between automatic refresh of notifications."
- :type 'integer
- :group 'github-notifications)
-
-(defface github-notifications-unread-face
- '((t :weight bold))
- "Face for unread notifications."
- :group 'github-notifications)
-
-(defvar github-notifications-buffer-name "*GitHub Notifications*"
- "Name of the buffer for displaying GitHub notifications.")
-
-(defvar github-notifications-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "g") 'github-notifications-refresh)
- (define-key map (kbd "m") 'github-notifications-mark-read)
- (define-key map (kbd "c") 'github-notifications-comment-on-pr)
- (define-key map (kbd "d") 'github-notifications-mark-done)
- (define-key map (kbd "a") 'github-notifications-approve-pr)
- (define-key map (kbd "w") 'github-notifications-copy-url)
- (define-key map (kbd "r") 'github-notifications-request-changes-on-pr)
- (define-key map (kbd "v") 'github-notifications-show-details)
- (define-key map (kbd "RET") 'github-notifications-open-at-point)
- ;; m for mark
- map)
- "Keymap for GitHub notifications buffer.")
-
-(defvar github-notifications-detail-buffer-name "*GitHub Notification Detail*"
- "Name of the buffer for displaying GitHub notification details.")
-
-(defvar github-notifications-detail-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "q") 'quit-window)
- map)
- "Keymap for GitHub notification detail buffer.")
-
-(define-derived-mode github-notifications-detail-mode special-mode "GitHub-Notification-Detail"
- "Major mode for displaying GitHub notification details."
- (setq buffer-read-only t))
-
-(defvar github-notifications--process-buffer "*github-notifications-process*"
- "Buffer for GitHub notifications processes.")
-
-(defun github-notifications--call-process-async (callback _buf name &rest args)
- "Call gh process asynchronously with ARGS and CALLBACK when done.
-Creates a temporary buffer for the process output."
- (let ((temp-buffer (generate-new-buffer (format " *gh-%s*" name))))
- (setenv "TERM" "dumb")
- (setenv "CLICOLOR" "0")
- (setenv "PAGER" "cat")
- (make-process
- :name name
- :buffer temp-buffer
- :command (cons "gh" args)
- :sentinel (lambda (process _event)
- (unwind-protect
- (when (eq (process-status process) 'exit)
- (if (= (process-exit-status process) 0)
- (with-current-buffer (process-buffer process)
- (funcall callback (buffer-string)))
- (message "GitHub CLI process failed")))
- (kill-buffer temp-buffer))))))
-
-(define-derived-mode github-notifications-mode tabulated-list-mode "GitHub-Notifications"
- "Major mode for displaying GitHub notifications."
- (setq tabulated-list-format
- [("Status" 6 t)
- ("CI" 8 t)
- ("Repository" 30 t)
- ("Type" 15 t)
- ("Title" 60 t)
- ("Updated" 20 t)])
- (setq tabulated-list-sort-key '("Updated" . t))
- (setq tabulated-list-padding 2)
- (tabulated-list-init-header))
-
-(defun github-notifications--ensure-gh ()
- "Ensure gh command line tool is available."
- (unless (executable-find "gh")
- (error "GitHub CLI (gh) not found. Please install it first")))
-
-(defun github-notifications--parse-json (json-string)
- "Parse JSON-STRING into Lisp objects."
- (json-read-from-string json-string))
-
-(defun github-notifications--format-time (time-string)
- "Format TIME-STRING to a human-readable format."
- (format-time-string
- "%Y-%m-%d %H:%M"
- (date-to-time time-string)))
-
-(defun github-notifications--format-list-entry (notification)
- "Format a NOTIFICATION as a tabulated list entry."
- (let-alist notification
- (list .id
- (vector
- (github-notifications--format-unread .unread)
- (if (string= .type "PullRequest")
- (github-notifications--format-ci-status .ci_status)
- " ")
- ;; (if (string= .type "PullRequest")
- ;; (or .ci_status "?")
- ;; "")
- .repo
- .type
- (propertize .title
- 'notification-id .id
- 'notification-url .url ; Add this line
- 'github-notifications--copy-url .url
- 'notification-type .type
- 'repo .repo)
- (github-notifications--format-time .updated)))))
-
-(defun github-notifications-fetch ()
- "Fetch notifications using gh CLI asynchronously."
- (github-notifications--ensure-gh)
- (github-notifications--call-process-async
- (lambda (output)
- (let* ((raw-notifications (github-notifications--parse-json output))
- (normalized-notifications
- (mapcar #'github-notifications--normalize-notification raw-notifications)))
- ;; For each PR notification, fetch its status
- (dolist (notif normalized-notifications)
- (when (and (equal (alist-get 'type notif) "PullRequest"))
- (github-notifications--get-pr-statuses notif))
- ;; FIXME there is a bug here, it share the same thing
- (github-notifications--display normalized-notifications))))
- (get-buffer-create github-notifications--process-buffer)
- "github-notifications"
- "api"
- "-H" "Accept: application/vnd.github+json"
- "/notifications?all=true"))
-
-(defun github-notifications--normalize-notification (notif)
- "Convert raw notification to normalized format."
- (let-alist notif
- `((id . ,.id)
- (type . ,.subject.type)
- (title . ,.subject.title)
- (repo . ,.repository.full_name)
- (url . ,.subject.url)
- (updated . ,.updated_at)
- (unread . ,.unread)
- (ci_status . nil)
- (statuses_url . ,.subject.statuses_url))))
-
-(defun github-notifications--display (notifications)
- "Display NOTIFICATIONS in the buffer."
- (with-current-buffer (get-buffer-create github-notifications-buffer-name)
- (github-notifications-mode)
- (setq tabulated-list-entries
- (mapcar #'github-notifications--format-list-entry notifications))
- (tabulated-list-print t)))
-
-(defun github-notifications-refresh ()
- "Refresh the notifications buffer."
- (interactive)
- (github-notifications-fetch))
-
-(defun github-notifications-mark-read ()
- "Mark notification at point as read."
- (interactive)
- (when-let* ((entry (github-notifications--get-entry-data))
- (id (nth 4 entry)))
- (github-notifications--ensure-gh)
- (with-temp-buffer
- (unless (= 0 (call-process "gh" nil t nil
- "api"
- "-X" "PATCH"
- (format "/notifications/threads/%s" id)))
- (error "Failed to mark notification as read")))
- (github-notifications-refresh)))
-
-(defun github-notifications-mark-done ()
- "Mark notification at point as done."
- (interactive)
- (when-let* ((entry (github-notifications--get-entry-data))
- (id (nth 4 entry)))
- (github-notifications--ensure-gh)
- (with-temp-buffer
- (unless (= 0 (call-process "gh" nil t nil
- "api"
- "-X" "DELETE"
- (format "/notifications/threads/%s" id)))
- (error "Failed to mark notification as done")))
- (github-notifications-refresh)))
-
-(defun github-notifications--copy-url ()
- "Copy the URL of the notification item at point."
- (interactive)
- (let* ((entry (github-notifications--get-entry-data))
- (api-url (nth 3 entry))
- (url (replace-regexp-in-string
- "api\\.github\\.com/repos"
- "github.com"
- (replace-regexp-in-string
- "/pulls/"
- "/pull/"
- api-url))))
- (kill-new url)))
-
-(defun github-notifications-open-at-point ()
- "Open the notification at point in a web browser."
- (interactive)
- (when-let* ((entry (tabulated-list-get-entry))
- (title-col (aref entry 3))
- (url (get-text-property 0 'notification-url title-col)))
- (let ((web-url (replace-regexp-in-string
- "api\\.github\\.com/repos"
- "github.com"
- (replace-regexp-in-string
- "/pulls/"
- "/pull/"
- url))))
- (browse-url web-url))))
-
-(defun github-notifications--get-entry-data ()
- "Get PR data from current entry."
- (let* ((entry (tabulated-list-get-entry))
- (id (aref entry 3))
- (title-cell (aref entry 4))
- (repo (get-text-property 0 'repo title-cell))
- (url (get-text-property 0 'notification-url title-cell))
- (notification-id (get-text-property 0 'notification-id title-cell))
- (pr-number (github-notifications--get-pr-number url)))
- (list id repo pr-number url notification-id)))
-
-(defun github-notifications-comment-on-pr ()
- "Add a comment to the pull request at point."
- (interactive)
- (let* ((pr-data (github-notifications--get-entry-data))
- (repo (nth 1 pr-data))
- (pr-number (nth 2 pr-data))
- (comment (read-string "Comment: "))),
- (when (and repo pr-number (not (string-empty-p comment)))
- (let ((default-directory (make-temp-file "gh-pr" t)))
- (call-process "gh" nil "*github-notifications process*" nil
- "pr" "comment"
- pr-number
- "--body" comment
- "--repo" repo)
- (message "Comment posted successfully")))))
-
-(defun github-notifications-request-changes-on-pr ()
- "Add a comment to the pull request at point."
- (interactive)
- (let* ((pr-data (github-notifications--get-entry-data))
- (repo (nth 1 pr-data))
- (pr-number (nth 2 pr-data))
- (comment (read-string "Comment: ")))
- (when (and repo pr-number (not (string-empty-p comment)))
- (let ((default-directory (make-temp-file "gh-pr" t)))
- (call-process "gh" nil "*github-notifications process*" nil
- "pr" "review"
- pr-number
- "--body" comment
- "--request-changes"
- "--repo" repo)
- (message "Comment posted successfully")))))
-
-(defun github-notifications-approve-pr (&optional comment)
- "Approve the pull request at point with an optional comment."
- (interactive
- (list (read-string "Approval comment (optional): ")))
- (let* ((pr-data (github-notifications--get-entry-data))
- (repo (nth 1 pr-data))
- (pr-number (nth 2 pr-data))
- (args (list "pr" "review"
- pr-number
- "--approve"
- "--repo" repo)))
- (when (and repo pr-number)
- (when (and comment (not (string-empty-p comment)))
- (setq args (append args (list "--body" comment))))
- (let ((default-directory (make-temp-file "gh-pr" t)))
- (apply #'call-process "gh" nil "*github-notifications process*" nil args)
- (message "PR approved successfully")))))
-
-(defun github-notifications--get-pr-statuses (notification)
- "Get CI statuses for a PR using the GitHub GraphQL API."
- (let* ((url (alist-get 'url notification))
- (repo (alist-get 'repo notification))
- (pr-number(github-notifications--get-pr-number url)))
- (when (and repo pr-number)
- (with-temp-buffer
- (github-notifications--call-process-async
- (lambda (output)
- (let* ((response (github-notifications--parse-json (buffer-string)))
- (contexts (thread-last response
- (alist-get 'data)
- (alist-get 'repository)
- (alist-get 'pullRequest)
- (alist-get 'commits)
- (alist-get 'nodes)
- (seq-first)
- (alist-get 'commit)
- (alist-get 'statusCheckRollup)
- (alist-get 'contexts)
- (alist-get 'nodes)))
- (statuses (seq-map
- (lambda (ctx)
- (let ((state (or (alist-get 'state ctx)
- (alist-get 'conclusion ctx))))
- (cond
- ((member state '("SUCCESS" "success" "COMPLETED")) "success")
- ((member state '("FAILURE" "failure" "ERROR" "error")) "failure")
- (t "pending"))))
- contexts))
- (total (length statuses))
- (successes (seq-count (lambda (s) (string= s "success")) statuses))
- (failures (seq-count (lambda (s) (string= s "failure")) statuses))
- (pendings (seq-count (lambda (s) (string= s "pending")) statuses))
- (ci-status (list :total total
- :successes successes
- :failures failures
- :pendings pendings)))
- (setf (alist-get 'ci_status notification) ci-status)))
- (get-buffer-create (format "*github-notifications-%s-%s-process*" repo pr-number))
- (format "github-notifications-%s-%s" repo pr-number)
- "api" "graphql" "-f"
- (format "query=%s"
- (github-notifications--make-graphql-query repo pr-number)))))))
-
-(defun github-notifications--format-ci-status (statuses)
- "Format CI status with appropriate face and count information."
- (if (null statuses)
- (propertize "?" 'face '(:foreground "gray"))
- (let* ((total (plist-get statuses :total))
- (successes (plist-get statuses :successes))
- (failures (plist-get statuses :failures))
- (pendings (plist-get statuses :pendings))
- (indicator
- (cond
- ((> failures 0) "✗")
- ((> pendings 0) "○")
- ((= successes total) "✓")
- (t "?")))
- (face
- (cond
- ((> failures 0) '(:foreground "red"))
- ((> pendings 0) '(:foreground "orange"))
- ((= successes total) '(:foreground "green"))
- (t '(:foreground "gray"))))
- (count-str (format "%d/%d" successes total)))
- (concat
- (propertize indicator 'face face)
- " "
- (propertize count-str 'face face)))))
-
-(defun github-notifications--make-graphql-query (repo pr-number)
- "Create a GraphQL query for PR status checks."
- (format "query {
- repository(owner: \"%s\", name: \"%s\") {
- pullRequest(number: %s) {
- commits(last: 1) {
- nodes {
- commit {
- statusCheckRollup {
- state
- contexts(first: 100) {
- nodes {
- ... on StatusContext {
- state
- context
- }
- ... on CheckRun {
- status
- conclusion
- name
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }"
- (car (split-string repo "/"))
- (cadr (split-string repo "/"))
- pr-number))
-
-(defun github-notifications--format-unread (unread)
- "Return a propertized string to showcase the status of the notifications"
- ;; (cond ((unread) (propertize "●" 'face 'github-notifications-unread-face))
- ;; ((not unread) (propertize "○" 'face 'github-notifications-unread-face))
- ;; (t (propertize "?" 'face 'github-notifications-unread-face)))
- (cond (unread (propertize "●" 'face 'github-notifications-unread-face))
- ((not unread) (propertize "○" 'face 'github-notifications-unread-face))
- (t (propertize "?" 'face 'github-notifications-unread-face))))
-
-(defun github-notifications--get-pr-number (url)
- "Extract pull request number from URL."
- (when (string-match "/pulls/\\([0-9]+\\)" url)
- (match-string 1 url)))
-
-(defun github-notifications-show-details ()
- "Show detailed view of the notification at point."
- (interactive)
- (when-let* ((entry (tabulated-list-get-entry))
- (title-cell (aref entry 4))
- (type (get-text-property 0 'notification-type title-cell))
- (repo (get-text-property 0 'repo title-cell))
- (url (get-text-property 0 'github-notifications--copy-url title-cell)))
- (let ((buffer (get-buffer-create github-notifications-detail-buffer-name)))
- (with-current-buffer buffer
- (let ((inhibit-read-only t))
- (erase-buffer)
- (github-notifications-detail-mode)
- (cond
- ((string= type "PullRequest")
- (github-notifications--show-pr-details repo url))
- ((string= type "Issue")
- (github-notifications--show-issue-details repo url))
- (t
- (insert "No detailed view available for this notification type."))))
- (goto-char (point-min)))
- (display-buffer buffer))))
-
-(defun github-notifications--show-pr-details (repo url)
- "Show pull request details for REPO and URL."
- (let ((pr-number (github-notifications--get-pr-number url)))
- (when pr-number
- (insert (format "=== Pull Request #%s ===\n\n" pr-number))
- ;; Fetch PR details
- (github-notifications--call-process-async
- (lambda (output)
- (let ((inhibit-read-only t))
- (save-excursion
- (goto-char (point-min))
- (forward-line 2)
- (let* ((pr-data (github-notifications--parse-json output)))
- (insert (format "Title: %s\n" (alist-get 'title pr-data)))
- (insert (format "State: %s\n" (alist-get 'state pr-data)))
- (insert (format "\nDescription:\n%s\n" (alist-get 'body pr-data)))))))
- nil
- "pr-details"
- "pr" "view" pr-number "--json" "title,body,state" "--repo" repo)
-
- ;; Fetch and display diff
- (insert "\n=== Diff ===\n\n")
- (github-notifications--call-process-async
- (lambda (output)
- (let ((inhibit-read-only t))
- (save-excursion
- (goto-char (point-max))
- (insert output)
- (let ((diff-start (save-excursion
- (goto-char (point-min))
- (search-forward "\n=== Diff ===\n\n" nil t))))
- (when diff-start
- (diff-mode-setup))))))
- nil
- "pr-diff"
- "pr" "diff" pr-number "--repo" repo))))
-
-(defun github-notifications--get-issue-number (url)
- "Extract issue number from URL."
- (when (string-match "/issues/\\([0-9]+\\)" url)
- (match-string 1 url)))
-
-(defun github-notifications--format-checks (checks)
- "Format checks data for display."
- (mapconcat
- (lambda (check)
- (let-alist check
- (format "%s: %s"
- .name
- (propertize .status 'face
- (pcase .status
- ("success" '(:foreground "green"))
- ("failure" '(:foreground "red"))
- (_ '(:foreground "yellow")))))))
- checks "\n"))
-
-;;;###autoload
-(defun github-notifications ()
- "Display GitHub notifications in a buffer."
- (interactive)
- (github-notifications--ensure-gh)
- (let ((buffer (get-buffer-create github-notifications-buffer-name)))
- (with-current-buffer buffer
- (github-notifications-fetch))
- (switch-to-buffer buffer)))
-
-(provide 'github-notifications-gh)
-;;; github-notifications-gh.el ends here
tools/emacs/lisp/gotest-ui.el
@@ -1,631 +0,0 @@
-;;; gotest-ui.el --- Major mode for running go test -json
-
-;; Copyright 2018 Andreas Fuchs
-;; Authors: Andreas Fuchs <asf@boinkor.net>
-
-;; URL: https://github.com/antifuchs/gotest-ui-mode
-;; Created: Feb 18, 2018
-;; Keywords: languages go
-;; Version: 0.1.0
-;; Package-Requires: ((emacs "25") (s "1.12.0") (gotest "0.14.0"))
-
-;; This file is not a part of GNU Emacs.
-
-;; 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.0, 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:
-
-;; Provides support for running go tests with a nice user interface
-;; that allows folding away output, highlighting failing tests.
-
-;;; Code:
-
-(eval-when-compile
- (require 'cl))
-
-(require 'subr-x)
-(require 'ewoc)
-(require 'json)
-(require 'compile)
-
-(defgroup gotest-ui nil
- "The go test runner."
- :group 'tools)
-
-(defface gotest-ui-pass-face '((t :foreground "green"))
- "Face for displaying the status of a passing test."
- :group 'gotest-ui)
-
-(defface gotest-ui-skip-face '((t :foreground "grey"))
- "Face for displaying the status of a skipped test."
- :group 'gotest-ui)
-
-(defface gotest-ui-fail-face '((t :foreground "pink" :weight bold))
- "Face for displaying the status of a failed test."
- :group 'gotest-ui)
-
-(defface gotest-ui-link-face '((t :foreground "white" :weight bold))
- "Face for displaying links to go source files."
- :group 'gotest-ui)
-
-(defcustom gotest-ui-expand-test-statuses '(fail)
- "Statuses to expand test cases for.
-Whenever a test enters this state, it is automatically expanded."
- :group 'gotest-ui)
-
-(defcustom gotest-ui-test-binary '("go")
- "Command list used to invoke the `go' binary."
- :group 'gotest-ui)
-
-(defcustom gotest-ui-test-args '("test" "-json")
- "Argument list used to run tests with JSON output."
- :group 'gotest-ui)
-
-(defcustom gotest-ui-additional-test-args '()
- "Additional args to pass to `go test'."
- :group 'gotest-ui)
-
-;;;; Data model:
-
-(defstruct (gotest-ui-section :named
- (:constructor gotest-ui-section-create)
- (:type vector)
- (:predicate gotest-ui-section-p))
- title tests node)
-
-;;; `gotest-ui-thing' is a thing that can be under test: a
-;;; package, or a single test.
-
-(defstruct gotest-ui-thing
- (name)
- (node)
- (expanded-p)
- (status)
- (buffer) ; the buffer containing this test's output
- (elapsed) ; a floating-point amount of seconds
- )
-
-;;; `gotest-ui-test' is a single test. It contains a status and
-;;; output.
-(defstruct (gotest-ui-test (:include gotest-ui-thing)
- (:constructor gotest-ui--make-test-1))
- (package)
- (reason))
-
-(defun gotest-ui-test->= (test1 test2)
- "Returns true if TEST1's name sorts greater than TEST2's."
- (let ((pkg1 (gotest-ui-test-package test1))
- (pkg2 (gotest-ui-test-package test2))
- (name1 (or (gotest-ui-thing-name test1) ""))
- (name2 (or (gotest-ui-thing-name test2) "")))
- (if (string= pkg1 pkg2)
- (string> name1 name2)
- (string> pkg1 pkg2))))
-
-(defstruct (gotest-ui-status (:constructor gotest-ui--make-status-1))
- (state)
- (cmdline)
- (dir)
- (output)
- (node))
-
-(cl-defun gotest-ui--make-status (ewoc cmdline dir)
- (let ((status (gotest-ui--make-status-1 :state 'run :cmdline (s-join " " cmdline) :dir dir)))
- (let ((node (ewoc-enter-first ewoc status)))
- (setf (gotest-ui-status-node status) node))
- status))
-
-(cl-defun gotest-ui--make-test (ewoc &rest args &key status package name &allow-other-keys)
- (apply #'gotest-ui--make-test-1 :status (or status "run") args))
-
-;;; Data manipulation routines:
-
-(cl-defun gotest-ui-ensure-test (ewoc package-name base-name &key (status 'run))
- (let* ((test-name (format "%s.%s" package-name base-name))
- (test (gethash test-name gotest-ui--tests)))
- (if test
- test
- (setf (gethash test-name gotest-ui--tests)
- (gotest-ui--make-test ewoc :name base-name :package package-name :status status)))))
-
-(defun gotest-ui-update-status (new-state)
- (setf (gotest-ui-status-state gotest-ui--status) new-state)
- (ewoc-invalidate gotest-ui--ewoc (gotest-ui-status-node gotest-ui--status)))
-
-(defun gotest-ui-update-status-output (new-output)
- (setf (gotest-ui-status-output gotest-ui--status) new-output)
- (ewoc-invalidate gotest-ui--ewoc (gotest-ui-status-node gotest-ui--status)))
-
-(defun gotest-ui-ensure-output-buffer (thing)
- (unless (gotest-ui-thing-buffer thing)
- (with-current-buffer
- (setf (gotest-ui-thing-buffer thing)
- (generate-new-buffer (format " *%s" (gotest-ui-thing-name thing))))
- (setq-local gotest-ui-parse-marker (point-min-marker))
- (setq-local gotest-ui-insertion-marker (point-min-marker))
- (set-marker-insertion-type gotest-ui-insertion-marker t)))
- (gotest-ui-thing-buffer thing))
-
-(defun gotest-ui-mouse-open-file (event)
- "In gotest-ui mode, open the file/line reference in another window."
- (interactive "e")
- (let ((window (posn-window (event-end event)))
- (pos (posn-point (event-end event)))
- file line)
- (if (not (windowp window))
- (error "No file chosen"))
- (with-current-buffer (window-buffer window)
- (goto-char pos)
- (gotest-ui-open-file-at-point))))
-
-(defun gotest-ui-open-file-at-point ()
- (interactive)
- (let ((file (gotest-ui-get-file-for-visit))
- (line (gotest-ui-get-line-for-visit)))
- (unless (file-exists-p file)
- (error "Could not open %s:%d" file line))
- (with-current-buffer (find-file-other-window file)
- (goto-char (point-min))
- (when line
- (forward-line (1- line))))))
-
-(defun gotest-ui-get-file-for-visit ()
- (get-text-property (point) 'gotest-ui-file))
-
-(defun gotest-ui-get-line-for-visit ()
- (string-to-number (get-text-property (point) 'gotest-ui-line)))
-
-(defun gotest-ui-file-from-gopath (package file-basename)
- (if (or (file-name-absolute-p file-basename)
- (string-match-p "/" file-basename))
- file-basename
- (let ((gopath (or (getenv "GOPATH")
- (expand-file-name "~/go"))))
- (expand-file-name (concat gopath "/src/" package "/" file-basename)))))
-
-(defvar gotest-ui-click-map
- (let ((map (make-sparse-keymap)))
- (define-key map [mouse-2] 'gotest-ui-mouse-open-file)
- map))
-
-(defun gotest-ui-ensure-parsed (thing)
- (save-excursion
- (goto-char gotest-ui-parse-marker)
- (while (re-search-forward "\\([^ \t]+\\.go\\):\\([0-9]+\\)" gotest-ui-insertion-marker t)
- (let* ((file-basename (match-string 1))
- (file (gotest-ui-file-from-gopath (gotest-ui-test-package thing) file-basename)))
- (set-text-properties (match-beginning 0) (match-end 0)
- `(face gotest-ui-link-face
- gotest-ui-file ,file
- gotest-ui-line ,(match-string 2)
- keymap ,gotest-ui-click-map
- follow-link t
- ))))
- (set-marker gotest-ui-parse-marker gotest-ui-insertion-marker)))
-
-(defun gotest-ui-update-thing-output (thing output)
- (with-current-buffer (gotest-ui-ensure-output-buffer thing)
- (goto-char gotest-ui-insertion-marker)
- (let ((overwrites (split-string output "\r")))
- (insert (car overwrites))
- (dolist (segment (cdr overwrites))
- (let ((delete-to (point)))
- (forward-line 0)
- (delete-region (point) delete-to))
- (insert segment)))
- (set-marker gotest-ui-insertion-marker (point))
- (gotest-ui-ensure-parsed thing)))
-
-;; TODO: clean up buffers on kill
-
-;;;; Mode definition
-
-(defvar gotest-ui-mode-map
- (let ((m (make-sparse-keymap)))
- (suppress-keymap m)
- ;; key bindings go here
- (define-key m (kbd "TAB") 'gotest-ui-toggle-expanded)
- (define-key m (kbd "g") 'gotest-ui-rerun)
- (define-key m (kbd "RET") 'gotest-ui-open-file-at-point)
- m))
-
-(define-derived-mode gotest-ui-mode special-mode "go test UI"
- "Major mode for running go test with JSON output."
- (setq truncate-lines t)
- (setq buffer-read-only t)
- (setq-local line-move-visual t)
- (setq show-trailing-whitespace nil)
- (setq list-buffers-directory default-directory)
- (make-local-variable 'text-property-default-nonsticky)
- (push (cons 'keymap t) text-property-default-nonsticky))
-
-
-(defun gotest-ui--clear-buffer (buffer)
- (let ((dir default-directory))
- (with-current-buffer buffer
- (when (buffer-live-p gotest-ui--process-buffer)
- (kill-buffer gotest-ui--process-buffer))
- (kill-all-local-variables)
- (let ((buffer-read-only nil))
- (erase-buffer))
- (buffer-disable-undo)
- (setq-local default-directory dir))))
-
-(defun gotest-ui--setup-buffer (buffer name cmdline dir)
- (setq-local default-directory dir)
- (setq gotest-ui--cmdline cmdline
- gotest-ui--dir dir)
- (let ((ewoc (ewoc-create 'gotest-ui--pp-test nil nil t))
- (tests (make-hash-table :test #'equal)))
- (setq gotest-ui--tests tests)
- (setq gotest-ui--ewoc ewoc)
- ;; Drop in the first few ewoc nodes:
- (setq gotest-ui--status (gotest-ui--make-status ewoc cmdline dir))
- (gotest-ui-add-section gotest-ui--ewoc 'fail "Failed Tests:")
- (gotest-ui-add-section gotest-ui--ewoc 'run "Currently Running:")
- (gotest-ui-add-section gotest-ui--ewoc 'skip "Skipped:")
- (gotest-ui-add-section gotest-ui--ewoc 'pass "Passed Tests:"))
- ;; Set up the other buffers:
- (setq gotest-ui--stderr-process-buffer (generate-new-buffer (format " *%s (stderr)" name)))
- (with-current-buffer gotest-ui--stderr-process-buffer
- (setq gotest-ui--ui-buffer buffer))
- (setq gotest-ui--process-buffer (generate-new-buffer (format " *%s" name)))
- (with-current-buffer gotest-ui--process-buffer
- (setq gotest-ui--ui-buffer buffer)))
-
-(defun gotest-ui-add-section (ewoc state name)
- (let ((section (gotest-ui-section-create :title name :tests (list nil))))
- (setf (gotest-ui-section-node section)
- (ewoc-enter-last ewoc section))
- (push (cons state section) gotest-ui--section-alist)))
-
-(defun gotest-ui-sort-test-into-section (test previous-state)
- (let (invalidate-nodes)
- (when-let ((previous-section* (and previous-state
- (assoc previous-state gotest-ui--section-alist))))
- (let ((previous-section (cdr previous-section*)))
- (setf (gotest-ui-section-tests previous-section)
- (delete test (gotest-ui-section-tests previous-section)))
- (when (null (cdr (gotest-ui-section-tests previous-section)))
- (push (gotest-ui-section-node previous-section) invalidate-nodes))))
- ;; Drop the node from the buffer:
- (when-let (node (gotest-ui-thing-node test))
- (let ((buffer-read-only nil))
- (ewoc-delete gotest-ui--ewoc node))
- (setf (gotest-ui-thing-node test) nil))
-
- ;; Put it in the next secion:
- (when-let ((section* (assoc (gotest-ui-thing-status test)
- gotest-ui--section-alist)))
- (let* ((section (cdr section*))
- (insertion-cons (gotest-ui-section-tests section)))
- (while (and (cdr insertion-cons)
- (gotest-ui-test->= test (cadr insertion-cons)))
- (setq insertion-cons (cdr insertion-cons)))
- (rplacd insertion-cons (cons test (cdr insertion-cons)))
- (let ((insertion-node (if (car insertion-cons)
- (gotest-ui-thing-node (car insertion-cons))
- (gotest-ui-section-node section))))
- (setf (gotest-ui-thing-node test)
- (ewoc-enter-after gotest-ui--ewoc insertion-node test)))
- (when (null (cddr (gotest-ui-section-tests section)))
- (push (gotest-ui-section-node section) invalidate-nodes))))
- (unless (null invalidate-nodes)
- (apply 'ewoc-invalidate gotest-ui--ewoc invalidate-nodes))
- (gotest-ui-thing-node test)))
-
-;;;; Commands:
-
-(defun gotest-ui-toggle-expanded ()
- "Toggle expandedness of a test/package node"
- (interactive)
- (let* ((node (ewoc-locate gotest-ui--ewoc (point)))
- (data (ewoc-data node)))
- (when (and data (gotest-ui-thing-p data))
- (setf (gotest-ui-thing-expanded-p data)
- (not (gotest-ui-thing-expanded-p data)))
- (ewoc-invalidate gotest-ui--ewoc node))))
-
-(defun gotest-ui-rerun ()
- (interactive)
- (gotest-ui gotest-ui--cmdline :dir gotest-ui--dir))
-
-;;;; Displaying the data:
-
-(defvar-local gotest-ui--tests nil)
-(defvar-local gotest-ui--section-alist nil)
-(defvar-local gotest-ui--ewoc nil)
-(defvar-local gotest-ui--status nil)
-(defvar-local gotest-ui--process-buffer nil)
-(defvar-local gotest-ui--stderr-process-buffer nil)
-(defvar-local gotest-ui--ui-buffer nil)
-(defvar-local gotest-ui--process nil)
-(defvar-local gotest-ui--stderr-process nil)
-(defvar-local gotest-ui--cmdline nil)
-(defvar-local gotest-ui--dir nil)
-
-(cl-defun gotest-ui (cmdline &key dir)
- (let* ((dir (or dir default-directory))
- (name (format "*go test: %s in %s" (s-join " " cmdline) dir))
- (buffer (get-buffer-create name)))
- (unless (eql buffer (current-buffer))
- (display-buffer buffer))
- (with-current-buffer buffer
- (let ((default-directory dir))
- (gotest-ui--clear-buffer buffer)
- (gotest-ui-mode)
- (gotest-ui--setup-buffer buffer name cmdline dir))
- (setq gotest-ui--stderr-process
- (make-pipe-process :name (s-concat name "(stderr)")
- :buffer gotest-ui--stderr-process-buffer
- :sentinel #'gotest-ui--stderr-process-sentinel
- :filter #'gotest-ui-read-stderr))
- (setq gotest-ui--process
- (make-process :name name
- :buffer gotest-ui--process-buffer
- :sentinel #'gotest-ui--process-sentinel
- :filter #'gotest-ui-read-stdout
- :stderr gotest-ui--stderr-process
- :command cmdline)))))
-
-(defun gotest-ui-pp-status (status)
- (propertize (format "%s" status)
- 'face
- (case status
- (fail 'gotest-ui-fail-face)
- (skip 'gotest-ui-skip-face)
- (pass 'gotest-ui-pass-face)
- (otherwise 'default))))
-
-(defun gotest-ui--pp-test-output (test)
- (with-current-buffer (gotest-ui-ensure-output-buffer test)
- (propertize (buffer-substring (point-min) (point-max))
- 'line-prefix "\t")))
-
-(defun gotest-ui--pp-test (test)
- (cond
- ((gotest-ui-section-p test)
- (unless (null (cdr (gotest-ui-section-tests test)))
- (insert "\n" (gotest-ui-section-title test) "\n")))
- ((gotest-ui-status-p test)
- (insert (gotest-ui-pp-status (gotest-ui-status-state test)))
- (insert (format " %s in %s\n\n"
- (gotest-ui-status-cmdline test)
- (gotest-ui-status-dir test)))
- (unless (zerop (length (gotest-ui-status-output test)))
- (insert (format "\n\n%s" (gotest-ui-status-output test)))))
- ((gotest-ui-test-p test)
- (let ((status (gotest-ui-thing-status test))
- (package (gotest-ui-test-package test))
- (name (gotest-ui-thing-name test)))
- (insert (gotest-ui-pp-status status))
- (insert " ")
- (insert (if name
- (format "%s.%s" package name)
- package))
- (when-let ((elapsed (gotest-ui-thing-elapsed test)))
- (insert (format " (%.3fs)" elapsed)))
- (when-let ((reason (gotest-ui-test-reason test)))
- (insert (format " [%s]" reason))))
- (when (and (gotest-ui-thing-expanded-p test)
- (> (length (gotest-ui--pp-test-output test)) 0))
- (insert "\n")
- (insert (gotest-ui--pp-test-output test)))
- (insert "\n"))))
-
-;;;; Handling input:
-
-(defun gotest-ui--process-sentinel (proc event)
- (let* ((process-buffer (process-buffer proc))
- (ui-buffer (with-current-buffer process-buffer gotest-ui--ui-buffer))
- (inhibit-quit t))
- (with-local-quit
- (with-current-buffer ui-buffer
- (cond
- ((string= event "finished\n")
- (gotest-ui-update-status 'pass))
- ((s-prefix-p "exited abnormally" event)
- (gotest-ui-update-status 'fail))
- (t
- (gotest-ui-update-status event)))))))
-
-(defun gotest-ui--stderr-process-sentinel (proc event)
- ;; ignore all events
- nil)
-
-(defun gotest-ui-read-stderr (proc input)
- (let* ((process-buffer (process-buffer proc))
- (ui-buffer (with-current-buffer process-buffer gotest-ui--ui-buffer))
- (inhibit-quit t))
- (with-local-quit
- (when (buffer-live-p process-buffer)
- (with-current-buffer process-buffer
- (gotest-ui-read-compiler-spew proc process-buffer ui-buffer input))))))
-
-(defun gotest-ui-read-stdout (proc input)
- (let* ((process-buffer (process-buffer proc))
- (ui-buffer (with-current-buffer process-buffer gotest-ui--ui-buffer))
- (inhibit-quit t))
- (with-local-quit
- (when (buffer-live-p process-buffer)
- (gotest-ui-read-json process-buffer (process-mark proc) input)))))
-
-(defun gotest-ui-read-json (process-buffer marker input)
- (with-current-buffer process-buffer
- (gotest-ui-read-json-1 process-buffer marker gotest-ui--ui-buffer input)))
-
-(defvar-local gotest-ui--current-failing-test nil)
-
-(defun gotest-ui-read-failing-package (ui-buffer)
- (when (looking-at "^# \\(.*\\)$")
- (let* ((package (match-string 1))
- test)
- (with-current-buffer ui-buffer
- (setq test (gotest-ui-ensure-test gotest-ui--ewoc package nil :status 'fail))
- (gotest-ui-maybe-expand test)
- (gotest-ui-sort-test-into-section test nil))
- (forward-line 1)
- test)))
-
-(defun gotest-ui-read-compiler-spew (proc process-buffer ui-buffer input)
- (with-current-buffer process-buffer
- (save-excursion
- (goto-char (point-max))
- (insert input)
- (goto-char (process-mark proc))
- (while (and (/= (point-max) (line-end-position)) ; incomplete line
- (/= (point-max) (point)))
- (cond
- (gotest-ui--current-failing-test
- (cond
- ((looking-at "^# \\(.*\\)$")
- (gotest-ui-read-failing-package ui-buffer))
- (t
- (let* ((line (buffer-substring (point) (line-end-position)))
- (test gotest-ui--current-failing-test))
- (forward-line 1)
- (set-marker (process-mark proc) (point))
- (with-current-buffer ui-buffer
- (gotest-ui-update-thing-output test (concat line "\n"))
- (ewoc-invalidate gotest-ui--ewoc (gotest-ui-thing-node test)))))))
- (t
- (let ((test (gotest-ui-read-failing-package ui-buffer)))
- (setq gotest-ui--current-failing-test test)
- (set-marker (process-mark proc) (point))
- (with-current-buffer ui-buffer
- (ewoc-invalidate gotest-ui--ewoc (gotest-ui-thing-node test))))))))))
-
-(defun gotest-ui-read-json-1 (process-buffer marker ui-buffer input)
- (with-current-buffer process-buffer
- (save-excursion
- ;; insert the chunk of output at the end
- (goto-char (point-max))
- (insert input)
-
- ;; try to read the next object (which is hopefully complete now):
- (let ((nodes
- (cl-loop
- for (node . continue) = (gotest-ui-read-test-event process-buffer marker ui-buffer)
- when node collect node into nodes
- while continue
- finally (return nodes))))
- (when nodes
- (with-current-buffer ui-buffer
- (apply #'ewoc-invalidate gotest-ui--ewoc
- (cl-remove-if-not (lambda (node) (marker-buffer (ewoc-location node))) (cl-remove-duplicates nodes)))))))))
-
-(defun gotest-ui-read-test-event (process-buffer marker ui-buffer)
- (goto-char marker)
- (when (= (point) (line-end-position))
- (forward-line 1))
- (case (char-after (point))
- (?\{
- ;; It's JSON:
- (condition-case err
- (let ((obj (json-read)))
- (set-marker marker (point))
- (with-current-buffer ui-buffer
- (cons (gotest-ui-update-test-status obj) t)))
- (json-error (cons nil nil))
- (wrong-type-argument
- (if (and (eql (cadr err) 'characterp)
- (eql (caddr err) :json-eof))
- ;; This is peaceful & we can ignore it:
- (cons nil nil)
- (signal 'wrong-type-argument err)))))
- (?\F
- ;; It's a compiler error:
- (when (looking-at "^FAIL\t\\(.*\\)\s+\\[\\([^]]+\\)\\]\n")
- (let* ((package-name (match-string 1))
- (reason (match-string 2))
- test node)
- (with-current-buffer ui-buffer
- (setq test (gotest-ui-ensure-test gotest-ui--ewoc package-name nil :status 'fail)
- node (gotest-ui-thing-node test))
- (setf (gotest-ui-test-reason test) reason)
- (gotest-ui-sort-test-into-section test nil)
- (gotest-ui-maybe-expand test))
- (forward-line 1)
- (set-marker marker (point))
- (cons node t))))
- (otherwise
- ;; We're done:
- (cons nil nil))))
-
-(defun gotest-ui-maybe-expand (test)
- (when (memq (gotest-ui-test-status test) gotest-ui-expand-test-statuses)
- (setf (gotest-ui-test-expanded-p test) t)))
-
-(defun gotest-ui-update-test-status (json)
- (let-alist json
- (let* ((action (intern .Action))
- (test (gotest-ui-ensure-test gotest-ui--ewoc .Package .Test))
- (previous-status (gotest-ui-thing-status test)))
- (case action
- (run
- (gotest-ui-sort-test-into-section test nil))
- (output (gotest-ui-update-thing-output test .Output))
- (pass
- (setf (gotest-ui-thing-status test) 'pass
- (gotest-ui-thing-elapsed test) .Elapsed)
- (gotest-ui-sort-test-into-section test previous-status)
- (gotest-ui-maybe-expand test))
- (fail
- (setf (gotest-ui-thing-status test) 'fail
- (gotest-ui-thing-elapsed test) .Elapsed)
- (gotest-ui-sort-test-into-section test previous-status)
- (gotest-ui-maybe-expand test))
- (skip
- (setf (gotest-ui-thing-status test) 'skip
- (gotest-ui-thing-elapsed test) .Elapsed)
- (gotest-ui-sort-test-into-section test previous-status)
- (gotest-ui-maybe-expand test))
- (otherwise
- (setq test nil)))
- (when test (gotest-ui-thing-node test)))))
-
-;;;; Commands for go-mode:
-
-(defun gotest-ui--command-line (&rest cmdline)
- (append gotest-ui-test-binary gotest-ui-test-args gotest-ui-additional-test-args
- cmdline))
-
-;;;###autoload
-(defun gotest-ui-current-test ()
- "Launch go test with the test that (point) is in."
- (interactive)
- (cl-destructuring-bind (test-suite test-name) (go-test--get-current-test-info)
- (let ((test-flag (if (> (length test-suite) 0) "-m" "-run")))
- (when test-name
- (gotest-ui (gotest-ui--command-line test-flag (s-concat test-name "$") "."))))))
-
-;;;###autoload
-(defun gotest-ui-current-file ()
- "Launch go test on the current buffer file."
- (interactive)
- (let* ((data (go-test--get-current-file-testing-data))
- (run-flag (s-concat "-run=" data "$")))
- (gotest-ui (gotest-ui--command-line run-flag "."))))
-
-;;;###autoload
-(defun gotest-ui-current-project ()
- "Launch go test on the current buffer's project."
- (interactive)
- (let ((default-directory (projectile-project-root)))
- (gotest-ui (gotest-ui--command-line "./..."))))
-
-(provide 'gotest-ui)
-
-;;; gotest-ui.el ends here
tools/emacs/lisp/init-func.el
@@ -1,19 +0,0 @@
-;;; init-func.el --- -*- lexical-binding: t -*-
-;;
-
-;;;###autoload
-(defun vde/el-load-dir (dir)
- "Load el files from the given folder `DIR'."
- (let ((files (directory-files dir nil "\.el$")))
- (while files
- (load-file (concat dir (pop files))))))
-
-;;;###autoload
-(defun vde/short-hostname ()
- "Return hostname in short (aka wakasu.local -> wakasu)."
- (string-match "[0-9A-Za-z-]+" system-name)
- (substring system-name (match-beginning 0) (match-end 0)))
-
-
-(provide 'init-func)
-;;; init-func.el ends here
tools/emacs/lisp/mcp-hub.el
@@ -1,313 +0,0 @@
-;;; mcp-hub.el --- manager mcp server -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2025 lizqwer scott
-
-;; Author: lizqwer scott <lizqwerscott@gmail.com>
-;; Keywords: ai, mcp
-
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'mcp)
-
-(defcustom mcp-hub-servers nil
- "Configuration for MCP servers.
-Each server configuration is a list of the form
- (NAME . (:command COMMAND :args ARGS)) or (NAME . (:url URL)), where:
-- NAME is a string identifying the server.
-- COMMAND is the command to start the server.
-- ARGS is a list of arguments passed to the command.
-- URL is a string arguments to connect sse mcp server."
- :group 'mcp-hub
- :type '(list (cons string (list symbol string))))
-
-(defun mcp-hub--start-server (server &optional inited-callback)
- "Start an MCP server with the given configuration.
-SERVER should be a cons cell of the form (NAME . CONFIG) where:
-- NAME is a string identifying the server
-- CONFIG is a plist containing either:
- - :command and :args for local servers
- - :url for remote servers
-
-Optional argument INITED-CALLBACK is a function called when the server
-has successfully initialized and tools are available. The callback
-receives no arguments."
- (apply #'mcp-connect-server
- (append (list (car server))
- (cdr server)
- (list :initial-callback
- #'(lambda (_)
- (mcp-hub-update))
- :tools-callback
- #'(lambda (_ _)
- (mcp-hub-update)
- (when inited-callback
- (funcall inited-callback)))
- :prompts-callback
- #'(lambda (_ _)
- (mcp-hub-update))
- :resources-callback
- #'(lambda (_ _)
- (mcp-hub-update))
- :error-callback
- #'(lambda (_ _)
- (mcp-hub-update))))))
-
-;;;###autoload
-(cl-defun mcp-hub-get-all-tool (&key asyncp categoryp)
- "Retrieve all available tools from connected MCP servers.
-This function collects all tools from currently connected MCP servers,
-filtering out any invalid entries. Each tool is created as a text tool
-that can be used for interaction.
-
-When ASYNCP is non-nil, the tools will be created asynchronously.
-
-When CATEGORYP is non-nil, the tools will be add to a category.
-
-Returns a list of text tools created from all valid tools across all
-connected servers. The list excludes any tools that couldn't be created
-due to missing or invalid names.
-
-Example:
- (mcp-hub-get-all-tool) ; Get all tools synchronously
- (mcp-hub-get-all-tool t) ; Get all tools asynchronously"
- (let ((res ))
- (maphash #'(lambda (name server)
- (when (and server
- (equal (mcp--status server)
- 'connected))
- (when-let* ((tools (mcp--tools server))
- (tool-names (mapcar #'(lambda (tool) (plist-get tool :name)) tools)))
- (dolist (tool-name tool-names)
- (push (let ((tool (mcp-make-text-tool name tool-name asyncp)))
- (if categoryp
- (plist-put
- tool
- :category
- (format "mcp-%s"
- name))
- tool))
- res)))))
- mcp-server-connections)
- (nreverse res)))
-
-;;;###autoload
-(defun mcp-hub-start-all-server (&optional callback servers)
- "Start all configured MCP servers.
-This function will attempt to start each server listed in `mcp-hub-servers'
-if it's not already running.
-
-Optional argument CALLBACK is a function to be called when all servers have
-either started successfully or failed to start.The callback receives no
-arguments.
-
-Optional argument SERVERS is a list of server names (strings) to filter which
-servers should be started. When nil, all configured servers are considered."
- (interactive)
- (let* ((servers-to-start (cl-remove-if (lambda (server)
- (or (not (cl-find (car server) servers :test #'string=))
- (gethash (car server) mcp-server-connections)))
- mcp-hub-servers))
- (total (length servers-to-start))
- (started 0))
- (if (zerop total)
- (progn
- (message "All MCP servers already running")
- (when callback (funcall callback)))
- (message "Starting %d MCP server(s)..." total)
- (dolist (server servers-to-start)
- (condition-case err
- (mcp-hub--start-server
- server
- (lambda ()
- (cl-incf started)
- (message "Started server %s (%d/%d)" (car server) started total)
- (when (and callback (>= started total))
- (funcall callback))))
- (error
- (message "Failed to start server %s: %s" (car server) err)
- (cl-incf started)
- (when (and callback (>= started total))
- (funcall callback))))))))
-
-;;;###autoload
-(defun mcp-hub-close-all-server ()
- "Stop all running MCP servers.
-This function will attempt to stop each server listed in `mcp-hub-servers'
-that is currently running."
- (interactive)
- (dolist (server mcp-hub-servers)
- (when (gethash (car server)
- mcp-server-connections)
- (mcp-stop-server (car server))))
- (mcp-hub-update))
-
-;;;###autoload
-(defun mcp-hub-restart-all-server ()
- "Restart all configured MCP servers.
-This function first stops all running servers, then starts them again.
-It's useful for applying configuration changes or recovering from errors."
- (interactive)
- (mcp-hub-close-all-server)
- (mcp-hub-start-all-server))
-
-(defun mcp-hub-get-servers ()
- "Retrieve status information for all configured servers.
-Returns a list of server statuses, where each status is a plist containing:
-- :name - The server's name
-- :status - Either `connected' or `stop'
-- :tools - Available tools (if connected)
-- :resources - Available resources (if connected)
-- :prompts - Available prompts (if connected)"
- (mapcar #'(lambda (server)
- (let ((name (car server)))
- (if-let* ((connection (gethash name mcp-server-connections)))
- (list :name name
- :type (mcp--connection-type connection)
- :status (mcp--status connection)
- :tools (mcp--tools connection)
- :resources (mcp--resources connection)
- :prompts (mcp--prompts connection))
- (list :name name :status 'stop))))
- mcp-hub-servers))
-
-(defun mcp-hub-update ()
- "Update the MCP Hub display with current server status.
-If called interactively, ARG is the prefix argument.
-When SILENT is non-nil, suppress any status messages.
-This function refreshes the *Mcp-Hub* buffer with the latest server information,
-including connection status, available tools, resources, and prompts."
- (interactive "P")
- (when-let* ((server-list (mcp-hub-get-servers))
- (server-show (mapcar #'(lambda (server)
- (let* ((name (plist-get server :name))
- (status (plist-get server :status)))
- (append (list name
- (symbol-name (plist-get server :type))
- (pcase status
- ('connected
- (propertize (symbol-name status)
- 'face 'success))
- ('error
- (propertize (symbol-name status)
- 'face 'error))
- (_
- (symbol-name status))))
- (if (equal status 'connected)
- (mapcar #'(lambda (x)
- (format "%d"
- (length x)))
- (list (plist-get server :tools)
- (plist-get server :resources)
- (plist-get server :prompts)))
- (list "nil" "nil" "nil")))))
- server-list)))
- (with-current-buffer (get-buffer-create "*Mcp-Hub*")
- (setq tabulated-list-entries
- (cl-mapcar #'(lambda (statu index)
- (list (format "%d" index)
- (vconcat statu)))
- server-show
- (number-sequence 1 (length server-list))))
- (tabulated-list-print t))))
-
-;;;###autoload
-(defun mcp-hub ()
- "View mcp hub server."
- (interactive)
- ;; start all server
- (when (and mcp-hub-servers
- (= (hash-table-count mcp-server-connections)
- 0))
- (mcp-hub-start-all-server))
- ;; show buffer
- (pop-to-buffer "*Mcp-Hub*" nil)
- (mcp-hub-mode))
-
-;;;###autoload
-(defun mcp-hub-start-server ()
- "Start the currently selected MCP server.
-This function starts the server that is currently highlighted in the *Mcp-Hub*
-buffer. It sets up callbacks for connection status, tools, prompts, and
-resources updates, and refreshes the hub view after starting the server."
- (interactive)
- (when-let* ((server (tabulated-list-get-entry))
- (name (elt server 0))
- (server-arg (cl-find name mcp-hub-servers :key #'car :test #'equal)))
- (mcp-hub--start-server server-arg)
- (mcp-hub-update)))
-
-;;;###autoload
-(defun mcp-hub-close-server ()
- "Stop the currently selected MCP server.
-This function stops the server that is currently highlighted in the *Mcp-Hub*
-buffer and updates the hub view to reflect the change in status."
- (interactive)
- (when-let* ((server (tabulated-list-get-entry))
- (name (elt server 0)))
- (mcp-stop-server name)
- (mcp-hub-update)))
-
-;;;###autoload
-(defun mcp-hub-restart-server ()
- "Restart the currently selected MCP server.
-This function stops and then starts the server that is currently highlighted
-in the *Mcp-Hub* buffer. It's useful for applying configuration changes or
-recovering from errors."
- (interactive)
- (mcp-hub-close-server)
- (mcp-hub-start-server))
-
-;;;###autoload
-(defun mcp-hub-view-log ()
- "View the event log for the currently selected MCP server.
-This function opens a buffer showing the event log for the server that is
-currently highlighted in the *Mcp-Hub* buffer."
- (interactive)
- (when-let* ((server (tabulated-list-get-entry))
- (name (elt server 0)))
- (switch-to-buffer (format "*%s events*"
- name))))
-
-(define-derived-mode mcp-hub-mode tabulated-list-mode "Mcp Hub"
- "A major mode for viewing a list of mcp server."
- (setq-local revert-buffer-function #'mcp-hub-update)
- (setq tabulated-list-format
- [("Name" 18 t)
- ("Type" 10 t)
- ("Status" 15 t)
- ("Tools" 10 t)
- ("Resources" 10 t)
- ("Prompts" 10 t)])
- (setq tabulated-list-padding 2)
- (setq tabulated-list-sort-key '("Name" . nil))
- (tabulated-list-init-header)
-
- (keymap-set mcp-hub-mode-map "l" #'mcp-hub-view-log)
- (keymap-set mcp-hub-mode-map "s" #'mcp-hub-start-server)
- (keymap-set mcp-hub-mode-map "k" #'mcp-hub-close-server)
- (keymap-set mcp-hub-mode-map "r" #'mcp-hub-restart-server)
- (keymap-set mcp-hub-mode-map "S" #'mcp-hub-start-all-server)
- (keymap-set mcp-hub-mode-map "R" #'mcp-hub-restart-all-server)
- (keymap-set mcp-hub-mode-map "K" #'mcp-hub-close-all-server)
-
- (mcp-hub-update))
-
-(provide 'mcp-hub)
-;;; mcp-hub.el ends here
tools/emacs/lisp/mcp.el
@@ -1,973 +0,0 @@
-;;; mcp.el --- Model Context Protocol -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2025 lizqwer scott
-
-;; Author: lizqwer scott <lizqwerscott@gmail.com>
-;; Version: 0.1.0
-;; Package-Requires: ((emacs "30.1") (jsonrpc "1.0.25"))
-;; Keywords: ai, mcp
-;; URL: https://github.com/lizqwerscott/mcp.el
-
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;
-
-;;; Code:
-
-(require 'jsonrpc)
-(require 'cl-lib)
-(require 'url)
-
-(defconst *MCP-VERSION* "2024-11-05"
- "MCP support version.")
-
-(defcustom mcp-server-start-time 60
- "The Seconds of mcp server start time."
- :group 'mcp
- :type 'integer)
-
-(defcustom mcp-server-wait-initial-time 2
- "Seconds to wait after server init before fetching MCP resources.
-
-This delay is applied after server initialization completes, but
-before requesting tools, prompts and resources. Gives the server
-time to fully initialize all components before handling requests."
- :group 'mcp
- :type 'integer)
-
-(defcustom mcp-log-level 'info
- "The min log level for mcp server.
-Available levels:
-- debug: Detailed debugging information (function entry/exit points)
-- info: General informational messages (operation progress updates)
-- notice: Normal but significant events (configuration changes)
-- warning: Warning conditions (deprecated feature usage)
-- error: Error conditions (operation failures)
-- critical: Critical conditions (system component failures)
-- alert: Action must be taken immediately (data corruption detected)
-- emergency: System is unusable (complete system failure)"
- :group 'mcp
- :type '(choice (const :tag "debug" debug)
- (const :tag "info" info)
- (const :tag "notice" notice)
- (const :tag "warning" warning)
- (const :tag "error" error)
- (const :tag "critical" critical)
- (const :tag "alert" alert)
- (const :tag "emergency" emergency)))
-
-(defclass mcp-process-connection (jsonrpc-process-connection)
- ((connection-type
- :initarg :connection-type
- :accessor mcp--connection-type)
- (-status
- :initform 'init
- :accessor mcp--status)
- (-capabilities
- :initform nil
- :accessor mcp--capabilities)
- (-serverinfo
- :initform nil
- :accessor mcp--server-info)
- (-prompts
- :initform nil
- :accessor mcp--prompts)
- (-tools
- :initform nil
- :accessor mcp--tools)
- (-resources
- :initform nil
- :accessor mcp--resources))
- :documentation "A MCP connection over an Emacs process.")
-
-(defclass mcp-sse-process-connection (mcp-process-connection)
- ((-host
- :initarg :host
- :accessor mcp--host)
- (-port
- :initarg :port
- :accessor mcp--port)
- (-tls
- :initarg :tls
- :accessor mcp--tls)
- (-endpoint
- :initform nil
- :accessor mcp--endpoint))
- :documentation "A sse MCP connection over an Emacs process.")
-
-(defclass mcp-stdio-process-connection (mcp-process-connection)
- ()
- :documentation "A stdio MCP connection over an Emacs process.")
-
-(cl-defmethod initialize-instance :after ((_ mcp-process-connection) slots)
- "Init mcp process connection."
- (cl-destructuring-bind (&key ((:process proc)) &allow-other-keys) slots
- (set-process-filter proc #'mcp--process-filter)))
-
-(cl-defmethod jsonrpc-connection-send ((connection mcp-process-connection)
- &rest args
- &key
- id
- method
- _params
- (_result nil result-supplied-p)
- error
- _partial)
- "Send JSON-RPC message to CONNECTION.
-CONNECTION is an MCP process connection instance. ARGS is a plist
-containing the message components:
-
-METHOD - Method name (string, symbol or keyword)
-PARAMS - Parameters for the method (optional)
-ID - Request ID (optional)
-RESULT - Response result (for replies)
-error - Error object (for error replies)
-partial - Partial response flag (optional)
-
-For requests, both :method and :id should be provided.
-For notifications, only :method is required.
-For replies, either :_result or :error should be provided.
-
-The message is sent differently based on connection type:
-- SSE connections use HTTP POST requests
-- Stdio connections write directly to the process"
- (when method
- ;; sanitize method into a string
- (setq args
- (plist-put args :method
- (cond ((keywordp method) (substring (symbol-name method) 1))
- ((symbolp method) (symbol-name method))
- ((stringp method) method)
- (t (error "[jsonrpc] invalid method %s" method))))))
- (let* ((kind (cond ((or result-supplied-p error) 'reply)
- (id 'request)
- (method 'notification)))
- (converted (jsonrpc-convert-to-endpoint connection args kind))
- (json (jsonrpc--json-encode converted)))
- (pcase (mcp--connection-type connection)
- ('sse
- (let ((url-request-method "POST")
- (url-request-extra-headers
- '(("Content-Type" . "application/json")))
- (url-request-data (encode-coding-string
- json
- 'utf-8))
- (url (format "%s://%s:%s%s"
- (if (mcp--tls connection) "https" "http")
- (mcp--host connection)
- (mcp--port connection)
- (mcp--endpoint connection))))
- (url-retrieve url
- #'(lambda (_)
- (when (buffer-live-p (current-buffer))
- (goto-char (point-min))
- ;; (when (search-forward "\n\n" nil t)
- ;; (let* ((headers (buffer-substring (point-min) (point)))
- ;; (body (buffer-substring (point) (point-max)))
- ;; (response-code (string-match "HTTP/.* \\([0-9]+\\)" headers)))))
- (kill-buffer))))))
- ('stdio
- (process-send-string
- (jsonrpc--process connection)
- (format "%s\r\n" json))))
- (jsonrpc--event
- connection
- 'client
- :json json
- :kind kind
- :message args
- :foreign-message converted)))
-
-(defvar mcp--in-process-filter nil
- "Non-nil if inside `mcp--process-filter'.")
-
-(cl-defun mcp--process-filter (proc string)
- "Called when new data STRING has arrived for PROC."
- (when mcp--in-process-filter
- ;; Problematic recursive process filters may happen if
- ;; `jsonrpc-connection-receive', called by us, eventually calls
- ;; client code which calls `process-send-string' (which see) to,
- ;; say send a follow-up message. If that happens to writes enough
- ;; bytes for pending output to be received, we will lose JSONRPC
- ;; messages. In that case, remove recursiveness by re-scheduling
- ;; ourselves to run from within a timer as soon as possible
- ;; (bug#60088)
- (run-at-time 0 nil #'mcp--process-filter proc string)
- (cl-return-from mcp--process-filter))
- (when (buffer-live-p (process-buffer proc))
- (with-current-buffer (process-buffer proc)
- (let* ((conn (process-get proc 'jsonrpc-connection))
- (queue (or (process-get proc 'jsonrpc-mqueue) nil))
- (buf (or (process-get proc 'jsonrpc-pending)
- (plist-get (process-put
- proc 'jsonrpc-pending
- (generate-new-buffer " *mcp-jsonrpc-pending*"))
- 'jsonrpc-pending)))
- (data (with-current-buffer buf
- (goto-char (point-max))
- (insert string)
- (buffer-string)))
- (type (mcp--connection-type conn))
- (parsed-messages nil)
- (lines (split-string data "\n"))
- (parsed-index 0)
- (endpoint-waitp nil)
- (line-index 0))
- (dolist (line lines)
- (pcase type
- ('sse
- (cond
- ((and (<= (+ line-index 1) (length lines))
- (string-prefix-p "event:" (elt lines (+ line-index 1)))))
- ((string-prefix-p "event: endpoint" line)
- (setq endpoint-waitp t))
- ((string-prefix-p "data: " line)
- (let ((json-str (if (and endpoint-waitp
- (string-match "http://[^/]+\\(/[^[:space:]]+\\)" line))
- (match-string 1 line)
- (string-trim (substring line 6)))))
- (unless (string-empty-p json-str)
- (if endpoint-waitp
- (setf (mcp--endpoint conn) json-str)
- (push (cons parsed-index json-str) parsed-messages)
- (cl-incf parsed-index)))))
- ((and (mcp--endpoint conn)
- (not (or (string-prefix-p "2d" line)
- (string-prefix-p ": ping" line)
- (string-prefix-p "event: message" line)))
- (not (with-current-buffer buf (= (point-min) (point-max)))))
- (let ((json-str (string-trim line)))
- (unless (string-empty-p json-str)
- (push (cons parsed-index json-str) parsed-messages)
- (cl-incf parsed-index))))))
- ('stdio
- (let ((json-str (string-trim line)))
- (unless (string-empty-p json-str)
- (push (cons parsed-index json-str) parsed-messages)
- (cl-incf parsed-index)))))
- (cl-incf line-index))
- (setq parsed-messages (nreverse parsed-messages))
-
- (with-current-buffer buf (erase-buffer))
- ;; Add messages to MQUEUE
- (dolist (msg parsed-messages)
- (pcase-let ((`(,_index . ,json-str) msg))
- (let ((json nil)
- (json-str (with-current-buffer buf
- (if (= (point-min) (point-max))
- json-str
- (goto-char (point-max))
- (insert json-str)
- (buffer-string)))))
- (condition-case-unless-debug err
- (setq json (json-parse-string json-str
- :object-type 'plist
- :null-object nil
- :false-object :json-false))
- (json-parse-error
- ;; parse error and not because of incomplete json
- (jsonrpc--warn "Invalid JSON: %s\t %s" (cdr err) json-str))
- (json-end-of-file
- ;; Save remaining data to pending for next processing
- (with-current-buffer buf
- (goto-char (point-max))
- (insert json-str)
- (process-put proc 'jsonrpc-pending buf))))
- (when json
- (with-current-buffer buf (erase-buffer))
- (when (listp json)
- (setq json (plist-put json :jsonrpc-json json-str))
- (push json queue))))))
-
- ;; Save updated queue
- (process-put proc 'jsonrpc-mqueue queue)
-
- ;; Dispatch messages in timer
- (cl-loop with time = (current-time)
- for msg = (pop queue) while msg
- do (let ((timer (timer-create)))
- (timer-set-time timer time)
- (timer-set-function timer
- (lambda (conn msg)
- (with-temp-buffer
- (jsonrpc-connection-receive conn msg)))
- (list conn msg))
- (timer-activate timer)))
-
- ;; Save final queue (might have been consumed by timer pop)
- (process-put proc 'jsonrpc-mqueue queue)))))
-
-(defun mcp--sse-connect (process host port path)
- "Establish SSE connection to server.
-PROCESS is the network process object. HOST and PORT specify the
-server address. PATH is the endpoint path for SSE connection.
-Sends HTTP GET request with SSE headers to initiate the event
-stream connection. Used internally by MCP for SSE-based JSON-RPC
-communication."
- (process-send-string process
- (concat
- (format "GET %s HTTP/1.1\r\n"
- path)
- (format "Host: %s:%s\r\n"
- host
- port)
- "Accept: text/event-stream\r\n"
- "Cache-Control: no-cache\r\n"
- "Connection: keep-alive\r\n\r\n")))
-
-(cl-defun mcp-notify (connection method &optional (params nil))
- "Send notification to CONNECTION without expecting response.
-METHOD is the notification name (string or symbol). PARAMS is an
-optional plist of parameters.
-This is a thin wrapper around =jsonrpc-connection-send' that
-omits the :id parameter to indicate it's a notification rather
-than a request."
- (apply #'jsonrpc-connection-send
- `(,connection
- :method ,method
- ,@(when params
- (list :params params)))))
-
-(defvar mcp-server-connections (make-hash-table :test #'equal)
- "Mcp server process.")
-
-(defun mcp-request-dispatcher (name method params)
- "Default handler for MCP server requests.
-NAME identifies the server connection. METHOD is the requested
-method name. PARAMS contains the method parameters.
-
-This basic implementation just logs the request. Applications
-should override this to implement actual request handling."
- (message "%s Received request: method=%s, params=%s" name method params))
-
-(defun mcp-notification-dispatcher (connection name method params)
- "Handle notifications from MCP server.
-CONNECTION is the JSON-RPC connection object. NAME identifies the
-server. METHOD is the notification name. PARAMS contains the
-notification data."
- (pcase method
- ('notifications/message
- (cond ((or (plist-member (mcp--capabilities connection) :logging)
- (and (plist-member params :level)
- (plist-member params :data)))
- (cl-destructuring-bind (&key level data &allow-other-keys) params
- (let ((logger (plist-get params :logger)))
- (message "[mcp][%s][%s]%s: %s"
- name
- level
- (if logger
- (format "[%s]" logger)
- "")
- data))))))
- (_
- (message "%s Received notification: method=%s, params=%s" name method params))))
-
-(defun mcp-on-shutdown (name)
- "When NAME mcp server shutdown."
- (message "%s connection shutdown" name))
-
-(defun mcp--parse-http-url (url)
- "Parse HTTP/HTTPS URL into connection components.
-URL should be a string in format http(s)://host[:port][/path].
-
-Returns a plist with connection parameters:
-:tls - Boolean indicating HTTPS (t) or HTTP (nil)
-:host - Server hostname (string)
-:port - Port number (integer, defaults to 80/443)
-:path - URL path component (string)
-
-Returns nil if URL is invalid or not HTTP/HTTPS."
- (when-let* ((url (url-generic-parse-url url))
- (type (url-type url))
- (host (url-host url))
- (filename (url-filename url)))
- (when (or (string= type "http")
- (string= type "https"))
- (let ((port (url-port url))
- (tls (string= "https" type)))
- (list :tls tls
- :host host
- :port (if port
- port
- (if tls
- 443
- 80))
- :path filename)))))
-
-;;;###autoload
-(cl-defun mcp-connect-server (name &key command args url env initial-callback
- tools-callback prompts-callback
- resources-callback error-callback)
- "Connect to an MCP server with NAME, COMMAND, and ARGS or URL.
-
-NAME is a string representing the name of the server.
-COMMAND is a string representing the command to start the server
-in stdio mcp server.
-ARGS is a list of arguments to pass to the COMMAND.
-URL is a string arguments to connect sse mcp server.
-ENV is a plist argument to set mcp server env.
-
-INITIAL-CALLBACK is a function called when the server completes
-the connection.
-TOOLS-CALLBACK is a function called to handle the list of tools
-provided by the server.
-PROMPTS-CALLBACK is a function called to handle the list of prompts
-provided by the server.
-RESOURCES-CALLBACK is a function called to handle the list of
-resources provided by the server.
-ERROR-CALLBACK is a function to call on error.
-
-This function creates a new process for the server, initializes a connection,
-and sends an initialization message to the server. The connection is stored
-in the `mcp-server-connections` hash table for future reference."
- (unless (gethash name mcp-server-connections)
- (when-let* ((server-config (cond (command
- (list :connection-type 'stdio
- :command command
- :args args))
- (url
- (when-let* ((res (mcp--parse-http-url url)))
- (plist-put res
- :connection-type 'sse)))))
- (connection-type (plist-get server-config :connection-type))
- (buffer-name (format "*Mcp %s server*" name))
- (process-name (format "mcp-%s-server" name))
- (process (pcase connection-type
- ('sse
- (get-buffer-create buffer-name)
- (open-network-stream process-name
- buffer-name
- (plist-get server-config :host)
- (plist-get server-config :port)
- :type (if (plist-get server-config :tls)
- 'tls
- 'network)))
- ('stdio
- (let ((env (mapcar #'(lambda (item)
- (pcase-let* ((`(,key ,value) item))
- (let ((key (symbol-name key)))
- (list (substring key 1)
- (format "%s" value)))))
- (seq-partition env 2)))
- (process-environment (copy-sequence process-environment)))
- (when env
- (dolist (elem env)
- (setenv (car elem) (cadr elem))))
- (make-process
- :name name
- :command (append (list command)
- (plist-get server-config :args))
- :connection-type 'pipe
- :coding 'utf-8-emacs-unix
- ;; :noquery t
- :stderr (get-buffer-create
- (format "*%s stderr*" name))
- ;; :file-handler t
- ))))))
- (when (equal connection-type 'sse)
- (mcp--sse-connect process
- (plist-get server-config :host)
- (plist-get server-config :port)
- (plist-get server-config :path)))
- (let ((connection (apply #'make-instance
- `(,(pcase connection-type
- ('sse
- 'mcp-sse-process-connection)
- ('stdio
- 'mcp-stdio-process-connection))
- :connection-type ,connection-type
- :name ,name
- :process ,process
- :request-dispatcher ,(lambda (_ method params)
- (funcall #'mcp-request-dispatcher name method params))
- :notification-dispatcher ,(lambda (connection method params)
- (funcall #'mcp-notification-dispatcher connection name method params))
- :on-shutdown ,(lambda (_)
- (funcall #'mcp-on-shutdown name))
- ,@(when (equal connection-type 'sse)
- (list :host (plist-get server-config :host)
- :port (plist-get server-config :port)
- :tls (plist-get server-config :tls))))))
- (initial-use-time 0)
- (initial-timer nil))
- ;; Initialize connection
- (puthash name connection mcp-server-connections)
- (when (equal connection-type 'sse)
- (setf (mcp--status connection)
- 'waitendpoint))
- ;; Send the Initialize message
- (setf initial-timer
- (run-with-idle-timer
- 1
- t
- #'(lambda ()
- (cl-incf initial-use-time)
- (if (jsonrpc-running-p connection)
- (when (or (equal connection-type 'stdio)
- (and (equal connection-type 'sse)
- (mcp--endpoint connection)))
- (cancel-timer initial-timer)
- (mcp-async-initialize-message
- connection
- #'(lambda (protocolVersion serverInfo capabilities)
- (if (string= protocolVersion *MCP-VERSION*)
- (progn
- (message "[mcp] Connected! Server `MCP (%s)' now managing." (jsonrpc-name connection))
- (setf (mcp--capabilities connection) capabilities
- (mcp--server-info connection) serverInfo)
- ;; Notify server initialized
- (mcp-notify connection
- :notifications/initialized)
- ;; handle logging
- (when (plist-member capabilities :logging)
- (mcp-async-set-log-level connection mcp-log-level))
- (when initial-callback
- (funcall initial-callback connection))
- (run-with-idle-timer mcp-server-wait-initial-time
- nil
- #'(lambda ()
- ;; Get prompts
- (when (plist-member capabilities :prompts)
- (mcp-async-list-prompts connection prompts-callback))
- ;; Get tools
- (when (plist-member capabilities :tools)
- (mcp-async-list-tools connection tools-callback))
- ;; Get resources
- (when (plist-member capabilities :resources)
- (mcp-async-list-resources connection resources-callback)))
- )
- (setf (mcp--status connection)
- 'connected))
- (progn
- (message "[mcp] Error %s server protocolVersion(%s) not support, client Version: %s."
- (jsonrpc-name connection)
- protocolVersion
- *MCP-VERSION*)
- (mcp-stop-server (jsonrpc-name connection)))))
- #'(lambda (code message)
- (when error-callback
- (funcall error-callback code message))
- (setf (mcp--status connection)
- 'error)
- (message "Sadly, mpc server reports %s: %s"
- code message)))
- (when (> initial-use-time mcp-server-start-time)
- (mcp-stop-server name)
- (cancel-timer initial-timer)
- (message "Sadly: mcp server start error timeout")))
- (cancel-timer initial-timer)
- (when error-callback
- (funcall error-callback -1 "mcp server process start error")
- (setf (mcp--status connection)
- 'error)
- (message "Sadly, %s mcp server process start error" name))))))))))
-
-;;;###autoload
-(defun mcp-stop-server (name)
- "Stop the MCP server with the given NAME.
-If the server is running, it will be shutdown and its connection will be removed
-from `mcp-server-connections'. If no server with the given NAME is found,
-a message will be displayed indicating that the server is not running."
- (if-let* ((connection (gethash name mcp-server-connections)))
- (progn
- (jsonrpc-shutdown connection)
- (setf (gethash name mcp-server-connections) nil))
- (message "mcp %s server not started" name)))
-
-(defun mcp--parse-tool-args (properties required)
- "Parse tool arguments from PROPERTIES and REQUIRED lists.
-
-PROPERTIES is a plist of tool argument properties.
-REQUIRED is a list of required argument names.
-
-The function processes each argument in PROPERTIES, marking optional arguments
-if they are not in REQUIRED. Each argument is parsed into a structured plist
-with :name, :type, and :optional fields.
-
-Returns a list of parsed argument plists."
- (let ((need-length (- (/ (length properties) 2)
- (length required))))
- (cl-mapcar #'(lambda (arg-value required-name)
- (pcase-let* ((`(,key ,value) arg-value))
- `( :name ,(substring (symbol-name key) 1)
- ,@value
- ,@(unless required-name
- `(:optional t)))))
- (seq-partition properties 2)
- (append required
- (when (> need-length 0)
- (make-list need-length nil))))))
-
-
-(defun mcp--parse-tool-call-result (res)
- "Parse the result of a tool call from RES.
-
-RES is a plist representing the tool call result.
-
-The function extracts text content from the result, concatenating it into
-a single string if multiple text entries are present.
-
-Returns the concatenated text or nil if no text content is found."
- (string-join
- (cl-remove-if #'null
- (mapcar #'(lambda (content)
- (when (string= "text" (plist-get content :type))
- (plist-get content :text)))
- (plist-get res :content)))
- "\n"))
-
-(defun mcp--generate-tool-call-args (args properties)
- "Generate tool call arguments from ARGS and PROPERTIES.
-
-ARGS is a list of argument values provided by the caller.
-PROPERTIES is a plist of tool argument properties.
-
-The function matches ARGS to PROPERTIES, filling in default values for missing
-optional arguments. It ensures the generated arguments match the tool's schema.
-
-Returns a plist of argument names and values ready for tool invocation."
- (let ((need-length (- (/ (length properties) 2)
- (length args))))
- (apply #'append
- (cl-mapcar #'(lambda (arg value)
- (when-let* ((value (if value
- value
- (plist-get (cl-second arg)
- :default))))
- (list (cl-first arg)
- value)))
- (seq-partition properties 2)
- (append args
- (when (> need-length 0)
- (make-list need-length nil)))))))
-
-;;;###autoload
-(defun mcp-make-text-tool (name tool-name &optional asyncp)
- "Create a `gptel' tool with the given NAME, TOOL-NAME, and ASYNCP.
-
-NAME is the name of the server connection.
-TOOL-NAME is the name of the tool to be created.
-
-Currently, only synchronous messages are supported.
-
-This function retrieves the tool definition from the server connection,
-constructs a basic tool with the appropriate properties, and returns it.
-The tool is configured to handle input arguments, call the server, and process
-the response to extract and return text content."
- (when-let* ((connection (gethash name mcp-server-connections))
- (tools (mcp--tools connection))
- (tool (cl-find tool-name tools :test #'equal :key #'(lambda (tool) (plist-get tool :name)))))
- (cl-destructuring-bind (&key description ((:inputSchema input-schema)) &allow-other-keys) tool
- (cl-destructuring-bind (&key properties required &allow-other-keys) input-schema
- (list
- :function (if asyncp
- #'(lambda (callback &rest args)
- (when (< (length args) (length required))
- (error "Error: args not match: %s -> %s" required args))
- (if-let* ((connection (gethash name mcp-server-connections)))
- (mcp-async-call-tool connection
- tool-name
- (mcp--generate-tool-call-args args properties)
- #'(lambda (res)
- (funcall callback
- (mcp--parse-tool-call-result res)))
- #'(lambda (code message)
- (funcall callback
- (format "call %s tool error with %s: %s"
- tool-name
- code
- message))))
- (error "Error: %s server not connect" name)))
- #'(lambda (&rest args)
- (when (< (length args) (length required))
- (error "Error: args not match: %s -> %s" required args))
- (if-let* ((connection (gethash name mcp-server-connections)))
- (if-let* ((res (mcp-call-tool connection
- tool-name
- (mcp--generate-tool-call-args args properties))))
- (mcp--parse-tool-call-result res)
- (error "Error: call %s tool error" tool-name))
- (error "Error: %s server not connect" name))))
- :name tool-name
- :async asyncp
- :description description
- :args
- (mcp--parse-tool-args properties (or required '())))))))
-
-(defun mcp-async-set-log-level (connection log-level)
- "Asynchronously set the log level for the MCP server.
-
-CONNECTION is the MCP connection object.
-LOG-LEVEL is the desired log level, which must be one of:
-- `debug': Detailed debugging information (function entry/exit points)
-- `info': General informational messages (operation progress updates)
-- `notice': Normal but significant events (configuration changes)
-- `warning': Warning conditions (deprecated feature usage)
-- `error': Error conditions (operation failures)
-- `critical': Critical conditions (system component failures)
-- `alert': Action must be taken immediately (data corruption detected)
-- `emergency': System is unusable (complete system failure)
-
-On success, displays a message confirming the log level change.
-On error, displays an error message with the server's response code and message."
- (jsonrpc-async-request connection
- :logging/setLevel
- (list :level (format "%s" log-level))
- :success-fn
- #'(lambda (res)
- (message "[mcp] setLevel success: %s" res))
- :error-fn (jsonrpc-lambda (&key code message _data)
- (message "Sadly, mpc server reports %s: %s"
- code message))))
-
-(defun mcp-async-ping (connection)
- "Send an asynchronous ping request to the MCP server via CONNECTION.
-
-The function uses `jsonrpc-async-request' to send a ping request.
-On success, it displays a message with the response.
-On error, it displays an error message with the code from the server."
- (jsonrpc-async-request connection
- :ping
- nil
- :success-fn
- #'(lambda (res)
- (message "[mcp] ping success: %s" res))
- :error-fn (jsonrpc-lambda (&key code message _data)
- (message "Sadly, mpc server reports %s: %s"
- code message))))
-
-(defun mcp-async-initialize-message (connection callback &optional error-callback)
- "Sending an `initialize' request to the CONNECTION.
-
-CONNECTION is the MCP connection object.
-CALLBACK is a function to call upon successful initialization.
-ERROR-CALLBACK is an optional function to call if an error occurs.
-
-This function sends an `initialize' request to the server
-with the client's capabilities and version information."
- (jsonrpc-async-request connection
- :initialize
- (list :protocolVersion "2024-11-05"
- :capabilities '(:roots (:listChanged t))
- :clientInfo '(:name "mcp-emacs" :version "0.1.0"))
- :success-fn
- #'(lambda (res)
- (cl-destructuring-bind (&key protocolVersion serverInfo capabilities &allow-other-keys) res
- (funcall callback protocolVersion serverInfo capabilities)))
- :error-fn
- (jsonrpc-lambda (&key code message _data)
- (if error-callback
- (funcall error-callback code message)
- (message "Sadly, mpc server reports %s: %s"
- code message)))))
-
-(defun mcp-async-list-tools (connection &optional callback error-callback)
- "Get a list of tools from the MCP server using the provided CONNECTION.
-
-CONNECTION is the MCP connection object.
-CALLBACK is a function to call with the result of the request.
-ERROR-CALLBACK is an optional function to call if the request fails.
-
-This function sends a request to the server to list available tools.
-The result is stored in the `mcp--tools' slot of the CONNECTION object."
- (jsonrpc-async-request connection
- :tools/list
- '(:cursor "")
- :success-fn
- #'(lambda (res)
- (cl-destructuring-bind (&key tools &allow-other-keys) res
- (setf (mcp--tools connection)
- tools)
- (when callback
- (funcall callback connection tools))))
- :error-fn
- (jsonrpc-lambda (&key code message _data)
- (if error-callback
- (funcall error-callback code message)
- (message "Sadly, mpc server reports %s: %s"
- code message)))))
-
-(defun mcp-call-tool (connection name arguments)
- "Call a tool on the remote CONNECTION with NAME and ARGUMENTS.
-
-CONNECTION is the MCP connection object.
-NAME is the name of the tool to call.
-ARGGUMENTS is a list of arguments to pass to the tool."
- (jsonrpc-request connection
- :tools/call
- (list :name name
- :arguments (if arguments
- arguments
- #s(hash-table)))))
-
-(defun mcp-async-call-tool (connection name arguments callback error-callback)
- "Async Call a tool on the remote CONNECTION with NAME and ARGUMENTS.
-
-CONNECTION is the MCP connection object.
-NAME is the name of the tool to call.
-ARGUMENTS is a list of arguments to pass to the tool.
-CALLBACK is a function to call on success.
-ERROR-CALLBACK is a function to call on error."
- (jsonrpc-async-request connection
- :tools/call
- (list :name name
- :arguments (if arguments
- arguments
- #s(hash-table)))
- :success-fn
- #'(lambda (res)
- (funcall callback res))
- :error-fn
- (jsonrpc-lambda (&key code message _data)
- (funcall error-callback code message))))
-
-(defun mcp-async-list-prompts (connection &optional callback error-callback)
- "Get list of prompts from the MCP server using the provided CONNECTION.
-
-CONNECTION is the MCP connection object. CALLBACK is an optional function to
-call on success,which will receive the CONNECTION and the list of prompts.
-ERROR-CALLBACK is an optional function to call on error, which will receive the
-error code and message.
-
-The result is stored in the `mcp--prompts' slot of the CONNECTION object."
- (jsonrpc-async-request connection
- :prompts/list
- '(:cursor "")
- :success-fn
- #'(lambda (res)
- (cl-destructuring-bind (&key prompts &allow-other-keys) res
- (setf (mcp--prompts connection)
- prompts)
- (when callback
- (funcall callback connection prompts))))
- :error-fn
- (jsonrpc-lambda (&key code message _data)
- (if error-callback
- (funcall error-callback code message)
- (message "Sadly, mpc server reports %s: %s"
- code message)))))
-
-(defun mcp-get-prompt (connection name arguments)
- "Call a prompt on the remote CONNECTION with NAME and ARGUMENTS.
-
-CONNECTION is the MCP connection object.
-NAME is the name of the prompt to call.
-ARGGUMENTS is a list of arguments to pass to the prompt"
- (jsonrpc-request connection
- :prompts/get
- (list :name name
- :arguments (if arguments
- arguments
- #s(hash-table)))))
-
-(defun mcp-async-get-prompt (connection name arguments callback error-callback)
- "Async Call a prompt on the remote CONNECTION with NAME and ARGUMENTS.
-
-CONNECTION is the MCP connection object.
-NAME is the name of the prompt to call.
-ARGUMENTS is a list of arguments to pass to the prompt.
-CALLBACK is a function to call on successful response.
-ERROR-CALLBACK is a function to call on error."
- (jsonrpc-async-request connection
- :prompts/get
- (list :name name
- :arguments (if arguments
- arguments
- #s(hash-table)))
- :success-fn
- #'(lambda (res)
- (funcall callback res))
- :error-fn
- (jsonrpc-lambda (&key code message _data)
- (funcall error-callback code message))))
-
-(defun mcp-async-list-resources (connection &optional callback error-callback)
- "Get list of resources from the MCP server using the provided CONNECTION.
-
-CONNECTION is the MCP connection object. CALLBACK is an optional function to
-call upon successful retrieval of resources. ERROR-CALLBACK is an optional
-function to call if an error occurs during the request.
-
-The result is stored in the `mcp--resources' slot of the CONNECTION object."
- (jsonrpc-async-request connection
- :resources/list
- '(:cursor "")
- :success-fn
- #'(lambda (res)
- (cl-destructuring-bind (&key resources &allow-other-keys) res
- (setf (mcp--resources connection)
- resources)
- (when callback
- (funcall callback connection resources))))
- :error-fn
- (jsonrpc-lambda (&key code message _data)
- (if error-callback
- (funcall error-callback code message)
- (message "Sadly, mpc server reports %s: %s"
- code message)))))
-(defun mcp-read-resource (connection uri)
- "Call a resource on the remote CONNECTION with URI.
-
-CONNECTION is the MCP connection object.
-URI is the uri of the resource to call."
- (jsonrpc-request connection
- :resources/read
- (list :uri uri)))
-
-(defun mcp-async-read-resource (connection uri &optional callback error-callback)
- "Call a resource on the remote CONNECTION with URI.
-
-CONNECTION is the MCP connection object.
-URI is the URI of the resource to call.
-CALLBACK is a function to call with the result on success.
-ERROR-CALLBACK is a function to call with the error code and message on failure.
-
-This function asynchronously reads a resource from the remote connection
-using the specified URI. The result is passed to CALLBACK if the request
-succeeds, or ERROR-CALLBACK if it fails."
- (jsonrpc-async-request connection
- :resources/read
- (list :uri uri)
- :success-fn
- #'(lambda (res)
- (funcall callback res))
- :error-fn
- (jsonrpc-lambda (&key code message _data)
- (funcall error-callback code message))))
-
-(defun mcp-async-list-resource-templates (connection &optional callback error-callback)
- "Get list of resource templates from the MCP server using the CONNECTION.
-
-CONNECTION is the MCP connection object. CALLBACK is an optional function to
-call upon successful retrieval of resources. ERROR-CALLBACK is an optional
-function to call if an error occurs during the request."
- (jsonrpc-async-request connection
- :resources/templates/list
- '(:cursor "")
- :success-fn
- #'(lambda (res)
- (cl-destructuring-bind (&key resourceTemplates &allow-other-keys) res
- (when callback
- (funcall callback connection resourceTemplates))))
- :error-fn
- (jsonrpc-lambda (&key code message _data)
- (if error-callback
- (funcall error-callback code message)
- (message "Sadly, mpc server reports %s: %s"
- code message)))))
-
-(provide 'mcp)
-;;; mcp.el ends here
tools/emacs/lisp/ol-github.el
@@ -1,70 +0,0 @@
-;;; ol-github.el --- Links to GitHub -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2020 Vincent Demeester
-
-;; Author: Vincent Demeester <vincent@sbr.pm>
-;; Keywords: org link github
-;; Version: 0.1
-;; URL: https://gitlab.com/vdemeester/vorg
-;; Package-Requires: ((emacs "26.0") (org "9.0"))
-;;
-;; This file is not part of GNU Emacs.
-
-;; 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.0, 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:
-
-;; This file implements links to GitHub from within Org mode.
-;; gh:tektoncd/pipeline : project
-;; gh:tektoncd/pipeline#1 : issue or pr #1
-
-;;; Code:
-
-(require 'ol)
-
-;; Install the link type
-(org-link-set-parameters "gh"
- :follow #'org-github-follow-link
- :export #'org-github-export
- :face '(:foreground "DimGrey" :underline t))
-
-
-(defun org-github-export (link description format)
- "Export a github page link from Org files."
- (let ((path (org-github-get-url link))
- (desc (or description link)))
- (cond
- ((eq format 'html) (format "<a hrefl=\"_blank\" href=\"%s\">%s</a>" path desc))
- ((eq format 'latex) (format "\\href{%s}{%s}" path desc))
- ((eq format 'texinfo) (format "@uref{%s,%s}" path desc))
- ((eq format 'ascii) (format "%s (%s)" desc path))
- (t path))))
-
-(defun org-github-follow-link (issue)
- "Browse github issue/pr specified."
- (browse-url (org-github-get-url issue)))
-
-(defun org-github-get-url (path)
- "Translate org-mode link `gh:foo/bar#1' to github url."
- (setq expressions (split-string path "#"))
- (setq project (nth 0 expressions))
- (setq issue (nth 1 expressions))
- (if issue
- (format "https://github.com/%s/issues/%s" project issue)
- (format "https://github.com/%s" project)))
-
-(provide 'ol-github)
-;;; ol-github.el ends here
tools/emacs/lisp/ol-gitlab.el
@@ -1,81 +0,0 @@
-;;; ol-gitlab.el --- Links to Gitlab -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2020 Vincent Demeester
-
-;; Author: Vincent Demeester <vincent@sbr.pm>
-;; Keywords: org link gitlab
-;; Version: 0.1
-;; URL: https://gitlab.com/vdemeester/vorg
-;; Package-Requires: ((emacs "26.0") (org "9.0"))
-;;
-;; This file is not part of GNU Emacs.
-
-;; 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.0, 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:
-
-;; This file implements links to Gitlab from within Org mode.
-;; gl:vdemeester/emacs-config : project
-;; gl:vdemeester/emacs-config#1 : issue #1
-;; gl:vdemeester/emacs-config##1 : merge-request #1
-
-;;; Code:
-
-(require 'ol)
-
-;; Install the link type
-(org-link-set-parameters "gl"
- :follow #'org-gitlab-follow-link
- :export #'org-gitlab-export
- :face '(:foreground "DimGrey" :underline t))
-
-
-(defun org-gitlab-export (link description format)
- "Export a gitlab page link from Org files."
- (let ((path (org-gitlab-get-url link))
- (desc (or description link)))
- (cond
- ((eq format 'html) (format "<a hrefl=\"_blank\" href=\"%s\">%s</a>" path desc))
- ((eq format 'latex) (format "\\href{%s}{%s}" path desc))
- ((eq format 'texinfo) (format "@uref{%s,%s}" path desc))
- ((eq format 'ascii) (format "%s (%s)" desc path))
- (t path))))
-
-(defun org-gitlab-follow-link (issue)
- "Browse gitlab issue/pr specified."
- (browse-url (org-gitlab-get-url issue)))
-
-(defun org-gitlab-get-url (path)
- "Translate org-mode link `gh:foo/bar#1' to gitlab url."
- (setq expressions (split-string path "#"))
- (setq project (nth 0 expressions))
- (setq issue (nth 1 expressions))
- (setq mr (nth 2 expressions))
- (message (format "issue: %s" issue))
- (message (format "mr: %s" mr))
- (if (not (empty-string-p mr))
- (format "https://gitlab.com/%s/-/merge_requests/%s" project mr)
- (if (not (empty-string-p issue))
- (format "https://gitlab.com/%s/-/issues/%s" project issue)
- (format "https://gitlab.com/%s" project))))
-
-(defun empty-string-p (string)
- "Return true if the STRING is empty or nil. Expects string type."
- (or (null string)
- (zerop (length (string-trim string)))))
-
-(provide 'ol-gitlab)
-;;; ol-gitlab.el ends here
tools/emacs/lisp/ol-grep.el
@@ -1,57 +0,0 @@
-;;; ol-grep.el --- Links to Grep -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2020 Vincent Demeester
-
-;; Author: Vincent Demeester <vincent@sbr.pm>
-;; Keywords: org link grep
-;; Version: 0.1
-;; URL: https://gitlab.com/vdemeester/vorg
-;; Package-Requires: ((emacs "26.0") (org "9.0"))
-;;
-;; This file is not part of GNU Emacs.
-
-;; 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.0, 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:
-
-;; This file implements links to Grep from within Org mode.
-;; grep:orgmode : run grep on current working dir with orgmode expression
-;; grep:orgmode:config/ : run grep on config/ dir with orgmode expression
-
-;;; Code:
-
-(require 'ol)
-
-;; Install the link type
-(org-link-set-parameters "rg"
- :follow #'org-grep-follow-link
- :face '(:foreground "DarkRed" :underline t))
-
-(defun org-grep-follow-link (issue)
- "Run `rgrep' with REGEXP and FOLDER as argument,
-like this : [[grep:REGEXP:FOLDER]]."
- (setq expressions (split-string regexp ":"))
- (setq exp (nth 0 expressions))
- (grep-compute-defaults)
- (if (= (length expressions) 1)
- (progn
- (rgrep exp "*" (expand-file-name "./")))
- (progn
- (setq folder (nth 1 expressions))
- (rgrep exp "*" (expand-file-name folder)))))
-
-(provide 'ol-grep)
-;;; ol-grep.el ends here
tools/emacs/lisp/ol-rg.el
@@ -1,61 +0,0 @@
-;;; ol-rg.el --- Links to rg -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2020 Vincent Demeester
-
-;; Author: Vincent Demeester <vincent@sbr.pm>
-;; Keywords: org link ripgrep rg.el
-;; Version: 0.1
-;; URL: https://gitlab.com/vdemeester/vorg
-;; Package-Requires: ((emacs "26.0") (org "9.0") (rg "1.8.0"))
-;;
-;; This file is not part of GNU Emacs.
-
-;; 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.0, 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:
-
-;; This file implements links to Ripgrep from within Org mode.
-;; rg:orgmode : run ripgrep on current working dir with orgmode expression
-;; rg:orgmode:config/ : run ripgrep on config/ dir with orgmode expression
-;; rg:orgmode:config/#org : run ripgrep on config/ dir with orgmode expression
-
-;;; Code:
-
-(require 'rg)
-(require 'ol)
-
-;; Install the link type
-(org-link-set-parameters "rg"
- :follow #'org-rg-follow-link
- :face '(:foreground "DarkGreen" :underline t))
-
-(defun org-rg-follow-link (regexp)
- "Run `rg` with REXEP as argument,
-like this : [[rg:REGEXP:FOLDER#FILTER]]"
- (setq expressions (split-string regexp ":"))
- (setq exp (nth 0 expressions))
- (setq folderpart (nth 1 expressions))
- (setq files (split-string folderpart "#"))
- (setq folder (nth 0 files))
- (setq filter (nth 1 files))
- (if folderpart
- (if filter
- (rg exp (concat "*." filter) folder)
- (rg exp "*" folder))
- (rg exp "*" "./")))
-
-(provide 'ol-rg)
-;;; ol-rg.el ends here
tools/emacs/lisp/org-extra-emphasis.el
@@ -1,805 +0,0 @@
-;;; org-extra-emphasis.el --- Extra Emphasis markers for Org -*- lexical-binding: t; coding: utf-8-emacs; -*-
-
-;; Copyright (C) 2022 Jambunathan K <kjambunathan at gmail dot com>
-;; Copyright (C) 2004-2022 Free Software Foundation, Inc.
-
-;; Author: Jambunathan K <kjambunathan at gmail dot com>
-;; Keywords: org
-;; Homepage: https://github.com/kjambunathan/org-extra-emphasis
-;; Version: 1.0
-;; Package-Requires: ((ox-odt "9.5.3.467"))
-
-;; This file is NOT part of GNU Emacs.
-
-;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Overview
-;; ========
-;;
-;; This library provides two additional markers `!!' and `!@' over
-;; and above those in `org-emphasis-alist'.'
-;;
-;; - Text enclosed in `!!' is highlighted in yellow, and exported likewise
-;; - Text enclosed in `!@' is displayed in red, and exported likewise
-;;
-;; Following backends are supported: HTML and ODT. For export of extra
-;; emphasis markers to the ODT side, you need
-;; [[https://github.com/kjambunathan/org-mode-ox-odt][Enhanced ODT]]
-;; exporter with version >= 9.5.3.467 (dtd. June 14, 2022 IST). This
-;; is the first version of the exporter that defines the user option
-;; `org-odt-extra-styles'.
-;;
-;; Example
-;; =======
-;;
-;; Setup
-;; =====
-;;
-;; Add the following to your `user-init-file' and restart Emacs.
-;;
-;; (requrie 'org-extra-emphasis)
-;;
-;; Test Run
-;; ========
-;;
-;; 1. Create an `org' file, say `org-export-emphasis.org' and fill it
-;; with following content or you can download the file from
-;; https://raw.githubusercontent.com/kjambunathan/org-extra-emphasis/main/org-extra-emphasis.org
-
- ;; #+TITLE: Test file for ==org-extra-emphasis== library
-
- ;; * Demo of extra emphasis markers ==!!== and ==!@==
-
- ;; !!Ea consectetur laboris adipiscing et ipsum labore esse qui minim
- ;; pariatur et sunt sunt nostrud anim laborum culpa.!!
-
- ;; !@Minim reprehenderit excepteur elit, dolore elit, veniam, eu.
- ;; Ullamco dolore elit, cupidatat sed labore ea aute.!@
-
- ;; Pariatur !!et lorem cupidatat !@minim irure!@ proident, ad.!! Eiusmod
- ;; sunt et lorem labore ex aliqua aute esse.
-
- ;; Ut mollit !@duis velit est est magna in quis ipsum. !!Aliqua aliqua
- ;; non laboris exercitation cupidatat aliqua incididunt.!! Qui voluptate
- ;; irure aute occaecat laborum cillum est.!@ Quis magna dolor ullamco
- ;; magna do consectetur est laborum enim ut.
-
- ;; * !!Demo of extra emphasis markers in a styled paragraph!!
-
- ;; #+ATTR_ODT: :target "extra_styles"
- ;; #+begin_src nxml
- ;; <style:style style:name="Warn"
- ;; style:parent-style-name="Text_20_body"
- ;; style:family="paragraph">
- ;; <style:paragraph-properties>
- ;; <style:tab-stops />
- ;; </style:paragraph-properties>
- ;; <style:text-properties fo:background-color="#ff0000"
- ;; fo:color="#ffffff"
- ;; fo:font-size="20pt"
- ;; fo:font-style="italic"
- ;; fo:font-weight="bold" />
- ;; </style:style>
- ;; #+end_src
-
- ;; #+ATTR_ODT: :style "Warn"
- ;; Proident, duis dolore consectetur sed nisi ea pariatur. Esse
- ;; proident, cillum duis qui ullamco sint cillum magna. !!Eiusmod
- ;; veniam, !@sint officia!@ non consectetur laboris cillum.!! Cillum
- ;; mollit consequat eu dolore ullamco qui reprehenderit anim cillum
- ;; in consectetur consequat sunt dolore aliquip voluptate
- ;; consectetur anim ea. Voluptate nisi est incididunt aliquip
- ;; excepteur aliqua id do enim ut non consequat.
-;;
-;; 2. Note that portions of text marked with `!!' and `!@' are fontified as described above.
-;;
-;; 3. Export the file to HTML with `C-c C-e h O'.
-;;
-;; Note that the text enclosed in the above emphasis markers are
-;; colorized in HTML file.
-;;
-;; 4. Export the file to ODT with `C-c C-e o O'.
-;;
-;; Note that the text enclosed in the above emphasis markers are
-;; colorized in ODT file.
-;;
-;; The HTML, ODT, PDF generated in steps (3) and (4) above are
-;; available at https://github.com/kjambunathan/org-extra-emphasis and
-;; the screenshots can be seen in https://github.com/kjambunathan/org-extra-emphasis/tree/main/screenshots
-;;
-
-;; Default Settings
-;; ================
-;;
-;; 16 Emphasis Markers
-;; ===================
-;;
-;; This library defines the following 16 emphasis markers,
-;;
-;; |----+----+----+----|
-;; | !! | !@ | !% | !& |
-;; |----+----+----+----|
-;; | @! | @@ | @% | @& |
-;; |----+----+----+----|
-;; | %! | %@ | %% | %& |
-;; |----+----+----+----|
-;; | &! | &@ | &% | && |
-;; |----+----+----+----|
-;;
-;; The above markers are all pairings of the following four characters:
-;; ! @ % &
-;;
-;; It is hoped that these set of emphasis markers don't pose issues
-;; while exporting.
-;;
-;; 17 Extra Emphasis Faces
-;; =======================
-;;
-;; This library defines 17 faces:
-;;
-;; - one base face `org-extra-emphasis'
-;; - 16 more faces `org-extra-emphasis-01',`org-extra-emphasis-02',
-;; ..., `org-extra-emphasis-16'.
-;;
-;; The later 16 faces derive from `org-extra-emphasis' face. Of
-;; these, only the first two faces `org-extra-emphasis-01' and
-;; `org-extra-emphasis-02' are explicitly configured. If you are
-;; using more than 2 emphasis markers, you may want to configure the
-;; other 14 faces.
-;;
-;; `org-extra-emphasis-alist' already associated 16 emphasis markers
-;; with 16 different faces.
-;;
-;; Customization
-;; =============
-;;
-;; Configuring your own Emphasis Markers
-;; =====================================
-;;
-;; 16 numbers of emphasis markers should suffice in practice.
-;; However, if none of the above emphasis markers resonate with you,
-;; you can customize `org-extra-emphasis-alist', and plug in your own
-;; markers. When choosing your own marker, ensure that you exercise
-;; some care. For example, if you choose `#' as a marker you are
-;; likely to get malformed `html' and `odt' files.
-;;
-;; Configuring Extra Emphasis Faces
-;; ===============================
-;;
-;; You can use `M-x customize-group RET org-extra-emphasis-faces RET'
-;; to configure the extra emphasis faces.
-;;
-;; Disabling the Extra Emphasis
-;; =============================
-;;
-;; You can use `M-x org-extra-emphasis-mode' to toggle this feature.
-;;
-;; Adding additional export backends
-;; =================================
-;;
-;; To add additional backends, modify `org-extra-emphasis-formatter'
-;; and `org-extra-emphasis-build-backend-regexp'.
-
-;;; Code:
-
-(require 'org)
-(require 'ox-odt)
-(require 'rx)
-(require 'htmlfontify)
-
-;;; PART-1: `org-extra-emphasis-mode'
-
-;;;; Internal Variables
-
-(defvar org-extra-emphasis-backends
- '(html odt ods))
-
-(defvar org-extra-emphasis-info
- (list :enabled nil))
-
-;; Helper snippets to convert a Emacs Face to Inine CSS and ODT Text Properties
-;;
-;; (defun org-extra-emphasis-emacs-face->inline-css (face)
-;; (let ((s (cdr (hfy-face-to-css-default face))))
-;; (when (string-match (rx-to-string '(and "{" (group (zero-or-more any)) "}")) s)
-;; (format "<span style=\"%s\">%%s</span>" (match-string 1 s)))))
-;;
-;; (org-extra-emphasis-emacs-face->inline-css 'hi-yellow)
-;; (org-extra-emphasis-emacs-face->inline-css 'hi-red-b)
-;;
-;; (defun org-extra-emphasis-emacs-face->odt-text-properties (face)
-;; (org-odt--lisp-to-xml
-;; (assoc 'style:text-properties
-;; (org-odt--xml-to-lisp
-;; (cdr (org-odt-hfy-face-to-css face))))))
-;;
-;; (org-extra-emphasis-emacs-face->odt-text-properties 'hi-yellow)
-;; (org-extra-emphasis-emacs-face->odt-text-properties 'hi-red-b)
-
-(defun org-extra-emphasis-update (&rest _ignored)
- "Workhorse function that responds to configuration changes.
-
-Current state is maintined in `org-extra-emphasis-info', a plist."
- ;; When `org-extra-emaphasis' is ON, override use
- ;; `org-extra-emphasis-org-do-emphasis-faces'.
- ;; Otherwise, use `org-do-emphasis-faces'.
- (cond
- ((plist-get org-extra-emphasis-info :enabled)
- (advice-add 'org-do-emphasis-faces :override
- 'org-extra-emphasis-org-do-emphasis-faces))
- (t
- (advice-remove 'org-do-emphasis-faces
- 'org-extra-emphasis-org-do-emphasis-faces)))
- ;; `org-extra-emphasis-alist' is effective only if
- ;; `org-extra-emphasis' is enabled.
- (plist-put org-extra-emphasis-info :work-alist
- (when (plist-get org-extra-emphasis-info :enabled)
- (plist-get org-extra-emphasis-info :alist)))
- ;; Set properties that control fontification.
- ;; The property names and their values mimics the corresponding
- ;; variables in `org-set-emph-re'.
- (plist-put org-extra-emphasis-info :org-emphasis-alist
- (when (and (boundp 'org-emphasis-regexp-components)
- org-emphasis-alist org-emphasis-regexp-components)
- (append (plist-get org-extra-emphasis-info :work-alist)
- org-emphasis-alist)))
- (plist-put org-extra-emphasis-info :org-emph-re-template
- (when (and (boundp 'org-emphasis-regexp-components)
- org-emphasis-alist org-emphasis-regexp-components)
- (pcase-let*
- ((`(,pre ,post ,border ,body ,nl) org-emphasis-regexp-components)
- (body (if (<= nl 0) body
- (format "%s*?\\(?:\n%s*?\\)\\{0,%d\\}" body body nl))))
- (format (concat "\\([%s]\\|^\\)" ;before markers
- "\\(\\(%%s\\)\\([^%s]\\|[^%s]%s[^%s]\\)\\3\\)"
- "\\([%s]\\|$\\)") ;after markers
- pre border border body border post))))
- (plist-put org-extra-emphasis-info :org-emph-re
- (format (plist-get org-extra-emphasis-info :org-emph-re-template)
- (rx-to-string
- `(or ,@(mapcar #'car
- (cl-remove-if (lambda (l)
- (eq 'verbatim (nth 2 l)))
- (plist-get org-extra-emphasis-info :org-emphasis-alist)))))))
- (plist-put org-extra-emphasis-info :org-verbatim-re
- (format (plist-get org-extra-emphasis-info :org-emph-re-template)
- (rx-to-string
- `(or ,@(mapcar #'car
- (cl-remove-if-not (lambda (l)
- (eq 'verbatim (nth 2 l)))
- (plist-get org-extra-emphasis-info :org-emphasis-alist)))))
- (rx-to-string
- `(or ,@(mapcar #'car
- (cl-remove-if-not (lambda (l)
- (eq 'verbatim (nth 2 l)))
- (plist-get org-extra-emphasis-info :org-emphasis-alist)))))))
- ;; Set properties that control Export backends
- ;; - Regexp to search for in the final exported document
- (plist-put org-extra-emphasis-info :export-alist
- (org-extra-emphasis-build-backend-regexp))
-
- ;; - Generate ODT character styles for the extra emphasis faces and
- ;; dump those in `org-odt-extra-styles' and `org-ods-automatic-styles'.
- (plist-put org-extra-emphasis-info :odt-extra-styles
- (let* ((odt-styles
- (concat (mapconcat #'identity
- (cl-loop for (_marker face) in (plist-get org-extra-emphasis-info :alist)
- collect (cdr (org-odt-hfy-face-to-css face)))
- "\n\n"))))
- (with-no-warnings
- (unless (boundp 'org-odt-extra-styles)
- (message "`org-odt-extra-styles' not found. Upgrade to `ox-odt-9.5.3.467' or later.")
- ;; (sleep-for 2)
- (setq org-odt-extra-styles nil))
- (setq org-odt-extra-styles
- (concat (or (when (boundp 'org-odt-extra-styles)
- (get 'org-odt-extra-styles 'saved-value))
- "")
- "\n\n"
- odt-styles))
- (setq org-ods-automatic-styles
- (concat (or (when (boundp 'org-ods-automatic-styles)
- (get 'org-ods-automatic-styles 'saved-value))
- "")
- "\n\n"
- odt-styles))
- (message "`org-odt-extra-styles' and `org-ods-automatic-styles' is updated for this session")
- ;; (sleep-for 1)
- )
- odt-styles))
- ;; Re-fontify all Org buffers based on current configuration.
- (dolist (buffer (buffer-list))
- (with-current-buffer buffer
- (when (derived-mode-p 'org-mode)
- (font-lock-flush)))))
-
-;;;; Fontify Extra Emphasis Markers
-
-(defun org-extra-emphasis-org-do-emphasis-faces (limit)
- "Workhorse function that does fontification This function is
-based on `org-do-emphasis-faces'. The property names and values
-correspond to the variables used in `org-do-emphasis-faces'. Key
-differences are:
-
- - `:org-emphasis-alist' includes entries for both standard
- emphasis markers and extra emphasis markers.
-
- - The regexes used for search-based fontification allow for
- the possibility that the emphasis markers _in all
- likelihood_ are multi-char strings, as opposed to single
- chars."
- (let* ((quick-re (format "\\([%s]\\|^\\)\\(%s\\)"
- (car org-emphasis-regexp-components)
- (rx-to-string
- `(or ,@(mapcar #'car (plist-get org-extra-emphasis-info :org-emphasis-alist)))))))
- (catch :exit
- (while (re-search-forward quick-re limit t)
- (let* ((marker (match-string 2))
- (verbatim? (member marker '("~" "="))))
- (when (save-excursion
- (goto-char (match-beginning 0))
- (and
- ;; Do not match table hlines.
- (not (and (equal marker "+")
- (org-match-line
- "[ \t]*\\(|[-+]+|?\\|\\+[-+]+\\+\\)[ \t]*$")))
- ;; Do not match headline stars. Do not consider
- ;; stars of a headline as closing marker for bold
- ;; markup either.
- (not (and (equal marker "*")
- (save-excursion
- (forward-char)
- (skip-chars-backward "*")
- (looking-at-p org-outline-regexp-bol))))
- ;; Match full emphasis markup regexp.
- (looking-at (if verbatim? (plist-get org-extra-emphasis-info :org-verbatim-re)
- (plist-get org-extra-emphasis-info :org-emph-re)))
- ;; Do not span over paragraph boundaries.
- (not (string-match-p org-element-paragraph-separate
- (match-string 2)))
- ;; Do not span over cells in table rows.
- (not (and (save-match-data (org-match-line "[ \t]*|"))
- (string-match-p "|" (match-string 4))))))
- (pcase-let ((`(,_ ,face ,_) (assoc marker (plist-get org-extra-emphasis-info :org-emphasis-alist)))
- (m (if org-hide-emphasis-markers 4 2)))
- (font-lock-prepend-text-property
- (match-beginning m) (match-end m) 'face face)
- (when verbatim?
- (org-remove-flyspell-overlays-in
- (match-beginning 0) (match-end 0))
- (remove-text-properties (match-beginning 2) (match-end 2)
- '(display t invisible t intangible t)))
- (add-text-properties (match-beginning 2) (match-end 2)
- '(font-lock-multiline t org-emphasis t))
- (when (and org-hide-emphasis-markers
- (not (org-at-comment-p)))
- (add-text-properties (match-end 4) (match-beginning 5)
- '(invisible t))
- (add-text-properties (match-beginning 3) (match-end 3)
- '(invisible t)))
- (throw :exit t))))))))
-
-;; There is no `:set' function for `deffaces'. So, when the extra
-;; faces `org-extra-emphasis-01', `org-extra-emphasis-02' reconfigured,
-;; we don't get a notification. The following export hook ensures
-;; that `org-extra-emphasis-info' is in sync with user configuration.
-(add-hook 'org-export-before-processing-hook 'org-extra-emphasis-update)
-
-;;;; Export Extra Emphasis Markers
-
-(defun org-extra-emphasis-formatter (marker text backend)
- "Style TEXT in the same font face as the face MARKER is mapped to.
-Note that TEXT is in BACKEND format.
-
-This currently supports HTML and ODT backends.
-
-See `org-extra-emphasis-alist' for MARKER to face mappings."
- (let* ((face (car (assoc-default marker (plist-get org-extra-emphasis-info :work-alist))))
- (encode-attribute-value
- (lambda (text)
- (dolist (pair '(("&" . "&")
- ("<" . "<")
- (">" . ">")
- ("'" . "'")
- ("\"" . """)))
- (setq text (replace-regexp-in-string (car pair) (cdr pair) text t t)))
- text)))
- (cl-case backend
- ((odt ods)
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- (car (org-odt-hfy-face-to-css face)) text))
- (html
- (format "<span class=\"%s\" style=\"%s\">%s</span>"
- face
- ;; An alternate implementation of
- ;; `hfy-face-to-css-default' which performs correctly
- ;; when a face specifies a `:family', and/or inherits
- ;; some attributes from other faces. Note that the
- ;; flattening (or non-duplication) of face attributes
- ;; here is done by Emacs itself.
- (mapconcat (lambda (x)
- (when (cdr x)
- (format "%s: %s;" (car x)
- (funcall encode-attribute-value (cdr x)))))
- (hfy-face-to-style-i
- (cl-loop with props = (mapcar #'car face-attribute-name-alist)
- for prop in props
- for value = (face-attribute face prop nil 'default)
- unless (eq prop :inherit)
- append (list prop value)))
- " ")
- text))
- (_ text))))
-
-(defun org-extra-emphasis-build-backend-regexp ()
- "Regexp to search for emphasized text in exported file.
-This function transcode an emphasis MARKER which is in plain text
-format, to the BACKEND format. That is, if you use `<<' as an
-emphasis marker, you need to search for `<<' in the
-exported HTML file.
-
-See `org-extra-emphasis-alist' for more information"
- (cl-loop for (marker . spec) in (plist-get org-extra-emphasis-info :work-alist) collect
- (cons marker
- (cl-loop for backend in org-extra-emphasis-backends collect
- (cons backend
- (rx-to-string `(and ,(org-export-data-with-backend marker backend nil)
- (group (minimal-match
- (zero-or-more (or any "\n"))))
- ,(org-export-data-with-backend marker backend nil))))))))
-
-(defun org-extra-emphasis-plain-text-filter (text backend _info)
- "Transcode TEXT in to BACKEND format.
-Uses `org-extra-emphasis-formatter' to do the transcoding.
-
-Search TEXT for one or more transcoded MARKERs, and mark it up as
-specified in `org-extra-emphasis-alist'."
- (with-temp-buffer
- (insert text)
- (cl-loop for (marker . spec) in (plist-get org-extra-emphasis-info :export-alist)
- for regex = (assoc-default backend spec)
- do (goto-char (point-min))
- (if (not regex) text
- (while (re-search-forward regex nil t)
- (let* ((contents (match-string 1))
- (emphasized-contents (save-match-data
- (org-extra-emphasis-formatter
- marker contents backend))))
- (replace-match emphasized-contents t t)))))
- (buffer-substring-no-properties (point-min) (point-max))))
-
-;; Install export filter for transcoding extra emphasis markers.
-(defun org-extra-emphasis-update-filter-functions (&optional export-filter-functions)
- (let* ((all-filter-functions (thread-last org-export-filters-alist
- (seq-map #'cdr)
- (seq-sort #'string<))))
- (dolist (filter-fn '(org-extra-emphasis-plain-text-filter org-extra-emphasis-strip-zws-maybe))
- (dolist (it all-filter-functions)
- (set it (delq filter-fn (symbol-value it))))
- (dolist (it export-filter-functions)
- (add-to-list it filter-fn)))))
-
-;;;; User Options & Commands
-
-;;;;; Custom Groups
-
-(defgroup org-extra-emphasis nil
- "Options for highlighting and exporting extra emphasis markers in Org files."
- :tag "Org Extra Emphasis"
- :group 'org)
-
-(defgroup org-extra-emphasis-faces nil
- "Faces for Org Extra Emphasis."
- :group 'org-extra-emphasis
- :group 'faces)
-
-;;;; Custom Faces
-
-(defface org-extra-emphasis nil
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-01
- '((t (:inherit org-extra-emphasis :background "yellow")))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-02
- '((t (:inherit org-extra-emphasis :foreground "red")))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-03
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-04
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-05
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-06
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-07
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-08
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-09
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-10
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-11
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-12
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-13
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-14
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-15
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-(defface org-extra-emphasis-16
- '((t (:inherit org-extra-emphasis)))
- "A face for Org Extra Emphasis."
- :group 'org-extra-emphasis-faces)
-
-;;;;; Useful Org Setting
-
-(setcar (last org-emphasis-regexp-components) 5)
-
-(defcustom org-extra-emphasis-alist
- '(("!!" org-extra-emphasis-01)
- ("!@" org-extra-emphasis-02)
- ("!%" org-extra-emphasis-03)
- ("!&" org-extra-emphasis-04)
- ("@!" org-extra-emphasis-05)
- ("@@" org-extra-emphasis-06)
- ("@%" org-extra-emphasis-07)
- ("@&" org-extra-emphasis-08)
- ("%!" org-extra-emphasis-09)
- ("%@" org-extra-emphasis-10)
- ("%%" org-extra-emphasis-11)
- ("%&" org-extra-emphasis-12)
- ("&!" org-extra-emphasis-13)
- ("&@" org-extra-emphasis-14)
- ("&%" org-extra-emphasis-15)
- ("&&" org-extra-emphasis-16))
- "Alist of emphasis marker and its associated face."
- :group 'org-extra-emphasis
- :type '(repeat
- (list
- (string :tag "Emphasis Marker")
- (face :tag "Face")))
- :set (lambda (var val)
- (set var val)
- (plist-put org-extra-emphasis-info :alist val)
- (org-extra-emphasis-update)))
-
-(defcustom org-extra-emphasis t
- "When non-nil, enable Org Extra Emphasis."
- :group 'org-extra-emphasis
- :type '(boolean "Org Extra Emphasis")
- :set (lambda (var val)
- (set var val)
- (plist-put org-extra-emphasis-info :enabled val)
- (org-extra-emphasis-update)))
-
-(defcustom org-extra-emphasis-filter-functions
- '(
- org-export-filter-headline-functions
- org-export-filter-paragraph-functions
- org-export-filter-table-cell-functions
- )
- "List of places to which `org-extra-emphasis-plain-text-filter'
-and `org-extra-emphasis-strip-zws-maybe' hooks itself.
-
-The places should be one among the values that occur in
-`org-export-filters-alist'.
-
-By default, the list includes
- - `org-export-filter-headline-functions'
- - `org-export-filter-paragraph-functions'
- - `org-export-filter-table-cell-functions',
-
-This means that text with extra emphasis which appears as plain
-text, or within headlines and table cells will be, fontified."
- :group 'org-extra-emphasis
- :type `(set
- ,@(thread-last org-export-filters-alist
- (seq-map #'cdr)
- (seq-sort #'string<)
- (seq-map (lambda (it)
- (list 'const it)))))
- :set (lambda (var value)
- (set-default var value)
- (org-extra-emphasis-update-filter-functions value)))
-
-;;;;; `M-x org-extra-emphasis-mode'
-
-(defun org-extra-emphasis-mode (&optional arg)
- "Enable / Disable Org Extra Emphasis.
-
-If called interactively, toggle Extra Emphasis.
-
-When called non-interactively, enable Extra Emphasis if ARG is
-positive; disable otherwise."
- (interactive "p")
- (cond
- ;; Called interactively; Toggle
- ((called-interactively-p 'any)
- (setq org-extra-emphasis (not org-extra-emphasis)))
- ;; Called programatically; enable if arg >= 1
- ((and (numberp arg)
- (>= arg 1))
- (setq org-extra-emphasis t))
- ;; Otherwise, disable
- (t
- (setq org-extra-emphasis nil)))
- (plist-put org-extra-emphasis-info :enabled org-extra-emphasis)
- (org-extra-emphasis-update))
-
-;;; PART-2: `org-extra-emphasis-intraword-emphasis-mode'
-
-;;;; User options
-
-(defface org-extra-emphasis-zws-face
- '((t (:inherit org-extra-emphasis :foreground "red")))
- "Use this face to highlight the ZERO WIDTH SPACE character."
- :group 'org-extra-emphasis-faces)
-
-(defcustom org-extra-emphasis-zws-display-char ?\N{SPACING UNDERSCORE}
- "Use the glyph of this character to display ZERO WIDTH SPACE.
-
-Set this to nil, if you want the ZERO WIDTH SPACE to remain
-inconspicuous in the buffer. Note that even if ZERO WIDTH SPACE
-is inconspicuos in the buffer, the ZERO WIDTH SPACE will be
-stripped from the export output accoding to the value of
-`org-extra-emphasis-intraword-emphasis-mode'."
- :type '(choice (const :tag "Disabled" nil)
- (character :tag "Display ZERO WIDTH SPACE as "))
- :group 'org-extra-emphasis)
-
-;;;; Internal Variables
-
-(defvar-local org-extra-emphasis-stashed-display-table nil
- "Stashed value of `buffer-display-table'.
-
-This is the value of `buffer-display-table' before
-`org-extra-emphasis-intraword-emphasis-mode' is turned on in the
-buffer.
-
-Use this value to restore a buffer's `buffer-display-table' when
-`org-extra-emphasis-intraword-emphasis-mode' is turned off in the
-buffer.")
-
-;;;; `M-x org-extra-emphasis-intraword-emphasis-mode'
-
-;;;###autoload
-(define-minor-mode org-extra-emphasis-intraword-emphasis-mode
- "Toggle intra word emphasis in `org-mode' export.
-
-When `org-extra-emphasis-intraword-emphasis-mode' is enabled:
-
-- ZERO WIDTH SPACE characters are stripped from export backends.
-- ZERO WIDTH SPACE characters are displayed using
- `org-extra-emphasis-zws-display-char' and highlighted with
- `org-extra-emphasis-zws-face' space.
-
-TIPS for the user:
-
-1. You can insert ZERO WIDTH SPACE using
-
- `M-x insert-char RET ZERO WIDTH SPACE RET'
-
- One another way is to store that the ZERO WIDTH SPACE in a
- register, say SPC, and
-
- (set-register ?\N{SPACE} \"\N{ZERO WIDTH SPACE}\")
-
- and use the \\[insert-register] command on that register to insert
- the ZERO WIDTH SPACE character.
-
-2. You can examine the presence of ZERO WIDTH SPACE character in the
- export output by turning on the `glyphless-display-mode'."
- :lighter " ZWS"
- :init-value nil
- :global t
- :group 'org-extra-emphasis
- (cond
- ;; Turn ON `org-extra-emphasis-intraword-emphasis-mode'
- (org-extra-emphasis-intraword-emphasis-mode
- (when org-extra-emphasis-zws-display-char
- ;; Display ZERO WIDTH CHAR in a conspicuous way.
- (setq org-extra-emphasis-stashed-display-table (copy-sequence buffer-display-table))
- (unless buffer-display-table
- (setq buffer-display-table (make-display-table)))
- (aset buffer-display-table
- ?\N{ZERO WIDTH SPACE}
- (vector (make-glyph-code org-extra-emphasis-zws-display-char
- 'org-extra-emphasis-zws-face)))))
- (t
- ;; Turn OFF `org-extra-emphasis-intraword-emphasis-mode'
- (when org-extra-emphasis-zws-display-char
- ;; Restore the buffer's original `buffer-display-table'.
- (setq buffer-display-table org-extra-emphasis-stashed-display-table)))))
-
-;; Adjust `buffer-display-table' so that ZERO WIDTH SPACE characters
-;; are displayed.
-(add-hook 'org-mode-hook 'org-extra-emphasis-intraword-emphasis-mode t)
-
-;;;; Export hook to strip ZERO WIDTH SPACE
-
-(defun org-extra-emphasis-strip-zws-maybe (text _backend _info)
- "Strip ZERO WIDTH SPACE from TEXT.
-
-If `org-extra-emphasis-intraword-emphasis-mode' is enabled, strip
-ZERO WIDTH SPACE from TEXT. Otherwise, return TEXT unmodified."
- (cond
- ;; `org-extra-emphasis-intraword-emphasis-mode' is ON
- (org-extra-emphasis-intraword-emphasis-mode
- ;; Strip ZERO WIDTH SPACE.
- (replace-regexp-in-string
- (rx-to-string `(one-or-more ,(char-to-string ?\N{ZERO WIDTH SPACE})))
- "" text t t))
- ;; `org-extra-emphasis-intraword-emphasis-mode' is OFF.
- (t
- ;; Nothing to do.
- text)))
-
-;; Configure Org Export Engine to strip ZERO WIDTH SPACE, if needed.
-;; (dolist (it '(org-export-filter-table-cell-functions
-;; org-export-filter-paragraph-functions))
-;; (add-to-list it 'org-extra-emphasis-strip-zws-maybe it))
-
-(provide 'org-extra-emphasis)
-
-;;; org-extra-emphasis.el ends here
tools/emacs/lisp/org-focus.el
@@ -1,49 +0,0 @@
-;; From http://www.howardism.org/Technical/Emacs/focused-work.html
-;; Write something a bit similar, but better ?
-
-(defvar vde/focus-timer nil "A timer reference for the vde/focus functions")
-
-(defun vde/focus-countdown-timer (minutes fun)
- (let ((the-future (* minutes 60)))
- (run-at-time the-future nil fun)))
-
-(defun vde/focus-begin ()
- "Start a concerted, focused effort, ala Pomodoro Technique.
-We first clock into the current org-mode header (or last one),
-start some music to indicate we are working, and set a timer.
-
-Call `ha-focus-break' when finished."
- (interactive)
- (vde/focus-countdown-timer 25 'vde/focus-break)
- (vde/focus--command "playerctl play-pause")
- (vde/focus--command "notify-send 'Let's focus.'")
- (vde/focus--command "swaync-client -d")
- (if (eq major-mode 'org-mode)
- (org-clock-in)
- (org-clock-in-last)))
-
-(defun vde/focus-break ()
- "Stop the focused time by stopping the music.
-This also starts another break timer, that calls
-`ha-focus-break-over' when finished."
- (interactive)
- (vde/focus-countdown-timer 5 'vde/focus-break-over)
- (vde/focus--command "swaync-client -d")
- (vde/focus--command "notify-send 'Let's take a break.'")
- (vde/focus--command "playerctl play-pause")
- (org-clock-out)
- (message "Time to take a break."))
-
-(defun vde/focus-break-over ()
- "Message me to know that the break time is over. Notice that
-this doesn't start anything automatically, as I may have simply
-wandered off."
- (vde/focus--command "notify-send 'Break is over.'"))
-
-(defun vde/focus--command (command)
- "Runs COMMAND by passing to the `command' command asynchronously."
- (async-start-process "focus-os" "zsh" 'vde/focus--command-callback "-c" command))
-
-(defun vde/focus--command-callback (proc)
- "Asynchronously called when the `osascript' process finishes."
- (message "Finished calling command."))
tools/emacs/lisp/org-func.el
@@ -1,193 +0,0 @@
-;;; org-func.el --- -*- lexical-binding: t -*-
-;;
-
-;; https://endlessparentheses.com/updating-org-mode-include-statements-on-the-fly.html
-;;;###autoload
-(defun save-and-update-includes ()
- "Update the line numbers of #+INCLUDE:s in current buffer.
-Only looks at INCLUDEs that have either :range-begin or :range-end.
-This function does nothing if not in `org-mode', so you can safely
-add it to `before-save-hook'."
- (interactive)
- (when (derived-mode-p 'org-mode)
- (save-excursion
- (goto-char (point-min))
- (while (search-forward-regexp
- "^\\s-*#\\+INCLUDE: *\"\\([^\"]+\\)\".*:range-\\(begin\\|end\\)"
- nil 'noerror)
- (let* ((file (expand-file-name (match-string-no-properties 1)))
- lines begin end)
- (forward-line 0)
- (when (looking-at "^.*:range-begin *\"\\([^\"]+\\)\"")
- (setq begin (match-string-no-properties 1)))
- (when (looking-at "^.*:range-end *\"\\([^\"]+\\)\"")
- (setq end (match-string-no-properties 1)))
- (setq lines (decide-line-range file begin end))
- (when lines
- (if (looking-at ".*:lines *\"\\([-0-9]+\\)\"")
- (replace-match lines :fixedcase :literal nil 1)
- (goto-char (line-end-position))
- (insert " :lines \"" lines "\""))))))))
-
-(defun decide-line-range (file begin end)
- "Visit FILE and decide which lines to include.
-BEGIN and END are regexps which define the line range to use."
- (let (l r)
- (save-match-data
- (with-temp-buffer
- (insert-file-contents file)
- (goto-char (point-min))
- (if (null begin)
- (setq l "")
- (search-forward-regexp begin)
- (setq l (line-number-at-pos (match-beginning 0))))
- (if (null end)
- (setq r "")
- (search-forward-regexp end)
- (setq r (1+ (line-number-at-pos (match-end 0)))))
- (format "%s-%s" (+ l 1) (- r 1)))))) ;; Exclude wrapper
-
-(defun vde/get-outline-path (element)
- "Return the outline path (as a list of titles) for ELEMENT, which is a headline."
- (let (path)
- (while (and element (eq (org-element-type element) 'headline))
- (let ((title (org-element-property :title element)))
- (when title
- (push title path)))
- (setq element (org-element-property :parent element)))
- (reverse path)))
-
-;;;###autoload
-(defun vde/org-clock-in-any-heading ()
- "Clock into any Org heading from `org-agenda-files' that is not DONE or CANCELED."
- (interactive)
- (let (headings)
- (dolist (file org-agenda-files)
- (when (file-exists-p file)
- (with-current-buffer (find-file-noselect file)
- (org-map-entries (lambda ()
- (let* ((element (org-element-context))
- (todo (org-element-property :todo-keyword element)))
- (when (not (member todo '("DONE" "CANCELED")))
- (let* ((path (vde/get-outline-path element)))
- (push (list :path path
- :file (buffer-file-name)
- :position (point))
- headings)))))
- t 'file))))
- (let* (candidates)
- (dolist (h headings)
- (let* ((path (plist-get h :path))
- (path-str (mapconcat 'identity path " > "))
- (file (plist-get h :file))
- (candidate (format "%s : %s" path-str (file-name-nondirectory file)))
- (data (list file (plist-get h :position))))
- (push (cons candidate data) candidates)))
- (let* ((selected-candidate (completing-read "Select heading: " candidates))
- (matching (cl-find-if (lambda (c) (string= (car c) selected-candidate)) candidates)))
- (when matching
- (let* ((data (cdr matching))
- (file (car data))
- (pos (cadr data)))
- (find-file file)
- (goto-char pos)
- (org-clock-in)))))))
-
-;;;###autoload
-(defun vde/org-next-visible-heading-or-link (&optional arg)
- "Move to the next visible heading or link, whichever comes first.
-With prefix ARG and the point on a heading(link): jump over subsequent
-headings(links) to the next link(heading), respectively. This is useful
-to skip over a long series of consecutive headings(links)."
- (interactive "P")
- (let ((next-heading (save-excursion
- (org-next-visible-heading 1)
- (when (org-at-heading-p) (point))))
- (next-link (save-excursion
- (when (vde/org-next-visible-link) (point)))))
- (when arg
- (if (and (org-at-heading-p) next-link)
- (setq next-heading nil)
- (if (and (looking-at org-link-any-re) next-heading)
- (setq next-link nil))))
- (cond
- ((and next-heading next-link) (goto-char (min next-heading next-link)))
- (next-heading (goto-char next-heading))
- (next-link (goto-char next-link)))))
-
-;;;###autoload
-(defun vde/org-previous-visible-heading-or-link (&optional arg)
- "Move to the previous visible heading or link, whichever comes first.
-With prefix ARG and the point on a heading(link): jump over subsequent
-headings(links) to the previous link(heading), respectively. This is useful
-to skip over a long series of consecutive headings(links)."
- (interactive "P")
- (let ((prev-heading (save-excursion
- (org-previous-visible-heading 1)
- (when (org-at-heading-p) (point))))
- (prev-link (save-excursion
- (when (vde/org-next-visible-link t) (point)))))
- (when arg
- (if (and (org-at-heading-p) prev-link)
- (setq prev-heading nil)
- (if (and (looking-at org-link-any-re) prev-heading)
- (setq prev-link nil))))
- (cond
- ((and prev-heading prev-link) (goto-char (max prev-heading prev-link)))
- (prev-heading (goto-char prev-heading))
- (prev-link (goto-char prev-link)))))
-
-;; Adapted from org-next-link to only consider visible links
-;;;###autoload
-(defun vde/org-next-visible-link (&optional search-backward)
- "Move forward to the next visible link.
-When SEARCH-BACKWARD is non-nil, move backward."
- (interactive)
- (let ((pos (point))
- (search-fun (if search-backward #'re-search-backward
- #'re-search-forward)))
- ;; Tweak initial position: make sure we do not match current link.
- (cond
- ((and (not search-backward) (looking-at org-link-any-re))
- (goto-char (match-end 0)))
- (search-backward
- (pcase (org-in-regexp org-link-any-re nil t)
- (`(,beg . ,_) (goto-char beg)))))
- (catch :found
- (while (funcall search-fun org-link-any-re nil t)
- (let ((folded (org-invisible-p nil t)))
- (when (or (not folded) (eq folded 'org-link))
- (let ((context (save-excursion
- (unless search-backward (forward-char -1))
- (org-element-context))))
- (pcase (org-element-lineage context '(link) t)
- (link
- (goto-char (org-element-property :begin link))
- (throw :found t)))))))
- (goto-char pos)
- ;; No further link found
- nil)))
-
-;;;###autoload
-(defun vde/org-shifttab (&optional arg)
- "Move to the previous visible heading or link.
-If already at a heading, move first to its beginning. When inside a table,
-move to the previous field."
- (interactive "P")
- (cond
- ((org-at-table-p) (call-interactively #'org-table-previous-field))
- ((and (not (bolp)) (org-at-heading-p)) (beginning-of-line))
- (t (call-interactively #'vde/org-previous-visible-heading-or-link))))
-
-;;;###autoload
-(defun vde/org-tab (&optional arg)
- "Move to the next visible heading or link.
-When inside a table, re-align the table and move to the next field."
- (interactive)
- (cond
- ((org-at-table-p) (org-table-justify-field-maybe)
- (call-interactively #'org-table-next-field))
- (t (call-interactively #'vde/org-next-visible-heading-or-link))))
-
-(provide 'org-func)
-;;; org-func.el ends here
tools/emacs/lisp/org-protocol-capture-html.el
@@ -1,280 +0,0 @@
-;;; org-protocol-capture-html.el --- Capture HTML with org-protocol
-
-;; URL: https://github.com/alphapapa/org-protocol-capture-html
-;; Version: 0.1-pre
-;; Package-Requires: ((emacs "24.4"))
-
-;;; Commentary:
-
-;; This package captures Web pages into Org-mode using Pandoc to
-;; process HTML. It can also use eww's eww-readable functionality to
-;; get the main content of a page.
-
-;; These are the helper functions that run in Emacs. To capture pages
-;; into Emacs, you can use either a browser bookmarklet or the
-;; org-protocol-capture-html.sh shell script. See the README.org file
-;; for instructions.
-
-;;; License:
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Code:
-
-;;;; Require
-
-(require 'org-protocol)
-(require 'cl-lib)
-(require 'subr-x)
-(require 's)
-
-;;;; Vars
-
-(defcustom org-protocol-capture-html-demote-times 1
- "How many times to demote headings in captured pages.
-You may want to increase this if you use a sub-heading in your capture template."
- :group 'org-protocol-capture-html :type 'integer)
-
-;;;; Test Pandoc
-
-(defconst org-protocol-capture-html-pandoc-no-wrap-option nil
- ;; Set this so it won't be unbound
- "Option to pass to Pandoc to disable wrapping.
-Pandoc >= 1.16 deprecates `--no-wrap' in favor of
-`--wrap=none'.")
-
-(defun org-protocol-capture-html--define-pandoc-wrap-const ()
- "Set `org-protocol-capture-html-pandoc-no-wrap-option'."
- (setq org-protocol-capture-html-pandoc-no-wrap-option
- ;; Pandoc >= 1.16 deprecates the --no-wrap option, replacing it with
- ;; --wrap=none. Sending the wrong option causes output to STDERR,
- ;; which `call-process-region' doesn't like. So we test Pandoc to see
- ;; which option to use.
- (with-temp-buffer
- (let* ((process (start-process "test-pandoc" (current-buffer) "pandoc" "--dump-args" "--no-wrap"))
- (limit 3)
- (checked 0))
- (while (process-live-p process)
- (if (= checked limit)
- (progn
- ;; Pandoc didn't exit in time. Kill it and raise
- ;; an error. This function will return `nil' and
- ;; `org-protocol-capture-html-pandoc-no-wrap-option'
- ;; will remain `nil', which will cause this
- ;; function to run again and set the const when a
- ;; capture is run.
- (set-process-query-on-exit-flag process nil)
- (error "Unable to test Pandoc! Please report this bug! (include the output of \"pandoc --dump-args --no-wrap\")"))
- (sleep-for 0.2)
- (cl-incf checked)))
- (if (and (zerop (process-exit-status process))
- (not (string-match "--no-wrap is deprecated" (buffer-string))))
- "--no-wrap"
- "--wrap=none")))))
-
-;;;; Direct-to-Pandoc
-
-(defun org-protocol-capture-html--with-pandoc (data)
- "Process an org-protocol://capture-html:// URL using DATA.
-
-This function is basically a copy of `org-protocol-do-capture', but
-it passes the captured content (not the URL or title) through
-Pandoc, converting HTML to Org-mode."
-
- ;; It would be nice to not basically duplicate
- ;; `org-protocol-do-capture', but passing the data back to that
- ;; function would require re-encoding the data into a URL string
- ;; with Emacs after Pandoc converts it. Since we've already split
- ;; it up, we might as well go ahead and run the capture directly.
-
- (unless org-protocol-capture-html-pandoc-no-wrap-option
- (org-protocol-capture-html--define-pandoc-wrap-const))
-
- (let* ((template (or (plist-get data :template)
- org-protocol-default-template-key))
- (url (org-protocol-sanitize-uri (plist-get data :url)))
- (type (if (string-match "^\\([a-z]+\\):" url)
- (match-string 1 url)))
- (title (or (org-protocol-capture-html--nbsp-to-space (string-trim (plist-get data :title))) ""))
- (content (or (org-protocol-capture-html--nbsp-to-space (string-trim (plist-get data :body))) ""))
- (orglink (org-make-link-string
- url (if (string-match "[^[:space:]]" title) title url)))
- (org-capture-link-is-already-stored t)) ; avoid call to org-store-link
-
- (setq org-stored-links
- (cons (list url title) org-stored-links))
- (kill-new orglink)
-
- (with-temp-buffer
- (insert content)
- (if (not (zerop (call-process-region
- (point-min) (point-max)
- "pandoc" t t nil "-f" "html" "-t" "org" org-protocol-capture-html-pandoc-no-wrap-option)))
- (message "Pandoc failed: %s" (buffer-string))
- (progn
- ;; Pandoc succeeded
- (org-store-link-props :type type
- :annotation orglink
- :link url
- :description title
- :orglink orglink
- :initial (buffer-string)))))
- (org-protocol-capture-html--do-capture)
- nil))
-
-(add-to-list 'org-protocol-protocol-alist
- '("capture-html"
- :protocol "capture-html"
- :function org-protocol-capture-html--with-pandoc
- :kill-client t))
-
-;;;; eww-readable
-
-(defvar url-http-end-of-headers)
-
-(eval-when-compile
- ;; eww-readable only works on Emacs >=25.1, but I think it's better
- ;; to check for the actual symbols. I think using
- ;; `eval-when-compile' is the right way to do this, but I'm not
- ;; sure.
- (when (and (require 'eww nil t)
- (require 'dom nil t)
- (fboundp 'eww-score-readability))
-
- (defun org-protocol-capture-html--capture-eww-readable (data)
- "Capture content of URL with eww-readable.."
-
- (unless org-protocol-capture-html-pandoc-no-wrap-option
- (org-protocol-capture-html--define-pandoc-wrap-const))
-
- (let* ((template (or (plist-get data :template)
- org-protocol-default-template-key))
- (url (org-protocol-sanitize-uri (plist-get data :url)))
- (type (if (string-match "^\\([a-z]+\\):" url)
- (match-string 1 url)))
- (html (org-protocol-capture-html--url-html url))
- (result (org-protocol-capture-html--eww-readable html))
- (title (cdr result))
- (content (with-temp-buffer
- (insert (org-protocol-capture-html--nbsp-to-space (car result)))
- ;; Convert to Org with Pandoc
- (unless (= 0 (call-process-region (point-min) (point-max)
- "pandoc" t t nil "-f" "html" "-t" "org"
- org-protocol-capture-html-pandoc-no-wrap-option))
- (error "Pandoc failed"))
- (save-excursion
- ;; Remove DOS CR/LF line endings
- (goto-char (point-min))
- (while (search-forward (string ?\C-m) nil t)
- (replace-match "")))
- ;; Demote page headings in capture buffer to below the
- ;; top-level Org heading and "Article" 2nd-level heading
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward (rx bol (1+ "*") (1+ space)) nil t)
- (beginning-of-line)
- (insert "**")
- (end-of-line)))
- (buffer-string)))
- (orglink (org-make-link-string
- url (if (s-present? title) title url)))
- ;; Avoid call to org-store-link
- (org-capture-link-is-already-stored t))
-
- (setq org-stored-links
- (cons (list url title) org-stored-links))
- (kill-new orglink)
-
- (org-store-link-props :type type
- :annotation orglink
- :link url
- :description title
- :orglink orglink
- :initial content)
- (org-protocol-capture-html--do-capture)
- nil))
-
- (add-to-list 'org-protocol-protocol-alist
- '("capture-eww-readable"
- :protocol "capture-eww-readable"
- :function org-protocol-capture-html--capture-eww-readable
- :kill-client t))
-
- (defun org-protocol-capture-html--url-html (url)
- "Return HTML from URL as string."
- (let* ((response-buffer (url-retrieve-synchronously url nil t))
- (encoded-html (with-current-buffer response-buffer
- (pop-to-buffer response-buffer)
- ;; Skip HTTP headers, using marker provided by url-http
- (delete-region (point-min) (1+ url-http-end-of-headers))
- (buffer-string))))
- (kill-buffer response-buffer) ; Not sure if necessary to avoid leaking buffer
- (with-temp-buffer
- ;; For some reason, running `decode-coding-region' in the
- ;; response buffer has no effect, so we have to do it in a
- ;; temp buffer.
- (insert encoded-html)
- (condition-case nil
- ;; Fix undecoded text
- (decode-coding-region (point-min) (point-max) 'utf-8)
- (coding-system-error nil))
- (buffer-string))))
-
- (defun org-protocol-capture-html--eww-readable (html)
- "Return `eww-readable' part of HTML with title.
-Returns list (HTML . TITLE)."
- ;; Based on `eww-readable'
- (let* ((html
- ;; Convert " " in HTML to plain spaces.
- ;; `libxml-parse-html-region' turns them into
- ;; underlines. The closest I can find to an explanation
- ;; is at <http://www.perlmonks.org/?node_id=825188>.
- (org-protocol-capture-html--nbsp-to-space html))
- (dom (with-temp-buffer
- (insert html)
- (libxml-parse-html-region (point-min) (point-max))))
- (title (cl-caddr (car (dom-by-tag dom 'title)))))
- (eww-score-readability dom)
- (cons (with-temp-buffer
- (shr-dom-print (eww-highest-readability dom))
- (buffer-string))
- title)))))
-
-;;;; Helper functions
-
-(defun org-protocol-capture-html--nbsp-to-space (s)
- "Convert HTML non-breaking spaces to plain spaces in S."
- ;; Not sure why sometimes these are in the HTML and Pandoc converts
- ;; them to underlines instead of spaces, but this fixes it.
- (replace-regexp-in-string (rx " ") " " s t t))
-
-(with-no-warnings
- ;; Ignore warning about the dynamically scoped `template' variable.
- (defun org-protocol-capture-html--do-capture ()
- "Call `org-capture' and demote page headings in capture buffer."
- (raise-frame)
- (funcall 'org-capture nil template)
-
- ;; Demote page headings in capture buffer to below the
- ;; top-level Org heading
- (save-excursion
- (goto-char (point-min))
- (re-search-forward (rx bol "*" (1+ space)) nil t) ; Skip 1st heading
- (while (re-search-forward (rx bol "*" (1+ space)) nil t)
- (dotimes (n org-protocol-capture-html-demote-times)
- (org-demote-subtree))))))
-
-(provide 'org-protocol-capture-html)
-
-;;; org-protocol-capture-html.el ends here
tools/emacs/lisp/org-review.el
@@ -1,263 +0,0 @@
-;;; org-review.el --- Schedule reviews for Org entries
-;;
-;; Copyright (C) 2024 Alan Schmitt
-;;
-;; Author: Alan Schmitt <alan.schmitt@polytechnique.org>
-;; URL: https://github.com/brabalan/org-review
-;; Version: 0.3
-;; Keywords: calendar
-
-;; This file is not part of GNU Emacs.
-
-;; 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, 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-;;
-;;; Commentary:
-;;
-;; This allows to schedule reviews of org entries.
-;;
-;; Entries will be scheduled for review if their NEXT_REVIEW or their
-;; LAST_REVIEW property is set. The next review date is the
-;; NEXT_REVIEW date, if it is present, otherwise it is computed from
-;; the LAST_REVIEW property and the REVIEW_DELAY period, such as
-;; "+1m". If REVIEW_DELAY is absent, a default period is used. Note
-;; that the LAST_REVIEW property is not considered as inherited, but
-;; REVIEW_DELAY is, allowing to set it for whole subtrees.
-;;
-;; Checking of review dates is done through an agenda view, using the
-;; `org-review-agenda-skip' skipping function. This function is based
-;; on `org-review-toreview-p', that returns `nil' if no review is
-;; necessary (no review planned or it happened recently), otherwise it
-;; returns the date the review was first necessary (NEXT_REVIEW, or
-;; LAST_REVIEW + REVIEW_DELAY, if it is in the past).
-;;
-;; To mark an entry as reviewed, use the function
-;; `org-review-insert-last-review' to set the LAST_REVIEW date to the
-;; current date. If `org-review-sets-next-date' is set (which is the
-;; default), this function also computes the date of the next review
-;; and inserts it as NEXT_REVIEW.
-;;
-;; Example use.
-;;
-;; 1 - To display the things to review in the agenda.
-;;
-;; (setq org-agenda-custom-commands (quote ( ...
-;; ("R" "Review projects" tags-todo "-CANCELLED/"
-;; ((org-agenda-overriding-header "Reviews Scheduled")
-;; (org-agenda-skip-function 'org-review-agenda-skip)
-;; (org-agenda-cmp-user-defined 'org-review-compare)
-;; (org-agenda-sorting-strategy '(user-defined-down)))) ... )))
-;;
-;; 2 - To set a key binding to review from the agenda
-;;
-;; (add-hook 'org-agenda-mode-hook (lambda () (local-set-key (kbd "C-c
-;; C-r") 'org-review-insert-last-review)))
-
-;;; Changes
-;;
-;; 2022-04-11: systematically insert name of week day in date
-;; 2016-08-18: better detection of org-agenda buffers
-;; 2014-05-08: added the ability to specify next review dates
-
-;; TODO
-;; - be able to specify a function to run when marking an item reviewed
-
-;;; Code:
-
-(require 'org)
-(require 'org-agenda)
-
-;;; User variables:
-
-(defgroup org-review nil
- "Org review scheduling."
- :tag "Org Review Schedule"
- :group 'org)
-
-(defcustom org-review-last-timestamp-format 'naked
- "Timestamp format for last review properties."
- :type '(radio (const naked)
- (const inactive)
- (const active))
- :group 'org-review)
-
-(defcustom org-review-next-timestamp-format 'naked
- "Timestamp format for last review properties."
- :type '(radio (const naked)
- (const inactive)
- (const active))
- :group 'org-review)
-
-(defcustom org-review-last-property-name "LAST_REVIEW"
- "The name of the property for the date of the last review."
- :type 'string
- :group 'org-review)
-
-(defcustom org-review-delay-property-name "REVIEW_DELAY"
- "The name of the property for setting the delay before the next review."
- :type 'string
- :group 'org-review)
-
-(defcustom org-review-next-property-name "NEXT_REVIEW"
- "The name of the property for setting the date of the next review."
- :type 'string
- :group 'org-review)
-
-(defcustom org-review-delay "+1m"
- "Time span between the date of last review and the next one.
-The default value for this variable (\"+1m\") means that entries
-will be marked for review one month after their last review.
-
-If the review delay cannot be retrieved from the entry or the
-subtree above, this delay is used."
- :type 'string
- :group 'org-review)
-
-(defcustom org-review-sets-next-date t
- "Indicates whether marking a project as reviewed automatically
-sets the next NEXT_REVIEW according to the current date and
-REVIEW_DELAY."
- :type 'boolean
- :group 'org-review)
-
-;;; Functions:
-
-(defun org-review-last-planned (last delay)
- "Computes the next planned review, given the LAST review
-date (in string format) and the review DELAY (in string
-format)."
- (let ((lt (org-read-date nil t last))
- (ct (current-time)))
- (time-add lt (time-subtract (org-read-date nil t delay) ct))))
-
-;;;###autoload
-(defun org-review-last-review-prop (&optional pos)
- "Return the value of the last review property of the headline
-at position POS, or the current headline if POS is not given."
- (org-entry-get (or pos (point)) org-review-last-property-name))
-
-;;;###autoload
-(defun org-review-next-review-prop (&optional pos)
- "Return the value of the review date property of the headline
-at position POS, or the current headline if POS is not given."
- (org-entry-get (or pos (point)) org-review-next-property-name))
-
-(defun org-review-review-delay-prop (&optional pos)
- "Return the value of the review delay property of the headline
-at position POS, or the current headline if POS is not given,
-considering inherited properties."
- (org-entry-get (or pos (point)) org-review-delay-property-name t))
-
-(defun org-review-toreview-p (&optional pos)
- "Check if the entry at point should be marked for review.
-Return nil if the entry does not need to be reviewed. Otherwise
-return the date when the entry was first scheduled to be
-reviewed.
-
-If there is a next review date, consider it. Otherwise, if there
-is a last review date, use it to compute the date of the next
-review (adding the value of the review delay property, or
-`org-review-delay' if there is no review delay property). If
-there is no next review date and no last review date, return
-nil."
- (let* ((lp (org-review-last-review-prop pos))
- (np (org-review-next-review-prop pos))
- (nextreview
- (cond
- (np (org-read-date nil t np))
- (lp (org-review-last-planned
- lp
- (or (org-review-review-delay-prop pos)
- org-review-delay)))
- (t nil))))
- (and nextreview
- (time-less-p nextreview (current-time))
- nextreview)))
-
-(defun org-review-insert-date (propname fmt date)
- "Insert the DATE under property PROPNAME, in the format
-specified by FMT."
- (org-entry-put
- (if (equal major-mode 'org-agenda-mode)
- (or (org-get-at-bol 'org-marker)
- (org-agenda-error))
- (point))
- propname
- (cond
- ((eq fmt 'inactive)
- (concat "[" date "]"))
- ((eq fmt 'active)
- (concat "<" date ">"))
- (t date))))
-
-;;;###autoload
-(defun org-review-insert-last-review (&optional prompt)
- "Insert the current date as last review. If prefix argument:
-prompt the user for the date. If `org-review-sets-next-date' is
-set to t, also insert a next review date."
- (interactive "P")
- (let ((ts (if prompt
- (format-time-string (car org-time-stamp-formats) (org-read-date nil t))
- (format-time-string (car org-time-stamp-formats)))))
- (org-review-insert-date org-review-last-property-name
- org-review-last-timestamp-format
- ts)
- (when org-review-sets-next-date
- (org-review-insert-date
- org-review-next-property-name
- org-review-next-timestamp-format
- (format-time-string
- (car org-time-stamp-formats)
- (org-review-last-planned
- ts
- (or (org-review-review-delay-prop
- (if (equal major-mode 'org-agenda-mode)
- (or (org-get-at-bol 'org-marker)
- (org-agenda-error))
- (point)))
- org-review-delay)))))))
-
-;;;###autoload
-(defun org-review-insert-next-review ()
- "Prompt the user for the date of the next review, and insert
-it as a property of the headline."
- (interactive)
- (let ((ts (format-time-string (car org-time-stamp-formats) (org-read-date nil t))))
- (org-review-insert-date org-review-next-property-name
- org-review-next-timestamp-format
- ts)))
-
-;;;###autoload
-(defun org-review-agenda-skip ()
- "To be used as an argument of `org-agenda-skip-function' to
-skip entries that are not scheduled to be reviewed. This function
-does not move the point; it returns nil if the entry is to be
-kept, and the position to continue the search otherwise."
- (and (not (org-review-toreview-p))
- (org-with-wide-buffer (or (outline-next-heading) (point-max)))))
-
-(defun org-review-compare (a b)
- "Compares the date of scheduled review for the two agenda
-entries, to be used with `org-agenda-cmp-user-defined'. Returns
-+1 if A has been scheduled for longer and -1 otherwise."
- (let* ((ma (or (get-text-property 0 'org-marker a)
- (get-text-property 0 'org-hd-marker a)))
- (mb (or (get-text-property 0 'org-marker b)
- (get-text-property 0 'org-hd-marker b)))
- (ra (org-review-toreview-p ma))
- (rb (org-review-toreview-p mb)))
- (if (time-less-p ra rb) 1 -1)))
-
-(provide 'org-review)
-
-;;; org-review.el ends here
tools/emacs/lisp/ox-rss.el
@@ -1,414 +0,0 @@
-;;; ox-rss.el --- RSS 2.0 Back-End for Org Export Engine
-
-;; Copyright (C) 2013-2015 Bastien Guerry
-
-;; Author: Bastien Guerry <bzg@gnu.org>
-;; Keywords: org, wp, blog, feed, rss
-
-;; This file is not yet part of GNU Emacs.
-
-;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This library implements a RSS 2.0 back-end for Org exporter, based on
-;; the `html' back-end.
-;;
-;; It requires Emacs 24.1 at least.
-;;
-;; It provides two commands for export, depending on the desired output:
-;; `org-rss-export-as-rss' (temporary buffer) and `org-rss-export-to-rss'
-;; (as a ".xml" file).
-;;
-;; This backend understands two new option keywords:
-;;
-;; #+RSS_EXTENSION: xml
-;; #+RSS_IMAGE_URL: http://myblog.org/mypicture.jpg
-;;
-;; It uses #+HTML_LINK_HOME: to set the base url of the feed.
-;;
-;; Exporting an Org file to RSS modifies each top-level entry by adding a
-;; PUBDATE property. If `org-rss-use-entry-url-as-guid', it will also add
-;; an ID property, later used as the guid for the feed's item.
-;;
-;; The top-level headline is used as the title of each RSS item unless
-;; an RSS_TITLE property is set on the headline.
-;;
-;; You typically want to use it within a publishing project like this:
-;;
-;; (add-to-list
-;; 'org-publish-project-alist
-;; '("homepage_rss"
-;; :base-directory "~/myhomepage/"
-;; :base-extension "org"
-;; :rss-image-url "http://lumiere.ens.fr/~guerry/images/faces/15.png"
-;; :html-link-home "http://lumiere.ens.fr/~guerry/"
-;; :html-link-use-abs-url t
-;; :rss-extension "xml"
-;; :publishing-directory "/home/guerry/public_html/"
-;; :publishing-function (org-rss-publish-to-rss)
-;; :section-numbers nil
-;; :exclude ".*" ;; To exclude all files...
-;; :include ("index.org") ;; ... except index.org.
-;; :table-of-contents nil))
-;;
-;; ... then rsync /home/guerry/public_html/ with your server.
-;;
-;; By default, the permalink for a blog entry points to the headline.
-;; You can specify a different one by using the :RSS_PERMALINK:
-;; property within an entry.
-
-;;; Code:
-
-(require 'ox-html)
-(declare-function url-encode-url "url-util" (url))
-
-;;; Variables and options
-
-(defgroup org-export-rss nil
- "Options specific to RSS export back-end."
- :tag "Org RSS"
- :group 'org-export
- :version "24.4"
- :package-version '(Org . "8.0"))
-
-(defcustom org-rss-image-url "http://orgmode.org/img/org-mode-unicorn-logo.png"
- "The URL of the an image for the RSS feed."
- :group 'org-export-rss
- :type 'string)
-
-(defcustom org-rss-extension "xml"
- "File extension for the RSS 2.0 feed."
- :group 'org-export-rss
- :type 'string)
-
-(defcustom org-rss-categories 'from-tags
- "Where to extract items category information from.
-The default is to extract categories from the tags of the
-headlines. When set to another value, extract the category
-from the :CATEGORY: property of the entry."
- :group 'org-export-rss
- :type '(choice
- (const :tag "From tags" from-tags)
- (const :tag "From the category property" from-category)))
-
-(defcustom org-rss-use-entry-url-as-guid t
- "Use the URL for the <guid> metatag?
-When nil, Org will create ids using `org-icalendar-create-uid'."
- :group 'org-export-rss
- :type 'boolean)
-
-;;; Define backend
-
-(org-export-define-derived-backend 'rss 'html
- :menu-entry
- '(?r "Export to RSS"
- ((?R "As RSS buffer"
- (lambda (a s v b) (org-rss-export-as-rss a s v)))
- (?r "As RSS file" (lambda (a s v b) (org-rss-export-to-rss a s v)))
- (?o "As RSS file and open"
- (lambda (a s v b)
- (if a (org-rss-export-to-rss t s v)
- (org-open-file (org-rss-export-to-rss nil s v)))))))
- :options-alist
- '((:description "DESCRIPTION" nil nil newline)
- (:keywords "KEYWORDS" nil nil space)
- (:with-toc nil nil nil) ;; Never include HTML's toc
- (:rss-extension "RSS_EXTENSION" nil org-rss-extension)
- (:rss-image-url "RSS_IMAGE_URL" nil org-rss-image-url)
- (:rss-categories nil nil org-rss-categories))
- :filters-alist '((:filter-final-output . org-rss-final-function))
- :translate-alist '((headline . org-rss-headline)
- (comment . (lambda (&rest args) ""))
- (comment-block . (lambda (&rest args) ""))
- (timestamp . (lambda (&rest args) ""))
- (plain-text . org-rss-plain-text)
- (section . org-rss-section)
- (template . org-rss-template)))
-
-;;; Export functions
-
-;;;###autoload
-(defun org-rss-export-as-rss (&optional async subtreep visible-only)
- "Export current buffer to a RSS buffer.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-A non-nil optional argument ASYNC means the process should happen
-asynchronously. The resulting buffer should be accessible
-through the `org-export-stack' interface.
-
-When optional argument SUBTREEP is non-nil, export the sub-tree
-at point, extracting information from the headline properties
-first.
-
-When optional argument VISIBLE-ONLY is non-nil, don't export
-contents of hidden elements.
-
-Export is done in a buffer named \"*Org RSS Export*\", which will
-be displayed when `org-export-show-temporary-export-buffer' is
-non-nil."
- (interactive)
- (let ((file (buffer-file-name (buffer-base-buffer))))
- (org-icalendar-create-uid file 'warn-user)
- (org-rss-add-pubdate-property))
- (org-export-to-buffer 'rss "*Org RSS Export*"
- async subtreep visible-only nil nil (lambda () (text-mode))))
-
-;;;###autoload
-(defun org-rss-export-to-rss (&optional async subtreep visible-only)
- "Export current buffer to a RSS file.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-A non-nil optional argument ASYNC means the process should happen
-asynchronously. The resulting file should be accessible through
-the `org-export-stack' interface.
-
-When optional argument SUBTREEP is non-nil, export the sub-tree
-at point, extracting information from the headline properties
-first.
-
-When optional argument VISIBLE-ONLY is non-nil, don't export
-contents of hidden elements.
-
-Return output file's name."
- (interactive)
- (let ((file (buffer-file-name (buffer-base-buffer))))
- (org-icalendar-create-uid file 'warn-user)
- (org-rss-add-pubdate-property))
- (let ((outfile (org-export-output-file-name
- (concat "." org-rss-extension) subtreep)))
- (org-export-to-file 'rss outfile async subtreep visible-only)))
-
-;;;###autoload
-(defun org-rss-publish-to-rss (plist filename pub-dir)
- "Publish an org file to RSS.
-
-FILENAME is the filename of the Org file to be published. PLIST
-is the property list for the given project. PUB-DIR is the
-publishing directory.
-
-Return output file name."
- (let ((bf (get-file-buffer filename)))
- (if bf
- (with-current-buffer bf
- (org-icalendar-create-uid filename 'warn-user)
- (org-rss-add-pubdate-property)
- (write-file filename))
- (find-file filename)
- (org-icalendar-create-uid filename 'warn-user)
- (org-rss-add-pubdate-property)
- (write-file filename) (kill-buffer)))
- (org-publish-org-to
- 'rss filename (concat "." org-rss-extension) plist pub-dir))
-
-;;; Main transcoding functions
-
-(defun org-rss-headline (headline contents info)
- "Transcode HEADLINE element into RSS format.
-CONTENTS is the headline contents. INFO is a plist used as a
-communication channel."
- (unless (or (org-element-property :footnote-section-p headline)
- ;; Only consider first-level headlines
- (> (org-export-get-relative-level headline info) 1))
- (let* ((author (and (plist-get info :with-author)
- (let ((auth (plist-get info :author)))
- (and auth (org-export-data auth info)))))
- (htmlext (plist-get info :html-extension))
- (hl-number (org-export-get-headline-number headline info))
- (hl-home (file-name-as-directory (plist-get info :html-link-home)))
- (hl-pdir (plist-get info :publishing-directory))
- (hl-perm (org-element-property :RSS_PERMALINK headline))
- (anchor (org-export-get-reference headline info))
- (category (org-rss-plain-text
- (or (org-element-property :CATEGORY headline) "") info))
- (pubdate0 (org-element-property :PUBDATE headline))
- (pubdate (let ((system-time-locale "C"))
- (if pubdate0
- (format-time-string
- "%a, %d %b %Y %H:%M:%S %z"
- (org-time-string-to-time pubdate0)))))
- (title (or (org-element-property :RSS_TITLE headline)
- (replace-regexp-in-string
- org-bracket-link-regexp
- (lambda (m) (or (match-string 3 m)
- (match-string 1 m)))
- (org-element-property :raw-value headline))))
- (publink
- (or (and hl-perm (concat (or hl-home hl-pdir) hl-perm))
- (concat
- (or hl-home hl-pdir)
- (file-name-nondirectory
- (file-name-sans-extension
- (plist-get info :input-file))) "." htmlext "#" anchor)))
- (guid (if org-rss-use-entry-url-as-guid
- publink
- (org-rss-plain-text
- (or (org-element-property :ID headline)
- (org-element-property :CUSTOM_ID headline)
- publink)
- info))))
- (if (not pubdate0) "" ;; Skip entries with no PUBDATE prop
- (format
- (concat
- "<item>\n"
- "<title>%s</title>\n"
- "<link>%s</link>\n"
- "<author>%s</author>\n"
- "<guid isPermaLink=\"false\">%s</guid>\n"
- "<pubDate>%s</pubDate>\n"
- (org-rss-build-categories headline info) "\n"
- "<description><![CDATA[%s]]></description>\n"
- "</item>\n")
- title publink author guid pubdate contents)))))
-
-(defun org-rss-build-categories (headline info)
- "Build categories for the RSS item."
- (if (eq (plist-get info :rss-categories) 'from-tags)
- (mapconcat
- (lambda (c) (format "<category><![CDATA[%s]]></category>" c))
- (org-element-property :tags headline)
- "\n")
- (let ((c (org-element-property :CATEGORY headline)))
- (format "<category><![CDATA[%s]]></category>" c))))
-
-(defun org-rss-template (contents info)
- "Return complete document string after RSS conversion.
-CONTENTS is the transcoded contents string. INFO is a plist used
-as a communication channel."
- (concat
- (format "<?xml version=\"1.0\" encoding=\"%s\"?>"
- (symbol-name org-html-coding-system))
- "\n<rss version=\"2.0\"
- xmlns:content=\"http://purl.org/rss/1.0/modules/content/\"
- xmlns:wfw=\"http://wellformedweb.org/CommentAPI/\"
- xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
- xmlns:atom=\"http://www.w3.org/2005/Atom\"
- xmlns:sy=\"http://purl.org/rss/1.0/modules/syndication/\"
- xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"
- xmlns:georss=\"http://www.georss.org/georss\"
- xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\"
- xmlns:media=\"http://search.yahoo.com/mrss/\">"
- "<channel>"
- (org-rss-build-channel-info info) "\n"
- contents
- "</channel>\n"
- "</rss>"))
-
-(defun org-rss-build-channel-info (info)
- "Build the RSS channel information."
- (let* ((system-time-locale "C")
- (title (plist-get info :title))
- (email (org-export-data (plist-get info :email) info))
- (author (and (plist-get info :with-author)
- (let ((auth (plist-get info :author)))
- (and auth (org-export-data auth info)))))
- (date (format-time-string "%a, %d %b %Y %H:%M:%S %z")) ;; RFC 882
- (description (org-export-data (plist-get info :description) info))
- (lang (plist-get info :language))
- (keywords (plist-get info :keywords))
- (rssext (plist-get info :rss-extension))
- (blogurl (or (plist-get info :html-link-home)
- (plist-get info :publishing-directory)))
- (image (url-encode-url (plist-get info :rss-image-url)))
- (ifile (plist-get info :input-file))
- (publink
- (concat (file-name-as-directory blogurl)
- (file-name-nondirectory
- (file-name-sans-extension ifile))
- "." rssext)))
- (format
- "\n<title>%s</title>
-<atom:link href=\"%s\" rel=\"self\" type=\"application/rss+xml\" />
-<link>%s</link>
-<description><![CDATA[%s]]></description>
-<language>%s</language>
-<pubDate>%s</pubDate>
-<lastBuildDate>%s</lastBuildDate>
-<generator>%s</generator>
-<webMaster>%s (%s)</webMaster>
-<image>
-<url>%s</url>
-<title>%s</title>
-<link>%s</link>
-</image>
-"
- title publink blogurl description lang date date
- (concat (format "Emacs %d.%d"
- emacs-major-version
- emacs-minor-version)
- " Org-mode " (org-version))
- email author image title blogurl)))
-
-(defun org-rss-section (section contents info)
- "Transcode SECTION element into RSS format.
-CONTENTS is the section contents. INFO is a plist used as
-a communication channel."
- contents)
-
-(defun org-rss-timestamp (timestamp contents info)
- "Transcode a TIMESTAMP object from Org to RSS.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (org-html-encode-plain-text
- (org-timestamp-translate timestamp)))
-
-(defun org-rss-plain-text (contents info)
- "Convert plain text into RSS encoded text."
- (let (output)
- (setq output (org-html-encode-plain-text contents)
- output (org-export-activate-smart-quotes
- output :html info))))
-
-;;; Filters
-
-(defun org-rss-final-function (contents backend info)
- "Prettify the RSS output."
- (with-temp-buffer
- (xml-mode)
- (insert contents)
- (indent-region (point-min) (point-max))
- (buffer-substring-no-properties (point-min) (point-max))))
-
-;;; Miscellaneous
-
-(defun org-rss-add-pubdate-property ()
- "Set the PUBDATE property for top-level headlines."
- (let (msg)
- (org-map-entries
- (lambda ()
- (let* ((entry (org-element-at-point))
- (level (org-element-property :level entry)))
- (when (= level 1)
- (unless (org-entry-get (point) "PUBDATE")
- (setq msg t)
- (org-set-property
- "PUBDATE" (format-time-string
- (cdr org-time-stamp-formats)))))))
- nil nil 'comment 'archive)
- (when msg
- (message "Property PUBDATE added to top-level entries in %s"
- (buffer-file-name))
- (sit-for 2))))
-
-(provide 'ox-rss)
-
-;;; ox-rss.el ends here
tools/emacs/lisp/paste-sbr.el
@@ -1,72 +0,0 @@
-;;; paste-sbr.el --- Paste to sbr.pm -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2020 Vincent Demeester
-
-;; Author: Vincent Demeester <vincent@sbr.pm>
-;; Keywords: org link github
-;;
-;; This file is not part of GNU Emacs.
-
-;; 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.0, 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:
-
-;; Take selection and share it to paste.sbr.pm
-
-;;; Code:
-
-(defvar htmlize-paste-it-target-directory
- "desktop/sites/paste.sbr.pm")
-(defvar htmlize-paste-it-base-url
- "https://paste.sbr.pm/")
-
-(defun htmlize-paste-it ()
- "Htmlize region-or-buffer and copy to directory."
- (interactive)
- (let* ((start (if (region-active-p)
- (region-beginning) (point-min)))
- (end (if (region-active-p)
- (region-end) (point-max)))
-
- ;; We use a basename-hash.ext.html format
- (basename (file-name-base (buffer-name)))
- (extension (file-name-extension (buffer-name)))
- (hash (sha1 (current-buffer) start end))
- (file-name (concat basename
- "-" (substring hash 0 6)
- "." extension
- ".html"))
-
- (new-file (expand-file-name (concat
- htmlize-paste-it-target-directory
- "/"
- file-name) "~"))
-
- (access-url (concat
- htmlize-paste-it-base-url
- file-name)))
- ;; Region messes with clipboard, so deactivate it
- (deactivate-mark)
- (with-current-buffer (htmlize-region start end)
- ;; Copy htmlized contents to target
- (write-file new-file)
- ;; Ensure target can be accessed by web server
- (chmod new-file #o755))
- ;; Put URL into clipboard
- (kill-new access-url)))
-
-(provide 'paste-sbr)
-;;; paste-sbr.el ends here
tools/emacs/lisp/portal.el
@@ -1,644 +0,0 @@
-;;; portal.el --- Run processes in portals
-;;
-;; Copyright (C) 2024 Chris Done
-;;
-;; This file 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 file 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 GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Customizations
-
-(defgroup portal nil
- "Portal group."
- :group 'convenience)
-
-(defcustom portal-outputs-directory
- "~/.local/share/portals/"
- "Directory where to create output artifacts."
- :type 'string :group 'portal)
-
-(defcustom portal-default-stdout-buffer-len
- 4096
- "Default buffer length for the stdout preview."
- :group 'portal :type 'number)
-
-(defcustom portal-default-stderr-buffer-len
- 4096
- "Default buffer length for the stderr preview."
- :group 'portal :type 'number)
-
-(defface portal-face
- '((((class color) (background dark))
- (:foreground "#fff" :bold t))
- (((class color) (background light))
- (:foreground "#000" :bold t)))
- "Portal face."
- :group 'portal)
-
-(defface portal-exited-stdout-face
- '((t :foreground "#acac9e"))
- "Portal exited stdout face."
- :group 'portal)
-
-(defface portal-timestamp-face
- '((t :foreground "#888888"))
- "Portal exited stdout face."
- :group 'portal)
-
-(defface portal-exited-stderr-face
- '((t :foreground "#aa7070"))
- "Portal exited stderr face."
- :group 'portal)
-
-(defface portal-exit-success-face
- '((t :foreground "#89b664"))
- "Portal exit successful face."
- :group 'portal)
-
-(defface portal-exit-failure-face
- '((t :foreground "#ae6161"))
- "Portal exit failure face."
- :group 'portal)
-
-(defface portal-meta-face
- '((t :foreground "#89b664"))
- "Portal meta face."
- :group 'portal)
-
-(defface portal-stdout-face
- '((t :inherit 'default))
- "Portal stdout face."
- :group 'portal)
-
-(defface portal-stderr-face
- '((t :foreground "#ae6161"))
- "Portal stderr face."
- :group 'portal)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Interactive commands
-
-(defun portal-insert-shell-command (command)
- "Launch an asynchronous shell of COMMAND, make a portal associated
-with the current buffer and insert the portal into the current
-buffer."
- (interactive "sCommand: ")
- (portal-insert-command
- (list shell-file-name shell-command-switch command)))
-
-(defun portal-open-stdout ()
- "Open the stdout of the file at point."
- (interactive)
- (with-current-buffer (find-file-other-window (portal-file-name (portal-at-point) "stdout"))
- (portal-ansi-colors-minor-mode)
- (auto-revert-tail-mode)
- (goto-char (point-max))
- (push-mark (point-max))))
-
-(defun portal-open-stderr ()
- "Open the stderr of the file at point."
- (interactive)
- (with-current-buffer (find-file-other-window (portal-file-name (portal-at-point) "stderr"))
- (portal-ansi-colors-minor-mode)
- (auto-revert-tail-mode)
- (goto-char (point-max))
- (push-mark (point-max))))
-
-(defun portal-interrupt ()
- "Interrupt the process at point."
- (interactive)
- (let ((proc (get-process (portal-process-name (portal-at-point)))))
- (when (process-live-p proc)
- (interrupt-process proc))))
-
-(defun portal-rerun ()
- "Re-run portal at point."
- (interactive)
- (portal-jump-to-portal)
- (let* ((portal (portal-at-point))
- (command (portal-read-json-file portal "command"))
- (env (portal-read-json-file portal "env"))
- (default-directory (portal-read-json-file portal "directory")))
- (portal-interrupt)
- (delete-region (line-beginning-position) (line-end-position))
- (portal-wipe-summary)
- (portal-insert-command (append command nil))
- (portal-refresh-soon)))
-
-(defun portal-edit ()
- "Edit and re-run portal at point."
- (interactive)
- (portal-jump-to-portal)
- (portal-interrupt)
- (let* ((portal (portal-at-point))
- (command
- (vector
- shell-file-name
- shell-command-switch
- (read-from-minibuffer
- "Edit command: "
- (portal-as-shell-command (portal-read-json-file portal "command")))))
- (env (portal-read-json-file portal "env"))
- (default-directory (portal-read-json-file portal "directory")))
- (delete-region (line-beginning-position) (line-end-position))
- (portal-wipe-summary)
- (portal-insert-command (append command nil))
- (portal-refresh-soon)))
-
-(defun portal-clone ()
- "Clone the portal at point."
- (interactive)
- (portal-jump-to-portal)
- (let* ((portal (portal-at-point))
- (command (portal-read-json-file portal "command"))
- (env (portal-read-json-file portal "env"))
- (default-directory (portal-read-json-file portal "directory")))
- (save-excursion (insert "\n"))
- (portal-insert-command (append command nil))
- (portal-refresh-soon)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Launching processes
-
-(defun portal-start (buffer portal stdout-path stderr-path program program-args)
- "Run PROGRAM-PATH with ARGS, connect it to portal PORTAL in buffer
-BUFFER, and write the stdout to STDOUT-PATH and stderr to
-STDERR-PATH."
- (let* ((stderr-pipe
- (make-pipe-process
- :name (portal-stderr-process-name portal)
- :buffer buffer
- :noquery t
- :filter 'portal-process-filter
- :sentinel 'portal-stderr-pipe-sentinel))
- (main-process
- (make-process
- :name (portal-process-name portal)
- :buffer buffer
- :command (cons program program-args)
- :noquery nil
- :connection-type 'pipe
- :sentinel 'portal-main-process-sentinel
- :filter 'portal-process-filter
- :stderr stderr-pipe)))
-
- (process-put stderr-pipe :portal portal)
- (process-put stderr-pipe :output-path stderr-path)
- (process-put stderr-pipe :buffer "")
- (process-put stderr-pipe :buffer-len portal-default-stderr-buffer-len)
-
- (process-put main-process :portal portal)
- (process-put main-process :output-path stdout-path)
- (process-put main-process :buffer "")
- (process-put main-process :buffer-len portal-default-stdout-buffer-len)
-
- ;; Connect the two processes.
- (process-put main-process :stderr-process stderr-pipe)
-
- (portal-write-json-file portal "command" (apply #'vector (cons program program-args)))
- (portal-write-json-file portal "env" (apply #'vector process-environment))
- (portal-write-json-file portal "directory" default-directory)
- (portal-write-json-file portal "status" (format "%S" (process-status main-process)))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Process filtering
-
-(defun portal-process-filter (process output)
- (let ((filepath (process-get process :output-path)))
- (when debug-on-error
- (message "portal-process-filter: Writing to %s" filepath))
- (portal-accumulate-buffer process output)
- (with-temp-buffer
- (insert output)
- (write-region (point-min) (point-max) filepath :append :no-messages))))
-
-(defun portal-accumulate-buffer (process output)
- "Accumulate some OUTPUT into PROCESS's preview buffer."
- (process-put
- process
- :buffer (portal-shrink-preview
- (process-get process :buffer-len)
- (concat (process-get process :buffer) output))))
-
-(defun portal-shrink-preview (len string)
- "Shrink a preview buffer STRING to the right length."
- (if (> (length string) len)
- (substring string (- len))
- string))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Sentinels
-
-(defun portal-main-process-sentinel (process event)
- "Handles the main process's status updates."
- (when debug-on-error
- (message "main-process-sentinel: %S: %S" process event))
- (portal-write-json-file
- (process-get process :portal)
- "status" (format "%S" (process-exit-status process))))
-
-(defun portal-stderr-pipe-sentinel (process event)
- "Handles the stderr pipe's status updates."
- (when debug-on-error
- (message "stderr-pipe-sentinel: %S: %S" process event)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; File/directory operations
-
-(defun portal-ensure-directory (portal)
- "Create the stdout/stderr files for PORTAL in an appropriate
-location."
- (let ((directory (concat (file-name-as-directory portal-outputs-directory) portal)))
- (make-directory directory :including-parents)
- directory))
-
-(defun portal-directory-exists-p (portal)
- "Check PORTAL has a directory that exists."
- (let ((directory (concat (file-name-as-directory portal-outputs-directory) portal)))
- (file-exists-p directory)))
-
-(defun portal-file-exists-p (portal name)
- "Check PORTAL has a file NAME that exists."
- (let ((directory (concat (file-name-as-directory portal-outputs-directory) portal)))
- (file-exists-p (concat (file-name-as-directory directory) name))))
-
-(defun portal-persist-file (portal name content)
- "Persist CONTENT to disk with filename NAME."
- (with-temp-buffer
- (insert content)
- (write-region
- (point-min) (point-max)
- (portal-file-name portal name)
- nil ; no-append
- :no-messages))
- content)
-
-(defun portal-write-json-file (portal name expr)
- "Print EXPR to disk with filename NAME."
- (with-temp-buffer
- (insert (json-serialize expr))
- (write-region
- (point-min) (point-max)
- (portal-file-name portal name)
- nil ; no-append
- :no-messages))
- expr)
-
-(defun portal-read-json-file (portal name)
- "Read JSON content from file NAME for the given PORTAL."
- (with-temp-buffer
- (insert-file-contents (portal-file-name portal name))
- (json-parse-string (buffer-string))))
-
-(defun portal-read-file (portal name)
- "Read content from file NAME for the given PORTAL."
- (with-temp-buffer
- (let ((file (portal-file-name portal name)))
- (when (file-exists-p file)
- (insert-file-contents file)))
- (buffer-string)))
-
-(defun portal-tail-file (portal n name)
- "Tail last N lines of file NAME for the given PORTAL."
- (with-temp-buffer
- (let ((file (portal-file-name portal name)))
- (if (file-exists-p file)
- (portal-tail-n-lines n file)
- ""))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Nano-IDs
-
-(defun portal-generate-nanoid ()
- "Generate a Nano ID of the form `portal_NGMyMDVkZjZiYTVlZTVhM' using SHA-1."
- (let* ((random-string (format "%s%s%S" (emacs-pid) (current-time-string) (random)))
- (sha1-hash (secure-hash 'sha1 random-string))
- (base64-encoded (base64-encode-string sha1-hash))
- (nanoid (string-trim-right (substring base64-encoded 0 21))))
- (concat "portal_" nanoid)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; A minor mode for applying ansi-term colors to a buffer
-
-(define-minor-mode portal-ansi-colors-minor-mode
- "Apply ANSI colors for terminal outputs."
- :init-value nil
- :lighter "ANSI"
- (ansi-color-apply-on-region (point-min) (point-max)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; A small minor mode that just sets up a timer that runs a thing in a
-;; given buffer every N seconds
-
-(defvar-local portal-alpha-timer
- nil)
-
-(define-minor-mode portal-alpha-minor-mode
- "TODO"
- :init-value nil
- :lighter "@"
- (when portal-alpha-timer (cancel-timer portal-alpha-timer))
- (when portal-alpha-minor-mode
- (setq portal-alpha-timer
- (run-with-timer 1 2 'portal-beta-refresh (current-buffer)))))
-
-(defun portal-refresh-soon ()
- "Trigger a refresh within the blink of an eye, but no sooner, or
-later."
- (run-with-timer 0.100 nil 'portal-beta-refresh (current-buffer)))
-
-(defun portal-beta-refresh (buffer)
- "Refresh portal displays."
- (when (buffer-live-p buffer)
- (let ((window (get-buffer-window buffer)))
- (when window
- (with-current-buffer buffer
- (let ((point (point)))
- (save-excursion
- (goto-char (point-min))
- (while (and (re-search-forward portal-regexp nil t nil)
- (<= (point) (window-end window)))
- (when (<= (window-start window) (point) (window-end window))
- (let* ((portal (match-string 0))
- (process (get-process (portal-process-name portal)))
- (summary (if (portal-directory-exists-p portal)
- (portal-summary portal process)
- "# Invalid portal."))
- (match-end (match-end 0))
- (old-summary (get-text-property (line-beginning-position) 'portal-summary)))
- (unless (and old-summary (string= summary old-summary))
- (put-text-property (line-beginning-position) (point)
- 'portal-summary
- summary)
- (put-text-property (line-beginning-position) (point)
- 'portal
- portal)
- (portal-wipe-summary)
- (insert "\n" summary))))))
- (goto-char point)))))))
-
-(defun portal-wipe-summary ()
- "Wipe the '# summary' lines that follow the portal."
- (save-excursion
- (when (looking-at "\n#")
- (forward-line 1)
- (let ((point (point)))
- (or (search-forward-regexp "^[^#]" nil t 1)
- (goto-char (point-max)))
- (delete-matching-lines "^#" point (point))))))
-
-(defun portal-summary (portal process)
- "Generate a summary of the portal."
- (let* ((command (portal-read-json-file portal "command"))
- (directory (portal-read-json-file portal "directory"))
- (status (portal-read-json-file portal "status"))
- (stdout (if process
- (portal-last-n-lines
- 5
- (process-get process :buffer))
- (portal-tail-file portal 5 "stdout")))
- (stderr (if process
- (portal-last-n-lines
- 5
- (process-get (process-get process :stderr-process) :buffer))
- (portal-tail-file portal 5 "stderr")))
- (started-time
- (file-attribute-modification-time (file-attributes (portal-file-name portal "command"))))
- (exited-time
- (file-attribute-modification-time (file-attributes (portal-file-name portal "status")))))
- (with-temp-buffer
- (insert (propertize
- (concat "# (" (if (string= status "run") "🌀" status) ") " (portal-as-shell-command command))
- 'face
- (if (string= status "run")
- 'portal-meta-face
- (if (string= status "0")
- 'portal-exit-success-face
- 'portal-exit-failure-face))))
- (insert "\n"
- (concat
- (propertize (format-time-string "# Started: %Y-%m-%d %T" started-time)
- 'face 'portal-timestamp-face)
- (if (string= status "run")
- ""
- (propertize (concat
- (format-time-string ", exited: %Y-%m-%d %T" exited-time)
- " => "
- (portal-display-time-difference started-time exited-time))
- 'face 'portal-timestamp-face))))
- ;; Only show if it's different to the current directory,
- ;; otherwise it's noise.
- (unless (string= default-directory directory) (insert "\n# " directory))
- (unless (= 0 (length (string-trim stdout)))
- (insert "\n"
- (propertize (portal-clean-output stdout)
- 'face (if (string= status "run")
- 'portal-stdout-face
- 'portal-exited-stdout-face))))
- (unless (= 0 (length (string-trim stderr)))
- (insert "\n"
- (propertize (portal-clean-output stderr)
- 'face
- (if (string= status "run")
- 'portal-stderr-face
- 'portal-exited-stderr-face))))
- (propertize (buffer-string)
- 'portal portal))))
-
-(defun portal-display-time-difference (start-time end-time)
- "Display the time difference between START-TIME and END-TIME in human-readable format.
-START-TIME and END-TIME should be Emacs Lisp time values as returned by `current-time'.
-The function will display the time in the most appropriate unit (from ns to days)."
- (let* ((diff (float-time (time-subtract end-time start-time))))
- (apply #'format
- (cons "%.3f %s"
- (cond
- ((< diff 1e-6)
- (list (* diff 1e9) "ns"))
- ((< diff 1e-3)
- (list (* diff 1e6) "us"))
- ((< diff 1)
- (list (* diff 1e3) "ms"))
- ((< diff 60)
- (list diff "s"))
- ((< diff 3600)
- (list (/ diff 60) "mins"))
- ((< diff 86400)
- (list (/ diff 3600) "hours"))
- (t
- (list (/ diff 86400) "days")))))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; String generation
-
-(defun portal-as-shell-command (command)
- "If the vector COMMAND is a shell run, strip the prefix, else return the whole thing joined."
- (if (and (= 3 (length command))
- (string= (elt command 0) shell-file-name)
- (string= (elt command 1) shell-command-switch))
- (elt command 2)
- (mapconcat 'shell-quote-argument command " ")))
-
-(defun portal-clean-output (output)
- "Clean output for previewing, prefixed with #."
- (portal-limit-lines-to-80-columns
- (concat "# " (replace-regexp-in-string
- "\n" "\n# "
- (portal-no-empty-lines output)))))
-
-(defun portal-limit-lines-to-80-columns (string)
- "Limit all lines in STRING to 80 columns."
- (with-temp-buffer
- (insert string)
- (goto-char (point-min))
- (while (not (eobp))
- (move-to-column 80 t)
- (delete-region (point) (line-end-position))
- (forward-line))
- (buffer-string)))
-
-(defun portal-process-name (portal)
- (concat portal "-main-process"))
-
-(defun portal-stderr-process-name (portal)
- (concat portal "-stderr-pipe"))
-
-(defun portal-file-name (portal name)
- (concat (file-name-as-directory (portal-ensure-directory portal)) name))
-
-(defun portal-no-empty-lines (string)
- "Drop empty lines from a string."
- (replace-regexp-in-string
- ;; Drop ANSI codes from terminal output
- ;; <https://superuser.com/questions/380772/removing-ansi-color-codes-from-text-stream>
- "\\(\x1B\\[[0-9;]*[A-Za-z]\\|[\x00-\x09\x0B-\x1F\x7F]\\|\n$\\|^\n\\)"
- ""
- string))
-
-(defun portal-last-n-lines (n string)
- "Take last N lines from STRING."
- (mapconcat #'identity (reverse (seq-take (reverse (split-string string "[\r\n]+" t)) n)) "\n"))
-
-(defun portal-tail-n-lines (n file-path)
- "Tail the last N lines from FILE-PATH using tail, if possible. If
-not possible (due to lack of such tool), return nil."
- (let ((this-buffer (current-buffer)))
- (with-temp-buffer
- (let ((out-buffer (current-buffer)))
- (with-current-buffer this-buffer
- (cl-case (call-process "tail" nil out-buffer nil "-n" (format "%d" n)
- (expand-file-name file-path))
- (0 (with-current-buffer out-buffer (buffer-string)))
- (t "")))))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Finding portals and gathering information for them
-
-(defconst portal-regexp "\\<portal_[A-Za-z0-9]\\{21\\}\\>"
- "Match on a portal's unique ID.")
-
-(defun portal-at-point ()
- "Return the portal at point."
- (or (save-excursion
- (goto-char (line-beginning-position))
- (when (looking-at portal-regexp)
- (buffer-substring (match-beginning 0) (match-end 0))))
- (get-text-property (point) 'portal)
- (error "Not at a portal.")))
-
-(defun portal-jump-to-portal ()
- "If there's a portal at point or a summary of a portal at point,
-jump to the portal at the beginning of the line upwards within
-the same paragraph."
- (let ((portal (portal-at-point)))
- (goto-char
- (save-excursion
- (goto-char (line-end-position))
- (re-search-backward
- (concat "^" (regexp-quote portal))
- (save-excursion (forward-paragraph -1))
- nil
- 1)))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Notes
-
-;; Use this on a portals buffer to stop it constantly being saved:
-;
-;; (setq buffer-save-without-query t)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Major mode
-
-(defvar-keymap portal-mode-map
- "M-!" 'portal-dwim-execute
- "C-c C-c" 'portal-interrupt
- "RET" 'portal-jump-to-thing-at-point
- "M-p" 'portal-rerun
- )
-
-(define-derived-mode portal-mode
- fundamental-mode "Portals"
- "Major mode for portals."
- (setq buffer-save-without-query t)
- (portal-alpha-minor-mode))
-
-(defun portal-insert-command (command)
- "Launch an asynchronous proc of COMMAND, make a portal associated
-with the current buffer and insert the portal into the current
-buffer."
- (let* ((portal (portal-generate-nanoid)))
- (portal-start
- (current-buffer)
- portal
- (portal-file-name portal "stdout")
- (portal-file-name portal "stderr")
- (car command)
- (cdr command))
- (insert portal)))
-
-(defun portal-dwim-execute ()
- (interactive)
- (call-interactively
- (if (condition-case nil
- (portal-at-point)
- (error nil))
- 'portal-edit
- 'portal-shell-command)))
-
-(defun portal-shell-command (command)
- "Run a shell command and insert it at point."
- (interactive "sCommand: ")
- (portal-insert-command
- (list shell-file-name shell-command-switch command)))
-
-(defun portal-jump-to-thing-at-point ()
- "Jump to the thing at point, i.e. an stdout/stderr output jumps to
-the file."
- (interactive)
- (let ((face (get-text-property (point) 'face)))
- (cond
- ((eq face 'portal-stderr-face)
- (portal-open-stderr))
- ((eq face 'portal-exited-stderr-face)
- (portal-open-stderr))
- ((eq face 'portal-stdout-face)
- (portal-open-stdout))
- ((eq face 'portal-exited-stdout-face)
- (portal-open-stdout))
- (t (call-interactively 'newline)))))
-
-(provide 'portal)
-
tools/emacs/lisp/project-func.el
@@ -1,150 +0,0 @@
-;;; project-func.el --- -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Code:
-(require 'project)
-(require 'vterm)
-(require 'json)
-(require 'vc)
-
-(defun in-git-repo-p ()
- "Check if current directory is in a git repository."
- (eq (vc-backend (or buffer-file-name default-directory))
- 'Git))
-
-(defun is-github-repo-p ()
- "Check if current git repository has a GitHub remote."
- (when (in-git-repo-p)
- (string-match-p "github\\.com"
- (shell-command-to-string "git remote -v"))))
-
-(defun fetch-github-prs ()
- "Fetch GitHub PRs synchronously."
- (let* ((output (shell-command-to-string "gh pr list --limit=5000 --json number,title,author,url,baseRefName,labels"))
- (prs (json-read-from-string output)))
- prs))
-
-(defun format-pr-candidates (prs)
- "Format PR data into candidates for completion."
- (mapcar (lambda (pr)
- (let-alist pr
- (cons (format "#%d %s (by @%s) on %s" .number .title .author.login .baseRefName)
- .number)))
- prs))
-
-;;;###autoload
-(defun checkout-github-pr ()
- "Interactive function to select and checkout a GitHub PR."
- (interactive)
- (cond
- ((not (in-git-repo-p))
- (message "Not in a Git repository"))
- ((not (is-github-repo-p))
- (message "Not a GitHub repository"))
- (t
- (let* ((prs (fetch-github-prs))
- (candidates (format-pr-candidates prs))
- (selected (if candidates
- (cdr (assoc (completing-read "Checkout PR: " candidates)
- candidates))
- nil)))
- (if selected
- (shell-command (format "gh pr checkout %d" selected))
- (message "No pull requests found"))))))
-
-;;;###autoload
-(defun vde-project--project-current ()
- "Return directory from `project-current' based on Emacs version."
- (if (>= emacs-major-version 29)
- (project-root (project-current))
- (cdr (project-current))))
-
-;;;###autoload
-(defun vde-project--project-root-or-default-directory ()
- "Return path to the project root *or* the default-directory."
- (cond
- ((and (featurep 'project) (project-current))
- (project-root (project-current)))
- (t default-directory)))
-
-;;;##autoload
-(defun vde/project-run-in-vterm (command &optional directory)
- "Run the given `COMMAND' in a new vterm buffer in `project-root' or the
-given `DIRECTORY'.
-
-This is similar to `compile' but with vterm.
-One reason for this is to be able to run commands that needs a TTY."
- (interactive "sCommand: ")
- (let* ((cwd (or directory (vde-project--project-root-or-default-directory)))
- (default-directory cwd)
- (buffer-name (format "*vterm %s: %s*" cwd command))
- (buffer (get-buffer buffer-name))
- (vterm-kill-buffer-on-exit nil)
- (vterm-shell (concat "bash -c '" command ";exit'")))
- (when buffer
- (kill-buffer buffer))
- (let ((buffer (generate-new-buffer buffer-name)))
- (pop-to-buffer buffer)
- (with-current-buffer buffer
- (vterm-mode)))))
-
-;;;###autoload
-(defun vde/open-readme ()
- "Open a README file in the current project.
-It will search for README.org, README.md or README in that order"
- (interactive)
- (let* ((default-directory (vde-project--project-current)))
- (cond ((file-exists-p (expand-file-name "README.org" default-directory))
- (find-file "README.org"))
- ((file-exists-p (expand-file-name "README.md" default-directory))
- (find-file "README.md"))
- ((file-exists-p (expand-file-name "README" default-directory))
- (find-file "README")))))
-
-;;;###autoload
-(defun vde/project-try-local (dir)
- "Determine if DIR is a non-VC project."
- (if-let ((root (if (listp vde/project-local-identifier)
- (seq-some (lambda (n)
- (locate-dominating-file dir n))
- vde/project-local-identifier)
- (locate-dominating-file dir vde/project-local-identifier))))
- (cons 'local root)))
-
-;;;###autoload
-(defun vde/project-vterm (&optional command)
- "Run `vterm' on project.
-If a buffer already exists for running a vterm shell in the project's root,
-switch to it. Otherwise, create a new vterm shell."
- (interactive)
- (let* ((default-directory (vde-project--project-current))
- (default-project-vterm-name (project-prefixed-buffer-name "vterm"))
- (vterm-buffer (get-buffer default-project-vterm-name)))
- (if (and vterm-buffer (not current-prefix-arg))
- (pop-to-buffer-same-window vterm-buffer)
- (let* ((cd-cmd (concat " cd " (shell-quote-argument default-directory))))
- (vterm default-project-vterm-name)
- (with-current-buffer vterm-buffer
- (vterm-send-string cd-cmd)
- (vterm-send-return))))
- (when command
- (vterm-send-string command)
- (vterm-send-return))))
-
-;;;###autoload
-(defun vde/project-eat ()
- "Run Eat term in the current project's root directory.
-If a buffer already exists for running Eshell in the project's root,
-switch to it. Otherwise, create a new Eshell buffer.
-With \\[universal-argument] prefix arg, create a new Eshell buffer even
-if one already exists."
- (interactive)
- (defvar eat-buffer-name)
- (let* ((default-directory (project-root (project-current t)))
- (eat-buffer-name (project-prefixed-buffer-name "eat"))
- (eat-buffer (get-buffer eat-buffer-name)))
- (if (and eat-buffer (not current-prefix-arg))
- (pop-to-buffer eat-buffer (bound-and-true-p display-comint-buffer-action))
- (eat shell-file-name))))
-
-(provide 'project-func)
-;;; project-func.el ends here
tools/emacs/lisp/project-headerline.el
@@ -1,920 +0,0 @@
-;;; project-headerline.el --- Customizable project headerline -*- lexical-binding: t -*-
-
-;; Copyright (C) 2025 Victor Gaydov and contributors
-;; Copyright (C) 2020 emacs-lsp maintainers
-
-;; Author: Victor Gaydov <victor@enise.org>
-;; Created: 03 Feb 2025
-;; URL: https://github.com/gavv/project-headerline
-;; Version: 0.4
-;; Package-Requires: ((emacs "28.2") (f "0.21.0") (s "1.13.0") (all-the-icons "5.0.0"))
-;; Keywords: convenience
-
-;;; License:
-
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; Notice:
-
-;; Several functions were ported from lsp-headerline.el, so the copyrights
-;; includes one from that module.
-
-;;; Commentary:
-
-;; project-headerline implements a minor mode that shows a headerline with
-;; current project name, and the path to current buffer from the project root.
-
-;; It is inspired by lsp-headerline, but it doesn't show symbol and diagnostic
-;; information, has no dependency on lsp, and can be used for buffers of any kind.
-
-;; Please refer to README.org and docstrings for further details.
-
-;;; Code:
-
-(require 'dired-aux)
-(require 'project)
-(require 'seq)
-(require 'vc)
-
-(require 'projectile nil 'noerror)
-(require 'magit nil 'noerror)
-(require 'all-the-icons nil 'noerror)
-
-(require 'f)
-(require 's)
-
-(defgroup project-headerline nil
- "Customizable project headerline."
- :prefix "project-headerline-"
- :group 'convenience
- :link '(url-link "https://github.com/gavv/project-headerline"))
-
-(defface project-headerline-project-name
- '((t :inherit font-lock-string-face :weight bold))
- "Face used for \\='project-name segment."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline)
-
-(defface project-headerline-path-in-project
- '((t :inherit font-lock-keyword-face))
- "Face used for \\='path-in-project segment."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline)
-
-(defface project-headerline-buffer-name
- '((t :inherit font-lock-builtin-face))
- "Face used for \\='buffer-name segment."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline)
-
-(defface project-headerline-segment-separator
- '((t :inherit shadow :height 0.8))
- "Face used for separator between segments."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline)
-
-(defface project-headerline-path-separator
- '((t :inherit shadow :height 0.8))
- "Face used for between path components inside `path-in-project' segment."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline)
-
-(defface project-headerline-space
- '((t :height 0.5))
- "Face used for spaces around segment and path separators."
- :package-version '(project-headerline . "0.2")
- :group 'project-headerline)
-
-(defcustom project-headerline-display-segments
- '(
- ;; list of pre-defined symbols, each symbol corresponds to a segment
- project-name
- path-in-project
- buffer-name
- ;;
- )
- "Which segments to show and in what order.
-
-Must be a list of symbols, where each symbol represents a segment:
-
- - `project-name' - name of project where current file belongs
- - `path-in-project' - relative path from project root up to the current file
- - `buffer-name' - file name or buffer name
-
-`path-in-project' segment is present only if buffer is file or directory.
-`buffer-name' segment displays file or directory name if buffer is visiting one,
-and uses function (buffer-name) otherwise."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type '(repeat
- (choice (const :tag "Project name." project-name)
- (const :tag "Directories up to project." path-in-project)
- (const :tag "Buffer or file name." buffer-name)))
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-segment-separator nil
- "String or icon to separate segments.
-
-Icon is actually also a string, but with special properties.
-For example, you can create one using `all-the-icons-material'.
-
-When separator is nil, `project-headerline-icon-function' is used
-to create it with default icon name."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type '(choice (const :tag "Default" nil)
- string)
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-path-separator nil
- "String or icon to separate path components inside \\='path-in-project segment.
-
-Icon is actually also a string, but with special properties.
-For example, you can create one using `all-the-icons-material'.
-
-When separator is nil, `project-headerline-icon-function' is used
-to create it with default icon name."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type '(choice (const :tag "Default" nil)
- string)
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-path-ellipsis "..."
- "String or icon used when \\='path-in-project' segment is truncated.
-
-If the segment is too long, a few leading path components are
-replaced with the value of this variable."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type 'string
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-detect-alist
- `(
- ;; detect using projectile, if installed
- (projectile :allow-remote nil
- :describe ,(lambda ()
- (when (and (featurep 'projectile)
- (projectile-project-p))
- (list :name (projectile-project-name)
- :path (projectile-project-root)))))
- ;; detect using builtin project.el package
- (project :allow-remote nil
- :describe ,(lambda ()
- (when-let* ((project (project-current)))
- (list :name (f-base (project-root project))
- :path (project-root project)))))
- ;; detect using magit, if installed
- (magit :allow-remote nil
- :describe ,(lambda ()
- (when (featurep 'magit)
- (when-let* ((magit-root (magit-toplevel)))
- (list :name (f-filename magit-root)
- :path (f-full magit-root))))))
- ;; detect using builtin vc package
- (vc :allow-remote nil
- :describe ,(lambda ()
- (when-let* ((vc-root (vc-root-dir)))
- (list :name (f-filename vc-root)
- :path (f-full vc-root)))))
- ;;
- )
- "Assoc list of project detection methods.
-
-Assoc list key is a symbol of your choice.
-Assoc list value is a plist with the following properties:
- - `:allow-remote' - whether to use this method on remote files
- - `:describe' - detection function
-
-`:allow-remote' is by default disabled for all methods because it
-may be very slow (depending on your connection).
-
-Detection function should take no arguments and return a plist:
- - `:name' - project name
- - `:path' - project path (tramp paths are allowed)
-
-Detection methods are tried one by one, until some of them
-returns non-nil.
-
-Used by default implementation of
-`project-headerline-describe-project-function'."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type '(alist :key-type symbol
- :value-type (plist :options ((:allow-remote boolean)
- (:describe function))))
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-fallback-alist
- '(
- ;; pseudo-project "~" for all orphan files under $HOME
- ("~" . "~/")
- ;; pseudo-project "/" for all other orphan files
- ("/" . "/")
- ;;
- )
- "Assoc list of fallback projects when normal detection fails.
-
-Assoc list key is project name.
-Assoc list value is project path.
-
-If no project was detected using `project-headerline-detect-alist',
-then `project-headerline-fallback-alist' is scanned. A fallback
-project is selected if it's path is the parent of buffer's path.
-
-You can use it both for real projects with hard-coded paths
-\(e.g. if they're not identified by common methods), and for
-fallbacks for buffers that don't really belong to a project.
-
-By default, two `pseudo projects` are registered: `~' for any
-file inside home directory, and `/' for any file elsewhere
-on filesystem. You can disable this by removing corresponding
-elements from the assoc list."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type '(alist :key-type (string :tag "Project Name")
- :value-type (string :tag "Project Path"))
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-rename-alist
- '(
- ;; magit
- ("^\\(magit\\):.*" . "\\1")
- ("^\\(magit-[a-z]+\\):.*" . "\\1")
- ;; compilation
- ("^\\*compilation\\*<.*>" . "compilation")
- ("^\\*compilation<.*>\\*" . "compilation")
- ;;
- )
- "Assoc list of buffer rename rules.
-
-Assoc list key is a regular expression.
-Assoc list value is a replacement string that can use capture groups.
-
-Keys and values are passed to `replace-regexp-in-string' and FROM and
-TO arguments. If any of the rule matches buffer, buffer name displayed
-in headerline is changed according to the replacement."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type '(alist :key-type (string :tag "Buffer Name Regexp")
- :value-type (string :tag "Buffer Name Replacement"))
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-describe-project-function
- #'project-headerline-describe-project
- "Function that returns properties of current project.
-
-Takes no arguments and returns plist:
- - `:name' - project name
- - `:path' - project directory path
-
-Default implementation uses the following algorithm:
- - if `project-headerline-current-project' is set, uses it
- - tries rules from `project-headerline-detect-alist'
- - tries paths from `project-headerline-fallback-alist'"
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type 'function
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-describe-buffer-function
- #'project-headerline-describe-buffer
- "Function that returns properties of current buffer.
-
-Takes no arguments and returns plist:
- - `:type' - kind of buffer, one of the symbols: `file', `dir', `other'
- - `:dir' - path to buffer's directory
- - `:name' - name of buffer
-
-For `file' buffers, `:dir' is path to directory containing the file.
-For `dir' buffers, `:dir' is path to directory itself.
-For `other' buffers, `:dir' is path to a directory associated with
-the buffer, typically `default-directory' inside that buffer.
-
-Default implementation reports `dir' for Dired buffers, `file' for
-buffers with non-empty variable `buffer-file-name', and `other' for
-the rest. It also applies buffer renaming rules according to variable
-`project-headerline-rename-alist'."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type 'function
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-format-function
- #'project-headerline-format
- "Function to format headerline from project and buffer properties.
-
-Takes two arguments:
- - `project' - plist from `project-headerline-describe-project-function'
- - `buffer' - plist from `project-headerline-describe-buffer-function'
-
-Returns propertized string with headerline contents.
-
-Default implementation formats headerline according to variables
-`project-headerline-display-segments', `project-headerline-segment-separator',
-`project-headerline-path-separator' (or `project-headerline-icon-function'),
-and applies corresponding faces."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type 'function
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-icon-function
- #'project-headerline-icon
- "Function to create icon from name.
-
-Takes two arguments:
- - `icon-name' - string name of the icon
- - `icon-face' - face to apply to the icon
-
-Returns propertized string with the icon.
-If icon is not available, returns nil. In this case fallback
-character will be used instead of the icon.
-
-Default implementation uses `all-the-icons-material' when it's
-available, or returns nil otherwise."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type 'function
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-width-function
- #'project-headerline-width
- "Function to return maximum headerline width.
-Takes no arguments and returns number of characters."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type 'function
- :initialize 'custom-initialize-default
- :set 'project-headerline--set-variable)
-
-(defcustom project-headerline-mode-list
- '(prog-mode
- conf-mode
- text-mode
- dired-mode)
- "Modes in which to enable `project-headerline-mode' automatically.
-
-When `global-project-headerline-mode' is enabled, it enables headerline
-in buffer if its major mode is derived from one of these modes.
-
-Note that minibuffer and hidden buffers are always excluded."
- :package-version '(project-headerline . "0.1")
- :group 'project-headerline
- :type '(repeat symbol))
-
-(defvar-local project-headerline-current-project nil
- "Overwrite current project path.
-
-If this variable is set, it is used instead of `project-headerline-detect-alist'
-and `project-headerline-fallback-alist' and defines project name and path.
-
-It can be either a string or a list:
-
- - If it's a string, it should be a path to project directory. Project name
- is set to the directory name.
-
- - If it's a list, it should be a plist with project properties, in the same
- format as returned by `project-headerline-describe-project-function'.
-
-It's convenient to set this from local variables, e.g. in `.dir-locals.el'
-in the project root.")
-
-;; Forward-declate mode variable.
-(defvar project-headerline-mode)
-
-(defun project-headerline--set-variable (symbol value)
- "Setter for defcustom.
-Assigns value to variable and invokes `project-headerline-reset'."
- (set-default-toplevel-value symbol value)
- (project-headerline-reset))
-
-(defvar-local project-headerline--cache nil)
-
-(defmacro project-headerline--cached (key form)
- "Cached evaluation of form.
-If there is cached value for KEY, return it.
-Otherwise, evaluate FORM, store in cache, and return it."
- `(let ((cache project-headerline--cache))
- (unless cache
- (setq cache (make-hash-table :test 'eq))
- (setq-local project-headerline--cache cache))
- (or (gethash ,key cache)
- (puthash ,key ,form cache))))
-
-(defmacro project-headerline--call (func-or-cons &rest args)
- "Call user function.
-On error, display warning and return nil."
- (let ((func (if (consp func-or-cons)
- (car func-or-cons)
- func-or-cons))
- (name (if (consp func-or-cons)
- (cdr func-or-cons)
- (symbol-name func-or-cons))))
- `(condition-case err
- (funcall ,func ,@args)
- (error
- (warn "Caught error from %s: %s" ,name
- (error-message-string err))
- nil))))
-
-(defun project-headerline-describe-project ()
- "Get current project properties.
-Default implementation of `project-headerline-describe-project-function',
-see its docstring for details."
- (or (project-headerline--project-from-variable)
- (project-headerline--project-from-detect-alist)
- (project-headerline--project-from-fallback-alist)))
-
-(defun project-headerline--project-from-variable ()
- "Get project from `project-headerline-current-project'."
- (when project-headerline-current-project
- (cond ((stringp project-headerline-current-project)
- (list :name (f-filename project-headerline-current-project)
- :path (f-full project-headerline-current-project)))
- ((plistp project-headerline-current-project)
- project-headerline-current-project)
- (t
- (warn "Invalid project-headerline-current-project")
- nil))))
-
-(defun project-headerline--project-from-detect-alist ()
- "Get project from `project-headerline-detect-alist'."
- (seq-some (lambda (method)
- (let ((allow-remote (plist-get (cdr method) :allow-remote))
- (describe-fn (plist-get (cdr method) :describe)))
- (when (and (or allow-remote
- (not (file-remote-p default-directory)))
- describe-fn)
- (project-headerline--call
- (describe-fn . "project-headerline-detect-alist :describe")))))
- project-headerline-detect-alist))
-
-(defun project-headerline--project-from-fallback-alist ()
- "Get project from `project-headerline-fallback-alist'."
- (let* ((directory (project-headerline--buffer-dir))
- (server (file-remote-p directory)))
- (when directory
- (seq-some (lambda (proj)
- (let ((proj-name (car proj))
- (proj-path (cdr proj)))
- (if server
- (when (s-prefix-p (expand-file-name (s-concat server proj-path))
- (expand-file-name directory))
- (list :name (s-concat server proj-name)
- :path (expand-file-name (s-concat server proj-path))))
- (when (s-prefix-p (f-full proj-path)
- (f-full directory))
- (list :name proj-name
- :path (f-full proj-path))))))
- project-headerline-fallback-alist))))
-
-(defun project-headerline-describe-buffer ()
- "Get current buffer properties.
-Default implementation of `project-headerline-describe-buffer-function',
-see its docstring for details."
- (let ((type (project-headerline--buffer-type))
- (dir (project-headerline--buffer-dir))
- (name (project-headerline--buffer-name)))
- (setq name
- (or (seq-some (lambda (rule)
- (let ((from (car rule))
- (to (cdr rule)))
- (when (string-match from name)
- (replace-regexp-in-string from to name))))
- project-headerline-rename-alist)
- name))
- (list :type type
- :dir dir
- :name name)))
-
-(defun project-headerline--buffer-type ()
- "Detect current buffer's type."
- (cond
- ;; dired
- ((derived-mode-p 'dired-mode)
- 'dir)
- ;; special
- ((derived-mode-p 'special-mode)
- 'other)
- ;; file
- (buffer-file-name
- 'file)
- ;; very special
- (t
- 'other)))
-
-(defun project-headerline--buffer-dir ()
- "Detect current buffer's directory.
-Returns path with trailing slash or nil."
- (cond
- ;; dired
- ((and (derived-mode-p 'dired-mode)
- (bound-and-true-p dired-subdir-alist))
- (f-full (dired-current-directory)))
- ;; file
- (buffer-file-name
- (f-slash (f-parent (f-full buffer-file-name))))
- ;; cwd
- (default-directory
- (f-full default-directory))))
-
-(defun project-headerline--buffer-name ()
- "Detect current buffer's name.
-For files and directories, returns base name.
-Otherwise returns buffer name."
- (cond
- ;; dired
- ((and (derived-mode-p 'dired-mode)
- (bound-and-true-p dired-subdir-alist))
- (f-filename (dired-current-directory)))
- ;; file
- (buffer-file-name
- (f-filename buffer-file-name))
- ;; other
- (t
- (buffer-name))))
-
-;; Forward-declare to ensure they are not byte-compiled as lexical.
-(defvar all-the-icons-scale-factor)
-(defvar all-the-icons-default-adjust)
-
-(defun project-headerline-icon (icon-name icon-face)
- "Format propertized icon string from icon name and face.
-Default implementation of `project-headerline-icon-function',
-see its docstring for details."
- (when (functionp 'all-the-icons-material)
- (let ((all-the-icons-scale-factor 1.0)
- (all-the-icons-default-adjust -0.15))
- (when-let* ((icon (all-the-icons-material icon-name :face icon-face))
- (space (propertize " " 'font-lock-face 'project-headerline-space)))
- (s-concat
- space icon space)))))
-
-(defun project-headerline-width ()
- "Return maximum number of characters in headerline.
-Default implementation of `project-headerline-width-function',
-see its docstring for details."
- (window-width))
-
-(defun project-headerline--separator (key default-icon default-char)
- "Make propertized icon string."
- (project-headerline--cached
- key
- (let ((var-name (intern (format "project-headerline-%s-separator" key)))
- (face-name (intern (format "project-headerline-%s-separator" key))))
- (or
- ;; user variable
- (symbol-value var-name)
- ;; default icon
- (project-headerline--call project-headerline-icon-function
- default-icon face-name)
- ;; default char
- (let ((char (propertize default-char 'font-lock-face face-name))
- (space (propertize " " 'font-lock-face 'project-headerline-space)))
- (s-concat space char space))))))
-
-(defun project-headerline--path-components (root-path path)
- "Split path from ROOT-PATH to CURR-PATH into components."
- (let (path-components)
- (while (and path
- (or (not root-path)
- (not (f-same-p root-path path))))
- (push (f-filename path) path-components)
- (setq path (f-parent path)))
- path-components))
-
-(defun project-headerline-format (project buffer)
- "Format headerline string for project and buffer.
-Default implementation of `project-headerline-format-function',
-see its docstring for details."
- (let* ((separator
- (project-headerline--separator 'segment "chevron_right" ">"))
- (margin
- (- (or (car (window-margins)) 0)))
- (max-width (project-headerline--call
- project-headerline-width-function))
- (max-path (- max-width
- (seq-reduce
- '+ (seq-map (lambda (segment)
- (if (eq segment 'path-in-project)
- 0
- (let ((str (project-headerline--format-segment
- segment project buffer 0)))
- (unless (s-blank-p str)
- (+ (length separator)
- (length str))))))
- project-headerline-display-segments)
- (length separator))))
- (segments (seq-map
- (lambda (segment)
- (project-headerline--format-segment
- segment project buffer max-path))
- project-headerline-display-segments))
- (headerline (s-join separator
- (append '("")
- (seq-remove 's-blank-p
- segments)))))
- (put-text-property 0 1 'display `(space :align-to ,margin)
- headerline)
- headerline))
-
-(defun project-headerline--format-segment (segment project buffer max-path)
- "Build segment with given name."
- (pcase segment
- (`project-name
- (project-headerline--format-project-name
- project buffer))
- (`path-in-project
- (project-headerline--format-path-in-project
- project buffer max-path))
- (`buffer-name
- (project-headerline--format-buffer-name
- project buffer))))
-
-(defun project-headerline--format-project-name (project buffer)
- "Build \\='project segment."
- (ignore buffer)
- (let ((project-name (plist-get project :name)))
- (when (s-present-p project-name)
- (propertize project-name
- 'font-lock-face 'project-headerline-project-name))))
-
-(defun project-headerline--format-path-in-project (project buffer max-path)
- "Build \\='path-in-project segment."
- (let* ((project-path (plist-get project :path))
- (buffer-type (plist-get buffer :type))
- (buffer-dir (plist-get buffer :dir))
- (path-in-project (cond
- ;; directory
- ((eq buffer-type 'dir)
- (if (and (seq-contains-p project-headerline-display-segments
- 'buffer-name)
- (not (f-same-p project-path
- buffer-dir)))
- (f-parent buffer-dir)
- buffer-dir))
- ;; file or other
- (t buffer-dir)))
- (components (project-headerline--path-components project-path
- path-in-project))
- (separator
- (project-headerline--separator 'path "chevron_right" ">")))
- (when components
- (let ((max-components (length components))
- result)
- (while (or (not result)
- (and (> (length result) max-path 2)
- (> max-components 0)))
- (setq result
- (s-join separator
- (seq-map (lambda (seg)
- (propertize
- seg 'font-lock-face 'project-headerline-path-in-project))
- (if (= max-components (length components))
- components
- (append (list project-headerline-path-ellipsis)
- (seq-drop components
- (- (length components)
- max-components)))))))
- (setq max-components (1- max-components)))
- result))))
-
-(defun project-headerline--format-buffer-name (project buffer)
- "Build \\='buffer segment."
- (let* ((project-path (plist-get project :path))
- (buffer-type (plist-get buffer :type))
- (buffer-dir (plist-get buffer :dir))
- (buffer-name (plist-get buffer :name))
- (display-name (cond
- ;; project root
- ((and (eq buffer-type 'dir)
- (f-same-p project-path buffer-dir))
- ".")
- ;; anything else
- (t
- buffer-name))))
- (when (s-present-p display-name)
- (propertize display-name
- 'font-lock-face 'project-headerline-buffer-name))))
-
-(defun project-headerline--compose ()
- "Build propertized headerline string."
- (project-headerline--cached
- 'headerline
- (or
- (when-let* ((project (project-headerline--call
- project-headerline-describe-project-function))
- (buffer (project-headerline--call
- project-headerline-describe-buffer-function)))
- (project-headerline--call
- project-headerline-format-function project buffer))
- "")))
-
-(defun project-headerline--composer-match (elem func)
- "Match `header-line-format' element by composer function."
- (when-let* ((form (car-safe (cdr-safe elem))))
- (and (eq (car form) :eval)
- (eq (caadr form) func))))
-
-(defun project-headerline--composer-append (func &rest args)
- "Add composer function to the head of `header-line-format'."
- (when (and header-line-format
- (not (listp header-line-format)))
- (setq header-line-format
- (list header-line-format)))
- (unless (seq-find (lambda (elem)
- (project-headerline--composer-match elem func))
- header-line-format)
- (setq header-line-format
- (append header-line-format
- `((t (:eval (,func ,@args))))))))
-
-(defun project-headerline--composer-prepend (func &rest args)
- "Add composer function to the tail of `header-line-format'."
- (when (and header-line-format
- (not (listp header-line-format)))
- (setq header-line-format
- (list header-line-format)))
- (unless (seq-find (lambda (elem)
- (project-headerline--composer-match elem func))
- header-line-format)
- (setq header-line-format
- (append `((t (:eval (,func ,@args))))
- header-line-format))))
-
-(defun project-headerline--composer-remove (func)
- "Remove composer function from `header-line-format'."
- (when (listp header-line-format)
- (setq header-line-format
- (seq-remove (lambda (elem)
- (project-headerline--composer-match elem func))
- header-line-format))))
-
-(defun project-headerline--magit-compose (text)
- "Build magit headerline.
-If `project-headerline-mode' is off, produces same result as original
-`magit-set-header-line-format'. Otherwise, produces right-aligned
-headerline that can be use together with `project-headerline'."
- (project-headerline--cached
- 'magit-headerline
- (s-concat
- (propertize " " 'display
- (if project-headerline-mode
- (let* ((margin (or (cdr (window-margins)) 0))
- (offset (- (length text)
- margin)))
- `(space :align-to (- right-margin ,offset)))
- '(space :align-to 0)))
- text)))
-
-(defun project-headerline--magit-advice (orig-fn &rest args)
- "Wraps magit headrline builder to support `project-headerline' in magit buffers.
-If you don't use project-headerline with magit, no visible changes are made."
- ;; safety check: don't follow advice if signature doesn't
- ;; match what it used to be
- (if (and (eq 1 (length args))
- (stringp (car args)))
- (project-headerline--composer-append 'project-headerline--magit-compose
- (car args))
- (apply orig-fn args)))
-
-(defun project-headerline--rename-file-advice (orig-fn &rest args)
- "Wraps `rename-file' to update headerline on name change."
- (unwind-protect
- (apply orig-fn args)
- (let ((from (car args))
- (to (cadr args)))
- (project-headerline--reset-paths from to))))
-
-(defun project-headerline--add-name-to-file-advice (orig-fn &rest args)
- "Wraps `add-name-to-file' to update headerline on name change."
- (unwind-protect
- (apply orig-fn args)
- (let ((from (car args))
- (to (cadr args)))
- (project-headerline--reset-paths from to))))
-
-(defun project-headerline--rename-buffer-advice (orig-fn &rest args)
- "Wraps `rename-buffer' to update headerline on name change."
- (unwind-protect
- (apply orig-fn args)
- (project-headerline--reset-buffer)))
-
-(defun project-headerline--enable-maybe ()
- "Enable `project-headerline-mode' in current buffer, if needed.
-Headerline is enabled if buffer major mode is derived from one of the modes
-in `project-headerline-mode-list'.
-Never enables in minibuffer and hidden buffers."
- (when (and (not (minibufferp))
- (not (string-match "^ " (buffer-name)))
- (seq-some #'derived-mode-p project-headerline-mode-list)
- (not project-headerline-mode))
- (project-headerline-mode 1)))
-
-(defun project-headerline--register-advices ()
- "Register all advices, if not registered yet."
- (when (featurep 'magit)
- (advice-add 'magit-set-header-line-format
- :around #'project-headerline--magit-advice))
- (advice-add 'rename-file
- :around #'project-headerline--rename-file-advice)
- (advice-add 'add-name-to-file
- :around #'project-headerline--add-name-to-file-advice)
- (advice-add 'rename-buffer
- :around #'project-headerline--rename-buffer-advice))
-
-(defun project-headerline--register-hooks ()
- "Register all hooks."
- (add-hook 'window-configuration-change-hook
- #'project-headerline--reset-buffer nil :local)
- (add-hook 'after-revert-hook
- #'project-headerline--reset-buffer nil :local)
- (add-hook 'after-set-visited-file-name-hook
- #'project-headerline--reset-buffer nil :local))
-
-(defun project-headerline--unregister-hooks ()
- "Unregister all hooks."
- (remove-hook 'window-configuration-change-hook
- #'project-headerline--reset-buffer :local)
- (remove-hook 'after-revert-hook
- #'project-headerline--reset-buffer :local)
- (remove-hook 'after-set-visited-file-name-hook
- #'project-headerline--reset-buffer :local))
-
-(defun project-headerline--reset-buffer (&optional buffer)
- "Refresh headerline in given BUFFER (or current)."
- (with-current-buffer (or buffer (current-buffer))
- (when (bound-and-true-p project-headerline--cache)
- (setq-local project-headerline--cache nil))
- (when project-headerline-mode
- (force-mode-line-update))))
-
-(defun project-headerline--reset-paths (&rest paths)
- "Refresh headerline in buffers visiting any of PATHS."
- (dolist (buffer (buffer-list))
- (when-let* ((buffer-path (buffer-file-name buffer)))
- (dolist (path paths)
- (when (and path (f-same-p buffer-path path))
- (project-headerline--reset-buffer buffer))))))
-
-;;;###autoload
-(defun project-headerline-reset (&optional buffer)
- "Forcibly refresh headerline in all buffers.
-If BUFFER is given, refresh only that buffer."
- (interactive)
- (if buffer
- (project-headerline--reset-buffer buffer)
- (dolist (buffer (buffer-list))
- (project-headerline--reset-buffer buffer))))
-
-;;;###autoload
-(define-minor-mode project-headerline-mode
- "Customizable project headerline."
- :group 'project-headerline
- :init-value nil
- :lighter nil
- (if project-headerline-mode
- ;; enable mode
- (progn
- (project-headerline--composer-prepend 'project-headerline--compose)
- (project-headerline--register-advices)
- (project-headerline--register-hooks)
- (force-mode-line-update))
- ;; disable mode
- (project-headerline--unregister-hooks)
- (project-headerline--composer-remove 'project-headerline--compose)
- (project-headerline--reset-buffer)
- (force-mode-line-update)))
-
-;;;###autoload
-(define-globalized-minor-mode global-project-headerline-mode
- project-headerline-mode
- project-headerline--enable-maybe
- :group 'project-headerline)
-
-(provide 'project-headerline)
-;;; project-headerline.el ends here
tools/emacs/lisp/project-x.el
@@ -1,217 +0,0 @@
-;;; project-x.el --- Extra convenience features for project.el -*- lexical-binding: t -*-
-
-;; Copyright (C) 2021 Karthik Chikmagalur
-
-;; Author: Karthik Chikmagalur <karthik.chikmagalur@gmail.com>
-;; URL: https://github.com/karthink/project-x
-;; Version: 0.1.5
-;; Package-Requires: ((emacs "27.1"))
-
-;; This file is NOT part of GNU Emacs.
-
-;; This file 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, 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.
-;;
-;; For a full copy of the GNU General Public License
-;; see <http://www.gnu.org/licenses/>.
-;;
-;;; Commentary:
-;;
-;; project-x provides some convenience features for project.el:
-;; - Recognize any directory with a `.project' file as a project.
-;; - Save and restore project files and window configurations across sessions
-;;
-;; COMMANDS:
-;;
-;; project-x-window-state-save : Save the window configuration of currently open project buffers
-;; project-x-window-state-load : Load a previously saved project window configuration
-;;
-;; CUSTOMIZATION:
-;;
-;; `project-x-window-list-file': File to store project window configurations
-;; `project-x-local-identifier': String matched against file names to decide if a
-;; directory is a project
-;; `project-x-save-interval': Interval in seconds between autosaves of the
-;; current project.
-;;
-;; by Karthik Chikmagalur
-;; <karthik.chikmagalur@gmail.com>
-
-;;; Code:
-
-(require 'project)
-(eval-when-compile (require 'subr-x))
-(eval-when-compile (require 'seq))
-(defvar project-prefix-map)
-(defvar project-switch-commands)
-(declare-function project-prompt-project-dir "project")
-(declare-function project--buffer-list "project")
-(declare-function project-buffers "project")
-
-(defgroup project-x nil
- "Convenience features for the Project library."
- :group 'project)
-
-;; Persistent project sessions
-;; -------------------------------------
-(defcustom project-x-window-list-file
- (locate-user-emacs-file "project-window-list")
- "File in which to save project window configurations by default."
- :type 'file
- :group 'project-x)
-
-(defcustom project-x-save-interval nil
- "Saves the current project state with this interval.
-
-When set to nil auto-save is disabled."
- :type '(choice (const :tag "Disabled" nil)
- integer)
- :group 'project-x)
-
-(defvar project-x-window-alist nil
- "Alist of window configurations associated with known projects.")
-
-(defvar project-x-save-timer nil
- "Timer for auto-saving project state.")
-
-(defun project-x--window-state-write (&optional file)
- "Write project window states to `project-x-window-list-file'.
-If FILE is specified, write to it instead."
- (when project-x-window-alist
- (require 'pp)
- (unless file (make-directory (file-name-directory project-x-window-list-file) t))
- (with-temp-file (or file project-x-window-list-file)
- (insert ";;; -*- lisp-data -*-\n")
- (let ((print-level nil) (print-length nil))
- (pp project-x-window-alist (current-buffer))))
- (message (format "Wrote project window state to %s" project-x-window-list-file))))
-
-(defun project-x--window-state-read (&optional file)
- "Read project window states from `project-x-window-list-file'.
-If FILE is specified, read from it instead."
- (and (or file
- (file-exists-p project-x-window-list-file))
- (with-temp-buffer
- (insert-file-contents (or file project-x-window-list-file))
- (condition-case nil
- (if-let ((win-state-alist (read (current-buffer))))
- (setq project-x-window-alist win-state-alist)
- (message (format "Could not read %s" project-x-window-list-file)))
- (error (message (format "Could not read %s" project-x-window-list-file)))))))
-
-(defun project-x-window-state-save (&optional arg)
- "Save current window state of project.
-With optional prefix argument ARG, query for project."
- (interactive "P")
- (when-let* ((dir (cond (arg (project-prompt-project-dir))
- ((project-current)
- (project-root (project-current)))))
- (default-directory dir))
- (unless project-x-window-alist (project-x--window-state-read))
- (let ((file-list))
- ;; Collect file-list of all the open project buffers
- (dolist (buf
- (funcall (if (fboundp 'project--buffers-list)
- #'project--buffers-list
- #'project-buffers)
- (project-current))
- file-list)
- (if-let ((file-name (or (buffer-file-name buf)
- (with-current-buffer buf
- (and (derived-mode-p 'dired-mode)
- dired-directory)))))
- (push file-name file-list)))
- (setf (alist-get dir project-x-window-alist nil nil 'equal)
- (list (cons 'files file-list)
- (cons 'windows (window-state-get nil t)))))
- (message (format "Saved project state for %s" dir))))
-
-(defun project-x-window-state-load (dir)
- "Load the saved window state for project with directory DIR.
-If DIR is unspecified query the user for a project instead."
- (interactive (list (project-prompt-project-dir)))
- (unless project-x-window-alist (project-x--window-state-read))
- (if-let* ((project-x-window-alist)
- (project-state (alist-get dir project-x-window-alist
- nil nil 'equal)))
- (let ((file-list (alist-get 'files project-state))
- (window-config (alist-get 'windows project-state)))
- (dolist (file-name file-list nil)
- (find-file file-name))
- (window-state-put window-config nil 'safe)
- (message (format "Restored project state for %s" dir)))
- (message (format "No saved window state for project %s" dir))))
-
-(defun project-x-windows ()
- "Restore the last saved window state of the chosen project."
- (interactive)
- (project-x-window-state-load (project-root (project-current))))
-
-;; Recognize directories as projects by defining a new project backend `local'
-;; -------------------------------------
-(defcustom project-x-local-identifier ".project"
- "Filename(s) that identifies a directory as a project.
-
-You can specify a single filename or a list of names."
- :type '(choice (string :tag "Single file")
- (repeat (string :tag "Filename")))
- :group 'project-x)
-
-(cl-defmethod project-root ((project (head local)))
- "Return root directory of current PROJECT."
- (cdr project))
-
-(defun project-x-try-local (dir)
- "Determine if DIR is a non-VC project.
-DIR must include a .project file to be considered a project."
- (if-let ((root (if (listp project-x-local-identifier)
- (seq-some (lambda (n)
- (locate-dominating-file dir n))
- project-x-local-identifier)
- (locate-dominating-file dir project-x-local-identifier))))
- (cons 'local root)))
-
-;;;###autoload
-(define-minor-mode project-x-mode
- "Minor mode to enable extra convenience features for project.el.
-When enabled, save and load project window states.
-Recognize any directory that contains (or whose parent
-contains) a special file as a project."
- :global t
- :version "0.10"
- :lighter ""
- :group 'project-x
- (if project-x-mode
- ;;Turning the mode ON
- (progn
- (add-hook 'project-find-functions 'project-x-try-local 90)
- (add-hook 'kill-emacs-hook 'project-x--window-state-write)
- (project-x--window-state-read)
- (define-key project-prefix-map (kbd "w") 'project-x-window-state-save)
- (define-key project-prefix-map (kbd "j") 'project-x-window-state-load)
- (if (listp project-switch-commands)
- (add-to-list 'project-switch-commands
- '(?j "Restore windows" project-x-windows) t)
- (message "`project-switch-commands` is not a list, not adding 'restore windows' command"))
- (when project-x-save-interval
- (setq project-x-save-timer
- (run-with-timer 0 (max project-x-save-interval 5)
- #'project-x-window-state-save))))
- (remove-hook 'project-find-functions 'project-x-try-local 90)
- (remove-hook 'kill-emacs-hook 'project-x--window-state-write)
- (define-key project-prefix-map (kbd "w") nil)
- (define-key project-prefix-map (kbd "j") nil)
- (when (listp project-switch-commands)
- (delete '(?j "Restore windows" project-x-windows) project-switch-commands))
- (when (timerp project-x-save-timer)
- (cancel-timer project-x-save-timer))))
-
-(provide 'project-x)
-;;; project-x.el ends here
tools/emacs/lisp/vde-buffers.el
@@ -1,11 +0,0 @@
-;;; vde-buffers.el --- -*- lexical-binding: t; -*-
-;; Commentary:
-;;; Helper function related to buffers
-;; Code:
-
-;;;###autoload
-(defun vde/buffer-has-project-p (buffer action)
- (with-current-buffer buffer (project-current nil)))
-
-(provide 'vde-buffers)
-;;; vde-buffers.el ends here
tools/emacs/lisp/vde-simple.el
@@ -1,24 +0,0 @@
-;;; vde-simple --- Common functions for my configuration -*- lexical-binding: t -*-
-
-;; Copyright (C) 2025 Vincent Demeester
-;; Author: Vincent Demeester <vincent@sbr.pm>
-
-;; This file is NOT part of GNU Emacs.
-;;; Commentary:
-;;
-;; Simple and useful function for a lot of things.
-;;
-;;; Code:
-
-(defvar vde-simple-override-mode-map (make-sparse-keymap)
- "Key map of `vde-simple-override-mode'.
-Enable that mode to have its key bindings to take effect over those of the major mode.")
-
-(define-minor-mode vde-simple-override-mode
- "Enable the `vde-simple-override-mode-map'."
- :init-value nil
- :global t
- :keymap vde-simple-override-mode-map)
-
-(provide 'vde-simple)
-;;; vde-simple.el ends here
tools/emacs/lisp/vde-windows.el
@@ -1,35 +0,0 @@
-;;; vde-windows.el --- -*- lexical-binding: t; -*-
-;; Commentary:
-;;; Helper function related to window management
-;; Code:
-
-;;;###autoload
-(defun vde/split-window-below (&optional arg)
- "Split window below from the parent or from the roo with ARG."
- (interactive "P")
- (split-window (if arg (frame-root-window)
- (window-parent (selected-window)))
- nil 'below nil))
-
-;;;###autoload
-(defun vde/split-window-right (&optional arg)
- "Split window right from the parent or from the roo with ARG."
- (interactive "P")
- (split-window (if arg (frame-root-window)
- (window-parent (selected-window)))
- nil 'right nil))
-
-;;;###autoload
-(defun vde/toggle-window-dedication ()
- "Toggles window dedication in the selected window."
- (interactive)
- (set-window-dedicated-p (selected-window)
- (not (window-dedicated-p (selected-window)))))
-
-;;;###autoload
-(defun make-display-buffer-matcher-function (major-modes)
- (lambda (buffer-name action)
- (with-current-buffer buffer-name (apply #'derived-mode-p major-modes))))
-
-(provide 'vde-windows)
-;;; vde-windows.el ends here
tools/emacs/transient/history.el
@@ -1,1 +1,20 @@
-nil
\ No newline at end of file
+((denote-transient nil)
+ (magit-blame
+ ("-w"))
+ (magit-branch nil)
+ (magit-commit nil
+ ("--reset-author"))
+ (magit-dispatch nil)
+ (magit-fetch nil)
+ (magit-gitignore nil)
+ (magit-log
+ ("-n256" "--graph" "--decorate"))
+ (magit-push nil
+ ("--force-with-lease"))
+ (magit-rebase
+ ("--autostash")
+ nil)
+ (magit-remote
+ ("-f"))
+ (magit-tag nil)
+ (rg-menu nil))
tools/emacs/early-init.el
@@ -1,39 +1,4 @@
-;;; early-init.el --- Early init configuration file -*- lexical-binding: t; -*-
-
-;; Copyright (c) 2020-2023 Vincent Demeester <vincent@sbr.pm>
-
-;; Author: Vincent Demeester <vincent@sbr.pm>
-;; URL: https://git.sr.ht/~vdemeester/home
-;; Version: 0.1.0
-;; Package-Requires: ((emacs "29.1"))
-
-;; This file is NOT part of GNU Emacs.
-
-;; This file 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 file 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 file. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Prior to Emacs 27, the `init.el' was supposed to handle the
-;; initialisation of the package manager, by means of calling
-;; `package-initialize'. Starting with Emacs 27, the default
-;; behaviour is to start the package manager before loading the init
-;; file.
-;;
-
-;; See my dotfiles: https://git.sr.ht/~vdemeester/home
-
-;;; Code:
+(add-to-list 'load-path (locate-user-emacs-file "site-lisp"))
;; Do not initialize installed packages
(setopt package-enable-at-startup nil
@@ -73,7 +38,6 @@
(setq file-name-handler-alist nil
vc-handled-backends nil)
-
;; Ignore X resources; its settings would be redundant with the other settings
;; in this file and can conflict with later config (particularly where the
;; cursor color is concerned).
tools/emacs/init.el
@@ -1,33 +1,50 @@
-;;; init.el --- init configuration file -*- lexical-binding: t; -*-
-
-;; Copyright (c) 2020-2023 Vincent Demeester <vincent@sbr.pm>
+;;; init --- vdemeester's emacs configuration -*- lexical-binding: t -*-
+;; Copyright (C) 2025 Vincent Demeester
;; Author: Vincent Demeester <vincent@sbr.pm>
-;; URL: https://git.sr.ht/~vdemeester/home
-;; Version: 0.1.0
-;; Package-Requires: ((emacs "29.1"))
;; This file is NOT part of GNU Emacs.
-
-;; This file 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 file 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 file. If not, see <http://www.gnu.org/licenses/>.
-
;;; Commentary:
-
-;; See my dotfiles: https://git.sr.ht/~vdemeester/home
-
+;; This is the "mini" version for now, but aims to become the default one.
;;; Code:
+;;; Some constants I am using across the configuration.
+(defconst org-directory "~/desktop/org/"
+ "`org-mode' directory, where most of the org-mode file lives.")
+(defconst org-notes-directory (expand-file-name "notes" org-directory)
+ "`org-mode' notes directory, for notes obviously, most likely managed by denote.")
+(defconst org-inbox-file (expand-file-name "inbox.org" org-directory)
+ "`org-mode' inbox file, where we collect entries to be triaged.")
+(defconst org-todos-file (expand-file-name "todos.org" org-directory)
+ "`org-mode' file for TODOs. This is the main file for the org angenda entries.")
+(defconst org-journal-file (expand-file-name "journal.org" org-directory)
+ "`org-mode' journal file, for journal-ling.")
+(defconst org-archive-dir (expand-file-name "archive" org-directory)
+ "`org-mode' directory of archived files.")
+(defconst org-people-dir (expand-file-name "people" org-notes-directory)
+ "`org-mode' people files directory, most likely managed by denote.")
+
+;;; The configuration.
+
+;;; Quick access to certain key file using registers
+(set-register ?e `(file . ,(locate-user-emacs-file "init.el")))
+(set-register ?i `(file . ,org-inbox-file))
+(set-register ?t `(file . ,org-todos-file))
+(set-register ?j `(file . ,org-journal-file))
+(set-register ?o `(file . ,org-directory))
+(set-register ?n `(file . ,org-notes-directory))
+(set-register ?P `(file . ,org-people-dir))
+
+;;; Some GC optimizations
+(defun my-minibuffer-setup-hook ()
+ (setq gc-cons-threshold most-positive-fixnum))
+
+(defun my-minibuffer-exit-hook ()
+ (setq gc-cons-threshold 800000000))
+
+(setq gc-cons-threshold most-positive-fixnum)
+
+(run-with-idle-timer 1.2 t 'garbage-collect)
(defconst emacs-start-time (current-time))
@@ -38,22 +55,13 @@
(setq inhibit-default-init t) ; Disable the site default settings
(setq confirm-kill-emacs #'y-or-n-p)
-(setq initial-major-mode 'fundamental-mode
- initial-scratch-message nil)
-
-;; Might not work as well on Windows but meh, I don't use it.
-(prefer-coding-system 'utf-8)
-(set-default-coding-systems 'utf-8)
-(set-language-environment 'utf-8)
-(set-selection-coding-system 'utf-8)
-(set-terminal-coding-system 'utf-8)
(setq custom-file (locate-user-emacs-file "custom.el"))
(setq
- custom-buffer-done-kill nil ; Kill when existing
- custom-buffer-verbose-help nil ; Remove redundant help text
- custom-unlispify-tag-names nil ; Show me the real variable name
- custom-unlispify-menu-entries nil)
+ custom-buffer-done-kill nil ; Kill when existing
+ custom-buffer-verbose-help nil ; Remove redundant help text
+ custom-unlispify-tag-names nil ; Show me the real variable name
+ custom-unlispify-menu-entries nil)
;; Create the custom-file if it doesn't exists
(unless (file-exists-p custom-file)
(write-region "" nil custom-file))
@@ -76,39 +84,6 @@
(put command 'disabled nil))
'(list-timers narrow-to-region narrow-to-page upcase-region downcase-region))
-(defun prot/keyboard-quit-dwim ()
- "Do-What-I-Mean behaviour for a general `keyboard-quit'.
-
-The generic `keyboard-quit' does not do the expected thing when
-the minibuffer is open. Whereas we want it to close the
-minibuffer, even without explicitly focusing it.
-
-The DWIM behaviour of this command is as follows:
-
-- When the region is active, disable it.
-- When a minibuffer is open, but not focused, close the minibuffer.
-- When the Completions buffer is selected, close it.
-- In every other case use the regular `keyboard-quit'."
- (interactive)
- (cond
- ((region-active-p)
- (keyboard-quit))
- ((derived-mode-p 'completion-list-mode)
- (delete-completion-window))
- ((> (minibuffer-depth) 0)
- (abort-recursive-edit))
- (t
- (keyboard-quit))))
-
-(define-key global-map (kbd "C-g") #'prot/keyboard-quit-dwim)
-
-(add-to-list 'load-path (concat user-emacs-directory "/lisp/"))
-(add-to-list 'load-path (concat user-emacs-directory "/lisp/aider.el"))
-(add-to-list 'load-path (concat user-emacs-directory "/lisp/auto-side-windows"))
-(add-to-list 'load-path (concat user-emacs-directory "/lisp/consult-mu"))
-(add-to-list 'load-path (concat user-emacs-directory "/lisp/consult-mu/extras"))
-(add-to-list 'load-path (concat user-emacs-directory "/config/"))
-
(unless noninteractive
(defconst font-height 130
"Default font-height to use.")
@@ -145,59 +120,26 @@ The DWIM behaviour of this command is as follows:
(set-fontset-font t 'symbol "Segoe UI Emoji" nil 'append)
(set-fontset-font t 'symbol "Symbola" nil 'append)
- (defvar contrib/after-load-theme-hook nil
- "Hook run after a color theme is loaded using `load-theme'.")
-
- (defun contrib/run-after-load-theme-hook (&rest _)
- "Run `contrib/after-load-theme-hook'."
- (run-hooks 'contrib/after-load-theme-hook))
-
- (advice-add #'load-theme :after #'contrib/run-after-load-theme-hook)
-
(require 'modus-themes)
- (setq modus-themes-to-toggle '(modus-operandi modus-vivendi)
- modus-themes-slanted-constructs nil
- modus-themes-italic-constructs nil
- modus-themes-bold-constructs nil
- modus-themes-mixed-fonts t
- modus-themes-subtle-diffs t
- modus-themes-fringes 'subtle ; {nil,'subtle,'intense}
- modus-themes-headings '((0 . (variable-pitch semilight 1.5))
- (1 . (regular 1.4))
- (2 . (regular 1.3))
- (3 . (regular 1.2))
- (agenda-structure . (variable-pitch light 2.2))
- (agenda-date . (variable-pitch regular 1.3))
- (t . (regular 1.15)))
- modus-themes-intense-paren-match t
- modus-themes-completions '(opinionated) ; {nil,'moderate,'opinionated}
- modus-themes-diffs 'desaturated ; {nil,'desaturated,'fg-only}
- modus-themes-org-blocks 'gray-background
- modus-themes-paren-match '(subtle-bold)
- modus-themes-variable-pitch-headings nil
- modus-themes-rainbow-headings t
- modus-themes-section-headings nil
- modus-themes-scale-headings t
- )
+ (setopt modus-themes-common-palette-overrides modus-themes-preset-overrides-cooler
+ modus-themes-to-rotate '(modus-operandi modus-vivendi)
+ modus-themes-mixed-fonts t
+ modus-themes-headings '((0 . (variable-pitch semilight 1.5))
+ (1 . (regular 1.4))
+ (2 . (regular 1.3))
+ (3 . (regular 1.2))
+ (agenda-structure . (variable-pitch light 2.2))
+ (agenda-date . (variable-pitch regular 1.3))
+ (t . (regular 1.15))))
+ ;; Default modus-operandi on GUI and modus-vivendi on CLI
+ (if (display-graphic-p)
+ (load-theme 'modus-operandi :no-confirm)
+ (load-theme 'modus-vivendi :no-confirm)))
- (defun my-update-active-mode-line-colors ()
- (set-face-attribute
- 'mode-line nil
- :foreground (modus-themes-get-color-value 'fg-mode-line-active)
- :background (modus-themes-get-color-value 'bg-blue-nuanced)))
- (add-hook 'modus-themes-after-load-theme-hook #'my-update-active-mode-line-colors)
- (define-key global-map (kbd "C-<f5>") #'modus-themes-toggle)
-
- (load-theme 'modus-operandi :no-confirm)
- (my-update-active-mode-line-colors))
-
-(setq load-prefer-newer t) ; Always load newer compiled files
-(setq ad-redefinition-action 'accept) ; Silence advice redefinition warnings
-
-;; Init `delight'
-;; (unless (package-installed-p 'delight)
-;; (package-refresh-contents)
-;; (package-install 'delight))
+(setopt load-prefer-newer t) ; Always load newer compiled files
+(setopt ad-redefinition-action 'accept) ; Silence advice redefinition warnings
+(setopt debug-on-error t)
+(setopt byte-compile-debug t)
;; Configure `use-package' prior to loading it.
(eval-and-compile
@@ -208,90 +150,1079 @@ The DWIM behaviour of this command is as follows:
(setq use-package-enable-imenu-support t)
(setq use-package-compute-statistics t))
-;; (unless (package-installed-p 'use-package)
-;; (package-refresh-contents)
-;; (package-install 'use-package))
-
(eval-when-compile
(require 'use-package))
-(setenv "SSH_AUTH_SOCK" "/run/user/1000/yubikey-agent/yubikey-agent.sock")
-;; (setenv "SSH_AUTH_SOCK" "/run/user/1000/gnupg/S.gpg-agent.ssh")
+(use-package emacs
+ :bind
+ ("C-x m" . mark-defun)
+ ("C-x C-b" . bs-show)
+ ("M-o" . other-window)
+ ("M-j" . duplicate-dwim)
+ ;; (:map completion-preview-active-mode-map
+ ;; ("M-n" . #'completion-preview-next-candidate)
+ ;; ("M-p" . #'completion-preview-prev-candidate))
+ :custom
+ (create-lockfiles nil) ; No backup files
+ (make-backup-files nil) ; No backup files
+ (backup-inhibited t) ; No backup files
+ (tab-always-indent 'complete)
+ (enable-local-variables :all)
+ (select-enable-clipboard t)
+ (select-enable-primary t)
+ (comment-multi-line t)
+ (make-backup-files nil)
+ (read-extended-command-predicate #'command-completion-default-include-p)
+ (mouse-autoselect 1)
+ (completion-cycle-threshold 2)
+ (completion-ignore-case t)
+ (completion-show-inline-help nil)
+ (completions-detailed t)
+ (enable-recursive-minibuffers t)
+ (read-buffer-completion-ignore-case t)
+ (read-file-name-completion-ignore-case t)
+ (find-ls-option '("-exec ls -ldh {} +" . "-ldh")) ; find-dired results with human readable sizes
+ (switch-to-buffer-obey-display-actions t)
+ :hook
+ (after-init . global-hl-line-mode)
+ (after-init . global-completion-preview-mode)
+ (after-init . auto-insert-mode)
+ (after-init . pixel-scroll-mode)
+ :config
+ (display-time-mode -1)
+ (tooltip-mode -1)
+ (blink-cursor-mode -1)
+ (setenv "GIT_EDITOR" (format "emacs --init-dir=%s " (shell-quote-argument user-emacs-directory)))
+ (setenv "EDITOR" (format "emacs --init-dir=%s " (shell-quote-argument user-emacs-directory)))
+ (delete-selection-mode 1)
+ (defun er-keyboard-quit ()
+ "Smater version of the built-in `keyboard-quit'.
-(defconst vde/custom-file (locate-user-emacs-file "custom.el")
- "File used to store settings from Customization UI.")
+The generic `keyboard-quit' does not do the expected thing when
+the minibuffer is open. Whereas we want it to close the
+minibuffer, even without explicitly focusing it."
+ (interactive)
+ (if (active-minibuffer-window)
+ (if (minibufferp)
+ (minibuffer-keyboard-quit)
+ (abort-recursive-edit))
+ (keyboard-quit)))
+ (global-set-key [remap keyboard-quit] #'er-keyboard-quit))
-;; Remove built-in org-mode
-(require 'cl-seq)
-(setq load-path
- (cl-remove-if
- (lambda (x)
- (string-match-p "org$" x))
- load-path))
+(use-package passage
+ :commands (passage-get))
-;; 2024-07-12: I wonder if I should be explicit instead, as using
-;; `require' explicitly. The benefit would be that I decide the order
-;; they load instead of relying on file-system.
-;; (vde/el-load-dir (concat user-emacs-directory "/config/"))
-(require 'init-func)
-(require 'org-func)
-(require 'project-func)
+(use-package ffap
+ :hook
+ (after-init . ffap-bindings))
-;; Make native compilation silent and prune its cache.
-(when (native-comp-available-p)
- (setq native-comp-async-report-warnings-errors 'silent) ; Emacs 28 with native compilation
- (setq native-compile-prune-cache t)
- (setq native-comp-jit-compilation t)
- (setq native-comp-async-query-on-exit t)) ; Emacs 29
+(use-package icomplete
+ :unless noninteractive
+ :hook
+ (icomplete-minibuffer-setup
+ . (lambda()(interactive)
+ (setq-local completion-styles '(flex partial-completion initials basic))))
+ (after-init . fido-vertical-mode)
+ :custom
+ (icomplete-compute-delay 0.01))
-(setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
+(use-package display-line-numbers
+ :unless noninteractive
+ :hook (prog-mode . display-line-numbers-mode)
+ :config
+ (setq-default display-line-numbers-type 'relative)
+ (defun vde/toggle-line-numbers ()
+ "Toggles the display of line numbers. Applies to all buffers."
+ (interactive)
+ (if (bound-and-true-p display-line-numbers-mode)
+ (display-line-numbers-mode -1)
+ (display-line-numbers-mode)))
+ :bind ("<f7>" . vde/toggle-line-numbers))
-;; Refactor this completely. Reduce to the minimum.
-(unless noninteractive
- (require '00-clean) ;; Maybe refactor no-littering
- (require 'config-keybindings)
- (require 'config-editing)
- (require 'config-files)
- (require 'config-misc)
- (require 'config-appearance)
- (require 'config-buffers)
- (require 'config-compile)
- (require 'config-completion)
- (require 'config-dired)
- (require 'config-mouse)
- (require 'config-navigating)
- (require 'config-org)
- (require 'config-programming)
- (require 'config-projects)
- (require 'config-search)
- (require 'config-shells)
- (require 'config-vcs)
- (require 'config-web)
- (require 'config-windows)
- (require 'config-llm)
- (require 'programming-config)
- (require 'programming-containers)
- (require 'programming-cue)
- (require 'programming-elisp)
- (require 'programming-eglot)
- (require 'programming-go)
- (require 'programming-js)
- (require 'programming-nix)
- (require 'programming-treesitter)
- (require 'programming-web)
- (require 'config-mu4e))
+(use-package helpful
+ :unless noninteractive
+ :bind (("C-h f" . helpful-callable)
+ ("C-h F" . helpful-function)
+ ("C-h M" . helpful-macro)
+ ("C-c h S" . helpful-at-point)
+ ("C-h k" . helpful-key)
+ ("C-h v" . helpful-variable)
+ ("C-h C" . helpful-command)))
-(if (file-exists-p (downcase (concat user-emacs-directory "/hosts/" (vde/short-hostname) ".el")))
- (load-file (downcase (concat user-emacs-directory "/hosts/" (vde/short-hostname) ".el"))))
+(use-package flymake
+ :bind
+ ("C-c f b" . flymake-show-buffer-diagnostics)
+ :hook
+ (prog-mode . flymake-mode))
-(let ((elapsed (float-time (time-subtract (current-time)
- emacs-start-time))))
- (message "Loading %s...done (%.3fs)" load-file-name elapsed))
+(use-package aggressive-indent
+ :commands (aggressive-indent-mode)
+ :hook
+ (emacs-lisp-mode . aggressive-indent-mode))
-(add-hook 'after-init-hook
- `(lambda ()
- (let ((elapsed
- (float-time
- (time-subtract (current-time) emacs-start-time))))
- (message "Loading %s...done (%.3fs) [after-init]"
- ,load-file-name elapsed))) t)
+(use-package save-place
+ :defer 1
+ :config (save-place-mode 1))
+
+(use-package symbol-overlay
+ :custom
+ (symbol-overlay-idle-time 0.2)
+ :bind
+ ("M-s s i" . symbol-overlay-put)
+ ("M-N" . symbol-overlay-jump-next)
+ ("M-P" . symbol-overlay-jump-prev)
+ ("M-s s r" . symbol-overlay-rename)
+ ("M-s s c" . symbol-overlay-remove-all)
+ :hook
+ (prog-mode . symbol-overlay-mode))
+
+(use-package savehist
+ :unless noninteractive
+ :hook (after-init . savehist-mode)
+ :custom
+ (history-length 10000)
+ (savehist-save-minibuffer-history t)
+ (savehist-delete-duplicates t)
+ (savehist-autosave-interval 180)
+ (savehist-additional-variables '(extended-command-history
+ search-ring
+ regexp-search-ring
+ comint-input-ring
+ compile-history
+ last-kbd-macro
+ shell-command-history)))
+
+(use-package which-key
+ :custom
+ (which-key-separator " → " )
+ (which-key-prefix-prefix "… ")
+ (which-key-add-column-padding 1)
+ (which-key-max-description-length 40)
+ (which-key-idle-delay 1)
+ (which-key-idle-secondary-delay 0.25)
+ :hook
+ (after-init . which-key-mode)
+ :config
+
+ ;; Define custom, concise descriptions for `tab-bar` commands under "C-x t"
+ (which-key-add-key-based-replacements
+ "C-c !" "flymake"
+ "C-x t C-f" "Open file in new tab"
+ "C-x t RET" "Switch tabs"
+ "C-x t C-r" "Open file (read-only) in new tab"
+ "C-x t 0" "Close current tab"
+ "C-x t 1" "Close other tabs"
+ "C-x t 2" "New empty tab"
+ "C-x t G" "Group tabs"
+ "C-x t M" "Move tab to position"
+ "C-x t N" "New tab and switch to it"
+ "C-x t O" "Previous tab"
+ "C-x t b" "Switch buffer in new tab"
+ "C-x t d" "Dired in new tab"
+ "C-x t f" "Open file in new tab"
+ "C-x t m" "Move tab left/right"
+ "C-x t n" "Duplicate tab"
+ "C-x t o" "Next tab"
+ "C-x t p" "Project in new tab"
+ "C-x t r" "Rename tab"
+ "C-x t t" "Switch to other tab"
+ "C-x t u" "Undo tab close"
+ "C-x t ^ f" "Detach tab window"
+ "C-x 8" "insert-special"
+ "C-x 8 ^" "superscript (⁰, ¹, ², …)"
+ "C-x 8 _" "subscript (₀, ₁, ₂, …)"
+ "C-x 8 a" "arrows & æ (←, →, ↔, æ)"
+ "C-x 8 e" "emojis (🫎, 🇧🇷, 🇮🇹, …)"
+ "C-x 8 *" "common symbols ( , ¡, €, …)"
+ "C-x 8 =" "macron (Ā, Ē, Ḡ, …)"
+ "C-x 8 N" "macron (№)"
+ "C-x 8 O" "macron (œ)"
+ "C-x 8 ~" "tilde (~, ã, …)"
+ "C-x 8 /" "stroke (÷, ≠, ø, …)"
+ "C-x 8 ." "dot (·, ż)"
+ "C-x 8 ," "cedilla (¸, ç, ą, …)"
+ "C-x 8 '" "acute (á, é, í, …)"
+ "C-x 8 `" "grave (à, è, ì, …)"
+ "C-x 8 \"" "quotation/dieresis (\", ë, ß, …)"
+ "C-x 8 1" "†, 1/…"
+ "C-x 8 2" "‡"
+ "C-x 8 3" "3/…"
+ "C-x 4" "other-window"
+ "C-x 5" "other-frame"))
+
+(use-package newcomment
+ :unless noninteractive
+ :custom
+ (comment-empty-lines t)
+ (comment-fill-column nil)
+ (comment-multi-line t)
+ (comment-style 'multi-line)
+ :config
+ (defun prot/comment-dwim (&optional arg)
+ "Alternative to `comment-dwim': offers a simple wrapper
+ around `comment-line' and `comment-dwim'.
+
+ If the region is active, then toggle the comment status of the
+ region or, if the major mode defines as much, of all the lines
+ implied by the region boundaries.
+
+ Else toggle the comment status of the line at point."
+ (interactive "*P")
+ (if (use-region-p)
+ (comment-dwim arg)
+ (save-excursion
+ (comment-line arg))))
+ :bind (("C-;" . prot/comment-dwim)
+ ("C-:" . comment-kill)
+ ("M-;" . comment-indent)
+ ("C-x C-;" . comment-box)))
+
+(use-package dired
+ :custom
+ (dired-hide-details-hide-information-lines 'nil)
+ (dired-kill-when-opening-new-dired-buffer 't)
+ :bind
+ (:map dired-mode-map
+ ("E" . wdired-change-to-wdired-mode)
+ ("l" . dired-find-file))
+ :hook
+ (dired-mode . dired-omit-mode)
+ (dired-mode . dired-hide-details-mode)
+ (dired-mode . dired-sort-toggle-or-edit))
+
+(use-package alert
+ :defer 2
+ :init
+ (defun alert-after-finish-in-background (buf str)
+ (when (or (not (get-buffer-window buf 'visible)) (not (frame-focus-state)))
+ (alert str :buffer buf)))
+ :config
+ (setq alert-default-style 'libnotify))
+
+(use-package elec-pair
+ :hook (after-init-hook . electric-pair-mode))
+
+(use-package uniquify
+ :custom
+ (uniquify-buffer-name-style 'forward)
+ (uniquify-strip-common-suffix t)
+ (uniquify-after-kill-buffer-p t))
+
+(use-package compile
+ :unless noninteractive
+ :commands (compile)
+ :custom
+ (compilation-always-kill t)
+ (compilation-scroll-output t)
+ (ansi-color-for-compilation-mode t)
+ :config
+ (add-hook 'compilation-finish-functions #'alert-after-finish-in-background))
+
+(use-package subword
+ :diminish
+ :hook (prog-mode-hook . subword-mode))
+
+;; Recentf
+(use-package recentf
+ :defer t
+ :hook
+ (after-nit . recentf-mode)
+ :bind (("C-x C-r" . recentf-open)))
+
+(use-package prog-mode
+ :hook
+ (prog-mode . eldoc-mode)
+ :custom
+ (eldoc-idle-delay 0.2))
+
+(use-package eglot
+ :bind
+ (:map eglot-mode-map
+ ("C-c e a" . eglot-code-actions)
+ ("C-c e r" . eglot-reconnect)
+ ("<f2>" . eglot-rename)
+ ("C-c e ?" . eldoc-print-current-symbol-info))
+ :custom
+ (eglot-autoshutdown t)
+ (eglot-confirm-server-initiated-edits nil)
+ :config
+ (add-to-list 'eglot-ignored-server-capabilities :documentHighlightProvider)
+ (add-to-list 'eglot-server-programs `(json-mode "vscode-json-language-server" "--stdio"))
+ (add-to-list 'eglot-server-programs '(nix-mode . ("nil")))
+ (setq-default eglot-workspace-configuration
+ '(
+ :gopls (
+ :usePlaceholders t
+ ;; See https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md
+ :analyses (
+ :QF1006 t
+ :QF1007 t
+ :S1002 t
+ :S1005 t
+ :S1006 t
+ :S1008 t
+ :S1025 t
+ :SA1003 t
+ :SA1014 t
+ :SA1015 t
+ :SA1023 t
+ :SA1032 t
+ :SA2002 t
+ :SA4023 t
+ :SA4031 t
+ :SA5000 t
+ :SA5010 t
+ :SA5000 t
+ :SA6000 t
+ :SA6001 t
+ :SA6002 t
+ :SA6003 t
+ :SA9003 t
+ :SA9007 t
+ :ST1000 t
+ :ST1001 t
+ :ST1005 t
+ :ST1013 t
+ :ST1015 t
+ :ST1016 t
+ :ST1017 t
+ :ST1019 t
+ :ST1020 t
+ :ST1021 t
+ :ST1022 t
+ :ST1023 t
+ :shadow t
+ )
+ ;; See https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md
+ :hints (:constantValues t :compositeLiteralTypes t :compositeLiteralFields t))
+ :nil (
+ :formatting (:command ["nixfmt"])
+ :nix (
+ :maxMemoryMB 2560
+ :autoEvalInputs t
+ :nixpkgsInputName "nixpkgs"
+ )
+ )
+ :pylsp (
+ :configurationSources ["flake8"]
+ :plugins (:pycodestyle (:enabled nil)
+ :black (:enabled t)
+ :mccabe (:enabled nil)
+ :flake8 (:enabled t)))))
+ (defun eglot-format-buffer-on-save ()
+ (if (and (project-current) (eglot-managed-p))
+ (add-hook 'before-save-hook #'eglot-format-buffer nil 'local)
+ (remove-hook 'before-save-hook #'eglot-format-buffer 'local)))
+ (add-hook 'eglot-managed-mode-hook #'eglot-format-buffer-on-save)
+ :hook
+ ;; (before-save . gofmt-before-save)
+ ;; (before-save . eglot-format-buffer)
+ (nix-mode . eglot-ensure)
+ (nix-ts-mode . eglot-ensure)
+ (rust-mode . eglot-ensure)
+ (rust-ts-mode . eglot-ensure)
+ (python-mode . eglot-ensure)
+ (python-ts-mode . eglot-ensure)
+ (go-mode . eglot-ensure)
+ (go-ts-mode . eglot-ensure)
+ (sh-mode . eglot-ensure)
+ (sh-script-mode . eglot-ensure))
+
+(setq major-mode-remap-alist
+ '((python-mode . python-ts-mode)
+ (go-mode . go-ts-mode)))
+
+(use-package markdown-mode
+ :mode "\\.md\\'")
+
+(use-package yaml-ts-mode
+ :mode "\\.yaml\\'")
+
+(use-package go-ts-mode
+ :mode (("\\.go$" . go-ts-mode)
+ ("\\.go" . go-ts-mode)
+ ("\\.go\\'" . go-ts-mode)))
+
+(use-package nix-ts-mode
+ :if (executable-find "nix")
+ :mode ("\\.nix\\'" "\\.nix.in\\'"))
+
+(use-package nix-drv-mode
+ :if (executable-find "nix")
+ :after nix-mode
+ :mode "\\.drv\\'")
+
+(use-package nix-shell
+ :if (executable-find "nix")
+ :after nix-mode
+ :commands (nix-shell-unpack nix-shell-configure nix-shell-build))
+
+(use-package nixpkgs-fmt
+ :if (executable-find "nix")
+ :after nix-ts-mode
+ :custom
+ (nixpkgs-fmt-command "nixfmt")
+ :config
+ (add-hook 'nix-ts-mode-hook 'nixpkgs-fmt-on-save-mode))
+
+(use-package minions
+ :hook (after-init . minions-mode)
+ :config
+ (add-to-list 'minions-prominent-modes 'flymake-mode))
+
+(use-package vundo
+ :bind (("M-u" . undo)
+ ("M-U" . undo-redo)
+ ("C-x u" . vundo)))
+
+(use-package vde-vcs
+ :commands (vde/gh-get-current-repo vde/vc-browse-remote)
+ :bind (("C-x v B" . vde/vc-browse-remote)))
+
+(use-package project-func
+ :commands (vde/project-magit-status vde/project-eat vde/project-vterm vde/project-run-in-vterm vde/project-try-local vde/open-readme))
+
+(use-package project
+ :commands (project-find-file project-find-regexp)
+ :custom
+ (project-switch-commands '((?f "File" project-find-file)
+ (?g "Grep" project-find-regexp)
+ (?d "Dired" project-dired)
+ (?b "Buffer" project-switch-to-buffer)
+ (?q "Query replace" project-query-replace-regexp)
+ (?m "Magit" vde/project-magit-status)
+ (?e "Eshell" project-eshell)
+ (?E "Eat" vde/project-eat)
+ (?s "Vterm" vde/project-vterm)
+ (?R "README" vde/open-readme)
+ (?g "Checkout GitHub PR" checkout-github-pr)))
+ (project-mode-line t)
+ (project-compilation-buffer-name-function 'project-prefixed-buffer-name)
+ (project-vc-extra-root-markers '(".project" "Cargo.toml" "pyproject.toml" "requirements.txt" "go.mod"))
+ :bind
+ ("C-x p v" . vde/project-magit-status)
+ ("C-x p s" . vde/project-vterm)
+ ("C-x p X" . vde/project-run-in-vterm)
+ ("C-x p E" . vde/project-eat)
+ ("C-x p G" . checkout-github-pr)
+ ("C-x p F" . flymake-show-project-diagnostics))
+
+(use-package magit
+ :unless noninteractive
+ :commands (magit-status magit-clone magit-pull magit-blame magit-log-buffer-file magit-log)
+ :bind (("C-c v c" . magit-commit)
+ ("C-c v C" . magit-checkout)
+ ("C-c v b" . magit-branch)
+ ("C-c v d" . magit-dispatch)
+ ("C-c v f" . magit-fetch)
+ ("C-c v g" . magit-blame)
+ ("C-c v l" . magit-log-buffer-file)
+ ("C-c v L" . magit-log)
+ ("C-c v p" . magit-pull)
+ ("C-c v P" . magit-push)
+ ("C-c v r" . magit-rebase)
+ ("C-c v s" . magit-stage)
+ ("C-c v v" . magit-status))
+ :custom
+ (magit-save-repository-buffers 'dontask)
+ (magit-refs-show-commit-count 'all)
+ (magit-branch-prefer-remote-upstream '("main"))
+ (magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1)
+ (magit-bury-buffer-function #'magit-restore-window-configuration)
+ (magit-refresh-status-buffer nil)
+ :config
+ ;; cargo-culted from https://github.com/magit/magit/issues/3717#issuecomment-734798341
+ ;; valid gitlab options are defined in https://docs.gitlab.com/ee/user/project/push_options.html
+ ;;
+ ;; the second argument to transient-append-suffix is where to append
+ ;; to, not sure what -u is, but this works
+ (transient-append-suffix 'magit-push "-u"
+ '(1 "=s" "Skip gitlab pipeline" "--push-option=ci.skip"))
+ (transient-append-suffix 'magit-push "=s"
+ '(1 "=m" "Create gitlab merge-request" "--push-option=merge_request.create"))
+ (transient-append-suffix 'magit-push "=m"
+ '(1 "=o" "Set push option" "--push-option=")) ;; Will prompt, can only set one extra
+ )
+
+(use-package ediff
+ :commands (ediff ediff-files ediff-merge ediff3 ediff-files3 ediff-merge3)
+ :custom
+ (ediff-window-setup-function 'ediff-setup-windows-plain)
+ (ediff-split-window-function 'split-window-horizontally)
+ (ediff-diff-options "-w")
+ :hook
+ (ediff-after-quit-hook-internal . winner-undo))
+
+(use-package diff
+ :custom
+ (diff-default-read-only nil)
+ (diff-advance-after-apply-hunk t)
+ (diff-update-on-the-fly t)
+ (diff-refine 'font-lock)
+ (diff-font-lock-prettify nil)
+ (diff-font-lock-syntax nil))
+
+(use-package gitconfig-mode
+ :commands (gitconfig-mode)
+ :mode (("/\\.gitconfig\\'" . gitconfig-mode)
+ ("/\\.git/config\\'" . gitconfig-mode)
+ ("/git/config\\'" . gitconfig-mode)
+ ("/\\.gitmodules\\'" . gitconfig-mode)))
+
+(use-package gitignore-mode
+ :commands (gitignore-mode)
+ :mode (("/\\.gitignore\\'" . gitignore-mode)
+ ("/\\.git/info/exclude\\'" . gitignore-mode)
+ ("/git/ignore\\'" . gitignore-mode)))
+
+(use-package gitattributes-mode
+ :commands (gitattributes-mode)
+ :mode (("/\\.gitattributes" . gitattributes-mode)))
+
+(use-package diff-hl
+ :hook (find-file . diff-hl-mode)
+ :hook (prog-mode . diff-hl-mode)
+ :hook (magit-post-refresh . diff-hl-magit-post-refresh)
+ :bind
+ (:map diff-hl-command-map
+ ("n" . diff-hl-next-hunk)
+ ("p" . diff-hl-previous-hunk)
+ ("[" . nil)
+ ("]" . nil)
+ ("DEL" . diff-hl-revert-hunk)
+ ("<delete>" . diff-hl-revert-hunk)
+ ("SPC" . diff-hl-mark-hunk)
+ :map vc-prefix-map
+ ("n" . diff-hl-next-hunk)
+ ("p" . diff-hl-previous-hunk)
+ ("s" . diff-hl-stage-dwim)
+ ("DEL" . diff-hl-revert-hunk)
+ ("<delete>" . diff-hl-revert-hunk)
+ ("SPC" . diff-hl-mark-hunk))
+ :config
+ (put 'diff-hl-inline-popup-hide
+ 'repeat-map 'diff-hl-command-map))
+
+(use-package diff-hl-inline-popup
+ :after (diff-hl))
+(use-package diff-hl-show-hunk
+ :after (diff-hl))
+
+(use-package diff-hl-dired
+ :after (diff-hl)
+ :hook (dired-mode . diff-hl-dired-mode))
+
+(use-package corfu
+ :custom
+ (corfu-auto 't)
+ :bind
+ (:map corfu-map
+ ("TAB" . corfu-next)
+ ("C-c" . corfu-quit)
+ ([tab] . corfu-next)
+ ("S-TAB" . corfu-previous)
+ ([backtab] . corfu-previous))
+ :hook
+ (after-init . global-corfu-mode))
+
+(use-package corfu-history
+ :after (corfu)
+ :hook
+ (after-init . corfu-history-mode))
+
+(use-package corfu-popupinfo
+ :after corfu
+ :config
+ (corfu-popupinfo-mode 1))
+
+(use-package corfu-terminal
+ :unless (display-graphic-p)
+ :ensure t
+ :hook
+ (after-init . corfu-terminal-mode))
+
+(use-package envrc
+ :defer 2
+ :if (executable-find "direnv")
+ :bind (:map envrc-mode-map
+ ("C-c e" . envrc-command-map))
+ :config (envrc-global-mode))
+
+(use-package cape
+ :init
+ (add-hook 'completion-at-point-functions #'cape-dabbrev)
+ (add-hook 'completion-at-point-functions #'cape-file)
+ (add-hook 'completion-at-point-functions #'cape-elisp-block))
+
+(use-package winner
+ :unless noninteractive
+ :hook
+ (after-init . winner-mode))
+
+(use-package windmove
+ :bind
+ ("S-<up>" . windmove-up)
+ ("S-<left>" . windmove-left)
+ ("S-<right>" . windmove-right)
+ ("S-<down>" . windmove-down)
+ ("M-S-<up>" . windmove-swap-states-up)
+ ("M-S-<left>" . windmove-swap-states-left)
+ ("M-S-<right>" . windmove-swap-states-right)
+ ("M-S-<down>" . windmove-swap-states-down))
+
+(use-package window
+ :unless noninteractive
+ :commands (shrink-window-horizontally shrink-window enlarge-window-horizontally enlarge-window)
+ :bind (("S-C-<left>" . shrink-window-horizontally)
+ ("S-C-<right>" . enlarge-window-horizontally)
+ ("S-C-<down>" . shrink-window)
+ ("S-C-<up>" . enlarge-window)))
+
+;; Prefer ripgrep (rg) if present (instead of grep)
+(setq xref-search-program
+ (cond
+ ((or (executable-find "ripgrep")
+ (executable-find "rg"))
+ 'ripgrep)
+ ((executable-find "ugrep")
+ 'ugrep)
+ (t
+ 'grep)))
+
+(use-package rg
+ :if (executable-find "rg")
+ :commands (rg rg-project rg-dwim)
+ :bind (("M-s r r" . rg)
+ ("M-s r p" . rg-project)
+ ("M-s r s" . rg-dwim))
+ :custom
+ (rg-group-result t)
+ (rg-hide-command t)
+ (rg-show-columns nil)
+ (rg-show-header t)
+ (rg-default-alias-fallback "all")
+ :config
+ (cl-pushnew '("tmpl" . "*.tmpl") rg-custom-type-aliases)
+ (cl-pushnew '("gotest" . "*_test.go") rg-custom-type-aliases)
+ (defun vde/rg-buffer-name ()
+ "Generate a rg buffer name from project if in one"
+ (let ((p (project-root (project-current))))
+ (if p
+ (format "rg: %s" (abbreviate-file-name p))
+ "rg")))
+ (setq rg-buffer-name #'vde/rg-buffer-name))
+
+(use-package wgrep
+ :unless noninteractive
+ :commands (wgrep-change-to-wgrep-mode)
+ :custom
+ (wgrep-auto-save-buffer t)
+ (wgrep-change-readonly-file t)
+ :bind (:map grep-mode-map
+ ("e" . wgrep-change-to-wgrep-mode)
+ ("C-x C-q" . wgrep-change-to-wgrep-mode)))
+
+(use-package tempel
+ :custom (tempel-path (expand-file-name "templates" user-emacs-directory))
+ :bind (("M-+" . tempel-complete) ;; Alternative tempel-expand
+ ("M-*" . tempel-insert)))
+
+(use-package embark
+ :unless noninteractive
+ :commands (embark-act embark-dwim embark-prefix-help-command)
+ :bind
+ ("C-." . embark-act)
+ ("M-." . embark-dwim)
+ ("C-h b" . embark-bindings)
+ ("C-h B" . embark-bindings-at-point)
+ ("C-h M" . embark-bindings-in-keymap)
+ (:map completion-list-mode-map
+ ("." . embark-act))
+ :custom
+ (embark-indicators '(embark-minimal-indicator
+ embark-highlight-indicator
+ embark-isearch-highlight-indicator))
+ (embark-cycle-key ".")
+ (embark-help-key "?"))
+
+(use-package pr-review
+ :commands (pr-review pr-review-open pr-review-submit-review)
+ :custom
+ (pr-review-ghub-host "api.github.com")
+ (pr-review-notification-include-read nil)
+ (pr-review-notification-include-unsubscribed nil))
+
+(use-package pr-review-search
+ :commands (pr-review-search pr-review-search-open pr-review-current-repository pr-review-current-repository-search)
+ :config
+ (defun pr-review-current-repository-search (query)
+ "Run pr-review-search on the current repository."
+ (interactive "sSearch query: ")
+ (pr-review-search (format "is:pr archived:false is:open repo:%s %s" (vde/gh-get-current-repo) query)))
+
+ (defun pr-review-current-repository ()
+ "Run pr-review-search on the current repository."
+ (interactive)
+ (pr-review-search (format "is:pr archived:false is:open repo:%s" (vde/gh-get-current-repo)))))
+
+(use-package jinx
+ :hook (emacs-startup . global-jinx-mode)
+ :bind (([remap ispell-word] . jinx-correct) ;; ("M-$" . jinx-correct)
+ ("C-M-$" . jinx-languages)))
+
+(use-package eljira
+ :commands (eljira)
+ :ensure nil
+ :load-path "~/src/github.com/sawwheet/eljira/"
+ :custom
+ (eljira-token (passage-get "redhat/issues/token/myji"))
+ (eljira-username "vdemeest@redhat.com")
+ (eljira-url "https://issues.redhat.com"))
+
+(use-package chatgpt-shell
+ :commands (chatgpt-shell)
+ :custom
+ (chatgpt-shell-google-key (passage-get "ai/gemini/api_key"))
+ (chatgpt-shell-openrouter-key (passage-get "ai/openroute/api_key"))
+ (chatgpt-shell-deepseek-key (passage-get "ai/deepseek/api_key")))
+
+;; TODO window management
+;; TODO ORG mode configuration (BIG one)
+(use-package org
+ :if (file-exists-p org-directory)
+ :mode (("\\.org$" . org-mode)
+ ("\\.org.draft$" . org-mode))
+ :commands (org-agenda org-capture)
+ :bind (("C-c o l" . org-store-link)
+ ("C-c o r r" . org-refile)
+ ;; ("C-c o r R" . vde/reload-org-refile-targets)
+ ("C-c o a a" . org-agenda)
+ ;; ("C-c o a r" . vde/reload-org-agenda-files)
+ ;; ("C-c C-x i" . vde/org-clock-in-any-heading)
+ ("C-c o s" . org-sort)
+ ("C-c O" . org-open-at-point-global)
+ ("<f12>" . org-agenda))
+ :custom
+ (org-use-speed-commands t)
+ (org-special-ctrl-a/e t)
+ (org-special-ctrl-k t)
+ (org-hide-emphasis-markers t)
+ (org-pretty-entities t)
+ (org-ellipsis "…")
+ (org-return-follows-link t)
+ (org-todo-keywords '((sequence "STRT(s)" "NEXT(n)" "TODO(t)" "WAIT(w)" "|" "DONE(d!)" "CANX(c@/!)")))
+ (org-todo-state-tags-triggers '(("CANX" ("CANX" . t))
+ ("WAIT" ("WAIT" . t))
+ (done ("WAIT"))
+ ("TODO" ("WAIT") ("CANX"))
+ ("NEXT" ("WAIT") ("CANX"))
+ ("DONE" ("WAIT") ("CANX"))))
+ (org-tag-alist
+ '((:startgroup)
+ ("Handson" . ?o)
+ (:grouptags)
+ ("Write" . ?w) ("Code" . ?c)
+ (:endgroup)
+
+ (:startgroup)
+ ("Handsoff" . ?f)
+ (:grouptags)
+ ("Read" . ?r) ("Watch" . ?W) ("Listen" . ?l)
+ (:endgroup)))
+ (org-log-done 'time)
+ (org-log-redeadline 'time)
+ (org-log-reschedule 'time)
+ (org-log-into-drawer t)
+ ;; https://jeffbradberry.com/posts/2025/05/orgmode-priority-cookies/
+ ;; 1 2 and 3 are high, 4 is default, 5 is "hide / whenever or maybe never"
+ (org-priority-highest 1)
+ (org-priority-lowest 5)
+ (org-priority-default 4)
+ (org-list-demote-modify-bullet '(("+" . "-") ("-" . "+")))
+ (org-agenda-file-regexp "^[a-zA-Z0-9-_]+.org$")
+ (org-agenda-files `(,org-inbox-file ,org-todos-file))
+ (org-agenda-remove-tags t)
+ (org-agenda-span 'day)
+ (org-agenda-start-on-weekday 1)
+ (org-agenda-window-setup 'current-window)
+ (org-agenda-sticky t)
+ (org-agenda-sorting-strategy
+ '((agenda time-up deadline-up scheduled-up todo-state-up priority-down)
+ (todo todo-state-up priority-down deadline-up)
+ (tags todo-state-up priority-down deadline-up)
+ (search todo-state-up priority-down deadline-up)))
+ (org-agenda-custom-commands
+ '(
+ ;; Archive tasks
+ ("#" "To archive" todo "DONE|CANX")
+ ;; TODO take inspiration from those
+ ;; ("$" "Appointments" agenda* "Appointments")
+ ;; ("b" "Week tasks" agenda "Scheduled tasks for this week"
+ ;; ((org-agenda-category-filter-preset '("-RDV")) ; RDV for Rendez-vous
+ ;; (org-agenda-use-time-grid nil)))
+ ;;
+ ;; ;; Review started and next tasks
+ ;; ("j" "STRT/NEXT" tags-todo "TODO={STRT\\|NEXT}")
+ ;;
+ ;; ;; Review other non-scheduled/deadlined to-do tasks
+ ;; ("k" "TODO" tags-todo "TODO={TODO}+DEADLINE=\"\"+SCHEDULED=\"\"")
+ ;;
+ ;; ;; Review other non-scheduled/deadlined pending tasks
+ ;; ("l" "WAIT" tags-todo "TODO={WAIT}+DEADLINE=\"\"+SCHEDULED=\"\"")
+ ;;
+ ;; ;; Review upcoming deadlines for the next 60 days
+ ;; ("!" "Deadlines all" agenda "Past/upcoming deadlines"
+ ;; ((org-agenda-span 1)
+ ;; (org-deadline-warning-days 60)
+ ;; (org-agenda-entry-types '(:deadline))))
+
+ ("d" "Daily Agenda"
+ ((agenda ""
+ ((org-agenda-span 'day)
+ (org-deadline-warning-days 5)))
+ (tags-todo "+PRIORITY=\"1\""
+ ((org-agenda-overriding-header "High Priority Tasks")))
+ (todo "NEXT"
+ ((org-agenda-overriding-header "Next Tasks")))))
+ ("D" "Daily Agenda (old)"
+ ((agenda ""
+ ((org-agenda-files (vde/all-org-agenda-files))
+ (org-agenda-span 'day)
+ (org-deadline-warning-days 5)))
+ (tags-todo "+PRIORITY=\"A\""
+ ((org-agenda-files (vde/all-org-agenda-files))
+ (org-agenda-overriding-header "High Priority Tasks")))
+ (todo "NEXT"
+ ((org-agenda-files (vde/all-org-agenda-files))
+ (org-agenda-overriding-header "Next Tasks")))))
+ ("i" "Inbox (triage)"
+ ((tags-todo ".*"
+ ((org-agenda-files `(,org-inbox-file)) ;; FIXME use constant here
+ (org-agenda-overriding-header "Unprocessed Inbox Item")))))
+ ("A" "All (old)"
+ ((tags-todo ".*"
+ ((org-agenda-files (vde/all-org-agenda-files))))))
+ ("u" "Untagged Tasks"
+ ((tags-todo "-{.*}"
+ ((org-agenda-overriding-header "Untagged tasks")))))
+ ("w" "Weekly Review"
+ ((agenda ""
+ ((org-agenda-overriding-header "Completed Tasks")
+ (org-agenda-skip-function '(org-agenda-skip-entry-if 'nottodo 'done))
+ (org-agenda-span 'week)))
+ (agenda ""
+ ((org-agenda-overriding-header "Unfinished Scheduled Tasks")
+ (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
+ (org-agenda-span 'week)))))
+ ;; FIXME Should only take into account projects and areas ?
+ ("R" "Review projects" tags-todo "-CANX/"
+ ((org-agenda-overriding-header "Reviews Scheduled")
+ (org-agenda-skip-function 'org-review-agenda-skip)
+ (org-agenda-cmp-user-defined 'org-review-compare)
+ (org-agenda-sorting-strategy '(user-defined-down))))))
+ ;; TODO cleanup this list a bit
+ (org-agenda-category-icon-alist `(("personal" ,(list (propertize "🏡")))
+ ("work" ,(list (propertize "🏢")))
+ ("appointments" ,(list (propertize "📅")))
+ ("health" ,(list (propertize "⚕️")))
+ ("systems" ,(list (propertize "🖥️")))
+ ("journal" ,(list (propertize "📝")))
+ ("project--" ,(list (propertize "💼" )))
+ ("tekton", (list (propertize "😼")))
+ ("openshift-pipelines", (list (propertize "🎩")))
+ ("redhat", (list (propertize "🎩")))
+ ("area--" ,(list (propertize"🏢" )))
+ ("area--home" ,(list (propertize "🏡")))
+ ("home" ,(list (propertize "🏡")))
+ ("home-services" ,(list (propertize "☕ ")))
+ ("email" ,(list (propertize"📨" )))
+ ("people" ,(list (propertize"👤" )))
+ ("machine" ,(list (propertize "🖥️")))
+ ("website" ,(list (propertize "🌍")))
+ ("bike" ,(list (propertize "🚴♂️")))
+ ("security" ,(list (propertize "🛡️")))
+ ("i*" ,(list (propertize "📒")))))
+ (org-agenda-prefix-format '((agenda . " %i %?-12t% s")
+ (todo . " %i")
+ (tags . " %i")
+ (search . " %i")))
+ (org-insert-heading-respect-content t)
+ (org-M-RET-may-split-line '((default . nil)))
+ (org-goto-interface 'outline-path-completion)
+ (org-outline-path-complete-in-steps nil)
+ (org-goto-max-level 2)
+ :bind
+ (:map org-mode-map
+ ("C-<left>" . org-shiftleft)
+ ("C-<right>" . org-shiftright)
+ ("C-<up>" . org-shiftup)
+ ("C-<down>" . org-shiftdown))
+ :config
+ (unbind-key "S-<left>" org-mode-map)
+ (unbind-key "S-<right>" org-mode-map)
+ (unbind-key "S-<up>" org-mode-map)
+ (unbind-key "S-<down>" org-mode-map)
+ (unbind-key "M-S-<left>" org-mode-map)
+ (unbind-key "M-S-<right>" org-mode-map)
+ (unbind-key "M-S-<up>" org-mode-map)
+ (unbind-key "M-S-<down>" org-mode-map)
+ (unbind-key "C-S-<left>" org-mode-map)
+ (unbind-key "C-S-<right>" org-mode-map)
+ (unbind-key "C-S-<up>" org-mode-map)
+ (unbind-key "C-S-<down>" org-mode-map))
+
+(use-package org-agenda
+ :after org
+ :commands (org-agenda)
+ :config
+ (unbind-key "S-<left>" org-agenda-mode-map)
+ (unbind-key "S-<right>" org-agenda-mode-map)
+ (unbind-key "S-<up>" org-agenda-mode-map)
+ (unbind-key "S-<down>" org-agenda-mode-map)
+ (unbind-key "C-S-<left>" org-agenda-mode-map)
+ (unbind-key "C-S-<right>" org-agenda-mode-map))
+
+;; Make sure we load org-protocol
+(use-package org-protocol
+ :after org)
+
+(use-package org-tempo
+ :after (org)
+ :custom
+ (org-structure-template-alist '(("a" . "aside")
+ ("c" . "center")
+ ("C" . "comment")
+ ("e" . "example")
+ ("E" . "export")
+ ("Ea" . "export ascii")
+ ("Eh" . "export html")
+ ("El" . "export latex")
+ ("q" . "quote")
+ ("s" . "src")
+ ("se" . "src emacs-lisp")
+ ("sE" . "src emacs-lisp :results value code :lexical t")
+ ("sg" . "src go")
+ ("sr" . "src rust")
+ ("sp" . "src python")
+ ("v" . "verse"))))
+
+(use-package org-capture
+ :after org
+ :commands (org-capture)
+ :config
+
+ (add-to-list 'org-capture-templates
+ `("j" "Journal entry" item
+ (file+datetree+prompt ,org-journal-file)
+ "%U %?\n%i"))
+
+ ;; TODO: refine this, create a function that reset this
+ (add-to-list 'org-capture-templates
+ `("l" "Link" entry
+ (file ,org-inbox-file)
+ "* %a\n%U\n%?\n%i"
+ :empty-lines 1))
+ (add-to-list 'org-capture-templates
+ `("t" "Tasks"))
+ (add-to-list 'org-capture-templates
+ `("tt" "New task" entry
+ (file ,org-inbox-file)
+ "* %?\n:PROPERTIES:\n:CREATED:\t%U\n:END:\n\n%i\n\nFrom: %a"
+ :empty-lines 1))
+ ;; Refine this
+ (add-to-list 'org-capture-templates
+ `("tr" "PR Review" entry
+ (file ,org-inbox-file)
+ "* TODO review gh:%^{issue} :review:\n:PROPERTIES:\n:CREATED:%U\n:END:\n\n%i\n%?\nFrom: %a"
+ :empty-lines 1))
+ ;; emails
+ (add-to-list 'org-capture-templates
+ `("m" "Email Workflow"))
+ (add-to-list 'org-capture-templates
+ `("mf" "Follow Up" entry
+ (file ,org-inbox-file)
+ "* TODO Follow up with %:from on %a\nSCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%i"
+ :immediate-finish t))
+ (add-to-list 'org-capture-templates
+ `("mr" "Read Later" entry
+ (file ,org-inbox-file)
+ "* TODO Read %:subject\nSCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%a\n\n%i" :immediate-finish t))
+ ;; (add-to-list 'org-capture-templates
+ ;; `("m" "Meeting notes" entry
+ ;; (file+datetree ,org-meeting-notes-file)
+ ;; (file ,(concat user-emacs-directory "/etc/orgmode/meeting-notes.org"))))
+
+ (defun vde/window-delete-popup-frame (&rest _)
+ "Kill selected selected frame if it has parameter `prot-window-popup-frame'.
+Use this function via a hook."
+ (when (frame-parameter nil 'vde/window-popup-frame)
+ (delete-frame)))
+
+ (add-to-list 'org-capture-templates
+ `("w" "Writing"))
+ (add-hook 'org-capture-after-finalize-hook #'vde/window-delete-popup-frame)
+ :bind (("C-c o c" . org-capture)))
+
+(use-package org-habit
+ :after org
+ :custom
+ (org-habit-show-habits-only-for-today nil)
+ (org-habit-graph-column 80))
+
+(use-package denote
+ :commands (denote)
+ :bind (("C-c n c" . denote-region)
+ ("C-c n i" . denote-link-or-create)
+ ("C-c n b" . denote-backlinks)
+ ("C-c n F f" . denote-find-link)
+ ("C-c n F b" . denote-find-backlink))
+ :custom
+ (denote-directory org-notes-directory)
+ (denote-rename-buffer-format "📝 %t")
+ (denote-date-prompt-denote-date-prompt-use-org-read-date t)
+ (denote-prompts '(title keywords))
+ (denote-backlinks-display-buffer-action
+ '((display-buffer-reuse-window
+ display-buffer-in-side-window)
+ (side . bottom)
+ (slot . 99)
+ (window-width . 0.3)
+ (dedicated . t)
+ (preserve-size . (t . t))))
+ :hook (dired-mode . denote-dired-mode)
+ :config
+ (denote-rename-buffer-mode 1)
+ (defun my-denote-always-rename-on-save-based-on-front-matter ()
+ "Rename the current Denote file, if needed, upon saving the file.
+Rename the file based on its front matter, checking for changes in the
+title or keywords fields.
+
+Add this function to the `after-save-hook'."
+ (let ((denote-rename-confirmations nil)
+ (denote-save-buffers t)) ; to save again post-rename
+ (when (and buffer-file-name (denote-file-is-note-p buffer-file-name))
+ (ignore-errors (denote-rename-file-using-front-matter buffer-file-name))
+ (message "Buffer saved; Denote file renamed"))))
+
+ (add-hook 'after-save-hook #'my-denote-always-rename-on-save-based-on-front-matter)
+
+ (defun vde/org-category-from-buffer ()
+ "Get the org category (#+category:) value from the buffer"
+ (cond
+ ((string-match "__journal.org$" (buffer-file-name))
+ "journal")
+ (t
+ (denote-sluggify (denote--retrieve-title-or-filename (buffer-file-name) 'org))))))
+
+(use-package denote-org
+ :after (denote org)
+ :defer 2)
+
+;; (use-package whisper
+;; :commands (whisper-run whisper-file)
+;; :custom
+;; (whisper-install-whispercpp nil))
+;; TODO gptel configuration (and *maybe* copilot)
+
+(provide 'init)
+;;; init.el ends here
tools/emacs/nano.el
@@ -1,255 +0,0 @@
-;; nano-emacs.el --- NANO Emacs (minimal version) -*- lexical-binding: t -*-
-
-;; Copyright (c) 2025 Nicolas P. Rougier
-;; Released under the GNU General Public License 3.0
-;; Author: Nicolas P. Rougier <nicolas.rougier@inria.fr>
-;; URL: https://github.com/rougier/nano-emacs
-
-;; This is NANO Emacs in 256 lines, without any dependency
-;; Usage (command line): emacs -Q -l nano.el -[light|dark]
-
-;; --- Speed benchmarking -----------------------------------------------------
-(setq init-start-time (current-time))
-
-;; --- Typography stack -------------------------------------------------------
-(set-face-attribute 'default nil
- :height 140 :weight 'light :family "Roboto Mono")
-(set-face-attribute 'bold nil :weight 'regular)
-(set-face-attribute 'bold-italic nil :weight 'regular)
-(set-display-table-slot standard-display-table 'truncation (make-glyph-code ?…))
-(set-display-table-slot standard-display-table 'wrap (make-glyph-code ?–))
-
-;; --- Frame / windows layout & behavior --------------------------------------
-(setq default-frame-alist
- '((height . 44) (width . 81) (left-fringe . 0) (right-fringe . 0)
- (internal-border-width . 32) (vertical-scroll-bars . nil)
- (bottom-divider-width . 0) (right-divider-width . 0)
- (undecorated-round . t)))
-(modify-frame-parameters nil default-frame-alist)
-(setq-default pop-up-windows nil)
-
-;; --- Activate / Deactivate modes --------------------------------------------
-(tool-bar-mode -1) (menu-bar-mode -1) (blink-cursor-mode -1)
-(global-hl-line-mode 1) (icomplete-vertical-mode 1)
-(pixel-scroll-precision-mode 1)
-
-;; --- Minimal NANO (not a real) theme ----------------------------------------
-(defface nano-default '((t)) "") (defface nano-default-i '((t)) "")
-(defface nano-highlight '((t)) "") (defface nano-highlight-i '((t)) "")
-(defface nano-subtle '((t)) "") (defface nano-subtle-i '((t)) "")
-(defface nano-faded '((t)) "") (defface nano-faded-i '((t)) "")
-(defface nano-salient '((t)) "") (defface nano-salient-i '((t)) "")
-(defface nano-popout '((t)) "") (defface nano-popout-i '((t)) "")
-(defface nano-strong '((t)) "") (defface nano-strong-i '((t)) "")
-(defface nano-critical '((t)) "") (defface nano-critical-i '((t)) "")
-
-(defun nano-set-face (name &optional foreground background weight)
- "Set NAME and NAME-i faces with given FOREGROUND, BACKGROUND and WEIGHT"
-
- (apply #'set-face-attribute `(,name nil
- ,@(when foreground `(:foreground ,foreground))
- ,@(when background `(:background ,background))
- ,@(when weight `(:weight ,weight))))
- (apply #'set-face-attribute `(,(intern (concat (symbol-name name) "-i")) nil
- :foreground ,(face-background 'nano-default)
- ,@(when foreground `(:background ,foreground))
- :weight regular)))
-
-(defun nano-link-face (sources faces &optional attributes)
- "Make FACES to inherit from SOURCES faces and unspecify ATTRIBUTES."
-
- (let ((attributes (or attributes
- '( :foreground :background :family :weight
- :height :slant :overline :underline :box))))
- (dolist (face (seq-filter #'facep faces))
- (dolist (attribute attributes)
- (set-face-attribute face nil attribute 'unspecified))
- (set-face-attribute face nil :inherit sources))))
-
-(defun nano-install-theme ()
- "Install THEME"
-
- (set-face-attribute 'default nil
- :foreground (face-foreground 'nano-default)
- :background (face-background 'nano-default))
- (dolist (item '((nano-default . (variable-pitch variable-pitch-text
- fixed-pitch fixed-pitch-serif))
- (nano-highlight . (hl-line highlight))
- (nano-subtle . (match region
- lazy-highlight widget-field))
- (nano-faded . (shadow
- font-lock-comment-face
- font-lock-doc-face
- icomplete-section
- completions-annotations))
- (nano-popout . (warning
- font-lock-string-face))
- (nano-salient . (success link
- help-argument-name
- custom-visibility
- font-lock-type-face
- font-lock-keyword-face
- font-lock-builtin-face
- completions-common-part))
- (nano-strong . (font-lock-function-name-face
- font-lock-variable-name-face
- icomplete-first-match
- minibuffer-prompt))
- (nano-critical . (error
- completions-first-difference))
- (nano-faded-i . (help-key-binding))
- (nano-default-i . (custom-button-mouse
- isearch))
- (nano-critical-i . (isearch-fail))
- ((nano-subtle nano-strong) . (custom-button
- icomplete-selected-match))
- ((nano-faded-i nano-strong) . (show-paren-match))))
- (nano-link-face (car item) (cdr item)))
-
- ;; Mode & header lines
- (set-face-attribute 'header-line nil
- :background 'unspecified
- :underline nil
- :box `( :line-width 1
- :color ,(face-background 'nano-default))
- :inherit 'nano-subtle)
- (set-face-attribute 'mode-line nil
- :background (face-background 'default)
- :underline (face-foreground 'nano-faded)
- :height 40 :overline nil :box nil)
- (set-face-attribute 'mode-line-inactive nil
- :background (face-background 'default)
- :underline (face-foreground 'nano-faded)
- :height 40 :overline nil :box nil))
-
-(defun nano-light (&rest args)
- "NANO light theme (based on material colors)"
-
- (interactive)
- (nano-set-face 'nano-default "#37474F" "#FFFFFF") ;; Blue Grey / L800
- (nano-set-face 'nano-strong "#000000" nil 'regular) ;; Black
- (nano-set-face 'nano-highlight nil "#FAFAFA") ;; Very Light Grey
- (nano-set-face 'nano-subtle nil "#ECEFF1") ;; Blue Grey / L50
- (nano-set-face 'nano-faded "#90A4AE") ;; Blue Grey / L300
- (nano-set-face 'nano-salient "#673AB7") ;; Deep Purple / L500
- (nano-set-face 'nano-popout "#FFAB91") ;; Deep Orange / L200
- (nano-set-face 'nano-critical "#FF6F00") ;; Amber / L900
- (nano-install-theme))
-
-(defun nano-dark (&rest args)
- "NANO dark theme (based on nord colors)"
-
- (interactive)
- (nano-set-face 'nano-default "#ECEFF4" "#2E3440") ;; Snow Storm 3
- (nano-set-face 'nano-strong "#ECEFF4" nil 'regular) ;; Polar Night 0
- (nano-set-face 'nano-highlight nil "#3B4252") ;; Polar Night 1
- (nano-set-face 'nano-subtle nil "#434C5E") ;; Polar Night 2
- (nano-set-face 'nano-faded "#677691") ;;
- (nano-set-face 'nano-salient "#81A1C1") ;; Frost 2
- (nano-set-face 'nano-popout "#D08770") ;; Aurora 1
- (nano-set-face 'nano-critical "#EBCB8B") ;; Aurora 2
- (nano-install-theme))
-
-;; --- Command line theme chooser ---------------------------------------------
-(add-to-list 'command-switch-alist '("-dark" . nano-dark))
-(add-to-list 'command-switch-alist '("-light" . nano-light))
-(if (member "-dark" command-line-args) (nano-dark) (nano-light))
-
-;; --- Minibuffer completion --------------------------------------------------
-(setq tab-always-indent 'complete
- icomplete-delay-completions-threshold 0
- icomplete-compute-delay 0
- icomplete-show-matches-on-no-input t
- icomplete-hide-common-prefix nil
- icomplete-prospects-height 9
- icomplete-separator " . "
- icomplete-with-completion-tables t
- icomplete-in-buffer t
- icomplete-max-delay-chars 0
- icomplete-scroll t
- resize-mini-windows 'grow-only
- icomplete-matches-format nil)
-(bind-key "TAB" #'icomplete-force-complete icomplete-minibuffer-map)
-(bind-key "RET" #'icomplete-force-complete-and-exit icomplete-minibuffer-map)
-
-;; --- Minimal key bindings ---------------------------------------------------
-(defun nano-quit ()
- "Quit minibuffer from anywhere (code from Protesilaos Stavrou)"
-
- (interactive)
- (cond ((region-active-p) (keyboard-quit))
- ((derived-mode-p 'completion-list-mode) (delete-completion-window))
- ((> (minibuffer-depth) 0) (abort-recursive-edit))
- (t (keyboard-quit))))
-
-(defun nano-kill ()
- "Delete frame or kill emacs if there is only one frame left"
-
- (interactive)
- (condition-case nil
- (delete-frame)
- (error (save-buffers-kill-terminal))))
-
-(bind-key "C-x k" #'kill-current-buffer)
-(bind-key "C-x C-c" #'nano-kill)
-(bind-key "C-x C-r" #'recentf-open)
-(bind-key "C-g" #'nano-quit)
-(bind-key "M-n" #'make-frame)
-(bind-key "C-z" nil) ;; No suspend frame
-(bind-key "C-<wheel-up>" nil) ;; No text resize via mouse scroll
-(bind-key "C-<wheel-down>" nil) ;; No text resize via mouse scroll
-
-;; --- Sane settings ----------------------------------------------------------
-(set-default-coding-systems 'utf-8)
-(setq-default indent-tabs-mode nil
- ring-bell-function 'ignore
- select-enable-clipboard t)
-
-;; --- OSX Specific -----------------------------------------------------------
-(when (eq system-type 'darwin)
- (select-frame-set-input-focus (selected-frame))
- (setq mac-option-modifier nil
- ns-function-modifier 'super
- mac-right-command-modifier 'hyper
- mac-right-option-modifier 'alt
- mac-command-modifier 'meta))
-
-;; --- Header & mode lines ----------------------------------------------------
-(setq-default mode-line-format "")
-(setq-default header-line-format
- '(:eval
- (let ((prefix (cond (buffer-read-only '("RO" . nano-default-i))
- ((buffer-modified-p) '("**" . nano-critical-i))
- (t '("RW" . nano-faded-i))))
- (mode (concat "(" (downcase (cond ((consp mode-name) (car mode-name))
- ((stringp mode-name) mode-name)
- (t "unknow")))
- " mode)"))
- (coords (format-mode-line "%c:%l ")))
- (list
- (propertize " " 'face (cdr prefix) 'display '(raise -0.25))
- (propertize (car prefix) 'face (cdr prefix))
- (propertize " " 'face (cdr prefix) 'display '(raise +0.25))
- (propertize (format-mode-line " %b ") 'face 'nano-strong)
- (propertize mode 'face 'header-line)
- (propertize " " 'display `(space :align-to (- right ,(length coords))))
- (propertize coords 'face 'nano-faded)))))
-
-;; --- Minibuffer setup -------------------------------------------------------
-(defun nano-minibuffer--setup ()
- (set-window-margins nil 3 0)
- (let ((inhibit-read-only t))
- (add-text-properties (point-min) (+ (point-min) 1)
- `(display ((margin left-margin)
- ,(format "# %s" (substring (minibuffer-prompt) 0 1))))))
- (setq truncate-lines t))
-(add-hook 'minibuffer-setup-hook #'nano-minibuffer--setup)
-
-;; --- Speed benchmarking -----------------------------------------------------
-(let ((init-time (float-time (time-subtract (current-time) init-start-time)))
- (total-time (string-to-number (emacs-init-time "%f"))))
- (message (concat
- (propertize "Startup time: " 'face 'bold)
- (format "%.2fs " init-time)
- (propertize (format "(+ %.2fs system time)"
- (- total-time init-time)) 'face 'shadow))))
tools/emacs/prot-init.el
@@ -1,170 +0,0 @@
-;; From https://protesilaos.com/codelog/2024-11-28-basic-emacs-configuration/
-;; For inspiration
-(setq custom-file (locate-user-emacs-file "custom.el"))
-(load custom-file :no-error-if-file-is-missing)
-
-;;; Set up the package manager
-
-(require 'package)
-(package-initialize)
-
-(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
-
-(when (< emacs-major-version 29)
- (unless (package-installed-p 'use-package)
- (unless package-archive-contents
- (package-refresh-contents))
- (package-install 'use-package)))
-
-(add-to-list 'display-buffer-alist
- '("\\`\\*\\(Warnings\\|Compile-Log\\)\\*\\'"
- (display-buffer-no-window)
- (allow-no-window . t)))
-
-;;; Basic behaviour
-
-(use-package delsel
- :ensure nil
- :hook (after-init . delete-selection-mode))
-
-(defun prot/keyboard-quit-dwim ()
- "Do-What-I-Mean behaviour for a general `keyboard-quit'.
-
-The generic `keyboard-quit' does not do the expected thing when
-the minibuffer is open. Whereas we want it to close the
-minibuffer, even without explicitly focusing it.
-
-The DWIM behaviour of this command is as follows:
-
-- When the region is active, disable it.
-- When a minibuffer is open, but not focused, close the minibuffer.
-- When the Completions buffer is selected, close it.
-- In every other case use the regular `keyboard-quit'."
- (interactive)
- (cond
- ((region-active-p)
- (keyboard-quit))
- ((derived-mode-p 'completion-list-mode)
- (delete-completion-window))
- ((> (minibuffer-depth) 0)
- (abort-recursive-edit))
- (t
- (keyboard-quit))))
-
-(define-key global-map (kbd "C-g") #'prot/keyboard-quit-dwim)
-
-;;; Tweak the looks of Emacs
-
-;; Those three belong in the early-init.el, but I am putting them here
-;; for convenience. If the early-init.el exists in the same directory
-;; as the init.el, then Emacs will read+evaluate it before moving to
-;; the init.el.
-(menu-bar-mode 1)
-(scroll-bar-mode 1)
-(tool-bar-mode -1)
-
-(let ((mono-spaced-font "Monospace")
- (proportionately-spaced-font "Sans"))
- (set-face-attribute 'default nil :family mono-spaced-font :height 100)
- (set-face-attribute 'fixed-pitch nil :family mono-spaced-font :height 1.0)
- (set-face-attribute 'variable-pitch nil :family proportionately-spaced-font :height 1.0))
-
-(use-package modus-themes
- :ensure t
- :config
- (load-theme 'modus-vivendi-tinted :no-confirm-loading))
-
-;; Remember to do M-x and run `nerd-icons-install-fonts' to get the
-;; font files. Then restart Emacs to see the effect.
-(use-package nerd-icons
- :ensure t)
-
-(use-package nerd-icons-completion
- :ensure t
- :after marginalia
- :config
- (add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup))
-
-(use-package nerd-icons-corfu
- :ensure t
- :after corfu
- :config
- (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))
-
-(use-package nerd-icons-dired
- :ensure t
- :hook
- (dired-mode . nerd-icons-dired-mode))
-
-;;; Configure the minibuffer and completions
-
-(use-package vertico
- :ensure t
- :hook (after-init . vertico-mode))
-
-(use-package marginalia
- :ensure t
- :hook (after-init . marginalia-mode))
-
-(use-package orderless
- :ensure t
- :config
- (setq completion-styles '(orderless basic))
- (setq completion-category-defaults nil)
- (setq completion-category-overrides nil))
-
-(use-package savehist
- :ensure nil ; it is built-in
- :hook (after-init . savehist-mode))
-
-(use-package corfu
- :ensure t
- :hook (after-init . global-corfu-mode)
- :bind (:map corfu-map ("<tab>" . corfu-complete))
- :config
- (setq tab-always-indent 'complete)
- (setq corfu-preview-current nil)
- (setq corfu-min-width 20)
-
- (setq corfu-popupinfo-delay '(1.25 . 0.5))
- (corfu-popupinfo-mode 1) ; shows documentation after `corfu-popupinfo-delay'
-
- ;; Sort by input history (no need to modify `corfu-sort-function').
- (with-eval-after-load 'savehist
- (corfu-history-mode 1)
- (add-to-list 'savehist-additional-variables 'corfu-history)))
-
-;;; The file manager (Dired)
-
-(use-package dired
- :ensure nil
- :commands (dired)
- :hook
- ((dired-mode . dired-hide-details-mode)
- (dired-mode . hl-line-mode))
- :config
- (setq dired-recursive-copies 'always)
- (setq dired-recursive-deletes 'always)
- (setq delete-by-moving-to-trash t)
- (setq dired-dwim-target t))
-
-(use-package dired-subtree
- :ensure t
- :after dired
- :bind
- ( :map dired-mode-map
- ("<tab>" . dired-subtree-toggle)
- ("TAB" . dired-subtree-toggle)
- ("<backtab>" . dired-subtree-remove)
- ("S-TAB" . dired-subtree-remove))
- :config
- (setq dired-subtree-use-backgrounds nil))
-
-(use-package trashed
- :ensure t
- :commands (trashed)
- :config
- (setq trashed-action-confirmer 'y-or-n-p)
- (setq trashed-use-header-line t)
- (setq trashed-sort-key '("Date deleted" . t))
- (setq trashed-date-format "%Y-%m-%d %H:%M:%S"))