-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmove-lines.el
138 lines (118 loc) · 4.83 KB
/
move-lines.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
;;https://raw.githubusercontent.com/targzeta/move-lines/master/move-lines.el
;;; move-lines.el --- move current line or lines surrounding region up or down
;; Copyright (C) 2014 Emanuele Tomasi <[email protected]>
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;; This file is NOT part of GNU Emacs.
;; Author: Emanuele Tomasi <[email protected]>
;; Version: 1.0
;; URL: https://gist.github.com/4170263
;; Maintainer: Emanuele Tomasi <[email protected]>
;; Keywords: convenience
;;; Commentary;
;; There are two entry points: `move-lines-up' moves the text up and
;; `move-lines-down' that moves the text down.
;;
;; Copy this file in a directory which is in the Emacs `load-path'. Then,
;; execute the following code either directly or in your .emacs file:
;;
;; (require 'move-lines)
;; (move-lines-binding)
;;
;; Now, you can move the line(s) up by M-p or M-<up> or down by M-n or
;; M-<down>.
;;; Code:
(defun move-lines--internal (n)
(let* ((start (point)) ;; The position of beginning of line of the first line
(end start) ;; The position of eol+\n of the end line
col-init ;; The current column for the first line
(col-end (current-column)) ;; The current column for the end line
exchange_pm ;; If I had exchanged point and mark
delete-latest-newline) ;; If I had inserted a newline at the end
;; STEP 1: Identifying the line(s) to cut.
;; ---
;; If region is actives, I ensure that point always is at the end of the
;; region and mark at the beginning.
(when (region-active-p)
(when (< (point) (mark))
(setq exchange_pm t)
(exchange-point-and-mark))
(setq start (mark)
end (point)
col-end (current-column)))
(goto-char start) (setq col-init (current-column))
(beginning-of-line) (setq start (point))
(goto-char end) (end-of-line)
;; If point == point-max, this buffers doesn't have the trailing newline.
;; In this case I have to insert a newline otherwise the following
;; `forward-char' (to keep the "\n") will fail.
(when (= (point) (point-max))
(setq delete-latest-newline t)
(insert-char ?\n) (forward-char -1))
(forward-char 1) (setq end (point))
;; STEP 2: Moving the lines.
;; ---
;; The region I'm cutting span from the beginning of line of the current
;; line (or current region) to the end of line + 1 (newline) of the current
;; line (or current region).
(let ((line-text (delete-and-extract-region start end)))
(forward-line n)
;; If the current-column != 0, I have moved the region at the bottom of a
;; buffer doesn't have the trailing newline.
(when (not (= (current-column) 0))
(insert-char ?\n)
(setq delete-latest-newline t))
(setq start (+ (point) col-init)) ;; Now, start is the start of new region
(insert line-text))
;; STEP 3: Restoring
;; ---
;; I'm at the end of new region (or line) and start has setted at the
;; beginning of new region (if a region is active).
;; Restoring the end column.
(forward-line -1)
(forward-char col-end)
(when delete-latest-newline
(save-excursion
(goto-char (point-max))
(delete-char -1)))
(when (region-active-p)
(setq deactivate-mark nil)
(set-mark start)
(if exchange_pm
(exchange-point-and-mark)))))
;;;###autoload
(defun move-lines-up (n)
"Moves the current line or, if region is actives, the lines surrounding
region, up by N lines, or 1 line if N is nil."
(interactive "p")
(if (eq n nil)
(setq n 1))
(move-lines--internal (- n)))
;;;###autoload
(defun move-lines-down (n)
"Moves the current line or, if region is actives, the lines surrounding
region, down by N lines, or 1 line if N is nil."
(interactive "p")
(if (eq n nil)
(setq n 1))
(move-lines--internal n))
;;;###autoload
(defun move-lines-binding ()
"Sets the default key binding for moving lines. M-p or M-<up> for moving up
and M-n or M-<down> for moving down."
(global-set-key (kbd "M-p") 'move-lines-up)
(global-set-key (kbd "M-<up>") 'move-lines-up)
(global-set-key (kbd "M-n") 'move-lines-down)
(global-set-key (kbd "M-<down>") 'move-lines-down))
(provide 'move-lines)
;; move-lines.el ends here