Here’s a handy tip: create Phoenix configurations that live only on your machine, not in version control.
I use this for setting machine-specific domain names. It’s ideal for any development settings that shouldn’t live in your shared repository.
First, add this snippet at the bottom of config.exs
:
if File.exists?("#{__DIR__}/#{config_env()}.local.exs") do
import_config "#{config_env()}.local.exs"
end
Create a file named dev.local.exs
and Phoenix will load it. Add this to your .gitignore
to keep it local:
# Ignore local environment configs
*.local.exs
Your machine-specific settings won’t touch production or bother teammates. Common uses:
- Local database credentials
- Custom domain names (like
dev.localhost
)
- Local service endpoints
- Personal log levels
Everyone on your team can customize their environment without stepping on each other’s toes. Enjoy!
Permalink
yt-dlp
is a powerful command-line tool for downloading videos from YouTube and other platforms. I frequently use it to save videos for offline viewing, particularly before long flights or to archive interesting content.
On macOS, you can install it using Homebrew:
brew install yt-dlp
Here’s the onfiguration that I use:
yt-dlp \
--cookies-from-browser safari
--format bestvideo+bestaudio
--merge-output-format mp4
-o "%(title)s.%(ext)s"
You can either supply these options through the command line or save them in a config file at ~/.config/yt-dlp/config
. The config file format is straightforward - just list the flags one per line:
--cookies-from-browser safari
--format bestvideo+bestaudio
--merge-output-format mp4
-o "%(title)s.%(ext)s"
Once configured, downloading a video is as simple as:
yt-dlp https://youtube.com/watch?v=...
The video will download in the highest available quality and save to your current directory.
Permalink
Want to save one keystroke and a few milliseconds? I’m trying something out, when I do my git commits, to start in insert mode, so I can start typing immediately.
You can do this by adding a new autocommand for git commit messages.
In Neovim and Lua you create one like this:
vim.api.nvim_create_autocmd("FileType", {
pattern = "gitcommit",
callback = function()
vim.cmd("startinsert")
end,
})
If for example you are using Lazyvim, add the above to
your ~/.config/nvim/lua/config/autocmds.lua
file.
Permalink
Sometimes I’m working on a system and I want to reboot it, but I don’t want it to go
to the default boot entry. E.g. I have Arch on my desktop, but it defaults to Windows
so my kids can easily start the computer.
If you are using EFI, you can reboot into a specific boot entry, just one time.
First, show the boot entries that you currently have:
sudo efibootmgr -v
Then, pick the entry you want to reboot in:
sudo efibootmgr -n 0000
Now you can reboot, and it will boot into that specific entry.
Permalink
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
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
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
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
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:
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
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