Skip to content

Instantly share code, notes, and snippets.

@clemera
Created February 9, 2019 13:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clemera/9c27bc8a003ef404182bf8d0f7bc00a0 to your computer and use it in GitHub Desktop.
Save clemera/9c27bc8a003ef404182bf8d0f7bc00a0 to your computer and use it in GitHub Desktop.
Display git info in dired
;; dired git info
(with-eval-after-load 'dired
(define-key dired-mode-map ")" 'dgi-toggle-git-info))
(defvar dgi-commit-ovs nil)
(defvar dgi-commit-message-format "--pretty=%s (%cr)"
"The placeholders are (git-log PRETTY FORMATS):
· %H: commit hash
· %h: abbreviated commit hash
· %T: tree hash
· %t: abbreviated tree hash
· %P: parent hashes
· %p: abbreviated parent hashes
· %an: author name
· %aN: author name (respecting .mailmap, see git-shortlog(1) or
git-blame(1))
· %ae: author email
· %aE: author email (respecting .mailmap, see git-shortlog(1) or
git-blame(1))
· %ad: author date (format respects --date= option)
· %aD: author date, RFC2822 style
· %ar: author date, relative
· %at: author date, UNIX timestamp
· %ai: author date, ISO 8601-like format
· %aI: author date, strict ISO 8601 format
· %cn: committer name
· %cN: committer name (respecting .mailmap, see git-shortlog(1) or
git- blame(1))
· %ce: committer email
· %cE: committer email (respecting .mailmap, see git-shortlog(1) or
git- blame(1))
· %cd: committer date (format respects --date= option)
· %cD: committer date, RFC2822 style
· %cr: committer date, relative
· %ct: committer date, UNIX timestamp
· %ci: committer date, ISO 8601-like format
· %cI: committer date, strict ISO 8601 format
· %d: ref names, like the --decorate option of git-log(1)
· %D: ref names without the\" (\", \")\" wrapping.
· %e: encoding
· %s: subject
· %f: sanitized subject line, suitable for a filename
· %b: body
· %B: raw body (unwrapped subject and body)
· %N: commit notes
· %GG: raw verification message from GPG for a signed commit
· %G?: show \"G\" for a good (valid) signature, \"B\" for
a bad signature, \"U\" for a good signature with
unknown validity, \"X\" for a good signature that
has expired, \"Y\" for a good signature made by an
expired key, \"R\" for a good signature made by a
revoked key, \"E\" if the signature cannot be
checked (e.g. missing key) and \"N\" for no
signature
· %GS: show the name of the signer for a signed commit
· %GK: show the key used to sign a signed commit
· %gD: reflog selector, e.g., refs/stash@{1} or
refs/stash@{2 minutes ago}; the format follows the
rules described for the -g option. The portion
before the @ is the refname as given on the
command line (so git log -g refs/heads/master
would yield refs/heads/master@{0}).
· %gd: shortened reflog selector; same as %gD, but the
refname portion is shortened for human
readability (so refs/heads/master becomes just
master).
· %gn: reflog identity name
· %gN: reflog identity name (respecting .mailmap, see
git-shortlog(1) or git- blame(1))
· %ge: reflog identity email
· %gE: reflog identity email (respecting .mailmap, see
git-shortlog(1) or git- blame(1))
· %gs: reflog subject
· %Cred: switch color to red
· %Cgreen: switch color to green
· %Cblue: switch color to blue
· %Creset: reset color
· %C(...): color specification, as described under
Values in the \"CONFIGURATION FILE\" section of
git-config(1). By default, colors are shown only
when enabled for log output (by color.diff,
color.ui, or --color, and respecting the auto
settings of the former if we are going to a
terminal). %C(auto,...) is accepted as a
historical synonym for the default (e.g.,
%C(auto,red)). Specifying %C(always,...) will show
the colors even when color is not otherwise
enabled (though consider just using
`--color=always to enable color for the whole
output, including this format and anything else
git might color). auto alone (i.e. %C(auto)) will
turn on auto coloring on the next placeholders
until the color is switched again.
· %m: left (<), right (>) or boundary (-) mark
· %n: newline
· %%: a raw %
· %x00: print a byte from a hex code
· %w([<w>[,<i1>[,<i2>]]]): switch line wrapping, like the -w option of git-
shortlog(1).
· %<(<N>[,trunc|ltrunc|mtrunc]): make the next
placeholder take at least N columns, padding
spaces on the right if necessary. Optionally
truncate at the beginning (ltrunc), the
middle (mtrunc) or the end (trunc) if the output
is longer than N columns. Note that truncating
only works correctly with N >= 2.
· %<|(<N>): make the next placeholder take at least
until Nth columns, padding spaces on the right if
necessary
· %>(<N>), %>|(<N>): similar to %<(<N>), %<|(<N>)
respectively, but padding spaces on the left
· %>>(<N>), %>>|(<N>): similar to %>(<N>), %>|(<N>)
respectively, except that if the next placeholder
takes more spaces than given and there are spaces
on its left, use those spaces
· %><(<N>), %><|(<N>): similar to %<(<N>), %<|(<N>)
respectively, but padding both sides (i.e. the
text is centered)
· %(trailers[:options]): display the trailers of the
body as interpreted by git-interpret-trailers(1).
The trailers string may be followed by a colon and
zero or more comma-separated options. If the only
option is given, omit non-trailer lines from the
trailer block. If the unfold option is given,
behave as if interpret-trailer’s --unfold option
was given. E.g., %(trailers:only,unfold) to do
both.
Note Some placeholders may depend on other options
given to the revision traversal engine. For example,
the %g* reflog options will insert an empty string
unless we are traversing reflog entries (e.g., by git
log -g). The %d and %D placeholders will use
the \"short\" decoration format if --decorate was not
already provided on the command line.
If you add a + (plus sign) after % of a placeholder, a
line-feed is inserted immediately before the expansion if
and only if the placeholder expands to a non-empty string.
If you add a - (minus sign) after % of a placeholder, all
consecutive line-feeds immediately preceding the expansion
are deleted if and only if the placeholder expands to an
empty string.
If you add a ` ` (space) after % of a placeholder, a space
is inserted immediately before the expansion if and only
if the placeholder expands to a non-empty string.")
(defface dgi-commit-message-face
'((t (:inherit font-lock-comment-face)))
"Face for commit message info")
(defun dgi-command-to-string (program &rest args)
"Execute PROGRAM with arguments ARGS and return its output as a string."
(with-output-to-string
(with-current-buffer standard-output
(apply #'process-file program nil t nil args))))
(defun dgi-get-commit-info (&optional file gitf)
"Get commit message info.
FILE default to current dired file. GITF determines the commit
info format and defaults to `dgi-commit-message-format'."
(when (locate-dominating-file "." ".git")
(let* ((file (or file (dired-get-file-for-visit)))
(lfile (and file
;; get the actual displayed name, to make it work with
;; dired collapse
(save-excursion
(dired-goto-file file)
(buffer-substring (point) (line-end-position))))))
(when lfile
(unless (and (string-match "\\`\\.\\." lfile)
(not (locate-dominating-file ".." ".git")))
(let ((msg (dgi-command-to-string
"git" "log" "-1" (or gitf dgi-commit-message-format)
lfile)))
(when (and msg
(not (string= "" msg)))
(substring msg
;; skip newline
0 -1))))))))
(defmacro dgi-save-marked (&rest body)
"Execute BODY with marks toggled."
`(let ((marked (save-excursion
(goto-char (point-min))
(dired-get-marked-files))))
(save-excursion
(unwind-protect
(progn ,@body)
(dired-unmark-all-marks)
(dolist (file marked)
(dired-goto-file file)
(dired-mark 1))))))
(defun dgi-toggle-git-info ()
"Toggle git message info in current dired buffer."
(interactive)
(if dgi-commit-ovs
(dgi-cleanup)
(let* ((files (dgi-save-marked
(dired-unmark-all-marks)
(dired-toggle-marks)
(sort (dired-get-marked-files)
(lambda (a b)
(> (length (file-name-nondirectory a))
(length (file-name-nondirectory b)))))))
(minspc (1+ (length (file-name-nondirectory (car files))))))
(save-excursion
(dolist (file files)
(let ((msg (dgi-get-commit-info file)))
(when msg
(let ((spc (make-string
(- minspc (length (file-name-nondirectory file))) ?\s)))
(dired-goto-file file)
(goto-char (line-end-position))
(let ((ov (make-overlay (1- (point)) (point)))
(ovs (concat (format "%c" (char-before))
spc
(propertize msg 'face 'dgi-commit-message-face))))
(push ov dgi-commit-ovs)
;; I don't use after-string because I didn't get it to work
;; in combination with hl-line-mode overlay
(overlay-put ov 'display ovs)
;; hl line mode should have priority
(overlay-put ov 'priority -60))))))))))
(defun dgi-cleanup ()
(dolist (ov dgi-commit-ovs)
(delete-overlay ov))
(setq dgi-commit-ovs nil))
@yisraeldov
Copy link

This is probably enough to be its own package.

@clemera
Copy link
Author

clemera commented Mar 18, 2019

@yisraeldov It's available as a package here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment