<?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>sglavoie.com – Tag: Productivity</title><link>https://www.sglavoie.com/tags/productivity/</link><description>Posts and writings by Sébastien Lavoie. Customization setups and articles on productivity for developers who like minimalism.</description><language>en</language><atom:link href="https://www.sglavoie.com/tags/productivity/feed.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Fri, 09 Oct 2026 16:20:00 -0600</lastBuildDate><item><title>From a plan to unattended agent runs: how I drive coding agents one session at a time</title><link>https://www.sglavoie.com/posts/from-plan-to-unattended-agent-runs/</link><description>Long conversations with a coding agent drift, and “done” too often means “the agent said so”. This is the pipeline I built to turn a plan into small sessions with checks the agent can’t talk its way around — a continuation of the same instinct behind systematic reviews and parallel work with Git worktrees.</description><content:encoded>&lt;p&gt;&lt;em&gt;Written with AI: This post was drafted with an AI assistant, working from my notes, code and tools, then reviewed and edited by me. The experiences and opinions are mine, and so are any mistakes.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Coding agents got good enough, quickly enough, that the bottleneck in my day moved. It&amp;rsquo;s no longer typing the code; it&amp;rsquo;s making sure the code that gets typed is the code I wanted, and that it actually works. The first few weeks went the way I suspect they go for a lot of people: one long conversation per feature, a growing pile of context, and a moment near the end where the agent cheerfully announces it&amp;rsquo;s done and I discover, ten minutes later, that &lt;em&gt;&amp;ldquo;done&amp;rdquo;&lt;/em&gt; meant &lt;em&gt;&amp;ldquo;the parts I remembered are done&amp;rdquo;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Trying to resume progress on large features led me to try different frameworks such as &lt;a href="https://github.com/github/spec-kit"&gt;Spec Kit&lt;/a&gt; from GitHub, &lt;a href="https://github.com/Fission-AI/openspec"&gt;OpenSpec&lt;/a&gt;, the &lt;a href="https://kiro.dev/"&gt;Kiro IDE&lt;/a&gt;, standalone Claude skills and so on. I even built my own harness-agnostic spec-driven framework which I used for a while with (slow) success with GitHub Copilot CLI, Codex and Claude Code. That level of ceremony was right for less capable models, but the picture evolved: the models got better at producing what I wanted without being walked through every step, and I found I needed a different kind of help.&lt;/p&gt;
&lt;p&gt;What I needed wasn&amp;rsquo;t more guidance for the agent. It was less trust in it. Generated code reads fluently, compiles, and is sometimes wrong in ways that only show up later: a concurrency guard that guards nothing, a test that faithfully asserts the bug. &lt;strong&gt;Fluency and correctness are uncorrelated&lt;/strong&gt;, and anyone who has reviewed enough agent output has caught that gap personally. Two problems kept coming back:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Long conversations drift.&lt;/strong&gt; The further a session goes, the more the early decisions fade, and the agent starts re-solving problems it already solved, or quietly undoing them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Done&amp;rdquo; was decided by the agent.&lt;/strong&gt; There was no external definition of done that the agent couldn&amp;rsquo;t argue with, so every finished session still needed me to establish, from scratch, whether it was actually finished.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The second one matters more than it looks. When an agent writes the code, the review doesn&amp;rsquo;t go away; it moves, and it gets harder, because I&amp;rsquo;m now checking work I didn&amp;rsquo;t build the understanding for. Review is the scarce resource. Anything that makes the agent produce more code without making that code cheaper to verify just moves the bottleneck around.&lt;/p&gt;
&lt;p&gt;What I ended up with is a small (well&amp;hellip; not so small anymore) tool called &lt;code&gt;asl&lt;/code&gt;, short for &lt;em&gt;agent session loop&lt;/em&gt;. The idea is simple: write a plan, cut it into sessions that each fit comfortably in one fresh conversation, attach to every session a check that a program — not the agent — runs, and then let a runner go through the sessions one at a time while I do something else. This post walks through that pipeline, why each step exists, and what I learned building it.&lt;/p&gt;
&lt;h2 id="why-plans-not-prompts"&gt;Why plans, not prompts&lt;/h2&gt;
&lt;p&gt;Most of the leverage happens before any code is written. A vague prompt to an agent yields a confident implementation of something adjacent to what you wanted; a precise plan yields something much closer. So the pipeline starts with a plain Markdown plan, and with a step whose entire job is to make that plan better before anything runs.&lt;/p&gt;
&lt;p&gt;The bar I hold a plan to is that it should be &lt;em&gt;decision-complete&lt;/em&gt;: every choice the implementer shouldn&amp;rsquo;t be making on their own has already been made. The test I use is a slightly hostile question: &lt;strong&gt;could two competent implementers follow this plan and end up with meaningfully different behaviour?&lt;/strong&gt; If the answer is yes, the plan is hiding a decision — about an API, a data format, an error case, a migration order — and the agent will happily make that decision for me, silently, somewhere in the middle of a diff.&lt;/p&gt;
&lt;p&gt;It helps to separate facts from decisions. &amp;ldquo;Which callers use this function?&amp;rdquo; is something the agent can discover by reading the repository, and it should. &amp;ldquo;Which of those callers are we willing to break?&amp;rdquo; is a judgement call, and it stays with me. A good plan records the first kind as discovery and the second kind as an explicit decision.&lt;/p&gt;
&lt;p&gt;The step that enforces this is a &lt;a href="https://docs.claude.com/en/docs/claude-code/skills"&gt;Claude Code skill&lt;/a&gt; called &lt;code&gt;plan-iterate&lt;/code&gt;. It reads the plan, assesses how complete it is (scope, interfaces, tests, risks), asks me targeted questions about the weakest areas, and edits my answers back into the file. With &lt;code&gt;--ideal&lt;/code&gt;, it first does one research pass over the codebase and describes what the &lt;em&gt;unconstrained&lt;/em&gt; ideal version of the change would look like, then ranks the gaps between my plan and that ideal by impact, and asks me to adopt, defer or reject each one. Deferred items get written into the plan so the decision is recorded rather than forgotten.&lt;/p&gt;
&lt;p&gt;This is the same instinct behind &lt;a href="https://www.sglavoie.com/posts/systematic-reviews/"&gt;systematic reviews&lt;/a&gt;: it&amp;rsquo;s cheaper to catch a bad idea on paper than in a diff.&lt;/p&gt;
&lt;h2 id="the-pipeline-step-by-step"&gt;The pipeline, step by step&lt;/h2&gt;
&lt;p&gt;Here is the whole flow, from a plan to a finished run:&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0046_from_plan_to_unattended_agent_runs/pipeline.svg"
 alt="Flowchart of the pipeline. PLAN.md is refined by plan-iterate, then asl prepare runs session-split, session-expand, asl baseline and asl preflight. Red or yellow preflight findings go through plan-preflight-iterate and back to preflight; an all-green plan goes to asl run, which runs one session per fresh agent turn. Python runs each session’s Verify checks: a failure triggers a repair turn with the failing evidence, a pass moves to the next pending session, and the run ends as all-complete. A blocked, unsafe or guard-violating turn, or an exhausted repair budget, pauses the run with a named reason."
 loading="lazy"
 decoding="async"/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://www.sglavoie.com/files/posts/0046_from_plan_to_unattended_agent_runs/pipeline.txt"&gt;Mermaid source of this diagram&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The steps in the middle used to be separate commands I had to remember to run in order. These days a single &lt;code&gt;asl prepare PLAN.md --cwd REPO_ROOT&lt;/code&gt; runs split, validation, expansion, baseline and the readiness gate deterministically and, on success, prints the exact &lt;code&gt;asl run&lt;/code&gt; command to use next.&lt;/p&gt;
