GithubHelp home page GithubHelp logo

Comments (12)

rktjmp avatar rktjmp commented on June 3, 2024

How do you imagine the API would look?

I think I want to keep all color operations in "chain format", so the API feels consistent, so it's probably:

Search { bg = Normal.bg.ro(10), fg = Normal.bg.do_it(maybe_some_strength_var?) }
-- invert? readable?  make_look_good? flip? shift?

I don't think invert is really an accurate name and readable might not make sense if applied to bg, maybe it's ok.


We actually do something similar to colorize, picking white or black fg, but it's just used for colorising hsl(...) calls when using :Lushify. It's somewhat naive, just checking the bg lightness > 50 and flipping:

fg = bg.l > 50 and fg.lightness(0) or fg.lightness(100)

It could be shifted into hsl's core pretty easily.

It also shouldn't be hard to extend that to step and check a few colors instead of just black or white. At least that's how I understand the bootstrap version working:

Given BG = RED, FG = ADJ_RED when CONTRAST_RATIO(BG, FG) > READABLE

I also had a basic contrast adjustment function https://github.com/rktjmp/lush.nvim/compare/post-processing#diff-1d4174e38fcba9ad940fcc5fb1813269e4ec110f804b6e3c76085672e9ca83f8 in a colorblind branch, again pretty naive implementation though and it was intended for increasing the contrast of a set of an entire theme. Maybe I can pull that in.

In my experience the auto-generated colours often "work" but end up needing tweaks because the sit too close to other colors or are too green or whatever, etc. I guess if you want to do that you can just keep chaining into a ro/li/sa/etc.

from lush.nvim.

rktjmp avatar rktjmp commented on June 3, 2024

Actually I misinterpreted how bootstrap works. Too early 😴.

from lush.nvim.

davidscotson avatar davidscotson commented on June 3, 2024

I went down a bit of an internet rabbithole as a result of this (still not surfaced from it) on the topic of accessible/readable text and currently think that the new WCAG3 algorithm seems like a good choice (just filed a ticket with colorizer (which I also use) to look into it).

The fundamental API I think should match what is provided here in this JS implementation:

https://github.com/Myndex/SAPC-APCA/blob/master/JS/APCAonly.98e_d12e.js

i.e. you pass it a background color and a foreground color (and the order is important, as you get different scores if reversed), and it gives you a score back.

This would the be used to build other functions, e.g. in the context of the colorizer usage or your own similar highlighting of text, you could pass in the desired target contrast level(1) , the background color to be used, and a list of potential fg choices, it would then return the one closest to the desired contrast level. I'd probably experiment with checking [pure black, pure white,Normal bg, Normal fg, whatever color the theme uses for syntax highlighting the current text area that the color was found in] and letting it pick one from those. (Note many of the implementations are accessability focussed, so they either return the candidate with the most constrast, or the lowest that meets some accessability level score, but I think for themeing you also sometimes want to reduce contrast to fit in with the rest of the theme)

I've not quite thought as far as the Lush API, I'm kind of working on an adaptar layer that will calculate many of these colors before passing them onto lush, so I'm kind of thinking one level of abstraction above that, but for basic usages like the insearch example I'd suggest something like "auto" as a color setting, that would use a standard list of 4 colors (normal light text, normal dark text, pure white, pure black) and return the one that is nearest the target contrast level. The color list and the target level would all default to a global setting if not passed in, so it can be set centrally, but since the underlying API will need to pass in it's own list of colors and target, it makes sense to expose that too for more advanced users, though not sure exactly how that would look.

That could probably be expanded to a similar auto for bg, though maybe they'd use different default color lists, and target contrasts.

Footnote 1. Like you mention, I'm thinking contrast is something that should be a core element of themes, and adjustable along a range. Gruvbox and a few others do something similar by hand at the moment. I want to build a theme for myself to replace solarized, and part of that will be the ability to switch from blue to red tones as the day passes, as well as invert in a style similar to Dark Reader Mode browser. One of the uses I had for Solarised light was when I was sitting somewhere with the sun at my back and my laptop screen became hard to read. If I could just turn up the contrast within the dark theme instead (or even have it do it automatically based on ambient light) that would be cool. I'm still experimenting with this, but your interactive color changing demos were part of the inspiration for trying this out.

