init-kbd-func.el (10011B)
1 ;;; init-kbd-func.el --- functions -*- lexical-binding: t -*- 2 3 ;;; Commentary: 4 5 ;;; Code: 6 7 (defun my-open-init-file () 8 "Open user's init.el file." 9 (interactive) 10 (find-file user-init-file)) 11 12 (defun my-open-custom-file () 13 "Open user's `custom-file'." 14 (interactive) 15 (or (find-file custom-file) 16 (user-error "No custom file"))) 17 18 (defun my-empty-line-p (&optional really-empty) 19 (save-excursion 20 (beginning-of-line) 21 (looking-at-p (if really-empty 22 "$" 23 "[[:blank:]]*$")))) 24 25 (defun my-electric-open-line-and-indent (n) 26 "Insert N newlines and leave point before them. 27 If there is a fill prefix and/or a `left-margin', insert them on the new 28 line if the line would have been blank. Reindent the line following the 29 inserted newlines, if that line is blank, remove its indentation." 30 (interactive "*p") 31 (let* ((do-fill-prefix (and fill-prefix (bolp))) 32 (do-left-margin (and (bolp) (> (current-left-margin) 0))) 33 (loc (point-marker)) 34 (abbrev-mode nil)) 35 (newline n) 36 (when (and (not do-left-margin) 37 (not do-fill-prefix)) 38 (indent-according-to-mode) 39 (when (my-empty-line-p) 40 (delete-horizontal-space t))) 41 (goto-char loc) 42 (while (> n 0) 43 (cond ((bolp) 44 (if do-left-margin (indent-to (current-left-margin))) 45 (if do-fill-prefix (insert-and-inherit fill-prefix)))) 46 (forward-line 1) 47 (setq n (1- n))) 48 (goto-char loc) 49 (end-of-line))) 50 51 (defun my-copy-function-name () 52 "Copy the function name return by `which-function'." 53 (interactive) 54 (if-let* ((func (which-function))) 55 (progn (kill-new func) 56 (message "Save `%s' to kill ring." func)) 57 (message "Cannot find the name of the current function."))) 58 59 (defun my-copy-buffer-name () 60 "Copy the name of the current buffer." 61 (interactive) 62 (if-let* ((buf (buffer-name))) 63 (progn (kill-new buf) 64 (message "Save `%s' to kill ring." buf)) 65 (message "Cannot find the name of the current buffer."))) 66 67 (defun my-copy-file-path (arg) 68 "Copy the path of the current file. 69 With a prefix ARG, copy the expanded file path." 70 (interactive "P") 71 (if-let* ((path (buffer-file-name))) 72 (progn 73 (unless arg (setq path (abbreviate-file-name path))) 74 (kill-new path) 75 (message "Save `%s' to kill ring." path)) 76 (message "Cannot find the path of the current file."))) 77 78 (defun my-count-words-region (start end &optional totals) 79 "Count the number of words in the region. 80 With prefix ARG, report for the entire buffer rather than the region." 81 (interactive (if current-prefix-arg 82 (list nil nil current-prefix-arg) 83 (list (region-beginning) (region-end) nil))) 84 (cl-letf (((symbol-function 'forward-word-strictly) #'forward-word)) 85 (if totals 86 (message "%s" (count-words--buffer-format)) 87 (message "%s" (count-words--format 88 "Region" (region-beginning) (region-end)))))) 89 90 (defun my-bounds-of-next-thing (thing) 91 "Return the bounds of THING at or after point." 92 (or (bounds-of-thing-at-point thing) 93 (save-excursion (ignore-errors (forward-thing thing 1) 94 (forward-thing thing -1)) 95 (bounds-of-thing-at-point thing)))) 96 97 (defun my-bounds-of-symbol-at-point-or-next-sexp () 98 (let* ((symbol (my-bounds-of-next-thing 'symbol)) 99 (sexp (my-bounds-of-next-thing 'sexp)) 100 (at-point-p (bounds-of-thing-at-point 'symbol))) 101 (if at-point-p 102 symbol 103 sexp))) 104 105 (defun my-mark-sexp-hack (fun &optional arg allow-extend) 106 (if (and allow-extend 107 (or (and (eq last-command this-command) (mark t)) 108 (and transient-mark-mode mark-active))) 109 (funcall fun arg allow-extend) 110 (let* ((bounds (or (my-bounds-of-symbol-at-point-or-next-sexp) 111 (bounds-of-thing-at-point 'sexp))) 112 (pos (point)) 113 (beg (car bounds)) 114 (end (cdr bounds)) 115 (endp (equal (point) end))) 116 (goto-char beg) 117 (funcall fun arg allow-extend) 118 (if endp (exchange-point-and-mark))))) 119 (advice-add #'mark-sexp :around #'my-mark-sexp-hack) 120 121 (defun my-mark-word-hack (&optional arg allow-extend) 122 (unless (and allow-extend 123 (or (and (eq last-command this-command) (mark t)) 124 (region-active-p))) 125 (when-let* ((beg (car (my-bounds-of-next-thing 'word)))) 126 (goto-char beg)))) 127 (advice-add #'mark-word :before #'my-mark-word-hack) 128 129 ;; from Bozhidar Batsov's crux 130 (defun my-kill-line-backwards () 131 "Kill line backwards and adjust the indentation." 132 (interactive) 133 (kill-line 0) 134 (indent-according-to-mode)) 135 136 ;; from Bozhidar Batsov's crux 137 (defun my-get-positions-of-line-or-region () 138 "Return positions (beg . end) of the current line or region." 139 (let (beg end) 140 (if (and mark-active (> (point) (mark))) 141 (exchange-point-and-mark)) 142 (setq beg (line-beginning-position)) 143 (if mark-active 144 (exchange-point-and-mark)) 145 (setq end (line-end-position)) 146 (cons beg end))) 147 148 (defun my-duplicate-current-line-or-region (arg) 149 "Duplicates the current line or region ARG times. 150 If there's no region, the current line will be duplicated. However, if 151 there's a region, all lines that region covers will be duplicated." 152 (interactive "p") 153 (pcase-let* ((origin (point)) 154 (`(,beg . ,end) (my-get-positions-of-line-or-region)) 155 (region (buffer-substring-no-properties beg end))) 156 (dotimes (_i arg) 157 (goto-char end) 158 (newline) 159 (insert region) 160 (setq end (point))) 161 (goto-char (+ origin (* (length region) arg) arg)))) 162 163 (defun enable-truncate-lines () 164 (setq truncate-lines t)) 165 166 (defun my-eshell-input-from-history () 167 "Insert command from eshell input history." 168 (interactive) 169 (let ((history (ring-elements eshell-history-ring))) 170 (insert 171 (completing-read 172 "Insert input from history: " 173 history)))) 174 175 (defun query-replace-case-sensitive () 176 "Case-sensitive `query-replace'." 177 (interactive) 178 (let ((case-fold-search nil)) 179 (call-interactively #'query-replace))) 180 181 (defun my-show-utc-time (&optional arg) 182 "Display current UTC time in echo area." 183 (interactive "P") 184 (let ((time (format-time-string "%Y-%m-%d %H:%M UTC" nil t))) 185 (if arg 186 (progn (kill-new time) (message "Save `%s' to kill ring." time)) 187 (message time)))) 188 189 (defun my-back-to-indentation () 190 "Move point to the first non-whitespace character on this line." 191 (interactive "^") 192 (beginning-of-line 1) 193 (when (looking-at "^ ?[-+]+") 194 (goto-char (match-end 0))) 195 (skip-syntax-forward " " (line-end-position)) 196 (backward-prefix-chars)) 197 198 (defun my-straight-package-dir (package) 199 "Return the source directory of PACKAGE if it exist. 200 PACKAGE is a string." 201 (when-let* ((recipe 202 (ignore-errors 203 (or (gethash package straight--recipe-cache) 204 (straight--convert-recipe (intern package))))) 205 (local-repo (plist-get recipe :local-repo))) 206 (straight--repos-dir local-repo))) 207 208 (defun my-straight-packages-count () 209 "Count how many straight.el package are currently installed." 210 (interactive) 211 (if (called-interactively-p 'interactive) 212 (message (format "%s packages installed" (hash-table-count straight--profile-cache))) 213 (hash-table-count straight--profile-cache))) 214 215 (defun my-insert-straight-packages () 216 "Insert straight.el packages." 217 (interactive) 218 (dolist (item (sort (hash-table-keys straight--profile-cache))) 219 (insert (format "- %s\n" item)))) 220 221 (defun my-insert-raw-org-link (arg) 222 "Insert the last link stored in `org-stored-links' in its raw form. 223 When a prefix ARG, do not delete the links from `org-stored-links'." 224 (interactive "P") 225 (if-let* ((links (and (bound-and-true-p org-stored-links) org-stored-links)) 226 (link (if arg (caar links) (car (pop org-stored-links)))) 227 (unpropertized (substring-no-properties link))) 228 (insert unpropertized) 229 (message "No link to insert"))) 230 231 (defun org-cycle-parent-subtree() 232 "Cycle parent org subtree." 233 (interactive) 234 (if (org-at-heading-p) 235 (progn 236 (org-up-heading 1) 237 (org-cycle)) 238 (org-back-to-heading) 239 (org-cycle))) 240 241 (defun my-blog-find-file () 242 "Find blog file use denote-file-prompt." 243 (interactive) 244 (let* ((denote-directory my-blog-directory) 245 (denote-prompts '(title keywords))) 246 (call-interactively #'denote-open-or-create))) 247 248 (defun my-blog-grep () 249 "Run `consult-grep' in `my-blog-directory'." 250 (interactive) 251 (consult-grep my-blog-directory)) 252 253 (defun my-org-table-align-all () 254 "Adjust all table in current buffer." 255 (interactive) 256 (org-table-map-tables 'org-table-align t)) 257 258 (defun my-org-align-description-list () 259 "Adjust all `::' in active region." 260 (interactive) 261 (align-regexp (region-beginning) (region-end) "\\(\\s-*\\)::" 1 1 nil)) 262 263 (defun my-push-with-timestamp (directory) 264 "Git add/commit/push, generate commit message." 265 (let ((timestamp (format-time-string "%Y-%m-%d %H:%M:%S")) 266 (default-directory directory)) 267 (message "Adding files...") 268 (eshell-command "git add .") 269 (message "Committing: %s" timestamp) 270 (eshell-command (format "git commit -m \"Update: %s\"" timestamp)) 271 (message "Pushing to remote...") 272 (let ((exit-code (eshell-command "git push"))) 273 (if (eq exit-code t) 274 (message "Push may have failed or nothing to push, check *Messages* buffer for details") 275 (message "Push successfully %s" timestamp))))) 276 277 (defun my-note-push () 278 "Git add/commit/push in 'my-org-directory'." 279 (interactive) 280 (my-push-with-timestamp my-org-directory)) 281 282 (defun my-org-publish () 283 "Git add/commit/push in `my-blog-directory'." 284 (interactive) 285 (my-push-with-timestamp my-blog-directory)) 286 (defalias 'my-blog-push (symbol-function #'my-org-publish)) 287 288 (provide 'init-kbd-func) 289 ;;; init-kbd-func.el ends here