The following code replaces newlines in quoted fields with the customizable string csv+-quoted-newline
in csv-mode-hook
.
It does the inverse replacement in write-contents-functions
.
Excerpt of the doc string of write-contents-functions
:
List of functions to be called before writing out a buffer to a file.
Only used by save-buffer'. If one of them returns non-nil, the
file is considered already written and the rest are not called
and neither are the functions in
write-file-functions'. This
hook can thus be used to create save behavior for buffers that
are not visiting a file at all.
This variable is meant to be used for hooks that pertain to the
buffer's contents, not to the particular visited file; thus,
`set-visited-file-name' does not clear this variable; but changing the
major mode does clear it.
(defcustom csv+-quoted-newline "\^@"
"Replace for newlines in quoted fields."
:group 'sv
:type 'string)
(defun csv+-quoted-newlines (&optional b e inv)
"Replace newlines in quoted fields of region B E by `csv+-quoted-newline'.
B and E default to `point-min' and `point-max', respectively.
If INV is non-nil replace quoted `csv+-quoted-newline' chars by newlines."
(interactive
(append (when (region-active-p)
(list (region-begin)
(region-end)))
prefix-arg))
(unless b (setq b (point-min)))
(unless e (setq e (point-max)))
(save-excursion
(goto-char b)
(let ((from (if inv csv+-quoted-newline "\n"))
(to (if inv "\n" csv+-quoted-newline)))
(while (search-forward from e t)
(when (nth 3 (save-excursion (syntax-ppss (1- (point)))))
(replace-match to))))))
(defsubst csv+-quoted-newlines-write-contents ()
"Inverse operation of `csv+-quoted-newlines' for the full buffer."
(save-excursion
(save-restriction
(widen)
(let ((file (buffer-file-name))
(contents (buffer-string)))
(with-temp-buffer
(insert contents)
(csv+-quoted-newlines (point-min) (point-max) t)
(write-region (point-min) (point-max) file)))))
(set-visited-file-modtime)
(set-buffer-modified-p nil)
t ;; File contents has been written (see `write-contents-functions').
)
(defun csv+-setup-quoted-newlines ()
"Hook function for `csv-mode-hook'.
Transform newlines in quoted fields to `csv+-quoted-newlines'
when reading files and the other way around when writing contents."
(add-hook 'write-contents-functions #'csv+-quoted-newlines-write-contents t t)
(let ((modified-p (buffer-modified-p)))
(csv+-quoted-newlines)
(set-buffer-modified-p modified-p)))
(add-hook 'csv-mode-hook #'csv+-setup-quoted-newlines)
Tested with Emacs 26.1, csv-mode 1.7 and the following csv-file:
11, 12, "Some
string", 14
21, 22, "Another
string", 24
31, 32, "And just another
string.", 34
41, 42, "And just another
string.", 44
Emacs displays the file after find-file
as follows:
11, 12, "Some^@string", 14
21, 22, "Another^@string", 24
31, 32, "And just another^@string.", 34
41, 42, "And just another^@string.", 44
Thereby, ^@
is the null character. You can input the null character by C-q C-@ to insert further newlines in quoted strings.