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?
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:
This setup ensures you always have access to the most recent ElixirLS features and improvements while maintaining a clean, organized development environment.
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.
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:
It prevents cookie mixing between different apps.
It allows for easier configuration of CORS policies.
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:
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.
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.
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.
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:
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.
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.
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:
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.
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):
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!