8

I use vc-mode to show information about the current VC state in my mode line, like this:

(setq mode-line-format '(… (vc-mode vc-mode) …))

However, I find the default format of vc-mode pretty verbose. Notably, it includes the name of the current VC backend, which is not particularly interesting to me—I usually know which VCS the current buffer as, and I don’t really use any VCS other than Git anyway.

How can I customize the appearance of vc-mode? Ideally, I’d hide the name of the backend, and show just the name of the current branch (or probably something similar to git describe).

Alternatively, if vc-mode can’t be customized, can I somehow get the current branch name from VC, for use in a custom (:eval …) construct?

3 Answers 3

6

How can I customize the appearance of vc-mode? Ideally, I’d hide the name of the backend, and show just the name of the current branch.

That's pretty much what smart-mode-line does. You can give it a try, or you can just copy the advice that it uses:

(defadvice vc-mode-line (after strip-backend () activate)
  (when (stringp vc-mode)
    (let ((noback (replace-regexp-in-string 
                   (format "^ %s" (vc-backend buffer-file-name))
                   " " vc-mode)))
      (setq vc-mode noback))))

Note that this is a streamlined version of it. You can find the full code for the advice here, which also applies different faces depending on the state of the branch.


As an alternative, here's an even more streamlined version that doesn't use an advice.

(setcdr (assq 'vc-mode mode-line-format)
        '((:eval (replace-regexp-in-string "^ Git" " " vc-mode))))
3
  • That would work—though I'd prefer to use an :eval construct instead of an advice—but it's not exactly what I'd call "customising". It's a dirty hack, isn't it? I'd treacly prefer a cleaner way…
    – user227
    Commented Apr 27, 2015 at 14:29
  • 1
    @lunaryorn Yes, it's a hack. vc-mode is not highly customizable in this aspect (that I can tell). I would prefer a cleaner way too. :-)
    – Malabarba
    Commented Apr 27, 2015 at 15:22
  • 2
    @lunaryorn I've edited the answer to use the :eval construct.
    – Malabarba
    Commented Apr 27, 2015 at 16:35
4

I was not happy with the default behavior either. I could never keep the vc info characters straight— ":" for edited, "@" for added, etc. You can feel free to use my method.

I defined several custom faces to display the statuses in various colors. Then I wrote a function to translate the default vc info into a string to insert into the mode line. Then I added a :eval line in my mode line definition to show it.

;; Define faces.

(defface my/mode:vc-added
  `(
     (  ((class color))
        (:background "#FFAA55"  :foreground "black")  )
     (  t
        (:weight bold :underline t)  )
   )
  "VC status tag face for files that have just been added to
version-control."
  :group 'MY/mode)

(defface my/mode:vc-edited
  `(
     (  ((class color))
        (:background "#F05B80"  :foreground "black")  )   ; "#F04040" maybe?
     (  t
        (:weight bold :underline t)  )
   )
  "VC status tag face for files that are under version control
but which have been edited."
  :group 'MY/mode)

(defface my/mode:vc-in-sync
  `(
     (  ((class color))
        (:background "#60CC60"  :foreground "black")  )
     (  t
        (:weight bold :underline t)  )
   )
  "VC status tag face for files that are under version control
and which are in sync with the respository."
  :group 'MY/mode)

(defface my/mode:vc-none
  `(
     (  ((class color))
        (:background "#70A0D0"  :foreground "black")  )
     (  t
        (:weight bold :underline t)  )
   )
  "VC status tag face for files that are not under version
control"
  :group 'MY/mode)

(defface my/mode:vc-unknown
  `(
     (  ((class color))
        (:background "#FF0000"  :foreground "white")  )
     (  t
        (:weight bold :underline t)  )
   )
  "VC status tag face for files whose version-control status
cannot be determined."
  :group 'MY/mode)

(defvar my-vc-mode-attrs
  '((""  . (" NoVC "  my/mode:vc-none))
    ("-" . (" VC = "  my/mode:vc-in-sync))
    (":" . (" VC > "  my/mode:vc-edited))
    ("@" . (" VC + "  my/mode:vc-added))
    ("?" . (" ?VC? "  my/mode:vc-unknown))
    )
  "Lookup table to translate vc-mode character into another string/face."
)


;; This function helps me understand the version-control status.
(defun my-mode-line-vc-info ()
  "Return version-control status information about the file in
the current buffer, as a fontified string.

The mode-line variable `vc-mode' is nil if the file is not under
version control, and displays a hyphen or a colon depending on whether
the file has been modified since check-in.  I can never keep those
straight.

This function returns \"NoVC\" if the file is not under version 
control.  It displays a string with an = sign if the file is in sync
with its version control, and a string with a > sign if the file has
been modified since its last check-in."
  (let* ((class
          (cond
           ;; If not under version-control
           ((not vc-mode)
            "")

           ;; If under version-control decode the -:@ character
           ((string-match "\\` ?\\(?:CVS\\|Git\\)\\([-:@]\\)\\([^^:~ \x00-\x1F\\\\/]+\\)?" vc-mode)
            (match-string-no-properties 1 vc-mode))

           ;; Otherwise, indicate confusion
           (t
            "?")
           ))

         (branch
          (if (any class '("-" ":" "@"))
              (concat " " (match-string-no-properties 2 vc-mode))
            ""))

         ;; Fetch properties list for the class character above
         (props (cdr (assoc class my-vc-mode-attrs)))
         )

    (concat (propertize (car props) 'face (cadr props))
            branch)))

(set-default 'mode-line-format
   '(
     ...
        (:eval (my-mode-line-vc-info))
     ...))
2
  • Thanks. This looks like something I really need to copy into my own configuration :)
    – user227
    Commented Apr 28, 2015 at 9:43
  • where can I get the function any?
    – MonLau
    Commented Dec 17, 2019 at 13:08
3

I don't use anything else than GIT as well so i have this advice specific to vc-git

(advice-add #'vc-git-mode-line-string :filter-return #'my-replace-git-status)
(defun my-replace-git-status (tstr)
  (let* ((tstr (replace-regexp-in-string "Git" "" tstr))
         (first-char (substring tstr 0 1))
         (rest-chars (substring tstr 1)))
    (cond
     ((string= ":" first-char) ;;; Modified
      (replace-regexp-in-string "^:" "⚡️" tstr))
     ((string= "-" first-char) ;; No change
      (replace-regexp-in-string "^-" "✔️" tstr))
     (t tstr))))

This would simply look like this to me in my mode-line (I use an emacs distro that supports OSX emojis) :

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.