<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Posts about Programming</title><link>https://chriswarrick.com/</link><atom:link href="https://chriswarrick.com/blog/tags/cat_programming.xml" rel="self" type="application/rss+xml" /><description>A rarely updated blog, mostly about programming.</description><lastBuildDate>Wed, 06 May 2026 19:00:00 GMT</lastBuildDate><generator>https://github.com/Kwpolska/YetAnotherBlogGenerator</generator><item><title>Certified 100% Slop</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/</link><pubDate>Wed, 06 May 2026 19:00:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/</guid><description>Recently, a port of Notepad++ to macOS has been making the rounds online, mainly due to the project using the Notepad++ name without permission and in breach of the original author’s trademark. But does it deserve any attention, or is it just AI slop all the way down?
</description><content:encoded><![CDATA[<p>Recently, a port of Notepad++ to macOS has been making the rounds online, mainly due to the project using the Notepad++ name without permission and in breach of the original author’s trademark. But does it deserve any attention, or is it just AI slop all the way down?</p>



<p>After <a href="https://notepad-plus-plus.org/news/npp-trademark-infringement/">the trademark dispute</a>, the port was renamed to Nextpad++. In the contributors section of its <a href="https://github.com/nextpad-plus-plus/nextpad-plus-plus-macos">GitHub page</a>, there are three accounts. The middle one belongs to Claude, Anthropic’s LLM; specifically, this GitHub account is used by <a href="https://claude.com/product/claude-code">Claude Code</a>, an <em>agentic coding tool</em>. Or, alternatively, a vibe-coded app that will vibe-code anything you ask for, as long as you pay for the (temporarily heavily subsidized) subscription fee.</p>
<figure class="figure border rounded float-end ms-2 mb-2">
<a href="https://chriswarrick.com/images/2026-05-06-nextpad-plus-plus-macos-contributors.png" class="image-reference">
<img class="figure-img rounded mb-0" src="https://chriswarrick.com/images/2026-05-06-nextpad-plus-plus-macos-contributors.thumbnail.png" alt="The contributors of Nextpad++.">
</a>
<figcaption class="figure-caption text-center mt-1 mb-1">The contributors of Nextpad++.</figcaption>
</figure>
<p>There were 191 commits in the repository at the time of writing. Let’s check out the <a href="https://github.com/nextpad-plus-plus/nextpad-plus-plus-macos/graphs/contributors">contributors</a> page:</p>
<ul>
<li><code>@aletik</code>: 188 commits, 747k lines added, 129k lines deleted</li>
<li><code>@claude</code>: 181 commits, 734k lines addded, 129k lines deleted</li>
<li><code>@christianbaumann</code>: 2 commits, 48 lines added, 44 lines deleted</li>
</ul>
<p>This codebase was written almost entirely by Claude. Furthermore, it is easy to notice Claudisms when looking at commits not attributed to Claude, such as <a href="https://github.com/nextpad-plus-plus/nextpad-plus-plus-macos/blob/71b1a8b2fddc00af3706e69e5bb0abcc63e23a2f/src/ColumnEditorPanel.mm#L4">section headers made out of em-dashes in the initial commit (11k lines added)</a>. Another <a href="https://github.com/nextpad-plus-plus/nextpad-plus-plus-macos/commit/480f2700b7f5950c39b5748ea99145f88bd8a048">commit without a Claude attribution</a> has an extremely long commit message — again, very Claude-y, very em-dash-y<a id="fnref:1" href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#fn:1" class="footnote-ref"><sup>1</sup></a>.</p>
<p>The Claude Code attribution is the last line of the commit message. For example, here’s a random commit<a id="fnref:2" href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#fn:2" class="footnote-ref"><sup>2</sup></a>:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-1" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-1"></a>$ git show --stat 8e2b0749fc4354532d89572fb7b6ae7ec6bf8e41
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-2" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-2"></a>commit 8e2b0749fc4354532d89572fb7b6ae7ec6bf8e41
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-3" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-3"></a>Author: Andrey Letov &lt;aletik@gmail.com&gt;
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-4" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-4"></a>Date:&nbsp;&nbsp;&nbsp;Fri Apr 24 17:57:25 2026 -0400
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-5" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-5"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-6" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-6"></a>&nbsp;&nbsp;&nbsp;&nbsp;Bump host to 1.0.5
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-7" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-7"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-8" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-8"></a>&nbsp;&nbsp;&nbsp;&nbsp;CMakeLists.txt (BUNDLE_VERSION + SHORT_VERSION_STRING) and
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-9" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-9"></a>&nbsp;&nbsp;&nbsp;&nbsp;resources/Info.plist (CFBundleVersion + CFBundleShortVersionString)
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-10" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-10"></a>&nbsp;&nbsp;&nbsp;&nbsp;roll from 1.0.4 → 1.0.5. Local DMG built but not pushed / notarized
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-11" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-11"></a>&nbsp;&nbsp;&nbsp;&nbsp;yet — release ships in a couple of days.
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-12" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-12"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-13" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-13"></a>&nbsp;&nbsp;&nbsp;&nbsp;Headline addition since 1.0.4:
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-14" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-14"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Pin / unpin toggle on popped side panels (defaults to unpinned;
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-15" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-15"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;was forced always-on-top in v1.0.4).
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-16"><code data-line-number="16"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-16" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-16"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-17"><code data-line-number="17"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-17" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-17"></a>&nbsp;&nbsp;&nbsp;&nbsp;Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-18"><code data-line-number="18"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-18" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-18"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-19"><code data-line-number="19"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-19" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-19"></a> CMakeLists.txt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 4 ++--
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-20"><code data-line-number="20"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-20" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-20"></a> resources/Info.plist | 4 ++--
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-21"><code data-line-number="21"></code></a></td><td class="code"><code><a id="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-21" name="code_74f8e058cc97094fe3f0e4cfc013b6e55bfa22d2-21"></a> 2 files changed, 4 insertions(+), 4 deletions(-)
</code></td></tr></table></div>
<p>GitHub picks up those attribution lines and shows them when viewing commits (“<strong>user</strong> and <strong>claude</strong> committed”), and includes them in the commit tally on the contributors page. But how does Git know to add this attribution? Is it some magic feature where Claude secretly writes a file for Git to pick up? Nope! Claude will include that attribution when it commits the changes. But by default, Claude will <em>not</em> commit anything when it finishes implementing your request. You need to <strong>explicitly</strong> ask it to commit, or include that in your instructions files (e.g., <code>CLAUDE.md</code>).<a id="fnref:3" href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#fn:3" class="footnote-ref"><sup>3</sup></a></p>
<p>If someone were to review the changes before committing, they would most likely do it in a code editor, navigating using the Git pane, so they see the commit box right in front of them, and they could just spend a minute writing a reasonable commit message. But nah, why bother with code review, let’s just <a href="https://www.macrumors.com/2026/04/29/notepad-plus-plus-editor-comes-to-mac/">vibe our way onto MacRumors</a>.</p>
<p>So: if you see the Claude attribution appear in a commit, you can be sure the commit is unreviewed <a href="https://en.wikipedia.org/wiki/AI_slop">slop</a>. And if virtually all commits in a project have a Claude attribution, the project is <strong>certified 100% slop</strong>. Especially since <a href="https://code.claude.com/docs/en/settings#attribution-settings">you can disable the attribution in Claude configuration</a>, so the authors of those projects don’t care at all about hiding their code’s sloppiness.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn:1">
<p>LLMs learning to use em-dashes from well-typeset books has ruined good typography. I’ve been using a <a href="https://chriswarrick.com/projects/kwkeyboard/">custom keyboard layout</a> since 2012, with em-dashes and “smart” quotes, but I’ve significantly limited the use of those characters since they became the tell-tale signs of LLM writing. (This post is 100% human-written.)<a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#fnref:1" class="footnote-back-ref">&#8617;</a></p>
</li>
<li id="fn:2">
<p>I picked a relatively recent one, with a fairly short commit message, an Unicode arrow (→), an em-dash, and where the only change is updating the version numbers in two files. This is why we can’t have nice things (and RAM).<a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#fnref:2" class="footnote-back-ref">&#8617;</a></p>
</li>
<li id="fn:3">
<p>It should be noted that VS Code has recently introduced a feature where it will sneakily add a Copilot attribution, and they managed to <a href="https://github.com/microsoft/vscode/pull/310226">make it apply it to <strong>all</strong> commits, even when AI features are disabled</a> (why was that <code>all</code> value even implemented?), but <a href="https://github.com/microsoft/vscode/blob/main/extensions/git/src/repository.ts#L1489">that feature attributes Copilot</a>, not Claude, even if you’re using Claude models within VS Code.<a href="https://chriswarrick.com/blog/2026/05/06/certified-100-percent-slop/#fnref:3" class="footnote-back-ref">&#8617;</a></p>
</li>
</ol>
</div>
]]></content:encoded><category>Programming</category><category>AI</category><category>Claude</category><category>Copilot</category><category>GitHub</category><category>LLM</category><category>programming</category></item><item><title>Docker In WSL: A No-Frills Guide</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/</link><pubDate>Wed, 04 Mar 2026 17:20:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/</guid><description>Docker is great, but how do you run Linux containers on Windows? In WSL, of course. The Docker Desktop application is certainly an option, but it eats up a lot of RAM thanks to its Electron-based GUI. It also has an LLM chatbot (because of course it does, it’s 2026 after all). Just the Docker Desktop installer takes up 598 MB. What if you want something simpler and with less RAM consumption? WSL 2 makes it really straightforward to set up Docker with some basic Windows integration.
</description><content:encoded><![CDATA[<p>Docker is great, but how do you run Linux containers on Windows? In WSL, of course. The Docker Desktop application is certainly an option, but it eats up a lot of RAM thanks to its Electron-based GUI. It also has an LLM chatbot (because of course it does, it’s 2026 after all). Just the Docker Desktop installer takes up 598 MB. What if you want something simpler and with less RAM consumption? WSL 2 makes it really straightforward to set up Docker with some basic Windows integration.</p>



<p>(Also, Docker Desktop demands payment for enterprise use; if your company fits the enterprise criteria but cannot afford $16/developer/month, run.)</p>
<p><em>Console command conventions: <code>$</code> means Linux, <code>&gt;</code> means Windows (PowerShell).<br>Path conventions: <code>/</code> means Linux, <code>\</code> means Windows.</em></p>
<h2 id="linux-setup">Linux setup</h2>
<p>You need to have WSL and a distribution installed, and you must be using WSL 2. <a href="https://learn.microsoft.com/en-us/windows/wsl/install">Read the install docs if you need to do it.</a></p>
<p>➡️ Start by installing Docker in the usual way for your Linux distribution of choice. I’m using Ubuntu with <a href="https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository">the official Docker apt repository</a>. Make sure to <a href="https://docs.docker.com/engine/install/linux-postinstall">add yourself to the Docker group</a>.</p>
<p>➡️ Enable systemd support in WSL. Put those two lines into <code>/etc/wsl.conf</code>:</p>
<div class="highlight"><pre><span></span><span class="k">[boot]</span>
<span class="na">systemd</span><span class="o">=</span><span class="s">true</span>
</pre></div>

<p>You can do it like so (if you don’t have a <code>wsl.conf</code> file already):</p>
<div class="highlight"><pre><span></span><span class="gp">$ </span><span class="nb">printf</span><span class="w"> </span><span class="s1">&#39;[boot]\nsystemd=true\n&#39;</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sudo<span class="w"> </span>tee<span class="w"> </span>/etc/wsl.conf
</pre></div>

<p>➡️ Next, enable the systemd services:</p>
<div class="highlight"><pre><span></span><span class="gp">$ </span>sudo<span class="w"> </span>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>containerd.service
<span class="gp">$ </span>sudo<span class="w"> </span>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>docker.service
</pre></div>

<h2 id="exposing-docker-to-windows">Exposing Docker to Windows</h2>
<p>By default, Docker only listens on a Unix domain socket. To work with Docker from Windows, it needs to listen on a TCP socket. If you’re fine with using Docker only from the WSL terminal, and won’t run any Docker-compatible tools on the Windows side, you can basically stop reading here.</p>
<p>Adding a socket can be done in two ways: by adding command-line arguments, or by modifying <code>/etc/docker/daemon.json</code>. If your Docker systemd service is passing in arguments, you need to edit the service, and can’t do it using the <code>daemon.json</code> file. Let’s edit the service, as this is more likely to be what you need.</p>
<p>➡️ Run <code>sudo systemctl edit docker.service</code> and override the <code>ExecStart</code> command. The first <code>ExecStart=</code> line clears out the existing configuration defined in the system-provided service. The second line is the new command. To avoid breaking things, review the <code>ExecStart</code> command that is shown as the current content of your <code>docker.service</code>, and make sure you have both <code>-H</code> arguments as in my example below.</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-1" name="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-1"></a><span class="c1">### Editing /etc/systemd/system/docker.service.d/override.conf</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-2" name="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-2"></a><span class="c1">### Anything between here and the comment below will become the contents of the drop-in file</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-3" name="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-3"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-4" name="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-4"></a><span class="k">[Service]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-5" name="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-5"></a><span class="na">ExecStart</span><span class="o">=</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-6"><code data-line-number="6"></code></a></td><td class="code"><code><a id="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-6" name="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-6"></a><span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/bin/dockerd -H fd:// -H tcp://127.0.0.1:2375 --containerd=/run/containerd/containerd.sock</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-7"><code data-line-number="7"></code></a></td><td class="code"><code><a id="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-7" name="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-7"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-8"><code data-line-number="8"></code></a></td><td class="code"><code><a id="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-8" name="code_74e3f0c1e66ee254ad53204ffcc30ad66875b005-8"></a><span class="c1">### Edits below this comment will be discarded</span>
</code></td></tr></table></div>
<p>➡️ We’re done with the WSL setup, so let’s restart WSL and make sure Docker is working:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-1" name="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-1"></a>&gt; wsl --shutdown
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-2" name="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-2"></a>&gt; wsl docker run --rm hello-world
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-3" name="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-3"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-4" name="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-4"></a>Hello from Docker!
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-5" name="code_2c45ca58d73b1fb5d17bb46934173dcfb55b65e3-5"></a>This message shows that your installation appears to be working correctly.
</code></td></tr></table></div>
<h2 id="windows-setup">Windows setup</h2>
<p>➡️ Download the latest version of the <a href="https://download.docker.com/win/static/stable/x86_64/">Docker binaries</a>. Extract <code>docker.exe</code> and put it somewhere on your Windows <code>PATH</code>. I have a <code>~\Tools\bin</code> folder for things like that.</p>
<p>We need to tell the Docker CLI where to look for Docker. The easiest way to do this is to set the <code>DOCKER_HOST</code> environment variable. This might not be the cleanest way if you want to work with Windows containers or Docker Desktop, but you don’t, so we don’t need to bother with anything nicer.</p>
<p>➡️ Press the Start key, type <em>environment variables</em> (or the equivalent phrase in your Windows language) and open the environment variables editor. Add an environment variable named <code>DOCKER_HOST</code> with the value <code>tcp://127.0.0.1:2375</code>.</p>
<p>➡️ Restart your Terminal. In one tab, run a WSL shell. In another, run PowerShell (or cmd):</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-1" name="code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-1"></a>&gt; docker run -it --rm hello-world
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-2" name="code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-3" name="code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-3"></a>Hello from Docker!
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-4" name="code_71178a5b7990c2f9c7621fcb3b389c2f84e8c174-4"></a>This message shows that your installation appears to be working correctly.
</code></td></tr></table></div>
<h2 id="optional-docker-compose">Optional: Docker Compose</h2>
<p>Docker Compose is a plugin for Docker CLI, and it not included in the Docker binary we’ve installed on Windows. It is quite easy to add it in if you want.</p>
<p>➡️ Download the latest version of the <a href="https://github.com/docker/compose/releases/latest">Docker Compose binary</a> (<code>docker-compose-windows-x86_64.exe</code>). Move it to <code>~\.docker\cli-plugins\docker-compose.exe</code>.</p>
<div class="highlight"><pre><span></span>&gt; mkdir ~\.docker\cli-plugins
&gt; mv ~\Downloads\docker-compose-windows-x86_64.exe ~\.docker\cli-plugins\docker-compose.exe
</pre></div>

<p>Let’s test it out:</p>
<div class="highlight"><pre><span></span>&gt; docker compose version
Docker Compose version v5.1.0
</pre></div>

<h2 id="optional-wsl-vm-management">Optional: WSL VM management</h2>
<p>WSL does not automatically start the Linux VM. And it kills it if no user process is running inside of it.</p>
<p>If you’re fine with having a WSL terminal open while you’re working with Docker, you don’t need to do anything. But if you don’t want to see a WSL terminal, <a href="https://askubuntu.com/questions/1177273/is-there-an-easy-way-to-have-wsl-ubuntu-services-start-automatically-on-windows">make Windows start WSL when you log in</a> and set a really large <em>VM Idle Timeout</em> in the <em>Optional Features</em> tab of the <em>WSL Settings</em> app. The maximum value accepted by the GUI<a id="fnref:1" href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#fn:1" class="footnote-ref"><sup>1</sup></a> is the maximum value a 32-bit integer can represent, i.e. 2147483647 ms (24 days). You can also manually add the option to <code>~\.wslconfig</code>:</p>
<div class="highlight"><pre><span></span><span class="k">[wsl2]</span>
<span class="na">vmIdleTimeout</span><span class="o">=</span><span class="s">2147483647</span>
</pre></div>

<div class="footnotes">
<hr>
<ol>
<li id="fn:1">
<p>If you try to input a larger number, the app just crashes. That’s what you get when you fire your QA department and let AI take over coding.<a href="https://chriswarrick.com/blog/2026/03/04/docker-in-wsl-a-no-frills-guide/#fnref:1" class="footnote-back-ref">&#8617;</a></p>
</li>
</ol>
</div>
]]></content:encoded><category>Programming</category><category>Docker</category><category>Linux</category><category>Windows</category><category>WSL</category></item><item><title>Spawning subprocesses smartly and securely</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/</link><pubDate>Sat, 02 Sep 2017 18:40:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/</guid><description>
As part of your code, you may be inclined to call a command to do
something. But is it always a good idea? How to do it safely? What happens
behind the scenes?
</description><content:encoded><![CDATA[
<p>As part of your code, you may be inclined to call a command to do
something. But is it always a good idea? How to do it safely? What happens
behind the scenes?</p>



<p>This article is written from a general perspective, with a Unix/C bias and a
very slight Python bias. The problems mentioned apply to all languages in most
environments, including Windows.</p>
<section id="use-the-right-tool-for-the-job">
<h1>Use the right tool for the job</h1>
<p>By calling another process, you introduce a third-party dependency.
That dependency isn’t controlled by your code, and your code becomes more fragile.
The problems include:</p>
<ul class="simple">
<li><p>the program is not installed, or even available, for the user’s OS of choice</p></li>
<li><p>the program is not in the <code class="docutils literal">$PATH</code> your process gets</p></li>
<li><p>the hard-coded path is not correct on the end user’s system</p></li>
<li><p>the program is in a different version (eg. GNU vs. BSD, updates/patches),
which means different option names or other behaviors</p></li>
<li><p>the program’s output is not what you expected due to user config (including
locale)</p></li>
<li><p>error reporting is based on numeric exit codes, and the meaning of those
differs between programs (<em>if</em> they have meaning besides 0/1 in the first
place)</p></li>
</ul>
<p>On the other hand, if your code uses a lot of subprocesses, perhaps you should
stay with Bash. You can do the harder parts with Python, Ruby, or some other
language by calling them from within your Bash script.</p>
</section>
<section id="dont-spawn-subprocesses-if-theres-an-alternative">
<h1>Don’t spawn subprocesses if there’s an alternative</h1>
<p>Spawning a subprocess always incurs a (minor) <a class="brackets" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-1" id="footnote-reference-1" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> performance hit minor
compared to the alternatives. With that in mind, and the resiliency issues
listed above, you should always try to find an alternative for the
external command.</p>
<p>The simplest ones are the basic Unix utilities. Replace <code class="docutils literal">grep</code>, <code class="docutils literal">sed</code> and
<code class="docutils literal">awk</code> with string operations and regular expressions. Filesystem utilities
will have equivalents — for Python, in <code class="docutils literal">os</code> or <code class="docutils literal">shutil</code>. Your language of
choice can also handle things like networking (don’t call <code class="docutils literal">curl</code>), file
compression, working with date/time…</p>
<p>Similarly, you should check if there are packages available that already do
what you want — library bindings or re-implementations. And if there isn’t,
perhaps you could help the world by writing one of those and sharing it?</p>
<p>One more important thing: if the program uses the same language as your code,
then you should try to import the code and run it from the same process instead
of spawning a process, if this is feasible.</p>
</section>
<section id="security-considerations-shells-spaces-and-command-injection">
<h1>Security considerations: shells, spaces, and command injection</h1>
<p>We come to the most important part of this article: how to spawn subprocesses
without compromising your system. When you spawn a subprocess on a typical Unix
system,  <code class="docutils literal">fork()</code> is called, and your process is copied. Many modern Unix
systems have a copy-on-write implementation of that syscall, meaning that the
operation does not result in copying all the memory of the host process over.
Forking is (almost) immediately followed by calling <code class="docutils literal">execve()</code> (or a helper
function from the exec family) <a class="brackets" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-2" id="footnote-reference-2" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> in the child process — that function
<em>transforms the calling process into a new process</em> <a class="brackets" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-3" id="footnote-reference-3" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>. This technique is
called <em>fork-exec</em> and is the typical way to spawn a new process on Unix. <a class="brackets" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-4" id="footnote-reference-4" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a></p>
<p>There are two ways to access this API, from the C perspective:</p>
<ul>
<li><p>directly, by calling <code class="docutils literal">fork()</code> and <code class="docutils literal"><span class="pre">exec*()</span></code> (or <code class="docutils literal">posix_spawn()</code>), and providing an array of
arguments passed to the process, or</p></li>
<li><p>through the shell (<code class="docutils literal">sh</code>), usually by calling <code class="docutils literal">system()</code>. As Linux’s
manpage for <code class="docutils literal">system(3)</code> puts it,</p>
<blockquote>
<p>The <code class="docutils literal">system()</code> library function uses <code class="docutils literal">fork(2)</code> to create a child process that executes the shell command specified in command using <code class="docutils literal">execl(3)</code> as follows:</p>
<div class="code"><pre class="code c"><a id="rest_code_ba3def1e6d134f318af0424fea199c9a-1" name="rest_code_ba3def1e6d134f318af0424fea199c9a-1" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_ba3def1e6d134f318af0424fea199c9a-1"></a><span class="n">execl</span><span class="p">(</span><span class="s">&quot;/bin/sh&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;sh&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;-c&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
</pre></div>
</blockquote>
</li>
</ul>
<p>If you go through the shell, you pass one string argument, whereas <code class="docutils literal"><span class="pre">exec*()</span></code> demands you to specify arguments separately. Let’s write a sample program to print all the arguments it receives. I’ll do it in Python to get a more readable output.</p>
<div class="code"><pre class="code python"><a id="rest_code_ce72efbf58624ae598862ad3319d5d48-1" name="rest_code_ce72efbf58624ae598862ad3319d5d48-1" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_ce72efbf58624ae598862ad3319d5d48-1"></a><span class="ch">#!/usr/bin/env python3</span>
<a id="rest_code_ce72efbf58624ae598862ad3319d5d48-2" name="rest_code_ce72efbf58624ae598862ad3319d5d48-2" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_ce72efbf58624ae598862ad3319d5d48-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
<a id="rest_code_ce72efbf58624ae598862ad3319d5d48-3" name="rest_code_ce72efbf58624ae598862ad3319d5d48-3" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_ce72efbf58624ae598862ad3319d5d48-3"></a><span class="nb">print</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span>
</pre></div>
<p>Let’s see what appears:</p>
<div class="code"><pre class="code text"><a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-1" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-1" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-1"></a>$ ./argv.py foo bar
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-2" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-2" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-2"></a>[&#39;./argv.py&#39;, &#39;foo&#39;, &#39;bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-3" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-3" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-3"></a>$ ./argv.py &#39;foo bar&#39;
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-4" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-4" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-4"></a>[&#39;./argv.py&#39;, &#39;foo bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-5" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-5" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-5"></a>$ ./argv.py foo\ bar baz
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-6" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-6" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-6"></a>[&#39;./argv.py&#39;, &#39;foo bar&#39;, &#39;baz&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-7" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-7" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-7"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-8" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-8" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-8"></a>$ ./argv.py $(date)
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-9" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-9" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-9"></a>[&#39;./argv.py&#39;, &#39;Sat&#39;, &#39;Sep&#39;, &#39;2&#39;, &#39;16:54:52&#39;, &#39;CEST&#39;, &#39;2017&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-10" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-10" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-10"></a>$ ./argv.py &quot;$(date)&quot;
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-11" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-11" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-11"></a>[&#39;./argv.py&#39;, &#39;Sat Sep  2 16:54:52 CEST 2017&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-12" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-12" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-12"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-13" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-13" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-13"></a>$ ./argv.py /usr/*
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-14" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-14" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-14"></a>[&#39;./argv.py&#39;, &#39;/usr/X11&#39;, &#39;/usr/X11R6&#39;, &#39;/usr/bin&#39;, &#39;/usr/include&#39;, &#39;/usr/lib&#39;, &#39;/usr/libexec&#39;, &#39;/usr/local&#39;, &#39;/usr/sbin&#39;, &#39;/usr/share&#39;, &#39;/usr/standalone&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-15" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-15" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-15"></a>$ ./argv.py &quot;/usr/*&quot;
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-16" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-16" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-16"></a>[&#39;./argv.py&#39;, &#39;/usr/*&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-17" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-17" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-17"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-18" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-18" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-18"></a>$ ./argv.py $EDITOR
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-19" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-19" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-19"></a>[&#39;./argv.py&#39;, &#39;nvim&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-20" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-20" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-20"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-21" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-21" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-21"></a>$ $PWD/argv.py foo bar
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-22" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-22" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-22"></a>[&#39;/Users/kwpolska/Desktop/blog/subprocess/argv.py&#39;, &#39;foo&#39;, &#39;bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-23" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-23" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-23"></a>$ ./argv.py a{b,c}d
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-24" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-24" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-24"></a>[&#39;./argv.py&#39;, &#39;abd&#39;, &#39;acd&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-25" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-25" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-25"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-26" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-26" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-26"></a>$ python argv.py foo bar | cat
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-27" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-27" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-27"></a>[&#39;argv.py&#39;, &#39;foo&#39;, &#39;bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-28" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-28" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-28"></a>$ python argv.py foo bar &gt; foo.txt
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-29" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-29" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-29"></a>$ cat foo.txt
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-30" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-30" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-30"></a>[&#39;argv.py&#39;, &#39;foo&#39;, &#39;bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-31" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-31" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-31"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-32" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-32" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-32"></a>$ ./argv.py foo; ls /usr
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-33" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-33" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-33"></a>[&#39;./argv.py&#39;, &#39;foo&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-34" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-34" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-34"></a>X11@        X11R6@      bin/        include/    lib/        libexec/    local/      sbin/       share/      standalone/
</pre></div>
<p>As you can see, the following things are handled by the shell (the process is unaware of this occurring):</p>
<ul class="simple">
<li><p>quotes and escapes</p></li>
<li><p>expanding expressions in braces</p></li>
<li><p>expanding variables</p></li>
<li><p>wildcards (glob, <code class="docutils literal">*</code>)</p></li>
<li><p>redirections and pipes (<code class="docutils literal">&gt; &gt;&gt; |</code>)</p></li>
<li><p>command substitution (backticks or <code class="docutils literal"><span class="pre">$(…)</span></code>)</p></li>
<li><p>running multiple commands on the same line (<code class="docutils literal">; &amp;&amp; || &amp;</code>)</p></li>
</ul>
<p>The list is full of potential vulnerabilities. If end users are in control of
the arguments passed, and you go through the shell, they can
<strong>execute arbitrary commands</strong> or even <strong>get full shell access</strong>. Even in other
cases, you’ll have to <em>depend on the shell’s parsing</em>, which introduces an
unnecessary indirection.</p>
</section>
<section id="tl-dr-how-to-do-this-properly-in-your-language-of-choice">
<h1>TL;DR: How to do this properly in your language of choice</h1>
<p>To ensure spawning subprocess is done securely, <strong>do not use the shell in between</strong>. If you need any of the operations I listed above as part of your command — wildcards, pipes, etc. — you will need to take care of them in your code; most languages have those features built-in.</p>
<dl class="simple dl-horizontal">
<dt>In C (Unix)</dt>
<dd><p>Perform fork-exec by yourself, or use <code class="docutils literal">posix_spawn()</code>. This also lets you communicate with the process if you open a pipe and make it stdout of the child process. Never use <code class="docutils literal">system()</code>.</p>
</dd>
<dt>In Python</dt>
<dd><p>Use the subprocess module. Always pass <code class="docutils literal">shell=False</code> and give it a <em>list</em> of arguments. With asyncio, use <code class="docutils literal">asyncio.create_subprocess_exec</code> (and not <code class="docutils literal">_shell</code>), but note it takes <code class="docutils literal">*args</code> and not a list. Never use <code class="docutils literal">os.system</code> and <code class="docutils literal">os.popen</code>.</p>
</dd>
<dt>In Ruby</dt>
<dd><p>Pass arrays to <code class="docutils literal">IO.popen</code>. Pass multiple arguments to <code class="docutils literal">system()</code> (<code class="docutils literal"><span class="pre">system([&quot;ls&quot;,</span> <span class="pre">&quot;ls&quot;])</span></code> or <code class="docutils literal"><span class="pre">system(&quot;ls&quot;,</span> <span class="pre">&quot;-l&quot;)</span></code>). Never use <code class="docutils literal">%x{command}</code> or backticks.</p>
</dd>
<dt>In Java</dt>
<dd><p>Pass arrays to <code class="docutils literal">Runtime.exec</code>. Pass multiple arguments or list to <code class="docutils literal">ProcessBuilder</code>.</p>
</dd>
<dt>In PHP</dt>
<dd><p>All the standard methods go through the shell. Try <code class="docutils literal">escapeshellcmd()</code>, <code class="docutils literal">escapeshellarg()</code> — or better, switch to Python. Or anything, really.</p>
</dd>
<dt>In Go</dt>
<dd><p><code class="docutils literal">os/exec</code> and <code class="docutils literal">os.StartProcess</code> are safe.</p>
</dd>
<dt>In Node.js</dt>
<dd><p>Use <code class="docutils literal">child_process.execFile</code> or <code class="docutils literal">child_process.spawn</code> with <code class="docutils literal">shell</code> set to false.</p>
</dd>
<dt>Elsewhere</dt>
<dd><p>You should be able to specify multiple strings (using variadic arguments,
arrays, or otherwise standard data structures of your language of choice) as
the command line. Otherwise, you might be running into something
shell-related.</p>
</dd>
</dl>
</section>
<section id="the-part-where-i-pretend-i-know-something-about-windows">
<h1>The part where I pretend I know something about Windows</h1>
<p>On Windows, argument lists are always passed to processes as strings (Python
joins them semi-intelligently if it gets a list). Redirections and variables
work in shell mode, but globs (asterisks) are always left for the called
process to handle.</p>
<p>Some useful functions are implemented as shell built-ins — in that case, you
need to call it via the shell.</p>
<p>Internals: There is no <code class="docutils literal">fork()</code> on Windows. Instead, <code class="docutils literal">CreateProcess()</code>,
<code class="docutils literal">ShellExecute()</code>, or lower-level <code class="docutils literal"><span class="pre">spawn*()</span></code> functions are used. <code class="docutils literal">cmd.exe
/c</code> is called in shell calls.</p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="footnote-1" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-reference-1">1</a><span class="fn-bracket">]</span></span>
<p>Unless your operating system does not implement copy-on-write forking — in that case, you might even run out of memory if you use too much of it.</p>
</aside>
<aside class="footnote brackets" id="footnote-2" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-reference-2">2</a><span class="fn-bracket">]</span></span>
<p>The function that does the real work is <code class="docutils literal">execve()</code>, which takes an exact path, an array of arguments, and takes environment variables as input. Other variants can also perform a <code class="docutils literal">$PATH</code> search, take argv as variadic arguments, and inherit environment from the current process. <code class="docutils literal">execl()</code> does the last two.</p>
</aside>
<aside class="footnote brackets" id="footnote-3" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-reference-3">3</a><span class="fn-bracket">]</span></span>
<p>Quoted from <code class="docutils literal">execve(2)</code> <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=execve&amp;sektion=2">man page</a> from FreeBSD.</p>
</aside>
<aside class="footnote brackets" id="footnote-4" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-reference-4">4</a><span class="fn-bracket">]</span></span>
<p>An alternative is <code class="docutils literal">posix_spawn()</code>, but it usually does fork-exec, unless your platform does not support forking.</p>
</aside>
</aside>
</section>
]]></content:encoded><category>Programming</category><category>best practices</category><category>C</category><category>devel</category><category>guide</category><category>Linux</category><category>Python</category><category>security</category><category>subprocess</category><category>Unix</category></item><item><title>Apple broke the display menu, so I wrote my own</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/06/24/apple-broke-the-display-menu-so-i-wrote-my-own/</link><pubDate>Sat, 24 Jun 2017 19:02:47 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/06/24/apple-broke-the-display-menu-so-i-wrote-my-own/</guid><description>
A short time ago, the macOS display menu stopped working for me. It no longer had options to change mirroring settings, only supporting AirPlay. So I wrote my own, also solving some other issues.
</description><content:encoded><![CDATA[
<p>A short time ago, the macOS display menu stopped working for me. It no longer had options to change mirroring settings, only supporting AirPlay. So I wrote my own, also solving some other issues.</p>



<p>The first thing to consider is: what features do I really want? I’m using a MacBook Pro with an external display. I sometimes need to switch to only one display <a class="brackets" href="https://chriswarrick.com/blog/2017/06/24/apple-broke-the-display-menu-so-i-wrote-my-own/#footnote-1" id="footnote-reference-1" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> — mirroring is useful here. Although I can afford to put the dock at the bottom in dual-screen mode, it works better on the right if I’m tight on space. <a class="brackets" href="https://chriswarrick.com/blog/2017/06/24/apple-broke-the-display-menu-so-i-wrote-my-own/#footnote-2" id="footnote-reference-2" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> Also when working on the MacBook screen, I can switch to a higher resolution. So, I need:</p>
<ul class="simple">
<li><p>mirroring</p></li>
<li><p>screen resolution</p></li>
<li><p>dock position and icon size</p></li>
</ul>
<p>But I don’t want to pick all those three independently — a preset, like <em>dual screen</em> or <em>MacBook only, 1440×900</em> works better.</p>
<p>So, I wrote <strong>Display Menu</strong>. It’s a simple menu bar extra — I haven’t yet built any friendly configuration GUI for it, so all you get for now is a JSON file. It’s roughly 600 lines of Swift. The app doesn’t do much, other than displaying an icon in the menu bar, and setting display preferences when asked to. But hey, it works for me.</p>
<p>Also, I must admit that Swift is a pretty nifty thing. Although the function to read JSON files needs to do a ton of type casting, and some of the low-level stuff looks as ugly as in C, but other than that, Swift is a modern, friendly language.</p>
<p>Display Menu is open-source, licensed under the 3-clause BSD license. <a class="reference external" href="https://github.com/Kwpolska/DisplayMenu">Fork it on GitHub</a> or <a class="reference external" href="https://github.com/Kwpolska/DisplayMenu/releases">download binary releases</a>.</p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="footnote-1" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/06/24/apple-broke-the-display-menu-so-i-wrote-my-own/#footnote-reference-1">1</a><span class="fn-bracket">]</span></span>
<p>Inkscape/Xorg don’t work well with multiple displays. I can also mirror and turn off the external screen or use it with some other device.</p>
</aside>
<aside class="footnote brackets" id="footnote-2" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/06/24/apple-broke-the-display-menu-so-i-wrote-my-own/#footnote-reference-2">2</a><span class="fn-bracket">]</span></span>
<p>also, in dual-screen mode, I can have the dock on one screen only, and the dock must live on the edge of the “extended” display — so either on the left side of the MacBook screen, or on the right side of the external display.</p>
</aside>
</aside>
]]></content:encoded><category>Programming</category><category>app</category><category>Apple</category><category>display</category><category>programming</category><category>projects</category><category>Swift</category></item><item><title>Unix locales vs Unicode (‘ascii’ codec can’t encode character…)</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/</link><pubDate>Sun, 18 Jun 2017 18:40:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/</guid><description>
You might get unusual errors about Unicode and inability to convert
to ASCII. Programs might just crash at random. Those are often simple to fix —
all you need is correct locale configuration.
</description><content:encoded><![CDATA[
<p>You might get unusual errors about Unicode and inability to convert
to ASCII. Programs might just crash at random. Those are often simple to fix —
all you need is correct locale configuration.</p>



<p class="lead">Has this ever happened to you?</p>
<div class="code"><pre class="code pytb"><a id="rest_code_526327b4277f4a8497b67746e0a751b2-1" name="rest_code_526327b4277f4a8497b67746e0a751b2-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_526327b4277f4a8497b67746e0a751b2-1"></a><span class="gt">Traceback (most recent call last):</span>
<a id="rest_code_526327b4277f4a8497b67746e0a751b2-2" name="rest_code_526327b4277f4a8497b67746e0a751b2-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_526327b4277f4a8497b67746e0a751b2-2"></a>  File <span class="nb">&quot;aogonek.py&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
<a id="rest_code_526327b4277f4a8497b67746e0a751b2-3" name="rest_code_526327b4277f4a8497b67746e0a751b2-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_526327b4277f4a8497b67746e0a751b2-3"></a><span class="w">    </span><span class="nb">print</span><span class="p">(</span><span class="sa">u</span><span class="s1">&#39;</span><span class="se">\u0105</span><span class="s1">&#39;</span><span class="p">)</span>
<a id="rest_code_526327b4277f4a8497b67746e0a751b2-4" name="rest_code_526327b4277f4a8497b67746e0a751b2-4" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_526327b4277f4a8497b67746e0a751b2-4"></a><span class="gr">UnicodeEncodeError</span>: <span class="n">&#39;ascii&#39; codec can&#39;t encode character &#39;\u0105&#39; in position 0: ordinal not in range(128)</span>
</pre></div>
<div class="code"><pre class="code text"><a id="rest_code_ca5594fd2ef54ad38a77f0c5883c3188-1" name="rest_code_ca5594fd2ef54ad38a77f0c5883c3188-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_ca5594fd2ef54ad38a77f0c5883c3188-1"></a>Nikola: Could not guess locale for language en, using locale C
</pre></div>
<div class="code"><pre class="code text"><a id="rest_code_f5ea18fead964936bccf8b8666032087-1" name="rest_code_f5ea18fead964936bccf8b8666032087-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_f5ea18fead964936bccf8b8666032087-1"></a>Input: ą
<a id="rest_code_f5ea18fead964936bccf8b8666032087-2" name="rest_code_f5ea18fead964936bccf8b8666032087-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_f5ea18fead964936bccf8b8666032087-2"></a>Desired ascii(): &#39;\u0105&#39;
<a id="rest_code_f5ea18fead964936bccf8b8666032087-3" name="rest_code_f5ea18fead964936bccf8b8666032087-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_f5ea18fead964936bccf8b8666032087-3"></a>Real ascii(): &#39;\udcc4\udc85&#39;
</pre></div>
<div class="code"><pre class="code text"><a id="rest_code_73da6abf15b34ece9c498c4adc163917-1" name="rest_code_73da6abf15b34ece9c498c4adc163917-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-1"></a>perl: warning: Setting locale failed.
<a id="rest_code_73da6abf15b34ece9c498c4adc163917-2" name="rest_code_73da6abf15b34ece9c498c4adc163917-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-2"></a>perl: warning: Please check that your locale settings:
<a id="rest_code_73da6abf15b34ece9c498c4adc163917-3" name="rest_code_73da6abf15b34ece9c498c4adc163917-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-3"></a>    [...]
<a id="rest_code_73da6abf15b34ece9c498c4adc163917-4" name="rest_code_73da6abf15b34ece9c498c4adc163917-4" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-4"></a>    are supported and installed on your system.
<a id="rest_code_73da6abf15b34ece9c498c4adc163917-5" name="rest_code_73da6abf15b34ece9c498c4adc163917-5" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-5"></a>perl: warning: Falling back to the standard locale (&quot;C&quot;).
</pre></div>
<p class="lead">All those errors have the same root cause: incorrect locale configuration.
To fix them all, you need to generate the missing locales and set them.</p>
<section id="check-currently-used-locale">
<h1>Check currently used locale</h1>
<p>The <code class="docutils literal">locale</code> command (without arguments) should tell you which locales you’re
currently using.  (The list might be shorter on your end)</p>
<div class="code"><pre class="code sh"><a id="rest_code_45351c7f546a450b945adfb5fea5446d-1" name="rest_code_45351c7f546a450b945adfb5fea5446d-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-1"></a>$<span class="w"> </span>locale
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-2" name="rest_code_45351c7f546a450b945adfb5fea5446d-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-2"></a><span class="nv">LANG</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-3" name="rest_code_45351c7f546a450b945adfb5fea5446d-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-3"></a><span class="nv">LC_CTYPE</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-4" name="rest_code_45351c7f546a450b945adfb5fea5446d-4" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-4"></a><span class="nv">LC_NUMERIC</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-5" name="rest_code_45351c7f546a450b945adfb5fea5446d-5" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-5"></a><span class="nv">LC_TIME</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-6" name="rest_code_45351c7f546a450b945adfb5fea5446d-6" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-6"></a><span class="nv">LC_COLLATE</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-7" name="rest_code_45351c7f546a450b945adfb5fea5446d-7" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-7"></a><span class="nv">LC_MONETARY</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-8" name="rest_code_45351c7f546a450b945adfb5fea5446d-8" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-8"></a><span class="nv">LC_MESSAGES</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-9" name="rest_code_45351c7f546a450b945adfb5fea5446d-9" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-9"></a><span class="nv">LC_PAPER</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-10" name="rest_code_45351c7f546a450b945adfb5fea5446d-10" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-10"></a><span class="nv">LC_NAME</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-11" name="rest_code_45351c7f546a450b945adfb5fea5446d-11" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-11"></a><span class="nv">LC_ADDRESS</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-12" name="rest_code_45351c7f546a450b945adfb5fea5446d-12" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-12"></a><span class="nv">LC_TELEPHONE</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-13" name="rest_code_45351c7f546a450b945adfb5fea5446d-13" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-13"></a><span class="nv">LC_MEASUREMENT</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-14" name="rest_code_45351c7f546a450b945adfb5fea5446d-14" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-14"></a><span class="nv">LC_IDENTIFICATION</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-15" name="rest_code_45351c7f546a450b945adfb5fea5446d-15" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-15"></a><span class="nv">LC_ALL</span><span class="o">=</span>
</pre></div>
<p>If any of those is set to <code class="docutils literal">C</code> or <code class="docutils literal">POSIX</code>, has a different encoding than
<code class="docutils literal"><span class="pre">UTF-8</span></code> (sometimes spelled <code class="docutils literal">utf8</code>) is empty (with the exception of
<code class="docutils literal">LC_ALL</code>), or if you see any errors, you need to reconfigure your locale.</p>
</section>
<section id="check-locale-availability-and-install-missing-locales">
<h1>Check locale availability and install missing locales</h1>
<p>The first thing you need to do is check locale availability. To do this, run
<code class="docutils literal">locale <span class="pre">-a</span></code>. This will produce a list of all installed locales.  You can use
<code class="docutils literal">grep</code> to get a more reasonable list.</p>
<div class="code"><pre class="code text"><a id="rest_code_704767d3e7724ac7b8d1176bc3b74b03-1" name="rest_code_704767d3e7724ac7b8d1176bc3b74b03-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_704767d3e7724ac7b8d1176bc3b74b03-1"></a>$ locale -a | grep -i utf
<a id="rest_code_704767d3e7724ac7b8d1176bc3b74b03-2" name="rest_code_704767d3e7724ac7b8d1176bc3b74b03-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_704767d3e7724ac7b8d1176bc3b74b03-2"></a>&lt;lists all UTF-8 locales&gt;
<a id="rest_code_704767d3e7724ac7b8d1176bc3b74b03-3" name="rest_code_704767d3e7724ac7b8d1176bc3b74b03-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_704767d3e7724ac7b8d1176bc3b74b03-3"></a>$ locale -a | grep -i utf | grep -i en_US
<a id="rest_code_704767d3e7724ac7b8d1176bc3b74b03-4" name="rest_code_704767d3e7724ac7b8d1176bc3b74b03-4" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_704767d3e7724ac7b8d1176bc3b74b03-4"></a>en_US.UTF-8
</pre></div>
<p>The best locale to use is the one for your language, with the UTF-8 encoding.
The locale will be used by some console apps for output. I’m going to use
<code class="docutils literal"><span class="pre">en_US.UTF-8</span></code> in this guide.</p>
<p>If you can’t see any UTF-8 locales, or no appropriate locale setting for your
language of choice, you might need to generate those. The required actions
depend on your distro/OS.</p>
<ul class="simple">
<li><p>Debian, Ubuntu, and derivatives: install <code class="docutils literal"><span class="pre">language-pack-en-base</span></code>, run <code class="docutils literal">sudo <span class="pre">dpkg-reconfigure</span> locales</code></p></li>
<li><p>RHEL, CentOS, Fedora: install <code class="docutils literal"><span class="pre">glibc-langpack-en</span></code></p></li>
<li><p>Arch Linux: uncomment relevant entries in <code class="docutils literal">/etc/locale.gen</code> and run <code class="docutils literal">sudo <span class="pre">locale-gen</span></code> <a class="reference external" href="https://wiki.archlinux.org/index.php/Locale">(wiki)</a></p></li>
<li><p>For other OSes, refer to the documentation.</p></li>
</ul>
<p>You need a UTF-8 locale to ensure compatibility with software. Avoid the <code class="docutils literal">C</code>
and <code class="docutils literal">POSIX</code> locales (it’s ASCII) and locales with other encodings (those
aren’t used by ~anyone these days)</p>
</section>
<section id="configure-system-wide">
<h1>Configure system-wide</h1>
<p>On some systems, you may be able to configure locale system-wide.  Check your
system documentation for details. If your system has systemd, run</p>
<div class="code"><pre class="code text"><a id="rest_code_8e2d3316c858497393bb3774f7ebe9d1-1" name="rest_code_8e2d3316c858497393bb3774f7ebe9d1-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_8e2d3316c858497393bb3774f7ebe9d1-1"></a>sudo localectl set-locale LANG=en_US.UTF-8
</pre></div>
</section>
<section id="configure-for-a-single-user">
<h1>Configure for a single user</h1>
<p>If your environment does not allow system-wide locale configuration (macOS,
shared server with generated but unconfigured locales), or if you want to
ensure it’s always configured independently of system settings.</p>
<p>To do this, you need to edit the configuration file for your shell. If you’re
using bash, it’s <code class="docutils literal">.bashrc</code> (or <code class="docutils literal">.bash_profile</code> on macOS). For zsh users,
<code class="docutils literal">.zshrc</code>.  Add this line (or equivalent in your shell):</p>
<div class="code"><pre class="code sh"><a id="rest_code_28348ddaf62c4af99190326623915503-1" name="rest_code_28348ddaf62c4af99190326623915503-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_28348ddaf62c4af99190326623915503-1"></a><span class="nb">export</span><span class="w"> </span><span class="nv">LANG</span><span class="o">=</span>en_US.UTF-8<span class="w"> </span><span class="nv">LC_ALL</span><span class="o">=</span>en_US.UTF-8
</pre></div>
<p>That should be enough. Note that those settings don’t apply to programs
not launched through a shell.</p>
<hr class="docutils">
<p><strong>Python/Windows corner:</strong> Python 3.7 will fix this on Unix by assuming UTF-8
if it encounters the C locale.  On Windows, Python 3.6 is using UTF-8
interactively, but not when using shell redirections to files or pipes.</p>
<p><em>This post was brought to you by ą — U+0105 LATIN SMALL LETTER A WITH OGONEK.</em></p>
</section>
]]></content:encoded><category>Programming</category><category>guide</category><category>locale</category><category>Python</category><category>Unicode</category><category>Unix</category></item><item><title>CSV is not a standard</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/04/07/csv-is-not-a-standard/</link><pubDate>Fri, 07 Apr 2017 18:00:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/04/07/csv-is-not-a-standard/</guid><description>
CSV is not a standard. What does that really mean for anyone using that format?
The file’s recipient may be unable to read it the way you intended. Separators,
decimal marks, escaping and encodings are all problems — and Excel does them
all pretty badly.
</description><content:encoded><![CDATA[
<p>CSV is not a standard. What does that really mean for anyone using that format?
The file’s recipient may be unable to read it the way you intended. Separators,
decimal marks, escaping and encodings are all problems — and Excel does them
all pretty badly.</p>



<p>So first, some people might claim that <a class="reference external" href="http://www.ietf.org/rfc/rfc4180.txt">RFC 4180</a> is the CSV standard. Those
people also have not read the document they’re referring to. It states:</p>
<blockquote>
<p>This memo provides information for the Internet community.  It does
not specify an Internet standard of any kind.</p>
</blockquote>
<p>The problem with this is the fact that a <code class="docutils literal">.csv</code> file does not mean much. There
are a few problems. The first question is,</p>
<blockquote>
<p>What is the field separator? Is it a comma or a semicolon?</p>
</blockquote>
<p>Hey, wait a minute, doesn’t the file format/extension stand for
<em>comma-separated values</em>? Yes, it does. But that does not matter in the
slightest. You see, Microsoft Excel — which most people will use to read/write
their CSV files — makes this decision based on the user locale settings. If the
OS is set to a locale where the comma is the <a class="reference external" href="https://en.wikipedia.org/wiki/Decimal_mark#Hindu.E2.80.93Arabic_numeral_system">decimal mark</a> (eg. most of
Europe), the list separator is set to <code class="docutils literal">;</code> instead of <code class="docutils literal">,</code> — and Excel uses
that.</p>
<p>Of course, there’s also the TSV data format — those are tab-separated values.
And some people might name their TSV files <code class="docutils literal">.csv</code>.</p>
<p>To read files saved in a different locale, or with a different separator, Excel
users need to change the file extension to <code class="docutils literal">.txt</code>, or go to Data → Get
External Data → From Text <a class="reference external" href="https://support.office.com/en-us/article/Text-Import-Wizard-c5b02af6-fda1-4440-899f-f78bafe41857">(documentation)</a> and use the import wizard. You
can’t double-click on files.</p>
<p>On a side note, Apple Numbers guesses the format — one of the few things it
gets right. LibreOffice always asks the user to pick import settings, but by
default it uses tab AND comma AND semicolon for CSV files, which brings its own
host of problems.</p>
<p>Here’s a quick test:</p>
<blockquote>
<p>What does <code class="docutils literal">foo;bar,baz;quux</code> mean? What about <code class="docutils literal">foo,bar;baz,quux</code>?</p>
</blockquote>
<ul class="simple">
<li><p>LibreOffice assumes it’s (Chinese) UTF-16 text, but after telling it the real encoding, both
files contain <strong>4 columns</strong>.</p></li>
<li><p>Microsoft Excel says one of the files contains <strong>3 columns</strong> and the other contains <strong>2 columns</strong>
(which is which depends on locale)</p></li>
<li><p>Apple Numbers says the first file contains <strong>3 columns</strong> and the other
contains <strong>2 columns</strong> if set to English, and both files contain <strong>3
columns</strong> if set to Polish.</p></li>
</ul>
<p>But let’s get back to gotchas:</p>
<blockquote>
<p>What is the decimal mark? Is it a dot or a comma?</p>
</blockquote>
<p>That’s a direct consequence of the previous question. However, one can’t simply
assume <code class="docutils literal">comma/dot</code> and <code class="docutils literal">semicolon/comma</code>, because users might do crazy
stuff.</p>
<blockquote>
<p>What is used to escape rows containing the field separator? Quotes?
Backslashes?  What is used to escape the escape character?</p>
</blockquote>
<p>Excel, for example, puts some things in <code class="docutils literal">&quot;quotes&quot;</code>. If a literal quote
character appears in the spreadsheet, it’s represented as <code class="docutils literal">&quot;&quot;</code>, and
the entire cell is quoted as well. But there might be programs that use
backslashes for escapes, or even bad code that does not consider the need of
escaping like this, with tragic results.</p>
<p>There’s still one more thing to cover: encodings. You see, even though the TSV
format effectively solves the issues I named before, both CSV and TSV suffer
from one problem:</p>
<blockquote>
<p>Which encoding to use when reading this file?</p>
</blockquote>
<p>I already mentioned that LibreOffice believed my sample file was UTF-16,
containing Chinese text — in reality, this file was UTF-8 (or ASCII).</p>
<p>What does Microsoft Excel do then? It looks like it follows <em>System locale for
non-Unicode programs</em>. While there is an encoding option hidden in the Save
dialog, it does not seem to affect the output. So what does that mean? You
can’t expect a CSV file that contains characters outside of your system locale
— or outside of ASCII if you’re working with people around the world — to look
right. Unless you’re on <a class="reference external" href="https://answers.microsoft.com/en-us/msoffice/forum/msoffice_install-mso_win10/announcing-october-feature-update-for-office-2016/927eea90-eea3-479a-a78a-45f7612460e1">Excel 2016</a> and Office 365 — if you have the October
2016 update, you can read and write UTF-8 files. But if you’re using an older
version of Excel, or you’re using a non-Office 365 license, tough luck.</p>
<p>So, to reiterate: CSV can mean a lot of things. And you can’t trust it to work
well most of the time, unless you’re dealing with people in one country, all
using the same locale settings and software. Which is pretty unlikely. TSV
can work around most of the problems, but encodings are still troublesome.</p>
]]></content:encoded><category>Programming</category><category>CSV</category><category>Excel</category><category>Microsoft</category><category>Microsoft Office</category></item><item><title>Code writing code: Python and Vim as development aids</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/</link><pubDate>Fri, 27 May 2016 08:46:35 GMT</pubDate><guid>https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/</guid><description>
Recently I was working on some C# and Java code. And along the way, I used
Python and Vim to (re)write my code. A small Python script and a 6-keystroke
Vim macro did it faster and better than a human would.
Every programmer should learn a good scripting language and use a programmable
editor like Vim. Why? Here are two examples, after the break.
</description><content:encoded><![CDATA[
<p>Recently I was working on some C# and Java code. And along the way, I used
Python and Vim to (re)write my code. A small Python script and a 6-keystroke
Vim macro did it faster and better than a human would.</p>
<p>Every programmer should learn a good scripting language and use a programmable
editor like Vim. Why? Here are two examples, after the break.</p>



<section id="episode-i-inotifypropertychanged-or-python-writing-c">
<h1>Episode I: <code class="docutils literal">INotifyPropertyChanged</code>, or Python writing C#</h1>
<p>I was building a private C# weekend project (that turned into a weeklong
project) — and by the way, WPF and C# are quite pleasant (Windows Forms is a
trainwreck, though). One of the things I used in that project was a DataGrid
bound to a list of custom objects (a DataGrid is a table, basically). And in
order to use it, you need to use the <code class="docutils literal">INotifyPropertyChanged</code> interface <a class="reference external" href="https://msdn.microsoft.com/en-us/library/ms229614(v=vs.100).aspx">(MSDN)</a>.
It involves doing something like this:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-1" name="rest_code_4c40930703c34f739bfa440b60bb2d79-1"></a><span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="n">name_</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="k">set</span><span class="p">;</span><span class="w"> </span><span class="p">};</span><span class="w"> </span><span class="c1">// can also be a field</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-2" name="rest_code_4c40930703c34f739bfa440b60bb2d79-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-3" name="rest_code_4c40930703c34f739bfa440b60bb2d79-3"></a><span class="w"> </span><span class="na">[JsonProperty]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-4" name="rest_code_4c40930703c34f739bfa440b60bb2d79-4"></a><span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-5" name="rest_code_4c40930703c34f739bfa440b60bb2d79-5"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="k">get</span><span class="w"> </span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-6" name="rest_code_4c40930703c34f739bfa440b60bb2d79-6"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="k">return</span><span class="w"> </span><span class="n">name_</span><span class="p">;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-7" name="rest_code_4c40930703c34f739bfa440b60bb2d79-7"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-8" name="rest_code_4c40930703c34f739bfa440b60bb2d79-8"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="k">set</span><span class="w"> </span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-9" name="rest_code_4c40930703c34f739bfa440b60bb2d79-9"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="k">value</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">name_</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-10" name="rest_code_4c40930703c34f739bfa440b60bb2d79-10"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="n">name_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">value</span><span class="p">;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-11" name="rest_code_4c40930703c34f739bfa440b60bb2d79-11"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="n">NotifyPropertyChanged</span><span class="p">(</span><span class="s">&quot;name&quot;</span><span class="p">);</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-12" name="rest_code_4c40930703c34f739bfa440b60bb2d79-12"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-13" name="rest_code_4c40930703c34f739bfa440b60bb2d79-13"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4c40930703c34f739bfa440b60bb2d79-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="rest_code_4c40930703c34f739bfa440b60bb2d79-14" name="rest_code_4c40930703c34f739bfa440b60bb2d79-14"></a><span class="w"> </span><span class="p">}</span>
</code></td></tr></table></div><p>That’s 12 lines of code (excluding <code class="docutils literal">[JsonProperty]</code> which comes from the
Json.NET library) for that pattern. Oh: and I need to do that for <strong>every</strong>
field/property of my class, because otherwise any changes to them would not be
reflected in the tables (and maybe one or two fields were <em>not</em> in the table).</p>
<p>Doing that by hand is really not feasible: you need to copy-paste this
large block 14 times and take care of 5 instances of the name (3 with
underscores, 2 without), 2 instances of the type, and the <code class="docutils literal">[JsonProperty]</code>
attribute (which does not appear on all properties).</p>
<p>So, I used one of those intelligent computer things to do it for me. I wrote a
really simple <a class="reference external" href="https://www.python.org/">Python</a> script and ran it. And I ended up with all 14 fields built
for me.</p>
<p><a class="reference external" href="link://listing/listings/code-writing-code/write_properties.py">code-writing-code/write_properties.py</a>  <a class="reference external" href="link://listing_source/listings/code-writing-code/write_properties.py">(Source)</a></p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-1" name="rest_code_5defa6b60bf345e8ac072f136362524b-1"></a><span class="ch">#!/usr/bin/env python3</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-2" name="rest_code_5defa6b60bf345e8ac072f136362524b-2"></a><span class="n">TEMPLATE</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span><span class="se">\</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-3" name="rest_code_5defa6b60bf345e8ac072f136362524b-3"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="si">%s</span><span class="s2">public </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> {</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-4" name="rest_code_5defa6b60bf345e8ac072f136362524b-4"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get {</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-5" name="rest_code_5defa6b60bf345e8ac072f136362524b-5"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return </span><span class="si">%s</span><span class="s2">_;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-6" name="rest_code_5defa6b60bf345e8ac072f136362524b-6"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-7" name="rest_code_5defa6b60bf345e8ac072f136362524b-7"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set {</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-8" name="rest_code_5defa6b60bf345e8ac072f136362524b-8"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (value != </span><span class="si">%s</span><span class="s2">_) {</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-9" name="rest_code_5defa6b60bf345e8ac072f136362524b-9"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="si">%s</span><span class="s2">_ = value;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-10" name="rest_code_5defa6b60bf345e8ac072f136362524b-10"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NotifyPropertyChanged(&quot;</span><span class="si">%s</span><span class="s2">&quot;);</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-11" name="rest_code_5defa6b60bf345e8ac072f136362524b-11"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-12" name="rest_code_5defa6b60bf345e8ac072f136362524b-12"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-13" name="rest_code_5defa6b60bf345e8ac072f136362524b-13"></a><span class="s2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-14" name="rest_code_5defa6b60bf345e8ac072f136362524b-14"></a><span class="s2">&quot;&quot;&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-15" name="rest_code_5defa6b60bf345e8ac072f136362524b-15"></a><span class="n">JSONPROPERTY_TEMPLATE</span> <span class="o">=</span> <span class="s1">&#39;[JsonProperty]</span><span class="se">\n</span><span class="s1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-16"><code data-line-number="16"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-16" name="rest_code_5defa6b60bf345e8ac072f136362524b-16"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-17"><code data-line-number="17"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-17" name="rest_code_5defa6b60bf345e8ac072f136362524b-17"></a><span class="k">def</span><span class="w"> </span><span class="nf">write</span><span class="p">(</span><span class="n">has_jsonproperty</span><span class="p">,</span> <span class="n">vtype</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-18"><code data-line-number="18"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-18" name="rest_code_5defa6b60bf345e8ac072f136362524b-18"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="n">has_jsonproperty</span><span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-19"><code data-line-number="19"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-19" name="rest_code_5defa6b60bf345e8ac072f136362524b-19"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">jsonproperty</span> <span class="o">=</span> <span class="n">JSONPROPERTY_TEMPLATE</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-20"><code data-line-number="20"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-20" name="rest_code_5defa6b60bf345e8ac072f136362524b-20"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">else</span><span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-21"><code data-line-number="21"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-21" name="rest_code_5defa6b60bf345e8ac072f136362524b-21"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">jsonproperty</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-22"><code data-line-number="22"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-22" name="rest_code_5defa6b60bf345e8ac072f136362524b-22"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="n">TEMPLATE</span> <span class="o">%</span> <span class="p">(</span><span class="n">jsonproperty</span><span class="p">,</span> <span class="n">vtype</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-23"><code data-line-number="23"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-23" name="rest_code_5defa6b60bf345e8ac072f136362524b-23"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-24"><code data-line-number="24"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-24" name="rest_code_5defa6b60bf345e8ac072f136362524b-24"></a><span class="n">properties</span> <span class="o">=</span> <span class="p">[</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-25"><code data-line-number="25"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-25" name="rest_code_5defa6b60bf345e8ac072f136362524b-25"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s1">&#39;1 string name&#39;</span><span class="p">,</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-26"><code data-line-number="26"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-26" name="rest_code_5defa6b60bf345e8ac072f136362524b-26"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s1">&#39;0 int another&#39;</span><span class="p">,</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-27"><code data-line-number="27"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-27" name="rest_code_5defa6b60bf345e8ac072f136362524b-27"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># 12 fields omitted for brevity</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-28"><code data-line-number="28"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-28" name="rest_code_5defa6b60bf345e8ac072f136362524b-28"></a><span class="p">]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-29"><code data-line-number="29"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-29" name="rest_code_5defa6b60bf345e8ac072f136362524b-29"></a><span class="n">properties_split</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">split</span><span class="p">()</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">properties</span><span class="p">]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-30"><code data-line-number="30"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-30" name="rest_code_5defa6b60bf345e8ac072f136362524b-30"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-31"><code data-line-number="31"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-31" name="rest_code_5defa6b60bf345e8ac072f136362524b-31"></a><span class="c1"># Private definitions (internal)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-32"><code data-line-number="32"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-32" name="rest_code_5defa6b60bf345e8ac072f136362524b-32"></a><span class="k">for</span> <span class="n">has_jsonproperty</span><span class="p">,</span> <span class="n">vtype</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">properties_split</span><span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-33"><code data-line-number="33"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-33" name="rest_code_5defa6b60bf345e8ac072f136362524b-33"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2">_ { get; set; }&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">vtype</span><span class="p">,</span> <span class="n">name</span><span class="p">))</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-34"><code data-line-number="34"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-34" name="rest_code_5defa6b60bf345e8ac072f136362524b-34"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-35"><code data-line-number="35"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-35" name="rest_code_5defa6b60bf345e8ac072f136362524b-35"></a><span class="nb">print</span><span class="p">()</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-36"><code data-line-number="36"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-36" name="rest_code_5defa6b60bf345e8ac072f136362524b-36"></a><span class="c1"># Public definitions (with notifications)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-37"><code data-line-number="37"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-37" name="rest_code_5defa6b60bf345e8ac072f136362524b-37"></a><span class="k">for</span> <span class="n">has_jsonproperty</span><span class="p">,</span> <span class="n">vtype</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">properties_split</span><span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_5defa6b60bf345e8ac072f136362524b-38"><code data-line-number="38"></code></a></td><td class="code"><code><a id="rest_code_5defa6b60bf345e8ac072f136362524b-38" name="rest_code_5defa6b60bf345e8ac072f136362524b-38"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">print</span><span class="p">(</span><span class="n">write</span><span class="p">(</span><span class="n">has_jsonproperty</span> <span class="o">==</span> <span class="s1">&#39;1&#39;</span><span class="p">,</span> <span class="n">vtype</span><span class="p">,</span> <span class="n">name</span><span class="p">))</span>
</code></td></tr></table></div><p>That script takes a list of properties and spits out a block of code, ready to
be pasted into the code. Visual Studio has a nice <em>Insert File as Text</em>
feature, so redirecting the output to a file and using that option is enough.</p>
</section>
<section id="episode-ii-fixing-argument-order-or-vim-re-writing-java">
<h1>Episode II: Fixing argument order, or Vim (re)writing Java</h1>
<p>Another project, <a class="reference external" href="https://github.com/Kwpolska/numbernamer">Number Namer</a>, written in Java, and it does what it says on
the tin: takes a number and writes it out as words, while being multilingual and
extensible. I used Eclipse for this project, because it looks good, is really
helpful with its code linting, and does not run slowly on my aging system (I’m
looking at you, IntelliJ IDEA aka PyCharm aka Android Studio…)</p>
<p>And so, I was building a test suite, using <a class="reference external" href="http://junit.org/">JUnit</a>. It’s pretty
straightforward, and I remember the syntax from Python’s unittest (even though
I write tests with <a class="reference external" href="http://pytest.org/">pytest</a> nowadays). Or so I thought.</p>
<div class="code"><pre class="code java"><a id="rest_code_4fd345f92b594e8bb7094164392eebcd-1" name="rest_code_4fd345f92b594e8bb7094164392eebcd-1" href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4fd345f92b594e8bb7094164392eebcd-1"></a><span class="c1">// (incorrect)</span>
<a id="rest_code_4fd345f92b594e8bb7094164392eebcd-2" name="rest_code_4fd345f92b594e8bb7094164392eebcd-2" href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4fd345f92b594e8bb7094164392eebcd-2"></a><span class="n">assertEquals</span><span class="p">(</span><span class="s">&quot;Basic integers (7) failed&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">namer</span><span class="p">.</span><span class="na">name</span><span class="p">(</span><span class="mi">7L</span><span class="p">),</span><span class="w"> </span><span class="s">&quot;seven&quot;</span><span class="p">);</span>
<a id="rest_code_4fd345f92b594e8bb7094164392eebcd-3" name="rest_code_4fd345f92b594e8bb7094164392eebcd-3" href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4fd345f92b594e8bb7094164392eebcd-3"></a><span class="c1">// (fixed)                              ^ cursor</span>
<a id="rest_code_4fd345f92b594e8bb7094164392eebcd-4" name="rest_code_4fd345f92b594e8bb7094164392eebcd-4" href="https://chriswarrick.com/blog/2016/05/27/code-writing-code-python-and-vim/#rest_code_4fd345f92b594e8bb7094164392eebcd-4"></a><span class="n">assertEquals</span><span class="p">(</span><span class="s">&quot;Basic integers (7) failed&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;seven&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">namer</span><span class="p">.</span><span class="na">name</span><span class="p">(</span><span class="mi">7L</span><span class="p">));</span>
</pre></div>
<p>You see, the typical Python spelling is <code class="docutils literal">self.assertEquals(actual,
expected)</code>. Java adds a <code class="docutils literal">String</code> message parameter and it also swaps
<code class="docutils literal">actual</code> and <code class="docutils literal">expected</code>. Which I didn’t notice at first, and I wrote my
assertions incorrectly. While it doesn’t <em>really</em> matter (it will still work),
the output looked a bit weird.</p>
<p>And I noticed only when I finished writing my tests (and I had a typo in my
expected output). I wanted to fix them all — not manually, of course. So, I
closed this file, brought up Vim, searched for the motion I need (it’s
<code class="docutils literal">t{char}</code> — see <code class="docutils literal">:help t</code>). And I ended up with this
(cursor placed on the comma after the first argument):</p>
<div style="text-align: center;">
<kbd style="font-size: 2em;">dt,</kbd><kbd style="font-size: 2em;">t)</kbd><kbd style="font-size: 2em;">p</kbd>
</div><p>What does this do, you may ask? It’s actually pretty self-explanatory:</p>
<blockquote><p>
<b>d</b>elete <b>t</b>ill comma, (go) <b>t</b>ill closing parenthesis, <b>p</b>aste.
</p></blockquote><p>This fixes one line. Automatically. Make it a macro (wrap in <code class="docutils literal">qq</code> … <code class="docutils literal">q</code>,
use with <code class="docutils literal">&#64;q</code>) and now you can run it on all lines, either by moving manually or by
searching for <code class="docutils literal">,</code> and pressing <code class="docutils literal">n&#64;q</code> until you run out of lines.</p>
</section>
<section id="epilogue">
<h1>Epilogue</h1>
<p>Some of you might say “but VS/Eclipse/IDEA has an option for that somewhere” or
“[expensive tool] can do that” — and a Google search shows that there is an
Eclipse plugin to swap arguments and that I could also write a regex to solve
my second issue. Nevertheless, Python is a great tool in a programmer’s toolbox
— especially the interactive interpreter. And Vim is an awesome editor that can
accomplish magic in a few keystrokes — and there are many more things you can
do with it.</p>
<p class="lead">Go learn <a class="reference external" href="https://www.python.org/">Python</a> and <a class="reference external" href="http://www.vim.org/">Vim</a> now.</p>
<p>Also: don’t even bother with VsVim or IdeaVim or any other Vim emulation
plugins, they work in unusual ways and often don’t give you everything — for
example, VsVim has a Vim visual mode (<code class="docutils literal">v</code> key) and Visual Studio selection
mode (mouse), and only one allows Vim keystrokes (the other will replace
selected text).</p>
</section>
]]></content:encoded><category>Programming</category><category>C#</category><category>Java</category><category>programming</category><category>Python</category><category>Vim</category></item></channel></rss>