[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/valign e885f67 048/198: Merge branch 'markdown'
From: |
Stefan Monnier |
Subject: |
[elpa] externals/valign e885f67 048/198: Merge branch 'markdown' |
Date: |
Tue, 1 Dec 2020 18:19:14 -0500 (EST) |
branch: externals/valign
commit e885f67080757bb56b3a69f7d18a64d09c9acca6
Merge: fc4c812 da56833
Author: Yuan Fu <casouri@gmail.com>
Commit: Yuan Fu <casouri@gmail.com>
Merge branch 'markdown'
---
valign.el | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 183 insertions(+), 41 deletions(-)
diff --git a/valign.el b/valign.el
index fc8e7b8..bd434dc 100644
--- a/valign.el
+++ b/valign.el
@@ -40,11 +40,13 @@
(define-error 'valign-werid-alignment
"Valign expects one space between the cell’s content and either the left bar
or the right bar, but this cell seems to violate that assumption")
-(defun valign--cell-alignment ()
+(cl-defmethod valign--cell-alignment ((type (eql org-mode)) hint)
"Return how is current cell aligned.
Return 'left if aligned left, 'right if aligned right.
Assumes point is after the left bar (“|”).
-Doesn’t check if we are in a cell."
+Doesn’t check if we are in a cell.
+TYPE must be 'org-mode. HINT is not used."
+ (ignore type hint)
(save-excursion
(if (looking-at " [^ ]")
'left
@@ -55,6 +57,24 @@ Doesn’t check if we are in a cell."
'right
(signal 'valign-werid-alignment nil))))))
+(cl-defmethod valign--cell-alignment ((type (eql markdown-mode)) hint)
+ "Return how is current cell aligned.
+Return 'left if aligned left, 'right if aligned right.
+Assumes point is after the left bar (“|”).
+Doesn’t check if we are in a cell.
+TYPE must be 'markdown-mode. Simply return HINT."
+ (ignore type)
+ hint)
+
+(cl-defmethod valign--cell-alignment ((type (eql gfm-mode)) hint)
+ "Return how is current cell aligned.
+Return 'left if aligned left, 'right if aligned right.
+Assumes point is after the left bar (“|”).
+Doesn’t check if we are in a cell.
+TYPE must be 'markdown-mode. Simply return HINT."
+ (ignore type)
+ (valign--cell-alignment 'markdown-mode hint))
+
;; (if (string-match (rx (seq (* " ")
;; ;; e.g., “5.”, “5.4”
;; (or (seq (? (or "-" "+"))
@@ -194,8 +214,20 @@ But we don’t skip over chars with display property."
(defun valign--sperator-p ()
"If the current cell is actually a separator.
Assume point is after the left bar (“|”)."
- (and (eq (char-before) ?|)
- (eq (char-after) ?-)))
+ (or (eq (char-after) ?:) ;; Markdown tables.
+ (eq (char-after) ?-)))
+
+(defun valign--alignment-from-seperator ()
+ "Return the alignment of this column.
+Assumes point is after the left bar (“|”) of a separator
+cell. We don’t distinguish between left and center aligned."
+ (save-excursion
+ (if (eq (char-after) ?:)
+ 'left
+ (skip-chars-forward "-")
+ (if (eq (char-after) ?:)
+ 'right
+ 'left))))
(defmacro valign--do-table (column-idx-sym limit &rest body)
"Go to each cell of a table and evaluate BODY.
@@ -208,17 +240,29 @@ Don’t go over LIMIT."
(while (and (cl-incf ,column-idx-sym)
(search-forward "|" nil t)
(< (point) ,limit))
- (if (eq (char-after (point)) ?\n)
+ (if (looking-at "[^|]*\n")
;; We are after the last “|” of a line.
(setq ,column-idx-sym -1)
;; Point is after the left “|”.
(progn ,@body)))))
-(defun valign--calculate-column-width-list (limit)
+(cl-defstruct valign-table-info
+ "Information about the current table."
+ ;; Width of each column.
+ column-width-list
+ ;; Alignment of each column, can be either 'left or 'right, only
+ ;; used by markdown. (Technically we can determine the alignment
+ ;; from each cell’s padding spaces, but the widest cell in a
+ ;; right-aligned column has one space on both side, and we can’t
+ ;; determine the alignment for that cell.)
+ column-alignment-list)
+
+(defun valign--calculate-table-info (limit)
"Return a list of column widths.
Each column width is the largest cell width of the column.
Start from point, stop at LIMIT."
(let (column-width-alist
+ column-alignment-alist
column-idx)
(save-excursion
(valign--do-table column-idx limit
@@ -231,15 +275,24 @@ Start from point, stop at LIMIT."
(cell-width (valign--cell-width)))
(if (> cell-width (or oldmax 0))
(setf (alist-get column-idx column-width-alist)
- cell-width))))))
+ cell-width))))
+ ;; Calculate the alignment if we are on the separator row
+ ;; for markdown.
+ (when (valign--sperator-p)
+ (setf (alist-get column-idx column-alignment-alist)
+ (valign--alignment-from-seperator)))))
;; Turn alist into a list.
- (let ((inc 0) return-list)
+ (let ((inc 0) return-width-list return-alignment-list)
(while (alist-get inc column-width-alist)
;; Add 16 pixels of padding.
(push (+ (alist-get inc column-width-alist) 16)
- return-list)
+ return-width-list)
+ (push (alist-get inc column-alignment-alist)
+ return-alignment-list)
(cl-incf inc))
- (nreverse return-list))))
+ (make-valign-table-info
+ :column-width-list (reverse return-width-list)
+ :column-alignment-list (reverse return-alignment-list)))))
(defun valign--beginning-of-table ()
"Go backward to the beginning of the table at point.
@@ -330,12 +383,23 @@ Force align if FORCE non-nil."
(put-text-property beg (point) 'valign-init t))))
(cons 'jit-lock-bounds (cons beg end)))
-(defun valign--align-separator-row (total-width)
- "Align the separator row (|---+---|) as “| |”.
-Assumes the point is after the left bar (“|”). TOTAL-WIDTH is the
-pixel width counting from the left of the left bar to the left of
-the right bar."
- (let ((p (point)))
+(defun valign-always-align (beg end)
+ "Perform initial alignment for tables between BEG and END.
+Supposed to be called from jit-lock. Unlike
+`valign-initial-ailgnment', always realign."
+ (valign-initial-alignment beg end t))
+
+(cl-defmethod valign--align-separator-row
+ (type (style (eql single-column)) pos-list)
+ "Align the separator row (|---+---|) as “|---------|”.
+Assumes the point is after the left bar (“|”). TYPE can be
+either 'org-mode or 'markdown, it doesn’t make any difference.
+STYLE is 'single-column. POS-LIST is a list of each column’s
+right bar’s position."
+ (ignore type style)
+ (let ((p (point))
+ ;; Position of the right-most bar.
+ (total-width (car (last pos-list))))
(when (search-forward "|" nil t)
(with-silent-modifications
(valign--put-text-property p (1- (point)) total-width))
@@ -354,11 +418,20 @@ the right bar."
(defun valign--separator-row-add-overlay (beg end right-pos)
"Add overlay to a separator row’s “cell”.
Cell ranges from BEG to END, the pixel position RIGHT-POS marks
-the position for the right bar (“|”)."
+the position for the right bar (“|”).
+Assumes point is on the right bar or plus sign."
;; Make “+” look like “|”
(when (eq (char-after end) ?+)
(with-silent-modifications
(put-text-property end (1+ end) 'display "|")))
+ ;; Markdown row
+ (when (eq (char-after beg) ?:)
+ (setq beg (1+ beg)))
+ (when (eq (char-before end) ?:)
+ (setq end (1- end)
+ right-pos (- right-pos
+ (valign--glyph-width-at-point (1- end)))))
+ ;; End of Markdown
(valign--put-text-property beg end right-pos)
;; Why do we have to add an overlay? Because text property
;; doens’t work. First, font-lock overwrites what ever face
@@ -372,6 +445,49 @@ the position for the right bar (“|”)."
(overlay-put ov 'face '(:strike-through t))
(overlay-put ov 'valign t)))
+(cl-defmethod valign--align-separator-row
+ ((type (eql org-mode)) (style (eql multi-column)) pos-list)
+ "Align the separator row in multi column style.
+TYPE must be 'org-mode, STYLE is 'multi-column.
+POS-LIST is a list of positions for each column’s right bar."
+ (ignore type style)
+ (let ((p (point))
+ (col-idx 0))
+ (while (search-forward "+" (line-end-position) t)
+ (valign--separator-row-add-overlay
+ p (1- (point))
+ (or (nth col-idx pos-list) 0))
+ (cl-incf col-idx)
+ (setq p (point)))
+ ;; Last column
+ (when (search-forward "|" (line-end-position) t)
+ (valign--separator-row-add-overlay
+ p (1- (point))
+ (or (nth col-idx pos-list) 0)))))
+
+(cl-defmethod valign--align-separator-row
+ ((type (eql markdown-mode)) (style (eql multi-column)) pos-list)
+ "Align the separator row in multi column style.
+TYPE must be 'markdown-mode, STYLE is 'multi-column.
+POS-LIST is a list of positions for each column’s right bar."
+ (ignore type style)
+ (let ((p (point))
+ (col-idx 0))
+ (while (search-forward "|" (line-end-position) t)
+ (valign--separator-row-add-overlay
+ p (1- (point))
+ (or (nth col-idx pos-list) 0))
+ (cl-incf col-idx)
+ (setq p (point)))))
+
+(cl-defmethod valign--align-separator-row
+ ((type (eql gfm-mode)) (style (eql multi-column)) pos-list)
+ "Align the separator row in multi column style.
+TYPE must be 'gfm-mode, STYLE is 'multi-column.
+POS-LIST is a list of positions for each column’s right bar."
+ (ignore type)
+ (valign--align-separator-row 'markdown-mode style pos-list))
+
;;; Userland
(defcustom valign-separator-row-style 'multi-column
@@ -394,7 +510,8 @@ for the former, and 'multi-column for the latter."
(condition-case err
(save-excursion
(let (end column-width-list column-idx pos ssw bar-width
- separator-row-point-list rev-list right-point)
+ separator-row-point-list rev-list right-point
+ column-alignment-list info)
;; ‘separator-row-point-list’ marks the point for each
;; separator-row, so we can later come back and align them.
;; ‘rev-list’ is the reverse list of right positions of each
@@ -404,14 +521,18 @@ for the former, and 'multi-column for the latter."
(user-error "Not on a table"))
(setq end (point))
(valign--beginning-of-table)
+ (setq info (valign--calculate-table-info end))
(setq column-width-list
- (valign--calculate-column-width-list end))
+ (valign-table-info-column-width-list info)
+ column-alignment-list
+ (valign-table-info-column-alignment-list info))
;; Iterate each cell and apply tab stops.
(valign--do-table column-idx end
;; We don’t align the separator row yet, but will come
;; back to it.
(if (valign--sperator-p)
- (push (point) separator-row-point-list)
+ (when (eq column-idx 0)
+ (push (point) separator-row-point-list))
(save-excursion
;; Check there is a right bar.
(when (save-excursion
@@ -457,7 +578,9 @@ for the former, and 'multi-column for the latter."
(1+ tab-start) (point)
(+ pos col-width ssw))))
;; Align a left-aligned cell.
- (pcase (valign--cell-alignment)
+ (pcase (valign--cell-alignment
+ major-mode
+ (nth column-idx column-alignment-list))
('left (search-forward "|" nil t)
(backward-char)
(setq tab-end (point))
@@ -479,31 +602,25 @@ for the former, and 'multi-column for the latter."
;; After aligning all rows, align the separator row.
(dolist (row-point separator-row-point-list)
(goto-char row-point)
- (pcase valign-separator-row-style
- ('single-column
- (valign--align-separator-row (car rev-list)))
- ('multi-column
- (let ((p (point))
- (col-idx 0))
- (while (search-forward "+" (line-end-position) t)
- (valign--separator-row-add-overlay
- p (1- (point))
- (or (nth col-idx (reverse rev-list)) 0))
- (cl-incf col-idx)
- (setq p (point)))
- ;; Last column
- (when (search-forward "|" (line-end-position) t)
- (valign--separator-row-add-overlay
- p (1- (point))
- (or (nth col-idx (reverse rev-list)) 0)))))))))
+ (valign--align-separator-row major-mode
+ valign-separator-row-style
+ (reverse rev-list)))))
(valign-bad-cell (message (error-message-string err)))
(valign-werid-alignment (message (error-message-string err)))))
+;;; Mode intergration
+
(defun valign--org-mode-hook ()
"Valign hook function used by `org-mode'."
(jit-lock-register #'valign-initial-alignment))
+(defun valign--markdown-mode-hook ()
+ "Valign hook function used by `markdown-mode'."
+ ;; We want our hook run after other markdown fontifications,
+ ;; because they mess up our alignment (which is not cool).
+ (add-hook 'jit-lock-functions #'valign-always-align 98 t))
+
(defun valign--force-align-buffer (&rest _)
"Forcefully realign every table in the buffer."
(valign-initial-alignment (point-min) (point-max) t))
@@ -543,6 +660,8 @@ When they are fontified next time."
(when (overlay-get ov 'valign)
(delete-overlay ov)))))
+;;; Userland
+
(define-minor-mode valign-mode
"Visually align Org tables."
:global t
@@ -552,6 +671,7 @@ When they are fontified next time."
(if (and valign-mode window-system)
(progn
(add-hook 'org-mode-hook #'valign--org-mode-hook 90)
+ (add-hook 'markdown-mode-hook #'valign--markdown-mode-hook 90)
(add-hook 'org-agenda-finalize-hook #'valign--force-align-buffer)
(advice-add 'org-table-align :after #'valign-table)
(advice-add 'org-toggle-inline-images
@@ -560,13 +680,20 @@ When they are fontified next time."
:before #'valign--realign-on-refontification)
(advice-add 'visible-mode
:before #'valign--realign-on-refontification)
+ ;; account for hide-link, show-math, and hide markup
+ (advice-add 'markdown-reload-extensions
+ :before #'valign--realign-on-refontification)
+ (advice-add 'markdown-toggle-inline-images
+ :after #'valign--force-align-buffer)
+ (advice-add 'markdown-table-align :after #'valign-table)
(advice-add 'org-flag-region :before #'valign--org-flag-region-advice)
;; Force jit-lock to refontify (and thus realign) the buffer.
(dolist (buf (buffer-list))
;; If the buffer is visible, realign immediately, if not,
;; realign when it becomes visible.
(with-current-buffer buf
- (when (derived-mode-p 'org-mode)
+ (when (or (derived-mode-p 'org-mode)
+ (derived-mode-p 'markdown-mode))
(if (get-buffer-window buf t)
(with-selected-window (get-buffer-window buf t)
(valign-initial-alignment (point-min) (point-max) t))
@@ -574,20 +701,35 @@ When they are fontified next time."
(put-text-property
(point-min) (point-max) 'fontified nil)
(put-text-property
- (point-min) (point-max) 'valign-init nil)))))))
+ (point-min) (point-max) 'valign-init nil))))
+ (cond ((derived-mode-p 'org-mode)
+ (valign--org-mode-hook))
+ ((derived-mode-p 'markdown-mode)
+ (valign--markdown-mode-hook))))))
(remove-hook 'org-mode-hook #'valign--org-mode-hook)
+ (remove-hook 'markdown-mode-hook #'valign--markdown-mode-hook)
(remove-hook 'org-agenda-finalize-hook #'valign--force-align-buffer)
(advice-remove 'org-toggle-inline-images #'valign--force-align-buffer)
(advice-remove 'org-restart-font-lock #'valign--realign-on-refontification)
(advice-remove 'visible-mode #'valign--realign-on-refontification)
(advice-remove 'org-table-align #'valign-table)
+ (advice-remove 'markdown-table-align #'valign-table)
(advice-remove 'org-flag-region #'valign--org-flag-region-advice)
+ (advice-remove 'markdown-reload-extensions
+ #'valign--realign-on-refontification)
+ (advice-remove 'markdown-toggle-inline-images
+ #'valign--force-align-buffer)
(dolist (buf (buffer-list))
(with-current-buffer buf
- (when (derived-mode-p 'org-mode)
+ (when (or (derived-mode-p 'org-mode)
+ (derived-mode-p 'markdown-mode))
(valign-reset-buffer))))))
(provide 'valign)
;;; valign.el ends here
+
+;; Local Variables:
+;; sentence-end-double-space: t
+;; End:
- [elpa] externals/valign e555277 029/198: Add with-silent-modification, (continued)
- [elpa] externals/valign e555277 029/198: Add with-silent-modification, Stefan Monnier, 2020/12/01
- [elpa] externals/valign bdb56ce 032/198: Sync all org mode alignment state automatically, Stefan Monnier, 2020/12/01
- [elpa] externals/valign 3c70c15 034/198: * valign.el (valign-mode): Fix., Stefan Monnier, 2020/12/01
- [elpa] externals/valign 3752d53 036/198: Solve a bunch of edge cases, Stefan Monnier, 2020/12/01
- [elpa] externals/valign 5b9a086 038/198: Fix edge case, Stefan Monnier, 2020/12/01
- [elpa] externals/valign 8cfe0ca 039/198: * valign.el (valign-separator-row-style): Add choice definition., Stefan Monnier, 2020/12/01
- [elpa] externals/valign 927d82d 041/198: Support indented tables, Stefan Monnier, 2020/12/01
- [elpa] externals/valign 81de913 042/198: Property support tabs, Stefan Monnier, 2020/12/01
- [elpa] externals/valign db0c4d8 043/198: Add support for markdown tables, Stefan Monnier, 2020/12/01
- [elpa] externals/valign da56833 047/198: Always realign markdown tables, Stefan Monnier, 2020/12/01
- [elpa] externals/valign e885f67 048/198: Merge branch 'markdown',
Stefan Monnier <=
- [elpa] externals/valign cd7c17f 052/198: Fix infinite loop, Stefan Monnier, 2020/12/01
- [elpa] externals/valign 638f978 054/198: Fix infinite loop!!, Stefan Monnier, 2020/12/01
- [elpa] externals/valign 994a4dc 056/198: Advice outline, Stefan Monnier, 2020/12/01
- [elpa] externals/valign cf4f9c9 059/198: * valign.el (valign-initial-alignment): Check buffer visibility., Stefan Monnier, 2020/12/01
- [elpa] externals/valign cc53114 060/198: * valign.el (valign-initial-alignment): Fix., Stefan Monnier, 2020/12/01
- [elpa] externals/valign f2ccbd9 069/198: * README.org: Rarrange., Stefan Monnier, 2020/12/01
- [elpa] externals/valign 24ad00d 074/198: * valign.el (valign--cell-width): Includes extra spaces in cell width., Stefan Monnier, 2020/12/01
- [elpa] externals/valign 931d102 035/198: * valign.el (valign-mode): Always add jit-lock hook., Stefan Monnier, 2020/12/01
- [elpa] externals/valign 3a84705 062/198: Suppress some errors, Stefan Monnier, 2020/12/01
- [elpa] externals/valign 455cb2c 070/198: * valign.el (Version): Change to 1.0.0., Stefan Monnier, 2020/12/01