editing-defuns.el 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. ;;; editing-defuns.el --- Basic text editing defuns -*- lexical-binding: t; -*-
  2. ;;; Code:
  3. (require 's)
  4. (defun open-line-below ()
  5. (interactive)
  6. (end-of-line)
  7. (newline)
  8. (indent-for-tab-command))
  9. (defun open-line-above ()
  10. (interactive)
  11. (beginning-of-line)
  12. (newline)
  13. (forward-line -1)
  14. (indent-for-tab-command))
  15. (defun smart-open-line ()
  16. "Insert an empty line after the current line.
  17. Position the cursor at its beginning, according to the current mode."
  18. (interactive)
  19. (move-end-of-line nil)
  20. (newline-and-indent))
  21. (defun smart-open-line-above ()
  22. "Insert an empty line above the current line.
  23. Position the cursor at it's beginning, according to the current mode."
  24. (interactive)
  25. (move-beginning-of-line nil)
  26. (newline-and-indent)
  27. (forward-line -1)
  28. (indent-according-to-mode))
  29. (defun new-line-in-between ()
  30. (interactive)
  31. (newline)
  32. (save-excursion
  33. (newline)
  34. (indent-for-tab-command))
  35. (indent-for-tab-command))
  36. (defun new-line-dwim ()
  37. (interactive)
  38. (let ((break-open-pair (or (and (looking-back "{" 1) (looking-at "}"))
  39. (and (looking-back ">" 1) (looking-at "<"))
  40. (and (looking-back "(" 1) (looking-at ")"))
  41. (and (looking-back "\\[" 1) (looking-at "\\]")))))
  42. (newline)
  43. (when break-open-pair
  44. (save-excursion
  45. (newline)
  46. (indent-for-tab-command)))
  47. (indent-for-tab-command)))
  48. (defun duplicate-current-line-or-region (arg)
  49. "Duplicates the current line or region ARG times.
  50. If there's no region, the current line will be duplicated."
  51. (interactive "p")
  52. (if (region-active-p)
  53. (let ((beg (region-beginning))
  54. (end (region-end)))
  55. (duplicate-region arg beg end)
  56. (one-shot-keybinding "d" (lambda () (duplicate-region 1 beg end))))
  57. (duplicate-current-line arg)
  58. (one-shot-keybinding "d" 'duplicate-current-line)))
  59. (defun one-shot-keybinding (key command)
  60. (set-temporary-overlay-map
  61. (let ((map (make-sparse-keymap)))
  62. (define-key map (kbd key) command)
  63. map) t))
  64. (defun replace-region-by (fn)
  65. (let* ((beg (region-beginning))
  66. (end (region-end))
  67. (contents (buffer-substring beg end)))
  68. (delete-region beg end)
  69. (insert (funcall fn contents))))
  70. (defun duplicate-region (&optional num start end)
  71. "Duplicates the region bounded by START and END NUM times.
  72. If no START and END is provided, the current region-beginning and
  73. region-end is used."
  74. (interactive "p")
  75. (save-excursion
  76. (let* ((start (or start (region-beginning)))
  77. (end (or end (region-end)))
  78. (region (buffer-substring start end)))
  79. (goto-char end)
  80. (dotimes (i num)
  81. (insert region)))))
  82. (defun duplicate-current-line (&optional num)
  83. "Duplicate the current line NUM times."
  84. (interactive "p")
  85. (save-excursion
  86. (when (eq (point-at-eol) (point-max))
  87. (goto-char (point-max))
  88. (newline)
  89. (forward-char -1))
  90. (duplicate-region num (point-at-bol) (1+ (point-at-eol)))))
  91. ;; automatically indenting yanked text if in programming-modes
  92. (require 'dash)
  93. (defvar yank-indent-modes '(prog-mode
  94. sgml-mode
  95. js2-mode)
  96. "Modes in which to indent regions that are yanked (or yank-popped)")
  97. (defvar yank-advised-indent-threshold 1000
  98. "Threshold (# chars) over which indentation does not automatically occur.")
  99. (defun yank-advised-indent-function (beg end)
  100. "Do indentation, as long as the region isn't too large."
  101. (if (<= (- end beg) yank-advised-indent-threshold)
  102. (indent-region beg end nil)))
  103. (defadvice yank (after yank-indent activate)
  104. "If current mode is one of 'yank-indent-modes, indent yanked text (with prefix arg don't indent)."
  105. (if (and (not (ad-get-arg 0))
  106. (--any? (derived-mode-p it) yank-indent-modes))
  107. (let ((transient-mark-mode nil))
  108. (yank-advised-indent-function (region-beginning) (region-end)))))
  109. (defadvice yank-pop (after yank-pop-indent activate)
  110. "If current mode is one of 'yank-indent-modes, indent yanked text (with prefix arg don't indent)."
  111. (if (and (not (ad-get-arg 0))
  112. (member major-mode yank-indent-modes))
  113. (let ((transient-mark-mode nil))
  114. (yank-advised-indent-function (region-beginning) (region-end)))))
  115. (defun yank-unindented ()
  116. (interactive)
  117. (yank 1))
  118. ;; toggle quotes
  119. (defun current-quotes-char ()
  120. (nth 3 (syntax-ppss)))
  121. (defalias 'point-is-in-string-p 'current-quotes-char)
  122. (defun move-point-forward-out-of-string ()
  123. (while (point-is-in-string-p) (forward-char)))
  124. (defun move-point-backward-out-of-string ()
  125. (while (point-is-in-string-p) (backward-char)))
  126. (defun alternate-quotes-char ()
  127. (if (eq ?' (current-quotes-char)) ?\" ?'))
  128. (defun toggle-quotes ()
  129. (interactive)
  130. (if (point-is-in-string-p)
  131. (let ((old-quotes (char-to-string (current-quotes-char)))
  132. (new-quotes (char-to-string (alternate-quotes-char)))
  133. (start (make-marker))
  134. (end (make-marker)))
  135. (save-excursion
  136. (move-point-forward-out-of-string)
  137. (backward-delete-char 1)
  138. (set-marker end (point))
  139. (insert new-quotes)
  140. (move-point-backward-out-of-string)
  141. (delete-char 1)
  142. (insert new-quotes)
  143. (set-marker start (point))
  144. (replace-string new-quotes (concat "\\" new-quotes) nil start end)
  145. (replace-string (concat "\\" old-quotes) old-quotes nil start end)))
  146. (error "Point isn't in a string")))
  147. ;; kill region if active, otherwise kill backward word
  148. (defun kill-region-or-backward-word ()
  149. (interactive)
  150. (if (region-active-p)
  151. (kill-region (region-beginning) (region-end))
  152. (backward-kill-word 1)))
  153. (defun kill-to-beginning-of-line ()
  154. (interactive)
  155. (kill-region (save-excursion (beginning-of-line) (point))
  156. (point)))
  157. ;; copy region if active
  158. ;; otherwise copy to end of current line
  159. ;; * with prefix, copy N whole lines
  160. (defun copy-to-end-of-line ()
  161. (interactive)
  162. (kill-ring-save (point)
  163. (line-end-position))
  164. (message "Copied to end of line"))
  165. (defun copy-line-or-region ()
  166. "Copy current line, or current text selection."
  167. (interactive)
  168. (if (region-active-p)
  169. (kill-ring-save (region-beginning) (region-end))
  170. (kill-ring-save (line-beginning-position) (line-beginning-position 2)) ) )
  171. (defun copy-whole-lines (arg)
  172. "Copy lines (as many as prefix argument) in the kill ring"
  173. (interactive "p")
  174. (kill-ring-save (line-beginning-position)
  175. (line-beginning-position (+ 1 arg)))
  176. (message "%d line%s copied" arg (if (= 1 arg) "" "s")))
  177. (defun copy-line (arg)
  178. "Copy to end of line, or as many lines as prefix argument"
  179. (interactive "P")
  180. (if (null arg)
  181. (copy-to-end-of-line)
  182. (copy-whole-lines (prefix-numeric-value arg))))
  183. (defun save-region-or-current-line (arg)
  184. (interactive "P")
  185. (if (region-active-p)
  186. (kill-ring-save (region-beginning) (region-end))
  187. (copy-line arg)))
  188. (defun kill-and-retry-line ()
  189. "Kill the entire current line and reposition point at indentation"
  190. (interactive)
  191. (back-to-indentation)
  192. (kill-line))
  193. (defun select-current-line ()
  194. "Select the current line"
  195. (interactive)
  196. (end-of-line) ; move to end of line
  197. (set-mark (line-beginning-position)))
  198. (defun camelize-buffer ()
  199. (interactive)
  200. (goto-char 0)
  201. (ignore-errors
  202. (replace-next-underscore-with-camel 0))
  203. (goto-char 0))
  204. (defun comment-or-uncomment-current-line ()
  205. (interactive)
  206. (comment-or-uncomment-region (line-beginning-position) (line-end-position)))
  207. (defun comment-dwim-line (&optional arg)
  208. "Replacement for the comment-dwim command.
  209. If no region is selected and current line is not blank and we are not at the end of the line,
  210. then comment current line.
  211. Replaces default behaviour of comment-dwim, when it inserts comment at the end of the line.
  212. From: http://www.emacswiki.org/emacs/CommentingCode"
  213. (interactive "*P")
  214. (comment-normalize-vars)
  215. (if (and (not (region-active-p)) (not (looking-at "[ \t]*$")))
  216. (comment-or-uncomment-region (line-beginning-position) (line-end-position))
  217. (comment-dwim arg)))
  218. (defun comment-kill-all ()
  219. "kill all comments in buffer"
  220. (interactive)
  221. (save-excursion
  222. (goto-char (point-min))
  223. (comment-kill (save-excursion
  224. (goto-char (point-max))
  225. (line-number-at-pos)))))
  226. (defun incs (s &optional num)
  227. (let* ((inc (or num 1))
  228. (new-number (number-to-string (+ inc (string-to-number s))))
  229. (zero-padded? (s-starts-with? "0" s)))
  230. (if zero-padded?
  231. (s-pad-left (length s) "0" new-number)
  232. new-number)))
  233. (defun change-number-at-point (arg)
  234. (interactive "p")
  235. (unless (or (looking-at "[0-9]")
  236. (looking-back "[0-9]"))
  237. (error "No number to change at point"))
  238. (save-excursion
  239. (while (looking-back "[0-9]")
  240. (forward-char -1))
  241. (re-search-forward "[0-9]+" nil)
  242. (replace-match (incs (match-string 0) arg) nil nil)))
  243. (defun subtract-number-at-point (arg)
  244. (interactive "p")
  245. (change-number-at-point (- arg)))
  246. (defun replace-next-underscore-with-camel (arg)
  247. (interactive "p")
  248. (if (> arg 0)
  249. (setq arg (1+ arg))) ; 1-based index to get eternal loop with 0
  250. (let ((case-fold-search nil))
  251. (while (not (= arg 1))
  252. (search-forward-regexp "\\b_[a-z]")
  253. (forward-char -2)
  254. (delete-char 1)
  255. (capitalize-word 1)
  256. (setq arg (1- arg)))))
  257. (defun snakeify-current-word ()
  258. (interactive)
  259. (er/mark-word)
  260. (let* ((beg (region-beginning))
  261. (end (region-end))
  262. (current-word (buffer-substring-no-properties beg end))
  263. (snakified (snake-case current-word)))
  264. (replace-string current-word snakified nil beg end)))
  265. (defun transpose-params ()
  266. "Presumes that params are in the form (p, p, p) or {p, p, p} or [p, p, p]"
  267. (interactive)
  268. (let* ((end-of-first (cond
  269. ((looking-at ", ") (point))
  270. ((and (looking-back ",") (looking-at " ")) (- (point) 1))
  271. ((looking-back ", ") (- (point) 2))
  272. (t (error "Place point between params to transpose."))))
  273. (start-of-first (save-excursion
  274. (goto-char end-of-first)
  275. (move-backward-out-of-param)
  276. (point)))
  277. (start-of-last (+ end-of-first 2))
  278. (end-of-last (save-excursion
  279. (goto-char start-of-last)
  280. (move-forward-out-of-param)
  281. (point))))
  282. (transpose-regions start-of-first end-of-first start-of-last end-of-last)))
  283. (defun move-forward-out-of-param ()
  284. (while (not (looking-at ")\\|, \\| ?}\\| ?\\]"))
  285. (cond
  286. ((point-is-in-string-p) (move-point-forward-out-of-string))
  287. ((looking-at "(\\|{\\|\\[") (forward-list))
  288. (t (forward-char)))))
  289. (defun move-backward-out-of-param ()
  290. (while (not (looking-back "(\\|, \\|{ ?\\|\\[ ?"))
  291. (cond
  292. ((point-is-in-string-p) (move-point-backward-out-of-string))
  293. ((looking-back ")\\|}\\|\\]") (backward-list))
  294. (t (backward-char)))))
  295. (autoload 'zap-up-to-char "misc"
  296. "Kill up to, but not including ARGth occurrence of CHAR.")
  297. (defun css-expand-statement ()
  298. (interactive)
  299. (save-excursion
  300. (end-of-line)
  301. (search-backward "{")
  302. (forward-char 1)
  303. (let ((beg (point)))
  304. (newline)
  305. (er/mark-inside-pairs)
  306. (replace-regexp ";" ";\n" nil (region-beginning) (region-end))
  307. (indent-region beg (point)))))
  308. (defun css-contract-statement ()
  309. (interactive)
  310. (end-of-line)
  311. (search-backward "{")
  312. (while (not (looking-at "}"))
  313. (join-line -1))
  314. (back-to-indentation))
  315. (provide 'editing-defuns)