nixcfg icon indicating copy to clipboard operation
nixcfg copied to clipboard

A better way to do multiline scripts in Sway

Open MatthewCroughan opened this issue 2 years ago • 3 comments

I've been studying your config and applying the bits I like to mine, but in doing so have found a better way to handle scripts in the sway config you have. I wanted to do some advanced scripting, so was getting quite annoyed with all of the \s for newlines. So instead, we can use pkgs.writeShellScript to write a script which is then used as a substitution, which avoids all of that.

For example:

You do

https://github.com/cole-mickens/nixcfg/blob/aef46f04089021adf3364c91402c761479cefb38/mixins/sway.nix#L56-L62

I do

{
  idlecmd = pkgs.writeShellScript "swayidle.sh" ''
    ${pkgs.swayidle}/bin/swayidle -w
    before-sleep "${swaylockcmd}"
    lock "${swaylockcmd}"
    timeout 500 "${swaylockcmd}"
    timeout 1000 "${pkgs.systemd}/bin/systemctl suspend"
  '';
}

pkgs.writeShellScript will return a path to the nix store where the script is, Sway will run the shell script rather than having to interpret \.

MatthewCroughan avatar Jul 22 '21 12:07 MatthewCroughan

While I grant that my swaylock setup might be broken, afaict that's not right either? From first glance, what you wrote is a shell script that executed 5 lines, only one of which is (partially) valid.

colemickens avatar Aug 02 '21 07:08 colemickens

only one of which is (partially) valid.

Hah, you're right, you still need the multiline \s. I still think this method of writing a shell script and calling it is less error prone though.

❯ sway
No status data could be sent: $NOTIFY_SOCKET was not set
tail: cannot open '/run/user/1000/sway-ipc.1000.160833.sock.wob' for reading: No such file or directory
tail: no files remaining
Failed to acquire service name: File exists
Is a notification daemon already running?
1627915052.999441 ERROR main.c:788: STDIN unexpectedly closed, revents = 16
No command specified! Nothing to do, will exit
/nix/store/ia71kkvb4gs4r5hhi13y7nx239zq9pm2-swayidle.sh: line 3: before-sleep: command not found
/nix/store/ia71kkvb4gs4r5hhi13y7nx239zq9pm2-swayidle.sh: line 4: lock: command not found
timeout: failed to run command ‘/nix/store/1iddbq0z64y9y6b3ms01grakw9zzcdb9-swaylock-1.5/bin/swaylock -c '#000000'’: No such file or directory
timeout: failed to run command ‘/nix/store/yh9hjlgknf4ff8di0lw0hgm6clx38p47-systemd-247.6/bin/systemctl suspend’: No such file or directory
Another flashfocus instance is running.

An example of where this method is obviously better would be how I manage my "dropdown" terminal, which is a terminal that pops up in the center of the screen when I hit f12. Each time I hit f12 this script is fired off, doing this without writing a shell script would be really hard due to how you'd have to write it in terms of escape chars, etc.

https://github.com/MatthewCroughan/nixcfg/blob/9436a367dec2d17df7d7c1cee84cad8825b422b9/mixins/sway.nix#L24-L37

let
  dropdownTerminalCmd = pkgs.writeShellScript "launchkitty.sh" ''
    open=$(ps aux | grep -i "kitty --class=dropdown" | grep -v grep)
    if [[ $open -eq 0 ]]
    then
      ${pkgs.kitty}/bin/kitty --class=dropdown --detach
      until swaymsg scratchpad show
      do
        echo "Waiting for Kitty to appear..."
      done
    else
      echo "Kitty is already open"
      swaymsg "[app_id=dropdown] scratchpad show"
    fi
  '';
in
{
...
}

MatthewCroughan avatar Aug 02 '21 14:08 MatthewCroughan

I have a pretty complete swayidle module here (that needs to be merged in HM): https://github.com/berbiche/dotfiles/blob/40a6f3666c11abcb5ae34a09099c190b36148b7f/modules/home-manager/swayidle.nix

This is what it looks like configured:

{
  services.swayidle = {
    enable = true;

    idlehint = "5 minutes";

    timeout = [
      {
        timeout = "5 minutes";
        command = "${swaylock} -f";
      }
      {
        timeout = "10 minutes";
        command = "${swaymsg} 'output * dpms off'";
        resume = "${swaymsg} 'output * dpms on'";
      }
    ];

    before-sleep = [
      "${playerctl} ${withPlayerctld} pause"
      "${dunstctl} set-paused true"
      "${swaylock} -f"
    ];

    lock = [
      "${dunstctl} set-paused true"
    ];

    unlock = [
      "${dunstctl} set-paused false"
    ];
  };
}

berbiche avatar Aug 06 '21 16:08 berbiche

This is pretty old, and I do use the better multiline strings now :).

colemickens avatar Apr 06 '23 20:04 colemickens