<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Tips &amp; Tricks on Clément Joly – Open-Source, Rust &amp; SQLite</title><link>https://joly.pw/blog/tips/</link><description>Recent content in Tips &amp; Tricks on Clément Joly – Open-Source, Rust &amp; SQLite</description><image><title>Clément Joly – Open-Source, Rust &amp; SQLite</title><url>https://joly.pw/images/open-graph-home-original.png</url><link>https://joly.pw/images/open-graph-home-original.png</link></image><generator>Hugo -- 0.154.3</generator><language>en</language><copyright>Clément Joly</copyright><lastBuildDate>Wed, 11 Mar 2026 03:32:38 +0000</lastBuildDate><atom:link href="https://joly.pw/blog/tips/index.xml" rel="self" type="application/rss+xml"/><item><title>You “Own” 16 Milion+ IPv4 Addresses!</title><link>https://joly.pw/blog/tips/you-own-16-milion-ipv4-addresses/</link><pubDate>Sat, 05 Mar 2022 21:13:22 +0000</pubDate><guid>https://joly.pw/blog/tips/you-own-16-milion-ipv4-addresses/</guid><description>What can you do with the huge loopback range (127.0.0.0/8)? Is it future-proof?</description><content:encoded><![CDATA[



  
  
  
  

  <div class="alert alert-tldr">
    <p class="alert-heading">
      ⚡
      
        TL;DR
      
    </p>
    <p>For the foreseeable future, you can likely use <code>127.0.0.0/8</code> freely (or at least <code>127.0.0.0/16</code>).</p>
  </div>



<h2 id="introducing-1270008-the-loopback-range">Introducing <code>127.0.0.0/8</code>, the Loopback Range</h2>
<figure>
    <img loading="lazy" src="/blog/tips/you-own-16-milion-ipv4-addresses/opengraph.webp"
         alt="If you have a Cidr range 127.0.0.0/8 visualized with 4 colors, one color per number." width="1941" height="855"/> <figcaption>
            Visualization of the 127.0.0.0/8 range<p>From <a href="https://cidr.xyz">cidr.xyz</a> by <a href="https://yuv.al/">Yuval Adam</a></p>
        </figcaption>
</figure>

<p>If you have ever done web development or otherwise set up a local server, you have most likely used the IP address <code>127.0.0.1</code> to communicate with a local server. Often, <a href="https://en.wikipedia.org/wiki/Localhost"><code>localhost</code></a> is even internally translated to that address. But what if you want to run another server on the same computer? Easy, make the first one use, say, port <code>8080</code> and the second one, port <code>8181</code>!</p>
<p>Something more difficult now: say you can convince<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> your browser that your local service is serving a valid HTTPS connection only if you use port number <code>443</code>. How can you run many of those services? In turns out in IPv4, you have many such local addresses: <code>127.0.0.1</code>, <code>127.0.0.2</code>,  <code>127.0.0.3</code>, <code>127.0.0.4</code>… So you just need to spawn the various servers on the same <code>443</code> port number with different addresses and packets will go straight to your <a href="https://en.wikipedia.org/wiki/Localhost">localhost</a>.</p>
<p>But how many such addresses do we have? According to <a href="https://www.rfc-editor.org/rfc/rfc990.txt">RFC990</a> from 1986:</p>




  <figure>
    <blockquote cite="https://www.rfc-editor.org/rfc/rfc990.txt">
      <pre><code>   The class A network number 127 is assigned the &quot;loopback&quot;
   function, that is, a datagram sent by a higher level protocol
   to a network 127 address should loop back inside the host.  No
   datagram &quot;sent&quot; to a network 127 address should ever appear on
   any network anywhere.
</code></pre>

    </blockquote>
    
      <figcaption class="blockquote-caption">
        
          <cite style="text-align: right"><a href="https://www.rfc-editor.org/rfc/rfc990.txt">https://www.rfc-editor.org/rfc/rfc990.txt</a></cite>
          <br/>
        
        
      </figcaption>
    
  </figure>



