A place where I capture raw, quick notes worth remembering.

December 5, 2024

fish shell

Make and jump into directory easily

Very often - like ALL the time - you end up creating a new directory with mkdir -p some_path and then immediately typing cd some_path right after. Such a waste of typing!

Here’s a super handy little function that does both things at once. Just drop this in your config and thank me later:

For Fish:

function mkcd
    mkdir -p $argv[1]; and cd $argv[1]
end

For those that have to still learn that Fish is the best shell, here’s Bash and ZSH:

mkcd() {
    mkdir -p "$1" && cd "$1"
}

Now you can just type mkcd ~/.config/test and boom - directory created and you’re already inside it! The -p flag means it’ll create any missing parent directories too, so you can go as deep as you want. Way better than typing two commands every single time, right?

Permalink

December 4, 2024

elixir

ElixirLS from Source

While the standard ElixirLS installation works well for most developers, running it from source provides access to the latest features and improvements. Recently, after discussing this setup with a colleague, I realized others might benefit from learning how to implement this configuration.

Before proceeding, ensure you have Erlang and Elixir installed on your system. While I personally use Mise for version management, asdf works as well.

Begin by cloning the ElixirLS repository and installing its dependencies:

git clone [email protected]:elixir-lsp/elixir-ls.git
cd elixir-ls
mix deps.get

Next, compile and install ElixirLS. I recommend storing it in ~/.local/share for better organization. The installation commands vary slightly depending on your shell:

For Fish shell users:

env MIX_ENV=prod mix compile
env MIX_ENV=prod mix elixir_ls.release2 -o ~/.local/share/elixir-ls

For Bash or ZSH users:

MIX_ENV=prod mix compile
MIX_ENV=prod mix elixir_ls.release2 -o ~/.local/share/elixir-ls

Editor Configuration

After installation, the executables will be available in ~/.local/share/elixir-ls. You’ll need to configure your editor to use this installation.

For Zed, add the following to your configuration:

"lsp": {
  "elixir-ls": {
    "binary": {
      "path": "/Users/<you>/.local/share/elixir-ls/language_server.sh"
    }
  }
}
  • Neovim users can reference my configuration on GitHub.
  • VSCode users should update the elixirLS.languageServerOverridePath setting.

To maintain the latest version of ElixirLS, simply pull the latest changes from the repository and recompile:

cd elixir-ls
git pull
MIX_ENV=prod mix compile
MIX_ENV=prod mix elixir_ls.release -o ~/.local/share/elixir-ls

This setup ensures you always have access to the most recent ElixirLS features and improvements while maintaining a clean, organized development environment.

Permalink

October 28, 2024

javascript YDKJSY

Comparisons in Javascript

So what’s the difference between == and === in Javascript? Nothing at all if the types on both ends are the same!

If they are different though, == will try to coerce, before compare and this is where a lot of confusion comes from.

42 == "42"; // true, "42" will be converted to number before comparison
1 == true; // true, because true will be converted to 1 before comparison

This also applies to relation comparisons like < and even <=.

There is no way to avoid coercion with relational comparisons. These are the only ones which are valid:

  • < (less than)
  • > (greater than)
  • <= (less than or equal to)
  • >= (greater than or equal to)
  • == (equality with coercion)
  • === (strict equality, no coercion)

Permalink

October 2, 2024

zed git

Zed as the default editor for commits

I started to use the Zed editor as my default editor, and with it I also use the terminal that comes with it. When using the Zed terminal, I would also like the git commit messages to open in Zed, but only if I’m actually in the Zed terminal. To do this, I first added this to my Zed configuration:

"terminal": {
  "env": {
    "TERM_PROGRAM": "zed"
  }
}

And then, in my Fish config, I added this:

# Zed editor
if test "$TERM_PROGRAM" = "zed"
    set -x EDITOR zed --wait
    set -x VISUAL zed --wait
end

Now, only when I’m in Zed terminal, git commits will also open in Zed. Any other terminal, it defaults back to Neovim.

Permalink

September 24, 2024

phoenix dns

Domains for local apps

When working on side projects, I prefer setting up a custom domain for each app I’m developing. This approach mimics the production environment more closely and simplifies juggling multiple apps simultaneously.

Using custom domains for local development offers several advantages:

  1. It prevents cookie mixing between different apps.
  2. It allows for easier configuration of CORS policies.
  3. It provides a more realistic testing environment.

Setting this up is straightforward, especially with the help of Caddy. Here’s my process:

First, choose your domain: I typically use the local subdomain. For instance, if my production app is breadandbutter.com, I’ll use local.breadandbutter.com for local development.

Configure Caddy, assuming my local server runs on port 4000, here’s the Caddy configuration I use:

local.breadandbutter.com {
    tls internal
    reverse_proxy localhost:4000
}

Finally, add an A record for local.breadandbutter.com pointing to 127.0.0.1 in my hosts file or local DNS server.

That’s all there is to it! Now I can access my app at local.breadandbutter.com, enjoying the benefits of a custom domain for my local development environment.

This setup not only enhances my development workflow but also helps catch potential issues related to domain-specific configurations early in the development process.

Permalink

Alias for fast testing in Elixir

In my previous note Shorter feedback loops with Elixir tests I already described how to run tests in Elixir, where it only runs the failed tests. Below is what I put in my mix.exs file to have faster feedback loops when testing:

defp aliases do
    [
      ...
      "test.failed": ["test --failed --max-failures 1"],
    ]
  end

  # Make sure the alias runs in the test MIX_ENV environment.
  def cli do
    [preferred_envs: ["test.failed": :test]]
  end

This will create a new alias test.failed that will run only the failed tests and stop after the first failure. This is useful when you are working on a specific test and you want to run it quickly without running all the tests.

Permalink

Connect to your PostgreSQL server from Tailscale

I’m a big fan of Tailscale, and I use it to create my own private network. This means that I can connect to my devices from anywhere in the world without having to worry about opening ports or exposing my IP address. I recently also used Tailscale to connect to a PostgreSQL server; below is how I did it.

To get Tailscale working on my Ubuntu machine, I first needed to install the Tailscale client. I did trust the Tailscale team and used their installation script:

curl -fsSL https://tailscale.com/install.sh | sh

Then, I needed to configure Tailscale to connect to my account with:

sudo tailscale up

Tailscale is now up and running. Next, let’s open up the PostgreSQL port on the Taiscale network. I’m running the UFW firewall, so this is what I did:

sudo ufw allow in on tailscale0 to any port 5432 proto tcp

Now, I also need to make sure PostgreSQL runs on any interface. I did that by changing the listen_addresses in my postgresql.conf file:

listen_addresses = '*'

In my pg_hba.conf file, I added the following line to allow connections from Tailscale. I decided to use the trust method because if somebody can connect to my Tailscale network, I’m already screwed anyway.

host    all    all   100.64.0.0/10    trust

And then restarting PostgreSQL:

sudo systemctl restart postgresql

When I’m on my laptop and I’m connected to the Tailscale network, I can connect to my PostgreSQL server with:

psql -h <name-of-your-server> -U postgres

The <name-of-your-server> is the name of your Tailscale device. You can find it in the Tailscale dashboard. It’s easier to remember than the IP address.

That’s all there is to it! Now you can securely connect to your PostgreSQL server from anywhere in the world using Tailscale’s private network. You can use this technique to expose multiple applications across your machines. For example, I’m also using it to connect to my Raspberry Pi, where I’m running PiHole, a DNS ad blocker.

Permalink

August 26, 2024

python

Install Python on Ubuntu 24.04

Wanting to try out some command line tools written in Python, I needed to install Python on my Ubuntu machine. Since it’s more than a decade without Python, I needed to lookup how that was done these days. This is what I ended up with:

sudo apt install python3 python3-is-python python3-pip pipx

And apparently, these days you can’t just install packages with pip unless you are in a virtual environment. So now you have pipx, which I used to install ruff.

pip instal ruff

Permalink

July 9, 2024

lisp

Rich Comment Blocks in Common Lisp

In Clojure, “Rich Comment Blocks” serve as both a playground and a log during development. Named after Clojure’s creator, Rich Hickey, these blocks offer a unique approach to REPL-driven development.

Stuart Halloway, in his talk “Running with Scissors,” quipped:

These comments are rich because they provide rich detail about the development process and because they were written by a person named Rich.

Rich Comment Blocks look like this:

(comment
  (println "foo"))

When the program runs, it ignores the top-level form. However, during development, you can evaluate each line individually, making it an invaluable tool for experimentation and debugging.

As a Common Lisp user, I initially missed this feature. While Common Lisp does have the #+nil reader macro that can be used for similar purposes, it’s not quite as flexible as Clojure’s comment form. The #+nil macro looks like this:

#+nil
(print "This won't be evaluated when the file is loaded")

However, I wanted something closer to Clojure’s Rich Comment Blocks, so I created my own comment macro in Common Lisp:

(defmacro comment (&body body)
  (declare (ignore body)))

This simple macro brings the power of Rich Comment Blocks to Common Lisp, offering more flexibility than the #+nil reader macro. It allows you to wrap multiple expressions and even nested forms, which can be selectively evaluated during development.

Give it a try - you might find it as useful as I do.

Permalink

Guile Hoot on the Mac

Recently, I was exploring the Spritely Institute’s blog and discovered their project, Guile Hoot. This Scheme to WebAssembly compiler enables running Scheme code directly in web browsers, opening up new possibilities of using Scheme.

While the project’s documentation is tailored for Guix users (a natural choice for Guile enthusiasts), I’m stuck on MacOS and needed to adapt the setup process using Homebrew. To save you time and frustration, this is how I got it running:

First, install the latest version of Guile using Homebrew:

# This may take some time
brew install guile --HEAD

Next, set up the necessary environment variables. For Fish shell users like myself:

set -x GUILE_LOAD_PATH $brew_prefix/share/guile/site/3.0
set -x GUILE_LOAD_COMPILED_PATH $brew_prefix/lib/guile/3.0/site-ccache
set -x GUILE_SYSTEM_EXTENSIONS_PATH $brew_prefix/lib/guile/3.0/extensions

For Bash or ZSH users, use the following (replace brew_prefix with the actual path or set it as a variable):

export GUILE_LOAD_PATH=$brew_prefix/share/guile/site/3.0
export GUILE_LOAD_COMPILED_PATH=$brew_prefix/lib/guile/3.0/site-ccache
export GUILE_SYSTEM_EXTENSIONS_PATH=$brew_prefix/lib/guile/3.0/extensions

Now, let’s clone the Guile Hoot repository, configure, and compile it. Ensure that the prefix directory matches your brew_prefix:

git clone https://gitlab.com/spritely/guile-hoot.git
cd guile-hoot
./bootstrap.sh
./configure --prefix=/opt/homebrew
make
# No sudo needed when using Homebrew
make install

To verify your installation, launch the Guile REPL and test if the following command loads without errors:

scheme@(guile-user)> ,use (hoot compile)

If you don’t encounter any errors, congratulations! You’ve successfully set up Guile Hoot on your Mac. Now, let’s see if I can create a game in the browser with Scheme and WASM!

Permalink