Add `ChangeLog-2008' files to the distribution.
[bpt/guile.git] / emacs / multistring.el
CommitLineData
c694af80
MD
1;;; multistring.el --- editing multiline strings.
2
6e7d5622 3;; Copyright (C) 2000, 2006 Free Software Foundation, Inc.
c694af80
MD
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 2, or (at your option)
10;; any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs; see the file COPYING. If not, write to the
92205699
MV
19;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20;; Boston, MA 02110-1301, USA.
c694af80
MD
21
22;;; Author: Mikael Djurfeldt <djurfeldt@nada.kth.se>
23
24;;; Commentary:
25
26;; Commands for editing multiline ANSI C compatible string literals.
27
28;;; Code:
29
30(defun ms-ansify-string (arg)
31 "Convert a string literal spanning multiple lines into multiple literals.
32With no argument, convert the single string at point to multiple strings.
33With an argument, convert multiple strings to a single one.
34
35ANSI C doesn't allow a string literal to span multiple lines. This
36function makes editing of multiline strings easier.
37
38The programmer can edit a string spanning multiple lines and then use
39this function to convert it into multiple literals representing the
40original string through the ANSI C string concatenation feature:
41
42 \"A string consisting of
43 multiple
44 lines.\"
45
46is converted into
47
48 \"A string consisting of\n\"
49 \"multiple\n\"
50 \"lines\""
51 (interactive "*P")
52 (save-excursion
53 (let (beg end)
54 (save-restriction
55 (ms-narrow-canonicalize-ansi-c-string)
56 (if (not arg)
57 (ms-break-string))
58 (setq beg (point-min))
59 (setq end (point-max)))
60 (if (not arg)
61 (c-indent-region beg end)))))
62
63(defun ms-pack-region (from to &optional unpack-flag)
64 "Pack paragraphs into single lines and remove one newline after paragraphs.
65With no argument, do the conversion.
66With an argument, do the reverse.
67
68When doing the reverse conversion, \\[fill-region] is used to break up
69the text into multiple lines."
70 (interactive "*r\nP")
71 (save-excursion
72 (save-restriction
73 (narrow-to-region from to)
74 (if (not unpack-flag)
75 (ms-pack-buffer)
76 (ms-unpack-buffer)))))
77
78(defun ms-pack-ansify-string (arg)
79 "Pack text in a string literal and convert into multiple literals.
80With no argument, do the conversion.
81With an argument, do the reverse.
82
83This command has the combined effect of \\[ms-pack-region] and
84\\[ms-ansify-string]. It is typically used if you want to store
85entire paragraphs without newlines in an ANSI C literal, but want to
86split it into multiple literals in order for the program text to look
87sensible. Using the reverse command, you can \"unpack\" the text,
88edit it and repack the text using the forward conversion."
89 (interactive "*P")
90 (save-excursion
91 (let (beg end)
92 (save-restriction
93 (ms-narrow-canonicalize-ansi-c-string)
94 (if (not arg)
95 (ms-break-string " " "" "\\n")
96 (ms-unpack-buffer))
97 (setq beg (point-min))
98 (setq end (point-max)))
99 (if (not arg)
100 (c-indent-region beg end)))))
101
102(defun ms-pack-buffer ()
103 "Pack paragraphs into single lines and remove one newline after paragraphs."
104 (interactive "*")
105 (goto-char (point-min))
106 (skip-chars-forward "^\n")
107 (while (not (eobp))
108 (delete-char 1)
109 (skip-chars-forward "\n")
110 (skip-chars-forward "^\n")))
111
112(defun ms-unpack-buffer ()
113 "Break single lines into paragraphs and add an extra newline between each."
114 (interactive "*")
115 (goto-char (point-min))
116 (skip-chars-forward "^\n")
117 (while (not (eobp))
118 (insert ?\n)
119 (skip-chars-forward "\n")
120 (skip-chars-forward "^\n"))
121 (fill-region (point-min) (point-max) nil t))
122
123(defconst ms-whitespace " \t\n")
124(defconst ms-string-beginning "\"")
125(defconst ms-string-end "\\(\\\\*\\)\"")
126(defconst ms-quoted-newline "\\(\\\\*\\)\\(\\\\n\\)")
127
128(defun ms-in-string-p ()
129 (eq (c-in-literal) 'string))
130
131(defun ms-narrow-canonicalize-ansi-c-string ()
132 ;; Find and check reference point
133 (cond ((ms-in-string-p))
134 ((eq (char-after) ?\") (forward-char))
135 (t (error "Not in string.")))
136 (set-mark (point))
137 ;; Find beginning
138 (ms-beginning-of-string)
139 (let ((beg (point)))
140 ;; Extend string backwards
141 (while (ms-extend-backwards)
142 (setq beg (point)))
143 (goto-char (mark))
144 ;; Find end
145 (ms-end-of-string)
146 (let ((end (point)))
147 ;; Extend string forwards
148 (while (ms-extend-forwards)
149 (setq end (point)))
150 ;; Narrow
151 (narrow-to-region beg end)
152 ;; Convert \n into explicit newlines
153 (ms-convert-quoted-newlines))))
154
155(defun ms-beginning-of-string ()
156 (let ((pos (search-backward ms-string-beginning nil t)))
157 (while (and pos
158 (char-before)
159 (eq (char-before) ?\\))
160 (setq pos (search-backward ms-string-beginning nil t)))
161 (if pos
162 (progn
163 (forward-char)
164 (1+ pos)))))
165
166(defun ms-extend-backwards ()
167 (let ((end (point)))
168 (backward-char)
169 (skip-chars-backward ms-whitespace)
170 (if (eq (char-before) ?\")
171 (progn
172 (backward-char)
173 (delete-region (point) end)
174 (ms-beginning-of-string)))))
175
176(defun ms-end-of-string ()
177 (let ((pos (search-forward-regexp ms-string-end nil t)))
178 (while (and pos (= (logand (- (match-end 1) (match-beginning 1)) 1) 1))
179 (setq pos (search-forward-regexp ms-string-end nil t)))
180 (if pos
181 (progn
182 (backward-char)
183 (match-end 1)))))
184
185(defun ms-extend-forwards ()
186 (let ((start (point)))
187 (forward-char)
188 (skip-chars-forward ms-whitespace)
189 (if (eq (char-after) ?\")
190 (progn
191 (forward-char)
192 (delete-region start (point))
193 (ms-end-of-string)))))
194
195(defun ms-convert-quoted-newlines ()
196 (goto-char (point-min))
197 (while (search-forward-regexp ms-quoted-newline nil t)
198 (if (= (logand (- (match-end 1) (match-beginning 1)) 1) 0)
199 (replace-match "\n" nil t nil 2))))
200
201(defun ms-break-string (&optional single-term multi-term-1 multi-term-n)
202 (let ((single-term (or single-term "\\n"))
203 (multi-term-1 (or multi-term-1 "\\n"))
204 (multi-term-n (or multi-term-n "\\n")))
205 (goto-char (point-min))
206 (skip-chars-forward "^\n")
207 (while (not (eobp))
208 (delete-char 1)
209 (if (not (eq (char-after) ?\n))
210 (insert single-term)
211 (insert multi-term-1)
212 (while (eq (char-after) ?\n)
213 (delete-char 1)
214 (insert multi-term-n)))
215 (insert "\"\n\"")
216 (skip-chars-forward "^\n"))))
217
218(eval-after-load "cc-mode"
219 (progn
220 (define-key c-mode-base-map "\C-ca" 'ms-ansify-string)
221 (define-key c-mode-base-map "\C-cd" 'ms-pack-ansify-string)
222 ))