-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to improve argument visibility in terminal light themes? #466
Comments
Do you mean a single clink color theme that works with both light and dark backgrounds? It's only possible by completely avoiding the terminal theme colors for anything at all (CSI SGR params 0,30-37,39,40-47,49,90-97,100-107) and instead using fixed 8-bit or 24-bit color codes. Because everyone who is making light themes is making them in such a way that "bright/bold" is still bright in light themes, which produces opposite of the intended effect. Similar problems in how they do the 4 gray scale colors, and the default fore/back colors. I'm thinking about what can potentially be done in Clink to compensate. But terminal usage in general isn't really seamlessly compatible flipping between light/dark backgrounds without reconfiguring all customized colors individually. Even if Clink completely overrides the terminal theme, that will only compensate in Clink. Any other console mode programs that use The problem is broader than just Clink. |
Same as #256. |
I'm going to change the default colors in the "use enhanced defaults" case, so that all colors have sufficient contrast to be readable in both Light and Dark terminal color themes. However, there's no way for programs to reliably detect whether a terminal is using a Light or Dark color theme. In fact, when a program uses the console APIs to ask Windows Terminal about the color theme, Windows Terminal always reports that the colors are the original default OS black background color theme. There's no way to find out whether Windows Terminal is using a Light theme. There's also no way to find out whether it's using Acrylic background, or what background opacity is used, or what the "effective" background color is at any particular location in the terminal window. So, there's no way for Clink to automatically update its colors on the fly for Light or Dark themes. However, there are two caveats:
Sorry, this is just a fact of life when using terminals. For output to be fully readable in both Light and Dark themes then it's necessary to either not use colors, or to customize the colors specifically to fit the terminal theme you're using. All shells have similar problems with color customizations, including PowerShell and P.S. I recognize that it would be handy to be able to do something simple to select different Clink color settings for different terminal windows. I'm exploring options for that. I have a bunch of half-baked ideas, but I'm not sure yet what will really be possible or feasible (especially since it's impossible for it to be automatic). |
I cannot fix this properly in Clink until microsoft/terminal#10639 is fixed. However, once that's fixed then it becomes possible to make the |
One way to alleviate this problem would be a command to show me all the current color settings in their own colors. I'm using a light theme and sometimes the input color makes things illegible. It depends on which color is being used for the stuff I'm typing at the moment. To fix this right now, I have to figure out which setting I need to change and then fix it. The trouble is, there are many color settings at play and I keep running into "bad" ones as I'm trying to get work done. I'd like to be able to see all the color settings in their own colors so that I can fix any problem ones while I still have their goofy syntax in my head. As it stands, I never know if I have fixed all the settings that are causing me trouble. |
@bruceoberg I think you mean something like the sample script below, which creates a pseudo-command " I have some thoughts about some kind of "color themes" kind of thing for Clink. It's complicated because some colors are specified in the Readline init file ( It would be nice to have a wizard that shows each color setting, plus in-context samples for common ones, a way to modify/pick colors, and a way to save/load themes.
Do you mean that "bright write on blue" feels like goofy syntax? Sample script-- This installs a pseudo-command "CLINK_COLOR_TEST", which prints a color
-- sample for each Clink color setting. Each sample is shown with the
-- background color initially set to default, and initially set to white.
if not clink.onfilterinput then
print("color_test.lua requires a newer version of Clink; please upgrade.")
return
end
local function get_clink()
local clink_alias = os.getalias('clink')
if not clink_alias or clink_alias == '' then
return ''
end
return clink_alias:gsub(' $[*]', '')
end
local function maybe_prefix(color)
color = ";"..(color or "")..";"
color = color:gsub("^;0;", ";")
if not color:find(";[34]8;") then
color = color:gsub(";[34]9;", ";")
end
color = color:match("^;*(.-);*$")
if color ~= "" then
color = ";"..color
end
return color
end
local function show_color_sample(name)
local color = settings.get(name)
local sgrBlack = "\x1b[0;48;5;0" .. maybe_prefix(color) .. "m"
local sgrWhite = "\x1b[0;48;5;15" .. maybe_prefix(color) .. "m"
local sgrDefault = "\x1b[0" .. maybe_prefix(color) .. "m"
local sample = string.format("%s Abc %s xyZ \x1b[m %s gTi \x1b[m", sgrBlack, sgrWhite, sgrDefault)
clink.print(string.format("%32s %s %s", name, sample, color))
end
clink.onfilterinput(function (line)
if line == "CLINK_COLOR_TEST" then
print("\nCLINK COLOR SAMPLES:")
print(string.rep(" ", 32) .. " \x1b[4mBlack\x1b[m \x1b[4mWhite\x1b[m \x1b[4mDefault\x1b[m")
local alias = get_clink()
local r = io.popen(alias.." set --list")
for name in r:lines() do
if name:match("^color.") then
show_color_sample(name)
end
end
r:close()
print()
return ""
end
end) |
@bruceoberg For the next update, I've added color samples into the Also, you might like the following script. Run it using the undocumented For usage info and available flags, run: When run, the script prints a table of ANSI codes; see the first screen shot further below. The color codes are all 256-color codes, i.e. for use with ansi_colors.lua-- Shows ANSI 256-color codes and styles.
--
-- Usage:
-- clink lua ansi_colors.lua [options]
--
-- Options:
-- --bg Show background colors with contrasting foreground colors.
-- --fg Show foreground colors with default background (the default).
-- --black Show foreground colors with black background.
-- --white Show foreground colors with white background.
-- --dark Show foreground colors with black background.
-- --light Show foreground colors with white background.
-- --pretty Show pretty layout for 6x6x6 color cube.
-- --simple Show simple layout for 6x6x6 color cube (the default).
-- --help, -? Show help text.
if not clink then
print("This ansi_colors.lua script requires the standalone Clink Lua engine.")
return
elseif clink.argmatcher then
log.info("This ansi_colors.lua script cannot be loaded into an injected Clink instance; it belongs in a separate directory that doesn't get loaded when Clink is injected.")
return
end
local fg = true
local forcing_background
local pretty_cube = false
local contrast_strategy = 1
local norm = "\x1b[m"
local bold = "\x1b[1m"
local italic = "\x1b[3m"
local underline = "\x1b[4m"
local overline = "\x1b[53m"
local emphasis = "\x1b[36m"
local CSI = "\\x1b["
local param = "\x1b[33m"
for _, a in ipairs(arg) do
if a == "--bg" then
fg = false
elseif a == "--fg" then
fg = true
elseif a == "--black" or a == "--dark" then
fg = true
forcing_background = 0
elseif a == "--white" or a == "--light" then
fg = true
forcing_background = 15
elseif a == "--pretty" then
pretty_cube = true
elseif a == "--simple" then
pretty_cube = false
elseif a == "--help" or a == "-?" or a == "-h" or a == "help" then
print("Shows ANSI 256-color codes.")
print()
print("Usage:")
print(" clink lua ansi_colors.lua [options]")
print()
print("Options:")
print(" --bg Show background colors with contrasting foreground colors.")
print(" --fg Show foreground colors with default background (the default).")
print(" --black Show foreground colors with black background.")
print(" --white Show foreground colors with white background.")
print(" --dark Show foreground colors with black background.")
print(" --light Show foreground colors with white background.")
print(" --pretty Show pretty layout for 6x6x6 color cube.")
print(" --simple Show simple layout for 6x6x6 color cube (the default).")
print(" --help, -? Show help text.")
return
else
print("Unrecognized option '"..tostring(a).."'.")
return
end
end
local function in_range(num, lo, hi)
return num >= lo and num <= hi
end
local hi_ranges = {}
table.insert(hi_ranges, { 0, 7 })
if contrast_strategy == 1 then
for i = 0, 5 do
table.insert(hi_ranges, { 16 + i*36, 16 + i*36 + 17 })
end
elseif contrast_strategy == 2 then
table.insert(hi_ranges, { 16, 123 })
else
-- TODO: calculate luminance to choose contrast color.
end
table.insert(hi_ranges, { 232, 243 })
local contrast_table = {}
for _, r in ipairs(hi_ranges) do
for i = r[1], r[2] do
contrast_table[i] = true
end
end
local function contrast(num)
assert(num >= 0)
assert(num <= 255)
return contrast_table[num] and 15 or 0
end
local function make_sgr(num, addl)
local color
if fg then
color = string.format("%s;38;5;%d", addl or "", num)
if forcing_background then
color = color..string.format(";48;5;%d", forcing_background)
end
else
color = string.format("%s;48;5;%d;38;5;%d", addl or "", num, contrast(num))
end
return color
end
local function make_color(num, addl)
return "\x1b[0;"..make_sgr(num, addl).."m"
end
local function print_sample(num)
local sample = string.format("%s%3d %s", make_color(num), num, norm)
clink.print(sample, NONL)
end
local function center(text)
local width = 3*4*6 + 2
local len = console.cellcount(text)
clink.print(string.rep(" ", (width - len) / 2)..italic..text..norm)
end
print()
center("System colors:")
clink.print(" ", NONL)
for i = 0, 7 do
print_sample(i)
end
clink.print(" ", NONL)
for i = 8, 15 do
print_sample(i)
end
print("\n")
center("Color cube:")
if pretty_cube then
for i = 0, 5 do
for j = 0, 2 do
for k = 0, 5 do
print_sample(16 + i*6 + j*72 + k)
end
clink.print(" ", NONL)
end
print()
end
for i = 5, 0, -1 do
for j = 0, 2 do
for k = 0, 5 do
print_sample(52 + i*6 + j*72 + k)
end
clink.print(" ", NONL)
end
print()
end
else
for i = 0, 5 do
for j = 0, 2 do
for k = 0, 5 do
print_sample(16 + i*36 + j*6 + k)
end
clink.print(" ", NONL)
end
print()
end
for i = 0, 5 do
for j = 0, 2 do
for k = 0, 5 do
print_sample(34 + i*36 + j*6 + k)
end
clink.print(" ", NONL)
end
print()
end
end
print()
center("Grayscale ramp:")
clink.print(" ", NONL)
for i = 232, 243 do
print_sample(i)
end
print()
clink.print(" ", NONL)
for i = 244, 255 do
print_sample(i)
end
print()
print()
center("Styles:")
local styles = {
{ "1", "22", "Boldface" },
{ "3", "23", "Italics" },
{ "7", "27", "Reverse" },
{ "4", "24", "Underline" },
{ "53", "55", "Overline" },
}
local text = ""
local on = ""
local off = ""
for _, s in ipairs(styles) do
if text ~= "" then
text = text.." "
on = on.." "
off = off.." "
end
text = text.."\x1b[0;"..s[1].."m"..s[3]..norm
local fmt = string.format("%%%ds", #s[3]--[[ - 4]])
on = on..string.format(--[["on: "..]]fmt, s[1])
off = off..string.format(--[["off:"..]]fmt, s[2])
end
center(norm..text)
center(norm..on)
center(norm..off)
print() The script outputThe upcoming change to include color samples when displaying completions |
Thanks for all this @chrisant996. Your lua scripts look like what I want. I'll check them out tonight. I know And sorry about the goofy syntax snark. I was referring to the |
A help command would print documentation, and the documentation web page covers that. Documentation is static i.e. it doesn't dynamically report current settings. A help command isn't where something like current color samples would go. Maybe more like a status command to report various kinds of settings. But "current color samples" is just scratching the surface. I don't want to make a bunch of piecemeal separate enhancements that don't fit together well. That's why I'm taking a slower and more methodical approach to designing a solution for the broader area of "color themes".
I think you mean the gobbledygook that goes after the "sgr", right? The gobbledygook is just how ANSI escape codes work. That's just part of how terminals work. I didn't define that, and it's not actually part of Clink. 🙃 I agree they're not friendly, which is why Clink tries to allow simpler friendly color strings, unless you want to use fancy/sophisticated escape codes. To use fancy codes, Clink expects awareness of escape codes. There is a rough edge, though: the "enhanced defaults" set some fancy codes. And so when I think the best solution there is just education, but I'm open to other ideas. |
UpdateBased on the conversation in microsoft/terminal#16493, it seems the current view is "Light themes are always going to be broken [in terminals]". WhyVT terminal specifications were designed for CRT monitors, which had black backgrounds. The fairly recent interest in trying to make Light themes for terminals isn't compatible with the existing VT escape codes for colors and styles. While it's possible to change the default background color in a theme to be white, that breaks the VT color specifications such that it's impossible for apps to present text with readable contrast using the colors in the theme. And currently in Windows Terminal it's impossible for an app to detect whether a Light theme is being used (microsoft/terminal#10639), so an app can't even automatically adjust its colors based on the current theme. Even though Windows Terminal itself includes some Light themes, the current state of things means Light themes are really faking it, and apps cannot automatically coexist with a Light theme unless the app doesn't use any colors. OptionsSo, in order to support Light themes, there are really only two options:
This has always been an issue in Unix and Linux terminals. In Windows Terminal and ConPTY-based terminals it's a problem only until microsoft/terminal#10639 is fixed so that the ClinkIn the meantime, I'm working on a way to define / save / load colors themes for Clink. The main challenge is that colors are stored in the profile, and the same profile is shared by different terminal windows which may be using different background colors.
I'm exploring other options, and variations of the above options. |
Color themes are coming soon, packaged as "*.clinktheme" files for easy sharing and hot-swapping. Custom prompts packaged as "*.clinkprompt" files are also coming soon. The code for them is written. Now I'm just working on documentation, and beta testing to make sure things are working smoothly. Sample screen shot of some color theme stuffSample screen shot of switching between different custom prompts |
Color themes, added in 8bc5914, are the solution for the challenges with terminal light themes. |
The visibility is somewhat poor in light themes of Windows Terminal and JetBrain IDEs.
I know the text colors can be changed for each element in clink config file. But since I use both dark and light themes in different software, is there a way to make clink have good visibility for both light and dark terminal themes?
The text was updated successfully, but these errors were encountered: