# replace a text from emacs buffer to insert it vertically with emacs lisp script

I just found this post with vim (https://stackoverflow.com/questions/704130/can-i-transpose-a-file-in-vim) and i just wanted to do the same thing with elisp by creating a little script to reordenate all the characters from a buffer text into a vertical position.

As the post said, the original buffer might be:

THE DAY WAS LONG
THE WAY WAS FAST


and it would become:

TT
HH
EE

DW
AA
YY

WW
AA
SS

LF
OA
NS
GT


I write this little emacs script to first read each buffer lines in a list (removing spaces), and after using a zip function to transpose each characters between lists, and at the end iterate my list to print it in x columns.

(require 'subr-x)
(let ((lines '()))
(with-current-buffer buf
(save-excursion
(goto-char (point-min))
(while (not (eobp))
(if (not (string-equal "" (buffer-substring (point) (point-at-eol))))
(push
(delete " " (delete "" (split-string
(string-trim (buffer-substring (point) (point-at-eol)))
"")))
lines)
)
(beginning-of-line 2))
(erase-buffer) ;; clean buffer
(nreverse lines)
))))

(defun zip_list (lst)
(let ((res))
(while (-none? 'null lst)
(setq res (cons (mapcar 'car lst) res))
(setq lst (mapcar 'cdr lst)))
(nreverse res)
))

(let* ((buf "*scratch*")
(with-current-buffer buf
(while a
(progn
(insert (mapconcat 'identity (car a) ""))
(newline)
(setq a (cdr a))))))

• Why would you save excursion and erase buffer? :) Where would Emacs have to put the mouse after the buffer is erased? Other than that: there's an easier way to split the contents of the buffer into lines: (split-string (buffer-string) "\n"). I wouldn't use a list of list to model a matrix (which you want to transpose). A vector of vectors would've made the task a lot easier. – wvxvw Dec 4 '17 at 13:20
• agree. good point. – papachan Dec 4 '17 at 19:43

1. (while condition &body) form already treats &body as an implicit progn. There's no reason to wrap it in a progn.
2. insert accepts multiple arguments. So, you could write (insert (mapconcat ...) "\n") instead of calling (insert ...) followed by (newline).
3. Traditionally, Lisp functions use - when the name of the function consists of multiple words, so, it would be better to call zip-list, not zip_list.
4. (let (res) ...) is exactly the same as (let ((res)) ...) but shorter.
5. (setq ...) can handle multiple assignments, they are executed in order they are written, so (setq a b c a) will assign b to c. No reason to write (setq a b) (setq c a).
6. split-string has argument OMIT-NULLS that controls whether empty strings are included in the results. It would be better to rely on this argument than to post-process the results.
7. As mentioned in the comments, there's an easier, more idiomatic way to obtain all lines of text from the buffer: (split-string (buffer-string) "\n").

Finally, unless only for the sake of an exercise in writing the zip-list function, the transpose operation calls for something like vector, not a list. Below is a possible alternative which uses vectors to perform this operation:

(defun wvxvw/transpose-buffer ()
(interactive)
(let* ((lines (split-string (buffer-string) "\n"))
(max-length
(cl-loop for line in lines
maximize (max (length line))))
(src (cl-coerce lines 'vector))
(dst (cl-loop with matrix = (make-vector max-length nil)
with len = (length src)
for i below max-length do
(aset matrix i (make-vector len ?\ ))
finally (cl-return matrix))))
(cl-loop for i upfrom 0
for line across src do
(cl-loop for j upfrom 0
for c across line do
(aset (aref dst j) i c)))
(erase-buffer)
(cl-loop for line across dst do
(insert (cl-coerce line 'string) "\n"))))

• nice work ! i just tried it and it work like a charm ! thank you for all your suggestions. there are very useful for me. – papachan Dec 4 '17 at 19:43