&lt;h3 id="splitting-where-to-cut"&gt;Splitting: where to cut&lt;/h3&gt;
&lt;p&gt;Splitting turns one plan into a directory: a &lt;code&gt;manifest.md&lt;/code&gt; listing the sessions and their readiness state, plus one &lt;code&gt;session-&amp;lt;id&amp;gt;.md&lt;/code&gt; per session. Each session has a scope, the files it&amp;rsquo;s expected to touch, a handoff section the agent fills in when it&amp;rsquo;s done, and a completion contract (more on that below).&lt;/p&gt;
&lt;p&gt;Where to cut took me a while to get right. A good session has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One primary outcome&lt;/strong&gt;, with evidence that can fail on its own. If I can&amp;rsquo;t write a check that distinguishes &amp;ldquo;this session worked&amp;rdquo; from &amp;ldquo;this session didn&amp;rsquo;t&amp;rdquo;, it isn&amp;rsquo;t a session yet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A useful state if the later sessions never run.&lt;/strong&gt; If the run stops after session 3, sessions 1 to 3 should still leave the codebase in a coherent, reviewable state, not half of a refactor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Room to work in one fresh context.&lt;/strong&gt; Context is a split criterion in its own right: the files involved, their size, the instructions that apply and the handoffs from earlier sessions all need to fit, with space left over for the agent to think. It&amp;rsquo;s much cheaper to re-split before running than to discover forty minutes in that a session can&amp;rsquo;t hold everything it needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two anti-patterns I now avoid on purpose: splitting implementation from its tests (the test session ends up testing whatever the implementation happened to do), and a &amp;ldquo;cleanup later&amp;rdquo; session whose absence would leave the change unsafe. Sessions are ordered by dependency, not by whatever is easiest to edit first: shared contracts and scaffolding before their consumers, additions before removals.&lt;/p&gt;
&lt;h3 id="expanding-the-plan-is-a-set-of-claims"&gt;Expanding: the plan is a set of claims&lt;/h3&gt;
&lt;p&gt;Every path, function signature, command and test name in a plan is a &lt;em&gt;claim&lt;/em&gt; about the repository, and plans are often written against a mental model that&amp;rsquo;s a few commits out of date. Expanding is where the agent reads the actual codebase and checks each of those claims: do these files exist, do these functions have the signatures the plan assumes, is this session secretly three sessions?&lt;/p&gt;
&lt;p&gt;The rule that makes this useful is that &lt;strong&gt;corrections go into the plan, not into the implementation.&lt;/strong&gt; Problems get written into a &lt;code&gt;## Contract Issues&lt;/code&gt; section of the session rather than silently patched around. If the agent compensates for a stale fact while implementing, the only record of that decision is the diff, and the next session inherits the stale fact. A session that turns out to be too big can be re-split into child sessions with &lt;code&gt;session-resplit&lt;/code&gt; while the rest of the plan is left untouched.&lt;/p&gt;
&lt;h3 id="preflight-the-gate"&gt;Preflight: the gate&lt;/h3&gt;
&lt;p&gt;Preflight produces red, yellow and green findings, each with a machine-readable repair hint that names the failing file, the check that failed and the smallest repair. A red or yellow finding blocks the plan from becoming &lt;code&gt;loop-ready&lt;/code&gt;, and &lt;code&gt;asl run&lt;/code&gt; refuses to start on anything else. When there are findings, a companion skill, &lt;code&gt;plan-preflight-iterate&lt;/code&gt;, walks through them with me as a short Q&amp;amp;A and reruns preflight until it&amp;rsquo;s clean. Because each finding names its smallest repair, that pass only touches what broke.&lt;/p&gt;
&lt;p&gt;Preflight also checks the contracts themselves: every expected file either exists or is explicitly marked as new, every command is available, and no placeholder or open decision survived into a session.&lt;/p&gt;
&lt;p&gt;One design rule from this part spread to the whole tool: &lt;strong&gt;keep authored state separate from derived state.&lt;/strong&gt; The plan, the sessions, the decisions and the handoffs are authored; the manifest&amp;rsquo;s readiness flags and status tables are derived, and get rebuilt from the authored files. When the two disagree, the tool pauses rather than picking a winner. A readiness table can always be regenerated; a decision that got silently overwritten can&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;The point of all this ceremony is to move failures earlier. A missing file discovered during preflight costs a few seconds; the same missing file discovered forty minutes into a run costs a confused agent, a half-finished session and a messy diff.&lt;/p&gt;
&lt;h2 id="completion-contracts-who-decides-what-done-means"&gt;Completion contracts: who decides what &amp;ldquo;done&amp;rdquo; means&lt;/h2&gt;
&lt;p&gt;This is the part I&amp;rsquo;d keep if I had to throw everything else away.&lt;/p&gt;
&lt;p&gt;Every session file ends with a block like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;markdown&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Completion Contract
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Done when
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; The &lt;span class="sb"&gt;`export`&lt;/span&gt; command writes one JSON file per project.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Existing CLI tests still pass.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Verify
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;```json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;session&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;02&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;checks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;unit-suite&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;argv&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;python3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;-m&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;unittest&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;-q&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;timeout_seconds&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;ldquo;Done when&amp;rdquo; is for humans (and for the agent to aim at). &amp;ldquo;Verify&amp;rdquo; is for the runner: a list of checks — commands to run, files that must exist, patterns that must appear in a file — that the Python runner executes after the agent says it&amp;rsquo;s finished. If a check fails, the session isn&amp;rsquo;t complete, no matter how convincing the agent&amp;rsquo;s summary was. Commands are given as an argument list and run without a shell, so there&amp;rsquo;s no quoting to get subtly wrong.&lt;/p&gt;
&lt;p&gt;Writing these contracts taught me that a check is only as good as what it can &lt;em&gt;falsify&lt;/em&gt;. A test suite that would also pass for a plausible wrong implementation isn&amp;rsquo;t evidence of anything, whoever wrote the code. Agents make that old truth urgent, because they produce plausible wrong implementations at volume. So before I accept a contract, I try to describe one implementation that would be wrong but would still pass it. If that&amp;rsquo;s easy, the contract needs a sharper check, or the session is claiming more than it can prove.&lt;/p&gt;
&lt;p&gt;Three details make this more robust than it sounds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Baselines.&lt;/strong&gt; Before the run, &lt;code&gt;asl baseline&lt;/code&gt; executes every contract and records what it reports on the unchanged codebase, and preflight won&amp;rsquo;t let a plan start without that evidence. A check can declare how it should behave before any work happens: a reproducer is &lt;em&gt;expected to fail&lt;/em&gt; (proving it actually reaches the thing being changed), while protected behaviour is &lt;em&gt;expected to pass&lt;/em&gt; throughout. A protected check that already fails is a broken contract, not a goal — and a reproducer that already passes means the session is either done or testing the wrong thing. Either way, better to know up front than to blame the session for a pre-existing red.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every check backs a named claim, with a limit.&lt;/strong&gt; &amp;ldquo;The focused test passes&amp;rdquo; says nothing about the database, the deployed service or the code paths it doesn&amp;rsquo;t exercise. Keeping that limit written next to the check stops a green session from quietly turning into &amp;ldquo;it works&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The split between judgement and enforcement.&lt;/strong&gt; The agent decides &lt;em&gt;how&lt;/em&gt; to implement a session. Python decides whether it&amp;rsquo;s &lt;em&gt;done&lt;/em&gt;. The skill the agent runs for each session, &lt;code&gt;session-run&lt;/code&gt;, is under a hundred lines of instructions, and that&amp;rsquo;s on purpose: when the runner launches it, Python already holds the plan lock and has checked readiness, and after the agent returns, Python runs the verification, syncs the progress journal and refreshes readiness. Nothing that matters is left for the model to remember.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last point turned into a design rule for everything else: &lt;strong&gt;anything that must happen is code; only things that require judgement go in a prompt.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="what-a-run-looks-like"&gt;What a run looks like&lt;/h2&gt;
&lt;p&gt;Starting a run looks like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;asl run ~/.local/share/agent-plans/export-command/ --harness claude&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The runner then loops:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Re-read the plan files from disk.&lt;/li&gt;
&lt;li&gt;Pick the first pending session.&lt;/li&gt;
&lt;li&gt;Start one agent turn, in a fresh context, running &lt;code&gt;/session-run&lt;/code&gt; on the plan.&lt;/li&gt;
&lt;li&gt;When the turn ends, run the session&amp;rsquo;s Verify checks.&lt;/li&gt;
&lt;li&gt;If they pass, mark the session complete and go back to step 1. If not, put the session back to pending and hand the failing evidence to a repair turn; when the repair budget runs out, stop with a reason.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Re-reading from disk on every turn matters more than it looks. The plan directory is the single source of truth, so I can edit a future session while a run is in progress, and the next turn picks up the change. Nothing about the plan lives only in the runner&amp;rsquo;s memory.&lt;/p&gt;
&lt;h3 id="fresh-context-durable-handoffs"&gt;Fresh context, durable handoffs&lt;/h3&gt;
&lt;p&gt;Every session starts in a brand new conversation, loaded with only what it needs: the instructions that apply, the plan, its own session file and contract, and the handoffs from the sessions it depends on. That&amp;rsquo;s the fix for drift: there&amp;rsquo;s no long transcript for early decisions to fade out of.&lt;/p&gt;
&lt;p&gt;It also means the handoff has to carry everything. When a session finishes, the agent fills in its handoff: the files it modified, the key decisions it made, anything blocking the next session, and notes such as why it reran a check. Two optional sections are worth singling out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Discovered facts&lt;/strong&gt; record what implementation proved about the plan&amp;rsquo;s assumptions (&amp;ldquo;the config loader already caches; no need for a second layer&amp;rdquo;), so the next session doesn&amp;rsquo;t spend its context re-researching a settled question.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open questions&lt;/strong&gt; hand forward what&amp;rsquo;s still uncertain, named, instead of leaving it to be rediscovered.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My test for a handoff is blunt: if losing the transcript changes what the next session is allowed to do, the handoff is incomplete. Conversations are disposable; the plan directory is the memory.&lt;/p&gt;
&lt;h3 id="pausing-is-a-feature"&gt;Pausing is a feature&lt;/h3&gt;
&lt;p&gt;Agents fail in loops more than in crashes: rereading the same files, rerunning the same green check, restating the same hypothesis as a &amp;ldquo;new&amp;rdquo; fix. Left alone, an unattended run will happily burn an hour that way. So a session that can&amp;rsquo;t make progress doesn&amp;rsquo;t keep trying; it pauses, and a pause is a durable state transition with a stable reason, not an abandoned conversation.&lt;/p&gt;
&lt;p&gt;The vocabulary is deliberately small and fixed: &lt;code&gt;blocked&lt;/code&gt; for a decision only I can make, &lt;code&gt;unsafe&lt;/code&gt; when continuing could do damage, &lt;code&gt;verify-failed&lt;/code&gt; when the contract didn&amp;rsquo;t pass after repairs, &lt;code&gt;no-contract&lt;/code&gt; or &lt;code&gt;malformed-contract&lt;/code&gt; when there&amp;rsquo;s nothing trustworthy to verify against, a guard violation, and so on. The agent isn&amp;rsquo;t allowed to invent new reasons. Each pause records what blocked it and the evidence, so the next step is obvious. That makes &amp;ldquo;why did it stop?&amp;rdquo; a question with an answer, and it means a retry has to come with something new — a changed hypothesis, a fixed fixture, a decision — rather than the same attempt with more hope.&lt;/p&gt;
&lt;p&gt;It took me a while to stop treating pauses as failures. &lt;strong&gt;A necessary pause is the system working.&lt;/strong&gt; A run that pushes through an unresolved decision to keep its completion rate up is worse than one that stops and asks.&lt;/p&gt;
&lt;h3 id="the-controls-i-use-all-the-time"&gt;The controls I use all the time&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;--harness&lt;/code&gt; picks the agent: Claude Code, Codex or Copilot CLI. The same plan runs on any of them, and I can switch mid-run for the remaining sessions with &lt;code&gt;asl control select-harness&lt;/code&gt;. A few other controls I use all the time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;asl control stop-after-current&lt;/code&gt;&lt;/strong&gt; lets the current session finish and then exits cleanly, so the next &lt;code&gt;asl run&lt;/code&gt; picks up where it stopped. It&amp;rsquo;s the polite version of Ctrl-C.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--max-sessions N&lt;/code&gt;&lt;/strong&gt; runs at most &lt;code&gt;N&lt;/code&gt; sessions and stops successfully. Useful when I want to look at the first session&amp;rsquo;s output before trusting the rest.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pauses with questions.&lt;/strong&gt; If an agent hits a decision it shouldn&amp;rsquo;t make alone, the session pauses with &lt;code&gt;reason: blocked&lt;/code&gt;. &lt;code&gt;asl questions PLAN_DIR&lt;/code&gt; renders the questions, and &lt;code&gt;asl run PLAN_DIR --reply &amp;quot;...&amp;quot;&lt;/code&gt; resumes the paused turn with my answer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--review-harness codex&lt;/code&gt;&lt;/strong&gt; adds a final session where a &lt;em&gt;different&lt;/em&gt; agent reviews the finished work and writes its findings to a &lt;code&gt;final-review.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="a-second-agent-reviewing-cold"&gt;A second agent, reviewing cold&lt;/h3&gt;
&lt;p&gt;That last control deserves a little more space. The reviewer runs on a different harness from the implementer, isn&amp;rsquo;t allowed to change any code, and reviews &lt;em&gt;cold&lt;/em&gt;: from the plan, the contracts and the actual changes, not from the implementer&amp;rsquo;s account of them. Its job is to find where the change violates the intent, the protected behaviour, the scope or the limits of its own evidence. Its output is structured, not &amp;ldquo;looks good&amp;rdquo;: every finding has a severity, the files it points at, an explanation, what &amp;ldquo;fixed&amp;rdquo; means, and the checks that would prove it, and the run refuses a review whose summary line and findings don&amp;rsquo;t agree.&lt;/p&gt;
&lt;p&gt;Repairs for its findings are bounded too. Findings are grouped, each group gets a capped number of repair attempts, and the review-and-repair cycles themselves are capped, so a reviewer and an implementer can&amp;rsquo;t ping-pong forever. The principle I hold myself to on top of that: a repair fixes the finding inside the reviewed boundary, and anything that would change the design goes back to the plan as a new session instead of being absorbed into the fix. The cap limits rework; it never lowers the bar for acceptance.&lt;/p&gt;
&lt;p&gt;Having one model check another&amp;rsquo;s work catches a surprising number of things, but I try not to over-read it. A different model brings different habits for finding failures, not independent evidence. What actually decides acceptance is still the checks, the reproducers and me reading the diff.&lt;/p&gt;
&lt;!-- TODO(seb): an example of a review finding from a second harness that the first one missed. --&gt;
&lt;p&gt;When the run ends, it ends with an explicit reason: &lt;code&gt;all-complete&lt;/code&gt;, &lt;code&gt;max-sessions&lt;/code&gt; or &lt;code&gt;stopped&lt;/code&gt; for the happy paths, or a named pause like a failing check or a guard violation. There is no &amp;ldquo;it just stopped&amp;rdquo;. And &amp;ldquo;all-complete&amp;rdquo; still means &lt;em&gt;the contracts passed&lt;/em&gt;, not &lt;em&gt;the change is correct&lt;/em&gt;: it&amp;rsquo;s the point where I go and read the diff, the handoffs and the review, not the point where I merge.&lt;/p&gt;
&lt;h2 id="guardrails-briefly"&gt;Guardrails, briefly&lt;/h2&gt;
&lt;p&gt;Once a run is unattended, you need a way to steer it, and the most important distinction I ended up drawing is between &lt;em&gt;advice&lt;/em&gt; and &lt;em&gt;enforcement&lt;/em&gt;. Telling an agent not to deploy is steering; making sure it can&amp;rsquo;t reach the deploy credentials is a boundary. A prompt expresses intent, never authority.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Guidance is advice.&lt;/strong&gt; I can send a running session a note (&amp;ldquo;prefer the existing date helper over adding a dependency&amp;rdquo;) and it&amp;rsquo;s delivered into the conversation. It can shape implementation choices, but it can&amp;rsquo;t change the session&amp;rsquo;s scope or its completion contract.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only a guard enforces.&lt;/strong&gt; &lt;code&gt;asl control guard add&lt;/code&gt; can deny a command (matched as an exact argument prefix and enforced by a per-run &lt;code&gt;PATH&lt;/code&gt; shim) or protect a path (compared against a snapshot taken at the start of the turn). A violation rejects the turn and pauses the run. It never rolls anything back, so I can always see exactly what the agent did.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A guard also reports, per harness, whether it is &lt;em&gt;active&lt;/em&gt;, &lt;em&gt;degraded&lt;/em&gt; or &lt;em&gt;unsupported&lt;/em&gt;. Not every agent CLI exposes the same hooks, and I&amp;rsquo;d rather have a guard say &amp;ldquo;I can&amp;rsquo;t enforce this here&amp;rdquo; than quietly imply it did.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s more to supervising a run than this, like a mailbox that lets a running agent ask questions without stopping, and a separate &amp;ldquo;overseer&amp;rdquo; that watches runs across projects. They all follow the same rule: an AI that can be argued into an action must never be the guard.&lt;/p&gt;
&lt;h2 id="when-this-is-overkill"&gt;When this is overkill&lt;/h2&gt;
&lt;p&gt;Most changes don&amp;rsquo;t need any of this. A local, reversible edit with a test that already covers it needs a boundary, a check and a review — that&amp;rsquo;s it. I reach for a full plan and an unattended run when a change spans several sessions&amp;rsquo; worth of work, when the order of the steps matters, or when I want the run to make progress while I&amp;rsquo;m doing something else. The pipeline exists so every decision has a home when a change is big enough to need one, not so every typo fix carries maximum ceremony.&lt;/p&gt;
&lt;p&gt;A quick way to tell: before handing a task to an agent, can I state the observable outcome and one behaviour that must not change, bound the files involved, name a check that would fail for a plausible wrong implementation, and point to someone (usually me) who can actually absorb the diff? If one of those answers is &amp;ldquo;no&amp;rdquo; or &amp;ldquo;not sure&amp;rdquo;, the right next step is usually a smaller precursor — reproduce the bug, inventory the callers, write the failing test — rather than the whole change.&lt;/p&gt;
&lt;h2 id="lessons-from-four-months-of-building-it"&gt;Lessons from four months of building it&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asl&lt;/code&gt; started as a small loop in a script in early June 2026. Four months later it&amp;rsquo;s about 180,000 lines of standard-library-only Python with about 270,000 lines of tests, built largely by running plans through the tool itself. A few things I&amp;rsquo;d tell myself at the start:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;More tests than code is not a vanity metric.&lt;/strong&gt; When most of the code is written by agents, the tests are the specification, and they&amp;rsquo;re what makes the next change safe. There is also a &lt;code&gt;reliability-stress&lt;/code&gt; suite that reruns timing-sensitive scenarios under load and across time zones, because &amp;ldquo;it passed on my machine at 3 p.m.&amp;rdquo; is not good enough for something that runs unattended overnight.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make failures early and loud.&lt;/strong&gt; Every hour spent on preflight, baselines and repair hints has paid itself back many times over in runs that didn&amp;rsquo;t die halfway.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Promote automation by maturity, not enthusiasm.&lt;/strong&gt; Almost every piece of &lt;code&gt;asl&lt;/code&gt; went through the same ladder: do it by hand while watching, write it down as a checklist or skill, script the deterministic parts, and only then enforce it in the runner. Skipping a rung always produced something that failed in a way I didn&amp;rsquo;t yet understand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turn each run failure into a control.&lt;/strong&gt; The best features came from runs that went wrong. Agents pausing the whole run for every small question became a live question-and-reply channel; answers that were accepted but never actually read by the agent became receipts proving the agent consumed them. Each one started as a reproducer from a real run and landed as its own reviewed change — never as a quick patch in the middle of the run that exposed it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write down the reason for every stop.&lt;/strong&gt; Every pause and every exit has a stable, named reason. That made the tool scriptable, and made it possible to build a supervisor on top of it at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t trust a harness to enforce what it can&amp;rsquo;t.&lt;/strong&gt; Supporting three agent CLIs taught me that they differ a lot in what they can actually guarantee, and that the honest answer is to report capabilities instead of assuming them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Be suspicious of feeling faster.&lt;/strong&gt; A &lt;a href="https://arxiv.org/abs/2507.09089"&gt;2025 randomized trial by METR&lt;/a&gt; found experienced open-source maintainers were about 19% &lt;em&gt;slower&lt;/em&gt; with early-2025 AI tooling on their own repositories, while believing they&amp;rsquo;d been faster. That&amp;rsquo;s not a verdict on today&amp;rsquo;s tools, but it&amp;rsquo;s a good reason to judge a workflow by what passes review rather than by how productive a session felt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standard library only has been worth it.&lt;/strong&gt; No dependency upgrades, no virtual environment to break, and the whole thing installs by symlinking a directory with GNU Stow, alongside the rest of &lt;a href="https://www.sglavoie.com/posts/managing-dotfiles-with-git-bare-repository/"&gt;my dotfiles&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- TODO(seb): what broke along the way, and what held up better than expected. --&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The biggest change wasn&amp;rsquo;t any single feature; it was moving &amp;ldquo;done&amp;rdquo; out of the agent&amp;rsquo;s hands. Once every session has a contract that a program checks, the rest follows naturally: sessions can be small and start fresh, runs can be unattended, pauses become information instead of mysteries, a second agent can review the first one&amp;rsquo;s work, and I can spend my attention on the plan and the review instead of on babysitting a conversation.&lt;/p&gt;
&lt;p&gt;If you work with coding agents a lot, my advice is to start there, and to start small. Pick one bounded task you&amp;rsquo;d normally do yourself in under an hour. Before handing it over, write down what &amp;ldquo;done&amp;rdquo; means and one check that would fail if the agent got it plausibly wrong. Then review the diff against that, not against the agent&amp;rsquo;s summary. If it doesn&amp;rsquo;t hold up, you&amp;rsquo;ve lost one session and gained a concrete reason; if it does, you have your first contract.&lt;/p&gt;
&lt;h2 id="resources-and-references"&gt;Resources and references&lt;/h2&gt;
&lt;h3 id="external-links"&gt;External links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.claude.com/en/docs/claude-code/skills"&gt;Agent Skills - Claude Code docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.claude.com/en/docs/claude-code/hooks"&gt;Hooks - Claude Code docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2507.09089"&gt;Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity (METR)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Secure_Coding_with_AI_Cheat_Sheet.html"&gt;OWASP Secure Coding with AI Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/stow/"&gt;GNU Stow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="from-this-website"&gt;From this website&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.sglavoie.com/posts/systematic-reviews/"&gt;Systematic reviews&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sglavoie.com/posts/git-worktrees-for-a-better-parallel-workflow/"&gt;Git worktrees for a better parallel workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sglavoie.com/posts/managing-dotfiles-with-git-bare-repository/"&gt;Managing dotfiles with a Git bare repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Fri, 09 Oct 2026 16:20:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/from-plan-to-unattended-agent-runs/</guid><category>workflow</category><category>ai</category><category>agents</category><category>automation</category><category>claude-code</category><category>productivity</category><category>python</category></item><item><title>Git the gist of it: common commands for a working workflow</title><link>https://www.sglavoie.com/posts/git-the-gist-of-it-common-commands-for-a-working-workflow/</link><description>Git is such a fascinating piece of software. It is not the only distributed version control system out there, but it is certainly ubiquitous in that category and has become a tool that must be mastered by any software developer in the modern era.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Git, the friend you wish you had met earlier, when organizing files like &lt;code&gt;report 1.pdf&lt;/code&gt;, &lt;code&gt;report 2.pdf&lt;/code&gt; and &lt;code&gt;report final 1.pdf&lt;/code&gt; still made sense somehow. It&amp;rsquo;s undoubtedly complicated to wrap one&amp;rsquo;s head around it at first, although there exist some GUIs to make the journey smoother – the best examples that come to mind would include &lt;a href="https://www.gitkraken.com/"&gt;GitKraken&lt;/a&gt; and &lt;a href="https://www.git-tower.com/"&gt;Tower&lt;/a&gt; at the top of the list. I have been advised to learn to use Git from the terminal and I would, without flinching, recommend anyone to do the same to really grok this tool and get an intuitive feel for what it does.&lt;/p&gt;
&lt;p&gt;Beyond the extraordinary technical prowess that it is, Git can be useful to a broad audience. It&amp;rsquo;s not good at dealing with large binary files (and &lt;a href="https://git-lfs.github.com/"&gt;Git LFS&lt;/a&gt; is not exactly easy to use just yet to cover that case), but for anything involving text that a human can read, it shines – may it be a programming language, some reports written with &lt;a href="https://www.latex-project.org/"&gt;LaTeX&lt;/a&gt;, some diagrams produced with &lt;a href="http://mermaid-js.github.io/mermaid/#/"&gt;Mermaid&lt;/a&gt; or &lt;a href="https://plantuml.com/"&gt;PlantUML&lt;/a&gt;, personal notes taken in plain text or in Markdown or the fact that synchronizing changes made to a project is a breeze and allows ones to work from multiple locations and machines.&lt;/p&gt;
&lt;p&gt;With platforms like &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; and &lt;a href="https://about.gitlab.com/"&gt;GitLab&lt;/a&gt;, it is easy to keep a &amp;ldquo;backup&amp;rdquo; of projects, which can be either public or private. And despite Git not being awesome with very large files, any smaller binary files like images and PDF files can easily be added to a Git repository, allowing users to keep different versions of these files very easily without using a cloud service such as Dropbox or Google Drive. So even if the original input is not written in a text-friendly manner, the output can still be saved under multiple versions with great details, backed up to different websites and fetched just as conveniently from anywhere else (assuming access has been set up to continue working on a project, or at least one can log in to the website and download files without issue).&lt;/p&gt;
&lt;p&gt;Sure, it is not for everyone, but the use cases just described can go a long way. I have used it to practice solving programming challenges, to document all my project at the university, to keep track of preferences and configuration files for my different systems (Linux and macOS) which I&amp;rsquo;ve described in &lt;a href="https://www.sglavoie.com/posts/managing-dotfiles-with-git-bare-repository/"&gt;Managing dotfiles with a Git bare repository&lt;/a&gt;, to work on pet programming projects and coding experiments that I keep private, to store code snippets into a growing library for reference purposes, to take notes in the form of &amp;ldquo;tutorials&amp;rdquo; or &amp;ldquo;wiki&amp;rdquo; (platforms like GitHub and GitLab have a nice wiki feature that renders prose nicely!) for different tasks I need to do infrequently and of course to build this very website in the open (the source code is &lt;a href="https://github.com/sglavoie/sglavoie.github.io-source"&gt;available on GitHub&lt;/a&gt;)! And that is just describing some of my personal use cases without touching on the fact that collaboration within a team is a huge reason to use it!&lt;/p&gt;
&lt;p&gt;So with that said, let&amp;rsquo;s explore some of its functionality, starting with a few tips and tricks, then delving deeper into a real-world workflow and topping it off with more useful commands and configuration settings.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="global-and-local-gitignore"&gt;Global and local &lt;code&gt;.gitignore&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;There are files we never care about adding to Git repositories, such as a thumbnail cache file &lt;code&gt;Thumbs.db&lt;/code&gt; on Windows or a &lt;code&gt;.DS_Store&lt;/code&gt; file storing custom attributes for folders on macOS. Instead of ignoring these kinds of entries in a per-repository &lt;code&gt;.gitignore&lt;/code&gt; file which might not contain everything we would like to exclude, it can be simpler and more efficient to use a global &lt;code&gt;.gitignore&lt;/code&gt;, which serves the same purpose but for &lt;em&gt;any&lt;/em&gt; Git repository regardless of the presence of a &lt;code&gt;.gitignore&lt;/code&gt; in that specific repository! In other words, this serves as a permanent list of things to ignore so that there is no need to remember about them later.&lt;/p&gt;
&lt;p&gt;The setup is straightforward: create a file &lt;code&gt;~/.gitignore&lt;/code&gt;, fill it as usual with patterns you are sure to want to exclude globally and set a configuration option to use that file – for instance by adding the following to &lt;code&gt;.gitconfig&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;git&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;pre tabindex="0"&gt;&lt;code class="language-git" data-lang="git"&gt;[core]
 excludesfile = ~/.gitignore&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.toptal.com/"&gt;Toptal&lt;/a&gt; provides &lt;a href="https://docs.gitignore.io/install/command-line"&gt;a nice tool on the command-line&lt;/a&gt; that can be used to easily exclude patterns. With it, typing &lt;code&gt;gi python &amp;gt;&amp;gt; .gitignore&lt;/code&gt; would append a bunch of common patterns to a &lt;code&gt;.gitignore&lt;/code&gt; file – in this case, for Python.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="meaningful-commit-messages-with-gitmessage"&gt;Meaningful commit messages with &lt;code&gt;.gitmessage&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Besides using the excellent &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/"&gt;Conventional Commits&lt;/a&gt; specification to write messages in a format that makes sense to other fellow human beings, using a template for Git commits can help with remembering &lt;em&gt;why&lt;/em&gt; commits are made and how they should be structured. There is a configuration setting, &lt;code&gt;commit.template&lt;/code&gt;, that can be used to set the default text being displayed when a text editor opens after typing &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The following is the current template I use, which can be saved in a file like &lt;code&gt;~/.gitmessage&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# [Add/Fix/Remove/Update/Refactor/Document] [summary]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Why is it necessary? (Bug fix, feature, improvements?)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# How does the change address the issue?
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# What side effects does this change have?
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Include a link to the ticket, if any.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then, this can be added to the config file under the &lt;code&gt;[commit]&lt;/code&gt; section like so:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;git&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;pre tabindex="0"&gt;&lt;code class="language-git" data-lang="git"&gt;[commit]
 template = ~/.gitmessage&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;All lines starting with a hash symbol (&lt;code&gt;#&lt;/code&gt;) will be ignored, so there is no need to manually delete all of this verbose content when saving the commit message. Sweet!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="my-usual-git-workflow"&gt;My usual Git workflow&lt;/h2&gt;
&lt;p&gt;This section depends very much on team standards, if applicable. But in general terms and considering mostly a solo interaction with Git, I like to adhere to the following processes, without taking into account how one would plan, produce diagrams, brainstorm, etc. That shall be the topic of an upcoming post!&lt;/p&gt;
&lt;h2 id="starting-a-new-project"&gt;Starting a new project&lt;/h2&gt;
&lt;p&gt;There are different ways to proceed, although I like the simplicity of just creating a new empty repository on GitHub and cloning it on my machine using the SSH protocol, e.g. &lt;code&gt;git clone git@github.com:some/project.git&lt;/code&gt;. This has the benefit of automatically setting the &lt;code&gt;main&lt;/code&gt; branch and the remote URL, using &lt;code&gt;origin&lt;/code&gt; as the default remote. Cloning an empty repository has the same effect as starting with &lt;code&gt;git init&lt;/code&gt;, so this also becomes unnecessary.&lt;/p&gt;
&lt;p&gt;If I have been experimenting locally first, I would do a &lt;code&gt;git init&lt;/code&gt;, commit any changes and then push the new repository on GitHub, either using the great Git integration provided by VS Code or again creating a new repository on GitHub to set the remote URL in order to be able to push local changes, i.e. by doing &lt;code&gt;git remote add origin git@github.com:some/project.git&lt;/code&gt; and then pushing to that new URL. To make sure that my default branch is always &lt;code&gt;main&lt;/code&gt; (to match the new default on GitHub) and not something like &lt;code&gt;dev&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt;, I have a Git template lying around that ensures that the first branch created when doing &lt;code&gt;git init&lt;/code&gt; will be &lt;code&gt;main&lt;/code&gt;. It is as simple as creating the file &lt;code&gt;~/.git-templates/HEAD&lt;/code&gt; with this content:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ref: refs/heads/main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then, in &lt;code&gt;~/.gitconfig&lt;/code&gt;, the following section is used to read the templates:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;git&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;pre tabindex="0"&gt;&lt;code class="language-git" data-lang="git"&gt;[init]
 defaultBranch = main
 templateDir = ~/.git-templates&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I have this template since before &lt;code&gt;init.defaultBranch&lt;/code&gt; was introduced in Git 2.28.0 back in July 2020: now just having the option &lt;code&gt;defaultBranch&lt;/code&gt; will do the trick. Still, it&amp;rsquo;s good to have a &lt;code&gt;templateDir&lt;/code&gt; configured for other purposes! Although admittedly, I don&amp;rsquo;t use them at all and would rather create a custom command to more easily script what I need for each repository: more on this in the section &lt;a href="#custom-git-sub-commands"&gt;Custom Git sub-commands&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="committing-to-an-existing-project"&gt;Committing to an existing project&lt;/h2&gt;
&lt;p&gt;Now that there is some folder set up for Git to track files, it&amp;rsquo;s time to make changes! I&amp;rsquo;m a big fan of committing &amp;ldquo;small and often&amp;rdquo; because Git is super flexible and updating the history is usually a simple process – unless you have pushed to a remote repository used by other people, in which case being a &amp;ldquo;force push&amp;rdquo; type of person won&amp;rsquo;t make you many friends. May the &lt;code&gt;--force&lt;/code&gt; be with you when you push to a private repository where you&amp;rsquo;re the only contributor, otherwise, it&amp;rsquo;s good practice to think twice before sending your final changes away as you should not mess up with public history (and depending on how your access is set up within a team, you might not even be able to use the &lt;code&gt;--force&lt;/code&gt; flag when pushing on certain branches!).&lt;/p&gt;
&lt;p&gt;So what&amp;rsquo;s the alternative to constantly rewriting history in a harmful way? Well, assuming you have a choice when working alone for instance, there are two main contenders: &lt;em&gt;merge&lt;/em&gt; vs &lt;em&gt;rebase&lt;/em&gt;. I think neither option is better than the other when used right, but it&amp;rsquo;s good to know that &lt;em&gt;rebase&lt;/em&gt; might create possible headaches because it modifies the Git history while &lt;em&gt;merge&lt;/em&gt; might create undesirable noise when used profusely by adding &amp;ldquo;merge commits&amp;rdquo;. I use both techniques, but for different purposes.&lt;/p&gt;
&lt;h3 id="being-committed"&gt;Being committed&lt;/h3&gt;
&lt;p&gt;The basic workflow might look like this, with a couple of different options thrown in to cover more scenarios:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check the current state of the repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Inspect the changes to commit (before staging)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Stage a file to be committed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add SOME_FILE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Stage all new/modified files, (i.e., --all)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add -A
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Stage all modified files (not any new ones, i.e., --update)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add -u
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get fancy with adding patches only (part of files)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add -p
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Undo changes done to a tracked file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git restore -- FILE_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Inspect staged changes to commit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff --staged
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Unstage files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git reset HEAD --
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# or just &amp;#39;git commit&amp;#39; to open a text editor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m &lt;span class="s2"&gt;&amp;#34;SOME_MESSAGE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# See the changes done in the latest commit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git show
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# or a specific commit hash from earlier&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git show COMMIT_HASH &lt;span class="c1"&gt;# or ref like HEAD^&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Forgot to add something?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add SOME_OTHER_FILE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit --amend --no-edit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Want to rephrase the last commit?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit --amend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Tag the latest commit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git tag TAG_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Tag earlier commit with annotation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git tag -a TAG_NAME COMMIT_HASH -m &lt;span class="s2"&gt;&amp;#34;MESSAGE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Undo a commit, keeping changes in the work tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git reset HEAD^
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Undo a commit and DO NOT keep changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git reset --hard HEAD^
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Oops, get back a commit that was &amp;#34;lost&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git reflog &lt;span class="c1"&gt;# find the relevant commit hash&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git cherry-pick COMMIT_HASH &lt;span class="c1"&gt;# or git checkout COMMIT_HASH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Explore the repo at an earlier commit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout COMMIT_HASH
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Committed some changes while checking out an old commit?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Save the changes to a new branch, then potentially merge them back&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git switch -c NEW_BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git switch OTHER_BRANCH
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge NEW_BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Undo a merge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git reflog &lt;span class="c1"&gt;# find the commit hash before the merge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git reset --hard COMMIT_HASH
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Or undo to a known point from a remote branch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git reset --hard origin/main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Stop tracking a file/directory (remove) but keep it on disk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rm --cached FILE_OR_DIRECTORY
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Remove stuff that hasn&amp;#39;t been committed yet (interactive mode is nice)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Don&amp;#39;t forget about -n for a dry run first!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clean -i
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Want to undo a change that&amp;#39;s already pushed?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Add a new commit without rewriting history&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git revert COMMIT_HASH
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# See who did what to which file and when&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git blame FILE_NAME&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Arguably, basic editing doesn&amp;rsquo;t require stashing, but that can be helpful for a quick modification, like temporarily saving changes to quickly switch to another branch or pull some remote changes without having to commit first.&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# git stash --help - &amp;#34;Stash the changes in a dirty working directory away&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Maybe you want to keep changes around without committing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --include-untracked and --keep-index might be needed!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Stash changes with a clearer name/purpose&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash save &lt;span class="s2"&gt;&amp;#34;SOME MESSAGE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Selectively stash changes (keep specific lines)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash save -p
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# List existing stashes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# See the summary of a stash&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash show
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# See all changes made in a stash (patch)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash show -p
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Apply changes from a stash (TAB completion after `apply` is useful)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash apply stash@&lt;span class="se"&gt;\{&lt;/span&gt;SOME_ID&lt;span class="se"&gt;\}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Apply and remove the last stash at the same time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash pop
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Remove a single stash&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash drop stash@&lt;span class="se"&gt;\{&lt;/span&gt;SOME_ID&lt;span class="se"&gt;\}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Remove all stashes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git stash clear&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="rebase"&gt;&lt;code&gt;rebase&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;When working locally with changes that are not yet part of the &amp;ldquo;permanent&amp;rdquo; Git history, I like to &lt;code&gt;git rebase&lt;/code&gt; very much to clean things up before making a &lt;code&gt;git push&lt;/code&gt;, which I like to view as an irrevocable decision. Because I &lt;em&gt;commit small and often&lt;/em&gt;, it&amp;rsquo;s often the case that I end up with a couple of very simple commits which really belong together and should form a bigger commit. While committing a big chunk of code at once avoids having to do any &lt;code&gt;rebase&lt;/code&gt; in the first place, it&amp;rsquo;s also inconvenient to undo a substantial amount of work when you&amp;rsquo;re experimenting and/or working on an unfamiliar codebase. So in the end, my preference goes towards smaller commits because rebasing is actually fun to do and lets you believe that you came up with brilliant solutions on your first attempt :). That makes for a cleaner Git history for sure, although you will lose some context if you never &lt;code&gt;merge&lt;/code&gt;. Meaning, rebasing creates a &amp;ldquo;linear&amp;rdquo; history while merging from different branches shows a more complete picture of how a repository really took shape over time. My simple rule of thumb on the matter is this: use &lt;code&gt;rebase&lt;/code&gt; to consistently ship meaningful commits (good descriptions, fewer typos, changes chunked logically and precisely, etc.) and use &lt;code&gt;merge&lt;/code&gt; to incorporate somewhat larger pieces of history, like a new feature coming from a &amp;ldquo;feature branch&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Some common commands I use:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# git rebase --help - &amp;#34;Reapply commits on top of another base tip&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Include all commits up to COMMIT_HASH, included&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase -i COMMIT_HASH^
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Include most recent commit only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase -i HEAD^
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Include 2 most recent commits&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase -i HEAD^^
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Include 3 most recent commits&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase -i HEAD~3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# make BRANCH have the history up to COMMIT_OR_BRANCH, included&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase COMMIT_OR_BRANCH BRANCH
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Used after resolving a conflict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase --continue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Reset to where you were before rebasing (move HEAD)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase --abort
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# To update the next actions to be taken on the remaining commits&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase --edit-todo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There are a bunch of obscure options just like almost any other Git command in existence, but for that there is help available for each command (such as &lt;code&gt;git rebase --help&lt;/code&gt;) from the terminal and the trusty Stack Overflow ;).&lt;/p&gt;
&lt;h4 id="sample-workflow"&gt;Sample workflow&lt;/h4&gt;
&lt;p&gt;In the case of &lt;code&gt;rebase&lt;/code&gt;, I enjoy working in this way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make small commits, maybe 5 to 10 depending on the complexity of the project – usually as long as a series of commits relates to a single topic whenever possible.&lt;/li&gt;
&lt;li&gt;Have a peak at the recent history with &lt;code&gt;git log&lt;/code&gt; to have a good idea of what just happened.&lt;/li&gt;
&lt;li&gt;Realize that the history can be improved. Find the oldest commit hash (not pushed yet!), take note of it and run &lt;code&gt;git rebase -i COMMIT_HASH^&lt;/code&gt; (with the &amp;ldquo;hat&amp;rdquo; &lt;code&gt;^&lt;/code&gt; at the end to reference the parent of that commit).&lt;/li&gt;
&lt;li&gt;This opens up a text editor with some explanations on how to proceed (for more on this, have a look at this great article on &lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history"&gt;Rewriting history&lt;/a&gt;). From there, I usually use &lt;code&gt;r&lt;/code&gt; to reword, &lt;code&gt;s&lt;/code&gt; to squash, &lt;code&gt;e&lt;/code&gt; to edit and sometimes &lt;code&gt;f&lt;/code&gt; to fixup, besides also re-ordering commits and from time to time deleting one by removing the line entirely.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt; is pretty harmless as it will just show up a new window where the commit message and description can be modified.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt; is more destructive because commits will be &amp;ldquo;merged&amp;rdquo; together! No actual change is lost, but if you squash a ton of commits by accident, it will create huge commits and you might want to undo that with &lt;code&gt;reflog&lt;/code&gt; before it&amp;rsquo;s too late (Atlassian has more to say about this in &lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history/git-reflog"&gt;git reflog&lt;/a&gt;). The &lt;code&gt;s&lt;/code&gt; option is also nice because it keeps all commit messages, so you can edit the final log message as needed without discarding messages.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;e&lt;/code&gt; is used to modify the actual source code being committed, maybe to fix a typo or a minor bug after realizing that the test suite no longer passes (assuming you are not programming blindly without tests :)). This can cause some &amp;ldquo;conflicts&amp;rdquo; if you change some lines which are also part of other commits in the selection you made originally, so one has to be careful with that. This can also be used in conjunction with &lt;code&gt;git reset HEAD^&lt;/code&gt; to &amp;ldquo;cancel&amp;rdquo; the current commit when doing the rebase in order to split it into multiple smaller commits, which can then be &amp;ldquo;&lt;code&gt;git add&lt;/code&gt;ed&amp;rdquo; back, followed by a &lt;code&gt;git rebase --continue&lt;/code&gt; to keep going.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt; is a quick way of squashing commits together while discarding messages you don&amp;rsquo;t need. So maybe the last commit has a proper description (&amp;ldquo;Implemented something&amp;hellip;&amp;rdquo;) and a few commits before that one were just temporary &amp;ldquo;savepoints&amp;rdquo; with non-sensical commit messages (things like &amp;ldquo;testing&amp;hellip;&amp;rdquo; or &amp;ldquo;new commit&amp;rdquo;) that were done until you reached a final solution that&amp;rsquo;s worth committing. So of course in that case the history would be pretty ugly and hard to understand if all commits were kept intact, so these can be added to the latest change which encompasses a working solution as a whole. Just as well, maybe that last commit didn&amp;rsquo;t have a complete message just yet, so it could also be rewritten with the &lt;code&gt;r&lt;/code&gt; prefix.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When individual commits make the &lt;code&gt;rebase&lt;/code&gt; stop temporarily (such as when a commit is to be edited with &lt;code&gt;e&lt;/code&gt; and waits for changes to be made), then it&amp;rsquo;s time to do &lt;code&gt;git rebase --continue&lt;/code&gt; once the necessary changes are made.&lt;/li&gt;
&lt;li&gt;If something goes wrong along the way, there&amp;rsquo;s always a way back to the place you were right before rebasing with &lt;code&gt;git rebase --abort&lt;/code&gt;. It&amp;rsquo;s worth noting that Git itself will output some useful messages all along so it&amp;rsquo;s not necessary to remember all of this: it quickly becomes intuitive.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, &lt;code&gt;rebase&lt;/code&gt; covers the cases where local changes are done in isolation, but for something more imposing or simply to keep track of what happened in which branch, &lt;code&gt;merge&lt;/code&gt; remains a powerful ally.&lt;/p&gt;
&lt;h3 id="merge"&gt;&lt;code&gt;merge&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;So I don&amp;rsquo;t use &lt;code&gt;merge&lt;/code&gt; as much, especially when working solo, but it is undeniably useful and could replace the &lt;code&gt;rebase&lt;/code&gt; workflow completely (it might also be demanded by your colleagues anyways!). There&amp;rsquo;s nothing like a good &lt;code&gt;rebase&lt;/code&gt; session to keep things tidy, but a flat history line won&amp;rsquo;t look attractive on a huge project with many contributors, so &lt;code&gt;merge&lt;/code&gt; is there to deal with cleanly integrating changes from different places into some &lt;code&gt;main&lt;/code&gt; branch (it could be named differently based on the team workflow of course and there might be more than one &amp;ldquo;main&amp;rdquo; branch too). What makes &lt;code&gt;merge&lt;/code&gt; incredibly cool is the fact that branches in Git are &amp;ldquo;cheap&amp;rdquo;, meaning they can be created very quickly and efficiently, they don&amp;rsquo;t take space at all, you could have dozens of branches or more and you can incorporate changes from one branch to another with a simple &lt;code&gt;git merge&lt;/code&gt;, which is nicer than using &lt;code&gt;git cherry-pick&lt;/code&gt; to get multiple commits from one branch into another (for one or two commits though, &lt;code&gt;cherry-pick&lt;/code&gt; is handy).&lt;/p&gt;
&lt;p&gt;I see &lt;code&gt;rebase&lt;/code&gt; more like a cleaning step while &lt;code&gt;merge&lt;/code&gt; really shines when dealing with multiple commits between different branches. Even on a simple project when working alone, it has its uses! For example, let&amp;rsquo;s say we have a repository full of small programming challenges (maybe from &lt;a href="https://www.hackerrank.com/"&gt;HackerRank&lt;/a&gt; or &lt;a href="https://leetcode.com/"&gt;LeetCode&lt;/a&gt;). We might get stuck on a tricky problem and wouldn&amp;rsquo;t want to commit an unfinished solution. Also, maybe we would get fed up eventually working on a given challenge and would rather try our luck with a different one. Well, we can always leave changes uncommitted (not very safe as these might be lost!), but that can cause confusion and you might inadvertently end up committing files that have nothing to do with the latest challenge – effectively committing at the same time your unfinished challenge with the one you just completed. There&amp;rsquo;s always the possibility to &lt;code&gt;git stash&lt;/code&gt; individual files to keep them somewhere, but I find working with stashes to be a bit more cumbersome than branches and you might literally forget that you have changes stashed. If you do that a few times, you might not even know which stash is what if you didn&amp;rsquo;t give them a good name&amp;hellip;&lt;/p&gt;
&lt;p&gt;Some common commands I use:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# git merge --help - &amp;#34;Join two or more development histories together&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get commits from BRANCH_NAME into the currently checked one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Merge one branch into another&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge SOURCE_BRANCH_NAME DESTINATION_BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get out of conflicts...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge --abort
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Continue after resolving conflicts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge --continue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Keep the &amp;#34;merge commit&amp;#34; in the history&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge --no-ff BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Set a custom commit message for a &amp;#34;merge commit&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge -m &lt;span class="s2"&gt;&amp;#34;MESSAGE&amp;#34;&lt;/span&gt; BRANCH&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;sub&gt;Tip: The command &lt;code&gt;git merge --help&lt;/code&gt; describes some nice examples about the whole process of conflict resolution.&lt;/sub&gt;&lt;/p&gt;
&lt;h4 id="sample-workflow-kinda"&gt;Sample workflow (kinda)&lt;/h4&gt;
&lt;p&gt;So, instead of risking losing changes like this, creating a new branch with &lt;code&gt;git switch -c BRANCH_NAME&lt;/code&gt; and working from there is much easier to confine changes to a specific matter, which we can see like a &amp;ldquo;feature&amp;rdquo; that can later be added to the main &amp;ldquo;trunk&amp;rdquo;. We can commit unfinished business, switch to a different branch, come back to it later, &lt;code&gt;git reset&lt;/code&gt; any old commit to &amp;ldquo;revert&amp;rdquo; the history and keep working from a clean state. In any case, there&amp;rsquo;s always &lt;code&gt;rebase&lt;/code&gt; to avoid committing useless stuff, so there&amp;rsquo;s really no reason to avoid branches.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;merge&lt;/code&gt; command will be involved when changes from a &amp;ldquo;feature branch&amp;rdquo; (or whatever other purpose you give a branch) are merged into the main branch with &lt;code&gt;git merge BRANCH_NAME&lt;/code&gt;. When there are no &amp;ldquo;merge conflicts&amp;rdquo; (such as when you work on a totally new file that won&amp;rsquo;t clash with prior work), this is a seamless workflow where you can just &lt;code&gt;merge&lt;/code&gt; as if changes were made in the branch you are on in the first place. There are other instances where bigger changes can be merged successfully in the same way, but it&amp;rsquo;s interesting to keep track of how you worked on a project, so in this scenario you can always use &lt;code&gt;git merge --no-ff BRANCH_NAME&lt;/code&gt; (&lt;code&gt;--no-ff&lt;/code&gt; meaning &amp;ldquo;&lt;em&gt;no fast-forward&lt;/em&gt;&amp;rdquo;) to keep a &amp;ldquo;&lt;em&gt;merge commit&lt;/em&gt;&amp;rdquo;, which is strictly speaking not needed (because there&amp;rsquo;s no conflict resolution in the case of a &amp;ldquo;successful&amp;rdquo; merge) but can be a helpful reference point when you look back at your Git history two years from now to understand how you worked on something, piecing things together bit by bit.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also an indisputable advantage conferred by the use of branches, which is: &lt;em&gt;you can have plenty of them&lt;/em&gt;! So while &lt;code&gt;rebase&lt;/code&gt; is nice to use on a given branch, in no way can working on multiple things at once in a single branch and then rebasing all that effort be as straightforward as creating new branches for every new topic that&amp;rsquo;s being started and then merging it back into a single place of truth. Juggling different concerns in a single branch where you have a few things going on (maybe 2-3 partially implemented features) is far from being a cozy environment and rebasing that kind of work where commits are not even related to each other can become a nightmare in a short amount of time.&lt;/p&gt;
&lt;h2 id="managing-branches"&gt;Managing branches&lt;/h2&gt;
&lt;p&gt;So with all that was written earlier, I believe a point was made in favour of using branches. Because branches are such a wonderful feature of Git, here are some more commands I rely on (surprisingly, there aren&amp;rsquo;t that many for &lt;code&gt;git branch&lt;/code&gt;!):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# git branch --help - &amp;#34;List, create, or delete branches&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# List local branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# List only remote branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch -r
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# List all branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch -a
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Delete a branch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch -d BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Delete a branch forcefully&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch -D BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Delete a remote branch (doesn&amp;#39;t matter if the local branch was deleted)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push origin --delete REMOTE_NAME/BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Rename a branch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch -m BRANCH_NAME NEW_BRANCH_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Track a specific remote branch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch BRANCH_NAME -u UPSTREAM_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# See which branches have been merged or not&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch --merged
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git branch --no-merged
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Switch to the branch last checked out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Compare changes between branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff BRANCH_ONE..BRANCH_TWO
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Compare a file across branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff BRANCH_ONE:FILE_NAME BRANCH_TWO:FILE_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# See a file from another branch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git show BRANCH_NAME:FILE_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get a file from a different branch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git restore --source OTHER_BRANCH_NAME path/to/file.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="aliases"&gt;Aliases&lt;/h2&gt;
&lt;p&gt;While I believe it&amp;rsquo;s good practice to type complete commands to remember them better, I also tend to use Git aliases for two reasons: because some deeply ingrained concepts don&amp;rsquo;t need as much reinforcement and because some obscure operations can be made so much more accessible with a pertinent mnemonic device.&lt;/p&gt;
&lt;p&gt;Some commands like &lt;code&gt;add&lt;/code&gt; just become unforgettable over time, while others – e.g., &lt;code&gt;unstage&lt;/code&gt; – just don&amp;rsquo;t exist yet. Without further ado, here is a list of the aliases I currently rely on when using Git, which comes straight from &lt;code&gt;~/.gitconfig&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For instance, instead of typing &lt;code&gt;git add&lt;/code&gt;, by setting the alias &lt;code&gt;a = add&lt;/code&gt; (see below), it is now possible to type &lt;code&gt;git a&lt;/code&gt; to get the same result.&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;git&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;pre tabindex="0"&gt;&lt;code class="language-git" data-lang="git"&gt;[alias]
 a = add
 br = branch
 c = commit
 ca = commit --amend
 can = commit --amend --no-edit
 ch = checkout
 d = diff
 ds = diff --staged
 po = push origin
 pos = push --set-upstream origin main
 rc = rebase --continue
 ri = rebase -i
 rl = reflog
 sh = show
 s = status --short
 st = status
 sw = switch
 t = tag
 unstage = reset HEAD --

 ; show changes since last commit
 difflast = diff --cached HEAD^

 ; show last commit
 last = l -1 HEAD

 ; undo last commit
 undo = &amp;#34;!f() { git reset --hard $(git rev-parse \
--abbrev-ref HEAD)@{${1-1}}; }; f&amp;#34;

 l = log

 ; short log
 sl = shortlog

 ; log graph
 lg = l --color --graph --pretty=format:&amp;#39;%Cred%h%Creset \
-%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&amp;lt;%an&amp;gt;%Creset&amp;#39; --abbrev-commit

 ; log name
 ln = l --name-only

 ; log decorate all
 logda = l --oneline --decorate --graph --all

 ; log stat
 ls = l --stat

 ; log pretty
 lp = log --pretty=&amp;#39;%C(yellow)%h %C(cyan)%ad %Cblue%aN%C(auto)%d \
%Creset%s&amp;#39; --date=relative --date-order --graph&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;At some point, using Git aliases will become second nature, but until then, it can be useful to have a separate terminal alias to list them all (or maybe you forgot the command an alias is using under the hood!). For this, you can set the following alias in a file like &lt;code&gt;~/.bash_aliases&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;gitaliases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;git config -l | grep alias | sed &amp;#34;s/^alias\.//g&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# For a fancier version displaying aliases in two columns neatly aligned:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;gitaliases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;git config -l | grep alias | sed &amp;#34;s/^alias\.//g&amp;#34; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; | sed &amp;#34;s/=/Ω/&amp;#34; | column -t -s &amp;#34;Ω&amp;#34;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That command will look in the Git configuration, extract all the lines containing &amp;ldquo;alias&amp;rdquo; and remove the &amp;ldquo;&lt;code&gt;alias.&lt;/code&gt;&amp;rdquo; prefix so that you can see all aliases in the form &lt;code&gt;a=add&lt;/code&gt; in the case of &lt;code&gt;git add&lt;/code&gt; being aliased to &lt;code&gt;git a&lt;/code&gt;. If you have a ton of aliases (which is probably a red flag&amp;hellip;), finding a specific one is just a matter of doing &lt;code&gt;gitaliases | grep keyword&lt;/code&gt;, of course replacing &lt;code&gt;keyword&lt;/code&gt; with something else ;).&lt;/p&gt;
&lt;p&gt;&lt;sub&gt;Tip: One can go further to shorten Git commands by shortening &lt;code&gt;git&lt;/code&gt; itself! You can put a line such as &lt;code&gt;alias g='git'&lt;/code&gt; in &lt;code&gt;~/.bash_aliases&lt;/code&gt; for instance. Now, &lt;code&gt;git add&lt;/code&gt; can become &lt;code&gt;g a&lt;/code&gt;. Pretty efficient! For more on Bash aliases, you might like to read &lt;a href="https://www.sglavoie.com/posts/aliases-also-known-as-terminal-users-best-friends/"&gt;Aliases: Also Known as Terminal User’s Best Friends&lt;/a&gt;.&lt;/sub&gt;&lt;/p&gt;
&lt;p&gt;This section is really just meant to give a taste of the possibilities that aliases offer. To learn about actual commands and their usage, there is nothing like the &lt;a href="https://git-scm.com/docs"&gt;official Git docs&lt;/a&gt; (there is a &lt;a href="https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases"&gt;short section on Git aliases&lt;/a&gt; too).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="custom-git-sub-commands"&gt;Custom Git sub-commands&lt;/h2&gt;
&lt;p&gt;There might be less of a need for custom-made commands to be created when so much can be done with Git alone, but there are cases where these custom additions can shine! As a concrete example, I have been updating this website with what I call my &amp;ldquo;&lt;a href="https://www.sglavoie.com/posts/what-it-took-to-propel-a-career-in-tech-in-five-years/"&gt;learning progress&lt;/a&gt;&amp;rdquo; but committing always the same kind of stuff gets boring, so I have created a simple Bash script to automate the process of publishing and committing (the content of the script is of no importance, it is only there to demonstrate that commands other than Git can be called too):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Act as custom command `git addlearning` and perform all that follows&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Assumes that `pelican` command is available&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/dev/sglavoie/sglavoie.github.io-source
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m &lt;span class="s2"&gt;&amp;#34;Add learning progress&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push origin main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pelican
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp -r &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ~/dev/sglavoie/sglavoie.github.io-source/output/* &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ~/dev/sglavoie/sglavoie.github.io/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ~/dev/sglavoie/sglavoie.github.io &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m &lt;span class="s2"&gt;&amp;#34;Add learning progress&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push origin main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/dev/sglavoie/sglavoie.github.io-source&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It is noteworthy to know that any kind of executable programs can be used, such as Ruby, Python and so on, as long as they are made available in the &lt;code&gt;$PATH&lt;/code&gt;. This will be somewhat similar on most UNIX-based system where the &lt;code&gt;PATH&lt;/code&gt; variable needs to be exported (usually in a file like &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;), for instance:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# $HOME refers to a place like /home/user on Linux or /Users/user on macOS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/dev/git-scripts:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;On Windows, there are &lt;a href="https://superuser.com/a/143121/1032549"&gt;separate instructions to be followed&lt;/a&gt;. With that done, there&amp;rsquo;s also a need to make sure the file is executable, which can be done on the command-line with &lt;code&gt;chmod +x FILENAME_HERE&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="some-lesser-known-yet-incredibly-useful-commands"&gt;Some lesser-known yet incredibly useful commands&lt;/h2&gt;
&lt;h2 id="git-bisect"&gt;&lt;code&gt;git bisect&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I try to commit working code as often as possible, but sometimes there are just bugs that have flown by and took residence in the codebase a long time ago. In this scenario, there is one tool in the Git tool belt for that very specific use case: &lt;code&gt;git bisect&lt;/code&gt;. Working with the &lt;a href="https://en.wikipedia.org/wiki/Binary_search_algorithm"&gt;binary search algorithm&lt;/a&gt;, &lt;code&gt;git bisect&lt;/code&gt; searches in a range of commits and by identifying &amp;ldquo;good&amp;rdquo; and &amp;ldquo;bad&amp;rdquo; commits, will pinpoint exactly where the issue came from in the minimum number of iterations possible. You&amp;rsquo;ll need sub-commands like &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;bad&lt;/code&gt;, &lt;code&gt;good&lt;/code&gt; and &lt;code&gt;reset&lt;/code&gt; at the very least and for more advanced use cases where automatically running a script for each commit is needed, &lt;code&gt;run&lt;/code&gt; will do the job. See &lt;a href="https://git-scm.com/docs/git-bisect"&gt;the docs on &lt;code&gt;git bisect&lt;/code&gt;&lt;/a&gt; for more.&lt;/p&gt;
&lt;h2 id="git-rerere"&gt;&lt;code&gt;git rerere&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I almost never use this in practice, but it &lt;em&gt;can&lt;/em&gt; be very useful when working in a large project where similar merge conflicts are likely to occur over time. Git can be &amp;ldquo;taught&amp;rdquo; to automatically solve merge conflicts! There are some &lt;a href="https://git-scm.com/docs/git-rerere"&gt;official docs on this&lt;/a&gt;, but I&amp;rsquo;ve found this &lt;a href="https://stackoverflow.com/a/49501436/8787680"&gt;Stack Overflow answer&lt;/a&gt; to be a more approachable read.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="a-word-on-the-configuration-file"&gt;A word on the configuration file&lt;/h2&gt;
&lt;p&gt;At the very minimum, setting a name and email will be necessary to use Git:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global user.name &lt;span class="s2"&gt;&amp;#34;Your Name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global user.email &lt;span class="s2"&gt;&amp;#34;email@example.com&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Seeing the current configuration can come in handy, too:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global --list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And in the case of this particular command, &lt;code&gt;git config&lt;/code&gt;, it can&amp;rsquo;t be emphasized enough how useful searching through the help page in the terminal will be: &lt;code&gt;git config --help&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d be remiss if I didn&amp;rsquo;t include an example of my own configuration at this point, so here it goes! To make it so that it is convenient to commit this configuration file publicly, some private settings can be &amp;ldquo;included&amp;rdquo; from other paths inside the &lt;code&gt;[include]&lt;/code&gt; block. For clarity, I&amp;rsquo;ll show what that file looks like below the main configuration file.&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# This is the content of ~/.gitconfig&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;include&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;;&lt;/span&gt; This file can add more information to extend the main configuration.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;;&lt;/span&gt; For example, when inside a directory that match a certain pattern,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;;&lt;/span&gt; we can tell Git to change our name or email &lt;span class="o"&gt;(&lt;/span&gt;e.g., when committing
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;;&lt;/span&gt; with different credentials from a work email&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; ~/Dropbox/.custom/.gitconfig
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;color&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;branch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;grep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;interactive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;ui&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;alias&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# cut out for brevity, see the section on Aliases&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;core&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; nvim
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;excludesfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; ~/.gitignore
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;pager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; diff-so-fancy &lt;span class="p"&gt;|&lt;/span&gt; less --tabs&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt; -RFX
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;commit&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;gpgsign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; ~/.gitmessage
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;mergetool &lt;span class="s2"&gt;&amp;#34;nvim&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; nvim &lt;span class="nv"&gt;$MERGED&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;difftool &lt;span class="s2"&gt;&amp;#34;vscode&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; code --wait --diff &lt;span class="nv"&gt;$LOCAL&lt;/span&gt; &lt;span class="nv"&gt;$REMOTE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;mergetool&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;color &lt;span class="s2"&gt;&amp;#34;diff-highlight&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;oldNormal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; red bold
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;oldHighlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; red bold &lt;span class="m"&gt;52&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;newNormal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; green bold
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;newHighlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; green bold &lt;span class="m"&gt;22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;color &lt;span class="s2"&gt;&amp;#34;diff&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;commit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; yellow bold
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;frag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; magenta bold
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;new&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; green bold
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;old&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; red bold
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;whitespace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; red reverse
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;push&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;recurseSubmodules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; on-demand
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;gpg&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; gpg2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;filter &lt;span class="s2"&gt;&amp;#34;lfs&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; git-lfs clean -- %f
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;smudge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; git-lfs smudge --skip -- %f
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; git-lfs filter-process --skip
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;pull&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;rebase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;credential&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;helper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; store
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;init&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;defaultBranch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;templateDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; ~/.git-templates
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;diff&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; vscode&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The file being referenced/included here, &lt;code&gt;~/Dropbox/.custom/.gitconfig&lt;/code&gt;, looks like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;user&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; email@example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; Your Name
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;signingkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 798034F11B2ADED2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;commit&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;gpgsign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# The following block could be used to update credentials when committing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# depending on what directory is opened. So, if you work for COMPANY_NAME&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# and the pattern &amp;#39;COMPANY_NAME&amp;#39; appears in the current working directory,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# then Git can be smart and update your configuration by including&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# something like the previous block so that the original email, name,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# signingkey and possibly other config options are overwritten.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;;&lt;/span&gt; when working at COMPANY_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;includeIf &lt;span class="s2"&gt;&amp;#34;gitdir:**/COMPANY_NAME/**/.git&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; ~/Dropbox/.custom/.gitconfig-COMPANY_NAME&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So this section briefly points out how custom tools like &lt;code&gt;diff-so-fancy&lt;/code&gt; can be used, how diff output colors can be customized, how specific code editors like Neovim and VS Code can be opened when committing or dealing with merge conflicts and generally just how the file is meant to be structured.&lt;/p&gt;
&lt;p&gt;A lot more on configuring Git can be found in &lt;a href="https://git-scm.com/docs/git-config"&gt;the official documentation on &lt;code&gt;git config&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Being exhaustive when it comes to using Git is definitely not something this article strived to achieve: Git is such a complex piece of software that has been evolving since 2005, when it became a necessity to deal with incoming patches sent to Linus Torvalds to make Linux the fantastic project it has become! There is much, much more to learn, but hopefully this post gives you a slightly different perspective and points the way to a well-rounded journey with the list of references below. Git good!&lt;/p&gt;
&lt;h2 id="more-resources-and-references"&gt;More resources and references&lt;/h2&gt;
&lt;h3 id="websites"&gt;Websites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.conventionalcommits.org/"&gt;Conventional Commits&lt;/a&gt; - &lt;em&gt;&amp;ldquo;A specification for adding human and machine readable meaning to commit messages.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ndpsoftware.com/git-cheatsheet.html"&gt;Git Cheatsheet&lt;/a&gt; - &lt;em&gt;&amp;ldquo;Interactive Git Cheatsheet, categorizing commands based on what they affect.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gitimmersion.com"&gt;Git Immersion&lt;/a&gt; - &lt;em&gt;&amp;ldquo;A guided tour that walks through the fundamentals of Git, inspired by the premise that to know a thing is to do it.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://githowto.com"&gt;GitHowTo&lt;/a&gt; - &lt;em&gt;&amp;ldquo;Git How To is a guided tour that walks through the fundamentals of Git, inspired by the premise that to know a thing is to do it.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lab.github.com/"&gt;GitHub Learning Lab&lt;/a&gt; - &lt;em&gt;&amp;ldquo;With GitHub Learning Lab, grow your skills by completing fun, realistic projects. Get advice and helpful feedback from our friendly Learning Lab bot.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learngitbranching.js.org"&gt;Learn Git Branching&lt;/a&gt; - &lt;em&gt;&amp;ldquo;An interactive Git visualization tool to educate and challenge!&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/learn/browse/?terms=Github"&gt;Microsoft Learn GitHub modules&lt;/a&gt; - &lt;em&gt;&amp;ldquo;Learn new skills and discover the power of Microsoft products with step-by-step guidance.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2"&gt;Pro Git Book&lt;/a&gt; - &lt;em&gt;&amp;ldquo;The entire Pro Git book, written by Scott Chacon and Ben Straub and published by Apress, is available here. All content is licensed under the Creative Commons Attribution Non Commercial Share Alike 3.0 license. Print versions of the book are available on Amazon.com.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://egghead.io/courses/productive-git-for-developers"&gt;Productive Git for Developers&lt;/a&gt; - &lt;em&gt;&amp;ldquo;You will walk through a series of scenarios which you’ll most commonly encounter in your daily work life as a developer.&amp;rdquo;&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dataschool.io/how-to-contribute-on-github/"&gt;Step-by-step guide to contributing on GitHub&lt;/a&gt; - &lt;em&gt;&amp;ldquo;Have you thought about contributing to an open source project, but you&amp;rsquo;re too confused (or intimidated) by the process to even try? I&amp;rsquo;ve been there too!&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://try.github.io"&gt;Try GitHub&lt;/a&gt; - &lt;em&gt;Resources to learn Git: Handbook, cheat sheets, git commands in the browser, etc.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="youtube"&gt;YouTube&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=eulnSXkhE7I"&gt;CS50 Beyond 2019&lt;/a&gt; - CS50&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=SWYqp7iY_Tc"&gt;Git &amp;amp; GitHub Crash Course For Beginners&lt;/a&gt; - Traversy Media&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=RGOj5yH7evk"&gt;Git and GitHub for Beginners - Crash Course&lt;/a&gt; - freeCodeCamp.org&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=HVsySz-h9r4&amp;amp;list=PL-osiE80TeTuRUfjRe54Eea17-YfnOOAx"&gt;Git Tutorial for Beginners: Command-Line Fundamentals&lt;/a&gt; (playlist) - Corey Schafer&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=x0EYpi38Yp4"&gt;GitHub Basics Tutorial - How to Use GitHub&lt;/a&gt; - freeCodeCamp.org&lt;/li&gt;
&lt;li&gt;&lt;a href="https://missing.csail.mit.edu/2020/version-control"&gt;MIT Missing semester (Version Control) - Git data model&lt;/a&gt; - MIT&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=i76ts_0UryI"&gt;The Ultimate Git &amp;amp; GitHub Crash Course - Learn to Version Control for Beginners&lt;/a&gt; - Laith Harb&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="online-courses"&gt;Online courses&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/learning/git-essential-training"&gt;Git Essential Training&lt;/a&gt; (&lt;em&gt;free with free trial&lt;/em&gt;) - LinkedIn Learning. &lt;em&gt;&amp;ldquo;Using a step-by-step approach, author Kevin Skoglund presents the commands that enable efficient code management and reveals the fundamental concepts behind version control systems and the Git architecture. Discover how to track changes to files in a repository, review previous edits, and compare versions of a file; create branches to test new ideas without altering the main project; and merge those changes into the project if they work out.&lt;/em&gt;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/git-started-with-github/"&gt;Git Started with GitHub&lt;/a&gt; - Udacity. &lt;em&gt;&amp;ldquo;This course is designed to jump right into showing how Git and GitHub work together, focusing on the Git basic workflow. Students can expect to learn the minimum needed to start using Git in about 30 minutes.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eu.udacity.com/course/how-to-use-git-and-github--ud775"&gt;How to Use Git and GitHub&lt;/a&gt; - Udacity. &lt;em&gt;&amp;ldquo;This course, built with input from GitHub, will introduce the basics of using version control by focusing on a particular version control system called Git and a collaboration platform called GitHub.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/short-and-sweet-get-started-with-git-and-github-right-now/"&gt;Short and Sweet: Get Started with Git and GitHub Right Now&lt;/a&gt; - Udemy. &lt;em&gt;&amp;ldquo;In just 30 minutes, this &amp;ldquo;Short and Sweet&amp;rdquo; course covers the essential ideas you need to move forward, without a lot of filler. At the end of the course, you&amp;rsquo;ll be able to set up a GitHub account, install Git, create and configure new Git and GitHub repositories, create a change history for your software projects, and publish your software projects to GitHub.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/the-ultimate-git-5-day-challenge/"&gt;The Ultimate GIT 5-day Challenge&lt;/a&gt; - Udacity. &lt;em&gt;&amp;ldquo;A quick way to determine if working with GIT is something you want to learn more about. This course takes us step-by-step through some basic GIT operations. The course will not dive too deep, and takes small steps on each of five days. As we continue through the course, we learn a basic, single-person workflow that could allow anyone to store files at GitHub or BitBucket.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursera.org/learn/version-control-with-git"&gt;Version Control with Git&lt;/a&gt; - Coursera. &lt;em&gt;&amp;ldquo;In this course, you will not learn everything there is to know about Git, but you will build a strong conceptual understanding of the technology, and afterward will be able to confidently dig deeper on any topic that interests you.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursera.org/learn/introduction-git-github"&gt;Introduction to Git and Github&lt;/a&gt; - Coursera. Offered by Google. &lt;em&gt;&amp;ldquo;In this course, you’ll learn how to keep track of the different versions of your code and configuration files using a popular version control system (VCS) called Git. We&amp;rsquo;ll also go through how to setup an account with a service called GitHub so that you can create your very own remote repositories to store your code and configuration.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="references-for-this-article"&gt;References for this article&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/docs/git-rerere"&gt;&lt;code&gt;git rerere&lt;/code&gt;&lt;/a&gt; - git-scm.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.loginradius.com/blog/engineering/git-commands/"&gt;35+ Git Commands List Every Programmer Should Know&lt;/a&gt; - loginradius.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Binary_search_algorithm"&gt;Binary search algorithm&lt;/a&gt; - Wikipedia.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gitignore.io/install/command-line"&gt;Gitignore&lt;/a&gt; - Toptal.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hackerrank.com/"&gt;HackerRank&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/"&gt;LeetCode&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history"&gt;Rewriting history&lt;/a&gt; - Atlassian.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://about.gitlab.com/blog/2021/03/10/new-git-default-branch-name"&gt;The new Git default branch name&lt;/a&gt; - GitLab.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/a/49501436/8787680"&gt;What is git-rerere and how does it work?&lt;/a&gt; - Stack Overflow.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sun, 03 Apr 2022 11:21:00 -0500</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/git-the-gist-of-it-common-commands-for-a-working-workflow/</guid><category>workflow</category><category>git</category><category>productivity</category><category>terminal</category></item><item><title>Using dmenu to Optimize Common Tasks</title><link>https://www.sglavoie.com/posts/using-dmenu-to-optimize-common-tasks/</link><description>If remembering dozens of keyboard shortcuts isn’t your forte, let dmenu come to the rescue! With this awesome tool, you will be able to create menus from plain text files swiftly and effortlessly (almost).</description><content:encoded>&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://tools.suckless.org/dmenu"&gt;dmenu&lt;/a&gt; is one of those tools that look a little unimpressive at first but can accomplish so much! It&amp;rsquo;s a program that you can use to receive any output redirected from other programs (through pipes in the terminal, the symbol &lt;code&gt;|&lt;/code&gt;) and treat that output so that it can pop up within a simple menu to make it available for execution. If you want to know more about other fantastic tools from &lt;a href="https://suckless.org"&gt;suckless.org&lt;/a&gt;, I &lt;a href="https://www.sglavoie.com/posts/using-dmenu-to-optimize-common-tasks/"&gt;went over some of them before&lt;/a&gt;, such as the &lt;code&gt;st&lt;/code&gt; terminal and &lt;code&gt;slock&lt;/code&gt;, a dead simple screen locker.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="any-simple-example"&gt;Any Simple Example?&lt;/h2&gt;
&lt;p&gt;You bet! Before diving in with how to install it and some more concrete examples, you could give &lt;code&gt;dmenu&lt;/code&gt; a go with a simple command such as the following (assuming the program is installed on your machine).&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls &lt;span class="p"&gt;|&lt;/span&gt; dmenu&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will effectively &amp;ldquo;pipe&amp;rdquo; the output of &lt;code&gt;ls&lt;/code&gt; into &lt;code&gt;dmenu&lt;/code&gt; and a menu like the following would appear (by default, it shows as a thin stripe at the top covering the width of the screen):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_ls_command.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_ls_command.png" alt="dmenu_ls_command" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you start typing, the displayed list will be filtered down like so:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_ls_command_typing.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_ls_command_typing.png" alt="dmenu_ls_command_typing" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can also switch to the next item to be highlighted by typing &lt;code&gt;Ctrl + n&lt;/code&gt;, to the previous item by typing &lt;code&gt;Ctrl + p&lt;/code&gt; and exit by reaching for the &lt;code&gt;Escape&lt;/code&gt; key. For now, if you type &lt;code&gt;Enter&lt;/code&gt; once your desired selection is highlighted, the selection will be outputted to the terminal and that will be the end of it. Let&amp;rsquo;s convert this into a practical thing, then.&lt;/p&gt;
&lt;p&gt;Keeping the same output as before which only contained directories, we could open a file manager (here, I&amp;rsquo;m going with &lt;code&gt;pcmanfm&lt;/code&gt;) and do something like this (bear with me, the explanation follows!):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls &lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs -I &lt;span class="o"&gt;{}&lt;/span&gt; pcmanfm &lt;span class="s2"&gt;&amp;#34;{}&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is now a fully functional example, albeit its practicality is debatable. What will happen, exactly?&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;ls&lt;/code&gt; will output a list of directories in the current working directory. That is, the following would be printed in the terminal without any piping:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Desktop Downloads Learning Pictures Public Templates virtualbox_vms
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Documents Dropbox Music Programming SortOut Videos&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When we &lt;em&gt;pipe&lt;/em&gt; this into &lt;code&gt;dmenu&lt;/code&gt;, we will get a menu with all that output nicely formatted vertically, which is what the &lt;code&gt;-l 5&lt;/code&gt; options does (here, we want only &lt;strong&gt;5&lt;/strong&gt; lines to show). We will see a maximum of &lt;strong&gt;5&lt;/strong&gt; items as this is the value we passed to the &lt;code&gt;-l&lt;/code&gt; option:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_ls_command_vertical_5_items.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_ls_command_vertical_5_items.png" alt="dmenu_ls_command_vertical_5_items" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We can still start typing a word that doesn&amp;rsquo;t show up in this list like &lt;code&gt;Mu&lt;/code&gt; and we will see that this list is filtered to only include the matching directory &lt;code&gt;Music&lt;/code&gt; even though we couldn&amp;rsquo;t see it before since we limited our results to &lt;strong&gt;5&lt;/strong&gt; items. We could also use the same technique with &lt;code&gt;Ctrl + n&lt;/code&gt; and &lt;code&gt;Ctrl + p&lt;/code&gt; to cycle between the elements.&lt;/p&gt;
&lt;p&gt;Up to this point, we are getting our selection outputted to the terminal. Next, we pipe it into &lt;code&gt;xargs&lt;/code&gt;, which will allow us to specify a command to which we will pass our result (what is printed to the terminal) as an argument (we could make use of more arguments depending on the output we get, but let&amp;rsquo;s start simple). The &lt;code&gt;-I {}&lt;/code&gt; option will make it possible to &amp;ldquo;quote&amp;rdquo; our result so it is read as a single argument and properly &lt;em&gt;escaped&lt;/em&gt;. This means that without this option, if we have spaces or other special characters in the argument (such as a folder called &lt;code&gt;My Music&lt;/code&gt;), it would try to pass each word as a new argument to &lt;code&gt;pcmanfm&lt;/code&gt;, trying to open both &lt;code&gt;My&lt;/code&gt; and &lt;code&gt;Music&lt;/code&gt; directories at once.&lt;/p&gt;
&lt;p&gt;We are representing our output as &lt;code&gt;{}&lt;/code&gt; and when we quote it with &lt;code&gt;pcmanfm &amp;quot;{}&amp;quot;&lt;/code&gt;, spaces are interpreted without any trouble. If we wanted to use various arguments instead, we could try something like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;file1.txt file2.txt\nfile3.txt file4.txt&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs cat&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The part before the first pipe character will print to the terminal those two lines:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;file1.txt file2.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;file3.txt file4.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When we pipe this into &lt;code&gt;dmenu -l 2&lt;/code&gt;, we will get this menu:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_echo_command_filenames.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_echo_command_filenames.png" alt="dmenu_echo_command_filenames" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Typing &lt;code&gt;Enter&lt;/code&gt; on one of the highlighted items would then trigger &lt;code&gt;xargs&lt;/code&gt; to pass the content literally to &lt;code&gt;cat&lt;/code&gt; as arguments, which would then print to the terminal the content of both &lt;code&gt;file1.txt&lt;/code&gt; and &lt;code&gt;file2.txt&lt;/code&gt; (the first line containing two arguments for &lt;code&gt;cat&lt;/code&gt;) or the content of both &lt;code&gt;file3.txt&lt;/code&gt; and &lt;code&gt;file4.txt&lt;/code&gt; (the second line also containing two arguments for &lt;code&gt;cat&lt;/code&gt;) in succession.&lt;/p&gt;
&lt;p&gt;Now that we got our feet wet with what &lt;code&gt;dmenu&lt;/code&gt; does (&lt;em&gt;displays a menu&lt;/em&gt;), we might want to install it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="how-do-you-install-it"&gt;How do You Install It?&lt;/h2&gt;
&lt;p&gt;In Manjaro Linux, it comes with &lt;code&gt;i3&lt;/code&gt; if you use that flavor of the distribution and can be opened by pressing the modifier key (either &lt;code&gt;Super/Windows&lt;/code&gt; key or &lt;code&gt;Alt&lt;/code&gt; key) along with the letter &lt;code&gt;d&lt;/code&gt;, as in the shortcut &lt;code&gt;mod + d&lt;/code&gt;, or by typing &lt;code&gt;dmenu_run&lt;/code&gt; in a terminal, which will present a list of installed applications to launch. Otherwise:&lt;/p&gt;
&lt;h2 id="debian-based-such-as-ubuntu"&gt;Debian-based (such as Ubuntu)&lt;/h2&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install dmenu&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="arch-based-such-as-manjaro"&gt;Arch-based (such as Manjaro)&lt;/h2&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -Syu dmenu&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can also install it from your distribution&amp;rsquo;s package manager if available or &lt;a href="https://tools.suckless.org/dmenu"&gt;from source&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="useful-real-world-examples"&gt;Useful Real-World Examples&lt;/h2&gt;
&lt;p&gt;Here are a couple of ways I like to use &lt;code&gt;dmenu&lt;/code&gt; to open a menu with a list of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cheat sheets;&lt;/li&gt;
&lt;li&gt;filesystem paths;&lt;/li&gt;
&lt;li&gt;most used documents;&lt;/li&gt;
&lt;li&gt;documents &amp;amp; books I read at the university;&lt;/li&gt;
&lt;li&gt;custom scripts I want to run in the background.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are a few screenshots of how it currently looks like in my daily usage so you get a better idea.&lt;/p&gt;
&lt;h2 id="cheat-sheets"&gt;Cheat sheets&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_cheat_sheets.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_cheat_sheets.png" alt="dmenu_cheat_sheets" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="university-shortcuts"&gt;University shortcuts&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_university_shortcuts.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_university_shortcuts.png" alt="dmenu_university_shortcuts" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="file-manager-shortcuts"&gt;File manager shortcuts&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_file_manager_shortcuts.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0018_using-dmenu-to-optimize-common-tasks/dmenu_file_manager_shortcuts.png" alt="dmenu_file_manager_shortcuts" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So, how does that all work? As a starting point, all of those menus are launched through a specific keyboard shortcut that uses a mnemonic for each one (&lt;code&gt;mod&lt;/code&gt; being the &amp;ldquo;modifier&amp;rdquo; key on &lt;strong&gt;i3&lt;/strong&gt;, which is set to &lt;code&gt;Super/Windows&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mod + Alt + c&lt;/code&gt;: &lt;strong&gt;c&lt;/strong&gt;heat sheets;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mod + Alt + d&lt;/code&gt;: &lt;strong&gt;d&lt;/strong&gt;ocuments;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mod + Alt + f&lt;/code&gt;: &lt;strong&gt;f&lt;/strong&gt;ile manager;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mod + Alt + s&lt;/code&gt;: &lt;strong&gt;s&lt;/strong&gt;cripts;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mod + Alt + u&lt;/code&gt;: &lt;strong&gt;u&lt;/strong&gt;niversity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;rsquo;s take the cheat sheets example, which is a bit more interesting since it launches different applications.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="setting-up-a-custom-command"&gt;Setting Up a Custom Command&lt;/h2&gt;
&lt;h3 id="configuration-for-i3-bind-a-keyboard-shortcut"&gt;Configuration for i3 (bind a keyboard shortcut)&lt;/h3&gt;
&lt;p&gt;Here, I&amp;rsquo;m using &lt;a href="https://i3wm.org"&gt;i3&lt;/a&gt; to set a keyboard shortcut to run a specific command, but this will be a similar experience on other window managers and desktop environments.&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# i3config file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# The backslash at the end of the line allows us&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# to split the line to increase readability&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;## Cheatsheets&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bindsym &lt;span class="nv"&gt;$mod&lt;/span&gt;+Mod1+c &lt;span class="nb"&gt;exec&lt;/span&gt; --no-startup-id &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat path/to/cheatsheets.conf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/.* \+//&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You would usually be able to launch a custom command from your environment through a keyboard shortcut. If passing a direct command such as the above one isn&amp;rsquo;t an option, you can always store it in a Bash script and run that Bash script instead as the designated custom command. The script would then contain the following:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;## Cheatsheets&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat path/to/cheatsheets.conf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/.* \+//&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As far as &lt;strong&gt;i3&lt;/strong&gt; is concerned, that&amp;rsquo;s all you need to do. You would need to reload the configuration file (by default: &lt;em&gt;i3config&lt;/em&gt;) where the previous &lt;code&gt;bindsym&lt;/code&gt; command has been set up to apply the changes (default shortcut to reload: &lt;code&gt;mod + Shift + c&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id="configuration-for-cheatsheetsconf"&gt;Configuration for cheatsheets.conf&lt;/h3&gt;
&lt;p&gt;The content of this file is literally what will be shown when &lt;strong&gt;dmenu&lt;/strong&gt; opens it. An excerpt:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#---------- Cheat Sheets -------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash st -e nvim path/to/bash.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git zathura path/to/github.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vimwiki firefox path/to/vimwiki.html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here, we have set a maximum of &lt;strong&gt;30&lt;/strong&gt; lines to be displayed (&lt;code&gt;-l 30&lt;/code&gt;). What follows after an element has been selected with &lt;strong&gt;dmenu&lt;/strong&gt; allows us to parse the content of the line and retrieve only the command we are interested in with &lt;code&gt;sed&lt;/code&gt; before passing that filtered content around to &lt;code&gt;sh&lt;/code&gt; to execute it as a shell command. With more complex commands requiring multiples arguments to be received, we could add one more pipe between &lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;sh&lt;/code&gt; like this (or with &lt;code&gt;xargs -I {}&lt;/code&gt; to avoid problems with spaces):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat path/to/cheatsheets.conf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/.* \+//&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs -r &lt;span class="p"&gt;|&lt;/span&gt; sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If the line we want to run only includes a path to a file as in:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;myshortcut path/to/file.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We could instead pipe it into an external command of choice if the same program applies to all items presented in the menu, say Firefox:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat path/to/file.conf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/.* \+//&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs -I &lt;span class="o"&gt;{}&lt;/span&gt; firefox &lt;span class="s2"&gt;&amp;#34;{}&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What&amp;rsquo;s nice with the way pipes work in a Unix-like system is that we can chain harmless commands until the very end so they will simply be printed to the terminal. In this example, if we want to see how to filter our lines before running a command, we can do so as follow.&lt;/p&gt;
&lt;h4 id="pipe-1"&gt;Pipe 1&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat path/to/cheatsheets.conf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you remember from the menu we saw earlier, there&amp;rsquo;s a shortcut to open a cheat sheet for Git. Let&amp;rsquo;s say we selected that one with &lt;strong&gt;dmenu&lt;/strong&gt;. Because our command isn&amp;rsquo;t doing anything with the result, it will be outputted to the terminal like so (just like in the excerpt of &lt;code&gt;cheatsheets.conf&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git zathura path/to/github.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What &lt;code&gt;sed&lt;/code&gt; does here is to cut everything from the beginning of the line up to where the command starts (that&amp;rsquo;s where we find &lt;a href="https://pwmt.org/projects/zathura/"&gt;zathura&lt;/a&gt;, which is a powerful document viewer), because we need to isolate that part of the line so it looks like a shell command we could run on its own. Let&amp;rsquo;s add a new pipe to our command and see what &lt;code&gt;sed&lt;/code&gt; does with it*.&lt;/p&gt;
&lt;p&gt;* &lt;sub&gt;We could have used other tools to parse the string like &lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;cut&lt;/code&gt;, etc.&lt;/sub&gt;&lt;/p&gt;
&lt;h4 id="pipe-2"&gt;Pipe 2&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat path/to/cheatsheets.conf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/.* \+//&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If we select the same item as before with &lt;strong&gt;dmenu&lt;/strong&gt; to illustrate more clearly what this new addition does, we will get this output:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zathura path/to/github.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If we were to type this in the terminal (assuming the file exists and &lt;strong&gt;zathura&lt;/strong&gt; is installed!), that would do the trick and it would open with the specified document viewer. &lt;strong&gt;Pipe 2&lt;/strong&gt; and subsequent pipes before we execute something is where the filtering magic happen. In short:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Everything &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;| dmenu&lt;/code&gt; is how our input will look like when we run &lt;code&gt;dmenu&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Everything &lt;strong&gt;after&lt;/strong&gt; &lt;code&gt;| dmenu [options here] |&lt;/code&gt; is what we need to do to our input so that it is converted into a working shell command;&lt;/li&gt;
&lt;li&gt;Finally, what comes &lt;strong&gt;after the last pipe&lt;/strong&gt; (either &lt;code&gt;xargs&lt;/code&gt;, &lt;code&gt;sh&lt;/code&gt; or a combination of both) is our way to redirect our string to the shell so it can be executed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once we are visually satisfied with how our command is supposed to look like (it has to be something that works when typed directly in the terminal), the next step is to pipe it again so it can be executed.&lt;/p&gt;
&lt;h4 id="pipe-3"&gt;Pipe 3&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat path/to/cheatsheets.conf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;|&lt;/span&gt; dmenu -l &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/.* \+//&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There we go, the command is launched. If we keep the same simple syntax in all of our &lt;code&gt;.conf&lt;/code&gt; files —or whatever extension we choose— where the content of our menus is stored in plain text, we can quickly and painlessly create keyboard shortcuts to run custom lists of commands that can be edited on the fly. Once our shortcuts are active, it&amp;rsquo;s only a matter of editing one of those &lt;code&gt;.conf&lt;/code&gt; files and automatically our lists will be up-to-date when we trigger the shortcut again.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="running-a-custom-script"&gt;Running a Custom Script&lt;/h2&gt;
&lt;p&gt;If we want to run custom scripts, we need to indicate a command that would work in the terminal, such as &lt;code&gt;python myscrypt.py&lt;/code&gt; or &lt;code&gt;./myscript.sh&lt;/code&gt;. When it comes to shell scripts, we have to make sure they are executable. We can do so through a file manager or within the terminal like this:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x path/to/script.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will add the necessary permissions for the user to execute the script. As we already know, we would then need to add a keyboard shortcut to launch our custom menu and store our command in a file like &lt;code&gt;scripts.conf&lt;/code&gt; that would contain the following:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#---------- scripts.conf -------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;myscript script.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And that&amp;rsquo;s all there is to know to get piping with &lt;code&gt;dmenu&lt;/code&gt;! You may also find &lt;a href="https://www.youtube.com/watch?v=8E8sUNHdzG8"&gt;this video from Luke Smith&lt;/a&gt; on YouTube to be quite helpful as well, which is where the inspiration for this post came from. He also &lt;a href="https://www.youtube.com/watch?v=R9m723tAurA"&gt;posted a complementary video&lt;/a&gt; about adding prompts to your commands which is a nice way to add interactivity to your scripts!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="chaining-dmenu-prompts"&gt;Chaining dmenu prompts&lt;/h2&gt;
&lt;p&gt;Another useful scenario is when you want to take a specific action based on the output of a previous command. For instance, let&amp;rsquo;s say you want to read a book but when you choose a &lt;code&gt;pdf&lt;/code&gt; with &lt;code&gt;dmenu&lt;/code&gt;, you want to be prompted for which reader to use while you want to let the system choose the default application for other types of files (e.g. &lt;code&gt;epub&lt;/code&gt; or &lt;code&gt;mobi&lt;/code&gt;). This could be achieved with a script similar to the following one:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;find ~/Documents/calibre_library -type f -iname &lt;span class="s2"&gt;&amp;#34;*.pdf&amp;#34;&lt;/span&gt; -o &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -iname &lt;span class="s2"&gt;&amp;#34;*.epub&amp;#34;&lt;/span&gt; -o -iname &lt;span class="s2"&gt;&amp;#34;*.mobi&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; dmenu -l 30&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; *.pdf &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;READER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;#34;zathura\natril&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; dmenu -i -p &lt;span class="s2"&gt;&amp;#34;Which reader?&amp;#34;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$READER&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; xdg-open &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;rsquo;s what&amp;rsquo;s happening:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We &lt;code&gt;find&lt;/code&gt; all the files (&lt;code&gt;-type f&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;in the directory &lt;code&gt;~/Documents/calibre_library&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;that match a pattern that&amp;rsquo;s case-insensitive with &lt;code&gt;-iname&lt;/code&gt; (here, ending in either &lt;code&gt;pdf&lt;/code&gt;, &lt;code&gt;mobi&lt;/code&gt; or &lt;code&gt;epub&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;matching one file at a time (&lt;code&gt;-o&lt;/code&gt; can be interpreted to mean &amp;ldquo;only&amp;rdquo; and will keep searching if the previous file extension was not matched)&lt;/li&gt;
&lt;li&gt;then presenting 30 lines (&lt;code&gt;-l 30&lt;/code&gt;) of results at a time with &lt;code&gt;dmenu&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;then, if the file is a PDF, prompts whether to use &lt;code&gt;atril&lt;/code&gt; or &lt;code&gt;zathura&lt;/code&gt; as the file reader and open with the chosen program&lt;/li&gt;
&lt;li&gt;otherwise, open the file with the default application.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="customize-the-look-of-dmenu"&gt;Customize the Look of dmenu&lt;/h2&gt;
&lt;p&gt;As they say, &lt;em&gt;&amp;ldquo;beauty is in the eye of the beholder&amp;rdquo;&lt;/em&gt;. If you would rather make some changes to how dmenu look, you can. &lt;strong&gt;dmenu&lt;/strong&gt; will be searching for the configuration file located at &lt;code&gt;~/.dmenurc&lt;/code&gt;, which could contain something as put below (with this configuration, it will look like the screenshots shown previously):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ~/.dmenurc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# define the font for dmenu to be used&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DMENU_FN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;NotoSans-10.5&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# background colour for unselected menu-items&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DMENU_NB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;#161925&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# textcolour for unselected menu-items&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DMENU_NF&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;#fdfffc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# background colour for selected menu-items&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DMENU_SB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;#235789&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# textcolour for selected menu-items&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DMENU_SF&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;#fdfffc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# command for the terminal application to be used:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TERMINAL_CMD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;st -e&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# export our variables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DMENU_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-fn &lt;/span&gt;&lt;span class="nv"&gt;$DMENU_FN&lt;/span&gt;&lt;span class="s2"&gt; -nb &lt;/span&gt;&lt;span class="nv"&gt;$DMENU_NB&lt;/span&gt;&lt;span class="s2"&gt; -nf &lt;/span&gt;&lt;span class="nv"&gt;$DMENU_NF&lt;/span&gt;&lt;span class="s2"&gt; -sf &lt;/span&gt;&lt;span class="nv"&gt;$DMENU_SF&lt;/span&gt;&lt;span class="s2"&gt; -sb &lt;/span&gt;&lt;span class="nv"&gt;$DMENU_SB&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Hopefully this introduction to what &lt;strong&gt;dmenu&lt;/strong&gt; has to offer gave you some ideas. I hope you&amp;rsquo;ll find many ways to adapt the examples so you can benefit from this amazing tool. You can find more configuration details in my &lt;a href="https://github.com/sglavoie/dotfiles/"&gt;dotfiles on GitHub&lt;/a&gt; for anything related to &lt;strong&gt;i3&lt;/strong&gt;, &lt;strong&gt;dmenu&lt;/strong&gt;, &lt;strong&gt;zathura&lt;/strong&gt;, &lt;strong&gt;st&lt;/strong&gt;, &lt;strong&gt;slock&lt;/strong&gt; and many more useful programs.&lt;/p&gt;
&lt;p&gt;Have a good time automating your digital life!&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sun, 10 Nov 2019 09:02:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/using-dmenu-to-optimize-common-tasks/</guid><category>tips-and-tricks</category><category>bash</category><category>dmenu</category><category>i3</category><category>linux</category><category>productivity</category><category>script</category></item><item><title>Black: A Python Formatter to Brighten Your Workflow</title><link>https://www.sglavoie.com/posts/black-a-python-formatter-to-brighten-your-workflow/</link><description>Meet Black, a superb Python code formatter that will automatically reformat your code in accordance to PEP-8 standards.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="what-is-black"&gt;What is Black?&lt;/h2&gt;
&lt;p&gt;From its &lt;a href="https://github.com/python/black"&gt;GitHub repository&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
 &lt;p&gt;Black is the uncompromising Python code formatter. By using it, you agree to cede control over minutiae of hand-formatting. In return, Black gives you speed, determinism, and freedom from pycodestyle nagging about formatting. You will save time and mental energy for more important matters.&lt;/p&gt;

&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;Black&lt;/strong&gt; will take less than ideal code and will automatically reformat it according to the &lt;a href="https://www.python.org/dev/peps/pep-0008/"&gt;PEP-8 style guide&lt;/a&gt;. It will take care of many things, including the following (taken in that order from &lt;code&gt;README.md&lt;/code&gt; in &lt;strong&gt;Black&lt;/strong&gt;&amp;rsquo;s repo):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wrapping lines properly by shortening as much as possible single statements;&lt;/li&gt;
&lt;li&gt;Break long lines;&lt;/li&gt;
&lt;li&gt;Remove superfluous empty lines;&lt;/li&gt;
&lt;li&gt;Take care of adding trailing commas where necessary;&lt;/li&gt;
&lt;li&gt;Convert single quotes (&lt;code&gt;'&lt;/code&gt;) to double quotes (&lt;code&gt;&amp;quot;&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;Convert numeric literals to lowercase (&lt;code&gt;0XAB&lt;/code&gt; to &lt;code&gt;0xAB&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;Superfluous parentheses are removed;&lt;/li&gt;
&lt;li&gt;Split call chains on different lines;&lt;/li&gt;
&lt;li&gt;Works from the terminal and support many code editor integrations (Emacs, Vim, VS Code, Sublime, etc.).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that it&amp;rsquo;s clear &lt;em&gt;why&lt;/em&gt; it can be a good idea to use it, let&amp;rsquo;s see how it works with Vim and the terminal.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="how-to-use-it"&gt;How to use it?&lt;/h2&gt;
&lt;p&gt;First, we need to install it using Python 3.6.0+:&lt;/p&gt;
&lt;div class="code-block" data-prompted&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;pip install black&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;h3 id="use-it-from-the-terminal"&gt;Use it from the terminal&lt;/h3&gt;
&lt;p&gt;In its simplest invocation, we can use &lt;strong&gt;Black&lt;/strong&gt; by specifying a file or a directory by typing:&lt;/p&gt;
&lt;div class="code-block" data-prompted&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;black path_to_file_or_directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It doesn&amp;rsquo;t come with many options as its goal is to automatically format code consistently, but you can find out more about this tool in the following way:&lt;/p&gt;
&lt;div class="code-block" data-prompted&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;black --help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="use-it-with-vim"&gt;Use it with Vim&lt;/h3&gt;
&lt;p&gt;Using &lt;strong&gt;Black&lt;/strong&gt; as part of your workflow in a code editor is where I believe it really shines, because you can see almost in real-time when you make a formatting mistake, which will help down the road in committing less sins.&lt;/p&gt;
&lt;p&gt;Integrating &lt;strong&gt;Black&lt;/strong&gt; with Vim or Neovim is quick and painless, adding a simple line in your &lt;code&gt;.vimrc&lt;/code&gt; or &lt;code&gt;init.vim&lt;/code&gt; file. You can also proceed to do a manual installation without a plugin manager as explained in the GitHub repository.&lt;/p&gt;
&lt;p&gt;With &lt;a href="https://github.com/junegunn/vim-plug"&gt;vim-plug&lt;/a&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Plug&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;python/black&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With &lt;a href="https://github.com/VundleVim/Vundle.vim"&gt;Vundle&lt;/a&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Plugin&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;python/black&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once the plugin is installed, it may well be convenient to automatically format Python files when saving the buffer, which can be accomplished by adding the following line to the configuration file:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;autocmd&lt;/span&gt; &lt;span class="nx"&gt;BufWritePre&lt;/span&gt; *.&lt;span class="nx"&gt;py&lt;/span&gt; &lt;span class="k"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;:Black&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;By default, &lt;strong&gt;Black&lt;/strong&gt; works surprisingly well on its own. I only went ahead and changed the default line length from 88 to 79 characters by also adding this line:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;black_linelength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;79&lt;/span&gt; &lt;span class="c"&gt;&amp;#34; default is 88&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally, it&amp;rsquo;s worth noting you can update &lt;strong&gt;Black&lt;/strong&gt; at any point from the terminal with &lt;code&gt;pip&lt;/code&gt; and you can also do it directly from within Vim/Neovim with this command:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;BlackUpgrade&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Vim will then output something along those lines:&lt;/p&gt;
&lt;blockquote&gt;
 &lt;p&gt;Upgrading Black with pip&amp;hellip;&lt;/p&gt;

&lt;/blockquote&gt;&lt;blockquote&gt;
 &lt;p&gt;DONE! You are all set, thanks for waiting&lt;/p&gt;

&lt;/blockquote&gt;&lt;h2 id="any-example"&gt;Any example?&lt;/h2&gt;
&lt;p&gt;Taking a random Python 3.6+ code sample, we could originally have something like this (hopefully not):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;python&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data_sources&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Retrieve a list of all matching log files in `source`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;log_files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;LOG_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;*&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;log_files&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;There is no log file to delete in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Log files in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;log_file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log_files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ARGUMENTS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remind&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;REMINDER_IS_SET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;log_file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;Do you want to delete log files &amp;#39;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;for this source? (y/n) &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_says_yes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;log_file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log_files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;Log files deleted.&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Exiting script...&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Running &lt;strong&gt;Black&lt;/strong&gt;, we will get something that&amp;rsquo;s quite a bit more palatable:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;python&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data_sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Retrieve a list of all matching log files in `source`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;log_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;LOG_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;*&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;log_files&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;There is no log file to delete in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Log files in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;log_file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log_files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ARGUMENTS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;REMINDER_IS_SET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Do you want to delete log files &amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;for this source? (y/n) &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_says_yes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;log_file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log_files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Log files deleted.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Exiting script...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I think the results speak for themselves: enforcing a style with a tool like &lt;strong&gt;Black&lt;/strong&gt; is definitely useful to avoid arguments about conflicting coding styles. It lets you focus on what matters instead: being productive while providing value to the world.&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sat, 13 Jul 2019 13:10:00 -0500</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/black-a-python-formatter-to-brighten-your-workflow/</guid><category>workflow</category><category>neovim</category><category>plugin</category><category>productivity</category><category>python</category><category>terminal</category><category>vim</category></item><item><title>fzf - A Fuzzy Finder to Accomplish Anything</title><link>https://www.sglavoie.com/posts/fzf-a-fuzzy-finder-to-accomplish-anything/</link><description>Search and, most importantly, finally find what you are looking for on your machine. If you rely on the terminal a lot, fzf may well be capable of speeding up your productivity!</description><content:encoded>&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I know people who make such a mess when &lt;em&gt;not&lt;/em&gt; organizing their files and
directories appropriately on their system, they would benefit greatly
from &lt;code&gt;fzf&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="what-is-fzf"&gt;What is fzf?&lt;/h2&gt;
&lt;p&gt;From the &lt;a href="https://github.com/junegunn/fzf"&gt;official GitHub page&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
 &lt;p&gt;fzf is a general-purpose command-line fuzzy finder. It&amp;rsquo;s an
interactive Unix filter for command-line that can be used with any list;
files, command history, processes, hostnames, bookmarks, git commits,
etc.&lt;/p&gt;

&lt;/blockquote&gt;&lt;hr&gt;
&lt;h2 id="terminal-aliases"&gt;Terminal aliases&lt;/h2&gt;
&lt;p&gt;One of the main uses of &lt;code&gt;fzf&lt;/code&gt; is from the terminal. Being so flexible
to use, it can be combined with all kinds of commands with the help
of pipes (&lt;code&gt;|&lt;/code&gt;) to bend it to your desires. Here are some aliases I am
currently using that undoubtedly improve my terminal workflow.&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;##### Functions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Select a configuration file with fzf and open it with Neovim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;conf&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; du -a ~/.dotfiles/* ~/.config/* &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; fzf &lt;span class="p"&gt;|&lt;/span&gt; xargs -r nvim &lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Select a file from current folder and recursively with fzf and open it with Neovim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;se&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; du -a ./* &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; fzf &lt;span class="p"&gt;|&lt;/span&gt; xargs -r nvim &lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Select a file recursively from university folder with fzf and open it with default app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sc&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; du -a ~/Dropbox/university/* &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; fzf &lt;span class="p"&gt;|&lt;/span&gt; xargs -r xdg-open &lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The first alias, &lt;code&gt;conf&lt;/code&gt; (short for &lt;em&gt;configuration&lt;/em&gt;), allows to search
only within the two folders specified for configuration files, which
makes it pop almost instantaneously since it doesn&amp;rsquo;t have to scan files
scattered anywhere else. You can then type anything that partially
matches a file path and even include slashes (&lt;code&gt;/&lt;/code&gt;) in your match if you
know in which directories to look. You can then type &lt;code&gt;Enter&lt;/code&gt; to open the
file with your favorite text editor (here set to &lt;code&gt;nvim&lt;/code&gt;) or type &lt;code&gt;CTRL + c&lt;/code&gt; to abort the command.&lt;/p&gt;
&lt;p&gt;The other aliases work in a similar fashion. &lt;code&gt;se&lt;/code&gt; (short for &lt;em&gt;search&lt;/em&gt;)
will simply search recursively for any kind of files in the current
directory and open the selected file in a text editor. Of course,
certain file types can be excluded and everything else can be tweaked
with more piping power. In the case of the third alias, &lt;code&gt;sc&lt;/code&gt; (short for
&lt;em&gt;school&lt;/em&gt;), it will also search recursively for any kind of file in the
&lt;code&gt;university&lt;/code&gt; folder and will open it with the default application set to
open that kind of file (video, image, text, PDF, etc.).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="vimneovim-integration"&gt;Vim/Neovim integration&lt;/h2&gt;
&lt;p&gt;Using &lt;a href="https://github.com/junegunn/vim-plug"&gt;Vim-Plug&lt;/a&gt; from the same
author as &lt;code&gt;fzf&lt;/code&gt; is as easy as adding the following to Vim/Neovim&amp;rsquo;s
configuration file. First, we make sure that &lt;code&gt;fzf&lt;/code&gt; is available on the
system and install it if it&amp;rsquo;s not. Then, we install the &lt;code&gt;fzf.vim&lt;/code&gt; plugin
to integrate fzf in Vim and optionally, we may configure more options so
that &lt;code&gt;fzf&lt;/code&gt; can be used more optimally, which can be found on the &lt;a href="https://github.com/junegunn/fzf.vim"&gt;GitHub
plugin page&lt;/a&gt;.&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Plug&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;junegunn/fzf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; { &lt;span class="s1"&gt;&amp;#39;dir&amp;#39;&lt;/span&gt;: $&lt;span class="nx"&gt;HOME&lt;/span&gt; . &lt;span class="s1"&gt;&amp;#39;/.fzf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;do&amp;#39;&lt;/span&gt;: &lt;span class="s1"&gt;&amp;#39;./install --all&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Plug&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;junegunn/fzf.vim&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34; [ FZF ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Allows fzf to ignore patterns in .gitignore&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; $&lt;span class="nx"&gt;FZF_DEFAULT_COMMAND&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ag -g &amp;#34;&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Mapping selecting mappings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;xmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;omap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Insert mode completion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;imap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;imap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;imap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;imap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Advanced customization using autoload functions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; (expand word completing window)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;inoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fzf&lt;/span&gt;#&lt;span class="nx"&gt;vim&lt;/span&gt;#&lt;span class="nx"&gt;complete&lt;/span&gt;#&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;{&lt;span class="s1"&gt;&amp;#39;left&amp;#39;&lt;/span&gt;: &lt;span class="s1"&gt;&amp;#39;20%&amp;#39;&lt;/span&gt;}&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Make use of fzf command instead of CtrlP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;map&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :&lt;span class="nx"&gt;FZF&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34;&amp;#34;&amp;#34; [ / FZF ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="working-with-neovim"&gt;Working with Neovim&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fzf&lt;/code&gt; really shines when used with Neovim as it is extremely fast,
especially when configured with
&lt;a href="https://github.com/ggreer/the_silver_searcher"&gt;The Silver Searcher&lt;/a&gt;
which deserves its own article. It
integrates with core functionality of Vim and makes it easy to find what
you are looking for.&lt;/p&gt;
&lt;p&gt;From the above configuration, for instance:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This allows to search for existing mappings and commands, which can be
faster than diving in the help pages when looking for a quick reference.&lt;/p&gt;
&lt;p&gt;This one in insert mode is very handy:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;imap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nx"&gt;fzf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Without affecting keyword completion with &lt;code&gt;CTRL + n&lt;/code&gt; and &lt;code&gt;CTRL + p&lt;/code&gt;
(unless you have &lt;code&gt;set complete+=k&lt;/code&gt; in your configuration file), you can
complete words from a custom dictionary of your choice with &lt;code&gt;CTRL + x CTRL + k&lt;/code&gt;. The window that appears can be moved and resized, which is
what is happening here:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;inoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fzf&lt;/span&gt;#&lt;span class="nx"&gt;vim&lt;/span&gt;#&lt;span class="nx"&gt;complete&lt;/span&gt;#&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;{&lt;span class="s1"&gt;&amp;#39;left&amp;#39;&lt;/span&gt;: &lt;span class="s1"&gt;&amp;#39;20%&amp;#39;&lt;/span&gt;}&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In the same way, file paths can be completed from the current working
directory &lt;code&gt;CTRL + x CTRL + f&lt;/code&gt; and existing lines can be quickly inserted
with &lt;code&gt;CTRL + x CTRL + l&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0016_a_fuzzy_file_finder_to_accomplish_anything/fzf_autocompletion.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0016_a_fuzzy_file_finder_to_accomplish_anything/fzf_autocompletion.png" alt="fzf_line_autocompletion" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally, I use &lt;code&gt;fzf&lt;/code&gt; to open any file quickly from the working directory
inside Neovim with the mapping &lt;code&gt;CTRL + p&lt;/code&gt;, which replaces the CtrlP
plugin and can work much faster on larger codebases.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There is much more that can be done with it and I am barely scratching
the surface here. Luke Smith shared
&lt;a href="https://www.youtube.com/watch?v=vt33Hp-4RXg"&gt;a great video&lt;/a&gt; that will
complement the information from this post nicely with a more technical
approach. Highly recommended to see more practical ways to use this
superb piece of software!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lukesmith.xyz/"&gt;Luke Smith&lt;/a&gt; also makes a strong point of
combining &lt;code&gt;fzf&lt;/code&gt; with &lt;a href="https://tools.suckless.org/dmenu/"&gt;dmenu&lt;/a&gt;, a tool
that I described succinctly in
&lt;a href="https://www.sglavoie.com/posts/suckless-minimalist-tools-that-work-great/"&gt;a previous article&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Fri, 24 May 2019 10:56:00 -0500</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/fzf-a-fuzzy-finder-to-accomplish-anything/</guid><category>workflow</category><category>plugin</category><category>productivity</category><category>shell</category><category>terminal</category></item><item><title>Suckless: Minimalist Tools That Work Great</title><link>https://www.sglavoie.com/posts/suckless-minimalist-tools-that-work-great/</link><description>I have been using a few different tools from suckless.org for a while and I must say that once everything is configured properly, they are a joy to use. Some tools, like dmenu and slock, seem simple on the surface, but they allow to simplify your workflow by quite a bit. Another one, st, is a truly fantastic and lightweight terminal!</description><content:encoded>&lt;hr&gt;
&lt;h2 id="what-are-suckless-tools"&gt;What are Suckless tools?&lt;/h2&gt;
&lt;p&gt;From the &lt;a href="https://suckless.org/"&gt;official website&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
 &lt;p&gt;Home of &lt;a href="https://dwm.suckless.org/"&gt;dwm&lt;/a&gt;,
&lt;a href="https://tools.suckless.org/dmenu"&gt;dmenu&lt;/a&gt; and other quality software
with a focus on simplicity, clarity, and frugality.&lt;/p&gt;

&lt;/blockquote&gt;&lt;p&gt;There are also other incredible pieces of software that are worth
mentioning, including &lt;a href="https://st.suckless.org/"&gt;st&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here, I will only go over the tools I use frequently, but keep in mind
that everything from Suckless&amp;hellip; Sucks less.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="st--simple-terminal"&gt;st — Simple Terminal&lt;/h2&gt;
&lt;p&gt;I did not know what to expect from this terminal and I found it delivers what I need! Configuring it is quite different than other terminals like &lt;a href="https://konsole.kde.org/"&gt;Konsole&lt;/a&gt; or &lt;a href="https://help.gnome.org/users/gnome-terminal/stable/"&gt;GNOME Terminal&lt;/a&gt;: you just edit a text file and compile the software before you can even use it. It may seem tedious at first, but compiling such a small piece of software is very fast and it needs to be done on seldom occasions when you may want to adjust a setting.&lt;/p&gt;
&lt;p&gt;I have experienced rendering issues when scaling the text with other terminals (including Konsole), where some weird flickering would happen at certain font sizes. &lt;a href="https://st.suckless.org/"&gt;Simple Terminal&lt;/a&gt; just works without hassle. It doesn&amp;rsquo;t have much bells and whistles out of the box, but it can be &lt;em&gt;patched&lt;/em&gt; to extend its functionality if you know what you are doing. I don&amp;rsquo;t, so my compiled version remains pretty basic although I must say I like the simplicity of it very much.&lt;/p&gt;
&lt;h3 id="configuration"&gt;Configuration&lt;/h3&gt;
&lt;p&gt;I didn&amp;rsquo;t have to adapt the configuration file very much. I ended up changing mainly the following lines:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Consolas:pixelsize=18:antialias=true:autohint=true&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;/bin/zsh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Terminal colors (16 first used in escape sequence) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;colorname&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* 8 normal colors */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#1c1c1c&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* black */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#ff005b&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* red */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#70e502&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* green */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#fcdd11&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* yellow */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#00a0ea&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* blue */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#bd1efc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* magenta */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#14ecfc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* cyan */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#ededed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* white */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* 8 bright colors */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#666666&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* black */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#ff00a0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* red */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#5dff00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* green */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#ff9f00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* yellow */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#71a9fc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* blue */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#d571fc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* magenta */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#6cf2fc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* cyan */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#fcfcfc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* white */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* special colors */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#0a0500&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* background */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;257&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#e0e0e0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* foreground */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * Default colors (colorname index)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * foreground, background, cursor
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;defaultfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;257&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;defaultbg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;defaultcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;257&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;defaultrcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * Colors used, when the specific fg == defaultfg. So in reverse mode this
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * will reverse too. Another logic would only make the simple feature too
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * complex.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;defaultitalic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;defaultunderline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * Default shape of cursor
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 2: Block (&amp;#34;█&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 4: Underline (&amp;#34;_&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 6: Bar (&amp;#34;|&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 7: Snowman (&amp;#34;☃&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cursorshape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * Default columns and rows numbers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="dmenu"&gt;dmenu&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://tools.suckless.org/dmenu/"&gt;dmenu&lt;/a&gt; can be configured in the same way as Simple Terminal by editing a text file and compiling the software. I like to use many keyboard shortcuts, but I find that for launching applications I don&amp;rsquo;t use that often or to launch custom Bash or Python scripts on the fly, nothing beats the simplicity of &lt;strong&gt;dmenu&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="configuration-1"&gt;Configuration&lt;/h3&gt;
&lt;p&gt;This one is very easy to configure and doesn&amp;rsquo;t really require any attention at all besides defining where you want it to appear on the screen and what colors you prefer. Here are some smalls changes I made to the configuration in &lt;code&gt;config.h&lt;/code&gt; before compiling it:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;topbar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* -b option; if 0, dmenu appears at bottom */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* -fn option overrides fonts[0]; default X11 font or font set */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fonts&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="s"&gt;&amp;#34;Consolas:size=12&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* -p option; prompt to the left of input field */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SchemeLast&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="cm"&gt;/* fg bg */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SchemeNorm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#D8D8D8&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#000000&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SchemeSel&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#000000&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#ff7400&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SchemeOut&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#000000&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;#00ffff&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* -l option; if nonzero, dmenu uses vertical list with given number of lines */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * Characters not considered part of a word while deleting words
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * for example: &amp;#34; /?\&amp;#34;&amp;amp;[]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;worddelimiters&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="slock"&gt;slock&lt;/h2&gt;
&lt;p&gt;What can be said about slock? It just works and never gets in your way. Set it and really forget it. From the official page:&lt;/p&gt;
&lt;blockquote&gt;
 &lt;p&gt;This is the simplest X screen locker we are aware of.&lt;/p&gt;

&lt;/blockquote&gt;&lt;p&gt;Again, its simplicity is charming and nothing really needs to be changed in &lt;code&gt;config.h&lt;/code&gt; apart from colors and setting the correct username and group name to lock and unlock the screen.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This was a lighting fast overview of some of the tools I now use on a daily basis. Suckless tools caught my attention and kept it! They offer other specialized software like a web browser, a tool for presentation from the terminal, IRC client and others&amp;hellip; but the ones described here are really those which I now can&amp;rsquo;t live without.&lt;/p&gt;
&lt;p&gt;I was originally inspired to seek out those tools thanks to &lt;a href="https://lukesmith.xyz/"&gt;Luke Smith&lt;/a&gt;, a &lt;a href="https://www.youtube.com/channel/UC2eYFnH61tmytImy1mTYvhA"&gt;fantastic YouTuber&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sun, 12 May 2019 22:50:00 -0500</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/suckless-minimalist-tools-that-work-great/</guid><category>tools</category><category>productivity</category><category>software</category><category>web</category></item><item><title>Tag Navigation in Vim</title><link>https://www.sglavoie.com/posts/tag-navigation-in-vim/</link><description>A quick introduction to tag navigation in Vim/Neovim.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="navigate-inside-the-current-buffer"&gt;Navigate inside the current buffer&lt;/h2&gt;
&lt;p&gt;There is a command &lt;code&gt;gd&lt;/code&gt; that stands for &lt;strong&gt;Goto local Declaration&lt;/strong&gt;. It is quite useful when looking for a variable inside the current buffer as it allows to jump to where it is declared when the variable is under the cursor. Using that command, you can also find where a function is declared and it will find the first occurrence in the current function. If looking for the first occurrence in the buffer, &lt;code&gt;gD&lt;/code&gt; (&lt;strong&gt;Goto global Declaration&lt;/strong&gt;) will do the trick. You can jump back and forth to where you were with the commands &lt;code&gt;Ctrl + O&lt;/code&gt; (older position) and &lt;code&gt;Ctrl + I&lt;/code&gt; (newer position) in normal mode.&lt;/p&gt;
&lt;h2 id="navigate-inside-all-buffers-within-the-current-project"&gt;Navigate inside all buffers within the current project&lt;/h2&gt;
&lt;p&gt;To be able to jump between buffers and go back to the origin of a declaration when it is imported in the current module, generating tags comes in very handy as it allows you to use the command &lt;code&gt;Ctrl + ]&lt;/code&gt; to jump to a tag, just like when using the help pages in &lt;strong&gt;Vim&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To make this work, we can conveniently use &lt;code&gt;ctags&lt;/code&gt;. First, we need to make sure it&amp;rsquo;s installed on the system as follow:&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="debianubuntu"&gt;Debian/Ubuntu&lt;/h3&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install ctags&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install exuberant-ctags&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="os-x"&gt;OS X&lt;/h3&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install ctags&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;You can put the following command in your configuration file to be able to generate the necessary tags inside &lt;strong&gt;Vim&lt;/strong&gt; by typing &lt;code&gt;MakeTags&lt;/code&gt; in command mode:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;MakeTags&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ctags&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will make it easy to remember how to do it. After that, open an existing project in its root directory and use this newly created &lt;code&gt;MakeTags&lt;/code&gt; command to generate the tags. This will create a file named &lt;code&gt;tags&lt;/code&gt; in the current working directory*. Now, you will be able to open any file inside your project and jump to all the available declarations with &lt;code&gt;Ctrl + ]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;* &lt;sub&gt;Note: This will create tags recursively from the &lt;em&gt;current working directory&lt;/em&gt;, &lt;strong&gt;not&lt;/strong&gt; from the path matching the current buffer.&lt;/sub&gt;&lt;/p&gt;
&lt;p&gt;If you go to a tag that leads you a few declarations away in one file or another, you can come back with &lt;code&gt;Ctrl + T&lt;/code&gt;. Here is a clear explanation from Vim&amp;rsquo;s help:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;pre tabindex="0"&gt;&lt;code&gt;The most obvious way to use this is while browsing through the call graph of
a program. Consider the following call graph:

	main ---&amp;gt; FuncA ---&amp;gt; FuncC
	 ---&amp;gt; FuncB

(Explanation: main calls FuncA and FuncB; FuncA calls FuncC).
You can get from main to FuncA by using CTRL-] on the call to FuncA. Then
you can CTRL-] to get to FuncC. If you now want to go back to main you can
use CTRL-T twice. Then you can CTRL-] to FuncB.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;To keep those tags useful when you update your project, you can map a sequence that saves the buffer you are working on and then regenerates the tags automatically. Here is an example:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;W&lt;/span&gt; :&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;:&lt;span class="nx"&gt;MakeTags&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;:&lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ctags have been updated.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And on this note, we&amp;rsquo;re ready to conquer the world.&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Fri, 19 Apr 2019 17:52:00 -0500</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/tag-navigation-in-vim/</guid><category>tips-and-tricks</category><category>productivity</category><category>vim</category></item><item><title>Dispose of Spam with Disposable Emails And More!</title><link>https://www.sglavoie.com/posts/dispose-of-spam-with-disposable-emails-and-more/</link><description>Have you ever received spam to your email address? Unless you are extremely lucky or are actually disconnected from the Internet and thus most probably not reading this, chances are you might have had an offer or two to receive gold from a Nigerian prince in the past. Before those princes and princesses generously start giving away their cryptocurrency in the near future in exchange for a trip to Western Union, get prepared and hide away your precious address!</description><content:encoded>&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;If your privacy matters to you even just a little, read on, if you dare.
There are easy solutions you can apply right now to filter those fools
out of your digital life.&lt;/p&gt;
&lt;h2 id="why-should-i-care"&gt;Why should I care?&lt;/h2&gt;
&lt;p&gt;Once your main email address is exposed to attacks because it was
leaked in a data breach or your data was somehow sold to a third-party
service, it is a hard and time-consuming process to try to unsubscribe
to everything or apply filters to automatically delete most of the
bad stuff coming in. Many websites won&amp;rsquo;t respect your privacy and
will go ahead and share your email, which can eventually have a
snowball effect and you end up getting more emails than there are trees
available to print them. As with printing emails, you must agree this
is totally irresponsible and should be punished by law
.&lt;/p&gt;
&lt;p&gt;Because attackers can often retrieve your complete name from your
email address (either because you signed up for a service sharing your
information from another provider or it&amp;rsquo;s easy to associate it with you
on social media, for example), they can craft advanced phishing emails
or create content that&amp;rsquo;s magically relevant to you thanks to social
engineering and if you don&amp;rsquo;t look close enough, you can fall into their
trap.&lt;/p&gt;
&lt;p&gt;Then suddenly, because you opened an attachment or went into the
&lt;strong&gt;dark&lt;/strong&gt; corners of the Web unbeknownst to you, your laptop fan is
spinning all the time at full speed or you get a colorful pop-up telling
you that all your files have been encrypted and a ransom, along with
only unrecognizable files on your system, convincingly dictates what
your destiny looks like. At this point, &lt;em&gt;you are doomed&lt;/em&gt;, unless you
actually take pleasure in formatting your computer once in a while for
the shear joy of it.&lt;/p&gt;
&lt;p&gt;So what shall we do about it?&lt;/p&gt;
&lt;h2 id="solution-1-use-a-temporary-email"&gt;Solution #1: Use a temporary email&lt;/h2&gt;
&lt;p&gt;This one is quick and easy. You can use a variety of services,
including &lt;a href="https://www.tempmailaddress.com/"&gt;Temp Mail Address&lt;/a&gt;,
&lt;a href="https://temp-mail.org/"&gt;Temp Mail&lt;/a&gt; and
&lt;a href="https://www.throwawaymail.com/"&gt;ThrowAwayMail&lt;/a&gt; to name a few. Those
are all free services and allow you to get access to a temporary email
address and its associated inbox.&lt;/p&gt;
&lt;p&gt;Perfect for all those cases when you want to receive a freebie or have
access to a specific page that asks for an email and a &lt;em&gt;real&lt;/em&gt; name. You
simply give a fake but working email address and you&amp;rsquo;re good to go.
Don&amp;rsquo;t even set it and forget it.&lt;/p&gt;
&lt;h2 id="solution-2-use-a-more-controlled-approach"&gt;Solution #2: Use a more controlled approach&lt;/h2&gt;
&lt;p&gt;There is one particular service that I have been using for almost
a decade now that eats your spam away on demand. That service is
appropriately called &lt;a href="https://www.spamgourmet.com"&gt;Spamgourmet&lt;/a&gt;. Does it
work? Here are my personal stats:&lt;/p&gt;
&lt;blockquote&gt;
 &lt;p&gt;Your message stats: 805 forwarded, 14,191 eaten. You have 245 spamgourmet address(es).&lt;/p&gt;

&lt;/blockquote&gt;&lt;h2 id="does-it-really-work"&gt;Does it really work?&lt;/h2&gt;
&lt;p&gt;Oh yes! From the above stats, you can see that from a total of
&lt;strong&gt;14,996&lt;/strong&gt; messages being sent to me, I have not received almost &lt;strong&gt;95%&lt;/strong&gt;
of it thanks to Spamgourmet working on auto-pilot all the time&amp;hellip; And
it&amp;rsquo;s important to mention that &lt;strong&gt;the other 5%, I actually wanted to
receive it&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="how-does-it-work"&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;You can create as many email addresses as you require to login to most
websites that you do not intend to use regularly and create a label
&lt;code&gt;Filtered mail&lt;/code&gt; in your inbox or something similar that matches anything
sent to &lt;code&gt;*@spamgourmet.com&lt;/code&gt;. You can create addresses on the fly without
ever needing to log into your Spamgourmet account and set how many
emails can be sent to a specific address all at once.&lt;/p&gt;
&lt;p&gt;With very few extra steps, you can manage your email addresses on
Spamgourmet, remove the ones you don&amp;rsquo;t want anymore, reset how many
emails can be received (increase/decrease that number), etc. You can
find out exactly how it works on the main page of Spamgourmet.&lt;/p&gt;
&lt;h2 id="why-consider-this-approach-instead-of-solution-1"&gt;Why consider this approach instead of solution #1?&lt;/h2&gt;
&lt;p&gt;This approach has the advantage that you can know exactly where your
spam is coming from and exactly when, as your email may be used quite a
long time after your original registration with a service to spam you.
If you have created an account on, say, &lt;code&gt;clouds.com&lt;/code&gt; with your special
email &lt;em&gt;created on the fly without ever needing to go to Spamgourmet&lt;/em&gt;,
let&amp;rsquo;s say it&amp;rsquo;s &lt;code&gt;clouds.my_username@spamgourmet.com&lt;/code&gt;, if you receive
spammy content sent to that address six months later, don&amp;rsquo;t look too
hard: you know who did it.&lt;/p&gt;
&lt;p&gt;Not only you know this, but you can keep on using this made up email
for as long as you wish. Need to be in touch with a person who
doesn&amp;rsquo;t fall into any of the categories &lt;code&gt;['friend', 'acquaintance', 'work', 'intimate', 'trustworthy']&lt;/code&gt;?
No worries, instantly claim &lt;code&gt;something.my_username@spamgourmet.com&lt;/code&gt; and
that&amp;rsquo;s the email you give that person. Since it doesn&amp;rsquo;t expire and you
have full control over how many more emails you can receive at that
address at any time, it can simplify a few exchanges where you don&amp;rsquo;t
really want to share your real email, not even to the Nigerian Prince.
This way, you can even receive attachments just as normal!&lt;/p&gt;
&lt;p&gt;You can even go as far as having trusted senders (from whom you can
receive as many emails as you define) and &lt;strong&gt;send mail from your custom
Spamgourmet emails, including with attachments&lt;/strong&gt;! For this, you can
visit Spamgourmet and generate an email of your choice that will be
sending to a specific address email. You will simply send the email to
this specially generated address from your email account and voilà!
The person on the other end will have a hard time figuring out your
real address, except if you added it in your signature.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0012_dispose-of-spam/spamgourmet_getting_through.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0012_dispose-of-spam/spamgourmet_getting_through.png" alt="spamgourmet_getting_through" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="solution-3-using-filters"&gt;Solution #3: Using filters&lt;/h2&gt;
&lt;p&gt;Gmail is one email service that allows you to create filters as you
wish: let&amp;rsquo;s take advantage of that. What you could do is delete only
messages that match exactly the groups of terms you never want to read
as to not exclude important emails. To create one filter for all of
them, you can use the field &lt;code&gt;has words&lt;/code&gt; and enter something like the
following in the case of GDPR policy updates:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#34;Privacy Policy Update&amp;#34; OR &amp;#34;GDPR&amp;#34; OR &amp;#34;General Data protection regulation&amp;#34; OR &amp;#34;Updates to our terms of use&amp;#34; OR &amp;#34;Updates to our privacy&amp;#34; OR &amp;#34;updating our privacy&amp;#34; OR &amp;#34;updated our privacy&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you know more specifically how the words you are looking for appear,
you can check for turns of phrases such as &lt;code&gt;Updates to X's Privacy Policy&lt;/code&gt; and manage them with the keyword &lt;code&gt;AROUND &amp;lt;number&amp;gt;&lt;/code&gt;, where
&lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; is how many words can be around what you are searching:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#34;privacy policy&amp;#34; AROUND 3 update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will look anywhere in the subject or in the content of the email
and find the word &lt;code&gt;update&lt;/code&gt; as well as &lt;code&gt;updates&lt;/code&gt; near the match &lt;code&gt;privacy policy&lt;/code&gt;. If you are interested in looking for the word &lt;code&gt;update&lt;/code&gt; but not
&lt;code&gt;updates&lt;/code&gt;, you can specify an exact match with the &lt;code&gt;+&lt;/code&gt; sign right in
front of it: &lt;code&gt;+update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;sub&gt;Note: If you go too broad with the chosen keywords, you may not be able to reply to everything you would like to&amp;hellip;&lt;/sub&gt;&lt;/p&gt;
&lt;p&gt;A next step could be to filter potentially important emails with more
keywords but instead of deleting them, you can select a few options for
your filter such as &lt;strong&gt;Skip the Inbox&lt;/strong&gt; (Archive it), &lt;strong&gt;Mark as read&lt;/strong&gt;,
&lt;strong&gt;Apply the label&lt;/strong&gt; and &lt;strong&gt;Never mark it as important&lt;/strong&gt;. That way, you
still have access to all those emails and you can review them separately
and quickly at your convenience.&lt;/p&gt;
&lt;p&gt;For a list of available search operators, you can refer to
this &lt;a href="https://support.google.com/mail/answer/7190?hl=en&amp;amp;topic=1668965&amp;amp;ctx=topic"&gt;Gmail help page — Search operators you can use with Gmail&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="solution-4-use-the--symbol-in-your-email"&gt;Solution #4: Use the &lt;code&gt;+&lt;/code&gt; symbol in your email&lt;/h2&gt;
&lt;p&gt;Gmail lets you add a &lt;code&gt;+&lt;/code&gt; symbol in your email address. For
example, you can set up your &lt;code&gt;ServiceNameHere&lt;/code&gt; email to be
&lt;code&gt;username+ServiceNameHere@gmail.com&lt;/code&gt;. That way, you know where your spam
may be coming from, but it is always more effective to just use a unique
address with the above service or even forward emails from another Gmail
account so you never have to give away your main email. By doing this,
you can then set up filters for individual services. This doesn&amp;rsquo;t work
for all websites as sometimes the &lt;code&gt;+&lt;/code&gt; symbol isn&amp;rsquo;t allowed. In that
scenario, there is another way&amp;hellip;&lt;/p&gt;
&lt;h2 id="solution-5-forward-secondary-emails-to-your-main-email"&gt;Solution #5: Forward secondary emails to your main email&lt;/h2&gt;
&lt;p&gt;This is pretty straightforward and even though you initially have to do
more work to set things up, this can work very well for various reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You get 15GB on each Gmail account. This can be useful, as long as you don&amp;rsquo;t abuse it and get banned for life without the possibility of ever communicating through email ever again in your lifetime.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can apply custom filters such as &lt;code&gt;send to trash&lt;/code&gt; for each secondary account before forwarding what&amp;rsquo;s left to your main account. You can then apply a filter in your main account to visually get a hint of where the email is coming from, like a label &lt;code&gt;my.second.email@gmail.com&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can stop forwarding emails at any moment if you decide. You will have to log into your secondary account and click a few buttons there, but it&amp;rsquo;s easy, almost painless and you shouldn&amp;rsquo;t have to repeat the process so often that it gets boring.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can even set up your main account so that you are able to send messages from your main account as if it were coming from any of your secondary accounts. No more account switching: you get something sent to &lt;code&gt;my.second.email@gmail.com&lt;/code&gt; in your main account and you can have it set up so that when you reply to that email, it is automatically sent from that secondary email instead of the main one.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope you found something useful in this rambling about spam.
I don&amp;rsquo;t like spam myself, so if you have any tips or tricks you
would like to share with me to help in this quest for freedom,
please reach out to me at my email shared in plain text at
&lt;a href="mailto:sebastien39571@gmail.com"&gt;&lt;a href="mailto:sebastien39571@gmail.com"&gt;sebastien39571@gmail.com&lt;/a&gt;&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Wed, 03 Apr 2019 20:08:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/dispose-of-spam-with-disposable-emails-and-more/</guid><category>tips-and-tricks</category><category>productivity</category><category>web</category></item><item><title>Surfing with qutebrowser — a Keyboard-Driven Web Browser</title><link>https://www.sglavoie.com/posts/surfing-with-qutebrowser-a-keyboard-driven-web-browser/</link><description>I recently started using this software as my main web browser and, as a Vim (Neovim) user, I must say I am finding the adventure quite compelling!</description><content:encoded>&lt;hr&gt;
&lt;h2 id="what-is-qutebrowser"&gt;What is qutebrowser?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://qutebrowser.org/"&gt;qutebrowser&lt;/a&gt; is a web browser that makes
great use of &lt;strong&gt;Vim&lt;/strong&gt; commands to navigate. From its website:&lt;/p&gt;
&lt;blockquote&gt;
 &lt;p&gt;qutebrowser is a keyboard-focused browser with a minimal GUI. It’s
based on Python and PyQt5 and free software, licensed under the GPL.
It was inspired by other browsers/addons like dwb and
Vimperator/Pentadactyl.&lt;/p&gt;

&lt;/blockquote&gt;&lt;hr&gt;
&lt;h3 id="why-use-it"&gt;Why use it?&lt;/h3&gt;
&lt;h4 id="perfect-companion-to-any-vim-user"&gt;Perfect companion to any Vim user&lt;/h4&gt;
&lt;p&gt;The first notable feature of &lt;strong&gt;qutebrowser&lt;/strong&gt; is obviously how well
the use of keyboard shortcuts is integrated with the experience of
using the software (there is a useful key binding cheatsheet on the
&lt;a href="https://qutebrowser.org/"&gt;homepage&lt;/a&gt;). Search bindings (&lt;code&gt;/&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;/&lt;code&gt;N&lt;/code&gt;,
&lt;code&gt;?&lt;/code&gt;), visual mode (&lt;code&gt;v&lt;/code&gt;), tabs (&lt;code&gt;gt&lt;/code&gt;, &lt;code&gt;T&lt;/code&gt;), copy (&lt;code&gt;yy&lt;/code&gt;), open URLs
(&lt;code&gt;o&lt;/code&gt;/&lt;code&gt;O&lt;/code&gt;), &lt;code&gt;J&lt;/code&gt; and &lt;code&gt;K&lt;/code&gt; for switching tabs, etc. Many key bindings will
look familiar to Vim users.&lt;/p&gt;
&lt;p&gt;It even features a &lt;em&gt;command mode&lt;/em&gt;, accessible by typing &lt;code&gt;:&lt;/code&gt;, just like
with Vim. Settings can be set from there directly, help can be accessed
by typing &lt;code&gt;:help [command/setting]&lt;/code&gt;, the configuration file can be
customized on the fly, the position and size of tabs can be set in many
ways, history and settings page can be accessed and navigated through
like any other page (&lt;code&gt;hjkl&lt;/code&gt;, &lt;code&gt;Ctrl + d&lt;/code&gt;, &lt;code&gt;Ctrl + u&lt;/code&gt;, &lt;code&gt;gg&lt;/code&gt;, &lt;code&gt;G&lt;/code&gt;), etc.&lt;/p&gt;
&lt;p&gt;Even though it is based on Python which is a &amp;ldquo;&lt;em&gt;slow&lt;/em&gt;&amp;rdquo; language, most of
the libraries and the web engine rely on C++ and the end result is a
fast and powerful browser that&amp;rsquo;s totally customizable&amp;hellip; Not unlike Vim.&lt;/p&gt;
&lt;h4 id="minimal-interface--more-space"&gt;Minimal interface ⇒ more space&lt;/h4&gt;
&lt;p&gt;Until I upgrade my laptop to a larger screen (≥ 17 inches), my
current setup with its 15 diagonal inches benefits tremendously
from configuring all applications to use pixels as efficiently as
possible — which is why I now use exclusively [i3 as a window
manager](/posts/2019/01/08/using-i3-as-a-window-manager-for-increased-pr
oductivity/).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;qutebrowser&lt;/strong&gt; doesn&amp;rsquo;t even have a menu bar. By default, it only
displays a small tab bar at the top (which can be moved to another
side or removed) and a thin status bar at the bottom to see the URL,
the current position in the page expressed in percentage, the number
assigned to the current tab, etc. There is also a fullscreen mode
available like in most other web browsers with the key &lt;code&gt;F11&lt;/code&gt;, which will
remove any window decoration and leave you in a (possibly) productive
mode.&lt;/p&gt;
&lt;h4 id="history-bookmarks-and-quickmarks"&gt;History, bookmarks and quickmarks&lt;/h4&gt;
&lt;p&gt;The history page (&lt;code&gt;:history&lt;/code&gt;), while being minimal like all the rest,
loads extremely fast and is a joy to navigate. The bookmarks page (&lt;code&gt;Sb&lt;/code&gt;)
is equally simple yet useful. The way I like to open a bookmark is in
a new tab by typing &lt;code&gt;gB&lt;/code&gt; (&lt;strong&gt;g&lt;/strong&gt;o &lt;strong&gt;b&lt;/strong&gt;ookmark as a mnemonic. Note that
usually all uppercase letters open or do some action in a new space,
such as a window or a tab).&lt;/p&gt;
&lt;p&gt;Where &lt;strong&gt;qutebrowser&lt;/strong&gt; shines in my opinion is with quickmarks. This is
a simple but genius way to find what you are looking for: you type &lt;code&gt;b&lt;/code&gt;
(or &lt;code&gt;B&lt;/code&gt; for new tab) to open a list of pages that are defined with a
keyword, you type that keyword (or can type anything to search for a
page), move around with arrow keys if necessary to select a page, type
&lt;code&gt;Enter&lt;/code&gt; and there you go. As far as I know, Google Chrome doesn&amp;rsquo;t offer
the equivalent (only keywords for search engines). Firefox allows to add
keywords for any bookmark that you have, but there is no good way to
search around for keywords, define them quickly, remove them quickly,
etc. &lt;strong&gt;qutebrowser&lt;/strong&gt; comes with a set of commands that serve just this
purpose (&lt;code&gt;:quickmark-add&lt;/code&gt;, &lt;code&gt;quickmark-del&lt;/code&gt;, etc.), apart from adding
them very quickly by typing &lt;code&gt;m&lt;/code&gt; for quickmarks and &lt;code&gt;M&lt;/code&gt; for bookmarks.&lt;/p&gt;
&lt;h4 id="hinting-system"&gt;Hinting system&lt;/h4&gt;
&lt;p&gt;You may have tried extensions for other web browsers such as Vimium,
Vimperator, or Vimium-FF that let you navigate with Vim shortcuts. They
usually use the letter &lt;code&gt;f&lt;/code&gt; for &lt;strong&gt;f&lt;/strong&gt;ollowing links. Some text appear on
the screen for each visible link and you type the letters that match the
link you want to see. The best way to get how it works is just to try it
out, really.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0007_surfing-with-qutebrowser/qutebrowser_hints.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0007_surfing-with-qutebrowser/qutebrowser_hints.png" alt="qutebrowser-hints" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Well, &lt;strong&gt;qutebrowser&lt;/strong&gt; takes those features and make them even greater!
There is, for example, a &lt;em&gt;rapid hinting mode&lt;/em&gt; you can access by typing
&lt;code&gt;f&lt;/code&gt; followed by &lt;code&gt;Ctrl + r&lt;/code&gt; and it will open links in the background
for as long as you type any matching &lt;em&gt;hint&lt;/em&gt; provided as a letter or
combination of two letters when there are many visible links on the
page. This is especially useful when doing some research to avoid
breaking the rhythm on the current reading while preparing more
resources to be available.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="whats-the-best-place-to-start-learning-about-it"&gt;What&amp;rsquo;s the best place to start learning about it?&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://qutebrowser.org/doc/help/"&gt;help page&lt;/a&gt; on the website
contains all the information you really need. I did stumble upon the
following resources, which I would recommend to read in order of
appearance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://qutebrowser.org/doc/quickstart.html"&gt;Quickstart Guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[Key bindings
cheatsheet](&lt;a href="https://raw.githubusercontent.com/qutebrowser/qutebrowser/ma"&gt;https://raw.githubusercontent.com/qutebrowser/qutebrowser/ma&lt;/a&gt;
ster/doc/img/cheatsheet-big.png).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qutebrowser.org/doc/faq.html"&gt;FAQ&lt;/a&gt;, which is interesting
but not indispensable. It did help me take a step forward in trying out
&lt;strong&gt;qutebrowser&lt;/strong&gt; though.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Open inside qutebrowser&lt;/em&gt;: &lt;a href="qute://help/settings.html#bindings.default"&gt;default
keybindings&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Open inside qutebrowser&lt;/em&gt;: &lt;a href="qute://settings/"&gt;settings page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qutebrowser.org/doc/help/commands.html"&gt;List of commands&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;qutebrowser&lt;/strong&gt; has been around for a while and is very stable. It is
ideal for any Vim user and is a great option for anyone interested in
efficiency and/or in trying out alternatives. Because I am very fond
of relying on the keyboard as much as possible and because I love to
program in Python, I have grown to like this web browser very quickly.
This is clearly a tool designed for a specific type of user in mind and
who knows, you might be one of those.&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Mon, 11 Feb 2019 14:46:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/surfing-with-qutebrowser-a-keyboard-driven-web-browser/</guid><category>tools</category><category>productivity</category><category>software</category><category>web</category></item><item><title>Using Embedded Terminals Inside Neovim</title><link>https://www.sglavoie.com/posts/using-embedded-terminals-inside-neovim/</link><description>Because every pixel counts, this neat trick will allow to use terminals inside Neovim and maximize the screen estate for a flawless integration with one of the best text editor available.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="terminals--neovim"&gt;Terminals &amp;amp; Neovim&lt;/h2&gt;
&lt;p&gt;Terminal buffers are a built-in feature of &lt;code&gt;Neovim&lt;/code&gt;. This means that
terminals can be launched inside Neovim just like any other buffer, may
it be a split window, a new tab or an independent buffer. Why is this so
useful? Be prepared to be amazed.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0006_using-embedded-terminals-inside-neovim/work_on_article.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0006_using-embedded-terminals-inside-neovim/work_on_article.png" alt="embedded-terminal" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0006_using-embedded-terminals-inside-neovim/terminal_buffers.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0006_using-embedded-terminals-inside-neovim/terminal_buffers.png" alt="terminal-buffers" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(click to open)&lt;/p&gt;
&lt;h3 id="seamless-integration-with-vim-commands"&gt;Seamless integration with Vim commands&lt;/h3&gt;
&lt;p&gt;For a start, terminals are not just &lt;em&gt;opened&lt;/em&gt; inside Neovim: they are
truly integrated. When you type the letter &lt;code&gt;i&lt;/code&gt; in a terminal buffer,
it switches to a new mode, &lt;code&gt;Terminal&lt;/code&gt;, where you have access to all
underlying features of a regular Bash terminal, such as &lt;code&gt;CTRL + r&lt;/code&gt;
to search, tab completion of commands, &lt;code&gt;CTRL + w&lt;/code&gt; to delete a word
backwards or &lt;code&gt;CTRL + u&lt;/code&gt; to delete the whole line backwards.&lt;/p&gt;
&lt;p&gt;When you escape the &lt;code&gt;Terminal&lt;/code&gt; mode, you switch back to &lt;code&gt;Normal&lt;/code&gt; mode,
where all Vim commands are available as usual, such as navigation,
search, etc. Where this gets interesting is when you consider that the
terminal is just like any other buffer (except it&amp;rsquo;s not &lt;em&gt;modifiable&lt;/em&gt;)
and so you can for instance copy its content or paste into it from
different registers. You can split them, view the line number, get
automatic scrolling when output appears in &lt;code&gt;Insert&lt;/code&gt; mode, you can switch
back to &lt;code&gt;Normal&lt;/code&gt; mode at any time even if a command hasn&amp;rsquo;t completed&amp;hellip;
and of course all commands like &lt;code&gt;gt&lt;/code&gt; to &lt;strong&gt;g&lt;/strong&gt;o to another &lt;strong&gt;t&lt;/strong&gt;ab work
as always.&lt;/p&gt;
&lt;h3 id="terminals-get-supercharged-with-the-power-of-vim"&gt;Terminals get supercharged with the power of Vim&lt;/h3&gt;
&lt;p&gt;This is getting exciting (at least for me). Now, having a terminal with
more power is useful in many cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A whole terminal session can be saved to another file easily by
copying the desired range (&lt;code&gt;:%y&lt;/code&gt; to copy everything, for example).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Instead of having to scroll with the mouse, all Vim commands are
available to search and navigate through the buffer: &lt;code&gt;gg&lt;/code&gt; to go to the
beginning of the session, &lt;code&gt;G&lt;/code&gt; to go to the end, &lt;code&gt;12G&lt;/code&gt; to go to line
number &lt;strong&gt;12&lt;/strong&gt;, &lt;code&gt;/&lt;/code&gt; or &lt;code&gt;?&lt;/code&gt; to search forward and backward respectively.
You can even set local or global marks to jump back and forth to precise
lines consistently!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It&amp;rsquo;s even possible to send commands directly to a specific
terminal or set up a REPL to execute any code, either a
selection, a line or a range of lines. I don&amp;rsquo;t personally
use that feature yet, but I see how useful that can be and
you can too if you watch this [screencast presented by Drew
Neil](&lt;a href="https://thoughtbot.com/upcase/videos/neovim-sending-commands-to-a-"&gt;https://thoughtbot.com/upcase/videos/neovim-sending-commands-to-a-&lt;/a&gt;
terminal-buffer) on
&lt;a href="https://thoughtbot.com"&gt;thoughtbot.com&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the terminal is opened in &lt;code&gt;Normal&lt;/code&gt; mode, the cursor and the current
position are kept intact even though new output could appear, such as
would be the case if you are running a server in the background or
waiting for a system update to finish. This is especially nice for
instance if you are trying to debug a web application: you can leave the
cursor exactly where you would like to keep reading the output and never
get lost&amp;hellip; Plus you have the ability to easily move around, search and
copy like a ninja!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-workflow-is-more-compact-and-centralized"&gt;The workflow is more compact and centralized&lt;/h3&gt;
&lt;p&gt;Because the terminals are running with one Neovim instance, you get
everything in the same place, which is usually how you need to access
your work anyway. If for some reasons you need to have multiple
instances of Neovim running, this is possible too and in that situation
you could simply split them into different workspaces.&lt;/p&gt;
&lt;p&gt;Because everything is launched with Neovim, every terminal left open
will also be exited when you close Neovim, shutting down any server
or quitting any background interaction going on in the terminals. I
have found that this behaviour is what I expect pretty much all the
time because the idea of having a terminal inside a working session
of Neovim is to work on something related, so it makes sense to close
everything that&amp;rsquo;s to do with a single project or task when you exit the
text editor. No need for &lt;code&gt;CTRL + d&lt;/code&gt; or &lt;code&gt;exit&lt;/code&gt; anymore!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="terminal-settings-to-consider"&gt;Terminal settings to consider&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t use many settings or mappings related to terminals, but I guess
the nicest one is to remap the &lt;code&gt;Escape&lt;/code&gt; key because by default, this is
a weird mapping that leads to twisted fingers (&lt;code&gt;&amp;lt;C-\&amp;gt;&amp;lt;C-n&amp;gt;&lt;/code&gt;). Here is
what I currently have in my &lt;code&gt;init.vim&lt;/code&gt; file (the equivalent of &lt;code&gt;.vimrc&lt;/code&gt;
for Neovim):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;vim&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;termguicolors&lt;/span&gt; &lt;span class="c"&gt;&amp;#34; Make colors look better in terminal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Exit from terminal buffer (Neovim) more easily (remaps Esc key in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; terminal)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;tnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;[&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;\&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Open terminal buffer (M stands for the Alt key)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;M&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :&lt;span class="nx"&gt;te&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Switch to terminal buffer automatically (when only one terminal is&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; open)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;M&lt;/span&gt;&lt;span class="m"&gt;-0&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="nx"&gt;term&lt;/span&gt;:&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Move between windows exactly the same way as usual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;tnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;\&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;tnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;\&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;tnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;\&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;tnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;\&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;tnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;\&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This was a quick overview of a feature that I have neglected for some
time but recently realized how well it integrates with my workflow. You
can find some more information by typing &lt;code&gt;:h terminal&lt;/code&gt;. If you already
use Neovim, it&amp;rsquo;s worth giving it a try! Otherwise, it&amp;rsquo;s worth giving
&lt;a href="https://neovim.io/"&gt;Neovim&lt;/a&gt; a try.&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Wed, 16 Jan 2019 17:32:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/using-embedded-terminals-inside-neovim/</guid><category>tips-and-tricks</category><category>neovim</category><category>productivity</category><category>terminal</category></item><item><title>Using i3 as a Window Manager for Increased Productivity</title><link>https://www.sglavoie.com/posts/using-i3-as-a-window-manager-for-increased-productivity/</link><description>I was striving to improve my productivity as one of my New Year’s resolutions and finally found the courage to take the time to try out i3, a fantastic window manager.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="what-is-i3"&gt;What is i3?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://i3wm.org/"&gt;i3&lt;/a&gt; is a tiling window manager. To get to know &lt;code&gt;i3&lt;/code&gt;
better, it&amp;rsquo;s good to situate what desktop environments are in the first
place.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="what-are-desktop-environments"&gt;What are desktop environments?&lt;/h3&gt;
&lt;p&gt;If you are familiar with Linux,
you certainly know about desktop environments such as
&lt;a href="https://www.gnome.org/"&gt;GNOME&lt;/a&gt;, &lt;a href="https://www.kde.org/"&gt;KDE&lt;/a&gt;,
&lt;a href="https://www.xfce.org/"&gt;Xfce&lt;/a&gt;&amp;hellip; and actually many
more are available (you can see &lt;a href="https://en.wikipedia.org/wiki/Desktop_environment"&gt;this article on
Wikipedia&lt;/a&gt;
for an extended selection)! The classic Graphical User Interface
(GUI) on Windows XP was known as
&lt;a href="https://en.wikipedia.org/wiki/Luna_%28theme%29"&gt;Luna&lt;/a&gt; and is now
called Modern on Windows 10.
&lt;a href="https://en.wikipedia.org/wiki/Aqua_%28user_interface%29"&gt;Aqua&lt;/a&gt; is the
name of the GUI on macOS. Well, every desktop environment comes with
a window manager, the main component that makes interactions with
windows possible, like moving, resizing, minimizing or closing them.&lt;/p&gt;
&lt;p&gt;Desktop environments are very useful in many ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They are usually very easy to set up as they come fully functional out
of the box. Like opening a user session on macOS or Windows.&lt;/li&gt;
&lt;li&gt;They are sometimes quite customizable, but you don&amp;rsquo;t have to change
anything to get them to work, as they normally set default applications
to open with certain file types.&lt;/li&gt;
&lt;li&gt;They automatically integrate services such as WiFi network detection,
automatic mounting of drives when you plug them in, etc.&lt;/li&gt;
&lt;li&gt;You can enable &lt;a href="https://en.wikipedia.org/wiki/Virtual_desktop"&gt;virtual
desktops&lt;/a&gt;
to split your work
across different spaces. This concept can grow to
&lt;em&gt;[Activities](&lt;a href="https://docs.kde.org/trunk5/en/kde-workspace/plasma-deskto"&gt;https://docs.kde.org/trunk5/en/kde-workspace/plasma-deskto&lt;/a&gt;
p/activities-interface.html)&lt;/em&gt;, which is a feature implemented in KDE
that allows you to use virtual spaces literally for different activities
by having settings that are specific to each activity (like launching
one application or keeping widgets in determined positions), plus the
ability to use multiple virtual desktops inside each &lt;em&gt;activity&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;They integrate with applications that are specifically designed to
take advantage of the desktop environment in question by adapting
colors and themes perfectly to match the general look of the system and
arranging settings in a common location for all applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="why-use-a-window-manager-like-i3"&gt;Why use a window manager like i3?&lt;/h3&gt;
&lt;p&gt;Even though desktop environments are user-friendly and include many
goodies, they do have several disadvantages that make window managers
great alternatives.&lt;/p&gt;
&lt;h4 id="less-bloated"&gt;Less bloated&lt;/h4&gt;
&lt;p&gt;Desktop environments are often bloated with many applications
that you may not need but that are nevertheless occupying system
resources as they have many dependencies. For example, if you use
&lt;a href="https://www.thunderbird.net"&gt;Thunderbird&lt;/a&gt; for managing your emails and
your desktop environment is GNOME, try to remove Evolution, the default
application for emails that comes with it&amp;hellip; It&amp;rsquo;s still relatively easy
to disable its processes, but you sometimes have to configure files
manually to satisfy your need for removing clutter.&lt;/p&gt;
&lt;h4 id="lower-memory-and-cpu-consumption"&gt;Lower memory and CPU consumption&lt;/h4&gt;
&lt;p&gt;Other than coming with a set of default applications (more disk space),
the whole environment occupies a lot more memory to run smoothly. On
my modest laptop, I was still experiencing speed issues because the
system was occupying too much RAM when opening heavy applications (lots
of tabs when web browsing, photo editing, loading IDEs like PyCharm
for programming, etc.) and I had 4 GB of RAM installed at the time.
KDE requires at least 600 MB, same is true for GNOME in most recent
versions (but used to be over 1 GB not very long ago, just like for
KDE). Windows, for example, requires more than 1.5 GB of RAM to operate
with basic features. &lt;strong&gt;&lt;code&gt;i3&lt;/code&gt;&lt;/strong&gt; needs less than &lt;strong&gt;~15 MB&lt;/strong&gt; with as many
windows and spaces open as you would ever want. Since there are much
less processes to take care of, CPU consumption is also lower, which is
more noticeable on older machines.&lt;/p&gt;
&lt;h4 id="keyboard-efficiency"&gt;Keyboard efficiency&lt;/h4&gt;
&lt;p&gt;There are obviously ways to go about using keyboard shortcuts for pretty
much anything you want with desktop environments. However, window
managers and especially &lt;code&gt;i3&lt;/code&gt; make this a must, as there is really no
reason to use a mouse for moving windows.&lt;/p&gt;
&lt;p&gt;First of all, windows are &amp;ldquo;stuck&amp;rdquo; in place and never overlap by default.
You can&amp;rsquo;t move them around with a mouse unless they are &amp;ldquo;floating&amp;rdquo;
windows, which means you can separate them to move them around freely
like in most desktop environments. The whole point of using a window
manager like &lt;code&gt;i3&lt;/code&gt; is to maximize screen space, so every window opens
in full screen. Honestly, the only time I ever found the need to use a
floating window with &lt;code&gt;i3&lt;/code&gt; is when using the operating system Windows in
a virtual environment when connecting through RDP with Google Chrome on
Google Cloud Platform (that is, not very often). Other than that, I find
it very practical to split the screen with no overlapping windows, even
with my small 15 inches screen.&lt;/p&gt;
&lt;p&gt;Because windows are managed the way they are in &lt;code&gt;i3&lt;/code&gt;, getting split when
multiple windows are in the same workspace and never overlapping, it
nurtures the good habit of dividing workspaces appropriately to maximize
the space that each application occupies, which is done with keyboard
shortcuts. With (customizable) shortcuts, you can split windows,
move them to other workspaces, change workspaces, open applications
automatically in specific workspaces, etc. Using exclusively the
keyboard to manage the windows becomes a huge time saver, and even more
so when considering the very small footprint required to use the window
manager, making for a lightning fast experience.&lt;/p&gt;
&lt;h4 id="extremely-fast-customization"&gt;Extremely fast customization&lt;/h4&gt;
&lt;p&gt;Once you get past the initial lack of visual appeal and weird way to
move around, you can actually customize many aspects of &lt;code&gt;i3&lt;/code&gt;, including
fonts, mouse bindings, window border decorations, colors, automatic
execution of apps when initiating a session, etc.&lt;/p&gt;
&lt;p&gt;Why is it so fast to customize? Because the configuration is all
contained in one simple text file and you can make a change and reload
the window manager on the fly to see your changes being reflected.
Setting the number of workspaces is as easy as adding or removing a line
(well, as a bare minimum, otherwise it&amp;rsquo;s useful to also bind certain
keyboard shortcuts to move to those newly created workspaces). Setting a
wallpaper is one line, setting a screen lock is another one. Quick and
efficient.&lt;/p&gt;
&lt;h4 id="easy-to-switch-layouts-and-focus"&gt;Easy to switch layouts and focus&lt;/h4&gt;
&lt;p&gt;I actually enjoy the default layout quite a lot, in which there exists
no overlap between windows (they split as needed) and all windows are
visible at the same time in each workspace. If you need to make more
space for a window, you can either &amp;ldquo;focus&amp;rdquo; on the current window, which
will make it full screen and cover every pixel of the screen, or you
can move particular windows to other workspaces. This last option will
automatically resize windows so that they occupy the maximum space
available.&lt;/p&gt;
&lt;p&gt;Besides the default layout, you can also &lt;em&gt;stack&lt;/em&gt; and &lt;em&gt;tab&lt;/em&gt; windows,
depending on how you like to work (it is well worth having a look at the
&lt;a href="https://i3wm.org/docs/userguide.html"&gt;i3 user&amp;rsquo;s guide&lt;/a&gt; to see the many
other features available). Personally, I prefer seeing everything at
once and dividing my work into many workspaces. If you are curious, here
is how I currently have my workspaces set up:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Programming&lt;/strong&gt; — Exclusively for programming purposes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terminals&lt;/strong&gt; — For working in the terminal, opening another
instance of a terminal text editor, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web&lt;/strong&gt; — Just for Internet. Always full screen unless I open
some website that requires to open new windows (like banking), which
conveniently split the windows. The web browser automatically launches
in the background when opening a session in &lt;code&gt;i3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multimedia&lt;/strong&gt; — Editing photos or watching videos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Music&lt;/strong&gt; — &lt;a href="https://github.com/arybczak/ncmpcpp"&gt;ncmpcpp&lt;/a&gt;
(terminal music player) automatically launches in the background when
opening a session.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Experiments&lt;/strong&gt; — I use this workspace when trying to understand
some programming concepts with an interactive IPython console or for
breaking the system in one way or another because I don&amp;rsquo;t know what I&amp;rsquo;m
doing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fix&lt;/strong&gt; — After realizing that sometimes experiments need to be
cleaned up a bit, I now use this workspace exclusively to run tools
in the background, such as &lt;a href="https://www.bleachbit.org"&gt;BleachBit&lt;/a&gt; for
cleaning files or &lt;a href="https://nicolargo.github.io/glances/"&gt;glances&lt;/a&gt;
(similar to the &lt;code&gt;top&lt;/code&gt; command) for watching how the system is doing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Words&lt;/strong&gt; — I use that workspace for reading e-books
or for writing, either in &lt;a href="https://neovim.io/"&gt;Neovim&lt;/a&gt; or
&lt;a href="https://www.libreoffice.org/"&gt;LibreOffice&lt;/a&gt; depending on the task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt; — This workspace is reserved for anything that I
might want to have access to once in a while, like a calendar or
&lt;a href="https://keepassxc.org/"&gt;KeepassXC&lt;/a&gt; for accessing a password database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sg&lt;/strong&gt; — I mainly use that workspace to update this very
website, but I also use it for setting up local web servers for
making personal projects in &lt;a href="http://flask.pocoo.org/"&gt;Flask&lt;/a&gt; and
&lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; or even just a temporary server
with &lt;code&gt;python -m http.server&lt;/code&gt; to share files with other devices on the
local network.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Only workspaces that contain windows will appear on the screen at any
given time and are automatically created when you access and use them.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-does-it-look-like-in-action"&gt;What does it look like in action?&lt;/h2&gt;
&lt;p&gt;Here is a screenshot* of the workspace where this article is being
written (click to open):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sglavoie.com/images/posts/0005_using-i3-as-window-manager-for-increased-productivity/i3-example.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0005_using-i3-as-window-manager-for-increased-productivity/i3-example.png" alt="i3-example" class="max-size-img-post"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;* &lt;sub&gt;In this particular scenario, the splits on the right side are
intentionally very small as I do not need to read the output, but need
quick access to a terminal to enter commands. Moving back and forth
between windows is a breeze, so that&amp;rsquo;s how I currently handle the
situation.&lt;/sub&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: With &lt;code&gt;Neovim&lt;/code&gt;, &lt;a href="https://www.sglavoie.com/posts/using-embedded-terminals-inside-neovim/"&gt;there is an embedded
terminal&lt;/a&gt;,
which makes things very easy to handle by avoiding splits altogether.
In that case, it is also possible to divide a workflow with tabs inside
&lt;code&gt;Neovim&lt;/code&gt; instead of physically splitting windows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alternatively&lt;/strong&gt;, instead of splitting windows, a more convenient
solution on smaller screens might be to use &lt;strong&gt;stacking&lt;/strong&gt; windows with
the shortcut &lt;code&gt;$mod + s&lt;/code&gt; in each workspace or, to provide that behavior
by default, the following can be added to i3&amp;rsquo;s configuration file
(defaults in &lt;code&gt;~/.config/i3/config&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Set default container layout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;workspace_layout stacking&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I am not trying to convince myself anymore: I really prefer this
workflow! If you are looking for a
change and would like to maximize both your productivity and your system
resources, &lt;code&gt;i3&lt;/code&gt; is a great window manager to consider. It doesn&amp;rsquo;t seem
very intuitive at first, but I swear it quickly becomes easy to use and
you also end up learning more about how Linux works and set things up
manually (just once!) to your likings. For example, I use Rofi instead
of dmenu to have a window pop-up to select applications or switch to
any window on any workspace&amp;hellip; which was only one line to modify in the
configuration file.&lt;/p&gt;
&lt;p&gt;I have found the following screencasts on YouTube to be quite useful in
learning how to configure &lt;code&gt;i3&lt;/code&gt; (apart from the official documentation
which is very comprehensive):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j1I63wGcvU4"&gt;i3wm: Jump Start (1/3)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=8-S0cWnLBKg"&gt;i3wm: Configuration (2/3)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=ARKIwOlazKI"&gt;i3wm: How To &amp;ldquo;Rice&amp;rdquo; Your Desktop (3/3)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Tue, 08 Jan 2019 11:12:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/using-i3-as-a-window-manager-for-increased-productivity/</guid><category>workflow</category><category>i3</category><category>linux</category><category>productivity</category><category>window-manager</category></item><item><title>Aliases: Also Known as Terminal User's Best Friends</title><link>https://www.sglavoie.com/posts/aliases-also-known-as-terminal-users-best-friends/</link><description>Here are presented a few terminal aliases that I find myself using regularly.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="some-aliases-that-i-find-useful"&gt;Some aliases that I find useful&lt;/h2&gt;
&lt;hr&gt;
&lt;blockquote&gt;
 &lt;p&gt;In all the following examples, the dollar sign &lt;code&gt;$&lt;/code&gt; at the beginning of
commands represents the prompt, it should not be typed.&lt;/p&gt;

&lt;/blockquote&gt;&lt;h3 id="general-purpose"&gt;General-purpose&lt;/h3&gt;
&lt;hr&gt;
&lt;h4 id="list-all-aliases"&gt;List all aliases&lt;/h4&gt;
&lt;div class="code-block" data-prompted&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;alias&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Prints all of your aliases. If you have plenty of those, you might
prefer to pipe this command with &lt;code&gt;less&lt;/code&gt; to get a nice pager that allows
you to easily nagivate them:&lt;/p&gt;
&lt;div class="code-block" data-prompted&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; less&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h4 id="setting-an-alias-in-bash_aliases"&gt;Setting an alias in &lt;code&gt;~/.bash_aliases&lt;/code&gt;&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;clear&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This would set &lt;code&gt;c&lt;/code&gt; as a shortcut to &lt;code&gt;clear&lt;/code&gt;. In order to use the
newly created alias, you would have to close the terminal or type the
following command in the terminal:&lt;/p&gt;
&lt;div class="code-block" data-prompted&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bash_aliases&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h4 id="clear-the-screen"&gt;Clear the screen&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;clear&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I like being absorbed into the emptiness of the terminal, so this one
comes in handy to tidy up the work space.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="reset-the-terminal"&gt;Reset the terminal&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;re&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tput reset&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If for some reasons the terminal displays badly or display funky
characters, it can usually be reset this way.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="exit-from-the-terminal"&gt;Exit from the terminal&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For exiting the terminal as if you were still in Vim!&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="display-all-file-extensions-recursively-from-the-current-directory"&gt;Display all file extensions recursively from the current directory&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;allextensions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;find . -type f -name &amp;#39;*.*&amp;#39; | sed &amp;#39;s|.*\.||&amp;#39; | sort -u&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It comes in handy to spot if a file shouldn&amp;rsquo;t be there or to check for
lower or uppercase extensions.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="find-text-inside-files-including-filenames"&gt;Find text inside files, including filenames&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;findinfiles&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ag --nobreak --nonumbers --noheading . | fzf&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this example, the alias is set up with
&lt;a href="https://github.com/ggreer/the_silver_searcher"&gt;ag&lt;/a&gt;, a fast
code-searching tool and &lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt;, a great
fuzzy finder.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="reboot-and-shutdown-the-system"&gt;Reboot and shutdown the system&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;reboot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;systemctl reboot&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;shutdown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;systemctl poweroff&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will reboot or power off the system without needing root privileges
in most working conditions.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="list-and-sort-files-and-directories-by-modification-time"&gt;List and sort files and directories by modification time&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;treeold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tree -hDF | less&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This requires the command &lt;code&gt;tree&lt;/code&gt; to be installed. The parameters are
(descriptions taken from &lt;code&gt;man tree&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-h&lt;/code&gt;: Print the size of files in a human readable way.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-D&lt;/code&gt;: Print the date of the last modification time.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-F&lt;/code&gt;: Append a &amp;lsquo;&lt;code&gt;/&lt;/code&gt;&amp;rsquo; for directories, a &amp;lsquo;&lt;code&gt;=&lt;/code&gt;&amp;rsquo; for socket files, a &amp;lsquo;&lt;code&gt;\*&lt;/code&gt;&amp;rsquo;
for executable files, a &amp;lsquo;&lt;code&gt;&amp;gt;&lt;/code&gt;&amp;rsquo; for doors (Solaris) and a &amp;lsquo;&lt;code&gt;|&lt;/code&gt;&amp;rsquo; for
FIFO&amp;rsquo;s, as per &lt;code&gt;ls -F&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="open-files-quickly-with-default-applications"&gt;Open files quickly with default applications&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;o&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;xdg-open&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will open files and URLs specified as argument in the default
application detected.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="moving-around"&gt;Moving around&lt;/h4&gt;
&lt;p&gt;If you are going to be working on projects for some time and require to
&lt;code&gt;cd&lt;/code&gt; into them, I have found the following to be useful:&lt;/p&gt;
&lt;div class="code-block" data-prompted&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;cdnameOfProject &lt;span class="c1"&gt;# instead of having to do cd /path/to/project/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;&lt;span class="c1"&gt;# More examples:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;cdcodeabbey &lt;span class="c1"&gt;# For codeabbey.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;cdhackerrank &lt;span class="c1"&gt;# For hackerrank.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;cdeuler &lt;span class="c1"&gt;# For projecteuler.net&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;cdgit &lt;span class="c1"&gt;# For all Github repositories&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is not advanced by any means, but it helps quite regularly! Since
you can take advantage of tab completion, you can type &lt;code&gt;cd&lt;/code&gt; (without
adding a space) and then press &lt;code&gt;TAB&lt;/code&gt; key to autocomplete the aliases.&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; ...&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cd ../..&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Make it easier to navigate into deep directory structures by basically
doing &lt;code&gt;cd .. &amp;amp;&amp;amp; cd ..&lt;/code&gt; to go back up two directories at once.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="listing-files"&gt;Listing files&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ls -CFh&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;la&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ls -Ah&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;ll&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ls -ahlF&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;ls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ls --color=auto&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Different ways to set up the command ls to quickly see the needed files.
The parameters are (descriptions taken from &lt;code&gt;man ls&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-A&lt;/code&gt;: &lt;em&gt;Do not list implied &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;..&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-C&lt;/code&gt;: &lt;em&gt;List entries by columns.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-F&lt;/code&gt;: &lt;em&gt;Append indicator (one of &lt;code&gt;\*/=&amp;gt;@|&lt;/code&gt;) to entries.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-a&lt;/code&gt;: &lt;em&gt;Do not ignore entries starting with .&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-h&lt;/code&gt;: &lt;em&gt;With &lt;code&gt;-l&lt;/code&gt; and/or &lt;code&gt;-s&lt;/code&gt;, print human readable sizes (e.g., 1K 234M 2G).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-l&lt;/code&gt;: &lt;em&gt;Use a long listing format.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="python-related"&gt;Python-related&lt;/h3&gt;
&lt;hr&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;aNameOfProject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;source /path/to/project/bin/activate&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;source ~/Programming/anaconda3/bin/activate&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# Example using Anaconda distribution&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The purpose is to activate a specific virtual environment quickly. The
command &lt;code&gt;cd&lt;/code&gt; could be added to go to the related project also:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;gNameOfProject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cd /path/to/project/ &amp;amp;&amp;amp; ./.venv/bin/activate&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;.venv&lt;/code&gt; would be the name of the virtual environment.&lt;/p&gt;
&lt;p&gt;I like to &lt;strong&gt;a&lt;/strong&gt;ctivate environments starting aliases with &lt;code&gt;a&lt;/code&gt; and &lt;strong&gt;go&lt;/strong&gt;
and activate at the same time starting aliases with &lt;code&gt;g&lt;/code&gt;. This way, it
feels like I am speaking the Vim language (&lt;code&gt;cw&lt;/code&gt; for &lt;strong&gt;c&lt;/strong&gt;hange &lt;strong&gt;w&lt;/strong&gt;ord,
for example).&lt;/p&gt;
&lt;hr&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;da&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;deactivate&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will deactivate a virtual environment.&lt;/p&gt;
&lt;hr&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;p36&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;python3.6&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;python3.7&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# Simply using `p` for main version of Python&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Practical way to quickly open the desired Python version.&lt;/p&gt;
&lt;hr&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;pyclean&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;find . -regex &amp;#34;.*\(__pycache__\|\.py[co]\)&amp;#34; -delete&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will delete recursively all files and directories that match one of
the following patterns in their name: &lt;code&gt;__pycache__&lt;/code&gt;, &lt;code&gt;.pyc&lt;/code&gt; or &lt;code&gt;.pyo&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope you will find at least one alias to improve your productivity.
Of course, you are welcome to chime in with your own suggestions!&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sat, 08 Dec 2018 13:52:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/aliases-also-known-as-terminal-users-best-friends/</guid><category>tips-and-tricks</category><category>aliases</category><category>bash</category><category>linux</category><category>productivity</category><category>terminal</category></item><item><title>Using Vimwiki for Note-Taking</title><link>https://www.sglavoie.com/posts/using-vimwiki-for-note-taking/</link><description>This short article explains why Vimwiki felt like the right solution to organize my notes.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="what-is-vimwiki"&gt;What is Vimwiki?&lt;/h2&gt;
&lt;p&gt;From the &lt;a href="https://vimwiki.github.io/"&gt;official website&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
 &lt;p&gt;Vimwiki is a personal wiki for Vim – interlinked, plain text files
written in a markup language.&lt;/p&gt;

&lt;/blockquote&gt;&lt;p&gt;As this relies upon Vim&amp;rsquo;s power to write content in a simple format,
this quickly became a viable option to organize more and more notes!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-were-the-other-options-considered"&gt;What were the other options considered?&lt;/h2&gt;
&lt;p&gt;I have used various approaches in the past for different purposes and
reasons, including &lt;em&gt;Evernote&lt;/em&gt;, &lt;em&gt;Simplenote&lt;/em&gt;, &lt;em&gt;Microsoft OneNote&lt;/em&gt;,
&lt;em&gt;Google Docs&lt;/em&gt;, &lt;em&gt;Boostnote&lt;/em&gt;, &lt;em&gt;Freeplane&lt;/em&gt;/&lt;em&gt;FreeMind&lt;/em&gt; (mind-mapping),
&lt;em&gt;Workflowy&lt;/em&gt; and even plain &lt;code&gt;.txt&lt;/code&gt; files. Each has its pros and cons, but
I then decided to limit my options based on the following self-imposed
requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It has to be &lt;strong&gt;available on Linux&lt;/strong&gt;. Right from the start, this would
disqualify many applications such as &lt;em&gt;Notational Velocity&lt;/em&gt;, &lt;em&gt;Bear&lt;/em&gt;,
&lt;em&gt;Quiver&lt;/em&gt;, &lt;em&gt;Paper&lt;/em&gt;, &lt;em&gt;Ulysses&lt;/em&gt; and &lt;em&gt;Squid&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;It has to be &lt;strong&gt;open source&lt;/strong&gt; as this is a philosophy that I strongly
embrace. Plus, having the ability to freely modify it and contribute to
the project is an important additional bonus. Adiós &lt;em&gt;Evernote&lt;/em&gt;, &lt;em&gt;Google
Docs&lt;/em&gt;, &lt;em&gt;Dropbox Paper&lt;/em&gt;, &lt;em&gt;Microsoft OneNote&lt;/em&gt;, &lt;em&gt;Workflowy&lt;/em&gt; and &lt;em&gt;Quip&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;It has to be &lt;strong&gt;fast to use&lt;/strong&gt; and it has to make it possible
to &lt;strong&gt;express oneself in more than one way&lt;/strong&gt;. Say goodbye to
&lt;em&gt;&lt;a href="https://www.freeplane.org"&gt;Freeplane&lt;/a&gt;&lt;/em&gt; (otherwise great for
general brainstorming!) and &lt;em&gt;FreeMind&lt;/em&gt; (which has been abandoned
by its own developers): both are relatively slow on an old machine
because they use Java and it is quite a stretch to use them for
something other than mind maps. In that same category would disappear
&lt;em&gt;&lt;a href="https://www.draw.io/"&gt;draw.io&lt;/a&gt;&lt;/em&gt;, which is fantastic for making
flowcharts and diagrams!&lt;/li&gt;
&lt;li&gt;It has to be versatile enough to handle features such as &lt;strong&gt;including
images, links and attached files&lt;/strong&gt; and have a way to perform &lt;strong&gt;search
and replace&lt;/strong&gt;. Ciao &lt;em&gt;&lt;a href="https://simplenote.com/"&gt;Simplenote&lt;/a&gt;&lt;/em&gt; which
is, well, simple. Even though it doesn&amp;rsquo;t fit the bill in this case,
it remains a great option as it can synchronize your notes with many
different devices (iOS, macOS, Android, Windows and Linux). It has
a feature that allows you to move a slider which acts as a timeline
and shows you a different version of your note since its creation
with the actual date and time down to the minute for each &lt;em&gt;restore
point&lt;/em&gt;. You can also use tags and Markdown and it has options to
share and collaborate with others. Highly recommended!&lt;/li&gt;
&lt;li&gt;It should have a hefty user base to back it up. This would exclude
text editor plugins such as &lt;code&gt;atom-notes&lt;/code&gt; for &lt;em&gt;Atom&lt;/em&gt; or &lt;code&gt;VSNotes&lt;/code&gt; for &lt;em&gt;VS
Code&lt;/em&gt;, which also lack features for accomplishing all of the above.&lt;/li&gt;
&lt;li&gt;On top of everything else, it has to be &lt;strong&gt;available offline&lt;/strong&gt;, in a
&lt;strong&gt;portable and readable format&lt;/strong&gt;. Now, after discarding most options, we
are left with &lt;em&gt;Boostnote&lt;/em&gt; which uses CoffeeScript-Object-Notation and
&lt;em&gt;Vimwiki&lt;/em&gt; which has its own Wiki syntax that&amp;rsquo;s similar in many ways to
Markdown*. Those are the strongest contenders that I could think of but
of course, if you would like to share your recommendations, please do so
in the comments below!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;* &lt;sub&gt;I somehow discredited
&lt;strong&gt;&lt;a href="https://www.gnu.org/software/emacs"&gt;Emacs&lt;/a&gt;&lt;/strong&gt; simply because I started
to learn Vim first and since I&amp;rsquo;m still far from understanding all of
its features, I had to postpone the discovery of Emacs.&lt;/sub&gt;&lt;/p&gt;
&lt;h3 id="one-feature-rich-alternative-to-vimwiki"&gt;One feature-rich alternative to Vimwiki&lt;/h3&gt;
&lt;p&gt;After settling down on Vimwiki, I later found out about &lt;a
href="https://joplin.cozic.net"&gt;Joplin&lt;/a&gt;, which comes with many great
features and characteristics such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Free &amp;amp; Open Source&lt;/li&gt;
&lt;li&gt;Manages notes and todo lists&lt;/li&gt;
&lt;li&gt;Search across all notes/todos&lt;/li&gt;
&lt;li&gt;Import/Export from/to various formats, including Markdown and even
imports from Evernote&lt;/li&gt;
&lt;li&gt;Support for attachments&lt;/li&gt;
&lt;li&gt;Tags&lt;/li&gt;
&lt;li&gt;Synchronization with multiple providers such as Dropbox, Nextcloud,
OneDrive and even your own private cloud&lt;/li&gt;
&lt;li&gt;Available for Windows, Linux, macOS, Android and iOS&lt;/li&gt;
&lt;li&gt;Web Clipper integration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This application left me a great first impression to say the least and I
will make sure to stay up to date on its active development, which you
can &lt;a href="https://github.com/laurent22/joplin"&gt;follow on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="why-did-vimwiki-win-in-the-end"&gt;Why did Vimwiki win in the end?&lt;/h2&gt;
&lt;h3 id="in-short"&gt;In short&lt;/h3&gt;
&lt;blockquote&gt;
 &lt;p&gt;The modal nature of Vim makes it very hard to enjoy any other text
editor once you get used to it. The learning curve is quite considerable
and nearly infinite, but this is also why I think it is worth investing
more time to master it as it has proven to be an everlasting piece of
trusty software.&lt;/p&gt;

&lt;/blockquote&gt;&lt;blockquote&gt;
 &lt;p&gt;There is a feature in Boostnote to set the Editor Keymap to &lt;code&gt;vim&lt;/code&gt; so
that you can edit text in a very similar way, but then you miss out on
Vim&amp;rsquo;s &lt;code&gt;Command mode&lt;/code&gt; which adds tremendous extensibility and the ability
to create any mappings you wish on the fly.&lt;/p&gt;

&lt;/blockquote&gt;&lt;hr&gt;
&lt;h4 id="expanded-edition"&gt;Expanded edition&lt;/h4&gt;
&lt;p&gt;Boostnote comes with nice features such as Tags, the ability to set
multiple storage locations for notes, a &lt;code&gt;Preferences&lt;/code&gt; panel to adjust
many options, a feature to add code snippets, real-time preview of
Markdown being edited, etc. Make no mistake: this is a great program.
But there are many Vim features that are hard or impossible to replicate
and everything that you can do in Boostnote can be done in Vim also
(ctags, emmet syntax, plugins for Markdown, etc.).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For starters, the terminal integration is obviously unmatched. In
Vim, &lt;code&gt;CTRL+Z&lt;/code&gt; will &lt;em&gt;stop&lt;/em&gt; Vim and gives you access to the terminal to
do whatever you want to do. From that point, you can simply switch back
to Vim by issuing the command &lt;code&gt;fg&lt;/code&gt;. The terminal integration goes even
further: you can have full access to the terminal inside Vim buffers
since Vim 8.1 and that is a feature that has been available in Neovim
for even longer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Even though &lt;code&gt;vim&lt;/code&gt; mode can be enabled to edit text, you have to use
the mouse to get many tasks done and the editing window can loose the
focus. On the other hand, Vim is just one single window by default that
you can split however you want, including adding tabs if your heart
tells you to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have to open your notes with Boostnote if you want them to be
fully readable out of the box. Vimwiki does almost no processing with
the content of the files so that it is very easy to open them with any
other text editor. On a related note, it is much easier to export many
notes at the same time with Vimwiki. Boostnote does have a few options
to export individual notes (&lt;code&gt;.md&lt;/code&gt;, &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.html&lt;/code&gt; and print), but it is
not as user-friendly with many notes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vimwiki makes it easy to link notes together and navigate between
them, even within subfolders: highlight text, press &lt;code&gt;Enter&lt;/code&gt; to create a
link and open a new note, write your note and press &lt;code&gt;Backspace&lt;/code&gt; to go
back to where you created the link. That&amp;rsquo;s quick and easy!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the end, it is a matter of taste as those programs are indeed very
distinct. Boostnote has a polished interface, is much easier to use and
has many settings easily changed. Vim/Neovim, on the contrary, requires
a lot of initial effort both to understand and to set up according
to your needs, but it does deliver a good dose of productivity&amp;hellip;
Eventually!&lt;/p&gt;
&lt;p&gt;An honorable mention goes to Simplenote, which is a joy to use with
mobile devices and allows for quick synchronization between different
devices across all the supported platforms.&lt;/p&gt;
&lt;p&gt;Where things really get in favor of Vim, you could mention the extensive
help system (command &lt;code&gt;:help&lt;/code&gt;), the use of macros, words and lines
completion, the dot (&lt;code&gt;.&lt;/code&gt;) command, the many registers at your disposal
for different tasks, the impressive amount of plugins available, the
ways in which you can configure mappings, functions&amp;hellip; But that&amp;rsquo;s for a
whole new story!&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Mon, 03 Dec 2018 13:26:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/using-vimwiki-for-note-taking/</guid><category>workflow</category><category>neovim</category><category>note-taking</category><category>productivity</category><category>vim</category><category>vimwiki</category></item></channel></rss>