Nix - filter and apply changes to attributes in a list

How to change/update an attribute (which is in a list)

  • getting the whole list with updates (only) to certain attributes as an output

all I got for now is

flt = (builtins.filter (x: x.manage == "desktop") ) 
map (x: x //  { start =  "test" ; } ) flt

Yes, this is usually awkward in functional languages.

The argument is that if you have a list where you want members from a specific index, you likely wanted an attrset to begin with, and should refactor your code to provide that instead.

Failing that you fall back to filters like yours, which in turn are more robust to list contents that you may not expect.

This falls flat in the face of efficient low-level algorithm stuff, but arguably you should not be doing those things in a high-level language like nix. Rust for example provides better features for such use cases, while still having high-level functional interfaces when you need them.

That said, what are you trying to achieve? Set start = "test" on all desktop sessions? There might be a better way of achieving what you actually want, rather than what you think you want :wink:

yes, that was the idea

I meant the higher level goal of this operation; as it stands, I think all that I would change about your solution is formatting and variable names:

  sessions =;
  map (session: session // { start = "test"; })
    (builtins.filter (session: session.manage == "desktop")

Makes it a bit easier to understand what’s being done to the data IMO, but this is splitting hairs.

If this was haskell I’d also think hard about partial function application to get rid of all the nesting and make the filter/map lambdas slightly more succinct. But I think nix lacks an operator or two (and is therefore probably easier to understand ;p).

I don’t think you want to replace all your desktop sessions with the test bash builtin though.

The change of the wallpaper / file path in plasma via config

  • currently the configuration contains only one desktop session

if that would be the nix-way?
:p lib.lists.forEach sessions (session : if session.manage == "desktop" then ( session // { start = "..."; }) else session )

I’d reccommend something like this instead:

systemd.user.units.plasma-wallpaper = {
  description = "Plasma wallpaper setter";
  script = "test";
  wantedBy = [""];
  # If you use e.g. `feh` on xorg
  # serviceConfig.Type = "oneshot";

Then systemd will ensure that the unit starts up with X11 (and with some hacks also wayland, wayland hasn’t been properly integrated into desktop startup yet).

Though I suppose there may be some race conditions, depending on when this target ends up running, and whether plasma is the process that starts that.