How to determine a terminal's background color?

后端 未结 5 525
余生分开走
余生分开走 2020-12-09 03:56

I\'d like to know if there is any way to determine a terminal\'s background color ?

In my case, using gnome-terminal.
It might matter, since it\'s entirety up to

5条回答
  •  猫巷女王i
    2020-12-09 04:41

    Some links:

    • Xterm escape code:
      • http://www.talisman.org/~erlkonig/documents/xterm-color-queries/
      • https://invisible-island.net/xterm/ctlseqs/ctlseqs.html (dynamic colors / Request Termcap/Terminfo String)
      • http://thrysoee.dk/xtermcontrol/ (xtermcontrol --get-bg)
      • https://gist.github.com/blueyed/c8470c2aad3381c33ea3
      • https://github.com/rocky/bash-term-background/blob/master/term-background.sh
    • COLORFGBG environment variable (used by Rxvt but not many others...):
      It is set to sth like :[:], (: is optional), and if in {0,1,2,3,4,5,6,8}, then we have some dark background.
    • Vim:
      • code: https://github.com/vim/vim/blob/05c00c038bc16e862e17f9e5c8d5a72af6cf7788/src/option.c#L3974
      • How does Vim guess background color on xterm?
    • Emacs... (background-mode) (I think it uses the escape code)
    • Related questions / reports / discussions:
      • Is there a way to determine a terminal's background color?
      • How does Vim guess background color on xterm?
      • https://unix.stackexchange.com/questions/245378/common-environment-variable-to-set-dark-or-light-terminal-background
      • https://bugzilla.gnome.org/show_bug.cgi?id=733423
      • https://github.com/neovim/neovim/issues/2764

    E.g. some related snippet from Neovim issue 2764:

    /*
     * Return "dark" or "light" depending on the kind of terminal.
     * This is just guessing!  Recognized are:
     * "linux"         Linux console
     * "screen.linux"   Linux console with screen
     * "cygwin"        Cygwin shell
     * "putty"         Putty program
     * We also check the COLORFGBG environment variable, which is set by
     * rxvt and derivatives. This variable contains either two or three
     * values separated by semicolons; we want the last value in either
     * case. If this value is 0-6 or 8, our background is dark.
     */
    static char_u *term_bg_default(void)
    {
      char_u      *p;
    
      if (STRCMP(T_NAME, "linux") == 0
          || STRCMP(T_NAME, "screen.linux") == 0
          || STRCMP(T_NAME, "cygwin") == 0
          || STRCMP(T_NAME, "putty") == 0
          || ((p = (char_u *)os_getenv("COLORFGBG")) != NULL
              && (p = vim_strrchr(p, ';')) != NULL
              && ((p[1] >= '0' && p[1] <= '6') || p[1] == '8')
              && p[2] == NUL))
        return (char_u *)"dark";
      return (char_u *)"light";
    }
    

    About COLORFGBG env, from Gnome BugZilla 733423:

    Out of quite a few terminals I've just tried on linux, only urxvt and konsole set it (the ones that don't: xterm, st, terminology, pterm). Konsole and Urxvt use different syntax and semantics, i.e. for me konsole sets it to "0;15" (even though I use the "Black on Light Yellow" color scheme - so why not "default" instead of "15"?), whereas my urxvt sets it to "0;default;15" (it's actually black on white - but why three fields?). So in neither of these two does the value match your specification.

    This is some own code I'm using (via):

    def is_dark_terminal_background():
        """
        :return: Whether we have a dark Terminal background color, or None if unknown.
            We currently just check the env var COLORFGBG,
            which some terminals define like ":",
            and if  in {0,1,2,3,4,5,6,8}, then we have some dark background.
            There are many other complex heuristics we could do here, which work in some cases but not in others.
            See e.g. `here `__.
            But instead of adding more heuristics, we think that explicitly setting COLORFGBG would be the best thing,
            in case it's not like you want it.
        :rtype: bool|None
        """
        if os.environ.get("COLORFGBG", None):
            parts = os.environ["COLORFGBG"].split(";")
            try:
                last_number = int(parts[-1])
                if 0 <= last_number <= 6 or last_number == 8:
                    return True
                else:
                    return False
            except ValueError:  # not an integer?
                pass
        return None  # unknown (and bool(None) == False, i.e. expect light by default)
    

提交回复
热议问题