;;; syd-text.el -*- lexical-binding: t; -*- ;;;###autoload (defun syd-region-active-p () "Return non-nil if selection is active. Detects evil visual mode as well." (declare (side-effect-free t)) (or (use-region-p) (and (bound-and-true-p evil-local-mode) (evil-visual-state-p)))) ;;;###autoload (defun syd-region-beginning () "Return beginning position of selection. Uses `evil-visual-beginning' if available." (declare (side-effect-free t)) (or (and (bound-and-true-p evil-local-mode) (evil-visual-state-p) (markerp evil-visual-beginning) (marker-position evil-visual-beginning)) (region-beginning))) ;;;###autoload (defun syd-region-end () "Return end position of selection. Uses `evil-visual-end' if available." (declare (side-effect-free t)) (or (and (bound-and-true-p evil-local-mode) (evil-visual-state-p) (markerp evil-visual-end) (marker-position evil-visual-end)) (region-end))) ;;;###autoload (cl-defun syd-thing-at-point-or-region (&optional thing &key prompt) "Grab the current selection, THING at point, or xref identifier at point. Returns THING if it is a string. Otherwise, if nothing is found at point and PROMPT is non-nil, prompt for a string (if PROMPT is a string it'll be used as the prompting string). Returns nil if all else fails. NOTE: Don't use THING for grabbing symbol-at-point. The xref fallback is smarter in some cases." (declare (side-effect-free t)) (cond ((stringp thing) thing) ((syd-region-active-p) (buffer-substring-no-properties (syd-region-beginning) (syd-region-end))) (thing (thing-at-point thing t)) ((require 'xref nil t) ;; Eglot, nox (a fork of eglot), and elpy implementations for ;; `xref-backend-identifier-at-point' betray the documented purpose of ;; the interface. Eglot/nox return a hardcoded string and elpy ;; prepends the line number to the symbol. (let ((backend (xref-find-backend))) (if (memq backend '(eglot elpy nox)) (thing-at-point 'symbol t) ;; A little smarter than using `symbol-at-point', though in most ;; cases, xref ends up using `symbol-at-point' anyway. (if-let ((ident (xref-backend-identifier-at-point backend))) ;; REVIEW: `xref-backend-identifier' seems to have some special ;; uses of text properties. Are we sure we want to remove ;; them? (substring-no-properties ident))))) (prompt (read-string (if (stringp prompt) prompt ""))))) ;;;###autoload (defun syd-insert-newline-above (count) "Insert a blank line below the current line." (interactive "p") (dotimes (_ count) (let ((point-was-at-bol-p (= (current-column) 0))) (save-excursion (evil-insert-newline-above)) ;; Special case: with `syd-insert-newline-above' is called with point at ;; BOL, the point unexpectedly fails to "stick" to its original position. (when point-was-at-bol-p (next-line))))) ;;;###autoload (defun syd-insert-newline-below (count) "Insert a blank line below the current line." (interactive "p") (dotimes (_ count) (save-excursion (evil-insert-newline-below)))) ;;;###autoload (defun syd-render-ansi-escape-codes (beg end) (interactive "r") (require 'ansi-color) (if (region-active-p) (ansi-color-apply-on-region beg end) (ansi-color-apply-on-region (point-min) (point-max)))) (defun syd-evil-paste (before-p arg &optional register yank-handler) "Like `evil-paste-after', but a 'C-u' prefix argument will instead act like ':put' (i.e. the register will be pasted onto a new line)." (if (consp arg) (evil-ex-put (syd-region-beginning) (syd-region-end) ;; `evil-ex-put' wants a string, but it is immediately ;; converted back to a char. }xP (and register (string register)) before-p) (funcall (if before-p #'evil-paste-before #'evil-paste-after) arg register yank-handler))) ;;;###autoload (evil-define-command syd-evil-paste-after (arg &optional register yank-handler) "See `syd-evil-paste'.'" (interactive "P") (syd-evil-paste nil arg register yank-handler)) ;;;###autoload (evil-define-command syd-evil-paste-before (arg &optional register yank-handler) "See `syd-evil-paste'.'" (interactive "P") (syd-evil-paste t arg register yank-handler)) (provide 'syd-text)