13

In org it is possible to set a column width like follows:

|---+------------------------------|               |---+----------------| 
|   |                              |               |   | <14>           | 
| 1 | one                          |               | 1 | one            | 
| 2 | two                          |     ----\     | 2 | two            | 
| 3 | This is a long chunk of text |     ----/     | 3 | This is a lo=> | 
| 4 | four                         |               | 4 | four           | 
|---+------------------------------|               |---+----------------| 

I would like to obtain this layout instead:

|---+----------------|
|   | <14>           |
| 1 | one            |
| 2 | two            |
| 3 | This is a long |
|   | chunk of text  |
| 4 | four           |
|---+----------------|

Of course I can use M-S-<down> and M-<ret> to insert a new row and wrap the long field.
However, for many fields, this is inconvenient. Is there any hack or package to speed up this process?

NickD
  • 27,023
  • 3
  • 23
  • 42
antonio
  • 1,762
  • 12
  • 24
  • AFAIK It's not possible. You could try to request it on the org mailing list. I am not sure `org-table` would easily be amended, though. – rasmus Mar 22 '17 at 09:18

1 Answers1

9

I am new to the Org API and I would be glad if you could give a look to the code and share some comments.

As for the proposed solution, consider the following table:

|---+--------------------------------+---|
| 1 | one                            | a |
| 2 | two                            | b |
| 3 | This is a long chunk of text   | c |
| 4 | four                           | d |
| 5 | Yet another long chunk of text | e |
|---+--------------------------------+---|

Put the cursor anywhere in the second column and type:

M-x org-table-wrap-to-width

Enter a column width as requested. E.g., entering 15, you get:

|---+----------------+---|
| 1 | one            | a |
| 2 | two            | b |
| 3 | This is a long | c |
|   | chunk of text  |   |
| 4 | four           | d |
| 5 | Yet another    | e |
|   | long chunk of  |   |
|   | text           |   |
|---+----------------+---|

If you are dissatisfied with this width and want to try a different value, use the Emacs standard undo, which will restore the previous layout, so you can rerun the wrap function.

Here's the code. If you know Org, please, give feedback.

(defun org-table-wrap-to-width (width)
  "Wrap current column to WIDTH."
  (interactive (list (read-number "Enter column width: ")))
  (org-table-check-inside-data-field)
  (org-table-align)

  (let (cline (ccol (org-table-current-column)) new-row-count (more t))
    (org-table-goto-line 1)
    (org-table-goto-column ccol)

    (while more
      (setq cline (org-table-current-line))

      ;; Cut current field
      (org-table-copy-region (point) (point) 'cut)

      ;; Justify for width
      (setq org-table-clip 
            (mapcar 'list (org-wrap (caar org-table-clip) width nil)))

      ;; Add new lines and fill
      (setq new-row-count (1- (length org-table-clip)))
      (if (> new-row-count 0)
          (org-table-insert-n-row-below new-row-count)) 
      (org-table-goto-line cline)
      (org-table-goto-column ccol)
      (org-table-paste-rectangle)
      (org-table-goto-line (+ cline new-row-count))

      ;; Move to next line
      (setq more (org-table-goto-line (+ cline new-row-count 1)))
      (org-table-goto-column ccol))

    (org-table-goto-line 1)
    (org-table-goto-column ccol)))

(defun org-table-insert-n-row-below (n)
  "Insert N new lines below the current."
  (let* ((line (buffer-substring (point-at-bol) (point-at-eol)))
         (new (org-table-clean-line line)))
    ;; Fix the first field if necessary
    (if (string-match "^[ \t]*| *[#$] *|" line)
        (setq new (replace-match (match-string 0 line) t t new)))
    (beginning-of-line 2)
    (setq new
      (apply 'concat (make-list n (concat new "\n"))))
    (let (org-table-may-need-update) (insert-before-markers new))  ;;; remove? 
    (beginning-of-line 0)
    (re-search-forward "| ?" (point-at-eol) t)
    (and (or org-table-may-need-update org-table-overlay-coordinates) ;;; remove? 
         (org-table-align))
    (org-table-fix-formulas "@" nil (1- (org-table-current-dline)) n)))
antonio
  • 1,762
  • 12
  • 24
  • 2
    Interesting. I guess it should be noted though, that org-mode does not know the lines were wrapped, so, for example, sorting will most likely mess it all up. It still looks useful, e.g. to use before exporting. – Rolazaro Azeveires Mar 15 '17 at 23:39
  • 1
    @RolazaroAzeveires: It would be relatively easy to add a symbol like `"` to mark the begin/end of a field spanning multiple lines, in order to go back to the non wrapped version, manipulate, and re-wrap. I am not sure whether this should be a visible symbol (which would make the layout less polished) or an invisible one (which would make the table structure obfuscated). – antonio Mar 22 '17 at 11:35
  • Yes, that could be interesting. Emacs, and others, use some visible "curly arrow" symbols to show that there is line wrapping (there is probably some unicode character for that but I found none in a quick search) – Rolazaro Azeveires Mar 22 '17 at 22:35
  • 1
    What about using the [broken bar](https://en.wikipedia.org/wiki/Vertical_bar#Solid_vertical_bar_vs_broken_bar) in place of the vertical bar, `|`, to indicate when a row is wrapped? – Melioratus Oct 25 '17 at 23:12
  • @Melioratus Great choice. Maybe set as a variable `org-table-wrapped-boundary-char` or similar? Also would be nice to have the bars in alternate row differ by color. – Gavin Jun 21 '21 at 10:25