diff options
Diffstat (limited to 'modules/custom-line-paragraph.el')
| -rw-r--r-- | modules/custom-line-paragraph.el | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/modules/custom-line-paragraph.el b/modules/custom-line-paragraph.el new file mode 100644 index 00000000..334aa8d2 --- /dev/null +++ b/modules/custom-line-paragraph.el @@ -0,0 +1,127 @@ +;;; custom-line-paragraph.el --- -*- coding: utf-8; lexical-binding: t; -*- + +;;; Commentary: +;; + +;;; Code: + +(use-package expand-region + :demand t) ;; used w/in join paragraph + +(defun cj/join-line-or-region () + "Join lines in the active region or join the current line with the previous one." + (interactive) + (if (use-region-p) + (let ((beg (region-beginning)) + (end (copy-marker (region-end)))) + (goto-char beg) + (while (< (point) end) + (join-line 1)) + (goto-char end) + (newline)) + ;; No region - only join if there's a previous line + (when (> (line-number-at-pos) 1) + (join-line)) + (newline))) + +(defun cj/join-paragraph () + "Join all lines in the current paragraph using `cj/join-line-or-region'." + (interactive) + (er/mark-paragraph) ;; from package expand region + (cj/join-line-or-region (region-beginning)(region-end)) + (forward-line)) + +(defun cj/duplicate-line-or-region (&optional comment) + "Duplicate the current line or active region below. + +Comment the duplicated text when optional COMMENT is non-nil." + (interactive "P") + (let* ((b (if (region-active-p) (region-beginning) (line-beginning-position))) + (e (if (region-active-p) (region-end) (line-end-position))) + (lines (split-string (buffer-substring-no-properties b e) "\n"))) + (save-excursion + (goto-char e) + (dolist (line lines) + (open-line 1) + (forward-line 1) + (insert line) + ;; If the COMMENT prefix argument is non-nil, comment the inserted text + (when comment + (comment-region (line-beginning-position) (line-end-position))))))) + +(defun cj/remove-duplicate-lines-region-or-buffer () + "Remove duplicate lines in the region or buffer, keeping the first occurrence. + +Operate on the active region when one exists; otherwise operate on the whole buffer." + (interactive) + (let ((start (if (use-region-p) (region-beginning) (point-min))) + (end (if (use-region-p) (region-end) (point-max)))) + (save-excursion + (let ((end-marker (copy-marker end))) + (while + (progn + (goto-char start) + (re-search-forward "^\\(.*\\)\n\\(\\(.*\n\\)*\\)\\1\n" end-marker t)) + (replace-match "\\1\n\\2")))))) + + +(defun cj/remove-lines-containing (text) + "Remove all lines containing TEXT. + +If region is active, operate only on the region, otherwise on entire buffer. +The operation is undoable." + (interactive "sRemove lines containing: ") + (save-excursion + (save-restriction + (let ((region-active (use-region-p)) + (count 0)) + (when region-active + (narrow-to-region (region-beginning) (region-end))) + (goto-char (point-min)) + ;; Count lines before deletion + (while (re-search-forward (regexp-quote text) nil t) + (setq count (1+ count)) + (beginning-of-line) + (forward-line)) + ;; Go back and delete + (goto-char (point-min)) + (delete-matching-lines (regexp-quote text)) + ;; Report what was done + (message "Removed %d line%s containing '%s' from %s" + count + (if (= count 1) "" "s") + text + (if region-active "region" "buffer")))))) + +(defun cj/underscore-line () + "Underline the current line by inserting a row of characters below it. + +If the line is empty or contains only whitespace, abort with a message." + (interactive) + (let ((line (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))) + (if (string-match-p "^[[:space:]]*$" line) + (message "Line empty or only whitespace. Aborting.") + (let* ((char (read-char "Enter character for underlining: ")) + (len (save-excursion + (goto-char (line-end-position)) + (current-column)))) + (save-excursion + (end-of-line) + (insert "\n" (make-string len char))))))) + + +;; Line & paragraph operations prefix and keymap +(define-prefix-command 'cj/line-and-paragraph-map nil + "Keymap for line and paragraph manipulation.") +(define-key cj/custom-keymap "l" 'cj/line-and-paragraph-map) +(define-key cj/line-and-paragraph-map "j" 'cj/join-line-or-region) +(define-key cj/line-and-paragraph-map "J" 'cj/join-paragraph) +(define-key cj/line-and-paragraph-map "d" 'cj/duplicate-line-or-region) +(define-key cj/line-and-paragraph-map "R" 'cj/remove-duplicate-lines-region-or-buffer) +(define-key cj/line-and-paragraph-map "r" 'cj/remove-lines-containing) +(define-key cj/line-and-paragraph-map "u" 'cj/underscore-line) + +(provide 'custom-line-paragraph) +;;; custom-line-paragraph.el ends here. |