<p>The “class A network” translate to a <code>/8</code> in <a href="https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing">CIDR notation</a>, so that’s all addresses between <code>127.0.0.0</code> and <code>127.255.255.255</code>. A quite sizeable 2²⁴ or <em>16,777,216</em> addresses<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>!</p>
<p>Note the wording of the RFC: IPs are not “owned”, there are just “allocated”. For addresses routable on the wider Internet, it’s usually done by <a href="https://en.wikipedia.org/wiki/Regional_Internet_registry">Regional Internet Registeries</a>. And allocations could change, as we will see at the end of this article.</p>
<h2 id="other-use-cases">Other Use Cases</h2>
<p>What can you do with so many IPs? A couple of things.</p>
<h3 id="multiple-servers-on-the-same-port-number">Multiple Servers on the Same Port Number</h3>
<p>As we have seen earlier with the port number <code>443</code> example, the <code>127.0.0.0/8</code> range is handy to run multiple local services on the same port. Thus, it’s not surprising to see <code>systemd-resolved</code> – a local DNS resolver that needs to listen on port <code>53</code> – use a couple addresses from that range. The <a href="https://man.archlinux.org/man/core/systemd/systemd-resolved.8.en">man page</a> reads:</p>




  <figure>
    <blockquote cite="https://man.archlinux.org/man/core/systemd/systemd-resolved.8.en">
      <p>Additionally, systemd-resolved provides a local DNS stub listener on the IP addresses 127.0.0.53 and
127.0.0.54 on the local loopback interface.</p>

    </blockquote>
    
      <figcaption class="blockquote-caption">
        
          <cite style="text-align: right"><a href="https://man.archlinux.org/man/core/systemd/systemd-resolved.8.en">https://man.archlinux.org/man/core/systemd/systemd-resolved.8.en</a></cite>
          <br/>
        
        
      </figcaption>
    
  </figure>



<p>In this case, <code>systemd-resolved</code> <em>has to</em> bind on the default port, because one of the main ways (on Unix-like systems) that DNS resolution is configured is through the file <a href="https://man.archlinux.org/man/resolv.conf.5.en"><code>/etc/resolv.conf</code></a>. This file does not widely support setting a port number, forcing the configured server to be reachable on the default port. Thanks to the use of a loopback addresse though, <code>systemd-resolved</code> can become the default resolver just by adding this line to <code>resolv.conf</code>:</p>
<pre tabindex="0"><code>nameserver 127.0.0.53
</code></pre><h3 id="naming-things">Naming Things</h3>
<p>On Unix-like systems, the <code>/etc/hosts</code> file associates IP addresses with names, like so:</p>
<pre tabindex="0"><code>127.0.0.1	localhost
::1		localhost
</code></pre><p>That’s how <code>localhost</code> is associated with <code>127.0.0.1</code> (and IPv6 <code>::1</code>).</p>
<p>You can edit this file and add useful aliases to other IPs (not necessarily in the local range by the way). Then, you just bind your multiple services to their default ports and access to them by name. No more complicated ports to remember! This benefit comes as a byproduct of using default ports but with different IPs for different services.</p>
<p>For instance, you could name one of the aforementioned <code>systemd-resolved</code> IPs by adding this line to <code>/etc/hosts</code>:</p>
<pre tabindex="0"><code>127.0.0.1	localhost
::1		localhost

