An open API service indexing awesome lists of open source software.

https://github.com/dnouri/markdown-table-wrap

Emacs package to word-wrap GFM pipe tables to fit a given character width
https://github.com/dnouri/markdown-table-wrap

Last synced: 2 months ago
JSON representation

Emacs package to word-wrap GFM pipe tables to fit a given character width

Awesome Lists containing this project

README

          

#+title: markdown-table-wrap
#+author: Daniel Nouri

#+html: MELPA
#+html: Tests
#+html: melpazoid

Word-wrap GFM (GitHub Flavored Markdown) pipe tables to fit a
given character width. Inline markup survives wrapping.

#+begin_example
| Feature | Status | Notes |
|-----------|--------|-------------------------------|
| **Auth** | Done | OAuth2 with `refresh tokens` |
| **DB** | WIP | PostgreSQL *connection pool* |
#+end_example

=(markdown-table-wrap table-string 36)= rewrites this as:

#+begin_example
| Feature | Status | Notes |
| -------- | ------ | ------------ |
| **Auth** | Done | OAuth2 with |
| | | `refresh` |
| | | `tokens` |
| | | |
| **DB** | WIP | PostgreSQL |
| | | *connection* |
| | | *pool* |
#+end_example

The wrapped text is meant for readable source editing and
round-tripping with =markdown-table-wrap-unwrap=. It is not a
semantic no-op for Markdown renderers: wrapped headers are no
longer valid GFM tables, and wrapped body continuation lines and
automatic spacer rows are parsed as additional rows. Bold,
italic, code, links, images, and strikethrough markers are
duplicated on each continuation line. In buffers where
=markdown-hide-markup= conceals syntax characters, column widths
can be measured from visible text so that hidden markers do not
waste space.

* Installation

Install from [[https://melpa.org/#/markdown-table-wrap][MELPA]]:

#+begin_src
M-x package-install RET markdown-table-wrap RET
#+end_src

If MELPA is not configured yet, add this to your init file, restart
Emacs, and run =M-x package-refresh-contents= once:

#+begin_src elisp
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
#+end_src

If you use the library from your own code, load it with:

#+begin_src elisp
(require 'markdown-table-wrap)
#+end_src

If you prefer =use-package=:

#+begin_src elisp
(use-package markdown-table-wrap
:ensure t)
#+end_src

** Manual installation

If you prefer a plain checkout, add the repository to your =load-path=
and require the library:

#+begin_src elisp
(add-to-list 'load-path "/path/to/markdown-table-wrap")
(require 'markdown-table-wrap)
#+end_src

* Usage

#+begin_src elisp
(markdown-table-wrap table-text 60)
#+end_src

Optional arguments:

#+begin_src elisp
;; Cap cell height at 3 lines (truncated cells end with "…")
(markdown-table-wrap table-text 60 3)

;; Measure widths from visible text only (for markdown-hide-markup)
(markdown-table-wrap table-text 60 nil t)

;; Suppress automatic empty rows between wrapped data rows
(markdown-table-wrap table-text 60 nil nil t)
#+end_src

** Unwrapping and re-wrapping

Wrapped output is optimized for readable source, not for preserving
exact GFM table semantics in Markdown-to-HTML renderers.

#+begin_src elisp
(markdown-table-wrap
(markdown-table-wrap-unwrap previously-wrapped) new-width)
#+end_src

** Batch rendering

Parse and measure once, render at each width:

#+begin_src elisp
(markdown-table-wrap-batch table-text '(40 60 80 120))
#+end_src

** Integration example

#+begin_src elisp
(defun my-wrap-table-at-point ()
"Wrap the pipe table at point to fit the window."
(interactive)
(save-excursion
(let* ((beg (progn (re-search-backward "^|" nil t)
(line-beginning-position)))
(end (progn (re-search-forward "^[^|]" nil t)
(line-beginning-position)))
(text (buffer-substring-no-properties beg (1- end)))
(wrapped (markdown-table-wrap
text (window-width)
nil ; max cell height
markdown-hide-markup))) ; t when markup hidden
(unless (equal wrapped text)
(delete-region beg (1- end))
(goto-char beg)
(insert wrapped)))))
#+end_src

* Features

- Markup-aware: bold, italic, links, code, images, strikethrough
- Graceful degradation when columns are too narrow for markup
- Proportional column-width allocation
- Alignment preservation (=:---:=, =---:=, =:---=)
- Cell height cap with ellipsis
- Unwrap/re-wrap for resizing; batch rendering
- Code fence awareness
- Unicode-aware (CJK, combining marks, VS16 emoji)
- Pure Elisp, no dependencies

* API

** Primary functions

- ~(markdown-table-wrap TEXT WIDTH &optional MAX-CELL-HEIGHT STRIP-MARKUP COMPACT)~

Rewrite a pipe table to fit WIDTH. Returns pipe-table-shaped text
for readable source editing and round-tripping with
=markdown-table-wrap-unwrap=, or TEXT unchanged when it already
fits. Wrapped headers are no longer valid GFM tables, and wrapped
body continuation lines and automatic spacer rows are parsed as
additional rows by Markdown renderers. STRIP-MARKUP measures
widths from visible text (for =markdown-hide-markup=). COMPACT
suppresses automatic empty rows between wrapped data rows.

- ~(markdown-table-wrap-batch TEXT WIDTHS &optional MAX-CELL-HEIGHT STRIP-MARKUP COMPACT)~

Render at each width in WIDTHS. Parses once.

- ~(markdown-table-wrap-unwrap TEXT)~

Merge continuation rows back into logical rows when their
boundaries remain detectable. Best suited for text known to be
produced by =markdown-table-wrap=.

The package also exposes =markdown-table-wrap-parse=,
=markdown-table-wrap-cell=, =markdown-table-wrap-compute-widths=,
=markdown-table-wrap-strip-markup=, =markdown-table-wrap-visible-width=,
and =markdown-table-wrap-inside-code-fence-p=. See their docstrings
for details.

All public functions are pure (except =inside-code-fence-p=). No
=defcustom= is defined; configuration is passed as arguments.

* License

GPL-3.0-or-later