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

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

July 1, 2024

emacs macos

Install Emacs on the Mac - Part Two

Previously, I used to install Emacs on the Mac through a build script, but I recently switched to the Emacs Plus version, installed through homebrew.

First, you need to “tap” it and install dependencies before you can use it:

brew tap d12frosted/emacs-plus

# Install dependencies
brew install jq

And then you can install it. I pin it to a version and use minimal flags:

brew install emacs-plus@30 --with-memeplex-slim-icon --with-native-comp

And there you go, an Emacs version specifically tuned for the Mac.

Permalink

June 30, 2024

emacs macos

Enhancing Font Rendering in Emacs on macOS

Recently, I stumbled upon a Reddit thread on font rendering in Emacs on macOS. I figured many users might be unaware of simple trick for crisper fonts:

defaults write org.gnu.Emacs AppleFontSmoothing -int 0

After running this command, restart Emacs to see the effect.

If you’re not satisfied with the result, you can easily revert to the default settings by running:

defaults delete org.gnu.Emacs AppleFontSmoothing

Remember to restart Emacs after making changes again.

Permalink

June 29, 2024

linux emacs

Sync Fastmail with isync

As an Emacs enthusiast, I’ve found Mu4e to be an excellent email client. While Emacs can send emails, it can’t fetch and sync them efficiently. Enter isync, the perfect companion to fill this gap.

Setting up this duo took some digging, so I’m sharing my configuration to save you time and headaches.

Here’s what my setup accomplishes:

  1. Syncs all mailboxes, excluding junk and notes.
  2. Renames “Sent Items” to “Sent” for simplicity.
  3. Encrypts your password on disk using GPG.

First, I recommend to install the latest version of isync, if you are on the Mac, use brew install isync --HEAD. Then, you’ll need to create an encrypted password file. In Emacs, run the epa-encrypt-file command.

Now, let’s dive into the heart of the setup. Here’s my .mbsyncrc configuration file:

# Petar account on Fastmail.
IMAPAccount petar
Host imap.fastmail.com
Port 993
AuthMechs LOGIN
User [email protected]
PassCmd "gpg -q --for-your-eyes-only --no-tty -d ~/.mbsync-password-petar.gpg"
TLSType IMAPS
TLSVersions +1.2

IMAPStore petar-remote
Account petar

# Petar Local.
MaildirStore petar-local
Path ~/Mail/Petar/
Inbox ~/Mail/Petar/Inbox
Trash ~/Mail/Petar/Trash/
SubFolders Verbatim

# Sync everything besides sent and junk.
Channel sync-petar-all
Far :petar-remote:
Near :petar-local:
Patterns * !"Sent Items" !"Junk Mail" !"Notes"
Expunge None
CopyArrivalDate yes
Sync All
Create Near
SyncState *

# Sync and rename the sent items
Channel sync-petar-sent
Far :petar-remote:"Sent Items"
Near :petar-local:Sent
Expunge None
CopyArrivalDate yes
Sync All
Create Near
SyncState *

Group petar
Channel sync-petar-all
Channel sync-petar-sent

With this setup, you’ll have all your email on disk, ready to use it in Emacs and Mu4e.

Permalink