127.0.0.53	sd
</code></pre><p>And then query it like so:</p>
<pre tabindex="0"><code>dig @sd s.cj.rs
</code></pre><p>instead of</p>
<pre tabindex="0"><code>dig @127.0.0.53 s.cj.rs
</code></pre><p>if you did not have the setting.</p>
<p>I’m using this trick to make the <a href="https://syncthing.net/">Syncthing</a> web interface accessible on a memorable port on an address with a memorable name in my web browser.</p>
<h2 id="future-of-1270008">Future of <code>127.0.0.0/8</code></h2>
<p>Even if the ability to give various services different IPs is handy, 16 milion addresses is huge. Given how IPv4 is sometimes called “internet <a href="https://fly.io/blog/32-bit-real-estate/">real-estate</a>”, there have been discussions to drastically limit the size of this loopback range, and use some of it as “normal” IPs. For instance, this <a href="https://www.ietf.org/id/draft-schoen-intarea-unicast-127-00.html">IETF draft</a> proposes to cut the loopback range to <code>127.0.0.0/16</code> (so only addresses between <code>127.0.0.0</code> and <code>127.0.255.255</code>) and make the rest (addresses between <code>127.1.0.0</code> and <code>127.255.255.255</code>) routable on the public internet. The 65536 addresses in <code>127.0.0.0/16</code> should to be enough for almost everyone on a local machine and nearly 16 million IPs could be used as a fresh supply of IPv4 addresses<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<h3 id="and-ipv6">And IPv6?</h3>
<p>Even though IPv6 has a huge namespace, your IPv6 loopback only has one address <code>::1</code>. And that’s quite a shame because, as we have just seen, multiple loopback addresses are quite handy.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>For instance using <a href="https://mkcert.dev/">mkcert</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Admittedly, some addresses like <code>127.0.0.0</code> or <code>127.255.255.255</code> are reserved, but there is still plenty of space.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Whether more useable IPv4 addresses is a good thing is debated. It might divert efforts from the IPv6 transition and even with a few millions more IPv4 addresses, these are still scarce.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Quick Git Commit Amend</title><link>https://joly.pw/blog/tips/quick-git-commit-amend/</link><pubDate>Sun, 21 Nov 2021 13:01:00 +0000</pubDate><guid>https://joly.pw/blog/tips/quick-git-commit-amend/</guid><description>&lt;p&gt;Sometimes when your pull request is reviewed, it turns out that you have to make a small change. For instance, you have to remove a white space. Here is a really quick way to fix it, that will not even fire your editor to change the commit message.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make sure you are on the branch of the pull request (for instance, by reading the output of &lt;code&gt;git status&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Edit and save your file, removing the white space.&lt;/li&gt;
&lt;li&gt;Then in your terminal, use:
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fish" data-lang="fish"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef;font-weight:bold"&gt;git&lt;/span&gt; commit &lt;span style="color:#e06c75"&gt;--amend&lt;/span&gt; &lt;span style="color:#e06c75"&gt;-a&lt;/span&gt; &lt;span style="color:#e06c75"&gt;-v&lt;/span&gt; &lt;span style="color:#e06c75"&gt;-C&lt;/span&gt; HEAD
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;This edits (&lt;code&gt;--amend&lt;/code&gt;) your last commit, adding all the changes made to files (&lt;code&gt;-a&lt;/code&gt;) and reusing the last commit message (&lt;code&gt;-C HEAD&lt;/code&gt;). Once this is done, a summary is printed (&lt;code&gt;-v&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;You can now push your changes with:
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fish" data-lang="fish"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef;font-weight:bold"&gt;git&lt;/span&gt; push &lt;span style="color:#e06c75"&gt;--force-with-lease&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;We need &lt;code&gt;--force-with-lease&lt;/code&gt; to “confirm to the server that we really want to edit the last commit”.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="caution"&gt;Caution&lt;/h2&gt;
&lt;p&gt;Two words of caution with this technique:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Sometimes when your pull request is reviewed, it turns out that you have to make a small change. For instance, you have to remove a white space. Here is a really quick way to fix it, that will not even fire your editor to change the commit message.</p>
<ol>
<li>Make sure you are on the branch of the pull request (for instance, by reading the output of <code>git status</code>)</li>
<li>Edit and save your file, removing the white space.</li>
<li>Then in your terminal, use:
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fish" data-lang="fish"><span style="display:flex;"><span><span style="color:#61afef;font-weight:bold">git</span> commit <span style="color:#e06c75">--amend</span> <span style="color:#e06c75">-a</span> <span style="color:#e06c75">-v</span> <span style="color:#e06c75">-C</span> HEAD
</span></span></code></pre></div>This edits (<code>--amend</code>) your last commit, adding all the changes made to files (<code>-a</code>) and reusing the last commit message (<code>-C HEAD</code>). Once this is done, a summary is printed (<code>-v</code>).</li>
<li>You can now push your changes with:
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fish" data-lang="fish"><span style="display:flex;"><span><span style="color:#61afef;font-weight:bold">git</span> push <span style="color:#e06c75">--force-with-lease</span>
</span></span></code></pre></div>We need <code>--force-with-lease</code> to “confirm to the server that we really want to edit the last commit”.</li>
</ol>
<h2 id="caution">Caution</h2>
<p>Two words of caution with this technique:</p>
<ul>
<li>you are <a href="https://www.atlassian.com/git/tutorials/rewriting-history">rewriting history</a>, if anyone has made changes on top of yours, they will face a confusing situation when they try to merge your changes again. <code>force-with-lease</code> protects us somewhat, as the push will fail if someone else has pushed changes on top of ours, but it won’t help if the other person’s changes are local.</li>
<li>in most situations, commit messages (and their content), should be <a href="https://jeremykun.com/2020/01/14/the-communicative-value-of-using-git-well/?utm_source=pocket_mylist">crafted</a> as an easy to review progression. Abusing this trick could make commits harder to review.</li>
</ul>
]]></content:encoded></item><item><title>Local NeoVim Plugin Development</title><link>https://joly.pw/blog/tips/nvim-plugin-development/</link><pubDate>Tue, 02 Nov 2021 14:28:13 +0000</pubDate><guid>https://joly.pw/blog/tips/nvim-plugin-development/</guid><description>&lt;div class="alert alert-note"&gt;
&lt;p class="alert-heading"&gt;
ℹ️
Note
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-05-20&lt;/strong&gt;: Updated to account for the features of NeoVim 0.9 and obsolete plugins&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;You have found a (Neo)Vim plugin that you want to fiddle with, either to contribute changes upstream or for your own use. Sounds familiar? Here are some tips and tricks I use for my &lt;a href="https://joly.pw/telescope-repo-nvim/"&gt;NeoVim plugin development&lt;/a&gt;. The aim of these small tricks is to iterate faster on changes, by loading your changes in a live NeoVim instance as quickly as possible.&lt;/p&gt;</description><content:encoded><![CDATA[



  
  
  
  

  <div class="alert alert-note">
    <p class="alert-heading">
      ℹ️
      
        Note
      
    </p>
    <p><strong>2023-05-20</strong>: Updated to account for the features of NeoVim 0.9 and obsolete plugins</p>
  </div>



<p>You have found a (Neo)Vim plugin that you want to fiddle with, either to contribute changes upstream or for your own use. Sounds familiar? Here are some tips and tricks I use for my <a href="https://joly.pw/telescope-repo-nvim/">NeoVim plugin development</a>. The aim of these small tricks is to iterate faster on changes, by loading your changes in a live NeoVim instance as quickly as possible.</p>
<p>We will use <a href="https://joly.pw/telescope-repo-nvim/">telescope-repo.nvim</a> as an example but it is applicable to any plugin (although some sections of this post only apply to Lua NeoVim plugins).</p>
<h2 id="load-local-plugin-version">Load Local Plugin Version</h2>
<p>When developing, you make your changes to a local git repository, for instance <code>~/ghq/github.com/cljoly/telescope-repo.nvim</code>. To test those changes, you need to tell NeoVim to load the plugin from the local repository, instead of using the location set by your plugin manager. To do this, just append the following near the beginning of your <code>init.lua</code> file:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#e06c75">vim.opt</span>.<span style="color:#e06c75">runtimepath</span>:<span style="color:#e06c75">prepend</span>(<span style="color:#98c379">&#34;~/ghq/github.com/cljoly/telescope-repo.nvim&#34;</span>)
</span></span></code></pre></div><p>Note the <code>:prepend</code>. It will ensure that your local dev version will override anything installed by your nvim package manager. This way no need to uninstall your plugin when developing!</p>
<h2 id="reloading-changes-in-a-live-neovim-instance">Reloading Changes in a Live NeoVim Instance</h2>
<p>You have now made some changes to the plugin that you would like to test. In doing so, you start a second NeoVim instance and open a set of files, change a bunch of settings…</p>
<p>You then change something in the code, but you don’t want to restart you test NeoVim instance, as that would mean reopening files and altering settings all over again. But just doing <code>require(…)</code> is not enough, because <code>require</code> caches already loaded files and doesn’t reload them if they are loaded already.</p>
<p>If you use <a href="https://github.com/nvim-telescope/telescope.nvim">telescope</a>, you can use the <code>reloader</code> picker. You can then select the module you want to reload, like so:</p>
<figure>
    <img loading="lazy" src="./telescope-reloader.png"
         alt="You type “telescop repo” and the corresponding Lua module surfaces. It will be reloaded when you hit Enter."/> <figcaption>
            Telescope reloader in action<p>You type “telescop repo” and the corresponding Lua module surfaces. It will be reloaded when you hit Enter.</p>
        </figcaption>
</figure>

<p>Under the hood, <code>telescope reload</code> <a href="https://github.com/nvim-telescope/telescope.nvim/blob/587a10d1494d8ffa1229246228f0655db2f0a48a/lua/telescope/builtin/internal.lua#L712">uses plenary</a>:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#e06c75">require</span>(<span style="color:#98c379">&#34;plenary.reload&#34;</span>).<span style="color:#e06c75">reload_module</span>(<span style="color:#e06c75">selection.value</span>)
</span></span></code></pre></div><p>which handle various cases (like whether <a href="https://github.com/lewis6991/impatient.nvim">impatient.nvim</a> is used at the time of writing). Despite this careful handling, sometimes, a plugin may not fully reload. In that case, you want to automate as much of the setup as possible on NeoVim restart.</p>
<h2 id="if-all-else-fails">If All Else Fails</h2>
<p>Sometimes, a “soft” reloading is not enough and you need to restart NeoVim. For instance, if we are testing the <code>:Telescope repo list</code> command and need to open <code>/tmp/file</code>, we can do:</p>
<pre tabindex="0"><code>nvim +&#39;Telescope repo list&#39; /tmp/file
</code></pre><p>and even place this in an infinite loop with a <code>sleep</code> command, to escape the loop more easily once we are done.</p>
<p>Of course, you will want to replace <code>Telescope repo list</code> with the command you want to test. You can also add more setup by supplying multiple “<code>+'…'</code>” arguments)</p>
<h2 id="all-set">All Set</h2>
<p>Now that you are all set, you can go on and write complete plugins! You may find the following resources useful in your journey:</p>
<ul>
<li>the <a href="https://neovim.io/doc/user/lua-guide.html"><code>:help lua-guide.txt</code></a> has a lot of resources to write plugins and alter NeoVim’s configuration,
<ul>
<li><a href="https://www.2n.pl/blog/how-to-write-neovim-plugins-in-lua">2n.pl</a> walks through writing a simple plugin,</li>
</ul>
</li>
<li><a href="https://web.archive.org/web/20211207190156/https://www.chrisatmachine.com/Neovim/28-neovim-lua-development/">set up a Language Server Protocol for Lua</a>,
<ul>
<li>and maybe even a full-blown <a href="https://github.com/folke/neodev.nvim">plugin</a> for Lua plugin development,</li>
</ul>
</li>
<li>to test a piece of Lua code real quick, <code>:=my.lua.code(here)</code> is great. For bigger pieces of code, <a href="https://github.com/rafcamlet/nvim-luapad">luapad</a> can be useful: it provides a scratch buffer where the result of a Lua snippet is displayed as you type.</li>
</ul>
]]></content:encoded></item></channel></rss>