Just a basic programmer living in California

  • 12 Posts
  • 188 Comments
Joined 2 years ago
cake
Cake day: February 23rd, 2024

help-circle
  • Whoops! Guess I was wrong. After some experimenting it looks like the flake system parses, but does not evaluate flake.nix to read inputs. I also experimented with string concatenation, and that failed with the same error:

    nixpkgs.url = "github:nixos/nixpkgs" ++ "/nixos-25.05"; # error: expected a string or path, but got a thunk
    

    A “thunk” is an expression whose evaluation has been delayed. It’s a key piece of lazy evaluation. Remember that every expression in Nix is lazily evaluated.

    It looks only literal attribute set, string, and path expressions will work in inputs. I think that means it is not possible to split inputs over multiple files.



  • I think you can use import to load the expression from each file, and the // operator to combine imported attribute sets. Like this:

    Edit: This doesn’t work - see replies

    # flake.nix
    {
      inputs =
        import ./inputs/nixpkgs.nix //
        import ./inputs/nix-index.nix;
    
      # ...
    }
    
    # inputs/nixpkgs.nix
    {
      nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
      nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
    }
    
    # inputs/nix-index.nix
    {
      nix-index-database = {
        url = "github:Mic92/nix-index-database";
        inputs.nixpkgs.follows = "nixpkgs";
      };
    }
    


  • Not OP, but I’ve been using Niri as my daily driver for almost two years (since v0.1.2). The stability and polish have really impressed me. In addition to the scrolling workflow it has some especially nice features for screen sharing & capturing, like key binds to quickly switch which window you are sharing, and customizable rules to block certain windows when showing your whole desktop.

    I do use a 40" ultrawide. Looking for options for getting the most out of an ultrawide was how I got into scrolling window managers.

    I only occasionally use my 13" laptop display. I still like scrolling because I like spatial navigation. Even if windows end up mostly or entirely off the screen I still think about my windows in terms of whether they’re left, right, up, or down from where I’m currently looking.

    I don’t like traditional tiling as much because I find squishing every window to be fully in view to be awkward; and with e.g. i3-style wms if I want to stash a window out of view, like in a tab that’s a separate metaphor I have to keep track of, with another axis where windows might be. Scrolling consistently uses on spatial metaphor, placing all windows on one 2D plane with one coordinate system.


  • Home Manager is a Nix tool for managing configuration for a single user, usually on a Linux or MacOS system, or possibly WSL. You configure installed programs, program configuration (such as dot files), and a number of other things, and you get a reproducible environment that’s easy to apply to multiple machines, or to roll back configuration, etc. I find it helpful for having a clear record of how everything is set up. It’s the sort of thing that people sometimes use GNU Stow or Ansible for, but it’s much more powerful.

    A Home Manager configuration is very similar to a NixOS configuration, except that NixOS configures the entire system instead of just configuring user level stuff. (The lines do blur in Nix because unlike traditional package managers where packages are installed at the system level, using Nix packages can be installed at the system, user, project, or shell session level.) Home Manager is often paired with NixOS. Or on Macs Home Manager is often paired with nix-darwin. As I mentioned, the Home Manager portion of my config is portable to OSes other than NixOS. In my case I’m sharing it in another Linux distro, but you can also use Home Manager to share configurations between Linux, MacOS, and WSL.



    • NixOS + Home Manager
    • Niri
    • Kitty
    • Neovim, via Neovide

    For work it’s Fedora + Home Manager because the remote admin software doesn’t support NixOS. Thankfully I’ve been able to define my dev environment almost fully in a Home Manager config that I can use at work and at home.

    I use lots of Neovim plugins. Beyond the basic LSP and completion plugins, some of my indispensables are:

    • Leap for in-buffer navigation & remote text copying
    • Oil for file management
    • Fugitive + Git Signs + gv.vim + diffview.nvim for git integration
    • nvim-surround to add/change/remove delimiters
    • vim-auto-save
    • kitty-scrollback



  • No, if something goes wrong with the VPN then the confined service will be unable to reach the internet. The setup runs the confined process in a network namespace that does not have a route to your default wifi or ethernet interfaces. If the VPN interface isn’t set up correctly, or stops working there is no other route out.

    You can test this with or without setting up VPN-Confinement. To do a quick test without any VPN setup, create a test service like this:

    systemd.services.test-unit = {
      serviceConfig = {
        NetworkNamespacePath = "/run/netns/test";
        Type = "oneshot";
      };
      script = ''
        ${pkgs.iputils}/bin/ping 1.1.1.1
      '';
    };
    

    Create a matching network namespace that doesn’t route anywhere:

    sudo ip netns add test
    

    Then set the unit running, and watch its output:

    sudo systemctl start test-unit.service
    journalctl -u test-unit.service -f
    

    You’ll see ping report that the network is unreachable. If you delete the namespace while ping is running it will continue to report that the network is unreachable.

    sudo ip netns del test
    

    (If you don’t want to bother with a systemd unit, you can run a process in a given network namespace using sudo ip netns exec <namespace> <command>. For example, sudo ip netns exec test ping 1.1.1.1.)

    If the namespace wasn’t set up for whatever reason the confined service won’t start. (See the edit on the post.)

    I also did some tests with the VPN-Confinement setup with this test unit:

    systemd.services.test-unit = {
      serviceConfig = {
        Type = "oneshot";
      };
      script = ''
        while true; do
          ${pkgs.curl}/bin/curl https://am.i.mullvad.net/connected
          sleep 5
        done
      '';
      vpnConfinement = {
        enable = true;
        inherit vpnNamespace;
      };
    };
    

    If I set vpnNamespace to a name that doesn’t match a configured vpnNamespace then the service won’t start.

    If I bring down the VPN namespace while that curl loop is running with sudo systemctl stop wg.service then test-unit also stops, because of the systemd dependencies that systemd.services.<name>.vpnConfinement sets up.

    If I bring down the network namespace manually while the curl loop is running with sudo ip netns del wg then the curl loop keeps running, and continues to report that it is connected to Mullvad. I guess the network namespace continues to exist while a running process is using it.

    If I bring down the VPN network interface with sudo ip -n wg link set dev wg0 down then curl fails with status=6/NOTCONFIGURED



  • I use a chat interface as a research tool when there’s something I don’t know how to do, like write a relationship with custom conditions using sqlalchemy, or I want to clarify my understanding on something. first I do a Kagi search. If I don’t find what I’m looking for on Stack Overflow or library docs in a few minutes then I turn to the AI.

    I don’t use autocompletion - I stick with LSP completions.

    I do consider environmental damage. There are a few things I do to try to reduce damage:

    1. Search first
    2. Search my chat history for a question I’ve already asked instead of asking it again.
    3. Start a new chat thread for each question that doesn’t follow a question I’ve already asked.

    On the third point, my understanding is that when you write a message in an LLM chat all previous messages in the thread are processed by the LLM again so it has context to respond to the new message. (It’s possible some providers are caching that context instead of replaying chat history, but I’m not counting on that.) My thinking is that by starting new threads I’m saving resources that would have been used replaying a long chat history.

    I use Claude 4.5.

    I ask general questions about how to do things. It’s most helpful with languages and libraries I don’t have a lot of experience with. I usually either check docs to verify what the LLM tells me, or verify by testing. Sometimes I ask for narrowly scoped code reviews, like “does this refactored function behave equivalently to the original” or “how could I rewrite this snippet to do this other thing” (with the relevant functions and types pasted into the chat).

    My company also uses Code Rabbit AI for code reviews. It doesn’t replace human reviewers, and my employer doesn’t expect it to. But it is quite helpful, especially with languages and libraries that I don’t have a lot of experience with. But it probably consumes a lot more tokens than my chat thread research does.


  • For the r case I think you need to set the mapping in “operator pending” mode, which you get by putting "o" in the same position you already have "!".

    I don’t know what the issue is with command mode.

    There is plenty of precedent for custom escape bindings, often using jk or jj. You might be able to find examples to get an idea of the best way to set up those bindings.

    There might be an issue with <C-space> in particular if it has existing mappings in certain modes. I know that auto-complete plugins often use that mapping to make the completions menu appear. There might be some interaction with that mapping specifically with plugins you’re using, or with built-in behavior. I suggest experimenting with a different mapping to narrow down whether problems are due to the way you are writing mappings, or to a specific interaction with that key sequence.





  • I haven’t gotten much into flake-parts, but my understanding is that it creates a module system very similar to NixOS modules and Home Manager modules. Except that instead of defining a system configuration, flake-parts modules define flake outputs.

    So I don’t think you would use it in your NixOS configuration. If your configuration uses a flake there might be use cases for using it at the flake level. For example your flake defines a nixosConfigurations output, which is a set with an attribute for each host. If you had some unusually complicated code in that flake output you might use flake-parts to modularize it.

    Or I suppose flake-parts is largely aimed at simplifying per-system outputs like packages and devShells. Once again, if you wanted to split those definitions over multiple files flake-parts can do that. Or you can use it just to get flake-parts’ eachDefaultSystem helper if you don’t want to use equivalent functionality from flake-utils, or the built-in genAttrs function.

    Although I love the NixOS module system, I haven’t used flake-parts because I haven’t had a case where I want reusable modules in the context of flake outputs. Usually my flakes are a pretty uncomplicated combination of genAttrs, basic devShells, basic overlays, and package expressions that I build with callPackage.




  • The first season, and the first few episodes of season two take some extra weird turns because of the revolving door of producers during that period. The original producer left the show during season one. Then a duo took over who took the story in quite a different direction. Those two left in early season two. After that production finally settled into a more stable state.

    Anyway the characters and acting are great, and that counts for a lot!