diff --git a/configuration.org b/configuration.org index b85416f..b2f3810 100644 --- a/configuration.org +++ b/configuration.org @@ -84,6 +84,591 @@ It is built-in since 29.1, and let’s hope I never get back using older version (require 'quelpa-use-package) #+end_src +* Custom functions and commands + +This is a collection of functions and commands i wrote or stole from all around the internet. + +** Utilities + +*** Make a backup filename under ~user-emacs-cache-directory~ + +Taken from [[http://ergoemacs.org/emacs/emacs_set_backup_into_a_directory.html][Xah’s site]]. + +#+begin_src emacs-lisp +(defun xah/backup-file-name (fpath) + "Return a new file path for FPATH under `user-emacs-cache-directory'" + (let* ((backup-root-dir (expand-file-name "backup" user-emacs-cache-directory)) + (file-path (replace-regexp-in-string "[A-Za-z]:" "" fpath)) + (backup-file-path (replace-regexp-in-string "//" "/" (concat backup-root-dir file-path "~")))) + (make-directory (file-name-directory backup-file-path) (file-name-directory backup-file-path)) + backup-file-path)) +#+end_src + +*** Check if we’re running under Termux + +We need to do things differently, if so. + +There’s probably a better way, though, other than checking the path of our home directory. + +#+begin_src emacs-lisp +(defun gpolonkai/termux-p () + "Check if Emacs is running under Termux." + (string-match-p + (regexp-quote "/com.termux/") + (expand-file-name "~"))) +#+end_src + +*** Find the first number on line + +#+begin_src emacs-lisp +(defun gpolonkai/find-number-on-line () + "Find the first number on the current line." + (save-excursion + (without-restriction + (goto-char (pos-bol)) + (when (re-search-forward "[0-9]+" (pos-eol) t) + (number-at-point))))) +#+end_src + +*** Round number at point to the given decimals + +#+begin_src emacs-lisp +(defun gpolonkai/round-number-at-point-to-decimals (decimal-count) + (interactive "NDecimal count: ") + (let ((mult (expt 10 decimal-count))) + (replace-match (number-to-string + (/ + (fround + (* + mult + (number-at-point))) + mult))))) +#+end_src + +*** Leave ~isearch~ at the other end of the matched string + +From [[http://endlessparentheses.com/leave-the-cursor-at-start-of-match-after-isearch.html][Endless Parentheses]]. + +#+begin_src emacs-lisp +(defun ep/isearch-exit-other-end () + "Exit isearch, at the opposite end of the string." + (interactive) + + (isearch-exit) + (goto-char isearch-other-end)) +#+end_src + +*** Mark the current match after leaving ~isearch~ + +From [[http://emacs.stackexchange.com/a/31321/507][Emacs SE]]. + +#+begin_src emacs-lisp +(defun e-se/isearch-exit-mark-match () + "Exit isearch and mark the current match." + (interactive) + (isearch-exit) + (push-mark isearch-other-end) + (activate-mark)) +#+end_src + +*** Copy the prototype of the current C function + +#+begin_src emacs-lisp +(defun gpolonkai/copy-func-prototype () + "Copy the current function's prototype to the kill ring." + + (interactive) + + (save-excursion + (beginning-of-defun) + (let ((protocopy-begin (point))) + (forward-list) + (let ((protocopy-end (point))) + (kill-ring-save protocopy-begin protocopy-end))))) +#+end_src + +** Window manipulation + +*** Bury a window + +#+begin_src emacs-lisp +(defun gpolonkai/bury-window (window) + "Quit WINDOW without killing it." + (interactive) + (quit-window nil window)) +#+end_src + +*** Scroll a specific window up or down + +#+begin_src emacs-lisp +(defun gpolonkai/scroll-window-up (window) + "Scroll WINDOW up as `scroll-up-command' would." + (interactive) + (save-selected-window + (select-window window) + (scroll-up))) + +(defun gpolonkai/scroll-window-down (window) + "Scroll WINDOW down as `scroll-down-command' would." + (interactive) + (save-selected-window + (select-window window) + (scroll-down))) +#+end_src + +*** Transpose windows + +#+begin_src emacs-lisp +(defun gpolonkai/transpose-windows (arg) + "Transpose the buffers shown in two windows." + (interactive "p") + (let ((selector (if (>= arg 0) 'next-window 'previous-window))) + (while (/= arg 0) + (let ((this-win (window-buffer)) + (next-win (window-buffer (funcall selector)))) + (set-window-buffer (selected-window) next-win) + (set-window-buffer (funcall selector) this-win) + (select-window (funcall selector))) + (setq arg (if (plusp arg) (1- arg) (1+ arg)))))) +#+end_src + +*** Toggle window split between horizontal and vertical + +#+begin_src emacs-lisp +(defun gpolonkai/toggle-window-split () + (interactive) + (if (= (count-windows) 2) + (let* ((this-win-buffer (window-buffer)) + (next-win-buffer (window-buffer (next-window))) + (this-win-edges (window-edges (selected-window))) + (next-win-edges (window-edges (next-window))) + (this-win-2nd (not (and (<= (car this-win-edges) + (car next-win-edges)) + (<= (cadr this-win-edges) + (cadr next-win-edges))))) + (splitter + (if (= (car this-win-edges) + (car (window-edges (next-window)))) + 'split-window-horizontally + 'split-window-vertically))) + (delete-other-windows) + (let ((first-win (selected-window))) + (funcall splitter) + (if this-win-2nd (other-window 1)) + (set-window-buffer (selected-window) this-win-buffer) + (set-window-buffer (next-window) next-win-buffer) + (select-window first-win) + (if this-win-2nd (other-window 1)))) + (error "This works only for two windows!"))) +#+end_src + +** Org-mode related + +*** Wrapper around ~org-agenda~ to open my own custom list + +#+begin_src emacs-lisp +(defun gpolonkai/org-agenda-list (&optional arg) + (interactive "P") + (org-agenda arg "c")) +#+end_src + +*** Insert the current timestamp + +#+begin_src emacs-lisp +(defun gpolonkai/org-insert-current-timestamp (&optional arg) + "Insert the current timestamp" + (interactive "P") + (org-time-stamp '(16) arg)) +#+end_src + +*** Insert two spaces after specific characters + +#+begin_src emacs-lisp +(defun gpolonkai/org-space-key (&optional arg) + "Insert two spaces after a period. + +ARG will be passed down verbatim to `self-insert-command'" + (interactive "p") + + (when (looking-back "[.!?…]" nil) + (call-interactively 'self-insert-command arg)) + (call-interactively 'self-insert-command arg)) +#+end_src + +*** Filter out tasks from the Org agenda if they have a specific priority + +The whole idea comes from [[https://blog.aaronbieber.com/2016/09/24/an-agenda-for-life-with-org-mode.html][here]] which i use almost verbatim, hence the ~air-~ prefix. + +#+begin_src emacs-lisp +(defun air-org-skip-subtree-if-priority (priority) + "Skip an agenda subtree if it has a priority of PRIORITY. + +PRIORITY may be one of the characters ?A, ?B, or ?C." + (let ((subtree-end (save-excursion (org-end-of-subtree t))) + (pri-value (* 1000 (- org-lowest-priority priority))) + (pri-current (org-get-priority (thing-at-point 'line t)))) + (if (= pri-value pri-current) + subtree-end + nil))) +#+end_src + +*** Filter out habits from the Org agenda + +#+begin_src emacs-lisp +(defun air-org-skip-subtree-if-habit () + "Skip an agenda entry if it has a STYLE property equal to \"habit\"." + (let ((subtree-end (save-excursion (org-end-of-subtree t)))) + (if (string= (org-entry-get nil "STYLE") "habit") + subtree-end + nil))) +#+end_src + +*** Filter out entries from the Org agenda with a specific state + +#+begin_src emacs-lisp +(defun gpolonkai/org-skip-subtree-if-state (state) + "Skip an agenda entry if its state is STATE." + (let ((subtree-end (save-excursion (org-end-of-subtree t)))) + (if (string= (org-get-todo-state) state) + subtree-end + nil))) +#+end_src + +*** Insert a heading with CREATED set to the current time + +This emulates how Orgzly work with my current settings. + +#+begin_src emacs-lisp +(defun gpolonkai/org-insert-heading-created (&optional arg) + (interactive "p") + (let* ((org-insert-heading-respect-content t) + (format-string (concat "[" (substring (cdr org-time-stamp-formats) 1 -1) "]")) + (timestamp (format-time-string format-string (current-time)))) + (if (> arg 1) + (org-insert-subheading '(4)) + (org-insert-heading)) + (org-set-property "CREATED" timestamp))) +#+end_src + +*** Unfold everything during ~ediff~ sessions + +EDiff and Org-mode files don’t play nice together… + +From [[http://article.gmane.org/gmane.emacs.orgmode/75222][the org-mode mailing list]]. + +#+begin_src emacs-lisp +(defun f-ediff-org-showhide (buf command &rest cmdargs) + "If buffer BUF exists and in `org-mode', execute COMMAND with CMDARGS." + (when buf + (when (eq (buffer-local-value 'major-mode (get-buffer buf)) 'org-mode) + (save-excursion + (set-buffer buf) + (apply command cmdargs))))) + +(defun f-ediff-org-unfold-tree-element () + "Unfold tree at diff location." + (f-ediff-org-showhide ediff-buffer-A 'org-reveal) + (f-ediff-org-showhide ediff-buffer-B 'org-reveal) + (f-ediff-org-showhide ediff-buffer-C 'org-reveal)) + +(defun f-ediff-org-fold-tree () + "Fold tree back to top level." + (f-ediff-org-showhide ediff-buffer-A 'hide-sublevels 1) + (f-ediff-org-showhide ediff-buffer-B 'hide-sublevels 1) + (f-ediff-org-showhide ediff-buffer-C 'hide-sublevels 1)) +#+end_src + +*** Add code references to Org documents + +From the [[http://www.howardism.org/Technical/Emacs/capturing-content.html][Howardism blog]]. + +#+begin_src emacs-lisp +(defun ha/org-capture-fileref-snippet (f type headers func-name) + (let* ((code-snippet + (buffer-substring-no-properties (mark) (- (point) 1))) + (file-name (buffer-file-name)) + (file-base (file-name-nondirectory file-name)) + (line-number (line-number-at-pos (region-beginning))) + (initial-txt (if (null func-name) + (format "From [[file:%s::%s][%s]]:" + file-name line-number file-base) + (format "From ~%s~ (in [[file:%s::%s][%s]]):" + func-name file-name line-number + file-base)))) + (format " + %s + + ,#+begin_%s %s +%s + ,#+end_%s" initial-txt type headers code-snippet type))) + +(defun ha/org-capture-clip-snippet (f) + "Given a file, F, this captures the currently selected text +within an Org EXAMPLE block and a backlink to the file." + (with-current-buffer (find-buffer-visiting f) + (ha/org-capture-fileref-snippet f "example" "" nil))) + +(defun ha/org-capture-code-snippet (f) + "Given a file, F, this captures the currently selected text +within an Org SRC block with a language based on the current mode +and a backlink to the function and the file." + (with-current-buffer (find-buffer-visiting f) + (let ((org-src-mode (replace-regexp-in-string "-mode" "" (format "%s" major-mode))) + (func-name (which-function))) + (ha/org-capture-fileref-snippet f "src" org-src-mode func-name)))) +#+end_src + +** Text manipulation + +*** Fill or unfill a paragraph + +From Sacha Chua’s [[http://pages.sachachua.com/.emacs.d/Sacha.html][blog]]. + +#+begin_src emacs-lisp +(defun sachachua/fill-or-unfill-paragraph (&optional unfill region) + "Fill (or unfill, if UNFILL is non-nil) paragraph (or REGION)." + (interactive (progn + (barf-if-buffer-read-only) + (list (if current-prefix-arg 'unfill) t))) + (let ((fill-column (if unfill (point-max) fill-column))) + (fill-paragraph nil region))) +#+end_src + +*** Toggle case of character at point + +Based on [[http://ergoemacs.org/emacs/modernization_upcase-word.html][Xah’s toggle letter case defun version 2015-12-22]] + +#+begin_src emacs-lisp +(defun gpolonkai/toggle-char-case (arg-move-point) + "Toggle the case of the char after point. + +If prefix argument ARG-MOVE-POINT is non-nil, move point after the char." + (interactive "P") + (let ((case-fold-search nil)) + (cond + ((looking-at "[[:lower:]]") (upcase-region (point) (1+ (point)))) + ((looking-at "[[:upper:]]") (downcase-region (point) (1+ (point))))) + (cond + (arg-move-point (right-char))))) +#+end_src + +*** Sort lines by the first number on it + +#+begin_src emacs-lisp +(defun gpolonkai/numeric-sort-lines (reverse beg end) + "Sort lines in region by version. +Interactively, REVERSE is the prefix argument, and BEG and END are the region. +Non-nil REVERSE means to sort in reverse order." + (interactive "P\nr") + (save-excursion + (save-restriction + (narrow-to-region beg end) + (goto-char (point-min)) + (let ((indibit-field-text-motion t)) + (sort-subr reverse 'forward-line 'end-of-line #'gpolonkai/find-number-on-line))))) +#+end_src + +*** Open a new line above + +#+begin_src emacs-lisp +(defun wted/open-line-above () + "Open a new line above point." + + (interactive) + + (beginning-of-line) + (newline) + (forward-line -1) + (indent-for-tab-command)) +#+end_src + +*** Open a new line below + +Copied from [[http://whattheemacsd.com/editing-defuns.el-01.html][whattheemacsd.com]]. + +#+begin_src emacs-lisp +(defun wted/open-line-below () + "Open a new line below point." + + (interactive) + + (end-of-line) + (newline) + (indent-for-tab-command)) +#+end_src + +*** Insert the current file’s name at point + +From [[http://mbork.pl/2019-02-17_Inserting_the_current_file_name_at_point][Marcin Borkowski]]. + +#+begin_src emacs-lisp +(defun mbork/insert-current-file-name-at-point (&optional full-path) + "Insert the current filename at point. +With prefix argument, use full path." + (interactive "P") + (let* ((buffer + (if (minibufferp) + (window-buffer + (minibuffer-selected-window)) + (current-buffer))) + (filename (buffer-file-name buffer))) + (if filename + (insert (if full-path filename (file-name-nondirectory filename))) + (error (format "Buffer %s is not visiting a file" (buffer-name buffer)))))) +#+end_src + +*** Swap occurences of strings + +From [[http://emacs.stackexchange.com/a/27170/507][Emacs SE]]. + +#+begin_src emacs-lisp +(defun e-se/query-swap-strings (from-string + to-string + &optional delimited start end) + "Swap occurrences of FROM-STRING and TO-STRING. + +DELIMITED, START, and END are passed down verbatim to `perform-replace'." + (interactive + (let ((common + (query-replace-read-args + (concat "Query swap" + (if current-prefix-arg + (if (eq current-prefix-arg '-) " backward" " word") + "") + (if (use-region-p) " in region" "")) + nil))) + (list (nth 0 common) (nth 1 common) (nth 2 common) + (if (use-region-p) (region-beginning)) + (if (use-region-p) (region-end))))) + (perform-replace + (concat "\\(" (regexp-quote from-string) "\\)\\|" (regexp-quote to-string)) + `(replace-eval-replacement replace-quote + (if (match-string 1) + ,to-string + ,from-string)) + t t delimited nil nil start end)) +#+end_src + +** Navigation + +*** Move to different beginnings/ends of the current line + +Inspired by Bozhidar Batsov's [[http://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/][solution]]. + +#+begin_src emacs-lisp +(defun gpolonkai/move-to-beginning-of-line () + "Move to different beginnings of the line. + +These are, in order: + +- beginning of the visual line if `visual-line-mode' is active, +- the first non-whitespace (indentation), +- the actual beginning of the line. + +This function will jump between the first character and the +indentation if used multiple times." + (interactive) + (let ((last-pos (point))) + (when visual-line-mode + (beginning-of-visual-line)) + (when (= (point) last-pos) + (back-to-indentation)) + (when (= (point) last-pos) + (beginning-of-line)) + (when (and (eq major-mode 'org-mode) + (= (point) last-pos)) + (org-beginning-of-line)) + (when (= (point) last-pos) + (back-to-indentation)))) + +(defun gpolonkai/move-to-end-of-line () + "Move to the end of the line. + +If `visual-line-mode' is active, jump to the end of the visual +line first. Then jump to the actual end of the line." + (interactive) + (let ((last-pos (point))) + (when visual-line-mode + (end-of-visual-line)) + (when (= (point) last-pos) + (end-of-line)) + (when (and (eq major-mode 'org-mode) + (= (point) last-pos)) + (org-end-of-line)))) +#+end_src + +*** Move to the next occurence of a character within the same line + +#+begin_src emacs-lisp +(defun gpolonkai/goto-next-char (chr) + (interactive "c") + (let ((substr (char-to-string chr)) + (end (save-excursion (end-of-line) (point)))) + (when (search-forward substr end t) + (backward-char)))) +#+end_src + +*** Move to the beginning of the next word + +#+begin_src emacs-lisp +(defun gpolonkai/beginning-of-next-word () + (interactive) + (let ((current-point (point))) + (forward-word 1) + (backward-word 1) + + (when (<= (point) current-point) + (forward-word 2) + (backward-word 1)))) +#+end_src + +** File manipulation + +*** Rename the current file + +From [[http://whattheemacsd.com/file-defuns.el-01.html][whattheemacsd.org]]. + +#+begin_src emacs-lisp +(defun wted/rename-current-buffer-file () + "Renames current buffer and file it is visiting." + (interactive) + + (let ((name (buffer-name)) + (filename (buffer-file-name))) + (if (not (and filename (file-exists-p filename))) + (error "Buffer '%s' is not visiting a file!" name) + (let ((new-name (read-file-name "New name: " filename))) + (if (get-buffer new-name) + (error "A buffer named '%s' already exists!" new-name) + (rename-file filename new-name 1) + (rename-buffer new-name) + (set-visited-file-name new-name) + ; TODO: this is suspicious for me… + (set-buffer-modified-p nil) + (message "File '%s' successfully renamed to '%s'" + name (file-name-nondirectory new-name))))))) +#+end_src + +*** Delete the current file + +From [[http://whattheemacsd.com/file-defuns.el-02.html][whattheemacsd.org]]. + +#+begin_src emacs-lisp +(defun wted/delete-current-buffer-file () + "Remove file connected to current buffer and kill the buffer." + (interactive) + + (let ((filename (buffer-file-name)) + (name (buffer-name)) + (buffer (current-buffer))) + (if (not (and filename (file-exists-p filename))) + (kill-buffer buffer) + (when (yes-or-no-p "Are you sure you want to remove this file? ") + (delete-file filename) + (kill-buffer buffer) + (message "File '%s' successfully removed" filename))))) +#+end_src + * Emacs configuration ** Set up the really basic things @@ -255,335 +840,6 @@ it as early as possible. * Custom commands and functions -** Utility functions - -*** Round number at point to the given decimals - -#+BEGIN_SRC emacs-lisp -(defun round-number-at-point-to-decimals (decimal-count) - (interactive "NDecimal count: ") - (let ((mult (expt 10 decimal-count))) - (replace-match (number-to-string - (/ - (fround - (* - mult - (number-at-point))) - mult))))) -#+END_SRC - -*** Make a backup filename under ~user-emacs-cache-directory~ - -Taken from [[http://ergoemacs.org/emacs/emacs_set_backup_into_a_directory.html][Xah’s site]]. - -#+BEGIN_SRC emacs-lisp -(defun xah/backup-file-name (fpath) - "Return a new file path for FPATH under `user-emacs-cache-directory'" - (let* ((backup-root-dir (expand-file-name "backup" user-emacs-cache-directory)) - (file-path (replace-regexp-in-string "[A-Za-z]:" "" fpath)) - (backup-file-path (replace-regexp-in-string "//" "/" (concat backup-root-dir file-path "~")))) - (make-directory (file-name-directory backup-file-path) (file-name-directory backup-file-path)) - backup-file-path)) -#+END_SRC - -*** Find the first number on line - -#+begin_src emacs-lisp -(defun gpolonkai/find-number-on-line () - "Find the first number on the current line." - (save-excursion - (without-restriction - (goto-char (pos-bol)) - (when (re-search-forward "[0-9]+" (pos-eol) t) - (number-at-point))))) -#+end_src - -** Check if we are running under Termux - -We need to do things differently, if so. - -#+BEGIN_SRC emacs-lisp -(defun termux-p () - "Check if Emacs is running under Termux." - (string-match-p - (regexp-quote "/com.termux/") - (expand-file-name "~"))) -#+END_SRC - -** Misc text manipulation functions - -*** Toggle case of character at point - -Based on [[http://ergoemacs.org/emacs/modernization_upcase-word.html][Xah’s toggle letter case defun version 2015-12-22]] - -#+BEGIN_SRC emacs-lisp -(defun toggle-char-case (arg-move-point) - "Toggle the case of the char after point. - -If prefix argument ARG-MOVE-POINT is non-nil, move point after the char." - (interactive "P") - (let ((case-fold-search nil)) - (cond - ((looking-at "[[:lower:]]") (upcase-region (point) (1+ (point)))) - ((looking-at "[[:upper:]]") (downcase-region (point) (1+ (point))))) - (cond - (arg-move-point (right-char))))) -#+END_SRC - -*** Open a new line below - -Copied from http://whattheemacsd.com/editing-defuns.el-01.html - -#+BEGIN_SRC emacs-lisp -(defun open-line-below () - "Open a new line below point." - - (interactive) - - (end-of-line) - (newline) - (indent-for-tab-command)) -#+END_SRC - -*** Open a new line above - -#+BEGIN_SRC emacs-lisp -(defun open-line-above () - "Open a new line above point." - - (interactive) - - (beginning-of-line) - (newline) - (forward-line -1) - (indent-for-tab-command)) -#+END_SRC - -*** Insert two spaces after specific characters - -#+BEGIN_SRC emacs-lisp -(defun org-space-key (&optional arg) - "Insert two spaces after a period. - -ARG will be passed down verbatim to `self-insert-command'" - (interactive "p") - - (when (looking-back "[.!?…]" nil) - (call-interactively 'self-insert-command arg)) - (call-interactively 'self-insert-command arg)) -#+END_SRC - -*** Fill or unfill a paragraph -:PROPERTIES: -:SOURCE: http://pages.sachachua.com/.emacs.d/Sacha.html -:END: - -#+BEGIN_SRC emacs-lisp -(defun sachachua/fill-or-unfill-paragraph (&optional unfill region) - "Fill (or unfill, if UNFILL is non-nil) paragraph (or REGION)." - (interactive (progn - (barf-if-buffer-read-only) - (list (if current-prefix-arg 'unfill) t))) - (let ((fill-column (if unfill (point-max) fill-column))) - (fill-paragraph nil region))) -#+END_SRC - -*** Swap occurences of strings -:PROPERTIES: -:SOURCE: http://emacs.stackexchange.com/a/27170/507 -:END: - -#+BEGIN_SRC emacs-lisp -(defun so/query-swap-strings (from-string - to-string - &optional delimited start end) - "Swap occurrences of FROM-STRING and TO-STRING. - -DELIMITED, START, and END are passed down verbatim to `perform-replace'." - (interactive - (let ((common - (query-replace-read-args - (concat "Query swap" - (if current-prefix-arg - (if (eq current-prefix-arg '-) " backward" " word") - "") - (if (use-region-p) " in region" "")) - nil))) - (list (nth 0 common) (nth 1 common) (nth 2 common) - (if (use-region-p) (region-beginning)) - (if (use-region-p) (region-end))))) - (perform-replace - (concat "\\(" (regexp-quote from-string) "\\)\\|" (regexp-quote to-string)) - `(replace-eval-replacement replace-quote - (if (match-string 1) - ,to-string - ,from-string)) - t t delimited nil nil start end)) -#+END_SRC - -*** Insert the current file’s name at point -:PROPERTIES: -:SOURCE: http://mbork.pl/2019-02-17_Inserting_the_current_file_name_at_point -:END: - -#+BEGIN_SRC emacs-lisp -(defun insert-current-file-name-at-point (&optional full-path) - "Insert the current filename at point. -With prefix argument, use full path." - (interactive "P") - (let* ((buffer - (if (minibufferp) - (window-buffer - (minibuffer-selected-window)) - (current-buffer))) - (filename (buffer-file-name buffer))) - (if filename - (insert (if full-path filename (file-name-nondirectory filename))) - (error (format "Buffer %s is not visiting a file" (buffer-name buffer)))))) -#+END_SRC - -*** Sort lines by the first number on it - -#+begin_src emacs-lisp -(defun gpolonkai/numeric-sort-lines (reverse beg end) - "Sort lines in region by version. -Interactively, REVERSE is the prefix argument, and BEG and END are the region. -Non-nil REVERSE means to sort in reverse order." - (interactive "P\nr") - (save-excursion - (save-restriction - (narrow-to-region beg end) - (goto-char (point-min)) - (let ((indibit-field-text-motion t)) - (sort-subr reverse 'forward-line 'end-of-line #'gpolonkai/find-number-on-line))))) -#+end_src - -** Navigation - -*** Move to different beginnings of the current line - -Inspired by Bozhidar Batsov's [[http://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/][solution]]. - -#+BEGIN_SRC emacs-lisp -(defun gpolonkai/move-to-beginning-of-line () - "Move to different beginnings of the line. - -These are, in order: - -- beginning of the visual line if `visual-line-mode' is active, -- the first non-whitespace (indentation), -- the actual beginning of the line. - -This function will jump between the first character and the -indentation if used multiple times." - (interactive) - (let ((last-pos (point))) - (when visual-line-mode - (beginning-of-visual-line)) - (when (= (point) last-pos) - (back-to-indentation)) - (when (= (point) last-pos) - (beginning-of-line)) - (when (and (eq major-mode 'org-mode) - (= (point) last-pos)) - (org-beginning-of-line)) - (when (= (point) last-pos) - (back-to-indentation)))) -#+END_SRC - -*** Move to the different ends of the current line - -#+BEGIN_SRC emacs-lisp -(defun gpolonkai/move-to-end-of-line () - "Move to the end of the line. - -If `visual-line-mode' is active, jump to the end of the visual -line first. Then jump to the actual end of the line." - (interactive) - (let ((last-pos (point))) - (when visual-line-mode - (end-of-visual-line)) - (when (= (point) last-pos) - (end-of-line)) - (when (and (eq major-mode 'org-mode) - (= (point) last-pos)) - (org-end-of-line)))) -#+END_SRC - -*** Move to the next occurence of a character within the same line - -#+begin_src emacs-lisp -(defun goto-next-char (chr) - (interactive "c") - (let ((substr (char-to-string chr)) - (end (save-excursion (end-of-line) (point)))) - (when (search-forward substr end t) - (backward-char)))) -#+end_src - -*** Move to the beginning of the next word - -#+begin_src emacs-lisp -(defun gpolonkai/beginning-of-next-word () - (interactive) - (let ((current-point (point))) - (forward-word 1) - (backward-word 1) - - (when (<= (point) current-point) - (forward-word 2) - (backward-word 1)))) -#+end_src - -** File manipulation - -*** Rename the current file -:PROPERTIES: -:SOURCE: http://whattheemacsd.com/file-defuns.el-01.html -:END: - -#+BEGIN_SRC emacs-lisp -(defun rename-current-buffer-file () - "Renames current buffer and file it is visiting." - (interactive) - - (let ((name (buffer-name)) - (filename (buffer-file-name))) - (if (not (and filename (file-exists-p filename))) - (error "Buffer '%s' is not visiting a file!" name) - (let ((new-name (read-file-name "New name: " filename))) - (if (get-buffer new-name) - (error "A buffer named '%s' already exists!" new-name) - (rename-file filename new-name 1) - (rename-buffer new-name) - (set-visited-file-name new-name) - ; TODO: this is suspicious for me… - (set-buffer-modified-p nil) - (message "File '%s' successfully renamed to '%s'" - name (file-name-nondirectory new-name))))))) -#+END_SRC - -*** Delete the current file -:PROPERTIES: -:SOURCE: http://whattheemacsd.com/file-defuns.el-02.html -:END: - -#+BEGIN_SRC emacs-lisp -(defun delete-current-buffer-file () - "Remove file connected to current buffer and kill the buffer." - (interactive) - - (let ((filename (buffer-file-name)) - (name (buffer-name)) - (buffer (current-buffer))) - (if (not (and filename (file-exists-p filename))) - (kill-buffer buffer) - (when (yes-or-no-p "Are you sure you want to remove this file? ") - (delete-file filename) - (kill-buffer buffer) - (message "File '%s' successfully removed" filename))))) -#+END_SRC - ** Frame manipulation *** Hidden modeline mode @@ -618,274 +874,8 @@ To temporarily hide the mode line. "Use M-x hidden-mode-line-mode to make mode-line appear.")))) #+END_SRC -** Window manipulation - -*** Transpose windows - -#+BEGIN_SRC emacs-lisp -(defun transpose-windows (arg) - "Transpose the buffers shown in two windows." - (interactive "p") - (let ((selector (if (>= arg 0) 'next-window 'previous-window))) - (while (/= arg 0) - (let ((this-win (window-buffer)) - (next-win (window-buffer (funcall selector)))) - (set-window-buffer (selected-window) next-win) - (set-window-buffer (funcall selector) this-win) - (select-window (funcall selector))) - (setq arg (if (plusp arg) (1- arg) (1+ arg)))))) -#+END_SRC - -*** Toggle window split between horizontal and vertical - -#+BEGIN_SRC emacs-lisp -(defun toggle-window-split () - (interactive) - (if (= (count-windows) 2) - (let* ((this-win-buffer (window-buffer)) - (next-win-buffer (window-buffer (next-window))) - (this-win-edges (window-edges (selected-window))) - (next-win-edges (window-edges (next-window))) - (this-win-2nd (not (and (<= (car this-win-edges) - (car next-win-edges)) - (<= (cadr this-win-edges) - (cadr next-win-edges))))) - (splitter - (if (= (car this-win-edges) - (car (window-edges (next-window)))) - 'split-window-horizontally - 'split-window-vertically))) - (delete-other-windows) - (let ((first-win (selected-window))) - (funcall splitter) - (if this-win-2nd (other-window 1)) - (set-window-buffer (selected-window) this-win-buffer) - (set-window-buffer (next-window) next-win-buffer) - (select-window first-win) - (if this-win-2nd (other-window 1)))) - (error "This works only for two windows!"))) -#+END_SRC - -*** Scroll up or down in a specific window - -#+BEGIN_SRC emacs-lisp -(defun gpolonkai/scroll-window-up (window) - "Scroll WINDOW up as `scroll-up-command' would." - (interactive) - (save-selected-window - (select-window window) - (scroll-up))) - -(defun gpolonkai/scroll-window-down (window) - "Scroll WINDOW down as `scroll-down-command' would." - (interactive) - (save-selected-window - (select-window window) - (scroll-down))) -#+END_SRC - -*** Bury a window - -#+BEGIN_SRC emacs-lisp -(defun gpolonkai/bury-window (window) - "Quit WINDOW without killing it." - (interactive) - (quit-window nil window)) -#+END_SRC - -** ~c-mode~ related - -*** Copy the prototype of the current function - -#+BEGIN_SRC emacs-lisp -(defun gpolonkai/copy-func-prototype () - "Copy the current function's prototype to the kill ring." - - (interactive) - - (save-excursion - (beginning-of-defun) - (let ((protocopy-begin (point))) - (forward-list) - (let ((protocopy-end (point))) - (kill-ring-save protocopy-begin protocopy-end))))) -#+END_SRC - -** Programming related - -*** Add code references to Org documents -:PROPERTIES: -:SOURCE: http://www.howardism.org/Technical/Emacs/capturing-content.html -:END: - -#+BEGIN_SRC emacs-lisp -(defun ha/org-capture-fileref-snippet (f type headers func-name) - (let* ((code-snippet - (buffer-substring-no-properties (mark) (- (point) 1))) - (file-name (buffer-file-name)) - (file-base (file-name-nondirectory file-name)) - (line-number (line-number-at-pos (region-beginning))) - (initial-txt (if (null func-name) - (format "From [[file:%s::%s][%s]]:" - file-name line-number file-base) - (format "From ~%s~ (in [[file:%s::%s][%s]]):" - func-name file-name line-number - file-base)))) - (format " - %s - - ,#+BEGIN_%s %s -%s - ,#+END_%s" initial-txt type headers code-snippet type))) - -(defun ha/org-capture-clip-snippet (f) - "Given a file, F, this captures the currently selected text -within an Org EXAMPLE block and a backlink to the file." - (with-current-buffer (find-buffer-visiting f) - (ha/org-capture-fileref-snippet f "EXAMPLE" "" nil))) - -(defun ha/org-capture-code-snippet (f) - "Given a file, F, this captures the currently selected text -within an Org SRC block with a language based on the current mode -and a backlink to the function and the file." - (with-current-buffer (find-buffer-visiting f) - (let ((org-src-mode (replace-regexp-in-string "-mode" "" (format "%s" major-mode))) - (func-name (which-function))) - (ha/org-capture-fileref-snippet f "SRC" org-src-mode func-name)))) -#+END_SRC - -** Utility functions for EDiff -:PROPERTIES: -:SOURCE: http://article.gmane.org/gmane.emacs.orgmode/75222 -:END: - -EDiff and Org-mode files don’t play nice together… - -#+BEGIN_SRC emacs-lisp -(defun f-ediff-org-showhide (buf command &rest cmdargs) - "If buffer BUF exists and in `org-mode', execute COMMAND with CMDARGS." - (when buf - (when (eq (buffer-local-value 'major-mode (get-buffer buf)) 'org-mode) - (save-excursion - (set-buffer buf) - (apply command cmdargs))))) - -(defun f-ediff-org-unfold-tree-element () - "Unfold tree at diff location." - (f-ediff-org-showhide ediff-buffer-A 'org-reveal) - (f-ediff-org-showhide ediff-buffer-B 'org-reveal) - (f-ediff-org-showhide ediff-buffer-C 'org-reveal)) - -(defun f-ediff-org-fold-tree () - "Fold tree back to top level." - (f-ediff-org-showhide ediff-buffer-A 'hide-sublevels 1) - (f-ediff-org-showhide ediff-buffer-B 'hide-sublevels 1) - (f-ediff-org-showhide ediff-buffer-C 'hide-sublevels 1)) -#+END_SRC - -** Leave ~isearch~ at the other end of the matched string -:PROPERTIES: -:SOURCE: http://endlessparentheses.com/leave-the-cursor-at-start-of-match-after-isearch.html -:END: - -#+BEGIN_SRC emacs-lisp -(defun isearch-exit-other-end () - "Exit isearch, at the opposite end of the string." - (interactive) - - (isearch-exit) - (goto-char isearch-other-end)) -#+END_SRC - -** Mark the current match after leaving ~isearch~ -:PROPERTIES: -:SOURCE: http://emacs.stackexchange.com/a/31321/507 -:END: - -#+BEGIN_SRC emacs-lisp -(defun isearch-exit-mark-match () - "Exit isearch and mark the current match." - (interactive) - (isearch-exit) - (push-mark isearch-other-end) - (activate-mark)) -#+END_SRC - ** Org mode stuff -*** Filter out tasks from the Org agenda if they have a specific priority - -The whole idea comes from [[https://blog.aaronbieber.com/2016/09/24/an-agenda-for-life-with-org-mode.html][here]], which i use almost verbatim. This is also the reason it has the -~air-~ prefix. - -#+begin_src emacs-lisp -(defun air-org-skip-subtree-if-priority (priority) - "Skip an agenda subtree if it has a priority of PRIORITY. - -PRIORITY may be one of the characters ?A, ?B, or ?C." - (let ((subtree-end (save-excursion (org-end-of-subtree t))) - (pri-value (* 1000 (- org-lowest-priority priority))) - (pri-current (org-get-priority (thing-at-point 'line t)))) - (if (= pri-value pri-current) - subtree-end - nil))) -#+end_src - -*** Filter out habits from the Org agenda - -#+begin_src emacs-lisp -(defun air-org-skip-subtree-if-habit () - "Skip an agenda entry if it has a STYLE property equal to \"habit\"." - (let ((subtree-end (save-excursion (org-end-of-subtree t)))) - (if (string= (org-entry-get nil "STYLE") "habit") - subtree-end - nil))) -#+end_src - -*** Filter out entries from the Org agenda with a specific state - -#+begin_src emacs-lisp -(defun gpolonkai/org-skip-subtree-if-state (state) - "Skip an agenda entry if its state is STATE." - (let ((subtree-end (save-excursion (org-end-of-subtree t)))) - (if (string= (org-get-todo-state) state) - subtree-end - nil))) -#+end_src - -*** Wrapper around ~org-agenda~ to open my own custom list - -#+begin_src emacs-lisp -(defun gpolonkai/org-agenda-list (&optional arg) - (interactive "P") - (org-agenda arg "c")) -#+end_src - -*** Insert the current timestamp - -#+begin_src emacs-lisp -(defun gpolonkai/org-insert-current-timestamp (&optional arg) - "Insert the current timestamp" - (interactive "P") - (org-time-stamp '(16) arg)) -#+end_src - -*** Insert a heading with CREATED set to the current time - -This emulates how Orgzly work with my current settings. - -#+begin_src emacs-lisp -(defun gpolonkai/org-insert-heading-created (&optional arg) - (interactive "p") - (let* ((org-insert-heading-respect-content t) - (format-string (concat "[" (substring (cdr org-time-stamp-formats) 1 -1) "]")) - (timestamp (format-time-string format-string (current-time)))) - (if (> arg 1) - (org-insert-subheading '(4)) - (org-insert-heading)) - (org-set-property "CREATED" timestamp))) -#+end_src - *** Display horizontal rulers as a full-width line From [[https://matrix.to/#/@suckless_shill:matrix.org][viz]] in the [[https://matrix.to/#/#org-mode:matrix.org][org-mode]] Matrix room. @@ -1306,7 +1296,7 @@ The cookies are from the Hungarian version an ancient MS-DOS based program calle ** Browse URL functionality in Termux #+BEGIN_SRC emacs-lisp -(when (termux-p) +(when (gpolonkai/termux-p) (use-package browse-url :ensure nil :config @@ -1831,7 +1821,7 @@ For all your spell-checking needs. (use-package alert :config (setq alert-default-style - (if (termux-p) + (if (gpolonkai/termux-p) (progn ;; TODO Remove this as soon as my PR gets merged ;; https://github.com/jwiegley/alert/pull/41 @@ -2599,7 +2589,7 @@ This is a big one; I use a lot of customisation here. ("C" . org-capture) ("l" . org-store-link) :map org-mode-map - ("SPC" . org-space-key) + ("SPC" . gpolonkai/org-space-key) ("C-c l" . org-toggle-link-display) ("C-a" . gpolonkai/move-to-beginning-of-line) ("C-e" . gpolonkai/move-to-end-of-line) @@ -3090,8 +3080,8 @@ directory. It is available from [[http://plantuml.com/download][here]]. #+BEGIN_SRC emacs-lisp (bind-keys :map global-map - ("" . open-line-below) - ("" . open-line-above) + ("" . wted/open-line-below) + ("" . wted/open-line-above) ("M-t" . nil) ;; Remove the old keybinding ("M-t c" . transpose-chars) ("M-t w" . transpose-words) @@ -3099,31 +3089,31 @@ directory. It is available from [[http://plantuml.com/download][here]]. ("M-t e" . transpose-sexps) ("M-t s" . transpose-sentences) ("M-t p" . transpose-paragraphs) - ("M-t W" . transpose-windows) + ("M-t W" . gpolonkai/transpose-windows) ("C-a" . gpolonkai/move-to-beginning-of-line) ("C-e" . gpolonkai/move-to-end-of-line) ("M-q" . sachachua/fill-or-unfill-paragraph) - ("C-c r" . round-number-at-point-to-decimals) + ("C-c r" . gpolonkai/round-number-at-point-to-decimals) ("C-s" . consult-line) ("C-r" . gpolonkai/isearch-regexp) ("C-M-s" . isearch-forward) ("C-M-r" . isearch-backward) - ("C-~" . toggle-char-case) + ("C-~" . gpolonkai/toggle-char-case) ("C-z" . nil) - ("M-g SPC" . goto-next-char) + ("M-g SPC" . gpolonkai/goto-next-char) ("M-F" . gpolonkai/beginning-of-next-word) :map ctl-x-map ("C-y" . duplicate-line) ("_" . maximize-window) - ("C-r" . rename-current-buffer-file) - ("C-d" . delete-current-buffer-file) - ("|" . toggle-window-split) + ("C-r" . wted/rename-current-buffer-file) + ("C-d" . wted/delete-current-buffer-file) + ("|" . gpolonkai/toggle-window-split) ("k" . kill-this-buffer) ("C-b" . bury-buffer) ("/" . repeat) :map isearch-mode-map - ("" . isearch-exit-other-end) - ("" . isearch-exit-mark-match) + ("" . ep/isearch-exit-other-end) + ("" . e-se/isearch-exit-mark-match) :map gpolonkai/pers-map ("h" . hidden-mode-line-mode) ("C-i e" . "gergely@polonkai.eu") @@ -3135,7 +3125,7 @@ directory. It is available from [[http://plantuml.com/download][here]]. ("c I" . org-clock-in-last) ("c o" . org-clock-out) ("c g" . org-clock-goto) - ("M-o" . insert-current-file-name-at-point) + ("M-o" . mbork/insert-current-file-name-at-point) ("i" . string-inflection-all-cycle)) #+END_SRC