emacs-elpa-diffs
[Top][All Lists]
Advanced

[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:



reply via email to

[Prev in Thread] Current Thread [Next in Thread]