Function: csv-align-fields

csv-align-fields is an interactive and natively compiled function defined in csv-mode.el.

Signature

(csv-align-fields HARD BEG END)

Documentation

Align all the fields in the region to form columns.

The alignment style is specified by csv-align-style. The number of spaces specified by csv-align-padding appears after each separator. Use soft alignment done by displaying virtual white space after the separators unless invoked with an argument, in which case insert real space characters into the buffer after the separators. Unalign first (see csv-unalign-fields). Ignore blank and comment lines.

In hard-aligned records, separators become invisible whenever buffer-invisibility-spec is non-nil. In soft-aligned records, make separators invisible if and only if buffer-invisibility-spec is non-nil when the records are aligned; this can be changed only by re-aligning. (Unaligning always makes separators visible.)

When called non-interactively, use hard alignment if HARD is non-nil; BEG and END specify the region to align. If there is no selected region, default to the whole buffer.

Key Bindings

csv-mode-map C-c C-a

Source Code

;; Defined in /nix/store/3gmjnyw9n226b7k7jamikx980vf8267p-emacs-packages-deps/share/emacs/site-lisp/elpa/csv-mode-1.27/csv-mode.el
(defun csv-align-fields (hard beg end)
  "Align all the fields in the region to form columns.
The alignment style is specified by `csv-align-style'.  The number of
spaces specified by `csv-align-padding' appears after each separator.
Use soft alignment done by displaying virtual white space after the
separators unless invoked with an argument, in which case insert real
space characters into the buffer after the separators.
Unalign first (see `csv-unalign-fields').  Ignore blank and comment lines.

In hard-aligned records, separators become invisible whenever
`buffer-invisibility-spec' is non-nil.  In soft-aligned records, make
separators invisible if and only if `buffer-invisibility-spec' is
non-nil when the records are aligned; this can be changed only by
re-aligning.  \(Unaligning always makes separators visible.)

When called non-interactively, use hard alignment if HARD is non-nil;
BEG and END specify the region to align.
If there is no selected region, default to the whole buffer."
  (interactive (cons current-prefix-arg
                     (if (use-region-p)
                         (list (region-beginning) (region-end))
                       (list (point-min) (point-max)))))
  ;; FIXME: Use csv--jit-align when applicable!
  (setq end (copy-marker end))
  (csv-unalign-fields hard beg end) ; If hard then barfs if buffer read only.
  (save-excursion
    (pcase-let ((`(,column-widths ,field-widths) (csv--column-widths beg end)))
      (save-restriction
        (narrow-to-region beg end)
        (set-marker end nil)

	;; Align fields:
	(goto-char (point-min))
	(while (not (eobp))		; for each record...
	  (unless (csv-not-looking-at-record)
            (let ((w column-widths)
                  (column 0))    ;Desired position of left-side of this column.
              (while (and w (not (eolp)))
                (let* ((beg (point))
                       (align-padding (if (bolp) 0 csv-align-padding))
                       (left-padding 0) (right-padding 0)
                       (field-width (pop field-widths))
                       (column-width (car (pop w)))
                       (x (- column-width field-width))) ; Required padding.
                  (csv-end-of-field)
                  (set-marker end (point)) ; End of current field.
                  ;; beg = beginning of current field
                  ;; end = (point) = end of current field

                  ;; Compute required padding:
                  (cond
                   ((eq csv-align-style 'left)
                    ;; Left align -- pad on the right:
                    (setq left-padding align-padding
                          right-padding x))
                   ((eq csv-align-style 'right)
                    ;; Right align -- pad on the left:
                    (setq left-padding (+ align-padding x)))
                   ((eq csv-align-style 'auto)
                    ;; Auto align -- left align text, right align numbers:
                    (if (string-match "\\`[-+.[:digit:]]+\\'"
                                      (buffer-substring beg (point)))
                        ;; Right align -- pad on the left:
                        (setq left-padding (+ align-padding x))
                      ;; Left align -- pad on the right:
                      (setq left-padding align-padding
                            right-padding x)))
                   ((eq csv-align-style 'centre)
                    ;; Centre -- pad on both left and right:
                    (let ((y (/ x 2)))  ; truncated integer quotient
                      (setq left-padding (+ align-padding y)
                            right-padding (- x y)))))

                  (cond
                   (hard ;; Hard alignment...
                    (when (> left-padding 0) ; Pad on the left.
                      ;; Insert spaces before field:
                      (if (= beg end)   ; null field
                          (insert (make-string left-padding ?\ ))
                        (goto-char beg) ; beginning of current field
                        (insert (make-string left-padding ?\ ))
                        (goto-char end))) ; end of current field
                    (unless (eolp)
                      (if (> right-padding 0) ; pad on the right
                          ;; Insert spaces after field:
                          (insert (make-string right-padding ?\ )))
                      ;; Make separator (potentially) invisible;
                      ;; in Emacs 21.3, neighbouring overlays
                      ;; conflict, so use the following only
                      ;; with hard alignment:
		      (csv--make-overlay (point) (1+ (point)) nil t nil
					 '(invisible csv evaporate t))
                      (forward-char)))  ; skip separator

                   ;; Soft alignment...
                   ((or (memq 'csv buffer-invisibility-spec)
                        ;; For TSV, hidden or not doesn't make much difference,
                        ;; but the behavior is slightly better when we "hide"
                        ;; the TABs with a `display' property than if we add
                        ;; before/after-strings.
                        (tsv--mode-p))

                    ;; Hide separators...
                    ;; Merge right-padding from previous field
                    ;; with left-padding from this field:
                    (if (zerop column)
                        (when (> left-padding 0)
                          ;; Display spaces before first field
                          ;; by overlaying first character:
			  (csv--make-overlay
			   beg (1+ beg) nil nil nil
			   `(before-string ,(make-string left-padding ?\ ))))
                      ;; Display separator as spaces:
                      (with-silent-modifications
                        (put-text-property
                         (1- beg) beg
                         'display `(space :align-to
                                          ,(+ left-padding column)))))
                    (unless (eolp) (forward-char)) ; Skip separator.
                    (setq column (+ column column-width align-padding)))

                   (t ;; Do not hide separators...
                    (let ((overlay (csv--make-overlay beg (point) nil nil t)))
                      (when (> left-padding 0) ; Pad on the left.
                        ;; Display spaces before field:
                        (overlay-put overlay 'before-string
                                     (make-string left-padding ?\ )))
                      (unless (eolp)
                        (if (> right-padding 0) ; Pad on the right.
                            ;; Display spaces after field:
                            (overlay-put
                             overlay
                             'after-string (make-string right-padding ?\ )))
                        (forward-char)))) ; Skip separator.

                   )))))
	  (forward-line)))))
  (set-marker end nil))