from lush.nvim.

rktjmp avatar rktjmp commented on June 3, 2024

The requirement of bg fg order makes things feel a bit awkward to me, in the context of lush colour api where it stylistically wants you to chain things. I guess you could have two functions auto_bg and auto_fg. (Indeed, because of how the "works like a dsl" functions, you can it define a group, break into a bit of lua, then go back to defining groups.)

I'd probably experiment with checking [pure black, pure white,Normal bg, Normal fg, whatever color the theme uses for syntax highlighting the current text area that the color was found in]

The colors are worked out independently of the group they're being used in so they have no way to know what the "current text color is" without it being passed in, so probably something like

-- black and white are included by default
auto_fg_opts = { color_palette.normal_fg_color, colors_palette.normal_bg_color }

lush(function()
  return {
  -- find best contrasting colour against bg_color
  Search { bg = bg_color, fg = bg_color.auto_fg(auto_fg_opts)
  ...

This isn't me saying "no", but I do wonder about the usefulness of it over something that say, checked all your groups after creation (could iterate the parsed spec, far easier and faster than grepping out vims hlgroups) and alert you on poor contrast values.

Because we're talking about design stuff, often concessions are made and I feel that the auto-best colour might just get thrown out anyway. Like if my bg is yellow, I don't really care if the normal_fg blue is "best contast" when really I just want black (or more likely a red, which I would have to pass in as an option, at which point I could just set it directly).

This would be sort of in the same vein of that colourblindness branch, a set of tools that won't fix your theme for colourblindness but it will help you spot problem areas. In my mind that idea was extended out to rendering your groups as virtual text showing different colourblindness modes as you worked so it could have contrast warnings attached.

(maybe even an LSP just for Lush.... depends how practical that is to run "in process" as lua, I don't want to ship some extra bin or something)

Or it could come from the other direction (sounds like what youre doing maybe), define a palette, pass that to some function that will fill some placeholder values marking "needs contrast appropriate value" and then pass the result for use in a lush spec.

from lush.nvim.

davidscotson avatar davidscotson commented on June 3, 2024

So possibly off at a tangent from the main use of this kind of thing, but one example where the current syntax color of the fg matters is diff highlighting. My current theme I've been using is github.com/sainnhe/sonokai which doesn't set the fg color at all, and sets a subtle bg color (a green/red tinted dark gray), so my diffs have full syntax highlighting (not sure if treesitter is part of this working so well or not), and also it's clear what is a diff addition line and what is a deletion, two different "channels" of information coming through the colors at the same time. Probably something that wasn't possible with old terminals with only a few colors available, and so people accept the syntax color getting wiped out as just "how it is", but any new neovim themes should be trying to achieve this in full color guis and terminals I think, as other tools won't be held back by old terminal standards. I've not double-checked in my current theme, but I think within line changes are also highlighted with again a subtly diffferent background color, similar to the delta pager screenshots here: https://github.com/dandavison/delta but I think Solarized would just set the partially changed line to blue and yellow fg depending on if they specific character had changed.

You can probably get pretty far just by tinting the standard background, most people are going to have something vaguely black or white and text that is mostly opposite but if you had access to both colors at the specific point (or even just a list of potential syntax colors), you might be able to do more exciting things and deal with odd cases where the text and background are now too closely matched. Tinting all the foreground colors towards green (or away from it) is also something that feels like it might be neat to try and see how it looks. (Could neovim put a semi-transparent colored floating window over the top to fake a tint? Seems like it might be possible in some cases, but maybe not in a current standard colorscheme or terminal)

I feel like a similar approach might work for Search/IncSearch, but it would be shame if you had to limit yourself
to subtle background shades in order to avoid some random combination of colors making the text disappear, if you have lime green as both your search and your string syntax color, it would be cool if it could switch that particular search match fg to white, but generally leave others alone if they were already visible.

But possibly that's beyond Neovim's theme system capabilities at the moment, I'm just learning more about it as I go so some of my ideas may not be possible at the moment.

from lush.nvim.

rktjmp avatar rktjmp commented on June 3, 2024

Hmm, that's an cool idea, tinting red/green.

That's currently incompatible with Lush, basically because (perhaps ironically for someone who wrote a theme tool) I don't actually use syntax highlighting (mostly) and when I wrote it for myself, I wanted to easily set all groups props to "NONE".

local function make_group(name, opts)
-- We define groups "greedily", meaning we set any un-set options to NONE
-- TODO: good idea or nah?
-- 2021/02/19 - believe it was chosen because it allowed for {} group defs
-- which can clear exiting highlights

There are provisions for passing options to the compiler though, so it's a simple fix to just flag to clear or not but the default behaviour is unlikely to change now.

I am not sure you could even do it in Neovim natively (tinting existing syntax highlights red/green) because your group definitions are pretty course. It's possible to set the BG, not set the FG and it should inherit like you'd think, but you can only really set DiffAdd, not DiffAdd_for_Keyword, *_for_Constant, etc.

At least not natively, though check to be sure.

I think it would be possible to write a plugin that does it though. The regions do retain all the group data ("is keyword, is constant, is diffadd"), so you could

  • get the group stack under your seek head in the file
  • get the lush-spec,
  • compare the groups under the diff against groups in the spec to find the nearest applied ones,
  • pull the fg out of the spec,
  • apply your tint/mix,
  • create a new group (KeywordDiffAdded fg = ..)
  • apply it to the region.

Lushify (lua/lush/ify.lua) actually does something similar to this for it's group colourising.

You could also just define all those groups upfront in a spec and write a plugin that finds keywords in diffadded applies the highlight group over the range. That's probably easier actually.

from lush.nvim.

rktjmp avatar rktjmp commented on June 3, 2024

I added a readable() function to the mix branch, name may change. It just flips white or black depending on whether the lightness of the color it was called on is over 50 or not.

You can combine it with you mix() which might be interesting, since it's the same as calling mix("white"|"black", x) but "white"|"black" is picked for you.

Test   { bg = colors.red_800, fg = colors.waterline_900 },
Error  { bg = Test.bg, fg = Test.bg.mix(Test.bg.readable(), 70) },  

from lush.nvim.

davidscotson avatar davidscotson commented on June 3, 2024

I've extended the readable function a bit, based on the ideas I mentioned above. I'll push them to a repo and link if you're at all interested, but I think the readable function as it stands here is a good addition to the lush theme tools.

I only recently grafted my redable function back into the Lush one, so I was using both side by side for a while and they were very similar for the standard use case of a bright background color with readable text (e.g. the internal color syntax highlighting) and only really diverge when you trying, as I am, to explore text with low contrast differences from the background.

from lush.nvim.

rktjmp avatar rktjmp commented on June 3, 2024

I wouldn't be interested to see what you use. I think I will probably keep the kind of dumb setup for simplicity (both maintenance and explaining how it works: "black on light, white on dark, you can use mix to tint.")

from lush.nvim.

davidscotson avatar davidscotson commented on June 3, 2024

Fair enough, the stuff I'm mucking around with is more "neat and intresting" than "vital and useful", and as I say, they give the same answers in most common cases for the main current usage.

I'll look into moving it from a fork of lush.nvim to some kind of wrapper or proxy so I can keep up with the main branch better while using it in a few different Lush themes.

from lush.nvim.

rktjmp avatar rktjmp commented on June 3, 2024

Ping back if you need a hand integrating. HSL doesn't support injecting custom operations (maybe in the future?) but I think you were already just wrapping in-out values or as I said, Lush just wants to be able to do "guifg=" .. value, so as long as your value is concat/tostring'able it should "just work".

I imagine you can just write a small wrapper to delegate to HSL when required with lua's metatables.

from lush.nvim.

rktjmp avatar rktjmp commented on June 3, 2024

Naive "readable" function in mainline d3071c7.

Mixing readable() and mix() probably gets most people near enough a "readable tint" implementation.

from lush.nvim.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.